diff --git a/gamebase.py b/gamebase.py index 8bc63b8..249b8cf 100644 --- a/gamebase.py +++ b/gamebase.py @@ -232,6 +232,23 @@ Returns (thing, x, y). "Thing" can be None.""" else: raise GameError('Invalid argument to getValueFromString: {}'.format(arg)) return val + + def compareValues(self, operator: str, left: str, right: str): + """Generalized comparisons, may eventually be extended to other operators""" + lval = self.getValueFromString(left) + rval = self.getValueFromString(right) + if operator == '==': + return lval == rval + elif operator == '!=': + return lval != rval + elif operator == '<=': + return lval <= rval + elif operator == '>=': + return lval >= rval + elif operator == '<': + return lval < rval + elif operator == '>': + return lval > rval # commands @@ -876,26 +893,12 @@ Object can be the name of the object, or its coordinates.""" 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:] + ret = self.compareValues(args[1], args[0], args[2]) else: - ret = bool(val) + ret = bool(self.parseValue(args[0])) args = args[1:] if inverse: ret = not ret diff --git a/gameshell.py b/gameshell.py index 65d91ef..3cc323e 100644 --- a/gameshell.py +++ b/gameshell.py @@ -315,33 +315,74 @@ If -l is given, a map legend will be printed under the map.""" return charsRead / 27 # based on average 250 words per minute, and word length of 5.5 + 1 for space. def dialog(self, dialogObj): - if 'opener' in dialogObj: - print(_tw.fill(dialogObj['opener'], width = TERM_SIZE)) if 'script' in dialogObj: self.gameBase.parseScript(dialogObj['script']) - while isinstance(dialogObj, dict): - if 'action' in dialogObj: - action = dialogObj['action'] - if action == 'answer': - answer = 0 - if 'answers' in dialogObj and isinstance(dialogObj['answers'], list): - for i in range(len(dialogObj['answers'])): - print(_tw.fill('{}: {}'.format(i+1, dialogObj['answers'][i]), width = TERM_SIZE)) - answer = int(input(self.ps2)) - 1 - if 'replies' in dialogObj and isinstance(dialogObj['replies'], list): - ret = self.dialog(dialogObj['replies'][answer]) - if ret > 1: - return ret - 1 - elif ret == 0: - return 0 - # if ret == 1, then do this dialog again - - elif len(action) >= 4 and action[:4] == 'back': - if len(action) == 4: - return 1 - return int(action[4:]) - elif action == 'exit': - return 0 + if 'cond' in dialogObj: + cases = dialogObj['cond'] + ret = 0 + for case in cases: + cond = case['case'].split() # should be list like ["value", "==", 1] + if len(cond) == 1 and (cond[0] == 'else' or self.gameBase.getValueFromString(cond[0])): + ret = self.dialog(case) + break + elif len(cond) == 3 and self.gameBase.compareValues(cond[1], cond[0], cond[2]): + ret = self.dialog(case) + break + else: + raise RuntimeError("All routes are false: {}".format(testValue)) + if ret > 1: + return ret - 1 + else: + return ret + # if ret == 1 or ret == 0, go back again. + elif 'opener' in dialogObj: + print(_tw.fill(dialogObj['opener'], width = TERM_SIZE)) + while isinstance(dialogObj, dict): + if 'action' in dialogObj: + action = dialogObj['action'] + if action == 'answer': + answer = 0 + skips = [] + j = 0 # follower to i + if 'answers' in dialogObj and isinstance(dialogObj['answers'], list): + for i in range(len(dialogObj['answers'])): + ans = dialogObj['answers'][i] + if ans[0] == '?': + condEnd = ans.index(':') + cond = ans[1:condEnd].strip().split() + if self.gameBase.compareValues(cond[1], cond[0], cond[2]): + print(_tw.fill('{}: {}'.format(j+1, ans[condEnd+1:]), width = TERM_SIZE)) + j += 1 + else: + skips.append(i) + else: + print(_tw.fill('{}: {}'.format(j+1, ans), width = TERM_SIZE)) + j += 1 + answer = int(input(self.ps2)) - 1 + # account for offset if there were answer options that didn't meet conditions + for i in skips: + if i <= answer: + answer += 1 + else: + break + if 'replies' in dialogObj and isinstance(dialogObj['replies'], list): + ret = self.dialog(dialogObj['replies'][answer]) + if ret > 1: + return ret - 1 + elif ret == 0: + return 0 + # if ret == 1, then do this dialog again + + elif len(action) >= 4 and action[:4] == 'back': + if len(action) == 4: + return 1 + return int(action[4:]) + elif action == 'exit': + return 0 + else: + raise RuntimeError('Malformed action: {}'.format(action)) + else: + raise RuntimeError("Dialog branch with neither switch nor openner.") def playercmd(self, args): self.handleCommand(args) diff --git a/testing/testDialog.yml b/testing/testDialog.yml index 42f7d0d..1d76367 100644 --- a/testing/testDialog.yml +++ b/testing/testDialog.yml @@ -10,8 +10,12 @@ answers: replies: - opener: Yup. action: exit - - opener: I would, but there's still a bunch of foreshadowing and stuff we - have to get through first. - action: back - script: set tellmore += 1; - printf "You have seen this text {} times." tellmore + - cond: + - case: tellmore < 5 + opener: I would, but there's still a bunch of foreshadowing and stuff we + have to get through first. + action: back + script: set tellmore += 1 + - case: else + opener: You really want to know more, don't you? + action: back