=======================
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
