Skip to content

Instantly share code, notes, and snippets.

@Pinacolada64
Last active November 23, 2022 23:48
Show Gist options
  • Save Pinacolada64/7fec32fba9a8fca08ae0fc9bf9bbee56 to your computer and use it in GitHub Desktop.
Save Pinacolada64/7fec32fba9a8fca08ae0fc9bf9bbee56 to your computer and use it in GitHub Desktop.
Getting object classes working.
"""
A note about positional parameters:
https://www.reddit.com/r/learnpython/comments/yptsyp/comment/ivkydz0/?utm_source=share&utm_medium=web2x&context=3
"""
import random
from datetime import datetime
from dataclasses import dataclass
from typing import Tuple
class Character(object):
def __init__(self, **kwargs):
self.name = kwargs['name']
self.gender = kwargs['gender']
# print(f"{kwargs['hit_points']=}")
x = int(kwargs['hit_points'])
# self.hit_points = dict(self.name, kwargs['hit_points'])
self.hit_points = kwargs['hit_points']
# self.food = list(kwargs['food'])
self.silver = dict(kwargs['silver'])
self.inv = list(kwargs['inv'])
self.allies = list(kwargs['allies'])
self.stat = dict(kwargs['stat'])
self.age = kwargs['age']
self.char_class = kwargs['char_class']
self.char_race = kwargs['char_race']
self.flag = dict(kwargs['flag'])
print(f'{self.name} {self.flag=}')
def display_stats(self):
# https://datagy.io/python-type-isinstance/
if isinstance(self, Character):
print(f"[{self.name} is a Character.]")
print(f" Name: {self.name:17}Gender: {self.gender.title()}")
print(f"Class: {self.char_class.title():19}Race: {self.char_race.title()}")
for stat_name, stat in self.stat.items():
print(f" {stat_name.title()}: {stat: 2d} ", end='') # end=''
print(f"HP: {self.hit_points:,}")
total = 0
for kind in ['in_hand', 'in_bank', 'in_bar']:
total += self.silver[kind]
self.display_silver(kind, right_justify=True)
print(f" Total silver: {total:>11,}")
# Silver in bank: nnn,nnn,nnn
# Total silver: nnn,nnn,nnn
if isinstance(self, Monster):
print("(TODO: is Monster...)")
print(f' []{"-=" * 20}-[]')
def display_inv(self):
print("\nInventory:")
# display silver in hand
self.display_silver('in_hand', right_justify=True)
if len(self.inv):
count = 0
for item in self.inv:
count += 1
print(f'{count: 2}. - {item.name}')
print(f'\t{item.description}')
if isinstance(item, Wand):
print("Charges.......Cast %")
print(f' {item.charges: 3}{"." * 9}{item.effectiveness: 3}%')
if isinstance(item, Book):
print("[Book book book book, yep yep yep yep yep uh huh!]")
else:
print("\tNothing")
print("\nAllies:")
if self.allies:
count = 0
for a in self.allies:
count += 1
print(f" {count: 2}. - {a.name:20}HP: {a.hit_points}")
if isinstance(a, Monster):
if a.flags:
print(f' Flags: {a.flags}')
else:
print("\tNone... sniff...")
def display_silver(self, kind: str, right_justify=False):
"""
:param right_justify: True=right-justify output
:param kind: in_hand, in_bank, in_bar
:return: "Silver [in hand | in bank | in bar]: value or "None"
"""
s = self.silver[kind]
# replace "_" with " " to transform e.g., "in_hand" -> "in hand":
display = kind.replace("_", " ")
if s:
if right_justify is False:
print(f'Silver {display}: {f"{s:,}" if s else "None"}')
else:
print(f'Silver {display:<7}: {f"{s:>11,}" if s else "None"}')
class Monster:
def __init__(self, **kwargs):
"""info about monsters"""
self.name = kwargs['name']
self.hit_points = kwargs['hit_points']
self.flags = kwargs['flags']
self.alignment = kwargs['alignment']
@dataclass
class DataclassCharacter:
def __init__(self):
"""
Attributes, flags and other stuff about characters.
This apparently does not work with Player.jsonload(**lh_data)
from server.
"""
name: str
id: int # for Player.connect
connection_id: int # TODO: eventually, CommodoreServer Internet Protocol connection ID
gender: str # [ male | female ]
# creates a new kwargs dict for each Character:
# set with Character.set_stat('xyz', val)
stats: dict['chr': int, 'con': int, 'dex': int, 'int': int, 'str': int, 'wis': int, 'egy': int]
# status flags:
flag: dict[
# status flags:
'room_descriptions': bool,
'autoduel': bool,
'hourglass': bool,
'expert': bool,
'more_prompt': bool,
'architect': bool,
# orator_mode: bool # TODO: define orator_mode more succinctly
# health flags:
'hungry': bool,
'thirsty': bool,
'diseased': bool,
'poisoned': bool,
'tired': bool,
'on_horse': bool,
'unconscious': bool,
# other flags:
'debug': bool,
'dungeon_master': bool,
'compass_used': bool,
'thug_attack': bool,
# game objectives:
'spur_alive': bool,
'dwarf_alive': bool,
'wraith_king_alive': bool,
'wraith_master': bool,
'tut_treasure': dict['examined': bool, 'taken': bool],
# magic items:
'gauntlets_worn': bool,
'ring_worn': bool,
'amulet_of_life': bool,
# wizard_glow stuff:
# 0 if inactive
# != 0 is number of rounds left, decrement every turn
'wizard_glow': int
]
"""
# things you can only do once per day (file_formats.txt)
'pr' has PRAYed once
'pr2' can PRAY twice per day (only if char_class is Druid)
"""
once_per_day: list
# TODO: money types may be expanded to platinum, electrum in future
# creates a new silver dict for each Character:
# in_bank: may be cleared on character death (TODO: look in TLOS source)
# in_bar: should be preserved after character's death (TODO: same)
# use Character.set_silver("kind", value)
silver: dict['in_hand': int, 'in_bank': int, 'in_bar': int]
age: int
birthday: Tuple[('0', '0', '0')] # (month, day, year)
guild: str # [civilian | fist | sword | claw | outlaw]
# 1 2 3 4 5 6 7 8 9
char_class: str # Wizard Druid Fighter Paladin Ranger Thief Archer Assassin Knight
race: str # ......Human Ogre Pixie Elf Hobbit Gnome Dwarf Orc Half-Elf
natural_alignment: str # good | neutral | evil (depends on race)
# client info:
client: dict[
# host (i.e., Python, C64, C128...?)
'name': None,
# screen dimensions:
'rows': int,
'cols': int,
# {'translation': None | ASCII | ANSI | Commodore }
'translation': str,
# colors for [bracket reader] text highlighting on C64/128:
'text': None,
'highlight': None,
'background': None,
'border': None]
hit_points: int
experience: int
# map stats:
map_level: int # cl
map_room: int # cr
moves_made: int
# combat stats:
armor: list # e.g., should it be its own class with attributes?
# Armor(object):
# def __init__(name, percent_left, armor_class, ...)
# TODO: weight (iron armor vs. padded leather armor will be different),
# could also define effectiveness, heavier armor absorbs more damage
shield: dict
shield_used: int # shield item being USEd
shield_skill: dict['item': int, 'skill': int]
# same:
# Shield(object):
# def __init__(name, percent_left, shield_size, ...)
# TODO: weight (iron shield vs. wooden shield will be different),
# could also define effectiveness, heavier shields absorb more damage
weapon: dict
weapon_used: int # if != 0, this weapon READYed
weapon_skill: dict # {weapon_item: int, weapon_skill: int}
weapon_left: int # map this to a rating
# bad_hombre_rating is calculated from stats, not stored in player log
honor_rating: int # helps determine current_alignment
formal_training: int
monsters_killed: int
"""
monsters_killed is not always the same as dead_monsters[];
still increment it if you re-kill a re-animated monster
"""
dead_monsters: list # keeps track of monsters for Zelda in the bar to resurrect
monster_at_quit: str
# ally stuff:
allies: list # (list of tuples?)
ally_inv: list
ally_abilities: list
# horse stuff:
has_horse: bool
horse_name: str
horse_armor: dict
has_saddlebags: bool
saddlebags: list # these can carry items for GIVE and TAKE commands
vinny_loan: dict # {amount_payable: int, days_til_due: int}
# inventory
"""
# TODO: There should be methods here for Inventory:
Inventory.item_held(item): check player/ally inventory, return True or False
(is it important to know whether the player or ally is carrying an item?)
maybe return Character or Ally object if they hold it, or None if no-one holds it
Or could be written:
if 'armor' in Character.inventory and 'armor' in Character.used:
# meaning 'armor' is in 'inventory' and 'used' lists?
# could this be shortened? perhaps:
# if Character.ItemHeldUsed('armor')
"""
max_inv: int
# also see weapons[], armor[], shields[]
food: list
drink: list
spells: list # list of dicts('spell_name': str, 'charges', 'chance_to_cast': int)
booby_traps: dict['room': int, 'combination': str] # combo: '[a-i]'
# TODO: increment at Character.save()
times_played: int
last_play_date: Tuple[(0, 0, 0)] # (month, day, year) like birthday
special_items: dict
# SCRAP OF PAPER is randomly placed on level 1 with a random elevator combination
# TODO: avoid placing objects in map "holes" where no room exists
# DINGHY # does not actually need to be carried around in inventory, I don't suppose, just a flag?
combinations: dict['elevator': (0, 0, 0),
'locker': (0, 0, 0),
'castle': (0, 0, 0)] # tuple: combo is 3 digits: (nn, nn, nn)
def create_character(self):
pass
def display_stats(self: Character):
print(f"Name: {self.name:20} Gender: {self.gender.title()}")
for stat_name, stat in self.stat.items():
print(f" {stat_name.title()}: {stat: 2d}") # end=''
print(f"HP: {self.hit_points:,}")
class Item:
def __init__(self, name, description):
self.name = name
self.description = description
class Wand(Item):
def __init__(self, name, description, charges, attribute, adjustment, effectiveness):
# name is already given in Item superclass, but AFAIK can't be left out here?
super().__init__(name, description)
# self.name = name
# self.description = description # shown in inv listing
self.charges = charges # how many shots this thing fires
self.attribute = attribute # which attribute it affects
self.adjustment = adjustment # how many points +/- it affects
self.effectiveness = effectiveness # random percentage it succeeds or fails
class Book(Item):
def __init__(self, name, description, text, attribute, adjustment, effectiveness):
super().__init__(name, description)
# self.name = name
# self.description = description # shown in inv listing
self.text = text # text displayed when read
self.attribute = attribute # which attribute it affects
self.adjustment = adjustment # how many points +/- it affects
self.effectiveness = effectiveness # % chance to adjust stats
# class Dog(pet):
# def __init__(self, name, chases_cats):
# pet.__init__(self, name, "Dog")
# self.chases_cats = chases_cats
#
# def ChasesCats(self):
# return self.chases_cats
guide = Book(name="Adventurer's Guide",
description="A guide to adventuring.",
text="text",
attribute="wis",
adjustment=5,
effectiveness=50)
wand = Wand(name="Wand of Understanding",
description="A short stout rod, inscribed 'Clue by four'. "
"Intelligence booster.",
charges=20, attribute="int",
adjustment=5,
effectiveness=100)
snrak = Item(name="Snrakity Thing",
description="A thing of snraking.")
toto = Monster(name="Toto",
description="A cute small dog.",
hit_points=random.randrange(25, 55),
flags=['living', 'reanimate'],
alignment='good'
)
"""
Amber = Character()
Amber.name = "Amber"
Amber.hit_points = 100
Amber.silver = {'in_hand': 2000, 'in_bank': 2000, 'in_bar': 1000}
Amber.inv = [guide]
Amber.allies = ['Rulan', 'Jee', 'Shaia']
Amber.stat = {'int': 20, 'wis': 20}
Amber.age = 25
Amber.gender = 'female'
print(f'Amber.gender=')
Rulan = Character()
Rulan.name = "Rulan"
Rulan.hit_points = 100
Rulan.silver = {'in_hand': 2000, 'in_bank': 2000, 'in_bar': 1000}
Rulan.inv = []
Rulan.allies = ['Jee']
Rulan.stat = {'int': 5}
Rulan.age = 46
Rulan.gender = 'male'
Rulan.char_class = 'polarfuchs'
Tricuspa = Character()
Tricuspa.name = "Tria"
Tricuspa.hit_points = 100
Tricuspa.silver = {'in_hand': 2000, 'in_bank': 2000, 'in_bar': 1000}
Tricuspa.inv = [guide, wand]
Tricuspa.allies = list
Tricuspa.stat = {'int': 5}
Tricuspa.age = 40
Tricuspa.gender = 'female'
Jee = Character()
Jee.name = "J'ee"
Jee.char_class = 'galaxy'
Jee.char_race = 'drgn'
Jee.hp = 100
Jee.silver = {'in_hand': 2000, 'in_bank': 2000, 'in_bar': 1000}
Jee.inv = [guide, wand, snrak]
Jee.allies = [Rulan]
Jee.stat = {'int': 18}
Shaia = Character()
Shaia.name = "Shaia"
Shaia.char_class = "faerie"
Shaia.hp = 2000
Shaia.silver = {'in_hand': 2000, 'in_bank': 2000, 'in_bar': 1000}
Shaia.inv = [wand]
Shaia.allies = ["Jee", "Rulan"]
Shaia.stat = {'int': 24}
Shaia.flag = dict['dungeon_master': True]
"""
def other_party_members(exclude: list):
# generate list of allies from party[], excluding name 'exclude'
# expected results:
# make_ally_list(exclude="J'ee"):
# ['Amber', 'Rulan', 'Shaia']
# result = ['{:#04x}'.format(x) for x in range(256) if x % 2 == 0]
# doesn't work: result = [name for name in party if exclude in party]
# FIXME: adds excluded party member
other_members = []
for char in party:
if char in exclude:
continue
else:
other_members.append(char)
print(other_members)
return other_members
Amber = Character(name="Amber",
hit_points=100,
silver={'in_hand': 2000, 'in_bank': 2000, 'in_bar': 1000},
inv=[guide],
allies=[],
stat={'int': 20, 'wis': 20},
age=25,
gender='female',
char_race='fennek',
char_class='large-eared',
flag={'dungeon_master': True,
'expert_mode': True}
)
# add party members as they're instantiated:
party = list([Amber])
Amber.allies.append(toto) # Toto is specific to only Amber
Rulan = Character(name="Rulan",
hit_points=100,
silver={'in_hand': 2000, 'in_bank': 2000, 'in_bar': 1000},
inv=[guide],
allies=[],
stat={'int': 20, 'wis': 20},
age=46,
gender='male',
char_class='fix-it',
char_race="polarfuchs",
flag={ # status flags:
'dungeon_master': True,
'room_descriptions': False,
'expert_mode': False,
'hourglass': True,
'autoduel': False,
'more_prompt': True,
# health flags:
'hungry': True,
'thirsty': False,
'poisoned': False,
'diseased': True,
'tired': True,
'unconscious': False,
'architect': False,
# orator_mode: False # TODO: define orator_mode more succinctly
'has_horse': False,
'mounted': False,
# other flags:
'debug': True,
'compass_used': False,
'thug_attack': False,
# game objectives:
'spur_alive': True,
'dwarf_alive': True,
'wraith_king_alive': True,
'wraith_master': False,
# magic items:
'tut_treasure': {'examined': False, 'taken': False},
'gauntlets_worn': False,
'ring_worn': False,
'amulet_of_life': False,
}
)
# append party members as they're instantiated:
party.append(Rulan)
Jee = Character(name="J'ee",
hit_points=100,
silver={'in_hand': 2000, 'in_bank': 2000, 'in_bar': 1000},
inv=[guide, snrak],
allies=[],
stat={'int': 20, 'wis': 20},
age=45,
gender='male',
char_class='galaxy',
char_race="drgn",
flag={'dungeon_master': True,
'expert_mode': True}
)
# append party members as they're instantiated:
# we can't use other_party_members() from within the Character instantiation
# since they're not all defined yet, so we do it here:
party.append(Jee)
Shaia = Character(name="Shaia",
hit_points=100,
silver={'in_hand': 2000, 'in_bank': 2000, 'in_bar': 1000},
inv=[guide, wand],
allies=[],
stat={'int': 20, 'wis': 20},
age=25,
gender='female',
char_class='fluttery',
char_race="fae",
flag={'dungeon_master': True,
'expert_mode': True}
)
party.append(Shaia)
# add allies to each character from party members, excluding themselves:
Rulan.allies = other_party_members(exclude=list(["Rulan"]))
Shaia.allies = other_party_members(exclude=list(["Shaia"]))
Jee.allies = other_party_members(exclude=list(["Jee"]))
"""
Rulan = Character()
Rulan.name = "Rulan"
Rulan.hit_points = 100
Rulan.silver = {'in_hand': 2000, 'in_bank': 2000, 'in_bar': 1000}
Rulan.inv = []
Rulan.allies = ['Jee']
Rulan.stat = {'int': 5}
Rulan.age = 46
Rulan.gender = 'male'
Rulan.char_class = 'polarfuchs'
Tricuspa = Character()
Tricuspa.name = "Tria"
Tricuspa.hit_points = 100
Tricuspa.silver = {'in_hand': 2000, 'in_bank': 2000, 'in_bar': 1000}
Tricuspa.inv = [guide, wand]
Tricuspa.allies = list
Tricuspa.stat = {'int': 5}
Tricuspa.age = 40
Tricuspa.gender = 'female'
Jee = Character()
Jee.name = "J'ee"
Jee.char_class = 'galaxy'
Jee.char_race = 'drgn'
Jee.hp = 100
Jee.silver = {'in_hand': 2000, 'in_bank': 2000, 'in_bar': 1000}
Jee.inv = [guide, wand, snrak]
Jee.allies = [Rulan]
Jee.stat = {'int': 18}
Shaia = Character()
Shaia.name = "Shaia"
Shaia.char_class = "faerie"
Shaia.hp = 2000
Shaia.silver = {'in_hand': 2000, 'in_bank': 2000, 'in_bar': 1000}
Shaia.inv = [wand]
Shaia.allies = ["Jee", "Rulan"]
Shaia.stat = {'int': 24}
Shaia.flag = dict['dungeon_master': True]
"""
"""
# https://bobbyhadz.com/blog/python-valueerror-update-sequence-element-0-has-length
a = dict(name='Alice', age=29)
b = {'name': 'Alice', 'age': 29}
c = dict(zip(['name', 'age'], ['Alice', 29]))
d = dict([('name', 'Alice'), ('age', 29)])
e = dict({'name': 'Alice', 'age': 29})
f = dict({'name': 'Alice'}, age=29)
print(a == b == c == d == e == f) # True
"""
# startup:
print("Your status:\n")
print(f"Dungeon Master: {Rulan.flag['dungeon_master']}")
while True:
# print()
# parser, such as it is:
if Rulan.flag['hourglass'] is True:
now = datetime.now()
current_time = now.strftime("%I:%M:%S %p")
print(f"Time: {current_time} ", end='')
if Rulan.flag['expert_mode'] is False:
print(f'HP: {Rulan.hit_points} ', end='')
print()
cmd = input("Command: ").lower()
print() # blank line
if cmd == "stat":
for member in party:
Character.display_stats(member)
if cmd in ["i", "inv"]:
for member in party:
Character.display_inv(member)
if cmd == "edit":
count = 0
for k, v in Rulan.flag.items():
flag = k.replace("_", " ").title()
# TODO: some of these flags will read "Yes/No" rather than "On/Off"
# add a dict() entry for {"kind": "yes/no"} or {"kind": "on/off"}
status = "On" if v is True else "Off"
count += 1
print(f'{count: >2}. {flag:.<20}: {status}')
print("(Work in progress.)")
if cmd in ["q", "quit"]:
# real game would ask "are you sure?"
exit()
@Pinacolada64
Copy link
Author

Output:

Command: stat
[Amber is a Character.]
 Name: Amber            Gender: Female
Class: large-eared        Race: fennek
  Int:  20     Wis:  20   HP: 100

Inventory:
Silver: 2,000
 1. - Adventurer's Guide
	A guide to adventuring.
[Book book book book, yep yep yep yep yep uh huh!]

Allies:
   1. - Toto                HP: 40
   Flags: ['living', 'reanimate']

[Rulan is a Character.]
 Name: Rulan            Gender: Male
Class: fix-it             Race: polarfuchs
  Int:  20     Wis:  20   HP: 100

Inventory:
Silver: 2,000
 1. - Adventurer's Guide
	A guide to adventuring.
[Book book book book, yep yep yep yep yep uh huh!]

Allies:
   1. - Amber               HP: 100
   2. - Rulan               HP: 100
   3. - J'ee                HP: 100
   4. - Shaia               HP: 100

[J'ee is a Character.]
 Name: J'ee             Gender: Male
Class: galaxy             Race: drgn
  Int:  20     Wis:  20   HP: 100

Inventory:
Silver: 2,000
 1. - Adventurer's Guide
	A guide to adventuring.
[Book book book book, yep yep yep yep yep uh huh!]
 2. - Snrakity Thing
	A thing of snraking.

Allies:
   1. - Amber               HP: 100
   2. - Rulan               HP: 100
   3. - J'ee                HP: 100
   4. - Shaia               HP: 100

[Shaia is a Character.]
 Name: Shaia            Gender: Female
Class: fluttery           Race: fae
  Int:  20     Wis:  20   HP: 100

Inventory:
Silver: 2,000
 1. - Adventurer's Guide
	A guide to adventuring.
[Book book book book, yep yep yep yep yep uh huh!]
 2. - Wand of Understanding
	A short stout rod, inscribed 'Clue by four'. Intelligence booster.
Charges.......Cast %
    20......... 100%

Allies:
   1. - Amber               HP: 100
   2. - Rulan               HP: 100
   3. - J'ee                HP: 100
   4. - Shaia               HP: 100

Command: 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment