import dataclasses import textwrap from typing import Any, MutableMapping, Match, Optional, Sequence 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) 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) @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) # Variables. vars: MutableMapping[str, Any] = dataclasses.field(default_factory=dict) def run_command(self, line: str): line = line.strip() if not line: return triggers: Sequence[Trigger] = [ GetTrigger(), UseTrigger(), PutTrigger(), LookTrigger(), ReadTrigger(), OpenTrigger(), CloseTrigger(), GoTrigger(), ] trigger = None match: Optional[Match] = None for t in 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 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