Skip to content

Instantly share code, notes, and snippets.

@Pinacolada64
Created January 9, 2025 22:46
Show Gist options
  • Save Pinacolada64/0c33d4352bb2e187404940988f35a838 to your computer and use it in GitHub Desktop.
Save Pinacolada64/0c33d4352bb2e187404940988f35a838 to your computer and use it in GitHub Desktop.
Trying out some Item classes and functions
from dataclasses import dataclass
from enum import StrEnum
from typing import Optional
# from flags import Size
@dataclass
class Item(object):
name: str = None
# percent_left: int: depletes with each use, 0 indicating the item is destroyed; or
# percent_left: None indicates a one-time use (e.g., bullets can't be reused)
percent_left: Optional[int] = None
quantity: int = 1
class Armor(Item):
armor_class: int
class Shield(Item):
# TODO: weight (iron shield vs. wooden shield will be different),
# could also define effectiveness, heavier shields absorb more damage
# FIXME: int will eventually be Size, but circular reference currently prevents using it
size: int
skill: int
@dataclass
class WeaponClass(StrEnum):
# in original code, 1 gets changed to 10:
ENERGY = 1
HACK_SLASH_BASH = 2
POKE_JAB = 3
# I don't know why class 4 was skipped, but keep it that way
POLE_RANGED = 5
# likewise, classes 6 & 7 were skipped
# +10% surprise against enemy
PROJECTILE = 8
PROXIMITY = 9
@dataclass
class Weapon(Item):
super().__init__(**kwargs)
weapon_class: WeaponClass
@dataclass
class Spell:
charges: int
chance_to_cast: int
@dataclass
class StormWeapon(Weapon):
# enchanted weapon with a personality, may be able to cast spells
can_cast_spells: bool = True
spell_list: Optional[Spell | list[Spell]] = None
@dataclass
class Ammunition(Item):
quantity: int = 1
enchanted: bool = False # I think there are some magical ammunition items
@dataclass
class AmmunitionWeapon(Weapon):
super().__init__(percent_left)
# a weapon that needs ammunition (e.g., SLING needs ROCKS or STEELIES, BOW needs ARROW, etc.)
takes_ammunition_type: Optional[list[Ammunition] | Ammunition] = None
loaded_ammunition_type: Optional[Ammunition] = None # None specifies the weapon being unloaded
# some might go with multiple Weapons: e.g., bullets;
# None is an option to avoid partially instantiated objects:
goes_with: Optional[Weapon | list[Weapon]] = None
def load_weapon(self, ammo: Ammunition):
# this can be called for SABRE POWER and the POWER PAK on the Spaceship level:
if self.takes_ammunition_type == ammo:
print(f"You load {ammo.quantity} {ammo.name} into the {self.name}.")
else:
# TODO: different messages for different weapon classes
if self.weapon_class == WeaponClass.PROJECTILE:
print(f"The {self.name} jams and cannot be fired. "
f"It is loaded with the wrong kind of ammunition.")
def has_correct_ammo(self):
# return whether the loaded ammunition type is correct for the weapon
if isinstance(self.takes_ammunition_type, list):
return self.loaded_ammunition_type in self.takes_ammunition_type
else:
return self.takes_ammunition_type == self.loaded_ammunition_type
if __name__ == '__main__':
# trying to avoid a circular reference here by stating 'bullet.goes_with=colt_45';
# colt_45 isn't instantiated yet
bullets = Ammunition(name=".45 bullets", quantity=6, percent_left=None)
colt_45 = AmmunitionWeapon(name="Colt .45",
percent_left=100,
takes_ammunition_type=bullets,
loaded_ammunition_type=None,
# likewise, avoiding circular reference here, set 'goes_with' later:
goes_with=None,
weapon_class=WeaponClass.PROJECTILE)
# now that the gun is instantiated, we can say the bullet goes with the gun:
bullets.goes_with = colt_45
colt_45.loaded_ammunition_type = bullets
colt_45.load_weapon(bullets)
if colt_45.has_correct_ammo():
print(f"The {colt_45.name} can be fired using {colt_45.takes_ammunition_type}, of which you have "
f"{colt_45.loaded_ammunition_type.quantity}.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment