Basic commands are being parsed. I think the only weird part is the 'use' command because it needs to possibly target two things. A tiny test example is provided in __main__, this will probably be broken out later. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
248 lines
6.8 KiB
Python
248 lines
6.8 KiB
Python
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]
|
|
# open x
|
|
# close x
|
|
# go/(go to)/leave/exit x
|
|
# give [a[n]/the] x to [a[n]/the] y
|
|
# push [a[n]/the] x
|
|
# pull [a[n]/the] x
|
|
# (put down)/drop [a[n]/the] x
|
|
__all__ = (
|
|
"Trigger",
|
|
"GetTrigger",
|
|
"UseTrigger",
|
|
"PutTrigger",
|
|
"LookTrigger",
|
|
"OpenTrigger",
|
|
"CloseTrigger",
|
|
"GoTrigger",
|
|
"GET",
|
|
"USE",
|
|
"PUT",
|
|
"LOOK",
|
|
"OPEN",
|
|
"CLOSE",
|
|
"GO",
|
|
)
|
|
GET = "get"
|
|
USE = "use"
|
|
PUT = "put"
|
|
LOOK = "look"
|
|
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"""
|
|
(?P<trigger>get|take|grab|pick[ ]*up)
|
|
(([ ]+(an?|the))?[ ]+(?P<item>.+))?
|
|
""",
|
|
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.lower())
|
|
if item 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"""
|
|
(?P<trigger>use)
|
|
(([ ]+(an?|the))?[ ]+(?P<item>.+?)
|
|
([ ]+(with|on)([ ]+(an?|the))?[ ]+(?P<target>.+))?)?
|
|
""",
|
|
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.lower()
|
|
)
|
|
if not item:
|
|
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.lower()
|
|
)
|
|
if not target:
|
|
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,
|
|
)
|
|
|
|
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,
|
|
)
|
|
|
|
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.lower())
|
|
if item and LOOK in item.triggers:
|
|
actions = item.triggers[LOOK]
|
|
game.do_actions(actions)
|
|
else:
|
|
game.say("Can't see that.")
|
|
|
|
|
|
class OpenTrigger(Trigger):
|
|
@staticmethod
|
|
def pattern() -> Pattern:
|
|
return re.compile(
|
|
r"""
|
|
(?P<trigger>open)
|
|
(((an?|the)[ ]+)?[ ]+(?P<item>.+?))?
|
|
""",
|
|
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.lower())
|
|
if item and OPEN in item.triggers:
|
|
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,
|
|
)
|
|
|
|
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.lower())
|
|
if item and CLOSE in item.triggers:
|
|
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"""
|
|
(?P<trigger>go|go[ ]*to|leave|exit)
|
|
(((an?|the)[ ]+)?[ ]+(?P<item>.+?))?
|
|
""",
|
|
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.lower())
|
|
if item and GO in item.triggers:
|
|
actions = item.triggers[GO]
|
|
game.do_actions(actions)
|