Things can now be shared globally by maps.

This commit is contained in:
Patrick Marsee 2019-10-15 18:40:50 -04:00
parent aba0014e27
commit 963c77f77c
3 changed files with 73 additions and 35 deletions

View file

@ -5,6 +5,38 @@ import ruamel.yaml
import math as _mt
import gamethings as _gt
import gamelocus as _gl
from ruamel.yaml.comments import CommentedMap
class Singleton(object):
"""This is a super basic class (would be a struct in other languages)
that represents where a singleton Thing should be in a map."""
yaml_flag = u'!Singleton'
def __init__(self, name: str, x: int, y: int):
self.name = name
self.x = x
self.y = y
@classmethod
def to_yaml(cls, representer, node):
representer.represent_mapping({
'name': self.name,
'location': (self.x, self.y)
})
@classmethod
def from_yaml(cls, constructor, node):
parts = CommentedMap()
constructor.construct_mapping(node, parts, True)
# since all parts are necessary, I won't bother with if statements
# and let it crash.
if not isinstance(parts['name'], str):
raise RuntimeError("Name must be a string.")
if not isinstance(parts['location'], list):
raise RuntimeError("Location must be a list.")
if not (isinstance(parts['location'][0], int) and isinstance(parts['location'][1], int)):
raise RuntimeError("Coordinates must be integers.")
return cls(parts['name'], parts['location'][0], parts['location'][1])
class MapError(RuntimeError):
pass
@ -24,6 +56,7 @@ class GameMap(object):
yaml.register_class(_gt.Door)
yaml.register_class(_gt.MapExit)
yaml.register_class(_gt.MapEntrance)
yaml.register_class(Singleton)
def __init__(self, name, graph, matrix, dimensions):
self.name = name
@ -63,7 +96,7 @@ class GameMap(object):
return text.replace('\n', end)
@staticmethod
def read(infile = None, prevMap = None, preLoaded = False, nextThing = 0):
def read(infile = None, prevMap = None, singletons = None, preLoaded = False, nextThing = 0):
"""Read map data and return a Map object. If infile is not provided, then
it will read from stdin. Otherwise, it should be a valid file name.
Entering a map through stdin will be obsolete once testing is over."""
@ -106,7 +139,7 @@ Entering a map through stdin will be obsolete once testing is over."""
level = GameMap(infile, mapGraph, mapMatrix, dimensions)
# Now, load other info
nextThing = GameMap.loadThings(level, info, prevMap, preLoaded, nextThing)
nextThing = GameMap.loadThings(level, info, prevMap, singletons, preLoaded, nextThing)
return level, nextThing
@ -171,7 +204,7 @@ list of lists of tuples."""
return mat, graph, dim
@staticmethod
def loadThings(level, info, prevMap = None, preLoaded = False, nextThing = 0):
def loadThings(level, info, prevMap = None, singletons = None, preLoaded = False, nextThing = 0):
"""load the things from the xml part of the map file."""
if 'openingText' in info:
level.openingText = info['openingText']
@ -197,37 +230,50 @@ list of lists of tuples."""
if 'loadOnce' in info and not preLoaded:
for thing in info['loadOnce']:
#print(type(thing))
nextThing = level.addThing(thing, nextThing, True)
if isinstance(thing, _gt.Thing):
nextThing = level.addThing(thing, nextThing, True)
else:
raise MapError("Non-thing loaded as a thing:\n{}".format(thing))
if 'loadAlways' in info:
for thing in info['loadAlways']:
#print(type(thing))
nextThing = level.addThing(thing, nextThing)
if ((thing.thingType == 'x' and not hasKnownEntrance) or thing.thingType == 'a') and prevMap == thing.exitid:
level.playerStart = (thing.x, thing.y)
hasKnownEntrance = True
if isinstance(thing, _gt.Thing):
nextThing = level.addThing(thing, nextThing)
if ((thing.thingType == 'x' and not hasKnownEntrance) or thing.thingType == 'a') and prevMap == thing.exitid:
level.playerStart = (thing.x, thing.y)
hasKnownEntrance = True
elif isinstance(thing, Singleton):
if singletons != None:
single = singletons[thing.name]
single.x, single.y = thing.x, thing.y
single.prevx, single.prevy = thing.x, thing.y
nextThing = level.addThing(single, nextThing)
else:
raise MapError("Non-thing loaded as a thing:\n{}".format(thing))
return nextThing
# stuff the gameshell itself might use
def addThing(self, thing, nextThing = 0, persist = False):
if thing == None:
if thing == None: # it must be a singleton
return nextThing
#if thing.name in self.thingNames: # resolved
# raise ValueError("Cannot have two objects named {0}.".format(thing.name))
if thing.thingID == -1: # This is to ensure that we don't double up IDs.
thing.thingID = nextThing
nextThing += 1
# Some things, like containers, have other things as custom values,
# so they need IDs as well.
if thing.thingType in 'iun':
nextThing = GameMap.addThingRecursive(thing.customValues, nextThing)
if thing.thingType == 'n':
for i in thing.tempInventory:
if i.thingID == -1:
i.thingID = nextThing
nextThing = GameMap.addThingRecursive(i.customValues, nextThing + 1)
thing.addThing(i)
del thing.tempInventory
# Some things, like containers, have other things as custom values,
# so they need IDs as well.
# Let's only add them if they weren't already loaded.
if thing.thingType in 'iun':
nextThing = GameMap.addThingRecursive(thing.customValues, nextThing)
if thing.thingType == 'n':
for i in thing.tempInventory:
if i.thingID == -1:
i.thingID = nextThing
nextThing = GameMap.addThingRecursive(i.customValues, nextThing + 1)
thing.addThing(i)
del thing.tempInventory
pos = self.coordsToInt(thing.x, thing.y)
if pos not in self.thingPos:
self.thingPos[pos] = [thing.thingID]