diff --git a/context/combat-damage.md b/context/combat-damage.md index 39fc05b..c89be24 100644 --- a/context/combat-damage.md +++ b/context/combat-damage.md @@ -374,6 +374,26 @@ way the crit path does — a `TakeDamage` call there will silently do nothing. T Myomers' Performance `@004b8bb9` (an un-powered self-repair) is dead code in the 1995 binary itself: see [[subsystems]] WAVE 6. +## ⚠ ZONE SELECTION IS A WEIGHTED LOTTERY — pixel-precise limb damage does not exist (2026-07-29) [T1] +Issue #73 ("fired only at the left arm, damage credited elsewhere, no crits") is **largely the +authored 1995 model, not a bug**. The chain (`dmgtable.cpp`, binary-faithful, byte-verified stream +format): impact point → `WorldToLocal` → **height layer** (`floor(layerCount·y/heightRef)`) → +**pie slice** (`atan2(local.z, local.x)`, optionally rotated by live torso twist — +`rotateWithTorso` per layer) → `DamageZonePercentTable::SelectZone()` = **`RandomUnit()` against +cumulative percent thresholds** (`@0x49de14`). Each slice sprays damage across an authored +*distribution* of zones — aiming at a limb at best biases WHICH SLICE you strike; the zone within +it is dice. Measured live (L/C/R aim sweep at 8u, `BT_DMG_LOG`): 24-46 hits per aim point spread +across 6+ zones each, with the distribution *shifting* by aim — the model working as designed. +Consequences for triage: reports of "damage landed somewhere I didn't aim" need this base rate +before being called bugs; crit expectations from aimed fire are likewise probabilistic. +**Residual genuine question [T3]:** the shooter's pick point comes from `Mech::PickRayHit` = a +**whole-mech AABB slab test** (a PORT stand-in — the binary's 0x37c/0x388/0x38c writer is in the +un-exported gap, never decompiled). Theta computed from a flat box FACE clusters toward the +facing slices, so flank slices may be under-reachable from frontal shots vs. the pod (which +plausibly intersected the mech's *cylinder* — the damage table is literally cylindrical). +Deciding whether that distortion is material needs a per-hit theta probe + a wheel dump (slices × +percent tables, MadCat) — see #73 on the tracker. + ## 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