import abc import re from typing import Match, Pattern, TYPE_CHECKING from agame.util import search_item_name, trigger_help_builder 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", "HelpTrigger", "GetTrigger", "UseTrigger", "PutTrigger", "LookTrigger", "ReadTrigger", "OpenTrigger", "CloseTrigger", "GoTrigger", "HELP", "GET", "USE", "PUT", "LOOK", "READ", "OPEN", "CLOSE", "GO", ) HELP = "help" 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 @staticmethod @abc.abstractmethod def help() -> str: pass @abc.abstractmethod def trigger(self, game: "Game", match: Match): pass class HelpTrigger(Trigger): @staticmethod def pattern() -> Pattern: return re.compile("help", re.IGNORECASE) @staticmethod def help() -> str: return trigger_help_builder("help") def trigger(self, game: "Game", _match: Match): game.say("In this game, short commands are usually the best.") game.say() game.say("These are the available actions that are recognized:") game.say() for trigger in game.database.triggers: game.say(trigger.help()) game.say("To quit the game, type ((quit)).") class GetTrigger(Trigger): @staticmethod def pattern() -> Pattern: return re.compile( r""" (?Pget|take|grab|pick[ ]*up) (([ ]+(an?|the))?[ ]+(?P.+))? """, re.IGNORECASE | re.VERBOSE, ) @staticmethod def help() -> str: return trigger_help_builder( ("get", "take", "grab", "pick up", "pickup"), "item" ) 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, ) @staticmethod def help() -> str: return trigger_help_builder("use", ("item", "[with/on target]")) 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, ) @staticmethod def help() -> str: return trigger_help_builder("put", ("item", "[on/in target]")) 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, ) @staticmethod def help() -> str: return trigger_help_builder("look", args=["[at]", "item"]) 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, ) @staticmethod def help() -> str: return trigger_help_builder("read", "item") 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, ) @staticmethod def help() -> str: return trigger_help_builder("open", "item") 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, ) @staticmethod def help() -> str: return trigger_help_builder("close", "item") 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, ) @staticmethod def help() -> str: return trigger_help_builder(["go", "go to", "goto", "leave", "exit"], "target") 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.")