Combat: THE AUTHENTIC DAMAGE ECONOMY -- authored per-weapon amounts through the real fire chain (task #8)
Three root causes, all fixed: 1. kDamageScale was 1.0 -- _DAT_004bafbc is an x87 float80 = 1e-7, cancelling the ctor's x1e7: damagePortion = authored DamageAmount x (charge/seekV)^2 (closed form at fire time; madcat AC=25/LRM=50/ERLL=6, bhk1 PPC=12/SRM=35). The observed "0.25" was the degenerate EC=1 fallback, never authored data. 2. CheckFireEdge NaN latch: TriggerState carries ControlsButton INTS; the release value (-65) is a negative NaN. The binary's x87 unordered compare read it as "released"; IEEE-correct float compares latched the edge detector shut after the first release -- the reason the emitter discharge chain NEVER fired in-game. Fixed with bit-pattern sign compares. 3. The weapon-side submission LIVE: Emitter::FireWeapon fills damageData (amount + damageForce=target-muzzle [the gyro directional-bounce feed] + impact) -> MechWeapon::SendDamageMessage (@004b9728 real body) -> messmgr consolidation with per-weapon records + explosion bundling. The mech4 bring-up damage block + flat kShotDamage retired to diag hooks. Bonus: LODReuseHysteresis 0.82 -> 0.33 (double misread). Zone model verified byte-exact (no change). Solo end-to-end: 5-record volleys (2 PPC + 3 ERML with authored amounts), per-weapon zone granularity, explosions, kill. Heat stays bring-up scale pending the heat-calibration audit [T3]. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
77190c93e5
commit
fd055281a8
@@ -672,6 +672,13 @@ extern void BTPostKillScore(Entity *victim, Scalar damage); // KILL (+ MP death
|
||||
#define MECH_TARGET_ENTITY(m) (*(Entity **)((char *)(m) + 0x388))
|
||||
#define MECH_TARGET_SUBIDX(m) (*(int *)((char *)(m) + 0x38c))
|
||||
|
||||
// task #8 bridge: the weapon-side damage submission (mechweap.cpp) reads the
|
||||
// owner's designated-zone slot; the raw target-slot block lives in this TU.
|
||||
int BTMechTargetZone(void *mech)
|
||||
{
|
||||
return MECH_TARGET_SUBIDX(mech);
|
||||
}
|
||||
|
||||
// Bring-up body-animation player (file scope so OnBodyAnimFinished can re-arm it).
|
||||
// The engine AnimationInstance walks the mech's joint subsystem from a baked .ani
|
||||
// clip in btl4.res; we advance it each moving frame so the legs CYCLE.
|
||||
@@ -3042,7 +3049,19 @@ void
|
||||
s_prevBtn[b] = want[b];
|
||||
ControlsButton v = (ControlsButton)(want[b]
|
||||
? (buttons[b] + 1) : -(buttons[b] + 1));
|
||||
cm->buttonGroup[buttons[b]].Update(&v, modeMask);
|
||||
cm->buttonGroup[buttons[b]].ForceUpdate(&v, modeMask); // diag: bypass the prev-diff gate
|
||||
if (getenv("BT_FIRE_LOG"))
|
||||
{
|
||||
static int s_pushN = 0;
|
||||
if ((++s_pushN % 60) == 1)
|
||||
DEBUG_STREAM << "[push] btn=0x" << std::hex
|
||||
<< buttons[b] << std::dec << " v=" << (int)v
|
||||
<< " mode=0x" << std::hex << (int)modeMask
|
||||
<< std::dec << " #" << s_pushN
|
||||
<< " thisMech=" << (void *)this
|
||||
<< " viewpoint=" << (void *)application->GetViewpointEntity()
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3170,52 +3189,22 @@ void
|
||||
// routes it to Mech__DamageZone::TakeDamage. Dispatch on a
|
||||
// REPLICANT is rerouted by Entity::Dispatch to the owning
|
||||
// master over the wire -- the cross-pod damage path.
|
||||
if (((Mech *)victim)->damageZoneCount > 0)
|
||||
// DAMAGE DELIVERY MOVED (task #8): the AUTHENTIC submitter is
|
||||
// each firing weapon's own SendDamageMessage (@004b9728, called
|
||||
// from Emitter::FireWeapon with the authored per-shot
|
||||
// damagePortion + damageForce + impact) into the
|
||||
// SubsystemMessageManager. This block keeps only the
|
||||
// presentation roles: the boresight pick feeds the target
|
||||
// slots the weapons read (mech+0x388/0x37C/0x38C), the [fire]
|
||||
// beam-entry explosion visual above, and the shot log. The
|
||||
// flat kShotDamage build + shooter-side score moved with the
|
||||
// submission (mechweap.cpp).
|
||||
if (getenv("BT_FIRE_LOG") && ((Mech *)victim)->damageZoneCount > 0)
|
||||
{
|
||||
Damage dmg;
|
||||
dmg.damageType = Damage::ExplosiveDamageType;
|
||||
dmg.damageAmount = kShotDamage;
|
||||
dmg.burstCount = 1;
|
||||
dmg.impactPoint = impact;
|
||||
|
||||
Entity::TakeDamageMessage take_damage(
|
||||
Entity::TakeDamageMessageID,
|
||||
sizeof(Entity::TakeDamageMessage),
|
||||
GetEntityID(), // inflicting = this (shooter)
|
||||
-1, // UNAIMED -> receiver's cylinder resolves
|
||||
dmg);
|
||||
// AUTHENTIC DELIVERY (task #7 tail): submit through the
|
||||
// SubsystemMessageManager -- per-frame consolidation into
|
||||
// ONE TakeDamageStream (id 0x13) dispatched at the victim,
|
||||
// whose T0 handler re-splits it (ENTITY.cpp:817).
|
||||
// Replicant victims reroute cross-pod as before. [T3:
|
||||
// the inflicting subsystemID is not threaded through this
|
||||
// bring-up fire block -- the authentic submitter is the
|
||||
// weapon's own SendDamageMessage @004b9728, pending the
|
||||
// damage-economy reconciliation (authored 0.25-scale
|
||||
// amounts vs the bring-up kShotDamage=12); until then the
|
||||
// messmgr's weapon-explosion bundling stays dormant.]
|
||||
if (messageManager != 0)
|
||||
((SubsystemMessageManager *)messageManager)
|
||||
->AddDamageMessage(victim, &take_damage);
|
||||
else
|
||||
victim->Dispatch(&take_damage);
|
||||
|
||||
// SCORE the damage (skip once the victim is dead).
|
||||
if (!((Mech *)victim)->IsMechDestroyed())
|
||||
BTPostDamageScore(victim, kShotDamage);
|
||||
|
||||
int zone = take_damage.damageZone;
|
||||
if (zone >= 0 && zone < ((Mech *)victim)->damageZoneCount)
|
||||
{
|
||||
Scalar s = ((Mech *)victim)->Zone(zone)->damageLevel;
|
||||
DEBUG_STREAM << "[damage] " << (void*)victim << " zone " << zone
|
||||
<< "/" << ((Mech *)victim)->damageZoneCount
|
||||
<< " structure=" << s
|
||||
<< (((Mech *)victim)->GetInstance() == ReplicantInstance
|
||||
? " (REPLICANT -> cross-pod)" : "")
|
||||
<< "\n" << std::flush;
|
||||
}
|
||||
DEBUG_STREAM << "[damage] beam hit " << (void*)victim
|
||||
<< (((Mech *)victim)->GetInstance() == ReplicantInstance
|
||||
? " (REPLICANT -> cross-pod via the weapon submit)" : "")
|
||||
<< "\n" << std::flush;
|
||||
}
|
||||
// DEATH effects fire at the VICTIM's own death transition
|
||||
// (UpdateDeathState, task #42) -- MP-correct: the master runs it.
|
||||
|
||||
Reference in New Issue
Block a user