Added simple scripting for yaml files.
This commit is contained in:
parent
8355dccb33
commit
b332d579e9
6 changed files with 506 additions and 4 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@ maps
|
||||||
saves
|
saves
|
||||||
__pycache__
|
__pycache__
|
||||||
gameshell.geany
|
gameshell.geany
|
||||||
|
gameexpr.py
|
||||||
|
|
484
gamebase.py
484
gamebase.py
|
@ -25,6 +25,7 @@ class GameBase(object):
|
||||||
self.__behaviors = {}
|
self.__behaviors = {}
|
||||||
self.__gameEvents = {}
|
self.__gameEvents = {}
|
||||||
self.__IOCalls = {} # {str : function}
|
self.__IOCalls = {} # {str : function}
|
||||||
|
self.__scripts = {} # functions with the same signature, but not callable by the user
|
||||||
self.customValues = {} # for setting flags and such
|
self.customValues = {} # for setting flags and such
|
||||||
self.level = None
|
self.level = None
|
||||||
self.persist = {} # {level : {thingName : thing}}
|
self.persist = {} # {level : {thingName : thing}}
|
||||||
|
@ -61,6 +62,11 @@ class GameBase(object):
|
||||||
self.registerUseFunc('info', self.info)
|
self.registerUseFunc('info', self.info)
|
||||||
self.registerUseFunc('wear', self.wear)
|
self.registerUseFunc('wear', self.wear)
|
||||||
self.registerBehavior('wander', self.wander)
|
self.registerBehavior('wander', self.wander)
|
||||||
|
self.registerScript('if', self.ifScript)
|
||||||
|
self.registerScript('printf', self.printfScript)
|
||||||
|
self.registerScript('set', self.setCustomValue)
|
||||||
|
self.registerScript('spawn', self.spawnThing)
|
||||||
|
self.registerScript('give', self.giveToPlayer)
|
||||||
|
|
||||||
# Helper functions
|
# Helper functions
|
||||||
|
|
||||||
|
@ -175,6 +181,60 @@ Returns (thing, x, y). "Thing" can be None."""
|
||||||
|
|
||||||
return '\n'.join(ret)
|
return '\n'.join(ret)
|
||||||
|
|
||||||
|
def getValueFromString(self, arg: str):
|
||||||
|
val = None
|
||||||
|
validIdent = _re.match(r'[_A-Za-z][_0-9A-Za-z]*', arg)
|
||||||
|
if arg[0] in '"\'': # assume it's a string
|
||||||
|
val = arg[1:-1]
|
||||||
|
elif _re.match(r'[+-]?(?:[0-9]*[.])?[0-9]+', arg) != None:
|
||||||
|
if '.' in arg:
|
||||||
|
val = float(arg)
|
||||||
|
else:
|
||||||
|
val = int(arg)
|
||||||
|
elif arg.casefold() == 'true':
|
||||||
|
val = True
|
||||||
|
elif arg.casefold() == 'false':
|
||||||
|
val = False
|
||||||
|
elif arg.casefold() == 'playerx':
|
||||||
|
val = self.playerx
|
||||||
|
elif arg.casefold() == 'playery':
|
||||||
|
val = self.playery
|
||||||
|
elif arg.casefold() == 'playername':
|
||||||
|
val = self.playerName
|
||||||
|
elif arg.casefold() == 'playerinv':
|
||||||
|
val = self.playerInv
|
||||||
|
elif validIdent != None:
|
||||||
|
if 'scriptLocal' in self.customValues and validIdent.group() in self.customValues['scriptLocal']:
|
||||||
|
val = self.customValues['scriptLocal'][arg]
|
||||||
|
elif validIdent.group() in self.customValues:
|
||||||
|
val = self.customValues[arg]
|
||||||
|
else:
|
||||||
|
return False # for if statements; if a variable doesn't exist, should evaluate to False
|
||||||
|
# evaluate all values of all indecies
|
||||||
|
if validIdent.end() < len(arg):
|
||||||
|
if arg[validIdent.end()] == '[':
|
||||||
|
openBracket = validIdent.end()
|
||||||
|
ptr = openBracket
|
||||||
|
depth = 0
|
||||||
|
while ptr < len(arg):
|
||||||
|
if ptr == '[':
|
||||||
|
depth += 1
|
||||||
|
elif ptr == ']':
|
||||||
|
depth -= 1
|
||||||
|
if depth == 0:
|
||||||
|
var = var[self.getValueFromString(arg[openBracket+1:ptr])]
|
||||||
|
openBracket = ptr + 1
|
||||||
|
ptr += 1
|
||||||
|
if depth == 0 and arg[ptr] != '[':
|
||||||
|
raise GameError('Invalid value syntax: {}'.format(arg))
|
||||||
|
else:
|
||||||
|
raise GameError('Invalid value syntax: {}'.format(arg))
|
||||||
|
else:
|
||||||
|
raise GameError('Invalid argument to getValueFromString: {}'.format(arg))
|
||||||
|
return val
|
||||||
|
|
||||||
|
# commands
|
||||||
|
|
||||||
def go(self, args):
|
def go(self, args):
|
||||||
"""go [-r] [to [the]] destination [additional arguments...]
|
"""go [-r] [to [the]] destination [additional arguments...]
|
||||||
Go to a location. "walk" and "move" are aliases of go.
|
Go to a location. "walk" and "move" are aliases of go.
|
||||||
|
@ -486,6 +546,7 @@ Object can be the name of the object, or its coordinates."""
|
||||||
self.prevx, self.prevy = self.playerx, self.playery
|
self.prevx, self.prevy = self.playerx, self.playery
|
||||||
if self.onLevelLoad != None:
|
if self.onLevelLoad != None:
|
||||||
self.onLevelLoad()
|
self.onLevelLoad()
|
||||||
|
self.parseScript(self.level.enterScript)
|
||||||
|
|
||||||
def saveGame(self, args):
|
def saveGame(self, args):
|
||||||
if len(args) < 1:
|
if len(args) < 1:
|
||||||
|
@ -541,13 +602,86 @@ Object can be the name of the object, or its coordinates."""
|
||||||
#_hq.heappush(self.eventQueue, (self.gameTime, _ge.NoOpEvent()))
|
#_hq.heappush(self.eventQueue, (self.gameTime, _ge.NoOpEvent()))
|
||||||
return
|
return
|
||||||
|
|
||||||
def dialog(self, dialogName, conversant):
|
def dialog(self, dialogName, conversant = None):
|
||||||
yaml = _yaml.YAML()
|
yaml = _yaml.YAML()
|
||||||
dialog = None
|
dialog = None
|
||||||
with open(dialogName, 'r') as f:
|
with open(dialogName, 'r') as f:
|
||||||
dialog = yaml.load(f)
|
dialog = yaml.load(f)
|
||||||
self.getIO('dialog')(dialog)
|
self.getIO('dialog')(dialog)
|
||||||
|
|
||||||
|
def parseScript(self, instr: str):
|
||||||
|
"""parses then runs a script."""
|
||||||
|
#print('parseScript called with {}.'.format(instr))
|
||||||
|
if instr == '':
|
||||||
|
return # nothing to be done.
|
||||||
|
literalStr = list(instr)
|
||||||
|
inQuotes = False
|
||||||
|
script = []
|
||||||
|
stack = []
|
||||||
|
ret = []
|
||||||
|
argStart = 0
|
||||||
|
c = 0
|
||||||
|
l = 0
|
||||||
|
while c < len(instr):
|
||||||
|
if inQuotes:
|
||||||
|
if instr[c] == '"':
|
||||||
|
if instr[c-1] == '\\':
|
||||||
|
del literalStr[l-1]
|
||||||
|
l -= 1
|
||||||
|
else:
|
||||||
|
inQuotes = False
|
||||||
|
del literalStr[l]
|
||||||
|
l -= 1
|
||||||
|
else:
|
||||||
|
if instr[c] == '"': # quoted string
|
||||||
|
if l > 0 and instr[c-1] == '\\':
|
||||||
|
del literalStr[l-1]
|
||||||
|
l -= 1
|
||||||
|
else:
|
||||||
|
inQuotes = True
|
||||||
|
del literalStr[l]
|
||||||
|
l -= 1
|
||||||
|
elif instr[c] in ' \t\n;}{':
|
||||||
|
if argStart != l:
|
||||||
|
ret.append(''.join(literalStr[argStart:l]))
|
||||||
|
if instr[c] == ';':
|
||||||
|
script.append(ret)
|
||||||
|
ret = []
|
||||||
|
elif instr[c] == '{': # block
|
||||||
|
stack.append(script)
|
||||||
|
script.append(ret)
|
||||||
|
script = []
|
||||||
|
ret.append(script)
|
||||||
|
ret = []
|
||||||
|
del literalStr[l]
|
||||||
|
l -= 1
|
||||||
|
elif instr[c] == '}': # close block
|
||||||
|
if len(ret) > 0:
|
||||||
|
script.append(ret)
|
||||||
|
script = stack.pop()
|
||||||
|
ret = []
|
||||||
|
del literalStr[l]
|
||||||
|
l -= 1
|
||||||
|
argStart = l + 1
|
||||||
|
c += 1
|
||||||
|
l += 1
|
||||||
|
if argStart != l:
|
||||||
|
ret.append(''.join(literalStr[argStart:l]))
|
||||||
|
script.append(ret)
|
||||||
|
#print('After parsing: {}'.format(script))
|
||||||
|
self.customValues['scriptLocal'] = {}
|
||||||
|
self.runScript(script)
|
||||||
|
del self.customValues['scriptLocal']
|
||||||
|
|
||||||
|
def runScript(self, script: list):
|
||||||
|
"""run a script"""
|
||||||
|
for line in script:
|
||||||
|
if line[0].casefold() == 'playercmd':
|
||||||
|
# run a player command
|
||||||
|
self.getIO('playercmd')(line[1:])
|
||||||
|
else:
|
||||||
|
self.__scripts[line[0]](line[1:])
|
||||||
|
|
||||||
def gameEventLoop(self):
|
def gameEventLoop(self):
|
||||||
#print(self.skipLoop)
|
#print(self.skipLoop)
|
||||||
if self.skipLoop:
|
if self.skipLoop:
|
||||||
|
@ -727,6 +861,350 @@ Object can be the name of the object, or its coordinates."""
|
||||||
print("The key doesn't fit that lock.", file = self.outstream)
|
print("The key doesn't fit that lock.", file = self.outstream)
|
||||||
return 0.125
|
return 0.125
|
||||||
|
|
||||||
|
# default scripts
|
||||||
|
|
||||||
|
def ifScript(self, args):
|
||||||
|
"""If statement: if [not] value [op value] script"""
|
||||||
|
if len(args) < 2:
|
||||||
|
raise GameError('Incomplete If statement: if {}'.format(' '.join(args)))
|
||||||
|
inverse = False
|
||||||
|
ret = False
|
||||||
|
if args[0] == 'not':
|
||||||
|
inverse = True
|
||||||
|
args.pop(0)
|
||||||
|
if len(args) < 2:
|
||||||
|
raise GameError('Incomplete If statement: if {}'.format(' '.join(args)))
|
||||||
|
|
||||||
|
# evaluate condition
|
||||||
|
val = self.parseValue(args[0])
|
||||||
|
if args[1] in ('==', '!=', '<=', '>=', '<', '>'):
|
||||||
|
if len(args) < 4:
|
||||||
|
raise GameError('Incomplete If statement: if {}'.format(' '.join(args)))
|
||||||
|
val2 = self.parseValue(args[2])
|
||||||
|
if args[1] == '==':
|
||||||
|
ret = val == val2
|
||||||
|
elif args[1] == '!=':
|
||||||
|
ret = val != val2
|
||||||
|
elif args[1] == '<=':
|
||||||
|
ret = val <= val2
|
||||||
|
elif args[1] == '>=':
|
||||||
|
ret = val >= val2
|
||||||
|
elif args[1] == '<':
|
||||||
|
ret = val < val2
|
||||||
|
elif args[1] == '>':
|
||||||
|
ret = val > val2
|
||||||
|
args = args[3:]
|
||||||
|
else:
|
||||||
|
ret = bool(val)
|
||||||
|
args = args[1:]
|
||||||
|
if inverse:
|
||||||
|
ret = not ret
|
||||||
|
|
||||||
|
# if condition is true, evaluate further
|
||||||
|
if ret:
|
||||||
|
if isinstance(args[-1], list):
|
||||||
|
self.runScript(args[-1])
|
||||||
|
else:
|
||||||
|
self.runScript([args])
|
||||||
|
|
||||||
|
def printfScript(self, args):
|
||||||
|
"""Assume the first argument is a stringable object, and format all others."""
|
||||||
|
print(args[0].format(*[self.getValueFromString(i) for i in args[1:]]), file = self.outstream)
|
||||||
|
|
||||||
|
def setCustomValue(self, args):
|
||||||
|
"""takes [customValue, op, value]"""
|
||||||
|
env = self.customValues
|
||||||
|
if len(args) > 0 and args[0] == 'local':
|
||||||
|
if 'scriptLocal' in self.customValues:
|
||||||
|
env = self.customValues['scriptLocal']
|
||||||
|
else:
|
||||||
|
raise GameError('Attempted to set a local variable without local scope.')
|
||||||
|
args.pop(0)
|
||||||
|
if len(args) < 3 or args[1] not in ('=', '+=', '-=', '*=', '/=', '%=', '//=', '**=', 'b=', '!=', '|=', '&=', '^='):
|
||||||
|
raise GameError('Arguments are not fit for the setCustomValue script.')
|
||||||
|
val = self.getValueFromString(args[2])
|
||||||
|
|
||||||
|
# set the value to a default value (0, 0.0, '', etc.) if not yet assigned
|
||||||
|
if args[0] not in env and args[1] != '=':
|
||||||
|
if isinstance(val, int):
|
||||||
|
env[args[0]] = 0
|
||||||
|
elif isinstance(val, float):
|
||||||
|
env[args[0]] = 0.0
|
||||||
|
elif isinstance(val, str):
|
||||||
|
env[args[0]] = ''
|
||||||
|
elif isinstance(val, bool):
|
||||||
|
env[args[0]] = False
|
||||||
|
# Beyond this point are types that can only be found from other customValues
|
||||||
|
elif isinstance(val, tuple):
|
||||||
|
env[args[0]] = ()
|
||||||
|
elif isinstance(val, list):
|
||||||
|
env[args[0]] = []
|
||||||
|
elif isinstance(val, dict):
|
||||||
|
env[args[0]] = {}
|
||||||
|
else:
|
||||||
|
raise GameError("Operation not supported for unassigned custom values of type {}: {}"
|
||||||
|
.format(type(val), args[1]))
|
||||||
|
|
||||||
|
# done parsing, evaluate
|
||||||
|
if args[1] == '=':
|
||||||
|
env[args[0]] = val
|
||||||
|
elif args[1] == '+=':
|
||||||
|
env[args[0]] += val
|
||||||
|
elif args[1] == '-=':
|
||||||
|
env[args[0]] -= val
|
||||||
|
elif args[1] == '*=':
|
||||||
|
env[args[0]] *= val
|
||||||
|
elif args[1] == '/=':
|
||||||
|
env[args[0]] /= val
|
||||||
|
elif args[1] == '%=':
|
||||||
|
env[args[0]] %= val
|
||||||
|
elif args[1] == '//=':
|
||||||
|
env[args[0]] //= val
|
||||||
|
elif args[1] == '**=':
|
||||||
|
env[args[0]] **= val
|
||||||
|
elif args[1] == 'b=':
|
||||||
|
env[args[0]] = bool(val)
|
||||||
|
elif args[1] == '!=':
|
||||||
|
env[args[0]] = not bool(val)
|
||||||
|
elif args[1] == '|=':
|
||||||
|
env[args[0]] |= val
|
||||||
|
elif args[1] == '&=':
|
||||||
|
env[args[0]] &= val
|
||||||
|
elif args[1] == '^=':
|
||||||
|
env[args[0]] ^= val
|
||||||
|
|
||||||
|
def spawnThing(self, args):
|
||||||
|
"""Spawns a thing. [type name=... location=... etc]"""
|
||||||
|
if args[0].casefold() not in ('item', 'useable', 'npc', 'door', 'mapexit', 'mapentrance'):
|
||||||
|
raise GameError("{} not a spawnable thing type.".format(args[0]))
|
||||||
|
|
||||||
|
# Get the standard fields that most Things have in common: name, coordinates, graphic.
|
||||||
|
name = None
|
||||||
|
x, y = -1, -1
|
||||||
|
fgc, bgc, shape = None, None, None
|
||||||
|
persist = False
|
||||||
|
for i in args[1:]:
|
||||||
|
if i[0:5].casefold() == 'name=':
|
||||||
|
name = i[5:]
|
||||||
|
elif i[0:10].casefold() == 'location=':
|
||||||
|
_, x, y = self.parseCoords(i[10:].split())
|
||||||
|
elif i[0:4].casefold() == 'fgc=':
|
||||||
|
if len(i[4:]) != 7 or i[0] != '#':
|
||||||
|
raise GameError("Invalid color: {}".format(i[4:]))
|
||||||
|
for j in i[4:]:
|
||||||
|
if j not in '0123456789abcdefABCDEF':
|
||||||
|
raise GameError("Invalid color: {}".format(i[4:]))
|
||||||
|
fgc = i[4:]
|
||||||
|
elif i[0:4].casefold() == 'bgc=':
|
||||||
|
if len(i[4:]) != 7 or i[0] != '#':
|
||||||
|
raise GameError("Invalid color: {}".format(i[4:]))
|
||||||
|
for j in i[4:]:
|
||||||
|
if j not in '0123456789abcdefABCDEF':
|
||||||
|
raise GameError("Invalid color: {}".format(i[4:]))
|
||||||
|
bgc = i[4:]
|
||||||
|
elif i[0:6].casefold() == 'shape=':
|
||||||
|
if len(i[6:]) != 7 or i[0] != '#':
|
||||||
|
raise GameError("Invalid color: {}".format(i[6:]))
|
||||||
|
for j in i[6:]:
|
||||||
|
if j not in '0123456789abcdefABCDEF':
|
||||||
|
raise GameError("Invalid color: {}".format(i[6:]))
|
||||||
|
shape = i[6:]
|
||||||
|
elif i == 'persist':
|
||||||
|
persist = True
|
||||||
|
if x < 0 or y < 0:
|
||||||
|
raise GameError("Cannot spawn thing: bad location")
|
||||||
|
|
||||||
|
# Unfortunately, there needs to be a case for each type.
|
||||||
|
if args[0].casefold() == 'item':
|
||||||
|
# spawn an item
|
||||||
|
description = 'A nondescript item.'
|
||||||
|
useFunc = ''
|
||||||
|
useOnFunc = ''
|
||||||
|
customValues = {}
|
||||||
|
ranged = False
|
||||||
|
if name == None:
|
||||||
|
name = 'item {}'.format(self.nextThing)
|
||||||
|
if fgc == None:
|
||||||
|
fgc = _gm.Item.defaultGraphic['fgc']
|
||||||
|
if bgc == None:
|
||||||
|
bgc = _gm.Item.defaultGraphic['bgc']
|
||||||
|
if shape == None:
|
||||||
|
shape = _gm.Item.defaultGraphic['shape']
|
||||||
|
for i in args[1:]:
|
||||||
|
if i[0:12].casefold() == 'description=':
|
||||||
|
description = i[12:]
|
||||||
|
elif i[0:8].casefold() == 'usefunc=':
|
||||||
|
useFunc = i[8:]
|
||||||
|
elif i[0:10].casefold() == 'useonfunc=':
|
||||||
|
useOnFunc = i[10:]
|
||||||
|
elif i.casefold() == 'ranged':
|
||||||
|
ranged = True
|
||||||
|
elif i[0:3].casefold() == 'cv:':
|
||||||
|
equalsign = i.index('=')
|
||||||
|
cv = i[3:equalsign]
|
||||||
|
customValues[cv] = getValueFromString(i[equalsign+1:])
|
||||||
|
thing = _gm.Item(name, x, y, description, useFunc, useOnFunc, customValues, ranged, (bgc, fgc, shape))
|
||||||
|
self.nextThing = self.level.addThing(thing, self.nextThing, persist)
|
||||||
|
elif args[0].casefold() == 'useable':
|
||||||
|
# spawn a useable thing
|
||||||
|
description = 'A nondescript useable thing.'
|
||||||
|
useFunc = ''
|
||||||
|
customValues = {}
|
||||||
|
playerx, playery = x, y
|
||||||
|
if name == None:
|
||||||
|
name = 'useable {}'.format(self.nextThing)
|
||||||
|
if fgc == None:
|
||||||
|
fgc = _gm.Item.defaultGraphic['fgc']
|
||||||
|
if bgc == None:
|
||||||
|
bgc = _gm.Item.defaultGraphic['bgc']
|
||||||
|
if shape == None:
|
||||||
|
shape = _gm.Item.defaultGraphic['shape']
|
||||||
|
for i in args[1:]:
|
||||||
|
if i[0:12].casefold() == 'description=':
|
||||||
|
description = i[12:]
|
||||||
|
elif i[0:8].casefold() == 'usefunc=':
|
||||||
|
useFunc = i[8:]
|
||||||
|
elif i[0:10].casefold() == 'playerpos=':
|
||||||
|
_, playerx, playery = self.parseCoords(i[10:].split())
|
||||||
|
elif i[0:3].casefold() == 'cv:':
|
||||||
|
equalsign = i.index('=')
|
||||||
|
cv = i[3:equalsign]
|
||||||
|
customValues[cv] = getValueFromString(i[equalsign+1:])
|
||||||
|
thing = _gm.Useable(name, x, y, description, useFunc, customValues, playerx, playery, (bgc, fgc, shape))
|
||||||
|
self.nextThing = self.level.addThing(thing, self.nextThing, persist)
|
||||||
|
elif args[0].casefold() == 'npc':
|
||||||
|
# spawn an NPC
|
||||||
|
description = 'A nondescript character.'
|
||||||
|
behavior = ''
|
||||||
|
inv = []
|
||||||
|
customValues = {}
|
||||||
|
playerx, playery = x, y
|
||||||
|
if name == None:
|
||||||
|
name = 'character {}'.format(self.nextThing)
|
||||||
|
if fgc == None:
|
||||||
|
fgc = _gm.Item.defaultGraphic['fgc']
|
||||||
|
if bgc == None:
|
||||||
|
bgc = _gm.Item.defaultGraphic['bgc']
|
||||||
|
if shape == None:
|
||||||
|
shape = _gm.Item.defaultGraphic['shape']
|
||||||
|
for i in args[1:]:
|
||||||
|
if i[0:12].casefold() == 'description=':
|
||||||
|
description = i[12:]
|
||||||
|
elif i[0:9].casefold() == 'behavior=':
|
||||||
|
useFunc = i[9:]
|
||||||
|
elif i[0:10].casefold() == 'playerpos=':
|
||||||
|
_, playerx, playery = self.parseCoords(i[10:].split())
|
||||||
|
elif i[0:3].casefold() == 'cv:':
|
||||||
|
equalsign = i.index('=')
|
||||||
|
cv = i[3:equalsign]
|
||||||
|
customValues[cv] = getValueFromString(i[equalsign+1:])
|
||||||
|
thing = _gm.NPC(name, x, y, description, behavior, inv, customValues, playerx, playery, False, (bgc, fgc, shape))
|
||||||
|
self.nextThing = self.level.addThing(thing, self.nextThing, persist)
|
||||||
|
elif args[0].casefold() == 'door':
|
||||||
|
# spawn a door
|
||||||
|
description = 'a nondescript door.'
|
||||||
|
locked = False
|
||||||
|
key = None
|
||||||
|
if name == None:
|
||||||
|
name = 'door {}'.format(self.nextThing)
|
||||||
|
if fgc == None:
|
||||||
|
fgc = _gm.Item.defaultGraphic['fgc']
|
||||||
|
if bgc == None:
|
||||||
|
bgc = _gm.Item.defaultGraphic['bgc']
|
||||||
|
if shape == None:
|
||||||
|
shape = _gm.Item.defaultGraphic['shape']
|
||||||
|
for i in args[1:]:
|
||||||
|
if i[0:12].casefold() == 'description=':
|
||||||
|
description = i[12:]
|
||||||
|
elif i.casefold() == 'locked':
|
||||||
|
locked = True
|
||||||
|
thing = _gm.Door(name, x, y, locked, description, key, (bgc, fgc, shape))
|
||||||
|
self.nextThing = self.level.addThing(thing, self.nextThing, persist)
|
||||||
|
elif args[0].casefold() == 'mapexit':
|
||||||
|
# spawn an exit to another map (use with EXTREME caution!)
|
||||||
|
destination = ''
|
||||||
|
prefix = None
|
||||||
|
exitid = 0
|
||||||
|
if name == None:
|
||||||
|
name = 'somewhere'
|
||||||
|
if fgc == None:
|
||||||
|
fgc = _gm.Item.defaultGraphic['fgc']
|
||||||
|
if bgc == None:
|
||||||
|
bgc = _gm.Item.defaultGraphic['bgc']
|
||||||
|
if shape == None:
|
||||||
|
shape = _gm.Item.defaultGraphic['shape']
|
||||||
|
for i in args[1:]:
|
||||||
|
if i[0:12].casefold() == 'destination=':
|
||||||
|
destination = i[12:]
|
||||||
|
elif i[0:7].casefold() == 'prefix=':
|
||||||
|
prefix = i[7:]
|
||||||
|
elif i[0:7].casefold() == 'exitid=':
|
||||||
|
exitid = int(i[7:])
|
||||||
|
thing = _gm.MapExit(name, x, y, exitid, destination, prefix, (bgc, fgc, shape))
|
||||||
|
self.nextThing = self.level.addThing(thing, self.nextThing, persist)
|
||||||
|
elif args[0].casefold() == 'mapentrance':
|
||||||
|
# spawn a map entrance
|
||||||
|
exitid = 0
|
||||||
|
for i in args[1:]:
|
||||||
|
if i[0:7].casefold() == 'exitid=':
|
||||||
|
exitid = int(i[7:])
|
||||||
|
thing = _gm.MapEntrance(x, y, exitid, name)
|
||||||
|
self.nextThing = self.level.addThing(thing, self.nextThing, persist)
|
||||||
|
|
||||||
|
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 = _gm.Item.defaultGraphic['fgc'], _gm.Item.defaultGraphic['bgc'], _gm.Item.defaultGraphic['shape']
|
||||||
|
description = 'A nondescript item.'
|
||||||
|
persist = True
|
||||||
|
useFunc = ''
|
||||||
|
useOnFunc = ''
|
||||||
|
customValues = {}
|
||||||
|
ranged = False
|
||||||
|
for i in args[1:]:
|
||||||
|
if i[0:5].casefold() == 'name=':
|
||||||
|
name = i[5:]
|
||||||
|
elif i[0:10].casefold() == 'location=':
|
||||||
|
_, x, y = self.parseCoords(i[10:].split())
|
||||||
|
elif i[0:4].casefold() == 'fgc=':
|
||||||
|
if len(i[4:]) != 7 or i[0] != '#':
|
||||||
|
raise GameError("Invalid color: {}".format(i[4:]))
|
||||||
|
for j in i[4:]:
|
||||||
|
if j not in '0123456789abcdefABCDEF':
|
||||||
|
raise GameError("Invalid color: {}".format(i[4:]))
|
||||||
|
fgc = i[4:]
|
||||||
|
elif i[0:4].casefold() == 'bgc=':
|
||||||
|
if len(i[4:]) != 7 or i[0] != '#':
|
||||||
|
raise GameError("Invalid color: {}".format(i[4:]))
|
||||||
|
for j in i[4:]:
|
||||||
|
if j not in '0123456789abcdefABCDEF':
|
||||||
|
raise GameError("Invalid color: {}".format(i[4:]))
|
||||||
|
bgc = i[4:]
|
||||||
|
elif i[0:6].casefold() == 'shape=':
|
||||||
|
if len(i[6:]) != 7 or i[0] != '#':
|
||||||
|
raise GameError("Invalid color: {}".format(i[6:]))
|
||||||
|
for j in i[6:]:
|
||||||
|
if j not in '0123456789abcdefABCDEF':
|
||||||
|
raise GameError("Invalid color: {}".format(i[6:]))
|
||||||
|
shape = i[6:]
|
||||||
|
elif i == 'persist':
|
||||||
|
persist = True
|
||||||
|
elif i[0:12].casefold() == 'description=':
|
||||||
|
description = i[12:]
|
||||||
|
elif i[0:8].casefold() == 'usefunc=':
|
||||||
|
useFunc = i[8:]
|
||||||
|
elif i[0:10].casefold() == 'useonfunc=':
|
||||||
|
useOnFunc = i[10:]
|
||||||
|
elif i.casefold() == 'ranged':
|
||||||
|
ranged = True
|
||||||
|
elif i[0:3].casefold() == 'cv:':
|
||||||
|
equalsign = i.index('=')
|
||||||
|
cv = i[3:equalsign]
|
||||||
|
customValues[cv] = getValueFromString(i[equalsign+1:])
|
||||||
|
thing = _gm.Item(name, x, y, description, useFunc, useOnFunc, customValues, ranged, (bgc, fgc, shape))
|
||||||
|
self.nextThing = self.level.addThing(thing, self.nextThing, persist)
|
||||||
|
|
||||||
# behaviors
|
# behaviors
|
||||||
|
|
||||||
def wander(self, actor):
|
def wander(self, actor):
|
||||||
|
@ -752,6 +1230,10 @@ always give the player a turn, False otherwise."""
|
||||||
"""Registers a function for useFuncs and such to use."""
|
"""Registers a function for useFuncs and such to use."""
|
||||||
self.__IOCalls[name] = func
|
self.__IOCalls[name] = func
|
||||||
|
|
||||||
|
def registerScript(self, name, func):
|
||||||
|
"""Registers a function as a script callable from yaml files."""
|
||||||
|
self.__scripts[name] = func
|
||||||
|
|
||||||
def getIO(self, name):
|
def getIO(self, name):
|
||||||
"""This is so derived classes can access their IOCalls."""
|
"""This is so derived classes can access their IOCalls."""
|
||||||
if name not in self.__IOCalls:
|
if name not in self.__IOCalls:
|
||||||
|
|
10
gamemap.py
10
gamemap.py
|
@ -411,11 +411,12 @@ class MapExit(Thing):
|
||||||
|
|
||||||
class MapEntrance(Thing):
|
class MapEntrance(Thing):
|
||||||
yaml_flag = u'!MapEntrance'
|
yaml_flag = u'!MapEntrance'
|
||||||
|
defaultGraphic = ('clear', 'clear', 'x')
|
||||||
# no graphic - should not be drawn
|
# no graphic - should not be drawn
|
||||||
|
|
||||||
def __init__(self, x: int, y: int, exitid: int):
|
def __init__(self, x: int, y: int, exitid: int, name = None):
|
||||||
if prefix:
|
if name == None:
|
||||||
description = "{0} {1}".format(prefix, name)
|
name = 'entrance {}'.format(exitid)
|
||||||
super(MapEntrance, self).__init__('a', name, x, y, description, 1)
|
super(MapEntrance, self).__init__('a', name, x, y, description, 1)
|
||||||
self.exitid = exitid
|
self.exitid = exitid
|
||||||
|
|
||||||
|
@ -458,6 +459,7 @@ class GameMap(object):
|
||||||
self.floorColors = []
|
self.floorColors = []
|
||||||
self.wallColors = []
|
self.wallColors = []
|
||||||
self.persistent = []
|
self.persistent = []
|
||||||
|
self.enterScript = ''
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __cleanStr(text: str, end = '\n'):
|
def __cleanStr(text: str, end = '\n'):
|
||||||
|
@ -674,6 +676,8 @@ list of lists of tuples."""
|
||||||
level.playerStart = info['playerStart']
|
level.playerStart = info['playerStart']
|
||||||
if 'description' in info:
|
if 'description' in info:
|
||||||
level.description = info['description']
|
level.description = info['description']
|
||||||
|
if 'enterScript' in info:
|
||||||
|
level.enterScript = info['enterScript']
|
||||||
|
|
||||||
# get map colors
|
# get map colors
|
||||||
if 'floorColors' in info:
|
if 'floorColors' in info:
|
||||||
|
|
12
gameshell.py
12
gameshell.py
|
@ -155,6 +155,8 @@ If -l is given, a map legend will be printed under the map."""
|
||||||
elif thing.thingType == 'i': # item
|
elif thing.thingType == 'i': # item
|
||||||
items[len(items)+1] = (thing.name, thing.graphic[1])
|
items[len(items)+1] = (thing.name, thing.graphic[1])
|
||||||
rows[-1].append('I{0}'.format(len(items)))
|
rows[-1].append('I{0}'.format(len(items)))
|
||||||
|
elif thing.thingType == 'a': # entrance
|
||||||
|
rows[-1].append(' ')
|
||||||
elif pos[0] == 'w':
|
elif pos[0] == 'w':
|
||||||
if level.wallColors[level.mapMatrix[y][x][1]] != textColor:
|
if level.wallColors[level.mapMatrix[y][x][1]] != textColor:
|
||||||
textColor = level.wallColors[level.mapMatrix[y][x][1]]
|
textColor = level.wallColors[level.mapMatrix[y][x][1]]
|
||||||
|
@ -210,6 +212,9 @@ If -l is given, a map legend will be printed under the map."""
|
||||||
ret.append("Event queue:")
|
ret.append("Event queue:")
|
||||||
for i in sorted(self.gameBase.eventQueue):
|
for i in sorted(self.gameBase.eventQueue):
|
||||||
ret.append("{0:.<8.3}:{1:.>72}".format(i[0], str(i[1])))
|
ret.append("{0:.<8.3}:{1:.>72}".format(i[0], str(i[1])))
|
||||||
|
ret.append("custom values:")
|
||||||
|
for i in self.gameBase.customValues:
|
||||||
|
ret.append("{0:<22}: {1}".format(i, self.gameBase.customValues[i]))
|
||||||
ret.append("Player name:{0:.>68}".format(self.gameBase.playerName))
|
ret.append("Player name:{0:.>68}".format(self.gameBase.playerName))
|
||||||
ret.append("Player position:{0:.>64}".format("{0}{1}".format(self.gameBase.numberToLetter(self.gameBase.playerx), self.gameBase.playery)))
|
ret.append("Player position:{0:.>64}".format("{0}{1}".format(self.gameBase.numberToLetter(self.gameBase.playerx), self.gameBase.playery)))
|
||||||
ret.append("Prev. position:{0:.>65}".format("{0}{1}".format(self.gameBase.numberToLetter(self.gameBase.prevx), self.gameBase.prevy)))
|
ret.append("Prev. position:{0:.>65}".format("{0}{1}".format(self.gameBase.numberToLetter(self.gameBase.prevx), self.gameBase.prevy)))
|
||||||
|
@ -230,6 +235,8 @@ If -l is given, a map legend will be printed under the map."""
|
||||||
def inv(self, args):
|
def inv(self, args):
|
||||||
print('\n'.join([self.gameBase.playerInv[i].name for i in self.gameBase.playerInv]))
|
print('\n'.join([self.gameBase.playerInv[i].name for i in self.gameBase.playerInv]))
|
||||||
|
|
||||||
|
# IO calls
|
||||||
|
|
||||||
def container(self, inv, cont):
|
def container(self, inv, cont):
|
||||||
"""container IO"""
|
"""container IO"""
|
||||||
# Pretty print: get length of the longest inventory item's name
|
# Pretty print: get length of the longest inventory item's name
|
||||||
|
@ -310,6 +317,8 @@ If -l is given, a map legend will be printed under the map."""
|
||||||
def dialog(self, dialogObj):
|
def dialog(self, dialogObj):
|
||||||
if 'opener' in dialogObj:
|
if 'opener' in dialogObj:
|
||||||
print(_tw.fill(dialogObj['opener'], width = TERM_SIZE))
|
print(_tw.fill(dialogObj['opener'], width = TERM_SIZE))
|
||||||
|
if 'script' in dialogObj:
|
||||||
|
self.gameBase.parseScript(dialogObj['script'])
|
||||||
while isinstance(dialogObj, dict):
|
while isinstance(dialogObj, dict):
|
||||||
if 'action' in dialogObj:
|
if 'action' in dialogObj:
|
||||||
action = dialogObj['action']
|
action = dialogObj['action']
|
||||||
|
@ -334,6 +343,9 @@ If -l is given, a map legend will be printed under the map."""
|
||||||
elif action == 'exit':
|
elif action == 'exit':
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def playercmd(self, args):
|
||||||
|
self.handleCommand(args)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.gameBase.gameEventLoop()
|
self.gameBase.gameEventLoop()
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
---
|
---
|
||||||
openingText: Floor 1 map loaded successfully. Normally, this would describe the environment.
|
openingText: Floor 1 map loaded successfully. Normally, this would describe the environment.
|
||||||
playerStart: [5, 26]
|
playerStart: [5, 26]
|
||||||
|
enterScript: printf "This script ran when you entered the level."
|
||||||
layout: |
|
layout: |
|
||||||
w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w0
|
w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w0
|
||||||
w w0
|
w w0
|
||||||
|
|
|
@ -13,3 +13,5 @@ replies:
|
||||||
- opener: I would, but there's still a bunch of foreshadowing and stuff we
|
- opener: I would, but there's still a bunch of foreshadowing and stuff we
|
||||||
have to get through first.
|
have to get through first.
|
||||||
action: back
|
action: back
|
||||||
|
script: set tellmore += 1;
|
||||||
|
printf "You have seen this text {} times." tellmore
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue