Files
ages/agame/game.py
Alek Ratzloff 2f86df2930 Add room entry auto-triggers, player input, and more
* When you teleport to a room, the teleport auto-triggers fire.
* Rooms have auto-triggers. None by default. They are run every time you
  teleport to a room, and when the game starts. Gate behavior behind a
  variable.
* PlayerInputAction waits for player input (and potentially write it
  into a variable)

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2021-11-18 20:32:02 -08:00

163 lines
4.7 KiB
Python

import dataclasses
import textwrap
from typing import Any, MutableMapping, List, Match, Optional, Sequence, Union
from agame.action import Action
from agame.color import colorize
from agame.item import Item, ItemInst
from agame.room import Room
from agame.trigger import *
__all__ = (
"Database",
"Game",
)
@dataclasses.dataclass
class Database:
# All items available to the game.
items: MutableMapping[str, Item] = dataclasses.field(default_factory=dict)
# All rooms available to the game.
rooms: MutableMapping[str, Room] = dataclasses.field(default_factory=dict)
# All variables available to the game.
vars: MutableMapping[str, Any] = dataclasses.field(default_factory=dict)
# All triggers available to the game.
triggers: List[Trigger] = dataclasses.field(
default_factory=lambda: [
GetTrigger(),
UseTrigger(),
PutTrigger(),
LookTrigger(),
ReadTrigger(),
OpenTrigger(),
CloseTrigger(),
GoTrigger(),
HelpTrigger(),
]
)
def add_item(self, item: Item):
self.items[item.id] = item
def add_items(self, *items: Item):
for item in items:
self.add_item(item)
def add_room(self, room: Room):
self.rooms[room.id] = room
def add_rooms(self, *rooms: Room):
for room in rooms:
self.add_room(room)
def add_var(self, var: str, value: Any):
self.vars[var] = value
def add_trigger(self, trigger: Trigger):
self.triggers += [trigger]
def add_pre_trigger(self, trigger: Trigger):
"""
Add a trigger to the front of the trigger list. This can be used to
override the behavior of a trigger that is added by default.
"""
self.triggers = [trigger] + self.triggers
@dataclasses.dataclass
class Game:
# Game room/items database
database: Database
# Current room.
room: Room
# Player inventory.
inventory: MutableMapping[str, ItemInst] = dataclasses.field(default_factory=dict)
def run_command(self, line: str):
line = line.strip()
if not line:
return
trigger = None
match: Optional[Match] = None
for t in self.database.triggers:
match = t.pattern().fullmatch(line)
if match:
trigger = t
break
if not trigger:
self.say("I'm not sure what you mean.")
return
assert match, "why were no patterns matched?"
trigger.trigger(self, match)
def do_actions(self, actions: Sequence[Action]):
"Executes the supplied actions."
for action in actions:
action.act(self)
def do_teleport_actions(self):
"Executes the teleport actions for the current room."
self.do_actions(self.room.teleport_actions)
def teleport(self, room: Union[str, Room]):
if isinstance(room, str):
assert room in self.database.rooms, f"could not find room with id {room}"
room = self.database.rooms[room]
self.room = room
self.do_teleport_actions()
def print_room(self):
"Prints this room's description."
self.say(f"(({self.room.name}))")
if isinstance(self.room.desc, str):
self.say(self.room.desc)
else:
assert isinstance(
self.room.desc, Sequence
), f"room.desc is not a list or a string from room id {room.id}"
self.say(*self.room.desc)
# Look at revealed text
for (index, item) in enumerate(self.room.items.values()):
if not item.revealed or item.room_desc is None or item.room_desc == []:
continue
if index != 0:
# Space this out with blank lines
self.say()
if isinstance(item.room_desc, str):
self.say(item.room_desc)
else:
assert isinstance(item.room_desc, Sequence)
self.say(*item.room_desc)
def say(self, *lines: str):
"Format, colorize, wrap, and print the message."
if lines:
head = textwrap.fill(lines[0])
print(colorize(head))
for line in lines[1:]:
message = textwrap.fill(line)
print()
print(colorize(message))
else:
print()
@property
def rooms(self):
"Shortcut property for `game.database.rooms`."
return self.database.rooms
@property
def items(self):
"Shortcut property for `game.database.items`."
return self.database.items
@property
def vars(self):
"Shortcut property for `game.database.vars`."
return self.database.vars