import abc import re from typing import Match, Pattern, TYPE_CHECKING from agame.util import search_item_name if TYPE_CHECKING: from agame.game import Game # Triggers: # get/take/grab/pick up [a[n]/the] x # use [a[n]/the] x [with/on [a[n]/the] y] # put [a[n]/the] x on/in [a[n]/the] y # look [[at] [a[n]/the] x] # read [a[n]/the] x # open x # close x # go/(go to)/leave/exit x # give [a[n]/the] x to [a[n]/the] y - TODO # push [a[n]/the] x - TODO # pull [a[n]/the] x - TODO # (put down)/drop [a[n]/the] x __all__ = ( "Trigger", "GetTrigger", "UseTrigger", "PutTrigger", "LookTrigger", "ReadTrigger", "OpenTrigger", "CloseTrigger", "GoTrigger", "GET", "USE", "PUT", "LOOK", "READ", "OPEN", "CLOSE", "GO", ) GET = "get" USE = "use" PUT = "put" LOOK = "look" READ = "read" OPEN = "open" CLOSE = "close" GO = "go" class Trigger(metaclass=abc.ABCMeta): @staticmethod @abc.abstractmethod def pattern() -> Pattern: pass @abc.abstractmethod def trigger(self, game: "Game", match: Match): pass class GetTrigger(Trigger): @staticmethod def pattern() -> Pattern: return re.compile( r""" (?Pget|take|grab|pick[ ]*up) (([ ]+(an?|the))?[ ]+(?P.+))? """, re.IGNORECASE | re.VERBOSE, ) def trigger(self, game: "Game", match: Match): item_name = match["item"] if not item_name: otrigger = match["trigger"].lower().capitalize() game.say(f"{otrigger} what?") return item = game.room.search_item_name(item_name) if item and item.revealed and GET in item.triggers: actions = item.triggers[GET] # if there are any actions, do them. else do the default action game.do_actions(actions) else: game.say("Can't get that.") class UseTrigger(Trigger): @staticmethod def pattern() -> Pattern: # TODO(low) - wouldn't it be cool to specify "use" actions? # e.g. you have a gun item and you want to be allowed to use "shoot" in order to # use the gun. return re.compile( r""" (?Puse) (([ ]+(an?|the))?[ ]+(?P.+?) ([ ]+(with|on)([ ]+(an?|the))?[ ]+(?P.+))?)? """, re.IGNORECASE | re.VERBOSE, ) def trigger(self, game: "Game", match: Match): item_name = match["item"] if not item_name: game.say("Use what?") return target_name = match["target"] # Get the item from inventory or room item = game.room.search_item_name(item_name) or search_item_name( game.inventory.values(), item_name ) if not item or not item.revealed: game.say(f"I'm not sure what you mean by {item_name}.") return target = None if target_name: # Get the target from inventory or room target = game.room.search_item_name(target_name) or search_item_name( game.inventory.values(), target_name ) if not target or not target.revealed: game.say(f"I'm not sure what you mean by {target_name}.") # Check if the target can be used on something elif target.id in item.use_actions: game.do_actions(item.use_actions[target.id]) else: game.say("I'm not sure how to do that.") elif USE in item.triggers: # Check if the item can be used by itself game.do_actions(item.triggers[USE]) elif item.use_actions: # This item can be used with *something*, but we don't know what. game.say(f"Use (({item_name})) with what?") else: # This can't be used. game.say("I can't really use that.") class PutTrigger(Trigger): @staticmethod def pattern() -> Pattern: return re.compile( r""" (?Pput) ([ ]+((an?|the)[ ]+)?(?P.+?) ((on|in)[ ]+)?((an?|the)[ ]+)?[ ]+(?P.+))? """, re.IGNORECASE | re.VERBOSE, ) def trigger(self, game: "Game", match: Match): item_name = match["item"] class LookTrigger(Trigger): @staticmethod def pattern() -> Pattern: return re.compile( r""" (?Plook) ([ ]+(at[ ]+)?((an?|the)[ ]+)?(?P.+?))? """, re.IGNORECASE | re.VERBOSE, ) def trigger(self, game: "Game", match: Match): item_name = match["item"] if not item_name: game.print_room() return item = game.room.search_item_name(item_name) or search_item_name( game.inventory.values(), item_name ) if item and LOOK in item.triggers and item.revealed: actions = item.triggers[LOOK] game.do_actions(actions) else: game.say("Can't see that.") class ReadTrigger(Trigger): @staticmethod def pattern() -> Pattern: return re.compile( r""" (?Pread) ([ ]+((an?|the)[ ]+)?(?P.+?))? """, re.IGNORECASE | re.VERBOSE, ) def trigger(self, game: "Game", match: Match): item_name = match["item"] if not item_name: game.print_room() return item = game.room.search_item_name(item_name) or search_item_name( game.inventory.values(), item_name ) if item and READ in item.triggers and item.revealed: actions = item.triggers[READ] game.do_actions(actions) else: game.say("Can't read that.") class OpenTrigger(Trigger): @staticmethod def pattern() -> Pattern: return re.compile( r""" (?Popen) (((an?|the)[ ]+)?[ ]+(?P.+?))? """, re.IGNORECASE | re.VERBOSE, ) def trigger(self, game: "Game", match: Match): item_name = match["item"] if not item_name: game.say("Open what?") return item = game.room.search_item_name(item_name) if item and OPEN in item.triggers and item.revealed: actions = item.triggers[OPEN] game.do_actions(actions) else: game.say("Can't open that.") class CloseTrigger(Trigger): @staticmethod def pattern() -> Pattern: return re.compile( r""" (?Pclose) (((an?|the)[ ]+)?[ ]+(?P.+?))? """, re.IGNORECASE | re.VERBOSE, ) def trigger(self, game: "Game", match: Match): item_name = match["item"] if not item_name: game.say("Close what?") return item = game.room.search_item_name(item_name) if item and CLOSE in item.triggers and item.revealed: actions = item.triggers[CLOSE] game.do_actions(actions) else: game.say("Can't close that.") class GoTrigger(Trigger): @staticmethod def pattern() -> Pattern: return re.compile( r""" (?Pgo([ ]*to)?|leave|exit) (((an?|the)[ ]+)?[ ]+(?P.+?))? """, re.IGNORECASE | re.VERBOSE, ) def trigger(self, game: "Game", match: Match): item_name = match["item"] if not item_name: otrigger = match["trigger"].lower().capitalize() game.say(f"{otrigger} where?") return item = game.room.search_item_name(item_name) if item and GO in item.triggers and item.revealed: actions = item.triggers[GO] game.do_actions(actions) else: game.say("Can't go there.")