from sqlalchemy import ForeignKey, String from sqlalchemy.orm import Mapped, mapped_column, relationship from ttfrog.db.base import BaseObject, EnumField from ttfrog.db.schema.constants import DamageType from ttfrog.db.schema.modifiers import ModifierMixin from ttfrog.db.schema.classes import CharacterClass __all__ = [ "Item", "Spell", ] ITEM_TYPES = [ "ITEM", "SPELL", "SCROLL", "WEAPON", "ARMOR", "SHIELD", ] RARITY = [ "Common", "Uncommon", "Rare", "Very Rare", "Legendary", "Artifact" ] ItemType = EnumField("ItemType", ((k, k) for k in ITEM_TYPES)) Rarity = EnumField("Rarity", ((k, k) for k in RARITY)) class Item(BaseObject, ModifierMixin): __tablename__ = "item" __mapper_args__ = {"polymorphic_identity": ItemType.ITEM, "polymorphic_on": "item_type"} 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) 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) consumable: Mapped[bool] = mapped_column(default=False) count: Mapped[int] = mapped_column(nullable=False, default=1) _class_restrictions: Mapped[int] = mapped_column(ForeignKey("character_class.id"), nullable=True, default=None) class_restrictions: Mapped["CharacterClass"] = relationship(init=False) # _spells: Mapped[int] = mapped_column(ForeignKey("spell.id"), nullable=True, default=None) # spells: Mapped["Spell"] = relationship(init=False) class Spell(Item): __tablename__ = "spell" __mapper_args__ = {"polymorphic_identity": ItemType.SPELL} id: Mapped[int] = mapped_column(ForeignKey("item.id"), primary_key=True, init=False) level: Mapped[int] = mapped_column(nullable=False, info={"min": 0, "max": 9}, default=0) concentration: Mapped[bool] = mapped_column(default=False) item_type: Mapped[ItemType] = mapped_column(default=ItemType.SPELL, init=False) class Weapon(Item): __tablename__ = "weapon" __mapper_args__ = {"polymorphic_identity": ItemType.WEAPON} id: Mapped[int] = mapped_column(ForeignKey("item.id"), primary_key=True, init=False) damage_die: Mapped[str] = mapped_column(nullable=False, default="1d6") damage_type: Mapped[DamageType] = mapped_column(nullable=False, default=DamageType.slashing) item_type: Mapped[ItemType] = mapped_column(default=ItemType.WEAPON) 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) @property def ranged(self): return self.attack_range > 0