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
@@ -51,7 +51,7 @@
|
||||
// FUN_00408050 (Scalar)Random -> [0,1) FUN_0040807c(rng,n) Random(n)
|
||||
// FUN_004ac07c Subsystem::ApplyDamage(damage) -> Scalar
|
||||
// FUN_004b11bc Generator::ForceShortRecovery (class derivations @0050f4bc)
|
||||
// FUN_0049fb54 Mech::<query torso/leg destroyed state>
|
||||
// FUN_0049fb54 Mech::IsDisabled() (movementMode 2||9; NOT a torso/leg query)
|
||||
// FUN_0040485c/00404720/00404088/00404190/004040d8 NotationFile readers
|
||||
// FUN_00402298/004022b0/004022d0 operator new / array new / delete
|
||||
// FUN_004dbb24/004db92c/004d9c38/004dbd4c DebugStream << / endl
|
||||
@@ -448,18 +448,26 @@ void
|
||||
if (damageLevel >= StructureMax)
|
||||
RecurseSegmentTable(mech); // FUN_0049cad4
|
||||
}
|
||||
else if ((unsigned)(mech->stance - 3) < 2) // standing/walking
|
||||
else if ((unsigned)(mech->MovementMode() - 3) < 2) // live sim state 3||4 (mech+0x40)
|
||||
{
|
||||
// task #60: the gate reads the LIVE MovementMode (mech+0x40),
|
||||
// @part_012.c:6910 `*(int*)(iVar1+0x40) - 3U < 2` -- NOT the phantom
|
||||
// `stance` member (no binary offset, zero writers -> perma-0, so
|
||||
// this whole leg-shot-out -> fall/death branch was DEAD).
|
||||
if (rightLeg != 0 && damageLevel >= StructureMax)
|
||||
mech->graphicAlarm.SetLevel(9); // fall / leg gone
|
||||
else if (leftLeg != 0 && damageLevel >= StructureMax)
|
||||
mech->graphicAlarm.SetLevel(9);
|
||||
}
|
||||
else if (mech->IsAirborne() == 0) // FUN_0049fb54
|
||||
else if (mech->IsDisabled() == 0) // FUN_0049fb54 (NOT disabled)
|
||||
{
|
||||
// Non-standing stance, still grounded: a half-destroyed leg zone
|
||||
// trips the partial-failure graphic (right -> 4, left -> 3). The
|
||||
// oracle compares against _DAT_0049c9a0 (0.5), NOT StructureMax.
|
||||
// A live (non-disabled) mech: a half-destroyed leg zone trips the
|
||||
// partial-failure graphic (right -> 4, left -> 3). The oracle
|
||||
// compares against _DAT_0049c9a0 (0.5), NOT StructureMax. task #60:
|
||||
// the guard is IsDisabled (@0049fb54 = movementMode 2||9), NOT the
|
||||
// always-0 IsAirborne stub -- on a WRECK the binary SUPPRESSES this
|
||||
// write; the stub let it corrupt graphicAlarm 9->4/3 (the task-#52
|
||||
// wreck-graphic bug, now fixed at source not just masked).
|
||||
if (rightLeg != 0 && damageLevel >= LegHalfStructure)
|
||||
mech->graphicAlarm.SetLevel(4);
|
||||
else if (leftLeg != 0 && damageLevel >= LegHalfStructure)
|
||||
|
||||
Reference in New Issue
Block a user