Last active
February 23, 2024 02:47
-
-
Save Pinacolada64/a28d39ad241c5d9e03a6b9c1c1c54ed0 to your computer and use it in GitHub Desktop.
New parser with individual functions per command
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# https://gist.github.com/anoryx/c34380a0a3ef4031f41c9ed8035e305b | |
# https://stackoverflow.com/questions/51575931/class-inheritance-in-python-3-7-dataclasses/53085935#53085935 | |
# combat considerations: | |
# https://codereview.stackexchange.com/questions/139121/my-implementation-of-item-objects-in-a-text-adventure | |
# thanks, volca & google gemini (née bard) | |
import doctest | |
import logging | |
from dataclasses import dataclass, field | |
from enum import Enum | |
from typing import Optional | |
""" | |
For attributes that have a closed set of possible choices, | |
I like to make an Enum object. Normally the Enum values are integers | |
but you can make them strings if you want, like this: | |
""" | |
class Gender(str, Enum): | |
MALE = "male" | |
FEMALE = "female" | |
class Handedness(str, Enum): | |
NO_HANDS = "hands-free" | |
ONE_HANDED = "single-handed" | |
TWO_HANDED = "double-handed" | |
class SpellTypes(str, Enum): | |
DISPEL_POISON = "dispel poison" | |
ELEVATOR_DOWN = "elevator down" | |
ELEVATOR_UP = "elevator up" | |
HEAL = "heal" | |
MAP = "map" # non-destructive scrolls | |
TELEPORT = "teleport" | |
# You can also declare enums like this: | |
Flag = Enum("Flag", ["cursed", "blessed", "cool"]) | |
Size = Enum("Size", ["huge", "large", "big", "man_sized", "short", "small", "swift", "tiny"]) | |
class IncrementItemNumber(object): | |
item_number = 0 | |
def __init__(self): | |
IncrementItemNumber.item_number += 1 | |
# The @dataclass decorator handles all the __init__ stuff | |
@dataclass | |
class Item(object): | |
""" | |
'number' is a holdover from the implementation of "The Land of Spur" on the | |
memory-constrained Apple //; it was more RAM-efficient to refer to objects | |
by their numbers instead of a name string. Its usage may be dropped eventually. | |
""" | |
# just for funsies, no real *need* to auto-increment item numbers... yet | |
number: IncrementItemNumber() | |
# For each attribute, define what type it should be. | |
# If there's a default value, you can add that with `= default_value` | |
# 'name' is how the player refers to it on the command line: | |
name: str = "name" | |
weight: Optional[int] = None | |
description: Optional[str] = None | |
def long_desc(self): | |
# FIXME: I forget what this was for. possibly just delete it | |
pass | |
def __str__(self): | |
_ = f"{self.name}" | |
if self.weight: | |
_ += f" ({self.weight} lb.)" | |
return _ | |
""" | |
@dataclass | |
class GameMap(Room): | |
rooms: Room = field(default_factory=list) | |
""" | |
@dataclass | |
class Weapon(Item): | |
handedness: Handedness = Handedness.ONE_HANDED # default | |
defense_bonus: int = 10 | |
def long_desc(self): | |
return f"The {self.name} " \ | |
f"{f'[#{self.number}]' if self.number else ''}" \ | |
f"is a {self.handedness.value} weapon." | |
def __str__(self): | |
return f"{self.name}" \ | |
f"{f' [#{self.number}]' if self.number else ''}" | |
class StormWeapon(Weapon): | |
pass | |
class Book(Item): | |
def __init__(self, number, text, title, description, | |
self_destruct_after_reading=True): | |
super().__init__(number=number, name=title, description=description) # Call parent's __init__ | |
self.text = text | |
self.self_destruct_after_reading = self_destruct_after_reading | |
def read(self, character): # Assuming you have a player object reference | |
if self.text: | |
print(self.text) | |
# Call any additional book-specific reading logic here | |
if self.self_destruct_after_reading: | |
print(f"The book {self.name} vanishes in a puff of smoke!") | |
character.remove_from_inventory(self) # Remove from inventory | |
else: | |
print(f"You can't see any writing on the {self.name}.") | |
@dataclass | |
class Spell(object): | |
""" | |
Spell is subclassed from the Item class, but due to additional attributes with defaults | |
being added, can't specify defaults here. so it is now just a composed (?) class instead | |
of inherited. | |
IncrementItemNumber() is just for funsies, no real *need* to auto-increment item numbers... yet | |
""" | |
number: IncrementItemNumber() | |
# For each attribute, define what type it should be. | |
# If there's a default value, you can add that with `= default_value` | |
name: str = "name" | |
weight: Optional[int] = None | |
description: Optional[str] = None | |
# copied from Weapon class: | |
# handedness: Handedness = Handedness.ONE_HANDED # default | |
# just to give it *some* default, not necessarily the "right" one: | |
spell_type: SpellTypes = SpellTypes.HEAL | |
chance_to_cast: float = .1 | |
# how many times you can cast the spell: | |
charges: int = 1 | |
def cast(self): | |
# TODO: if Witch or Wizard class, and if Staff READY, increase chance of spell casting | |
# if self.carried(Staff): blah | |
print(f"You cast {self.name}.") | |
def long_desc(self): | |
return f"A spell of {self.spell_type.lower()}." | |
def __str__(self): | |
# (###x) 12345678901234567890: ###% | |
# ( 10x) test_spell..........: 100% | |
""" | |
>>> test_spell = Spell(name="test_spell", number=1, spell_type="heal", | |
... chance_to_cast=.5, charges=10) | |
>>> print(test_spell) | |
( 10x) test_spell..........: 50% | |
""" | |
# TODO: add spell_type output | |
return f"({self.charges:>3}x) " \ | |
f"{self.name.ljust(20, '.')}: " \ | |
f"{int(self.chance_to_cast * 100):>3}%" | |
@dataclass | |
class Scroll(Item, Spell): | |
self_destruct_after_reading: bool = True | |
def read(self): | |
# FIXME: call Book read function? | |
if self.self_destruct_after_reading: | |
print(f"The scroll {self.name} vanishes in a puff of smoke!") | |
# TODO: determine player object holding it, remove from inventory | |
class MapScroll(Spell): | |
def __init__(self, map_level): | |
self.map_level = map_level | |
self.self_destruct_after_reading: False | |
def __str__(self): | |
return f"A level {self.map_level} map scroll" | |
@dataclass | |
class PlayerStats: | |
str_: int = 0 # This one has an underscore at the end because 'str' is a reserved Python keyword | |
dex: int = 0 | |
con: int = 0 | |
int_: int = 0 # 'int' is also reserved | |
wis: int = 0 | |
cha: int = 0 | |
@dataclass | |
class Character: | |
""" | |
For these attributes, since it can be either a string or None, the type is: str | None | |
(This only works in Python 3.10+. If you're using an older version, | |
upgrade. Otherwise you can use the typing library, which would look like: name: Optional[str] = None) | |
Details here: https://docs.python.org/3.8/library/typing.html | |
""" | |
# inventory is a list of InventoryItems (a custom class which bundles/tracks item name & quntity) | |
inventory: list = field(default_factory=list) | |
name: str | None = None | |
# You can use your other classes here, too. Character.gender will be a Gender object. | |
gender: Optional[Gender] = None | |
flag: Optional[Flag] = None | |
size: Optional[Size] = "man-sized" | |
agility: Optional[int] = None | |
max_inventory: int = 10 | |
weapon_readied: Optional[Weapon] = None | |
# Lists, dicts, and similar data structures are special and need extra handling with 'field()' | |
def add_to_inventory(self, item_name: [Item | Book | Spell], quantity: int = 1) -> object: | |
""" | |
Add an item to the Character's inventory. | |
:param item_name: thing to add to inventory | |
:param quantity: number of <item>(s) to add to inventory | |
:returns True: was successful, False: was not successful | |
""" | |
""" | |
>>> item = InventoryItem("item", 2) | |
>>> inv = [item] | |
>>> book = Book(title="Adventurer's Guide") | |
>>> inv.add_to_inventory(item=book) | |
>>> self.print_inv() | |
""" | |
if self.inventory is None: | |
self.inventory = [] | |
if len(self.inventory) == self.max_inventory: | |
print("You can't carry any more.") | |
return False | |
else: | |
if item_name in self.inventory: | |
# add to the quantity of an existing item: | |
self.inventory[item_name].count += quantity | |
else: | |
# add a new item of the specified quantity: | |
new_item = InventoryItem(item_name, quantity) | |
self.inventory.append(new_item) | |
return True | |
def remove_from_inventory(self, item_name: str, quantity: int = 1): | |
if item_name in self.inventory: | |
item = self.inventory[item_name] | |
item.count -= quantity | |
if item.count <= 0: | |
del self.inventory[item_name] | |
else: | |
print(f"You don't have any {item_name} in your inventory.") | |
# inventory is defined in Character parent class | |
def print_inventory(self): | |
logging.info(f"print_inventory(): {self.inventory=}") | |
if not self.inventory: | |
print(f"{self.name} is not carrying anything.") | |
else: | |
armor_carried = [] | |
books_carried = [] | |
drink_carried = [] | |
food_carried = [] | |
items_carried = [] | |
spells_carried = [] | |
weapons_carried = [] | |
for index, item in enumerate(self.inventory, start=1): | |
logging.info(f"{item.item_name=}, {item.quantity}") | |
logging.info(f"{item.item_name} is {type(item.item_name)}") | |
# if isinstance(item, Armor): | |
# armor_carried.append(item) | |
if isinstance(item.item_name, Book): | |
books_carried.append(item) | |
# elif isinstance(item, Food): | |
# food_carried.append(item) | |
elif isinstance(item.item_name, Item): | |
items_carried.append(item) | |
elif isinstance(item.item_name, Spell): | |
spells_carried.append(item) | |
elif isinstance(item.item_name, Weapon): | |
weapons_carried.append(item) | |
else: | |
logging.info(f"{item} is of class {type(item)}") | |
self.list_inventory_category("Food", food_carried) | |
self.list_inventory_category("Drink", drink_carried) | |
self.list_inventory_category("Book", books_carried) | |
self.list_inventory_category("Item", items_carried) | |
self.list_inventory_category("Spell", spells_carried, | |
header=" (Qty.) Spell Name..........: Cast %") | |
self.list_inventory_category("Weapon", weapons_carried) | |
def list_inventory_category(self, category: str, item_list: list, header: str = None): | |
if item_list: | |
print(f"{category}:") if len(item_list) == 1 else print(f'{category}s:') | |
print() | |
if header: | |
print(header) | |
for index, item in enumerate(item_list, start=1): | |
if item.quantity == 1: | |
print(f'{index}) {item.item_name}') | |
else: | |
print(f'{index}) {item.item_name} ({item.quantity}x)') | |
print() | |
else: | |
# print("You are not carrying anything.") | |
logging.info(f"{item_list=}") | |
def pronoun(self, type: str, uppercase=False): | |
""" | |
Return the character's pronoun in several different forms: | |
personal: he / she | |
possessive: his / hers | |
:param type: pronoun type | |
:param uppercase: True if this starts a sentence | |
:return: str | |
""" | |
if type == "personal": | |
temp = "he" if self.gender == Gender.MALE else "she" | |
if type == "possessive": | |
temp = "his" if self.gender == Gender.MALE else "hers" | |
return temp.title() if uppercase else temp | |
@dataclass | |
class PlayerCharacter(Character): | |
""" | |
>>> volca = PlayerCharacter(name="Volca", gender=Gender.MALE) | |
>>> volca.name | |
'Volca' | |
>>> # The type of this is Gender: | |
>>> volca.gender | |
<Gender.MALE: 'male'> | |
>>> # The type of this is str | |
>>> volca.gender.value | |
'male' | |
""" | |
description: str = None | |
room_number: int = 1 | |
stats: dict[PlayerStats] = field(default_factory=dict) | |
race: Optional[str] = None | |
class_: Optional[str] = None | |
horse_rider: bool = True | |
def __str__(self): | |
return self.description | |
class InventoryItem: | |
"""Class to store and display an inventory item's name and quantity""" | |
def __init__(self, item: Item, quantity: int = 1): | |
self.item = item | |
self.quantity = quantity | |
def __str__(self): | |
if self.quantity > 1: | |
return f"{self.item.name} ({self.quantity}x)" | |
else: | |
return f"{self.item.name}" | |
# Room must be defined after PlayerCharacter: | |
@dataclass | |
class Room: | |
number: Optional[int] # e.g., int | None | |
title: str | |
description: str | |
items: Optional[list[Item]] = field(default_factory=list) | |
players: Optional[list[PlayerCharacter]] = field(default_factory=list) | |
exits: [Optional[int], Optional[int], Optional[int], Optional[int]] = field(default_factory=list) | |
# exits are defined in north, east, south, west order | |
class UserCmd: | |
def __init__(self, *args): | |
""" | |
TODO: for later expansion, when there's a difference between admin-only and user commands | |
""" | |
print(f"UserCmd: called {args[0]}") | |
class Game: | |
def __init__(self): | |
self.running = True | |
# Map commands to functions | |
self.commands = { | |
"go": self.cmd_go, # Example function for a "go" command | |
"help": self.cmd_help, # Example function for a "help" command | |
"i": self.cmd_inventory, | |
"inv": self.cmd_inventory, | |
"l": self.cmd_look, | |
"look": self.cmd_look, # Example function for a "look" command | |
"quit": self.cmd_quit, # Example function to quit the game | |
# TODO: Add more commands and their corresponding functions here | |
} | |
# currently used when LOOKing at yourself to reply with the proper pronoun: | |
# TODO: expand code to refer to "it" and "here" | |
self.pronouns = {"me": "yourself", | |
"you": "yourself"} | |
self.nouns = ["sword", "lance", "spell", "book"] | |
room_0 = Room(number=0, # this is a placeholder so room # accesses are not off-by-one | |
title="empty", | |
description="empty", | |
items=None, | |
players=None, | |
exits=[None, None, None, None]) | |
room_1 = Room(number=1, | |
title="NW Room", | |
description="You are in the northwest room.", | |
items=[lance], | |
exits=[None, 2, None, None], | |
players=[volca]) | |
room_2 = Room(2, "NE Room", "You are in the northeast room.", | |
items=[howling], | |
exits=[None, None, None, 1], | |
players=[elissa, strolik]) | |
self.game_map = [room_0, room_1, room_2] | |
# utility functions ############################################################################ | |
def get_players_in_room(self, character: PlayerCharacter) -> list: | |
""" | |
Returns a list containing player names in the same room as the given character, | |
excluding the character themselves. | |
The verb ("is"/"are") to make the sentence grammatically correct depends on how | |
many names are in the list, and is handled by grammatical_player_list(). | |
:returns None: if no characters in room | |
""" | |
# TODO: exclude_caller: bool, whether or not to include caller's character name in results; | |
# e.g. exclude_caller: True to list players in room without listing yourself | |
# or exclude_caller: False to broadcast a message to all players in room including the caller | |
players_in_room = [] | |
room = self.game_map[character.room_number] | |
# Print room.players before the loop in get_players_in_room to inspect player data. | |
logging.info(f"{room.players=}") | |
""" | |
>>> game.game_map[1].players[0].name | |
'Volca' | |
""" | |
if room.players: | |
for p in room.players: | |
if p.name != character.name: | |
players_in_room.append(p.name) | |
return players_in_room if room.players else None | |
def look_room(self, character: PlayerCharacter): | |
"""Show room description (if enabled) and players in room""" | |
room = self.game_map[character.room_number] | |
# Display room title and description | |
print(room.title) | |
print(room.description) | |
print() | |
if room.items: | |
for i in room.items: | |
print(f"You see {i.name}.") | |
available_directions = [] | |
for i, e in enumerate("nesw"): | |
if room.exits[i]: | |
available_directions.append(cardinal_directions[e]) | |
# Combine direction names into a comma-separated string | |
travel_message = f"You may travel {', '.join(available_directions)}." | |
print(travel_message) # Output: You may travel North, East, South. | |
player_names_list = self.get_players_in_room(character) | |
if player_names_list: | |
""" | |
Desired example output: | |
"Elissa is here." | |
"Elissa and Strolik are here." | |
"Elissa, Strolik and Volca are here." | |
""" | |
logging.info(f"look_room: {player_names_list=}") | |
print(f"\n{self.grammatical_player_list(player_names=player_names_list)}") | |
def parser(self, character: PlayerCharacter): | |
while self.running: | |
# look at room | |
print() | |
self.look_room(character) | |
print() | |
command_line = input("What now? ") | |
if command_line: | |
args = command_line.split() # .append(dict["character", character]) | |
command = args[0].lower() # Get the first word as the command, lowercase it | |
args = list(args[1:]) # Keep the remaining words as arguments | |
logging.info(f"{command=} {args=}") | |
# TODO: refer to a noun as "it", player as "them", room as "here", etc. | |
# self.it = something | |
if command in self.commands: | |
# Call the appropriate function with any arguments | |
self.commands[command](character, *args) # Expand arguments using *args | |
else: | |
print("I don't understand that command.") | |
# game commands ################################################################################# | |
def cmd_go(self, character: PlayerCharacter, *args): | |
"""Travel in the direction <dir>""" | |
""" | |
:param character: Character object | |
:returns: None | |
""" | |
direction = args[0][0].lower() | |
if direction in ["n", "e", "s", "w"]: | |
dir_index = "nesw".index(direction) | |
# Access character's current room number: | |
current_room_number = character.room_number | |
# TODO: check for room flags, obstacles preventing travel | |
target_room_number = self.game_map[current_room_number].exits[dir_index] | |
if target_room_number: | |
character.room_number = target_room_number | |
print(f"You move to the {cardinal_directions[direction]}.") | |
else: | |
print("You can't go that way.") | |
else: | |
print("Invalid direction.") | |
def cmd_help(self, character: PlayerCharacter, *args): | |
"""Displays help information for commands. 'help <topic>' displays help for <topic>.""" | |
logging.info("Running 'help' command.") | |
if args: | |
# Get the function object based on the first argument | |
try: | |
func = getattr(self, args[0]) # Access the function from the class | |
print(func.__doc__) # Print the function's docstring | |
except AttributeError: | |
print(f"No help available for '{args[0]}'.") | |
else: | |
print("Available commands:") | |
# return longest command name length, plus 4 extra for spaces at either end: | |
command_names = self.commands.items() | |
longest_command = len(max([x for x in command_names], key=len)) + 8 | |
for command, func in command_names: | |
# Print command name and its docstring | |
cmd = command + " " | |
print(f"{cmd.ljust(longest_command, '.')} {func.__doc__}") | |
def cmd_inventory(self, character: PlayerCharacter, *args): | |
"""Show items in your inventory""" | |
logging.info("Running 'inventory' command.") | |
character.print_inventory() | |
def cmd_look(self, character: PlayerCharacter, *args): | |
""" | |
'look' at the room | |
'look <thing>' to look at <thing> | |
'look <dir>' to look at a room in <dir>ection. | |
""" | |
logging.info(f"look: {args}") | |
if len(args) == 0: | |
# assuming 'look [here]' | |
self.look_room(character) | |
else: | |
# Access the actual object based on the argument: | |
# pass character doing the LOOKing, and the base command: | |
target = self.get_object_by_name(character, args[0]) | |
if target: | |
if isinstance(target, PlayerCharacter): | |
print(f"You look at {target.name}:") | |
print() | |
print(target.description) | |
if target.weapon_readied: | |
print(f"\n{target.pronoun(type='personal', uppercase=True)} " | |
f"has a {target.weapon_readied} at the ready.") | |
print(f"{target.pronoun(type='personal', uppercase=True)} is carrying:") | |
if target.inventory: | |
for i in target.inventory: | |
print(f" {i}") | |
else: | |
print("nothing") | |
elif isinstance(target, Room): | |
# Handle looking at rooms | |
print(target.description) | |
elif isinstance(target, Item): | |
# Handle looking at items | |
print(target.description) | |
else: | |
# Handle other object types | |
pass | |
else: | |
print(f"You can't see {args[0]} clearly.") | |
def cmd_quit(self, character: PlayerCharacter): | |
"""Quit the game.""" | |
logging.info("Running 'quit' command.") | |
self.running = False | |
# TODO: save character | |
print("Quitting.") | |
# helper functions ####################################################### | |
def get_object_by_name(self, character: PlayerCharacter, object_name_request): | |
"""Retrieves an object from the game world by its name. | |
:param character: character doing the request | |
:param object_name_request: object | |
:returns object_name: if object found, False if not found | |
""" | |
# TODO: look for an item in the character's inventory, | |
# or does PlayerCharacter.in_inventory() fulfil this need? | |
# look for an item in the current room: | |
""" | |
game.game_map[2].players[0].name | |
'Elissa' | |
""" | |
# Search for the object in relevant collections or data structures | |
room = self.game_map[character.room_number] | |
# try to match item in room: | |
for item in room.items: | |
if item.name.lower() == object_name_request.lower(): | |
logging.info(f"{item.name} matches") | |
return item | |
# else: | |
# print("There are no items in this room.") | |
# try to match an item in the room: | |
for item in room.items: # Assuming you have a list of rooms | |
logging.info(f"{item}") | |
if item.name.lower() == object_name_request.lower(): | |
logging.info(f"{item.name} matches") | |
return item | |
# Check for players present in room: | |
for player in room.players: | |
if player.name.lower() == object_name_request.lower(): | |
logging.info(f"{player.name} matches") | |
return player | |
# If not found, return None | |
return None | |
def grammatical_item_list(self, item_list: list | str): | |
result_list = [] | |
for item in item_list: | |
if item.endswith("s"): | |
result_list.append(f"some {item}") | |
elif item.startswith(('a', 'e', 'i', 'o', 'u')): | |
result_list.append(f"an {item}") | |
else: | |
result_list.append(f"a {item}") | |
# tanabi: Add 'and' if we need it | |
if len(result_list) > 1: | |
result_list[-1] = f"and {result_list[-1]}" | |
# Join it together | |
return ", ".join(result_list) | |
def grammatical_player_list(self, player_names: list[str] | str) -> str: | |
""" | |
>>> print(grammatical_player_list(player_names=['Elissa'])) | |
'Elissa is here.' # if only one player is here. | |
>>> print(grammatical_player_list(player_names=['Elissa', 'Strolik'])) | |
'Elissa and Strolik are here.' # if two players are here. | |
>>> print(self.grammatical_player_list(player_names=['Elissa', 'Volca', 'Strolik'])) | |
'Elissa, Volca and Strolik are here.' # if three or more players are here. | |
""" | |
if len(player_names) == 1: | |
# single player in room: | |
return f"{player_names[0]} is here." | |
if type(player_names) is list: | |
logging.info(f"{player_names=}") | |
if len(player_names) == 2: | |
# 2 players in room: | |
return f"{' and '.join(player_names)} are here." | |
elif len(player_names) > 2: | |
# 2+ players in room: | |
# Use conditional join to insert "and" before the last element | |
return f"{', '.join(player_names[:-1])} and {player_names[-1]} are here." | |
def header(self, message: str): | |
# TODO: Player.header will know Player.terminal_width / Player.translation | |
return f"{message.title()}\n{'-' * len(message)}\n" | |
if __name__ == '__main__': | |
doctest.testmod(verbose=False) | |
logging.basicConfig(level="INFO") | |
cardinal_directions = {"n": "North", "e": "East", "s": "South", "w": "West"} | |
# define game items | |
adventurers_guide = Book(number=1, title="Adventurer's Guide", | |
description="A worn pamphlet that gives off an aura of understated " | |
"importance.", | |
text="""The novice adventurer should take these words to heart: | |
1) Eat and drink often enough to keep thy health up! | |
2) READY a weapon before encountering the demon! | |
3) Shields are of little value unless put to use! | |
4) Armor carried is armor wasted! | |
5) Mapping thy journey saves time & lives! | |
6) Acquisitions made in haste can prove hazardous to thy health! | |
7) Choose thy weapons well, for the strongest may not always be the most | |
effective. | |
....courtesy of The Adventurers Widows & Orphans Guild""") | |
amulet = Item(number=4, name="Amulet of Life", weight=1, | |
description="A glittering amulet.") | |
heal_spell = Spell(name="Midas Touch", number=1, spell_type=SpellTypes.HEAL, | |
chance_to_cast=.5, charges=10) | |
howling = Book(number=13, title="The Howling", | |
description="A faded old book. The cover depicts a shaggy human-like creature howling " | |
"at the moon.", | |
text="Be it known that to kill a werewolf requires a special craft--one made of silver.") | |
lance = Weapon(number=None, name="lance", weight=15, | |
description="A wooden lance.") | |
sword = Weapon(number=1, name="sword", weight=5, handedness=Handedness.ONE_HANDED, | |
description="A sharp-looking short sword.") | |
# FIXME: to make Volca's sign readable, it must currently be of type Book. Perhaps this could | |
# be fixed later, and a Sign class of items created. | |
okapi_sign = Book(number=19, title="World Okapi Day", | |
description="Volca is holding a sign.", | |
text="World Okapi Day: October 18th.") | |
# Players: | |
volca = PlayerCharacter(name="Volca", gender=Gender.MALE, room_number=1, | |
description="Volca is a nice okapi! He's Elissa's friend.", | |
inventory=[okapi_sign]) | |
elissa = PlayerCharacter(name="Elissa", gender=Gender.FEMALE, flag=None, | |
description="A vixen, Volca's friend.", room_number=1) | |
strolik = PlayerCharacter(name="Strolik", gender=Gender.MALE, flag=None, | |
description="A goat, Elissa's friend.", weapon_readied=lance) | |
# FIXME: Game() depends on objects being referenced prior to calling it, so define them above here | |
game = Game() | |
# game.header(message="Instantiate player 'Strolik'") | |
strolik.add_to_inventory(item_name=adventurers_guide) | |
# game.header(message="Instantiate player 'Volca'") | |
# print(volca.name) | |
# print(volca.gender.value) | |
# print(volca) | |
volca.add_to_inventory(sword, 1) | |
volca.add_to_inventory(howling) | |
volca.add_to_inventory(item_name=lance, quantity=2) | |
volca.add_to_inventory(heal_spell, 5) | |
game.header("Start game using Volca") | |
game.parser(volca) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment