======================= loot and corpse system ======================= the death system has three phases: knockout, finisher, and decomposition. corpses are containers that rot over time. loot is probabilistic. loot tables =========== loot is defined per-mob in toml with ``LootEntry`` records:: [[loot]] name = "crude club" chance = 0.8 description = "a crude wooden club" [[loot]] name = "gold coin" chance = 0.5 min_count = 1 max_count = 3 fields: - ``name`` - item name - ``chance`` - probability (0.0-1.0) to drop - ``min_count`` / ``max_count`` - quantity range (defaults to 1) - ``description`` - item description string ``roll_loot()`` processes the table entry by entry. for each entry, it rolls random against chance. if successful, picks a count in the min/max range and creates that many ``Thing`` objects. returns a flat list of items. death flow ========== knockout (automatic) -------------------- when stamina or pl drops to/below zero, the entity's ``posture`` becomes ``"unconscious"``. the mob stays registered in ``mobs`` dict. no corpse is created yet. items stay in the mob's inventory. finisher (explicit) ------------------- requires a command (e.g. ``snapneck``) targeting an unconscious entity. sets ``pl`` to -100 (dead). loads mob template to get loot table. calls ``create_corpse()`` with the mob, zone, and loot table. no corpse until finisher — knockout alone doesn't drop loot. corpse creation =============== ``create_corpse(mob, zone, ttl=300, loot_table=None)`` 1. creates ``Corpse`` object (extends ``Container``) at mob's coords 2. names it ``"{mob.name}'s corpse"`` 3. transfers all items from mob inventory to corpse 4. rolls loot table, adds generated items to corpse 5. calls ``despawn_mob()`` to remove mob from world 6. registers corpse in global ``active_corpses`` list 7. returns the corpse corpse properties: - ``closed=False`` - always open - ``portable=False`` - can't be picked up - ``decompose_at`` - timestamp (now + ttl seconds) corpses work with existing item commands (``get``, ``put``, ``look in``) because they're containers. decomposition ============= ``process_decomposing()`` runs every game loop tick. checks each corpse in ``active_corpses`` against current time. when ``decompose_at`` passes: 1. broadcasts "X decomposes." to entities on same tile 2. clears all items (items rot with corpse — no loot recovery) 3. removes corpse from world 4. removes from ``active_corpses`` registry ttl-based cleanup ensures corpses don't clutter the world. default 300s (5min). code ==== implementation: - ``src/mudlib/loot.py`` - loot table dataclass and roll logic - ``src/mudlib/corpse.py`` - Corpse container, creation, decomposition - ``src/mudlib/commands/snapneck.py`` - finisher command - ``content/mobs/*.toml`` - per-mob loot tables related systems: - ``src/mudlib/combat.py`` - knockout logic (posture="unconscious") - ``src/mudlib/entity.py`` - Entity.posture, inventory - ``src/mudlib/item.py`` - Thing, Container base classes - ``src/mudlib/server.py`` - calls process_decomposing() each tick