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

@ -44,7 +44,7 @@ class GameBase(object):
self.eventQueue = [] self.eventQueue = []
self.gameTime = 0.0 self.gameTime = 0.0
self.skipLoop = True self.skipLoop = True
self.nextThing = 0 self.nextThing = 1
# player info # player info
self.playerName = 'You' self.playerName = 'You'
@ -363,9 +363,9 @@ Object can be the name of the object, or its coordinates."""
# load the new level # load the new level
if len(args) == 2: if len(args) == 2:
self.level, self.nextThing = _gm.GameMap.read(args[0], int(args[1]), preLoaded, self.nextThing) self.level, self.nextThing = _gm.GameMap.read(args[0], int(args[1]), self.singletons, preLoaded, self.nextThing)
else: else:
self.level, self.nextThing = _gm.GameMap.read(args[0], None, preLoaded, self.nextThing) self.level, self.nextThing = _gm.GameMap.read(args[0], None, self.singletons, preLoaded, self.nextThing)
if self.level == None: if self.level == None:
raise GameError("Map could not be loaded.") raise GameError("Map could not be loaded.")
@ -388,7 +388,7 @@ Object can be the name of the object, or its coordinates."""
inventory = {}, customValues = {}, name = self.playerName) inventory = {}, customValues = {}, name = self.playerName)
#print("Player created.") #print("Player created.")
else: else:
self.player.x, self.player.y = x, y self.player.x, self.player.y = mx, my
#print("Player moved.") #print("Player moved.")
self.player.prevx, self.player.prevy = self.player.x, self.player.y 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.nextThing) # The player needs to be added to the new level.
@ -559,6 +559,7 @@ Object can be the name of the object, or its coordinates."""
# any map. This is useful for when you have major characters who will # 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 # show up in many scenes, and their inventory must stay the same, for
# example. # example.
self.singletons = {}
if 'singletons' in data: if 'singletons' in data:
for thing in data['singletons']: for thing in data['singletons']:
#thing = data['singletons'][datum] #thing = data['singletons'][datum]
@ -576,7 +577,7 @@ Object can be the name of the object, or its coordinates."""
self.nextThing = _gm.GameMap.addThingRecursive(i.customValues, self.nextThing + 1) self.nextThing = _gm.GameMap.addThingRecursive(i.customValues, self.nextThing + 1)
thing.addThing(i) thing.addThing(i)
del thing.tempInventory del thing.tempInventory
self.singletons = list(data['singletons']) self.singletons[thing.name] = thing
return data return data
def gameEventLoop(self): def gameEventLoop(self):

View file

@ -5,6 +5,38 @@ import ruamel.yaml
import math as _mt import math as _mt
import gamethings as _gt import gamethings as _gt
import gamelocus as _gl 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): class MapError(RuntimeError):
pass pass
@ -24,6 +56,7 @@ class GameMap(object):
yaml.register_class(_gt.Door) yaml.register_class(_gt.Door)
yaml.register_class(_gt.MapExit) yaml.register_class(_gt.MapExit)
yaml.register_class(_gt.MapEntrance) yaml.register_class(_gt.MapEntrance)
yaml.register_class(Singleton)
def __init__(self, name, graph, matrix, dimensions): def __init__(self, name, graph, matrix, dimensions):
self.name = name self.name = name
@ -63,7 +96,7 @@ class GameMap(object):
return text.replace('\n', end) return text.replace('\n', end)
@staticmethod @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 """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. 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.""" 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) level = GameMap(infile, mapGraph, mapMatrix, dimensions)
# Now, load other info # Now, load other info
nextThing = GameMap.loadThings(level, info, prevMap, preLoaded, nextThing) nextThing = GameMap.loadThings(level, info, prevMap, singletons, preLoaded, nextThing)
return level, nextThing return level, nextThing
@ -171,7 +204,7 @@ list of lists of tuples."""
return mat, graph, dim return mat, graph, dim
@staticmethod @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.""" """load the things from the xml part of the map file."""
if 'openingText' in info: if 'openingText' in info:
level.openingText = info['openingText'] level.openingText = info['openingText']
@ -197,20 +230,32 @@ list of lists of tuples."""
if 'loadOnce' in info and not preLoaded: if 'loadOnce' in info and not preLoaded:
for thing in info['loadOnce']: for thing in info['loadOnce']:
#print(type(thing)) #print(type(thing))
if isinstance(thing, _gt.Thing):
nextThing = level.addThing(thing, nextThing, True) nextThing = level.addThing(thing, nextThing, True)
else:
raise MapError("Non-thing loaded as a thing:\n{}".format(thing))
if 'loadAlways' in info: if 'loadAlways' in info:
for thing in info['loadAlways']: for thing in info['loadAlways']:
#print(type(thing)) #print(type(thing))
if isinstance(thing, _gt.Thing):
nextThing = level.addThing(thing, nextThing) nextThing = level.addThing(thing, nextThing)
if ((thing.thingType == 'x' and not hasKnownEntrance) or thing.thingType == 'a') and prevMap == thing.exitid: if ((thing.thingType == 'x' and not hasKnownEntrance) or thing.thingType == 'a') and prevMap == thing.exitid:
level.playerStart = (thing.x, thing.y) level.playerStart = (thing.x, thing.y)
hasKnownEntrance = True 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 return nextThing
# stuff the gameshell itself might use # stuff the gameshell itself might use
def addThing(self, thing, nextThing = 0, persist = False): def addThing(self, thing, nextThing = 0, persist = False):
if thing == None: if thing == None: # it must be a singleton
return nextThing return nextThing
#if thing.name in self.thingNames: # resolved #if thing.name in self.thingNames: # resolved
# raise ValueError("Cannot have two objects named {0}.".format(thing.name)) # raise ValueError("Cannot have two objects named {0}.".format(thing.name))
@ -219,6 +264,7 @@ list of lists of tuples."""
nextThing += 1 nextThing += 1
# Some things, like containers, have other things as custom values, # Some things, like containers, have other things as custom values,
# so they need IDs as well. # so they need IDs as well.
# Let's only add them if they weren't already loaded.
if thing.thingType in 'iun': if thing.thingType in 'iun':
nextThing = GameMap.addThingRecursive(thing.customValues, nextThing) nextThing = GameMap.addThingRecursive(thing.customValues, nextThing)
if thing.thingType == 'n': if thing.thingType == 'n':

View file

@ -51,15 +51,6 @@ loadAlways:
none: none # might this work to prevent this character from doing anything? none: none # might this work to prevent this character from doing anything?
customValues: customValues:
dialogs: testing/testDialog.yml dialogs: testing/testDialog.yml
- !NPC - !Singleton
name: follower name: follower
description: a follower
location: [6, 26] location: [6, 26]
behaviors:
go: [-1, follow]
arrive: [-1, follow]
customValues:
follow:
distance: 2
isFollowing: True
target: You # yes, YOU!