gameshell/gamethings.py

768 lines
31 KiB
Python
Raw Normal View History

#gamethings.py
"""Standard thing classes.
Classes:
- ThingGraphic: Represents how thing is to be visualized.
- Thing: The abstract base class for every thing.
- Observer: The abstract base class for things that listen to events.
- Item: A thing that can exist in a character's inventory.
- Useable: A thing that can be used by a character.
- Character: A thing that represents a character.
- NPC: A character that is not controlled by the player.
- Door: A thing that sometimes blocks paths.
- MapExit: A technical thing that marks a map transition.
"""
import ruamel.yaml
from ruamel.yaml.comments import CommentedMap
class ThingGraphic(object):
"""Represent how a thing is to be visualized.
Background color, foreground color, and shape are represented.
This could hypothetically be extended to hold sprites, textures or models."""
def __init__(self, background: str, foreground: str, shape: str):
"""Create a graphic for a thing.
The background and foregrond must be strings with color hex representations.
For instance: '#00FF00' means bright green.
The shape must be a string containing exactly one of the following shapes:
o: circle
x: cross
-: horizontal line
|: vertical line
#: square
^: triangle
A graphic may be invalid.
"""
if not isinstance(background, str):
raise TypeError("Background must be a string of form '#[0-9A-Fa-f]{6}'.")
if not isinstance(foreground, str):
raise TypeError("Foreground must be a string of form '#[0-9A-Fa-f]{6}'.")
if not isinstance(shape, str):
raise TypeError("Shape must be a string of form '[-|ox#^]'.")
self.background = background
self.foreground = foreground
self.shape = shape
class Thing(object):
def __init__(self, thingType: str, name: str, x: int, y: int, description: str, flags: int, playerx = None, playery = None, **kwargs):
self.thingType = thingType
self.name = name
self.description = description
self.x = x
self.y = y
self.playerx = x
self.playery = y
self.prevx = x # if an area gets double-occupied, a thing can get pushed back.
self.prevy = y
if playerx:
self.playerx = playerx
if playery:
self.playery = playery
2021-11-14 22:25:30 -05:00
self.flags = flags
self.graphic = ThingGraphic('clear', '#7F7F7F', ' ')
self.thingID = -1 # ID not assigned
def __str__(self):
"""__str__ is used for look."""
return self.description
def __eq__(self, other):
if not isinstance(other, Thing):
return False
return self.name == other.name
2021-11-14 22:25:30 -05:00
@property
def passable(self):
return bool(self.flags & 1)
@property
def talkable(self):
return bool(self.flags & 2)
@property
def lookable(self):
return bool(self.flags & 4)
@property
def takeable(self):
return bool(self.flags & 8)
@property
def useable(self):
return bool(self.flags & 16)
def fromPrefab(self, prefab):
"""This only exists as a catch-all in case an unsupported thing type is prefabed."""
parts = prefab.details
# set default values for optional arguments
name = self.name
description = self.description
playerx = prefab.x + (self.playerx - self.x)
playery = prefab.y + (self.playery - self.y)
bgc = self.graphic.background
fgc = self.graphic.foreground
shape = self.graphic.shape
if parts != None:
if 'name' in parts:
name = parts['name']
if 'description' in parts:
description = parts['description']
# load graphic
if 'graphic' in parts:
if 'bgc' in parts['graphic']:
bgc = parts['graphic']['bgc']
if 'fgc' in parts['graphic']:
fgc = parts['graphic']['fgc']
if 'shape' in parts['graphic']:
shape = parts['graphic']['shape']
if 'useLocation' in parts:
playerx, playery = parts['useLocation']
graphic = ThingGraphic(bgc, fgc, shape)
return Thing(self.thingType, name, prefab.x, prefab.y, description, self.flags, playerx, playery)
class Prefab(Thing):
"""Basically a placeholder for a predefined prefab. This is for reading in YAML."""
yaml_flag = u'!Prefab'
defaultGraphic = ThingGraphic('clear', 'clear', 'x')
def __init__(self, name: str, x: int, y: int, **kwargs):
super(Prefab, self).__init__('z', name, x, y, '', 1) # 'p' is already taken by the player.
self.details = None # This is so that custom overrides can be made for specific instances.
if "details" in kwargs:
self.details = kwargs["details"]
@classmethod
def to_yaml(cls, representer, node):
# save usual things
ret = {'name': node.name, 'location': (node.x, node.y), 'details': self.details}
return representer.represent_mapping(cls.yaml_flag, ret)
@classmethod
def from_yaml(cls, constructor, node):
parts = CommentedMap()
constructor.construct_mapping(node, parts, True)
# set default values for optional arguments
mdetails = None
if 'details' in parts:
mdetails = dict(parts['details'])
return cls(parts['name'], parts['location'][0], parts['location'][1], details = mdetails)
class Observer(Thing):
"""ABC for things that have a dict of events that they should listen to."""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.behaviors = {} # {the name of the event : (behaviorQueue priority, the name of the behavior)}
self.busy = False # Prevents a new behavior until the current one is finished
self.behaviorQueue = [] # If you can't make it perfect, then make it adjustable.
# The behavior queue is for behaviors that need to execute once the current action is finished.
# If it's not considered important enough (behaviors[event][0] < 0), it's dropped.
class Item(Thing):
yaml_flag = u'!Item'
defaultGraphic = ThingGraphic('clear', '#00BF00', '^')
def __init__(self, name, x: int, y: int, description: str, useFunc: str, useOnFunc: str, customValues: dict, ranged: bool, graphic = defaultGraphic):
super(Item, self).__init__('i', name, x, y, description, 13)
self.useFunc = useFunc
self.useOnFunc = useOnFunc
self.customValues = customValues
self.ranged = ranged
self.graphic = graphic
def use(self):
pass
@classmethod
def to_yaml(cls, representer, node):
# save usual things
ret = {'name': node.name, 'location': (node.x, node.y), 'description': node.description}
# save graphic
graphic = {}
if node.graphic.background != Item.defaultGraphic.background:
graphic['bgc'] = node.graphic.background
if node.graphic.foreground != Item.defaultGraphic.forground:
graphic['fgc'] = node.graphic.foreground
if node.graphic.shape != Item.defaultGraphic.shape:
graphic['shape'] = node.graphicshape
if len(graphic) > 0:
ret['graphic'] = graphic
# save use functions
if node.useFunc != '':
ret['useFunc'] = node.useFunc
if node.useOnFunc != '':
ret['useOnFunc'] = node.useOnFunc
if len(node.customValues) > 0:
ret['customValues'] = node.customValues
if node.ranged:
ret['ranged'] = node.ranged
return representer.represent_mapping(cls.yaml_flag, ret)
@classmethod
def from_yaml(cls, constructor, node):
parts = CommentedMap()
constructor.construct_mapping(node, parts, True)
# set default values for optional arguments
useFunc = ''
useOnFunc = ''
customValues = {}
ranged = False
bgc = Item.defaultGraphic.background
fgc = Item.defaultGraphic.foreground
shape = Item.defaultGraphic.shape
# load graphic
if 'graphic' in parts:
if 'bgc' in parts['graphic']:
bgc = parts['graphic']['bgc']
if 'fgc' in parts['graphic']:
fgc = parts['graphic']['fgc']
if 'shape' in parts['graphic']:
shape = parts['graphic']['shape']
graphic = ThingGraphic(bgc, fgc, shape)
# load use functions
if 'useFunc' in parts:
useFunc = parts['useFunc']
if 'useOnFunc' in parts:
useOnFunc = parts['useOnFunc']
if 'customValues' in parts:
customValues = dict(parts['customValues'])
for v in customValues:
if isinstance(customValues[v], tuple):
customValues[v] = list(customValues[v])
if 'ranged' in parts:
2021-11-14 22:25:30 -05:00
ranged = parts['ranged']
return cls(parts['name'], parts['location'][0], parts['location'][1],
parts['description'], useFunc, useOnFunc, customValues, ranged, graphic)
def use(self, user, gameBase, args) -> float:
pass
def useOn(self, user, gameBase, thing, args) -> float:
pass
2021-11-14 22:25:30 -05:00
def fromPrefab(self, prefab):
parts = prefab.details
# set default values for optional arguments
name = self.name
useFunc = self.useFunc
useOnFunc = self.useOnFunc
customValues = dict(self.customValues)
ranged = self.ranged
bgc = self.graphic.background
fgc = self.graphic.foreground
shape = self.graphic.shape
description = self.description
if parts:
if 'name' in parts:
name = parts['name']
if 'description' in parts:
description = parts['description']
# load graphic
if 'graphic' in parts:
if 'bgc' in parts['graphic']:
bgc = parts['graphic']['bgc']
if 'fgc' in parts['graphic']:
fgc = parts['graphic']['fgc']
if 'shape' in parts['graphic']:
shape = parts['graphic']['shape']
# load use functions
if 'useFunc' in parts:
useFunc = parts['useFunc']
if 'useOnFunc' in parts:
useOnFunc = parts['useOnFunc']
if 'customValues' in parts:
customValues = dict(parts['customValues'])
for v in customValues:
if isinstance(customValues[v], tuple):
customValues[v] = list(customValues[v])
if 'ranged' in parts:
ranged = parts['ranged']
graphic = ThingGraphic(bgc, fgc, shape)
return Item(name, prefab.x, prefab.y, description, useFunc, useOnFunc, customValues, ranged, graphic)
class Useable(Thing):
yaml_flag = u'!Useable'
defaultGraphic = ThingGraphic('clear', '#0000FF', '#')
def __init__(self, name, x: int, y: int, description: str, useFunc: str, customValues: dict, playerx = None, playery = None, graphic = defaultGraphic):
super(Useable, self).__init__('u', name, x, y, description, 16, playerx, playery)
self.useFunc = useFunc
self.customValues = customValues
self.graphic = graphic
@classmethod
def to_yaml(cls, representer, node):
# save usual things
ret = {'name': node.name, 'location': (node.x, node.y), 'description': node.description}
# save graphic
graphic = {}
if node.graphic.background != Useable.defaultGraphic.background:
graphic['bgc'] = node.graphic.background
if node.graphic.foreground != Useable.defaultGraphic.foreground:
graphic['fgc'] = node.graphic.foreground
if node.graphic.shape != Useable.defaultGraphic.shape:
graphic['shape'] = node.graphic.shape
if len(graphic) > 0:
ret['graphic'] = graphic
# save use functions
if node.useFunc != '':
ret['useFunc'] = node.useFunc
if len(node.customValues) > 0:
ret['customValues'] = node.customValues
if node.x != node.playerx or node.y != node.playery:
ret['useLocation'] = (node.playerx, node.playery)
return representer.represent_mapping(cls.yaml_flag, ret)
@classmethod
def from_yaml(cls, constructor, node):
parts = CommentedMap()
constructor.construct_mapping(node, parts, True)
# set default values for optional arguments
useFunc = ''
customValues = {}
playerx, playery = parts['location']
bgc = Useable.defaultGraphic.background
fgc = Useable.defaultGraphic.foreground
shape = Useable.defaultGraphic.shape
# load graphic
if 'graphic' in parts:
if 'bgc' in parts['graphic']:
bgc = parts['graphic']['bgc']
if 'fgc' in parts['graphic']:
fgc = parts['graphic']['fgc']
if 'shape' in parts['graphic']:
shape = parts['graphic']['shape']
graphic = ThingGraphic(bgc, fgc, shape)
# load use functions
if 'useFunc' in parts:
useFunc = parts['useFunc']
if 'customValues' in parts:
customValues = dict(parts['customValues'])
for v in customValues:
if isinstance(customValues[v], tuple):
customValues[v] = list(customValues[v])
if 'useLocation' in parts:
playerx, playery = parts['useLocation']
return cls(parts['name'], parts['location'][0], parts['location'][1],
parts['description'], useFunc, customValues, playerx, playery, graphic)
def use(self, user, gameBase, args) -> float:
pass
2021-11-14 22:25:30 -05:00
def fromPrefab(self, prefab):
parts = prefab.details
# set default values for optional arguments
name = self.name
description = self.description
useFunc = self.useFunc
customValues = dict(self.customValues)
playerx = prefab.x + (self.playerx - self.x)
playery = prefab.y + (self.playery - self.y)
bgc = self.graphic.background
fgc = self.graphic.foreground
shape = self.graphic.shape
if parts != None:
if 'name' in parts:
name = parts['name']
if 'description' in parts:
description = parts['description']
# load graphic
if 'graphic' in parts:
if 'bgc' in parts['graphic']:
bgc = parts['graphic']['bgc']
if 'fgc' in parts['graphic']:
fgc = parts['graphic']['fgc']
if 'shape' in parts['graphic']:
shape = parts['graphic']['shape']
# load use functions
if 'useFunc' in parts:
useFunc = parts['useFunc']
if 'customValues' in parts:
customValues = dict(parts['customValues'])
for v in customValues:
if isinstance(customValues[v], tuple):
customValues[v] = list(customValues[v])
if 'useLocation' in parts:
playerx, playery = parts['useLocation']
graphic = ThingGraphic(bgc, fgc, shape)
return Useable(name, prefab.x, prefab.y, description, useFunc, customValues, playerx, playery, graphic)
class Character(Thing):
defaultGraphic = ThingGraphic('clear', '#000000', 'o')
def __init__(self, inventory: dict, customValues: dict, graphic = defaultGraphic, **kwargs):
super(Character, self).__init__(**kwargs)
if inventory == None:
inventory = {} # create a new dict for the inventory.
# This couldn't be in the NPC constructor because
# then all characters would share a reference to
# the same empty inventory.
self.__inventory = inventory
self.customValues = customValues
self.graphic = graphic
self.thingNames = {} #{str: int}
# set up inventory shtuff
for i in self.__inventory:
if self.__inventory[i].name in self.thingNames:
self.thingNames[self.__inventory[i].name].append(i)
else:
self.thingNames[self.__inventory[i].name] = [i]
def addThing(self, thing):
if not isinstance(thing, Item):
raise TypeError("Only items can be added to a character's inventory.")
self.__inventory[thing.thingID] = thing
if thing.name in self.thingNames:
self.thingNames[thing.name].append(thing.thingID)
else:
self.thingNames[thing.name] = [thing.thingID]
def getThingByID(self, thingID):
if thingID in self.__inventory:
return self.__inventory[thingID]
else:
return None
def getThingByName(self, name):
if name in self.thingNames:
return self.__inventory[self.thingNames[name][0]]
else:
return None
def removeThingByID(self, thingID):
ret = self.__inventory[thingID]
self.thingNames[ret.name].remove(thingID)
if len(self.thingNames[ret.name]) == 0:
del self.thingNames[ret.name]
del self.__inventory[thingID]
return ret
def removeThingByName(self, name):
ret = self.getThingByName(name)
self.thingNames[ret.name].remove(ret.thingID)
if len(self.thingNames[ret.name]) == 0:
del self.thingNames[ret.name]
del self.__inventory[ret.thingID]
return ret
def removeThing(self, ret):
self.thingNames[ret.name].remove(ret.thingID)
if len(self.thingNames[ret.name]) == 0:
del self.thingNames[ret.name]
del self.__inventory[ret.thingID]
return ret
@property
def inventory(self):
"""Get the inventory as a list."""
return list(self.__inventory.values())
class NPC(Character, Observer):
yaml_flag = u'!NPC'
defaultGraphic = ThingGraphic('clear', '#000000', 'o')
def __init__(self, behaviors: dict, tempInventory: list, **kwargs):
if 'graphic' not in kwargs:
kwargs['graphic'] = PlayerCharacter.defaultGraphic
super(NPC, self).__init__(thingType = 'n', inventory = {}, flags = 6, **kwargs)
self.behaviors = behaviors
self.behaveEvent = None
self.tempInventory = tempInventory # should be deleted once NPC is loaded
@classmethod
def to_yaml(cls, representer, node):
# save usual things
ret = {'name': node.name, 'location': (node.x, node.y),
'description': node.description, 'behaviors': node.behaviors}
# save graphic
graphic = {}
if node.graphic.background != Useable.defaultGraphic.background:
graphic['bgc'] = node.graphic.background
if node.graphic.foreground != Useable.defaultGraphic.foreground:
graphic['fgc'] = node.graphic.foreground
if node.graphic.shape != Useable.defaultGraphic.shape:
graphic['shape'] = node.graphic.shape
if len(graphic) > 0:
ret['graphic'] = graphic
# save use functions
if len(node.inventory) > 0:
ret['inventory'] = node.inventory
if len(node.customValues) > 0:
ret['customValues'] = node.customValues
if node.x != node.playerx or node.y != node.playery:
ret['useLocation'] = (node.playerx, node.playery)
return representer.represent_mapping(cls.yaml_flag, ret)
@classmethod
def from_yaml(cls, constructor, node):
parts = CommentedMap()
constructor.construct_mapping(node, parts, True)
# set default values for optional arguments
minventory = []
mcustomValues = {}
mplayerx, mplayery = parts['location']
bgc = NPC.defaultGraphic.background
fgc = NPC.defaultGraphic.foreground
shape = NPC.defaultGraphic.shape
# load graphic
if 'graphic' in parts:
if 'bgc' in parts['graphic']:
bgc = parts['graphic']['bgc']
if 'fgc' in parts['graphic']:
fgc = parts['graphic']['fgc']
if 'shape' in parts['graphic']:
shape = parts['graphic']['shape']
mgraphic = ThingGraphic(bgc, fgc, shape)
# load use functions
if 'inventory' in parts:
inventory = parts['inventory']
if 'customValues' in parts:
mcustomValues = dict(parts['customValues'])
for v in mcustomValues:
if isinstance(mcustomValues[v], tuple):
mcustomValues[v] = list(mcustomValues[v])
if 'useLocation' in parts:
playerx, playery = parts['useLocation']
return cls(name = parts['name'], x = parts['location'][0], y = parts['location'][1],
description = parts['description'], behaviors = parts['behaviors'], tempInventory = minventory, customValues = mcustomValues,
playerx = mplayerx, plyery = mplayery, graphic = mgraphic)
2021-11-14 22:25:30 -05:00
def fromPrefab(self, prefab):
parts = prefab.details
# set default values for optional arguments
mname = self.name
mdescription = self.description
minventory = list(self.tempInventory)
mcustomValues = dict(self.customValues)
mbehaviors = dict(self.behaviors)
mplayerx = prefab.x + (self.playerx - self.x)
mplayery = prefab.y + (self.playery - self.y)
bgc = self.graphic.background
fgc = self.graphic.foreground
shape = self.graphic.shape
if prefab != None:
if 'name' in parts:
mname = parts['name']
if 'description' in parts:
mdescription = parts['description']
# load graphic
if 'graphic' in parts:
if 'bgc' in parts['graphic']:
bgc = parts['graphic']['bgc']
if 'fgc' in parts['graphic']:
fgc = parts['graphic']['fgc']
if 'shape' in parts['graphic']:
shape = parts['graphic']['shape']
# load use functions
if 'inventory' in parts:
inventory = parts['inventory']
if 'customValues' in parts:
mcustomValues = dict(parts['customValues'])
for v in mcustomValues:
if isinstance(mcustomValues[v], tuple):
mcustomValues[v] = list(mcustomValues[v])
if 'useLocation' in parts:
playerx, playery = parts['useLocation']
if 'behaviors' in parts:
mbehaviors = dict(parts['behaviors'])
mgraphic = ThingGraphic(bgc, fgc, shape)
return NPC(name = mname, x = prefab.x, y = prefab.y, description = mdescription, behaviors = mbehaviors, tempInventory = minventory, customValues = mcustomValues,
playerx = mplayerx, plyery = mplayery, graphic = mgraphic)
class Door(Thing):
yaml_flag = u'!Door'
defaultGraphic = ThingGraphic('clear', '#7F3F00', '#')
def __init__(self, name, x: int, y: int, locked: bool, description = None, key = None, graphic = defaultGraphic):
self.descBase = description
if description == None:
if locked:
description = "The {0} is locked.".format(name)
else:
description = "The {0} is unlocked.".format(name)
else:
if locked:
description += " It is locked.".format(name)
else:
description += " It is unlocked.".format(name)
super(Door, self).__init__('d', name, x, y, description, 1)
self.passable = not locked
self.key = key
self.graphic = graphic
def lock(self, key = None):
if key == self.key:
self.passable = not self.passable
if self.descBase == None:
if self.passable:
self.description = "The {0} is unlocked.".format(self.name)
else:
self.description = "The {0} is locked.".format(self.name)
else:
if self.passable:
self.description += " It is unlocked.".format(self.name)
else:
self.description += " It is locked.".format(self.name)
return True
return False
@classmethod
def to_yaml(cls, representer, node):
# save usual things
ret = {'name': node.name, 'location': (node.x, node.y)}
# save graphic
graphic = {}
if node.graphic.background != Useable.defaultGraphic.background:
graphic['bgc'] = node.graphic.background
if node.graphic.foreground != Useable.defaultGraphic.foreground:
graphic['fgc'] = node.graphic.foreground
if node.graphic.shape != Useable.defaultGraphic.shape:
graphic['shape'] = node.graphic.shape
if len(graphic) > 0:
ret['graphic'] = graphic
# save door state
if node.passable:
ret['locked'] = not node.passable
if node.descBase != None:
ret['description'] = node.descBase
if node.key != None:
ret['key'] = node.key
return representer.represent_mapping(cls.yaml_flag, ret)
@classmethod
def from_yaml(cls, constructor, node):
parts = CommentedMap()
constructor.construct_mapping(node, parts, True)
# set default values for optional arguments
description = None
locked = False
key = None
bgc = Door.defaultGraphic.background
fgc = Door.defaultGraphic.foreground
shape = Door.defaultGraphic.shape
# load graphic
if 'graphic' in parts:
if 'bgc' in parts['graphic']:
bgc = parts['graphic']['bgc']
if 'fgc' in parts['graphic']:
fgc = parts['graphic']['fgc']
if 'shape' in parts['graphic']:
shape = parts['graphic']['shape']
graphic = ThingGraphic(bgc, fgc, shape)
# load door state
if 'description' in parts:
description = parts['description']
if 'locked' in parts:
locked = parts['locked']
if 'key' in parts:
key = parts['key']
return cls(parts['name'], parts['location'][0], parts['location'][1],
locked, description, key, graphic)
class MapExit(Thing):
yaml_flag = u'!MapExit'
defaultGraphic = ThingGraphic('clear', '#FF0000', 'x')
def __init__(self, name, x: int, y: int, exitid: int, destination: str, prefix = None, onUse = '', key = True, graphic = defaultGraphic):
description = name
if prefix:
description = "{0} {1}".format(prefix, name)
super(MapExit, self).__init__('x', name, x, y, description, 5)
self.exitid = exitid
self.destination = destination
self.prefix = prefix
self.onUse = onUse
self.key = key
self.graphic = graphic
@classmethod
def to_yaml(cls, representer, node):
# save usual things
ret = {'name': node.name, 'location': (node.x, node.y), 'id': node.exitid, 'destination': node.destination}
# save graphic
graphic = {}
if node.graphic.background != Useable.defaultGraphic.background:
graphic['bgc'] = node.graphic.background
if node.graphic.foreground != Useable.defaultGraphic.foreground:
graphic['fgc'] = node.graphic.foreground
if node.graphic.shape != Useable.defaultGraphic.shape:
graphic['shape'] = node.graphic.shape
if len(graphic) > 0:
ret['graphic'] = graphic
if node.prefix != None:
ret['prefix'] = node.prefix
if node.onUse != '':
ret['onUse'] = node.onUse
if node.key != True:
ret['key'] = node.key
return representer.represent_mapping(cls.yaml_flag, ret)
@classmethod
def from_yaml(cls, constructor, node):
parts = CommentedMap()
constructor.construct_mapping(node, parts, True)
# set default values for optional arguments
prefix = None
onUse = ''
key = True
bgc = MapExit.defaultGraphic.background
fgc = MapExit.defaultGraphic.foreground
shape = MapExit.defaultGraphic.shape
# load graphic
if 'graphic' in parts:
if 'bgc' in parts['graphic']:
bgc = parts['graphic']['bgc']
if 'fgc' in parts['graphic']:
fgc = parts['graphic']['fgc']
if 'shape' in parts['graphic']:
shape = parts['graphic']['shape']
graphic = ThingGraphic(bgc, fgc, shape)
if 'prefix' in parts:
prefix = parts['prefix']
if 'onUse' in parts:
onUse = parts['onUse']
if 'key' in parts:
key = parts['key']
return cls(parts['name'], parts['location'][0], parts['location'][1],
parts['id'], parts['destination'], prefix, onUse, key, graphic)
class MapEntrance(Thing):
yaml_flag = u'!MapEntrance'
defaultGraphic = ThingGraphic('clear', 'clear', 'x')
# no graphic - should not be drawn
def __init__(self, x: int, y: int, exitid: int, name = None):
if name == None:
name = 'entrance {}'.format(exitid)
super(MapEntrance, self).__init__('a', name, x, y, '', 1)
self.exitid = exitid
#self.graphic = MapEntrance.defaultGraphic
@classmethod
def to_yaml(cls, representer, node):
# save usual things
ret = {'location': (node.x, node.y), 'id': node.exitid}
return representer.represent_mapping(cls.yaml_flag, ret)
@classmethod
def from_yaml(cls, constructor, node):
parts = CommentedMap()
constructor.construct_mapping(node, parts, True)
# set default values for optional arguments
return cls(parts['location'][0], parts['location'][1], parts['id'])
class PlayerCharacter(Character):
"""Player object. Cannot be created with yaml."""
defaultGraphic = ThingGraphic('clear', '#0000FF', 'o')
def __init__(self, **kwargs):
if 'name' not in kwargs:
kwargs['name'] == 'You'
if 'graphic' not in kwargs:
kwargs['graphic'] = PlayerCharacter.defaultGraphic
super(PlayerCharacter, self).__init__(thingType = 'p', flags = 5, **kwargs)