2021-11-18 11:31:21 -08:00
|
|
|
import abc
|
|
|
|
|
import re
|
|
|
|
|
from typing import Match, Pattern, TYPE_CHECKING
|
2021-11-18 19:31:38 -08:00
|
|
|
from agame.util import search_item_name, trigger_help_builder
|
2021-11-18 11:31:21 -08:00
|
|
|
|
|
|
|
|
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]
|
2021-11-18 16:26:16 -08:00
|
|
|
# read [a[n]/the] x
|
2021-11-18 11:31:21 -08:00
|
|
|
# open x
|
|
|
|
|
# close x
|
|
|
|
|
# go/(go to)/leave/exit x
|
2021-11-18 16:26:16 -08:00
|
|
|
# give [a[n]/the] x to [a[n]/the] y - TODO
|
|
|
|
|
# push [a[n]/the] x - TODO
|
|
|
|
|
# pull [a[n]/the] x - TODO
|
2021-11-18 11:31:21 -08:00
|
|
|
# (put down)/drop [a[n]/the] x
|
|
|
|
|
__all__ = (
|
|
|
|
|
"Trigger",
|
2021-11-18 19:31:38 -08:00
|
|
|
"HelpTrigger",
|
2021-11-18 11:31:21 -08:00
|
|
|
"GetTrigger",
|
|
|
|
|
"UseTrigger",
|
|
|
|
|
"PutTrigger",
|
|
|
|
|
"LookTrigger",
|
2021-11-18 16:26:16 -08:00
|
|
|
"ReadTrigger",
|
2021-11-18 11:31:21 -08:00
|
|
|
"OpenTrigger",
|
|
|
|
|
"CloseTrigger",
|
|
|
|
|
"GoTrigger",
|
2021-11-18 19:31:38 -08:00
|
|
|
"HELP",
|
2021-11-18 11:31:21 -08:00
|
|
|
"GET",
|
|
|
|
|
"USE",
|
|
|
|
|
"PUT",
|
|
|
|
|
"LOOK",
|
2021-11-18 16:26:16 -08:00
|
|
|
"READ",
|
2021-11-18 11:31:21 -08:00
|
|
|
"OPEN",
|
|
|
|
|
"CLOSE",
|
|
|
|
|
"GO",
|
|
|
|
|
)
|
2021-11-18 19:31:38 -08:00
|
|
|
HELP = "help"
|
2021-11-18 11:31:21 -08:00
|
|
|
GET = "get"
|
|
|
|
|
USE = "use"
|
|
|
|
|
PUT = "put"
|
|
|
|
|
LOOK = "look"
|
2021-11-18 16:26:16 -08:00
|
|
|
READ = "read"
|
2021-11-18 11:31:21 -08:00
|
|
|
OPEN = "open"
|
|
|
|
|
CLOSE = "close"
|
|
|
|
|
GO = "go"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Trigger(metaclass=abc.ABCMeta):
|
|
|
|
|
@staticmethod
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
|
def pattern() -> Pattern:
|
|
|
|
|
pass
|
|
|
|
|
|
2021-11-18 19:31:38 -08:00
|
|
|
@staticmethod
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
|
def help() -> str:
|
|
|
|
|
pass
|
|
|
|
|
|
2021-11-18 11:31:21 -08:00
|
|
|
@abc.abstractmethod
|
|
|
|
|
def trigger(self, game: "Game", match: Match):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2021-11-18 19:31:38 -08:00
|
|
|
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())
|
|
|
|
|
|
|
|
|
|
|
2021-11-18 11:31:21 -08:00
|
|
|
class GetTrigger(Trigger):
|
|
|
|
|
@staticmethod
|
|
|
|
|
def pattern() -> Pattern:
|
|
|
|
|
return re.compile(
|
|
|
|
|
r"""
|
|
|
|
|
(?P<trigger>get|take|grab|pick[ ]*up)
|
|
|
|
|
(([ ]+(an?|the))?[ ]+(?P<item>.+))?
|
|
|
|
|
""",
|
|
|
|
|
re.IGNORECASE | re.VERBOSE,
|
|
|
|
|
)
|
|
|
|
|
|
2021-11-18 19:31:38 -08:00
|
|
|
@staticmethod
|
|
|
|
|
def help() -> str:
|
|
|
|
|
return trigger_help_builder(
|
|
|
|
|
("get", "take", "grab", "pick up", "pickup"), "item"
|
|
|
|
|
)
|
|
|
|
|
|
2021-11-18 11:31:21 -08:00
|
|
|
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
|
2021-11-18 16:26:16 -08:00
|
|
|
item = game.room.search_item_name(item_name)
|
|
|
|
|
if item and item.revealed and GET in item.triggers:
|
2021-11-18 11:31:21 -08:00
|
|
|
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"""
|
|
|
|
|
(?P<trigger>use)
|
|
|
|
|
(([ ]+(an?|the))?[ ]+(?P<item>.+?)
|
|
|
|
|
([ ]+(with|on)([ ]+(an?|the))?[ ]+(?P<target>.+))?)?
|
|
|
|
|
""",
|
|
|
|
|
re.IGNORECASE | re.VERBOSE,
|
|
|
|
|
)
|
|
|
|
|
|
2021-11-18 19:31:38 -08:00
|
|
|
@staticmethod
|
|
|
|
|
def help() -> str:
|
|
|
|
|
return trigger_help_builder("use", ("item", "[with/on target]"))
|
|
|
|
|
|
2021-11-18 11:31:21 -08:00
|
|
|
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(
|
2021-11-18 16:26:16 -08:00
|
|
|
game.inventory.values(), item_name
|
2021-11-18 11:31:21 -08:00
|
|
|
)
|
2021-11-18 16:26:16 -08:00
|
|
|
if not item or not item.revealed:
|
2021-11-18 11:31:21 -08:00
|
|
|
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(
|
2021-11-18 16:26:16 -08:00
|
|
|
game.inventory.values(), target_name
|
2021-11-18 11:31:21 -08:00
|
|
|
)
|
2021-11-18 16:26:16 -08:00
|
|
|
if not target or not target.revealed:
|
2021-11-18 11:31:21 -08:00
|
|
|
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"""
|
|
|
|
|
(?P<trigger>put)
|
|
|
|
|
([ ]+((an?|the)[ ]+)?(?P<item>.+?)
|
|
|
|
|
((on|in)[ ]+)?((an?|the)[ ]+)?[ ]+(?P<target>.+))?
|
|
|
|
|
""",
|
|
|
|
|
re.IGNORECASE | re.VERBOSE,
|
|
|
|
|
)
|
|
|
|
|
|
2021-11-18 19:31:38 -08:00
|
|
|
@staticmethod
|
|
|
|
|
def help() -> str:
|
|
|
|
|
return trigger_help_builder("put", ("item", "[on/in target]"))
|
|
|
|
|
|
2021-11-18 11:31:21 -08:00
|
|
|
def trigger(self, game: "Game", match: Match):
|
|
|
|
|
item_name = match["item"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LookTrigger(Trigger):
|
|
|
|
|
@staticmethod
|
|
|
|
|
def pattern() -> Pattern:
|
|
|
|
|
return re.compile(
|
|
|
|
|
r"""
|
|
|
|
|
(?P<trigger>look)
|
|
|
|
|
([ ]+(at[ ]+)?((an?|the)[ ]+)?(?P<item>.+?))?
|
|
|
|
|
""",
|
|
|
|
|
re.IGNORECASE | re.VERBOSE,
|
|
|
|
|
)
|
|
|
|
|
|
2021-11-18 19:31:38 -08:00
|
|
|
@staticmethod
|
|
|
|
|
def help() -> str:
|
|
|
|
|
return trigger_help_builder("look", args=["[at]", "item"])
|
|
|
|
|
|
2021-11-18 11:31:21 -08:00
|
|
|
def trigger(self, game: "Game", match: Match):
|
|
|
|
|
item_name = match["item"]
|
|
|
|
|
if not item_name:
|
|
|
|
|
game.print_room()
|
|
|
|
|
return
|
2021-11-18 16:26:16 -08:00
|
|
|
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:
|
2021-11-18 11:31:21 -08:00
|
|
|
actions = item.triggers[LOOK]
|
|
|
|
|
game.do_actions(actions)
|
|
|
|
|
else:
|
|
|
|
|
game.say("Can't see that.")
|
|
|
|
|
|
|
|
|
|
|
2021-11-18 16:26:16 -08:00
|
|
|
class ReadTrigger(Trigger):
|
|
|
|
|
@staticmethod
|
|
|
|
|
def pattern() -> Pattern:
|
|
|
|
|
return re.compile(
|
|
|
|
|
r"""
|
|
|
|
|
(?P<trigger>read)
|
|
|
|
|
([ ]+((an?|the)[ ]+)?(?P<item>.+?))?
|
|
|
|
|
""",
|
|
|
|
|
re.IGNORECASE | re.VERBOSE,
|
|
|
|
|
)
|
|
|
|
|
|
2021-11-18 19:31:38 -08:00
|
|
|
@staticmethod
|
|
|
|
|
def help() -> str:
|
|
|
|
|
return trigger_help_builder("read", "item")
|
|
|
|
|
|
2021-11-18 16:26:16 -08:00
|
|
|
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.")
|
|
|
|
|
|
|
|
|
|
|
2021-11-18 11:31:21 -08:00
|
|
|
class OpenTrigger(Trigger):
|
|
|
|
|
@staticmethod
|
|
|
|
|
def pattern() -> Pattern:
|
|
|
|
|
return re.compile(
|
|
|
|
|
r"""
|
|
|
|
|
(?P<trigger>open)
|
|
|
|
|
(((an?|the)[ ]+)?[ ]+(?P<item>.+?))?
|
|
|
|
|
""",
|
|
|
|
|
re.IGNORECASE | re.VERBOSE,
|
|
|
|
|
)
|
|
|
|
|
|
2021-11-18 19:31:38 -08:00
|
|
|
@staticmethod
|
|
|
|
|
def help() -> str:
|
|
|
|
|
return trigger_help_builder("open", "item")
|
|
|
|
|
|
2021-11-18 11:31:21 -08:00
|
|
|
def trigger(self, game: "Game", match: Match):
|
|
|
|
|
item_name = match["item"]
|
|
|
|
|
if not item_name:
|
|
|
|
|
game.say("Open what?")
|
|
|
|
|
return
|
2021-11-18 16:26:16 -08:00
|
|
|
item = game.room.search_item_name(item_name)
|
|
|
|
|
if item and OPEN in item.triggers and item.revealed:
|
2021-11-18 11:31:21 -08:00
|
|
|
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"""
|
|
|
|
|
(?P<trigger>close)
|
|
|
|
|
(((an?|the)[ ]+)?[ ]+(?P<item>.+?))?
|
|
|
|
|
""",
|
|
|
|
|
re.IGNORECASE | re.VERBOSE,
|
|
|
|
|
)
|
|
|
|
|
|
2021-11-18 19:31:38 -08:00
|
|
|
@staticmethod
|
|
|
|
|
def help() -> str:
|
|
|
|
|
return trigger_help_builder("close", "item")
|
|
|
|
|
|
2021-11-18 11:31:21 -08:00
|
|
|
def trigger(self, game: "Game", match: Match):
|
|
|
|
|
item_name = match["item"]
|
|
|
|
|
if not item_name:
|
|
|
|
|
game.say("Close what?")
|
|
|
|
|
return
|
2021-11-18 16:26:16 -08:00
|
|
|
item = game.room.search_item_name(item_name)
|
|
|
|
|
if item and CLOSE in item.triggers and item.revealed:
|
2021-11-18 11:31:21 -08:00
|
|
|
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"""
|
2021-11-18 16:26:16 -08:00
|
|
|
(?P<trigger>go([ ]*to)?|leave|exit)
|
2021-11-18 11:31:21 -08:00
|
|
|
(((an?|the)[ ]+)?[ ]+(?P<item>.+?))?
|
|
|
|
|
""",
|
|
|
|
|
re.IGNORECASE | re.VERBOSE,
|
|
|
|
|
)
|
|
|
|
|
|
2021-11-18 19:31:38 -08:00
|
|
|
@staticmethod
|
|
|
|
|
def help() -> str:
|
|
|
|
|
return trigger_help_builder(["go", "go to", "goto", "leave", "exit"], "target")
|
|
|
|
|
|
2021-11-18 11:31:21 -08:00
|
|
|
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
|
2021-11-18 16:26:16 -08:00
|
|
|
item = game.room.search_item_name(item_name)
|
|
|
|
|
if item and GO in item.triggers and item.revealed:
|
2021-11-18 11:31:21 -08:00
|
|
|
actions = item.triggers[GO]
|
|
|
|
|
game.do_actions(actions)
|
2021-11-18 16:26:16 -08:00
|
|
|
else:
|
|
|
|
|
game.say("Can't go there.")
|