diff --git a/context/combat-damage.md b/context/combat-damage.md index c89be24..4cc9172 100644 --- a/context/combat-damage.md +++ b/context/combat-damage.md @@ -394,6 +394,25 @@ plausibly intersected the mech's *cylinder* — the damage table is literally cy Deciding whether that distortion is material needs a per-hit theta probe + a wheel dump (slices × percent tables, MadCat) — see #73 on the tracker. +## ⚠ CRITS NEVER ROLL FROM WEAPON FIRE — the trigger is un-exported + the sink is a stub (2026-07-29) [T1] +The authored crit machinery exists and is reconstructed — `Mech__DamageZone::CriticalHit @0049ccc4` +(half the damage to armour, half to ONE critical subsystem chosen by `criticalWeight`, capped by +`damagePercentage`) — but **nothing in the port calls it**. Raw byte-scan of the binary: exactly ONE +call site, `@0x4a0461`, inside the **un-exported gap** (no decomp covers `0x4a03xx-0x4a05xx` — the +same dark region as the `0x37c/0x388/0x38c` pick writer), so the crit TRIGGER CONDITIONS (per-hit +chance? threshold crossing?) are unknown and unreconstructed. Second layer: +`MechSubsystem::TakeDamage` is an **empty bring-up stub** (`btstubs.cpp:179`), so even a wired +caller would measure a delta of 0 through `ApplyDamageAndMeasure` (and the weapon-family overrides +chain to the engine base whose private-zone write is the zero-`damageScale` no-op — see the +subsystem-zone finding above). Net: **the Critical view lights ONLY on zone destruction +(`SendSubsystemDamage`, direct pin) or ammo cook-off (`DistributeCriticalHit`, direct pin), never +from accumulating fire.** The DISPLAY is fine — the paper doll shows ZONE ARMOR, the Critical panel +shows SUBSYSTEM crits (different data by design); the panel's near-permanent emptiness is the gap. +Field signature (night 6, Conn Man): "Armor panel damage. Critical damage display did not show any +crits." **#28 (vital-subsystem-crit death path) is very likely blocked by the same missing caller.** +Recovery: raw-disasm the `@0x4a04xx` container (#60-class gap work) for the trigger; dump +MechSubsystem vtable `0050e210` slot `+0x24` for the real TakeDamage body; wire both. Tracker: #80. + ## Damage delivery + the real damage model `Entity::TakeDamageMessage(id, size, inflictingEntityID, zone, Damage&)` → `target->Dispatch`. **Base handler IGNORES zone==−1** (`Entity::TakeDamageMessageHandler`, ENTITY.cpp:878 — returns on