tabletop-frog/src/ttfrog/db/schema/item.py

152 lines
5.7 KiB
Python
Raw Normal View History

2024-08-29 15:14:47 -07:00
from typing import List
2024-07-28 13:55:19 -07:00
from sqlalchemy import ForeignKey, String
2024-08-03 17:46:12 -07:00
from sqlalchemy.orm import Mapped, mapped_column, relationship
2024-07-28 13:55:19 -07:00
from ttfrog.db.base import BaseObject, EnumField
2024-08-20 09:30:23 -07:00
from ttfrog.db.schema.classes import CharacterClass
2024-08-03 17:46:12 -07:00
from ttfrog.db.schema.constants import DamageType
from ttfrog.db.schema.modifiers import ModifierMixin
2024-07-28 13:55:19 -07:00
__all__ = [
"Item",
"Spell",
]
2024-08-03 17:46:12 -07:00
ITEM_TYPES = [
"ITEM",
"SPELL",
"SCROLL",
"WEAPON",
"ARMOR",
"SHIELD",
2024-08-29 17:10:39 -07:00
"CONTAINER",
2024-08-03 17:46:12 -07:00
]
2024-08-29 15:14:47 -07:00
RECHARGE_TIMES = [
"short rest",
"long rest",
"dawn",
]
COST_TYPES = ["Action", "Bonus Action", "Reaction"]
2024-08-20 09:30:23 -07:00
RARITY = ["Common", "Uncommon", "Rare", "Very Rare", "Legendary", "Artifact"]
2024-08-03 17:46:12 -07:00
2024-07-28 13:55:19 -07:00
2024-08-03 17:46:12 -07:00
ItemType = EnumField("ItemType", ((k, k) for k in ITEM_TYPES))
Rarity = EnumField("Rarity", ((k, k) for k in RARITY))
2024-08-29 15:14:47 -07:00
RechargeTime = EnumField("RechargeTime", ((k.replace(" ", "_").upper(), k) for k in RECHARGE_TIMES))
Cost = EnumField("Cost", ((k, k) for k in COST_TYPES))
def item_property_creator(fields):
if isinstance(fields, list):
for f in fields:
yield f
elif isinstance(fields, ItemProperty):
return fields
return ItemProperty(**fields)
2024-07-28 13:55:19 -07:00
2024-08-03 17:46:12 -07:00
class Item(BaseObject, ModifierMixin):
2024-07-28 13:55:19 -07:00
__tablename__ = "item"
__mapper_args__ = {"polymorphic_identity": ItemType.ITEM, "polymorphic_on": "item_type"}
2024-08-29 15:14:47 -07:00
2024-07-28 13:55:19 -07:00
id: Mapped[int] = mapped_column(init=False, primary_key=True, autoincrement=True)
name: Mapped[str] = mapped_column(String(collation="NOCASE"), nullable=False, unique=True)
2024-08-03 17:46:12 -07:00
description: Mapped[str] = mapped_column(String, nullable=True, default=None)
item_type: Mapped[ItemType] = mapped_column(default=ItemType.ITEM, nullable=False)
rarity: Mapped[Rarity] = mapped_column(default=Rarity.Common, nullable=False)
requires_attunement: Mapped[bool] = mapped_column(nullable=False, default=False)
2024-07-28 13:55:19 -07:00
consumable: Mapped[bool] = mapped_column(default=False)
2024-07-28 20:47:42 -07:00
count: Mapped[int] = mapped_column(nullable=False, default=1)
2024-08-03 17:46:12 -07:00
2024-08-29 15:14:47 -07:00
charges: Mapped[int] = mapped_column(nullable=True, info={"min": 0}, default=None)
recharge_time: Mapped[RechargeTime] = mapped_column(default=RechargeTime.LONG_REST)
recharge_amount: Mapped[str] = mapped_column(String(collation="NOCASE"), default="1")
2024-08-03 17:46:12 -07:00
_class_restrictions: Mapped[int] = mapped_column(ForeignKey("character_class.id"), nullable=True, default=None)
class_restrictions: Mapped["CharacterClass"] = relationship(init=False)
2024-08-29 15:14:47 -07:00
properties: Mapped[List["ItemProperty"]] = relationship(
uselist=True, cascade="all,delete,delete-orphan", lazy="immediate", default_factory=lambda: []
)
2024-08-03 17:46:12 -07:00
# _spells: Mapped[int] = mapped_column(ForeignKey("spell.id"), nullable=True, default=None)
# spells: Mapped["Spell"] = relationship(init=False)
2024-07-28 13:55:19 -07:00
2024-08-29 15:14:47 -07:00
@property
def has_charges(self):
return self.charges is not None
2024-07-28 13:55:19 -07:00
class Spell(Item):
__tablename__ = "spell"
__mapper_args__ = {"polymorphic_identity": ItemType.SPELL}
2024-07-28 20:47:42 -07:00
id: Mapped[int] = mapped_column(ForeignKey("item.id"), primary_key=True, init=False)
2024-08-21 14:14:37 -07:00
item_type: Mapped[ItemType] = ItemType.SPELL
2024-07-28 13:55:19 -07:00
level: Mapped[int] = mapped_column(nullable=False, info={"min": 0, "max": 9}, default=0)
concentration: Mapped[bool] = mapped_column(default=False)
2024-08-03 17:46:12 -07:00
class Weapon(Item):
__tablename__ = "weapon"
__mapper_args__ = {"polymorphic_identity": ItemType.WEAPON}
id: Mapped[int] = mapped_column(ForeignKey("item.id"), primary_key=True, init=False)
2024-08-21 14:14:37 -07:00
item_type: Mapped[ItemType] = ItemType.WEAPON
2024-08-03 17:46:12 -07:00
damage_die: Mapped[str] = mapped_column(nullable=False, default="1d6")
damage_type: Mapped[DamageType] = mapped_column(nullable=False, default=DamageType.slashing)
attack_range: Mapped[int] = mapped_column(nullable=False, info={"min": 0}, default=0)
attack_range_long: Mapped[int] = mapped_column(nullable=True, info={"min": 0}, default=None)
targets: Mapped[int] = mapped_column(nullable=False, info={"min": 1}, default=1)
martial: Mapped[bool] = mapped_column(default=False)
melee: Mapped[bool] = mapped_column(default=False)
ammunition: Mapped[bool] = mapped_column(default=False)
finesse: Mapped[bool] = mapped_column(default=False)
heavy: Mapped[bool] = mapped_column(default=False)
light: Mapped[bool] = mapped_column(default=False)
loading: Mapped[bool] = mapped_column(default=False)
reach: Mapped[bool] = mapped_column(default=False)
thrown: Mapped[bool] = mapped_column(default=False)
two_handed: Mapped[bool] = mapped_column(default=False)
versatile: Mapped[bool] = mapped_column(default=False)
silvered: Mapped[bool] = mapped_column(default=False)
adamantine: Mapped[bool] = mapped_column(default=False)
2024-08-29 15:14:47 -07:00
magical: Mapped[bool] = mapped_column(default=False)
2024-08-03 17:46:12 -07:00
@property
def ranged(self):
return self.attack_range > 0
2024-08-21 14:14:37 -07:00
class Shield(Item):
__tablename__ = "shield"
__mapper_args__ = {"polymorphic_identity": ItemType.SHIELD}
id: Mapped[int] = mapped_column(ForeignKey("item.id"), primary_key=True, init=False)
item_type: Mapped[ItemType] = ItemType.SHIELD
class Armor(Item):
__tablename__ = "armor"
__mapper_args__ = {"polymorphic_identity": ItemType.ARMOR}
id: Mapped[int] = mapped_column(ForeignKey("item.id"), primary_key=True, init=False)
item_type: Mapped[ItemType] = ItemType.ARMOR
2024-08-29 15:14:47 -07:00
class ItemProperty(BaseObject):
__tablename__ = "item_property"
id: Mapped[int] = mapped_column(init=False, primary_key=True, autoincrement=True)
name: Mapped[str] = mapped_column(String(collation="NOCASE"), nullable=False, unique=True)
description: Mapped[str] = mapped_column(String, nullable=True, default=None)
charge_cost: Mapped[int] = mapped_column(nullable=True, info={"min": 0}, default=None)
item_id: Mapped[int] = mapped_column(ForeignKey("item.id"), default=0)
# action/reaction/bonus
# modifiers?