Mi2dRPGamEng/engine/item.py

66 lines
4.3 KiB
Python

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
consumable: bool = False # single-use: activate_hand unwields (and removes) it after one
# successful grants_ability cast instead of leaving it wielded, e.g. a stimulant syringe -
# as opposed to a reusable wand/rod, which just goes on cooldown and stays in hand
is_hacking_implant: bool = False # an installed implant of this kind both applies
# hack_bonus/hack_min_roll_percent to every tech check AND lets a bare hand attempt a hack
# with no wielded hacking_tool at all - see resources/logic/hacking.py::find_hacking_implant
hack_bonus: float = 0.0 # flat modifier added to a tech skill check's effective_skill
hack_min_roll_percent: float | None = None # floors the raw d20 roll at this fraction of
# SKILL_CHECK_DIE (e.g. 0.45 = "never worse than a rolled 9") - None = no floor
secret: bool = False # excluded from discovery UI (e.g. DevSpawnMenu's cycle list) - still
# fully functional if granted directly (by def id, save editing, etc.)
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