from __future__ import annotations from dataclasses import dataclass @dataclass(frozen=True) class ItemDef: id: str name: str width: int height: int texture: str | None = None color: tuple[int, int, int] = (255, 0, 255) stackable: bool = False max_stack: int = 1 clothing_slot: str | None = None # set if this item can be worn (e.g. "torso", "back") grants_inventory_size: tuple[int, int] | None = None # e.g. a backpack, when worn armor_reduction: float = 0.0 # flat damage reduction while worn (clothing) arm_slots_required: int = 0 # sleeved garments only (e.g. a jacket): 0 = no arm-count # constraint (hats, backpacks, pants, ...); a garment with more sleeves than the wearer # has arms still fits (extras go unused), fewer does not - see Character.wear_item compatible_body_types: tuple[str, ...] = () # e.g. ("biped",), ("quadruped",) - which # SpeciesDef.body_type values this item can be worn by at all; empty = fits any body type weapon_skill: str | None = None # bio skill this weapon's attacks are checked against weapon_damage: float = 0.0 # flat bonus added on a successful skill check weapon_range: int = 1 # tiles; 1 = melee (adjacent), >1 = ranged (used by shooting) projectile_type: str | None = None # e.g. "bullet", "arrow" - what a shield needs to block it hands_required: int = 1 # 1 or 2; two-handed items occupy a hand pair when wielded shield_block_bonus: float = 0.0 # bonus added to the defender's blocking skill check blockable_projectile_types: tuple[str, ...] = () # projectile_types this shield stops tool_kind: str | None = None # e.g. "deconstructor", "constructor" builds_tile_layer: str | None = None # which layer this material can construct (used with a constructor tool) builds_tile_layer_def_id: str | None = None # which def gets placed there ammo_type: str | None = None # set on ammo items: "small_caliber", "heavy_caliber", "shotgun_shell", ... ranged_knockback: float = 0.0 # ammo items: tiles of knockback dealt on impact ammo_damage_bonus: float = 0.0 # ammo items: extra flat damage added to the weapon's own bonus compatible_ammo_types: tuple[str, ...] = () # ammo-based weapons: which ammo_types they accept magazine_size: int = 0 # ammo-based weapons: base capacity (0 = not ammo-fed, e.g. bow/pistol_basic) aim_cone_degrees: float = 0.0 # ranged weapons: base spread; 0 = perfectly accurate pellet_count: int = 1 # shotgun-style weapons: independent projectiles fired per shot blast_radius: int = 0 # rocket-style weapons: AoE radius in tiles (0 = no AoE) attachment_kind: str | None = None # e.g. "scope", "stock", "magazine" aimcone_reduction_degrees: float = 0.0 # attachment effect magazine_capacity_bonus: int = 0 # attachment effect (e.g. an extended mag) melee_knockback: float = 0.0 # melee weapons: base knockback tiles, scaled by attacker strength grants_ability: str | None = None # e.g. "time_warp_sphere" - triggered on activation, see resources/logic/abilities.py is_implant: bool = False # slotless: installed directly on the character, not held/worn class ItemInstance: def __init__(self, item_id: str, def_id: str, quantity: int = 1): self.item_id = item_id self.def_id = def_id self.quantity = quantity