From a5dd0eabc505a59310d9a4fdb3d71a8ebc3971fd Mon Sep 17 00:00:00 2001 From: Joe DiPrima Date: Wed, 29 Jul 2026 08:42:23 -0500 Subject: [PATCH] issue #73 investigated: zone selection is a weighted lottery -- per-limb aiming never existed Night-6 report: three players, controlled conditions, "fired only at the left arm, damage credited all over the paper doll, no crits". Chased it to the bottom and the bottom is the authored 1995 model, working as designed. The zone a hit credits is chosen by dice, in binary-faithful code reading binary-shipped tables (dmgtable.cpp, stream format byte-verified): impact point -> height layer (floor(layerCount*y/heightRef)) -> pie slice (atan2(z,x) around the vertical axis, optionally rotating with live torso twist) -> DamageZonePercentTable::SelectZone() = RandomUnit() rolled against cumulative percent thresholds (@0x49de14). Every slice carries an authored DISTRIBUTION of zones. Aiming at a limb at best biases which slice you strike; the zone inside it is a weighted roll. Pixel-precise limb damage does not exist in Tesla 4.10. Measured live to be sure the code read was real: solo dummy, walked to 8u, aim pinned left/center/right across the silhouette, trigger held. 24-46 hits per aim point, each spread across 6+ zones (the percent tables), with the distribution shifting by aim point (the slice selection responding). Both halves of the model visibly working. What remains genuinely open, and is now the whole of #73: the shooter's pick point comes from Mech::PickRayHit, a whole-mech AABB slab test -- a port stand-in, since the binary's 0x37c/0x388/0x38c writer sits in an un-exported gap nobody has decompiled. Theta computed from a flat box FACE clusters toward the slices facing the shooter, so flank slices (presumably arm-heavy) may be under-reachable from frontal shots compared with the pod, which plausibly intersected the mech's cylinder -- the damage table is literally cylindrical. Deciding that needs a per-hit theta probe and a one-shot wheel dump; if confirmed, the fix is a ray-vs-cylinder pick replacing the box slab. Filed on #73 with the plan. KB: combat-damage.md gets the lottery model as a load-bearing triage fact -- "damage landed somewhere I didn't aim" now has a documented base rate, and crit expectations from aimed fire are probabilistic by design. Co-Authored-By: Claude Fable 5 --- context/combat-damage.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) 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