Added the ability to create prefabs.
This commit is contained in:
parent
871646fccc
commit
18595087ff
5 changed files with 304 additions and 59 deletions
93
gamebase.py
93
gamebase.py
|
@ -5,6 +5,7 @@ import heapq as _hq
|
|||
import gamemap as _gm
|
||||
import gameevents as _ge
|
||||
import random as _ra
|
||||
import os as _os
|
||||
import sys as _sys
|
||||
import pickle as _pi
|
||||
import ruamel.yaml as _yaml
|
||||
|
@ -40,6 +41,7 @@ class GameBase(object):
|
|||
self.level = None
|
||||
self.persist = {} # {level : {thingID : thing}}
|
||||
self.singletons = {} # {thingName : thing}
|
||||
self.prefabs = {} # {thingName : thing}
|
||||
self.ps2 = '? '
|
||||
self.eventQueue = []
|
||||
self.gameTime = 0.0
|
||||
|
@ -411,9 +413,9 @@ Object can be the name of the object, or its coordinates."""
|
|||
|
||||
# load the new level
|
||||
if len(args) == 2:
|
||||
self.level, self.nextThing = _gm.GameMap.read(args[0], int(args[1]), self.singletons, preLoaded, self.nextThing)
|
||||
self.level, self.nextThing = _gm.GameMap.read(args[0], int(args[1]), self.singletons, self.prefabs, preLoaded, self.nextThing)
|
||||
else:
|
||||
self.level, self.nextThing = _gm.GameMap.read(args[0], None, self.singletons, preLoaded, self.nextThing)
|
||||
self.level, self.nextThing = _gm.GameMap.read(args[0], None, self.singletons, self.prefabs, preLoaded, self.nextThing)
|
||||
|
||||
if self.level == None:
|
||||
raise GameError("Map could not be loaded.")
|
||||
|
@ -422,7 +424,7 @@ Object can be the name of the object, or its coordinates."""
|
|||
if args[0] in self.persist:
|
||||
persistedThings = tuple(self.persist[args[0]].keys())
|
||||
for i in persistedThings:
|
||||
self.nextThing = self.level.addThing(self.persist[args[0]][i], self.nextThing, True) #nextThing shouldn't change
|
||||
self.nextThing = self.level.addThing(self.persist[args[0]][i], self.prefabs, self.nextThing, True) #nextThing shouldn't change
|
||||
del self.persist[args[0]][i] # delete them from the persist dict to prevent item duplication
|
||||
|
||||
print(self.level.openingText, file = self.outstream)
|
||||
|
@ -439,7 +441,7 @@ Object can be the name of the object, or its coordinates."""
|
|||
self.player.x, self.player.y = mx, my
|
||||
#print("Player moved.")
|
||||
self.player.prevx, self.player.prevy = self.player.x, self.player.y
|
||||
self.nextThing = self.level.addThing(self.player, self.nextThing) # The player needs to be added to the new level.
|
||||
self.nextThing = self.level.addThing(self.player, self.prefabs, self.nextThing) # The player needs to be added to the new level.
|
||||
if self.onLevelLoad != None:
|
||||
self.onLevelLoad()
|
||||
self.parseScript(self.level.enterScript)
|
||||
|
@ -472,8 +474,16 @@ Object can be the name of the object, or its coordinates."""
|
|||
fileName = 'saves/' + args[0].replace(' ', '_') + '.dat'
|
||||
if args[0].endswith('.dat'): # This is really for absolute paths, but doesn't really check for that.
|
||||
fileName = args[0]
|
||||
with open(fileName, 'wb') as f:
|
||||
try:
|
||||
f = open(fileName, 'wb')
|
||||
_pi.dump(data, f, protocol=prot)
|
||||
except FileNotFoundException as err:
|
||||
_os.mkdir('saves')
|
||||
try:
|
||||
f = open(fileName, 'wb')
|
||||
_pi.dump(data, f, protocol=prot)
|
||||
except OSError as newErr:
|
||||
print("Save failed: {}".format(newErr), file = self.outstream)
|
||||
|
||||
# delete things in the current map from the persist dict to prevent item duplication
|
||||
persistedThings = tuple(self.persist[self.level.name].keys())
|
||||
|
@ -487,6 +497,7 @@ Object can be the name of the object, or its coordinates."""
|
|||
def loadGame(self, args):
|
||||
if len(args) < 1:
|
||||
print("Save file must have a name!", file = self.outstream)
|
||||
print('\n'.join(_os.listdir('./saves')), file = self.outstream)
|
||||
return
|
||||
|
||||
# pickle protocol 4 for Python 3.4.0 to 3.7.x
|
||||
|
@ -589,6 +600,7 @@ Object can be the name of the object, or its coordinates."""
|
|||
|
||||
def loadGameData(self, dataFile):
|
||||
yaml = _yaml.YAML()
|
||||
yaml.register_class(_gt.Prefab)
|
||||
yaml.register_class(_gt.Item)
|
||||
yaml.register_class(_gt.Useable)
|
||||
yaml.register_class(_gt.NPC)
|
||||
|
@ -598,6 +610,23 @@ Object can be the name of the object, or its coordinates."""
|
|||
data = None
|
||||
with open(dataFile, 'r') as f:
|
||||
data = yaml.load(f)
|
||||
self.prefabs = {}
|
||||
if 'prefabs' in data:
|
||||
for thing in data['prefabs']:
|
||||
if not isinstance(thing, _gt.Thing):
|
||||
print("Non-thing in prefabs, ignoring.\n", _sys.stderr)
|
||||
continue
|
||||
thing.thingID = self.nextThing
|
||||
self.nextThing += 1
|
||||
if thing.thingType in 'iun':
|
||||
self.nextThing = _gm.GameMap.addThingRecursive(thing.customValues, self.prefabs, self.nextThing)
|
||||
if thing.thingType == 'n':
|
||||
for i in thing.tempInventory:
|
||||
if i.thingID == -1:
|
||||
i.thingID = self.nextThing
|
||||
self.nextThing = _gm.GameMap.addThingRecursive(i.customValues, self.prefabs, self.nextThing + 1)
|
||||
# for prefabs, we don't add their items to their "real" inventory and don't delete the temporary one.
|
||||
self.prefabs[thing.name] = thing
|
||||
# In this context, 'singleton' means a 'thing' that can be accessed by
|
||||
# any map. This is useful for when you have major characters who will
|
||||
# show up in many scenes, and their inventory must stay the same, for
|
||||
|
@ -613,12 +642,12 @@ Object can be the name of the object, or its coordinates."""
|
|||
thing.thingID = self.nextThing
|
||||
self.nextThing += 1
|
||||
if thing.thingType in 'iun':
|
||||
self.nextThing = _gm.GameMap.addThingRecursive(thing.customValues, self.nextThing)
|
||||
self.nextThing = _gm.GameMap.addThingRecursive(thing.customValues, self.prefabs, self.nextThing)
|
||||
if thing.thingType == 'n':
|
||||
for i in thing.tempInventory:
|
||||
if i.thingID == -1:
|
||||
i.thingID = self.nextThing
|
||||
self.nextThing = _gm.GameMap.addThingRecursive(i.customValues, self.nextThing + 1)
|
||||
self.nextThing = _gm.GameMap.addThingRecursive(i.customValues, self.prefabs, self.nextThing + 1)
|
||||
thing.addThing(i)
|
||||
del thing.tempInventory
|
||||
self.singletons[thing.name] = thing
|
||||
|
@ -749,7 +778,7 @@ Object can be the name of the object, or its coordinates."""
|
|||
raise GameError("'Drop' event cannot be handled.")
|
||||
e.item.x = e.actor.x
|
||||
e.item.y = e.actor.y
|
||||
self.nextThing = self.level.addThing(e.item, self.nextThing, True) # nextThing shouldn't change
|
||||
self.nextThing = self.level.addThing(e.item, self.prefabs, self.nextThing, True) # nextThing shouldn't change
|
||||
e.actor.removeThing(e.item)
|
||||
return True
|
||||
|
||||
|
@ -917,11 +946,11 @@ Object can be the name of the object, or its coordinates."""
|
|||
if name == None:
|
||||
name = 'item {}'.format(self.nextThing)
|
||||
if bgc == None:
|
||||
bgc = _gt.Item.defaultGraphic[0]
|
||||
bgc = _gt.Item.defaultGraphic.background
|
||||
if fgc == None:
|
||||
fgc = _gt.Item.defaultGraphic[1]
|
||||
fgc = _gt.Item.defaultGraphic.foreground
|
||||
if shape == None:
|
||||
shape = _gt.Item.defaultGraphic[2]
|
||||
shape = _gt.Item.defaultGraphic.shape
|
||||
for i in args[1:]:
|
||||
if i[0:12].casefold() == 'description=':
|
||||
description = i[12:]
|
||||
|
@ -950,11 +979,11 @@ Object can be the name of the object, or its coordinates."""
|
|||
if name == None:
|
||||
name = 'useable {}'.format(self.nextThing)
|
||||
if bgc == None:
|
||||
bgc = _gt.Useable.defaultGraphic[0]
|
||||
bgc = _gt.Useable.defaultGraphic.background
|
||||
if fgc == None:
|
||||
fgc = _gt.Useable.defaultGraphic[1]
|
||||
fgc = _gt.Useable.defaultGraphic.foreground
|
||||
if shape == None:
|
||||
shape = _gt.Useable.defaultGraphic[2]
|
||||
shape = _gt.Useable.defaultGraphic.shape
|
||||
for i in args[1:]:
|
||||
if i[0:12].casefold() == 'description=':
|
||||
description = i[12:]
|
||||
|
@ -977,11 +1006,11 @@ Object can be the name of the object, or its coordinates."""
|
|||
if name == None:
|
||||
name = 'character {}'.format(self.nextThing)
|
||||
if bgc == None:
|
||||
bgc = _gt.NPC.defaultGraphic[0]
|
||||
bgc = _gt.NPC.defaultGraphic.background
|
||||
if fgc == None:
|
||||
fgc = _gt.NPC.defaultGraphic[1]
|
||||
fgc = _gt.NPC.defaultGraphic.foreground
|
||||
if shape == None:
|
||||
shape = _gt.NPC.defaultGraphic[2]
|
||||
shape = _gt.NPC.defaultGraphic.shape
|
||||
for i in args[1:]:
|
||||
if i[0:12].casefold() == 'description=':
|
||||
description = i[12:]
|
||||
|
@ -1002,11 +1031,11 @@ Object can be the name of the object, or its coordinates."""
|
|||
if name == None:
|
||||
name = 'door {}'.format(self.nextThing)
|
||||
if bgc == None:
|
||||
bgc = _gt.Door.defaultGraphic[0]
|
||||
bgc = _gt.Door.defaultGraphic.background
|
||||
if fgc == None:
|
||||
fgc = _gt.Door.defaultGraphic[1]
|
||||
fgc = _gt.Door.defaultGraphic.foreground
|
||||
if shape == None:
|
||||
shape = _gt.Door.defaultGraphic[2]
|
||||
shape = _gt.Door.defaultGraphic.shape
|
||||
for i in args[1:]:
|
||||
if i[0:12].casefold() == 'description=':
|
||||
description = i[12:]
|
||||
|
@ -1023,11 +1052,11 @@ Object can be the name of the object, or its coordinates."""
|
|||
if name == None:
|
||||
name = 'somewhere'
|
||||
if bgc == None:
|
||||
bgc = _gt.MapExit.defaultGraphic[0]
|
||||
bgc = _gt.MapExit.defaultGraphic.background
|
||||
if fgc == None:
|
||||
fgc = _gt.MapExit.defaultGraphic[1]
|
||||
fgc = _gt.MapExit.defaultGraphic.foreground
|
||||
if shape == None:
|
||||
shape = _gt.MapExit.defaultGraphic[2]
|
||||
shape = _gt.MapExit.defaultGraphic.shape
|
||||
for i in args[1:]:
|
||||
if i[0:12].casefold() == 'destination=':
|
||||
destination = i[12:]
|
||||
|
@ -1054,21 +1083,21 @@ Object can be the name of the object, or its coordinates."""
|
|||
single.prevx, single.prevy = x, y
|
||||
else:
|
||||
raise GameError("{} not a valid thing type.".format(args[0]))
|
||||
self.nextThing = self.level.addThing(thing, self.nextThing, persist)
|
||||
self.nextThing = self.level.addThing(thing, self.prefabs, self.nextThing, persist)
|
||||
return thing
|
||||
|
||||
def giveToPlayer(self, args):
|
||||
"""We get to assume it's an item."""
|
||||
name = 'item {}'.format(self.nextThing)
|
||||
x, y = self.playerx, self.playery
|
||||
fgc, bgc, shape = _gt.Item.defaultGraphic['fgc'], _gt.Item.defaultGraphic['bgc'], _gt.Item.defaultGraphic['shape']
|
||||
x, y = self.player.x, self.player.y
|
||||
fgc, bgc, shape = _gt.Item.defaultGraphic.foreground, _gt.Item.defaultGraphic.background, _gt.Item.defaultGraphic.shape
|
||||
description = 'A nondescript item.'
|
||||
persist = True
|
||||
useFunc = ''
|
||||
useOnFunc = ''
|
||||
customValues = {}
|
||||
ranged = False
|
||||
for i in args[1:]:
|
||||
for i in args[0:]:
|
||||
if i[0:5].casefold() == 'name=':
|
||||
name = i[5:]
|
||||
elif i[0:10].casefold() == 'location=':
|
||||
|
@ -1108,11 +1137,11 @@ Object can be the name of the object, or its coordinates."""
|
|||
equalsign = i.index('=')
|
||||
cv = i[3:equalsign]
|
||||
customValues[cv] = getValueFromString(i[equalsign+1:])
|
||||
thing = _gt.Item(name, x, y, description, useFunc, useOnFunc, customValues, ranged, _gt.ThingGraphic(bgc, fgc, shape))
|
||||
thing.thingID = self.nextThing
|
||||
self.player.addThing(thing)
|
||||
self.nextThing += 1
|
||||
return thing
|
||||
thing = _gt.Item(name, x, y, description, useFunc, useOnFunc, customValues, ranged, _gt.ThingGraphic(bgc, fgc, shape))
|
||||
thing.thingID = self.nextThing
|
||||
self.player.addThing(thing)
|
||||
self.nextThing += 1
|
||||
return thing
|
||||
|
||||
def moveThingScript(self, args):
|
||||
colon = args.index(':')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue