Damage economy RECONCILED: 3 stand-ins fixed, 3 paths confirmed authentic (task #60)
Full 5-path audit of the damage economy vs the decomp (5-finder + adversarial-verify workflow), resolving the KB self-contradiction the binary-coverage audit flagged. CONFIRMED AUTHENTIC as-is (no change needed): - Energy beam (emitter.cpp): damagePortion = authored DamageAmount x (charge/seekV)^2; the ctor x1e7 and fire x1e-7 cancel (_DAT_004bafbc dumped from the exe = x87 80-bit 1e-7 exactly). - Autocannon (projweap.cpp): full authored DamageAmount from resource +0x19C delivered unmodified; the 0.0625 at :667 is the shooter's own gyro recoil, not the round. - Zone-armor BASE model: damageLevel += amount x damageScale[type] (engine DAMAGE.cpp:379, called mechdmg.cpp:427), legs x0.5, 1.0=dead. 3 STAND-INS FIXED (all byte-verified against the decomp): - A. mechdmg.cpp:451 -- read the phantom `stance` member (no binary offset, zero writers -> perma-0), so the leg-shot-out -> fall/death branch was DEAD. Now MovementMode() (mech+0x40, @part_012.c:6910). - B. mechdmg.cpp:458 -- guarded the leg partial-failure graphic on the always-0 IsAirborne() stub where the binary calls IsDisabled() (@0049fb54 = movementMode 2||9). On a wreck the binary SUPPRESSES the write; the stub let it corrupt graphicAlarm 9->4/3 -- the task-#52 wreck-graphic bug, now fixed AT SOURCE (was only masked by the IsMechDestroyed latch). - C. mech4.cpp:1551 -- flat kShotDamage=12 fed as the kill-score damageAmount (the KB self-contradiction: task #8 claimed it retired, but it was live). The score handler @0x4c02e4 derives the whole kill award from it, so every kill scored identically regardless of weapon. Now lastInflictingDamage -- the real killing-blow magnitude, latched in TakeDamageMessageHandler (mech.cpp:624), mirroring the per-hit path (mech4.cpp:1207). The phantom `int stance` slot is reused for the new Scalar member (size-neutral, no layout shift); init 0 in the ctor. DEFERRED (task #60-D, documented): the missile CLUSTER model -- the port fires N flying rounds (net armor total authentic) vs the binary's ONE missile with a random burstCount cluster roll (loses cluster variance + single-zone concentration). Blocked on an OPEN decomp semantic (does burstCount multiply armor or only the gyro kick? settle at FUN_004bef78 -> FUN_004be078 -> EXPLODE.cpp:209-210). VERIFIED live: clean build; 2-node fight -> clean center-mass kill (no crash, kills 0->1); [zone-armor] dump confirms per-zone armor 50-140 + legs x0.5. NB the displayed POINTS score still reads 0 -- a SEPARATE open gap (scoreAward + role/team/tonnage multipliers unwired); fix C corrected the damage INPUT to that formula. KB swept: open-questions.md (self-contradiction resolved + task #60 summary + deferred missile item), combat-damage.md (damageScale is type-indexed not even/odd; task-#52 source fix; kill-score section), RECONCILE.md (missile = ONE spawn not N), stale comments in mechweap.cpp (SendDamageMessage is LIVE), mislanch.hpp, mechdmg.cpp (FUN_0049fb54 = IsDisabled). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
2e9c78d604
commit
267059ab88
@@ -122,9 +122,12 @@ offsets). [T2]
|
||||
|
||||
## The RAM economy — CLOSED (2026-07-12) [T1 evidence, T3 normalization]
|
||||
Three-layer story, measured live + decomp-verified:
|
||||
1. **The armor economy is POINTS**: every zone streams `damageScale[5]` EVEN = `1/armorPoints`
|
||||
(armor 50–140; `damageLevel += amount/armor`, 1.0 = destroyed — the `[zone-armor]` dump,
|
||||
BT_DMG_LOG, mechdmg.cpp). Weapons author point-scale amounts (laser 11.77 ≈ 10 torso hits). ✓
|
||||
1. **The armor economy is POINTS**: every zone streams `damageScale[5]` — 5 cells indexed by
|
||||
`damageType` DIRECTLY (Collision/Ballistic/Explosive/Laser/Energy; task #60 correction — NOT an
|
||||
"even/odd slot" parity), each destructive type's cell ≈ `1/armorPoints` (armor 50–140).
|
||||
`damageLevel += amount × damageScale[type]`, 1.0 = destroyed — engine `DAMAGE.cpp:379`, called
|
||||
from `mechdmg.cpp:427`; the `[zone-armor]` dump, BT_DMG_LOG. Weapons author point-scale amounts
|
||||
(laser 11.77 ≈ 10 torso hits). ✓
|
||||
2. **StaticBounce prices rams with the AUTHORED moverMass ≈ 1.3e6 units** → ~600×v² ≈ 59,000
|
||||
points for a 10 m/s ram (measured: 59221@9.94, 398@0.81; `[collide-tx]` now logs mass/e).
|
||||
The binary DISPATCHES it raw (@part_012:15324-15358) — but in pod MP it landed on the local
|
||||
@@ -418,6 +421,23 @@ is the death `movementMode`: `IsDestroyed == (movementMode 2 || 9)` (`FUN_0049fb
|
||||
the death modes never revert. Fix: `IsMechDestroyed()` = `movementMode 2||9` (latch) **OR**
|
||||
`graphicAlarm >= 9` (the vital-kill TRIGGER that first enters the transition). Lesson: **a gauge/status
|
||||
alarm is never a state latch** — later writers rewrite it; latch on the state machine's own mode.
|
||||
**ROOT-CAUSE now fixed AT SOURCE (task #60):** the illegitimate wreck rewrite to 4/3 came from
|
||||
`mechdmg.cpp:458` gating the leg partial-failure graphic on the always-0 `IsAirborne()` stub instead
|
||||
of `IsDisabled()` (`@0049fb54` = movementMode 2||9). On a wreck the binary SUPPRESSES that write; the
|
||||
stub let it fire and corrupt `graphicAlarm`. Now `mech->IsDisabled()` — the latch above remains as
|
||||
defence-in-depth. Sibling fix: `mechdmg.cpp:451` read the phantom `stance` (perma-0) instead of
|
||||
`MovementMode()`, so the leg-shot-out → `graphicAlarm=9` fall/death branch was entirely DEAD; now live.
|
||||
|
||||
## Kill-score damage (task #60)
|
||||
`BTPostKillScore` (btplayer.cpp:1491) feeds the ScoreMessage `damageAmount` into the kill award
|
||||
(`@0x4c02e4` → `(damageAmount + scoreAward) × roleScalar × teamMult × tonnageRatio`, `@0x4c052c`).
|
||||
The port passed a flat `kShotDamage=12` (mech4.cpp:1551), so every kill scored identically regardless
|
||||
of the finishing weapon. Now it passes `lastInflictingDamage` — the real killing-blow magnitude
|
||||
latched in `TakeDamageMessageHandler` (mech.cpp:624), mirroring the working per-hit score path
|
||||
(mech4.cpp:1207). `scoreAward=0` (the authentic kill BONUS) stays an open bring-up gap — it lives in
|
||||
the un-exported master-perf writer (0x4a9770-0x4ab188 [T4]); the exact authentic `damageAmount` that
|
||||
writer emitted (msg+0x24) is likewise unrecovered, so the killing-blow magnitude is the faithful
|
||||
stand-in until it is. [T1 mechanism / T4 exact authentic value]
|
||||
|
||||
## Key Relationships
|
||||
- Weapons/roster: [[subsystems]]. Aim source: [[locomotion]] (drive/facing). Effects: [[rendering]].
|
||||
|
||||
@@ -257,7 +257,11 @@ register. ⚠ The audit also flags the damage-economy item as SELF-CONTRADICTOR
|
||||
in the task #8 synthesis) → the pod's 4-8-hit heavy-weapon pacing. The weapon-side
|
||||
SendDamageMessage (@004b9728) is LIVE from Emitter::FireWeapon (damageData filled incl.
|
||||
**damageForce = target−muzzle → the gyro's directional hit-bounce feed**); the mech4
|
||||
bring-up damage block + flat kShotDamage are retired to diag hooks. **ROOT-CAUSE find: the
|
||||
bring-up damage block + flat kShotDamage are retired to diag hooks **(CORRECTED, task #60:
|
||||
`kShotDamage=12` was only HALF-retired — still LIVE at the kill-score `mech4.cpp:1551` until
|
||||
task #60 replaced it with `lastInflictingDamage`, the real killing-blow magnitude; only the
|
||||
cross-pod force hook `mech4.cpp:3255` was env-gated. See the task #60 reconciliation below).**
|
||||
**ROOT-CAUSE find: the
|
||||
CheckFireEdge NaN latch** -- TriggerState carries ControlsButton INTS (release −65 = a
|
||||
negative NaN); the binary's x87 unordered-compare treated it as "released" but an
|
||||
IEEE-correct float compare latched the detector shut after the first release (why the
|
||||
@@ -267,6 +271,38 @@ register. ⚠ The audit also flags the damage-economy item as SELF-CONTRADICTOR
|
||||
LODReuseHysteresis corrected 0.82→0.33 (a double); the MP beam-kill live-verify awaits a
|
||||
clear-sightline spawn (mechanism identical to solo; force-dmg cross-pod cycles verified).
|
||||
|
||||
- **✅ DAMAGE-ECONOMY RECONCILIATION (task #60, 2026-07-13) [T1/T2].** Full 5-path audit vs the
|
||||
decomp (5-finder + adversarial-verify workflow). **Clean as-is:** energy beam (`emitter.cpp`,
|
||||
closed form byte-exact; `_DAT_004bafbc` dumped = x87 1e-7), autocannon (`projweap.cpp`, full
|
||||
authored DamageAmount from resource +0x19C; the 0.0625 at :667 is the shooter's own gyro recoil,
|
||||
not the round), zone-armor BASE model (`damageLevel += amount·damageScale[type]`, engine
|
||||
DAMAGE.cpp:379, legs ×0.5, 1.0=destroyed). **3 stand-ins FIXED:** (A) `mechdmg.cpp:451`
|
||||
`mech->stance` (phantom, perma-0 → the leg-shot-out fall/death branch was DEAD) → `MovementMode()`
|
||||
(mech+0x40, @part_012.c:6910); (B) `mechdmg.cpp:458` `IsAirborne()` (always-0 stub) → `IsDisabled()`
|
||||
(@0049fb54) — the task-#52 wreck-graphic corruption fixed AT SOURCE (was only masked by the
|
||||
IsMechDestroyed latch); (C) `mech4.cpp:1551` flat `kShotDamage=12` kill-score → `lastInflictingDamage`
|
||||
(real killing-blow, latched in TakeDamageMessageHandler; the score handler @0x4c02e4 derives the
|
||||
whole kill award from it, so a flat 12 scored every kill identically). Phantom `int stance` slot
|
||||
reused for `lastInflictingDamage`. **KB corrected:** the "damageScale[5] EVEN=1/armorPoints"
|
||||
prose is a mild inaccuracy — the array is 5 cells indexed by damageType directly
|
||||
(Collision/Ballistic/Explosive/Laser/Energy); the per-type value IS ≈1/armorPoints for the
|
||||
destructive types (net model unchanged). See [[combat-damage]].
|
||||
- **DEFERRED (task #60-D): the missile CLUSTER model.** The port fires N flying rounds each
|
||||
carrying `authored/N` damage (net salvo total = authored, so per-armor damage is correct), but
|
||||
the binary (@004bcc60) fires ONE missile whose `burstCount` is a RANDOM cluster-hit roll
|
||||
(`min(rand(0..N-1)+N/4, N)`, FUN_004bef78) applied to ONE cylinder-resolved zone. The port thus
|
||||
loses (i) cluster-hit VARIANCE (always full N) and (ii) single-zone CONCENTRATION (N rounds
|
||||
scatter across zones). Net-neutral on total armor, so LOW priority. **OPEN semantic gating the
|
||||
severity:** does `burstCount` multiply ARMOR damage or only the gyro kick? DAMAGE.h:49-54 [T0]
|
||||
says "times to apply the damage" (→ apply-count → port total authentic); settle by reading the
|
||||
consumer chain FUN_004bef78 → FUN_004be078 → EXPLODE.cpp:209-210 (does it loop burstCount over
|
||||
DamageZone::TakeDamage or apply once?). Fix only if made byte-faithful (roll clusterHits, thread
|
||||
`burst` through BTPushProjectile, one damage-bearing round + rest visual-only).
|
||||
- Also open (bring-up, not stand-ins): `scoreAward=0` (btplayer.cpp:1526 — the authentic kill
|
||||
bonus lives in the un-exported master-perf writer 0x4a9770-0x4ab188, T4); the exact authentic
|
||||
kill `damageAmount` from that same writer (msg+0x24) is unrecovered — the killing-blow magnitude
|
||||
is the faithful stand-in until it is.
|
||||
|
||||
- **HEAT (task #9, 2026-07-11): authentic 1e7-unit heat LIVE; conduction ROUTING defect
|
||||
remains [T2/T3].** Landed + byte-anchored: emitters emit `heatCostToFire x 1e7 x
|
||||
(charge/seekV)^2` (closed form; PPC = 1.1e8 -> +632 K on its 174000-mass sink); the missing
|
||||
|
||||
Reference in New Issue
Block a user