Fixed most input validation bugs, and did too many improvements to remember. Did I mention that I am typing these words with my hands?

This commit is contained in:
Patrick Marsee 2020-05-10 23:26:21 -04:00
parent ee5c4da549
commit 4a398cc2a3
11 changed files with 546 additions and 253 deletions

View file

@ -3,6 +3,7 @@
from shell import Shell
from gamebase import GameBase
import sys as _sys
import os as _os
#import re
import heapq
#import gamemap
@ -23,12 +24,12 @@ class GameShell(Shell):
WALLS = ('++', '++', ' +', '++', '++', '||', '++', '|+', '+ ', '++',
'==', '++', '++', '+|', '++', '++')
def __init__(self, gameBase):
def __init__(self, gameBase, gameData = 'testing/testdata.yml'):
super(GameShell, self).__init__()
self.outstream = _sys.stdout
self.gameBase = gameBase
self.colorMode = 0
data = self.gameBase.loadGameData('testing/testdata.yml')
data = self.gameBase.loadGameData(gameData)
self.gameTitle = 'Game Shell' # should be changed for actual games
if 'title' in data:
self.gameTitle = data['title']
@ -38,12 +39,16 @@ class GameShell(Shell):
self.openingText = '{}\nIn Development'
if 'openingText' in data:
self.openingText = data['openingText']
if 'playerName' in data:
self.gameBase.playerName = data['playerName']
if 'playerDescription' in data:
self.gameBase.playerDescription = data['playerDescription']
self.ps2 = '?> '
self.__inGame = False
# register functions
self.registerCommand('load', self.gameBase.loadGame) # should always be available
self.registerCommand('load', self.loadGame) # should always be available
self.registerCommand('flippetywick', self.devMode)
self.registerCommand('options', self.options)
self.registerCommand('colorTest', self.colorTest)
@ -62,7 +67,6 @@ class GameShell(Shell):
def man(self, args):
super(GameShell, self).man(args)
#heapq.heappush(self.gameBase.eventQueue, (self.gameBase.gameTime, gameevents.NoOpEvent()))
def options(self, args):
i = 0
@ -171,25 +175,26 @@ If -l is given, a map legend will be printed under the map."""
for i in things[1:]:
if priorities[i.thingType] < priorities[thing.thingType]:
thing = i
if thing.graphic[1] != textColor:
textColor = thing.graphic[1]
if thing.graphic.foreground != textColor:
textColor = thing.graphic.foreground
#print(textColor)
rows[-1].append(self.color(textColor[1:]))
if thing.thingType == 'p': # player
rows[-1].append('()')
elif thing.thingType == 'x': # exit
rows[-1].append('X{0}'.format(thing.exitid))
exits[thing.exitid] = (thing.name, thing.graphic[1])
exits[thing.exitid] = (thing.name, thing.graphic.foreground)
elif thing.thingType == 'n': # NPC
characters[len(characters)+1] = (thing.name, thing.graphic[1])
characters[len(characters)+1] = (thing.name, thing.graphic.foreground)
rows[-1].append('C{0}'.format(len(characters)))
elif thing.thingType == 'd': # door
doors[len(doors)+1] = (thing.name, thing.graphic[1])
doors[len(doors)+1] = (thing.name, thing.graphic.foreground)
rows[-1].append('D{0}'.format(len(doors)))
elif thing.thingType == 'u': # useable
useables[len(useables)+1] = (thing.name, thing.graphic[1])
useables[len(useables)+1] = (thing.name, thing.graphic.foreground)
rows[-1].append('U{0}'.format(len(useables)))
elif thing.thingType == 'i': # item
items[len(items)+1] = (thing.name, thing.graphic[1])
items[len(items)+1] = (thing.name, thing.graphic.foreground)
rows[-1].append('I{0}'.format(len(items)))
else: # entrance
rows[-1].append(' ')
@ -254,7 +259,7 @@ If -l is given, a map legend will be printed under the map."""
ret.append("Gametime:{0:.>71.3}".format(self.gameBase.gameTime))
ret.append("Event queue:")
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:.>71}".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]))
@ -283,19 +288,19 @@ If -l is given, a map legend will be printed under the map."""
response = input("Do you want to save before exiting (Y/n/x)? ")
if len(response) > 0:
if response[0] in 'Nn':
super(GameShell, self).exitShell(args)
pass
elif response[0] in 'Xx': # cancel
return
else:
sf = input('Save file: ')
if len(sf) > 0:
gameBase.saveGame([sf])
self.gameBase.saveGame([sf])
else:
print('No save file given, cancelling exit.')
else:
sf = input('Save file: ')
if len(sf) > 0:
gameBase.saveGame([sf])
self.gameBase.saveGame([sf])
else:
print('No save file given, cancelling exit.')
try:
@ -305,6 +310,43 @@ If -l is given, a map legend will be printed under the map."""
return
self.gameMode()
def loadGame(self, args):
# Check if there's a name in args. If not, just present a list of save files.
if len(args) == 0:
import pickle as _pi
for fileName in _os.listdir('saves'):
with open(f'saves/{fileName}', 'rb') as f:
player, levelname, persist, eventQueue, customValues, gameTime, nextThing = _pi.load(f)
print(f'{fileName[:-4]}\n - {levelname[5:-4]}')
return
if self.__inGame:
response = input("Do you want to save before exiting (Y/n/x)? ")
if len(response) > 0:
if response[0] in 'Nn':
pass
elif response[0] in 'Xx': # cancel
return
else:
sf = input('Save file: ')
if len(sf) > 0:
self.gameBase.saveGame([sf])
else:
print('No save file given, cancelling exit.')
return
else:
sf = input('Save file: ')
if len(sf) > 0:
self.gameBase.saveGame([sf])
else:
print('No save file given, cancelling exit.')
return
try:
self.gameBase.loadGame(args)
except RuntimeError as e:
print(e)
return
self.gameMode()
def gameMode(self):
"""Mode for in-game."""
if not self.__inGame:
@ -366,7 +408,7 @@ If -l is given, a map legend will be printed under the map."""
# IO calls
def container(self, player, cont):
def container(self, player, cont: list):
"""container IO
Player is modified through side-effect."""
# Pretty print: get length of the longest inventory item's name
@ -393,36 +435,64 @@ Player is modified through side-effect."""
print(i.name)
# Now, actually interacting with the container
timeSpent = 0.5 # using a container always takes at least 1/2 second, even just opening and closing it again.
instr = input("Take, store, or exit: ")
instr = input("Look, take, store, or exit: ")
while instr != "exit":
instr = instr.split()
if instr[0] == "take":
# take something out of the container
if instr[1] == "the":
del instr[1]
thing = ' '.join(instr[1:])
for i in range(len(cont)):
if thing == cont[i].name:
player.addThing(cont[i])
del cont[i]
if len(instr) != 0:
if instr[0] == "take":
# take something out of the container
if len(instr) > 1 and instr[1] == "the":
del instr[1]
thingName = ' '.join(instr[1:])
if len(thingName) == 0:
print(f"{self.gameBase.player.name} takes nothing.")
else:
for i in range(len(cont)):
if thingName == cont[i].name:
player.addThing(cont[i])
del cont[i]
timeSpent += 0.5
print(f"{thingName} taken.")
break
else:
# If it got here, it didn't find it.
print(f"No {thingName} in container.")
elif instr[0] == "store":
# store something in the container
if len(instr) > 1 and instr[1] == "the":
del instr[1]
thingName = ' '.join(instr[1:])
if len(thingName) == 0:
print(f"{self.gameBase.player.name} stores nothing.")
elif thingName in player.thingNames:
cont.append(player.removeThingByName(thingName))
print(f"{thingName} stored.")
timeSpent += 0.5
print("{0} taken.".format(thing))
break
else:
# If it got here, it didn't find it.
print("No {0} in container.".format(thing))
elif instr[0] == "store":
# store something in the container
if instr[1] == "the":
del instr[1]
thingName = ' '.join(instr[1:])
if thingName in player.thingNames:
cont.append(player.removeThingByName(thingName))
print("{0} stored.".format(thingName))
timeSpent += 0.5
else:
print("No {0} in inventory.".format(thingName))
instr = input("Take, store, or exit: ")
else:
print(f"No {thingName} in inventory.")
elif instr[0] == "look":
# look at something in the container
if len(instr) > 1 and instr[1] == "at":
del instr[1]
if len(instr) > 1 and instr[1] == "the":
del instr[1]
thingName = ' '.join(instr[1:])
if len(thingName) == 0:
print(f"{self.gameBase.player.name} looks at nothing.")
else:
# Check the container first.
for i in range(len(cont)):
if thingName == cont[i].name:
print(self.gameBase.justifyText(str(cont[i])))
break
else:
# If it wasn't there, try the player's inventory.
if thingName in player.thingNames:
print(self.gameBase.justifyText(str(player.getThingByName(thingName))))
else:
# If we get here, it just isn't there.
print(f"There is no {thingName} to look at.")
instr = input("Look, take, store, or exit: ")
return cont, timeSpent
def info(self, items):
@ -456,7 +526,11 @@ Player is modified through side-effect."""
print(_tw.fill('{}: {}'.format(lineNo+1, options[lineNo]), width = TERM_SIZE))
answer = -1
while answer < 0 or answer >= len(options):
answer = int(input(self.ps2)) - 1
answerString = input(self.ps2)
if not answerString.isdigit():
# If the player inputs a non-integer, just prompt again.
continue
answer = int(answerString) - 1
return answer
def endDialog(self):
@ -479,14 +553,14 @@ Player is modified through side-effect."""
else:
sf = input('Save file: ')
if len(sf) > 0:
gameBase.saveGame([sf])
self.gameBase.saveGame([sf])
super(GameShell, self).exitShell(args)
else:
print('No save file given, cancelling exit.')
else:
sf = input('Save file: ')
if len(sf) > 0:
gameBase.saveGame([sf])
self.gameBase.saveGame([sf])
super(GameShell, self).exitShell(args)
else:
print('No save file given, cancelling exit.')
@ -497,3 +571,7 @@ if __name__ == '__main__':
sh = GameShell(GameBase())
sh.menuMode()
sh.run()
# |\_/|
# /0 0\
# \o/