Cross-pod beams: replicate emitter discharge via subsystem update records
User report: lasers only visible on the window firing them. The peer's replicant emitters never learned the master fired. THE AUTHENTIC PIPE (decomp-verified): - FUN_0041c350 (the "beam keepalive" ServiceDischarge/ContinueDischarge call) does TWO things: queue the LOCAL deferred beam-effect callback (@0x4bac0c) on the app+0x34 manager -- our per-weapon render walk already plays that role -- and set the subsystem DIRTY bit, which maps to the 2007 engine's updateModel / ForceUpdate(). - Replication rides SUBSYSTEM UPDATE RECORDS inside the mech's update message: the roster walk already hands the entity's stream to every subsystem's PerformAndWatch; Simulation::WriteSimulationUpdate serializes each requested updateModel bit; Entity::UpdateMessageHandler routes received records by subsystemID to the subsystem's ReadUpdateRecord. All engine machinery -- the missing pieces were the Emitter's serialize/apply pair + the triggers. CORRECTIONS to the dormant task-33-era transcriptions (never exercised -- nothing ever set updateModel -- so the latent misreads never surfaced): - The weapon-family VTABLE SLOT MAP was swapped: slot 6 = ReadUpdateRecord, 7 = WriteUpdateRecord, 9 = TakeDamage (evidence: Mech hierarchy symmetry + body semantics; @004ba568 resolves an EntityID at rec+0x30 through the entity index -- record semantics, not Damage). Renamed across MechWeapon / Emitter / ProjectileWeapon; the real Emitter::TakeDamage @004bafc8 is undecoded (inherits MechWeapon for now). - Emitter/MechWeapon Write: `*record = 0x38/0x18` is the record LENGTH, not recordID; rec+0x30 is the TARGET's EntityID (GetEntityID()), not a colour -- the old `CopyColor(targetEntity+0x184)` was also a databinding trap. - OVERRIDE-SIGNATURE TRAP: the decls used each class's own shadowing UpdateRecord typedef as the param type, silently NOT overriding the engine virtual (the base ran instead; nothing would ever have serialized). Base-typed params (Simulation__UpdateRecord*), casts inside. - Emitter::ReadUpdateRecord reconstructed (@004ba568): target EntityID resolve (drop unknown non-null targets), MechWeapon alarm apply chain, beam fields. - ServiceDischarge/ContinueDischarge: ForceUpdate() per keepalive tick + one final record at beam end (turns the peer's beam off). - Mech::DrawWeaponBeams extracted from the player-only drive block so the walk runs for REPLICANTS (+ per-mech gun-port cache -- the process-wide statics would have served the player's segment pointers as the replicant's muzzles). VERIFIED 2-node: A fires 57 volleys -> 225 emitter records -> B applies all 225 -> B draws 414 beams (PPC blue / laser red, from A's replicant's own gun ports). Solo un-regressed (150 beams, kill chain, no crash). Also preserved: the full Mech::WriteUpdateRecord @0x4a0c2c recovery (reference/decomp/mech_writeupdate_004a0c2c.disasm.txt) with all 9 record types decoded (pose/alarm/leg-state+heat with the body-channel write-through re-sync, knockdown, death, impact, movementMode) -- transcription deferred; it replicates remote knockdown/death/heat and was not needed for beams. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
a110041a70
commit
29035028fd
+22
-4
@@ -181,10 +181,28 @@ transition, HUD all landed since P6): console egg → mesh → RunningMission on
|
|||||||
3. **Victim visuals on the shooter's screen**: the wreck swap gates on zone/graphic state the
|
3. **Victim visuals on the shooter's screen**: the wreck swap gates on zone/graphic state the
|
||||||
REPLICANT copy may never see (zone damage may not replicate — only pose updates confirmed).
|
REPLICANT copy may never see (zone damage may not replicate — only pose updates confirmed).
|
||||||
Check DamageZone/subsystem state in the update stream; else replicate the death as an event.
|
Check DamageZone/subsystem state in the update stream; else replicate the death as an event.
|
||||||
4. **Cross-pod beam visuals**: replicant emitters don't run the local trigger sim, so the peer's
|
4. ✅ **Cross-pod beam visuals — DONE (task #51, 2026-07-09).** The keepalive theory needed one
|
||||||
beams never draw today. ⭐ The authentic path exists: ServiceDischarge/ContinueDischarge SEND
|
correction: `FUN_0041c350` = (a) queue the LOCAL deferred beam-effect callback (@0x4bac0c) on the
|
||||||
**beam-keepalive messages** (`FUN_0041c350`, templates @0x511e6c/@0x511e78, emitter.cpp already
|
app+0x34 manager (our per-weapon render walk plays that role) AND (b) set the subsystem DIRTY bit —
|
||||||
stubs them) — decode + route those to drive replicant beam draws.
|
which maps to the 2007 engine's `updateModel`/`ForceUpdate()`. The REPLICATION rides **subsystem
|
||||||
|
update records inside the mech's update message**: the roster walk passes the entity's stream to
|
||||||
|
every subsystem's `PerformAndWatch`; `Emitter::WriteUpdateRecord` (@004ba65c, corrected: record
|
||||||
|
LENGTH not recordID; rec+0x30 = the TARGET's **EntityID** not a colour) serializes
|
||||||
|
firingActive/beamEndpoint/beamFlag/targetID; the engine's `Entity::UpdateMessageHandler` routes
|
||||||
|
records by `subsystemID` to `Emitter::ReadUpdateRecord` (@004ba568 — was MIStranscribed as
|
||||||
|
TakeDamage; the whole weapon-family slot map was swapped: slot 6=Read, 7=Write, 9=TakeDamage — see
|
||||||
|
mechweap.hpp). `ServiceDischarge`/`ContinueDischarge` call `ForceUpdate()` per keepalive tick +
|
||||||
|
once at beam end. The render walk was extracted to `Mech::DrawWeaponBeams` (per-mech port cache)
|
||||||
|
and runs for REPLICANTS. ⚠ two silent-failure traps fixed: the overrides originally used the
|
||||||
|
class's own shadowing `UpdateRecord` typedef as the param type → never overrode the engine virtual
|
||||||
|
(base ran, nothing serialized); and `recordLength` must be each level's sizeof or the stream
|
||||||
|
framing misparses. VERIFIED 2-node: A fires 57 volleys → 225 records → B applies 225 → draws 414
|
||||||
|
replicant beams (PPC blue / laser red from A's replicant's gun ports). Solo un-regressed.
|
||||||
|
REMAINING (deferred): the MECH-level writer @0x4a0c2c (recovered + preserved:
|
||||||
|
`reference/decomp/mech_writeupdate_004a0c2c.disasm.txt`; 9 record types decoded — 0/1/4 pose
|
||||||
|
variants, 2 alarm, 3 leg-state+heat with body-channel write-through re-sync, 5 knockdown
|
||||||
|
(SetBodyAnimation(0x20) write-through), 6 death, 7 impact, 8 movementMode) — transcribing it
|
||||||
|
would replicate remote KNOCKDOWN/death/heat states; beams did not need it.
|
||||||
5. **2-window driving**: input gates on window focus (alternate windows; `BT_KEY_NOFOCUS` for
|
5. **2-window driving**: input gates on window focus (alternate windows; `BT_KEY_NOFOCUS` for
|
||||||
harness). DEATHS scoring should light via the existing BTPostKillScore MP branch. Respawn =
|
harness). DEATHS scoring should light via the existing BTPostKillScore MP branch. Respawn =
|
||||||
the P5 teardown debt (deferred until needed).
|
the P5 teardown debt (deferred until needed).
|
||||||
|
|||||||
@@ -72,6 +72,7 @@
|
|||||||
#if !defined(TESTBT_HPP)
|
#if !defined(TESTBT_HPP)
|
||||||
# include <testbt.hpp>
|
# include <testbt.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
#include <hostmgr.hpp> // HostManager::GetEntityPointer -- the update-record target resolve (task #51)
|
||||||
|
|
||||||
// E8 (bring-up): the player fire input. The controls mapper that would normally write
|
// E8 (bring-up): the player fire input. The controls mapper that would normally write
|
||||||
// the weapon's fireImpulse is bypassed (mech4.cpp), so EmitterSimulation reads this
|
// the weapon's fireImpulse is bypassed (mech4.cpp), so EmitterSimulation reads this
|
||||||
@@ -413,11 +414,21 @@ void
|
|||||||
beamFlag = 0; // 0x46c
|
beamFlag = 0; // 0x46c
|
||||||
dischargeTimer = dischargeTime; // 0x440 = 0x43c
|
dischargeTimer = dischargeTime; // 0x440 = 0x43c
|
||||||
SetDirty();
|
SetDirty();
|
||||||
|
// replicate the beam END: one final Emitter update record turns the
|
||||||
|
// peer's copy off (the 1995 flush wrote idle-flagged subsystems too).
|
||||||
|
ForceUpdate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// keep the beam alive for another frame (re-send the beam message).
|
// keep the beam alive for another frame -- BEAM REPLICATION (task #51):
|
||||||
// CROSS-FAMILY (messaging): SendMessage(PTR_LAB_00511e6c,..) -- FUN_0041c350.
|
// the 1995 keepalive (FUN_0041c350, template @0x511e6c) marked the
|
||||||
|
// subsystem dirty + queued the local deferred beam-effect callback; the
|
||||||
|
// local draw is our per-weapon render walk, and the dirty-mark maps to the
|
||||||
|
// engine's updateModel bit -- the next PerformAndWatch serializes THIS
|
||||||
|
// emitter's record (@004ba65c) into the mech's update stream, and the
|
||||||
|
// peer's replicant emitter applies it (@004ba568) so its own walk draws
|
||||||
|
// the beam.
|
||||||
|
ForceUpdate();
|
||||||
(void)PTR_LAB_00511e6c; (void)DAT_00511e70; (void)DAT_00511e74;
|
(void)PTR_LAB_00511e6c; (void)DAT_00511e70; (void)DAT_00511e74;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,7 +460,9 @@ void
|
|||||||
ResetFiringState(); // @004ba9a8
|
ResetFiringState(); // @004ba9a8
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// re-send the beam-keepalive message (CROSS-FAMILY messaging, FUN_0041c350)
|
// re-send the beam keepalive -- the engine's updateModel bit (task #51,
|
||||||
|
// same mapping as ServiceDischarge above; 1995 template @0x511e78).
|
||||||
|
ForceUpdate();
|
||||||
(void)PTR_LAB_00511e78; (void)DAT_00511e7c; (void)DAT_00511e80;
|
(void)PTR_LAB_00511e78; (void)DAT_00511e7c; (void)DAT_00511e80;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -552,45 +565,52 @@ void
|
|||||||
//
|
//
|
||||||
|
|
||||||
//
|
//
|
||||||
// @004ba568 -- slot 6. Resolve the incoming damage's source subsystem (the
|
// @004ba568 -- slot 6 (TASK #51 RENAME: was mistranscribed as TakeDamage; the
|
||||||
// VoltageSource link), then apply the base MechWeapon damage and replicate the
|
// body is unambiguous RECORD semantics -- it compares rec+0x30 against
|
||||||
// extra Emitter fields (firingActive, beam endpoint, target). A "no-source"
|
// EntityID::Null (DAT_00522524), resolves it through the entity index, and
|
||||||
// damage clears the link and sets the alarm to 2 (Loaded) / 0 (active).
|
// applies alarm/beam fields). Apply an Emitter update record on the
|
||||||
|
// REPLICANT: resolve the beam TARGET id (drop the record when a non-null id is
|
||||||
|
// unknown on this host), chain the MechWeapon read (@004b964c, alarm apply),
|
||||||
|
// then the beam-replication fields. The tail `this+0x10 = this+0x14` is the
|
||||||
|
// 1995 Simulation lastUpdate=lastPerformance resync (the earlier transcription
|
||||||
|
// misread it as rechargeLevel=effectiveRange) -- the engine base read already
|
||||||
|
// maintains lastUpdate.
|
||||||
//
|
//
|
||||||
void
|
void
|
||||||
Emitter::TakeDamage(Damage &damage)
|
Emitter::ReadUpdateRecord(Simulation__UpdateRecord *message)
|
||||||
{
|
{
|
||||||
int src = FUN_00421070(&damage, DAT_00522524); // damage source (damage+0x30)
|
Emitter__UpdateRecord *rec = (Emitter__UpdateRecord *)message;
|
||||||
if (src == 0)
|
|
||||||
|
if (rec->targetID == EntityID::Null) // FUN_00421070 vs DAT_00522524
|
||||||
{
|
{
|
||||||
targetEntity = 0; // 0x474
|
targetEntity = 0; // 0x474
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// look up the named source through the global subsystem registry
|
targetEntity = (application != 0)
|
||||||
targetEntity = (Entity *)ResolveSource(&damage); // this+0x474
|
? application->GetHostManager()->GetEntityPointer(rec->targetID)
|
||||||
|
: 0;
|
||||||
if (targetEntity == 0)
|
if (targetEntity == 0)
|
||||||
{
|
{
|
||||||
return;
|
return; // unknown target -> drop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MechWeapon::TakeDamage(damage); // FUN_004b964c
|
MechWeapon::ReadUpdateRecord(message); // FUN_004b964c (alarm apply)
|
||||||
|
|
||||||
// CROSS-FAMILY (replication): the shipped Emitter also pulled its beam state
|
firingActive = rec->firingActive; // 0x418 <- rec+0x18
|
||||||
// (firingActive, beamFlag, beamEndpoint, beamColor, targetLocalFlag) out of the
|
weaponAlarm.SetLevel(firingActive != 0 ? 0 : 2); // 0=Firing / 2=Loaded
|
||||||
// networked damage record. Those fields are not present on the engine Damage;
|
beamFlag = rec->beamFlag; // 0x46c <- rec+0x28
|
||||||
// they arrive through the update-record path (WriteUpdateRecord) instead.
|
beamEndpoint = rec->beamEndpoint; // 0x460 <- rec+0x1c
|
||||||
if (firingActive == 0)
|
targetLocalFlag = rec->targetLocalFlag; // 0x470 <- rec+0x2c
|
||||||
|
ClearDirty(); // this+0x28 &= ~2 (idle bit clear)
|
||||||
|
if (getenv("BT_BEAM_LOG"))
|
||||||
{
|
{
|
||||||
weaponAlarm.SetLevel(2); // Loaded
|
static int s_rd = 0;
|
||||||
|
if ((s_rd++ % 60) == 0)
|
||||||
|
DEBUG_STREAM << "[emit-rd] " << (void*)this << " firing=" << firingActive
|
||||||
|
<< " beamFlag=" << beamFlag << "\n" << std::flush;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
weaponAlarm.SetLevel(0); // Firing
|
|
||||||
}
|
|
||||||
ClearDirty(); // this+0x28 &= ~2
|
|
||||||
rechargeLevel = effectiveRange; // this+0x10 = this+0x14 (best-effort)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -599,23 +619,31 @@ void
|
|||||||
// endpoint, beamFlag and the target's colour tag.
|
// endpoint, beamFlag and the target's colour tag.
|
||||||
//
|
//
|
||||||
void
|
void
|
||||||
Emitter::WriteUpdateRecord(UpdateRecord *message, int update_model)
|
Emitter::WriteUpdateRecord(Simulation__UpdateRecord *message, int update_model)
|
||||||
{
|
{
|
||||||
MechWeapon::WriteUpdateRecord(message, update_model); // FUN_004b9690
|
MechWeapon::WriteUpdateRecord(message, update_model); // FUN_004b9690
|
||||||
|
|
||||||
message->recordID = 0x38; // *message
|
Emitter__UpdateRecord *rec = (Emitter__UpdateRecord *)message;
|
||||||
message->firingActive = firingActive; // message[6] <- 0x418
|
// DISASM CORRECTIONS (task #51): `*param_2 = 0x38` writes the record
|
||||||
message->targetLocalFlag= targetLocalFlag; // message[10] <- 0x470
|
// LENGTH, not recordID; and rec+0x30 receives the TARGET's EntityID
|
||||||
message->beamEndpoint = beamEndpoint; // message[7] <- 0x460
|
// (FUN_00420ef4 copies from targetEntity+0x184 = the 1995 entityID --
|
||||||
message->beamFlag = beamFlag; // message[11] <- 0x46c
|
// the old `CopyColor(...targetEntity+0x184)` was both a misread AND a
|
||||||
|
// databinding trap in our compiled Entity layout).
|
||||||
if (targetEntity == 0) // 0x474
|
rec->recordLength = sizeof(Emitter__UpdateRecord); // *message = 0x38
|
||||||
|
rec->firingActive = firingActive; // rec+0x18 <- 0x418
|
||||||
|
rec->beamEndpoint = beamEndpoint; // rec+0x1c <- 0x460
|
||||||
|
rec->beamFlag = beamFlag; // rec+0x28 <- 0x46c
|
||||||
|
rec->targetLocalFlag = targetLocalFlag; // rec+0x2c <- 0x470
|
||||||
|
rec->targetID = (targetEntity != 0)
|
||||||
|
? ((Entity *)targetEntity)->GetEntityID()
|
||||||
|
: EntityID::Null; // rec+0x30
|
||||||
|
if (getenv("BT_BEAM_LOG"))
|
||||||
{
|
{
|
||||||
CopyColor(&message->color, DAT_00522524); // FUN_00420ef4
|
static int s_wr = 0;
|
||||||
}
|
if ((s_wr++ % 60) == 0)
|
||||||
else
|
DEBUG_STREAM << "[emit-wr] " << (void*)this << " firing=" << firingActive
|
||||||
{
|
<< " beamFlag=" << beamFlag << " subsysID=" << (int)rec->subsystemID
|
||||||
CopyColor(&message->color, (void*)((char*)targetEntity + 0x184));
|
<< " len=" << (int)rec->recordLength << "\n" << std::flush;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,12 +97,18 @@ class NotationFile;
|
|||||||
struct Emitter__UpdateRecord:
|
struct Emitter__UpdateRecord:
|
||||||
public MechWeapon::UpdateRecord
|
public MechWeapon::UpdateRecord
|
||||||
{
|
{
|
||||||
int firingActive; // message[6]
|
int firingActive; // rec+0x18 <- 0x418
|
||||||
int targetLocalFlag; // message[10]
|
Point3D beamEndpoint; // rec+0x1c <- 0x460
|
||||||
Point3D beamEndpoint; // message[7]
|
int beamFlag; // rec+0x28 <- 0x46c
|
||||||
int beamFlag; // message[11]
|
int targetLocalFlag; // rec+0x2c <- 0x470
|
||||||
RGBColor color;
|
// DISASM CORRECTION (task #51, @004ba65c/@004ba568): rec+0x30 is the
|
||||||
int payloadCount; // message+0xc (AdvanceSeekVoltage)
|
// TARGET's EntityID -- FUN_00420ef4 (an EntityID copy) from
|
||||||
|
// targetEntity+0x184 (the 1995 Entity::entityID) or DAT_00522524
|
||||||
|
// (EntityID::Null) -- NOT an RGB colour. The reader resolves it
|
||||||
|
// through the entity index and DROPS the record when a non-null id
|
||||||
|
// is unknown on this host.
|
||||||
|
EntityID targetID; // rec+0x30
|
||||||
|
int payloadCount; // (AdvanceSeekVoltage)
|
||||||
};
|
};
|
||||||
typedef Emitter__UpdateRecord UpdateRecord;
|
typedef Emitter__UpdateRecord UpdateRecord;
|
||||||
|
|
||||||
@@ -160,9 +166,14 @@ class NotationFile;
|
|||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Subsystem / Simulation virtual overrides (vtable @00512078)
|
// Subsystem / Simulation virtual overrides (vtable @00512078)
|
||||||
//
|
//
|
||||||
// Slot indices verified against the MechWeapon vtable @00511d2c:
|
// SLOT MAP CORRECTED (task #51): slot 6 is ReadUpdateRecord, not TakeDamage
|
||||||
// slot 6 TakeDamage (MechWeapon base @004b964c)
|
// (@004ba568 resolves an EntityID at rec+0x30 through the entity index and
|
||||||
// slot 7 WriteUpdateRecord (MechWeapon base @004b9690)
|
// applies alarm/beam fields -- record semantics; it chains @004b964c, the
|
||||||
|
// MechWeapon slot-6 read). The real Emitter::TakeDamage is slot 9
|
||||||
|
// @004bafc8 (undecoded -- inherit MechWeapon::TakeDamage until recovered).
|
||||||
|
// slot 6 ReadUpdateRecord @004ba568 (MechWeapon base @004b964c)
|
||||||
|
// slot 7 WriteUpdateRecord @004ba65c (MechWeapon base @004b9690)
|
||||||
|
// slot 9 TakeDamage @004bafc8 (NOT yet reconstructed)
|
||||||
// slot 10 ResetToInitialState (MechWeapon base @004b96ec)
|
// slot 10 ResetToInitialState (MechWeapon base @004b96ec)
|
||||||
// slot 13 PrintState (MechWeapon base @004b9d00)
|
// slot 13 PrintState (MechWeapon base @004b9d00)
|
||||||
// slot 16 ReadyToDischarge (Simulation interface)
|
// slot 16 ReadyToDischarge (Simulation interface)
|
||||||
@@ -171,7 +182,7 @@ class NotationFile;
|
|||||||
//
|
//
|
||||||
public:
|
public:
|
||||||
void
|
void
|
||||||
TakeDamage(Damage &damage); // slot 6, @004ba568
|
ReadUpdateRecord(Simulation__UpdateRecord *message); // slot 6, @004ba568
|
||||||
void
|
void
|
||||||
ResetToInitialState(); // slot 10, @004ba4d0
|
ResetToInitialState(); // slot 10, @004ba4d0
|
||||||
void
|
void
|
||||||
@@ -184,12 +195,13 @@ class NotationFile;
|
|||||||
int BeamOn() const { return beamFlag; } // 0x46c
|
int BeamOn() const { return beamFlag; } // 0x46c
|
||||||
const Point3D &BeamEndpoint() const { return beamEndpoint; } // 0x460
|
const Point3D &BeamEndpoint() const { return beamEndpoint; } // 0x460
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
void
|
void
|
||||||
WriteUpdateRecord( // slot 7, @004ba65c
|
WriteUpdateRecord( // slot 7, @004ba65c
|
||||||
UpdateRecord *message,
|
Simulation__UpdateRecord *message,
|
||||||
int update_model
|
int update_model
|
||||||
);
|
);
|
||||||
|
protected:
|
||||||
|
|
||||||
// @004ba6e0 -- True when the supplied (or linked) voltage source can
|
// @004ba6e0 -- True when the supplied (or linked) voltage source can
|
||||||
// satisfy the current seekVoltage index and is in the "ready" state (2).
|
// satisfy the current seekVoltage index and is in the "ready" state (2).
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ public:
|
|||||||
void SetLevel(int n) { level = n; }
|
void SetLevel(int n) { level = n; }
|
||||||
int GetLevel() const { return level; }
|
int GetLevel() const { return level; }
|
||||||
int Level() const { return level; }
|
int Level() const { return level; }
|
||||||
|
int LevelCountB() const { return levelB; } // +0x10 (the weapon update-record "reset" source)
|
||||||
// ReconAlarm/AlarmIndicator API aliases (callers that predate the retype use these):
|
// ReconAlarm/AlarmIndicator API aliases (callers that predate the retype use these):
|
||||||
void SetState(unsigned n){ level = (int)n; }
|
void SetState(unsigned n){ level = (int)n; }
|
||||||
unsigned GetState() const { return (unsigned)level; }
|
unsigned GetState() const { return (unsigned)level; }
|
||||||
|
|||||||
@@ -487,6 +487,11 @@ public:
|
|||||||
// -> world hit point. Defined in mech.cpp.
|
// -> world hit point. Defined in mech.cpp.
|
||||||
Logical PickRayHit(const Point3D &start, const Vector3D &dir,
|
Logical PickRayHit(const Point3D &start, const Vector3D &dir,
|
||||||
Scalar max_range, Point3D *hit_world);
|
Scalar max_range, Point3D *hit_world);
|
||||||
|
|
||||||
|
// Per-weapon beam render walk (task #33; extracted task #51 so it runs for
|
||||||
|
// EVERY mech -- player, dummy masters, and MP replicants whose emitters
|
||||||
|
// carry replicated discharge state). Defined in mech4.cpp.
|
||||||
|
void DrawWeaponBeams(Scalar dt);
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|||||||
+105
-82
@@ -1237,6 +1237,11 @@ void
|
|||||||
if (legCycleSpeed < -100.0f || legCycleSpeed > 200.0f)
|
if (legCycleSpeed < -100.0f || legCycleSpeed > 200.0f)
|
||||||
legCycleSpeed = 0.0f;
|
legCycleSpeed = 0.0f;
|
||||||
(void)AdvanceLegAnimation(dt); // joints only; travel = DeadReckon
|
(void)AdvanceLegAnimation(dt); // joints only; travel = DeadReckon
|
||||||
|
|
||||||
|
// REPLICANT BEAMS (task #51): the emitters carry live replicated
|
||||||
|
// discharge state (Emitter::ReadUpdateRecord); draw them with the
|
||||||
|
// same per-weapon walk the master uses.
|
||||||
|
DrawWeaponBeams(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getenv("BT_REPL_LOG"))
|
if (getenv("BT_REPL_LOG"))
|
||||||
@@ -2461,88 +2466,7 @@ void
|
|||||||
// PPCs) instead of the old hardcoded single-look stagger, so every
|
// PPCs) instead of the old hardcoded single-look stagger, so every
|
||||||
// mech type fires like its data says. (Old stagger/keepalive block
|
// mech type fires like its data says. (Old stagger/keepalive block
|
||||||
// removed; see the git history for the bring-up scaffolding.)
|
// removed; see the git history for the bring-up scaffolding.)
|
||||||
{
|
DrawWeaponBeams(dt); // task #51: extracted (runs for replicants too)
|
||||||
extern void BTPushBeam(float,float,float, float,float,float, unsigned, float, float);
|
|
||||||
const Scalar ttl1 = (dt > 1e-4f) ? dt : 1e-4f; // one-frame life (redrawn while on)
|
|
||||||
static int s_beamStateLog = 0;
|
|
||||||
int energyOrdinal = -1; // Nth energy weapon (port assignment)
|
|
||||||
for (int wi = 0; wi < GetSubsystemCount(); ++wi)
|
|
||||||
{
|
|
||||||
Subsystem *ws = GetSubsystem(wi);
|
|
||||||
if (ws == 0)
|
|
||||||
continue;
|
|
||||||
// EXACT class filter: Emitter (0xBC8=3016) or PPC (0xBD4=3028).
|
|
||||||
// The derivation check matched too broadly here (the recon
|
|
||||||
// derivation chains are shared stubs for some subsystems --
|
|
||||||
// a Sensor and the MissileLauncher passed and drew garbage
|
|
||||||
// from misinterpreted offsets).
|
|
||||||
const int wcid = (int)ws->GetClassID();
|
|
||||||
if (wcid != 3016 && wcid != 3028)
|
|
||||||
continue;
|
|
||||||
++energyOrdinal;
|
|
||||||
Emitter *em = (Emitter *)ws;
|
|
||||||
if (!em->BeamOn())
|
|
||||||
continue;
|
|
||||||
Point3D mz;
|
|
||||||
em->MuzzlePoint(mz); // LIVE muzzle (tracks the gun)
|
|
||||||
// MOUNT FALLBACK: when the weapon's mount segment doesn't
|
|
||||||
// resolve, GetMuzzlePoint returns the mech ORIGIN (feet).
|
|
||||||
// Assign this weapon its own gun-port segment by roster
|
|
||||||
// ordinal (the same port set the old visual used) so each
|
|
||||||
// energy weapon keeps a stable muzzle on the arms.
|
|
||||||
if (mz.y - localOrigin.linearPosition.y < 1.0f)
|
|
||||||
{
|
|
||||||
static const char *const kGunPorts[] =
|
|
||||||
{ "siterugunport", "sitelugunport", "siterdgunport",
|
|
||||||
"siteldgunport", "siterbgunport", "sitelbgunport" };
|
|
||||||
static EntitySegment *s_portCache[64];
|
|
||||||
static int s_portTried[64];
|
|
||||||
if (energyOrdinal >= 0 && energyOrdinal < 64)
|
|
||||||
{
|
|
||||||
if (!s_portTried[energyOrdinal])
|
|
||||||
{
|
|
||||||
s_portTried[energyOrdinal] = 1;
|
|
||||||
s_portCache[energyOrdinal] = GetSegment(
|
|
||||||
CString(kGunPorts[energyOrdinal % 6]));
|
|
||||||
}
|
|
||||||
if (s_portCache[energyOrdinal] != 0)
|
|
||||||
{
|
|
||||||
AffineMatrix mw;
|
|
||||||
mw.Multiply(s_portCache[energyOrdinal]->GetSegmentToEntity(),
|
|
||||||
localToWorld);
|
|
||||||
mz = mw; // Point3D = matrix translation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const Point3D &bend = em->BeamEndpoint(); // the fire's world hit point
|
|
||||||
// authored per-weapon colour; unset (-1) -> the ER-laser red
|
|
||||||
RGBColor pc = em->PipColor();
|
|
||||||
float r = (float)pc.Red, g = (float)pc.Green, b = (float)pc.Blue;
|
|
||||||
if (r < 0.0f || g < 0.0f || b < 0.0f) { r = 0.78f; g = 0.08f; b = 0.02f; }
|
|
||||||
// PPC (classID 0xBD4 = 3028): a thicker, brighter bolt than a laser tube.
|
|
||||||
const int isPPC = ((int)em->GetClassID() == 3028);
|
|
||||||
// ONE draw per beam, at the model's NATURAL width: the weapon's
|
|
||||||
// own tube (ERMLASER radius 0.22u, PPC bolt 0.62u) IS the beam
|
|
||||||
// -- the old inflated two-layer glow/core (3.0x + 0.9x widths)
|
|
||||||
// drew fat cartoon cylinders 13x the authored size. The tint
|
|
||||||
// modulates the scrolling grit; thin natural tubes stay under
|
|
||||||
// saturation without a hand-dimmed core.
|
|
||||||
extern void BTPushBeamKind(float,float,float, float,float,float,
|
|
||||||
unsigned, float, float, int);
|
|
||||||
unsigned tint =
|
|
||||||
(((unsigned)(40.0f + r * 215.0f) & 0xFF) << 16) |
|
|
||||||
(((unsigned)(40.0f + g * 215.0f) & 0xFF) << 8) |
|
|
||||||
((unsigned)(40.0f + b * 215.0f) & 0xFF);
|
|
||||||
BTPushBeamKind(mz.x, mz.y, mz.z, bend.x, bend.y, bend.z,
|
|
||||||
tint, ttl1, 1.0f /* natural model width */,
|
|
||||||
isPPC ? 1 : 0 /* ppc.bgf : ermlaser.bgf */);
|
|
||||||
if (getenv("BT_BEAM_LOG") && (s_beamStateLog++ % 31) == 0) // 31: coprime with the 5-beam volley (a %30 sampler aliased to one weapon)
|
|
||||||
DEBUG_STREAM << "[beam] " << (isPPC ? "PPC" : "laser") << " #" << wi
|
|
||||||
<< " mz=(" << mz.x << "," << mz.y << "," << mz.z
|
|
||||||
<< ") end=(" << bend.x << "," << bend.y << "," << bend.z
|
|
||||||
<< ") rgb=(" << r << "," << g << "," << b << ")\n" << std::flush;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- TARGETING: the WORLD-PICK model (task #41, the reconciliation of
|
// --- TARGETING: the WORLD-PICK model (task #41, the reconciliation of
|
||||||
@@ -3538,3 +3462,102 @@ static const DamageStateEntry kDamageStateTable[] =
|
|||||||
//===========================================================================//
|
//===========================================================================//
|
||||||
// End of recovered mech4.cpp slice.
|
// End of recovered mech4.cpp slice.
|
||||||
//===========================================================================//
|
//===========================================================================//
|
||||||
|
|
||||||
|
//
|
||||||
|
// DrawWeaponBeams (task #51 extraction) -- the per-weapon beam render walk
|
||||||
|
// (task #33), extracted from the player-only drive block so it runs for
|
||||||
|
// EVERY mech: the local player, the solo dummy, and MP REPLICANTS (whose
|
||||||
|
// emitters now carry live replicated discharge state via the Emitter update
|
||||||
|
// records; without this the peer's beams applied but never drew).
|
||||||
|
//
|
||||||
|
void
|
||||||
|
Mech::DrawWeaponBeams(Scalar dt)
|
||||||
|
{
|
||||||
|
extern void BTPushBeam(float,float,float, float,float,float, unsigned, float, float);
|
||||||
|
const Scalar ttl1 = (dt > 1e-4f) ? dt : 1e-4f; // one-frame life (redrawn while on)
|
||||||
|
static int s_beamStateLog = 0;
|
||||||
|
int energyOrdinal = -1; // Nth energy weapon (port assignment)
|
||||||
|
for (int wi = 0; wi < GetSubsystemCount(); ++wi)
|
||||||
|
{
|
||||||
|
Subsystem *ws = GetSubsystem(wi);
|
||||||
|
if (ws == 0)
|
||||||
|
continue;
|
||||||
|
// EXACT class filter: Emitter (0xBC8=3016) or PPC (0xBD4=3028).
|
||||||
|
// The derivation check matched too broadly here (the recon
|
||||||
|
// derivation chains are shared stubs for some subsystems --
|
||||||
|
// a Sensor and the MissileLauncher passed and drew garbage
|
||||||
|
// from misinterpreted offsets).
|
||||||
|
const int wcid = (int)ws->GetClassID();
|
||||||
|
if (wcid != 3016 && wcid != 3028)
|
||||||
|
continue;
|
||||||
|
++energyOrdinal;
|
||||||
|
Emitter *em = (Emitter *)ws;
|
||||||
|
if (!em->BeamOn())
|
||||||
|
continue;
|
||||||
|
Point3D mz;
|
||||||
|
em->MuzzlePoint(mz); // LIVE muzzle (tracks the gun)
|
||||||
|
// MOUNT FALLBACK: when the weapon's mount segment doesn't
|
||||||
|
// resolve, GetMuzzlePoint returns the mech ORIGIN (feet).
|
||||||
|
// Assign this weapon its own gun-port segment by roster
|
||||||
|
// ordinal (the same port set the old visual used) so each
|
||||||
|
// energy weapon keeps a stable muzzle on the arms.
|
||||||
|
if (mz.y - localOrigin.linearPosition.y < 1.0f)
|
||||||
|
{
|
||||||
|
static const char *const kGunPorts[] =
|
||||||
|
{ "siterugunport", "sitelugunport", "siterdgunport",
|
||||||
|
"siteldgunport", "siterbgunport", "sitelbgunport" };
|
||||||
|
// PER-MECH cache (task #51): the walk now runs for EVERY mech
|
||||||
|
// (player + replicants); the old process-wide statics would serve
|
||||||
|
// the PLAYER's segment pointers as the replicant's muzzles. Key
|
||||||
|
// the slot by owner and re-resolve on mismatch.
|
||||||
|
static EntitySegment *s_portCache[64];
|
||||||
|
static int s_portTried[64];
|
||||||
|
static Mech *s_portOwner[64];
|
||||||
|
if (energyOrdinal >= 0 && energyOrdinal < 64)
|
||||||
|
{
|
||||||
|
if (!s_portTried[energyOrdinal]
|
||||||
|
|| s_portOwner[energyOrdinal] != this)
|
||||||
|
{
|
||||||
|
s_portTried[energyOrdinal] = 1;
|
||||||
|
s_portOwner[energyOrdinal] = this;
|
||||||
|
s_portCache[energyOrdinal] = GetSegment(
|
||||||
|
CString(kGunPorts[energyOrdinal % 6]));
|
||||||
|
}
|
||||||
|
if (s_portCache[energyOrdinal] != 0)
|
||||||
|
{
|
||||||
|
AffineMatrix mw;
|
||||||
|
mw.Multiply(s_portCache[energyOrdinal]->GetSegmentToEntity(),
|
||||||
|
localToWorld);
|
||||||
|
mz = mw; // Point3D = matrix translation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const Point3D &bend = em->BeamEndpoint(); // the fire's world hit point
|
||||||
|
// authored per-weapon colour; unset (-1) -> the ER-laser red
|
||||||
|
RGBColor pc = em->PipColor();
|
||||||
|
float r = (float)pc.Red, g = (float)pc.Green, b = (float)pc.Blue;
|
||||||
|
if (r < 0.0f || g < 0.0f || b < 0.0f) { r = 0.78f; g = 0.08f; b = 0.02f; }
|
||||||
|
// PPC (classID 0xBD4 = 3028): a thicker, brighter bolt than a laser tube.
|
||||||
|
const int isPPC = ((int)em->GetClassID() == 3028);
|
||||||
|
// ONE draw per beam, at the model's NATURAL width: the weapon's
|
||||||
|
// own tube (ERMLASER radius 0.22u, PPC bolt 0.62u) IS the beam
|
||||||
|
// -- the old inflated two-layer glow/core (3.0x + 0.9x widths)
|
||||||
|
// drew fat cartoon cylinders 13x the authored size. The tint
|
||||||
|
// modulates the scrolling grit; thin natural tubes stay under
|
||||||
|
// saturation without a hand-dimmed core.
|
||||||
|
extern void BTPushBeamKind(float,float,float, float,float,float,
|
||||||
|
unsigned, float, float, int);
|
||||||
|
unsigned tint =
|
||||||
|
(((unsigned)(40.0f + r * 215.0f) & 0xFF) << 16) |
|
||||||
|
(((unsigned)(40.0f + g * 215.0f) & 0xFF) << 8) |
|
||||||
|
((unsigned)(40.0f + b * 215.0f) & 0xFF);
|
||||||
|
BTPushBeamKind(mz.x, mz.y, mz.z, bend.x, bend.y, bend.z,
|
||||||
|
tint, ttl1, 1.0f /* natural model width */,
|
||||||
|
isPPC ? 1 : 0 /* ppc.bgf : ermlaser.bgf */);
|
||||||
|
if (getenv("BT_BEAM_LOG") && (s_beamStateLog++ % 31) == 0) // 31: coprime with the 5-beam volley (a %30 sampler aliased to one weapon)
|
||||||
|
DEBUG_STREAM << "[beam] " << (isPPC ? "PPC" : "laser") << " #" << wi
|
||||||
|
<< " mz=(" << mz.x << "," << mz.y << "," << mz.z
|
||||||
|
<< ") end=(" << bend.x << "," << bend.y << "," << bend.z
|
||||||
|
<< ") rgb=(" << r << "," << g << "," << b << ")\n" << std::flush;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -233,59 +233,73 @@ Logical
|
|||||||
//
|
//
|
||||||
|
|
||||||
//
|
//
|
||||||
// @004b964c -- slot 6. Apply damage through the base, then set the weapon's
|
// @004b96d4 -- slot 9 (TASK #51 RENAME: this body was mislabeled slot-6
|
||||||
// display alarm: a destroyed weapon (damage->destroyed flag, +0x14) clears the
|
// ReadUpdateRecord; @004b96d4 chains @004b0efc = PoweredSubsystem::TakeDamage,
|
||||||
// alarm to 0, otherwise the alarm tracks the incoming damage level (+0x10).
|
// which dispatches on *param==4 == Damage::damageType -- damage semantics).
|
||||||
|
// The PoweredSubsystem::TakeDamage body (electrical-short handling) is not yet
|
||||||
|
// reconstructed; chain to the engine Subsystem base, and keep the damage-zone
|
||||||
|
// alarm tracking this port has shipped with (best-effort; the binary's alarm
|
||||||
|
// display on weapon damage flows through the unreconstructed @004b0efc chain).
|
||||||
//
|
//
|
||||||
void
|
void
|
||||||
MechWeapon::TakeDamage(Damage &damage)
|
MechWeapon::TakeDamage(Damage &damage)
|
||||||
{
|
{
|
||||||
Subsystem::TakeDamage(damage); // FUN_0041bd34
|
Subsystem::TakeDamage(damage); // engine base (real chain: @004b0efc)
|
||||||
|
|
||||||
// A destroyed weapon clears its display alarm; otherwise the alarm tracks
|
// Port behavior (kept): a destroyed weapon clears its display alarm;
|
||||||
// the damage-zone state set by the base TakeDamage above. (The decomp read
|
// otherwise the alarm tracks the resolved damage-zone state.
|
||||||
// the post-damage destroyed/level flags out of the damage record; here we
|
|
||||||
// read them back off the resolved damage zone.)
|
|
||||||
// Read the ENGINE Subsystem::damageZone (the real built zone), qualified -- the
|
|
||||||
// nearer MechSubsystem::damageZone is a ReconDamageZone-shim SHADOW of it (exposed
|
|
||||||
// once HeatableSubsystem re-based onto MechSubsystem). TODO: remove that shadow.
|
|
||||||
::DamageZone *dz = this->Subsystem::damageZone;
|
::DamageZone *dz = this->Subsystem::damageZone;
|
||||||
if (dz != 0
|
if (dz != 0
|
||||||
&& dz->GetGraphicState() == DamageZone::DestroyedGraphicState)
|
&& dz->GetGraphicState() == DamageZone::DestroyedGraphicState)
|
||||||
{
|
{
|
||||||
weaponAlarm.SetLevel(0); // FUN_0041bbd8(this+0xd4, 0)
|
weaponAlarm.SetLevel(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
weaponAlarm.SetLevel(
|
weaponAlarm.SetLevel(
|
||||||
(dz != 0 && dz->damageLevel > 0.0f) ? 1 : 0
|
(dz != 0 && dz->damageLevel > 0.0f) ? 1 : 0
|
||||||
); // FUN_0041bbd8(this+0xd4, level)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// @004b9690 -- slot 7. Append the weapon's replication fields to the update
|
// @004b9690 -- slot 7. Append the weapon's replication fields to the update
|
||||||
// record: record type 0x18, the alarm state (this+0x364), and a "ready/idle"
|
// record. DISASM CORRECTIONS (task #51): `*message = 0x18` writes the record
|
||||||
// flag derived from this+0x360.
|
// LENGTH (record[0] = recordLength), not recordID; and message[5] derives from
|
||||||
|
// this+0x360 == weaponAlarm+0x10 (LevelCountB), not from the level. BASE-TYPED
|
||||||
|
// param: with the class's own UpdateRecord typedef this silently failed to
|
||||||
|
// override the engine virtual, so the engine base ran and no weapon field
|
||||||
|
// ever serialized.
|
||||||
//
|
//
|
||||||
void
|
void
|
||||||
MechWeapon::WriteUpdateRecord(UpdateRecord *message, int update_model)
|
MechWeapon::WriteUpdateRecord(Simulation__UpdateRecord *message, int update_model)
|
||||||
{
|
{
|
||||||
Subsystem::WriteUpdateRecord(message, update_model); // FUN_0041c500
|
Subsystem::WriteUpdateRecord(message, update_model); // FUN_0041c500 (header + subsystemID)
|
||||||
|
|
||||||
message->recordID = 0x18; // *message = 0x18
|
MechWeapon__UpdateRecord *rec = (MechWeapon__UpdateRecord *)message;
|
||||||
message->alarmState = weaponAlarm.GetLevel(); // message[4] = *(this+0x364)
|
rec->recordLength = sizeof(MechWeapon__UpdateRecord); // *message = 0x18
|
||||||
message->weaponIdle = (weaponAlarm.GetLevel() == 0) ? 1 : 0; // message[5]
|
rec->alarmState = weaponAlarm.GetLevel(); // message[4] = *(this+0x364)
|
||||||
|
rec->weaponIdle = (weaponAlarm.LevelCountB() == 0) ? 1 : 0; // message[5] = (*(this+0x360)==0)
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// @004b96d4 -- slot 9. MechWeapon adds nothing of its own; defers to the
|
// @004b964c -- slot 6 (TASK #51 RENAME: was mislabeled TakeDamage). Apply a
|
||||||
// PoweredSubsystem implementation (paired with WriteUpdateRecord above).
|
// weapon update record on the REPLICANT: chain the Simulation base
|
||||||
|
// (@0041bd34 -- lastUpdate + simulationState), then the weapon alarm --
|
||||||
|
// reset-through-0 first when the record's weaponIdle flag is set, then the
|
||||||
|
// replicated alarm level.
|
||||||
//
|
//
|
||||||
void
|
void
|
||||||
MechWeapon::ReadUpdateRecord(UpdateRecord *message)
|
MechWeapon::ReadUpdateRecord(Simulation__UpdateRecord *message)
|
||||||
{
|
{
|
||||||
PoweredSubsystem::ReadUpdateRecord(message); // FUN_004b0efc
|
Simulation::ReadUpdateRecord(message); // FUN_0041bd34
|
||||||
|
|
||||||
|
MechWeapon__UpdateRecord *rec = (MechWeapon__UpdateRecord *)message;
|
||||||
|
if (rec->weaponIdle != 0) // record+0x14
|
||||||
|
{
|
||||||
|
weaponAlarm.SetLevel(0);
|
||||||
|
}
|
||||||
|
weaponAlarm.SetLevel(rec->alarmState); // record+0x10
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -159,30 +159,39 @@ class CockpitHud;
|
|||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Subsystem virtual overrides (slots on vtable @00511d2c)
|
// Subsystem virtual overrides (slots on vtable @00511d2c)
|
||||||
//
|
//
|
||||||
// Slot indices verified by diffing against the Subsystem vtable tail of
|
// SLOT MAP CORRECTED (task #51): the Read/TakeDamage attributions were
|
||||||
// @0050e170 and the PoweredSubsystem vtable @0050f9d8:
|
// SWAPPED. By symmetry with the Entity hierarchy (Mech slot 6 =
|
||||||
// slot 6 TakeDamage(Damage&) (Subsystem base @0041bd34)
|
// ReadUpdateRecord @004a1232, slot 7 = WriteUpdateRecord @004a0c2c, both
|
||||||
// slot 7 WriteUpdateRecord(...) (Subsystem base @0041c500)
|
// verified) and by body semantics (@004b964c reads record+0x10/+0x14 into
|
||||||
// slot 9 ReadUpdateRecord(...) (PoweredSubsystem base @004b0efc)
|
// the weapon alarm after chaining @0041bd34 = Simulation::ReadUpdateRecord;
|
||||||
|
// @004b0efc dispatches on *param==4 = Damage::damageType):
|
||||||
|
// slot 6 ReadUpdateRecord(...) @004b964c (base @0041bd34 = Simulation::ReadUpdateRecord)
|
||||||
|
// slot 7 WriteUpdateRecord(...) @004b9690 (base @0041c500 = Subsystem::WriteUpdateRecord)
|
||||||
|
// slot 9 TakeDamage(Damage&) @004b96d4 (chains @004b0efc = PoweredSubsystem::TakeDamage)
|
||||||
// slot 10 ResetToInitialState() (PoweredSubsystem base @004b0e6c)
|
// slot 10 ResetToInitialState() (PoweredSubsystem base @004b0e6c)
|
||||||
// slot 13 PrintState() (PoweredSubsystem base @004b1224)
|
// slot 13 PrintState() (PoweredSubsystem base @004b1224)
|
||||||
//
|
//
|
||||||
|
// NOTE the ENGINE-OVERRIDE signature rule: the virtuals are declared on
|
||||||
|
// Simulation with Simulation::UpdateRecord* (SIMULATE.h:127-131). Declaring
|
||||||
|
// them here with THIS class's shadowing `UpdateRecord` typedef silently
|
||||||
|
// fails to override (the engine base runs instead and none of the weapon
|
||||||
|
// fields ever serialize) -- base-typed params, cast inside.
|
||||||
|
//
|
||||||
public:
|
public:
|
||||||
void
|
void
|
||||||
TakeDamage(Damage &damage); // slot 6, @004b964c
|
TakeDamage(Damage &damage); // slot 9, @004b96d4
|
||||||
void
|
void
|
||||||
ResetToInitialState(); // slot 10, @004b96ec
|
ResetToInitialState(); // slot 10, @004b96ec
|
||||||
void
|
void
|
||||||
PrintState(); // slot 13, @004b9d00
|
PrintState(); // slot 13, @004b9d00
|
||||||
|
|
||||||
protected:
|
|
||||||
void
|
void
|
||||||
WriteUpdateRecord( // slot 7, @004b9690
|
WriteUpdateRecord( // slot 7, @004b9690
|
||||||
UpdateRecord *message,
|
Simulation__UpdateRecord *message,
|
||||||
int update_model
|
int update_model
|
||||||
);
|
);
|
||||||
void
|
void
|
||||||
ReadUpdateRecord(UpdateRecord *message); // slot 9, @004b96d4
|
ReadUpdateRecord(Simulation__UpdateRecord *message); // slot 6, @004b964c
|
||||||
|
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Test Class Support
|
// Test Class Support
|
||||||
|
|||||||
@@ -314,13 +314,15 @@ Logical
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// @004bbae0 -- slot 9. ProjectileWeapon adds nothing of its own; defers to the
|
// @004bbae0 -- slot 9 (TASK #51 RENAME: slot 9 is TakeDamage, not
|
||||||
// MechWeapon implementation.
|
// ReadUpdateRecord -- see the corrected slot map in mechweap.hpp).
|
||||||
|
// ProjectileWeapon adds nothing of its own; defers to the MechWeapon
|
||||||
|
// implementation (@004b96d4 chains @004b0efc = PoweredSubsystem::TakeDamage).
|
||||||
//
|
//
|
||||||
void
|
void
|
||||||
ProjectileWeapon::ReadUpdateRecord(UpdateRecord *message)
|
ProjectileWeapon::TakeDamage(Damage &damage)
|
||||||
{
|
{
|
||||||
MechWeapon::ReadUpdateRecord(message); // FUN_004b96d4
|
MechWeapon::TakeDamage(damage); // FUN_004b96d4
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -172,11 +172,13 @@ class NotationFile;
|
|||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Subsystem virtual overrides (slots on vtable @0051242c)
|
// Subsystem virtual overrides (slots on vtable @0051242c)
|
||||||
//
|
//
|
||||||
// Slot indices verified by decoding the raw vtable bytes (section_dump):
|
// Slot indices verified by decoding the raw vtable bytes (section_dump).
|
||||||
// slot 6 TakeDamage INHERITED MechWeapon @004b964c
|
// SLOT MAP CORRECTED (task #51): 6=ReadUpdateRecord, 9=TakeDamage (the
|
||||||
|
// old attributions were swapped -- see mechweap.hpp for the evidence):
|
||||||
|
// slot 6 ReadUpdateRecord INHERITED MechWeapon @004b964c
|
||||||
// slot 7 WriteUpdateRecord INHERITED MechWeapon @004b9690
|
// slot 7 WriteUpdateRecord INHERITED MechWeapon @004b9690
|
||||||
// slot 8 HandleMessage OVERRIDE @004bcabc
|
// slot 8 HandleMessage OVERRIDE @004bcabc
|
||||||
// slot 9 ReadUpdateRecord OVERRIDE @004bbae0 (thin -> MechWeapon)
|
// slot 9 TakeDamage OVERRIDE @004bbae0 (thin -> MechWeapon)
|
||||||
// slot 10 ResetToInitialState OVERRIDE @004bbaf8
|
// slot 10 ResetToInitialState OVERRIDE @004bbaf8
|
||||||
// slot 12 GetStatusFlags OVERRIDE @004bbf88 (body not recovered)
|
// slot 12 GetStatusFlags OVERRIDE @004bbf88 (body not recovered)
|
||||||
// slot 13 PrintState OVERRIDE @004bc6c8
|
// slot 13 PrintState OVERRIDE @004bc6c8
|
||||||
@@ -194,8 +196,11 @@ class NotationFile;
|
|||||||
PrintState(); // slot 13, @004bc6c8
|
PrintState(); // slot 13, @004bc6c8
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// TASK #51 RENAME: slot 9 is TakeDamage (the old ReadUpdateRecord
|
||||||
|
// attribution was swapped; the record read is INHERITED from
|
||||||
|
// MechWeapon slot 6 @004b964c -- see mechweap.hpp for the evidence).
|
||||||
void
|
void
|
||||||
ReadUpdateRecord(UpdateRecord *message); // slot 9, @004bbae0
|
TakeDamage(Damage &damage); // slot 9, @004bbae0
|
||||||
|
|
||||||
// slot 16, @004bbc20 -- MechWeapon-family per-frame hook (overrides
|
// slot 16, @004bbc20 -- MechWeapon-family per-frame hook (overrides
|
||||||
// MechWeapon @004b0b5c). Body not recovered. TODO: confirm role.
|
// MechWeapon @004b0b5c). Body not recovered. TODO: confirm role.
|
||||||
|
|||||||
@@ -0,0 +1,467 @@
|
|||||||
|
=== Mech::WriteUpdateRecord @0x4a0c2c (vtable slot 7) ===
|
||||||
|
=== args: (this=ebp+8, record=ebp+0xC, type=ebp+0x10); jump table @0x4a0c55 on type 0..8 ===
|
||||||
|
=== table: 0:0x4a0c79 1:0x4a11cb 2:0x4a0e5b 3:0x4a0d84 4:0x4a0e9e 5:0x4a0fab 6:0x4a104d 7:0x4a10ff 8:0x4a117f ===
|
||||||
|
|
||||||
|
===== prologue + dispatch @0x4a0c2c..0x4a0c55 =====
|
||||||
|
0x4a0c2c: push ebp
|
||||||
|
0x4a0c2d: mov ebp, esp
|
||||||
|
0x4a0c2f: add esp, -0x68
|
||||||
|
0x4a0c32: push ebx
|
||||||
|
0x4a0c33: push esi
|
||||||
|
0x4a0c34: push edi
|
||||||
|
0x4a0c35: mov edi, dword ptr [ebp + 0x10]
|
||||||
|
0x4a0c38: mov ebx, dword ptr [ebp + 8]
|
||||||
|
0x4a0c3b: mov eax, dword ptr [ebx + 0x128]
|
||||||
|
0x4a0c41: mov esi, dword ptr [eax]
|
||||||
|
0x4a0c43: mov eax, edi
|
||||||
|
0x4a0c45: cmp eax, 8
|
||||||
|
0x4a0c48: ja 0x4a11cb
|
||||||
|
0x4a0c4e: jmp dword ptr [eax*4 + 0x4a0c55]
|
||||||
|
|
||||||
|
===== case 0 (full pose snapshot) @0x4a0c79..0x4a0d84 =====
|
||||||
|
0x4a0c79: lea edx, [ebx + 0x138]
|
||||||
|
0x4a0c7f: push edx
|
||||||
|
0x4a0c80: lea ecx, [ebp - 0x44]
|
||||||
|
0x4a0c83: push ecx
|
||||||
|
0x4a0c84: call 0x408f44
|
||||||
|
0x4a0c89: add esp, 8
|
||||||
|
0x4a0c8c: lea eax, [ebx + 0x2d4]
|
||||||
|
0x4a0c92: push eax
|
||||||
|
0x4a0c93: lea edx, [ebp - 0x50]
|
||||||
|
0x4a0c96: push edx
|
||||||
|
0x4a0c97: call 0x408440
|
||||||
|
0x4a0c9c: add esp, 8
|
||||||
|
0x4a0c9f: push edi
|
||||||
|
0x4a0ca0: mov ecx, dword ptr [ebp + 0xc]
|
||||||
|
0x4a0ca3: push ecx
|
||||||
|
0x4a0ca4: push ebx
|
||||||
|
0x4a0ca5: call 0x4225a4
|
||||||
|
0x4a0caa: mov edi, dword ptr [ebp + 0xc]
|
||||||
|
0x4a0cad: add esp, 0xc
|
||||||
|
0x4a0cb0: lea eax, [ebp - 0x44]
|
||||||
|
0x4a0cb3: lea edx, [ebx + 0x138]
|
||||||
|
0x4a0cb9: mov word ptr [edi + 4], 0
|
||||||
|
0x4a0cbf: mov dword ptr [ebx + 0x77c], 1
|
||||||
|
0x4a0cc9: push eax
|
||||||
|
0x4a0cca: push edx
|
||||||
|
0x4a0ccb: call 0x409a00
|
||||||
|
0x4a0cd0: add esp, 8
|
||||||
|
0x4a0cd3: lea ecx, [ebx + 0x2d4]
|
||||||
|
0x4a0cd9: mov dword ptr [ebp - 4], ecx
|
||||||
|
0x4a0cdc: lea eax, [ebp - 0x50]
|
||||||
|
0x4a0cdf: push eax
|
||||||
|
0x4a0ce0: mov edx, dword ptr [ebp - 4]
|
||||||
|
0x4a0ce3: push edx
|
||||||
|
0x4a0ce4: call 0x408440
|
||||||
|
0x4a0ce9: add esp, 8
|
||||||
|
0x4a0cec: mov ecx, dword ptr [ebx + 0x3b0]
|
||||||
|
0x4a0cf2: cmp ecx, 2
|
||||||
|
0x4a0cf5: je 0x4a0d02
|
||||||
|
0x4a0cf7: mov eax, dword ptr [ebx + 0x3b0]
|
||||||
|
0x4a0cfd: cmp eax, 3
|
||||||
|
0x4a0d00: jne 0x4a0d16
|
||||||
|
0x4a0d02: push 0x4e0fd4 ; [0x4e0fd4]=0f
|
||||||
|
0x4a0d07: lea edx, [ebx + 0x298]
|
||||||
|
0x4a0d0d: push edx
|
||||||
|
0x4a0d0e: call 0x40a7f4
|
||||||
|
0x4a0d13: add esp, 8
|
||||||
|
0x4a0d16: mov ecx, dword ptr [ebx + 0x40]
|
||||||
|
0x4a0d19: mov eax, dword ptr [ebx + 0x3c]
|
||||||
|
0x4a0d1c: cmp ecx, eax
|
||||||
|
0x4a0d1e: je 0x4a0d64
|
||||||
|
0x4a0d20: mov edx, dword ptr [ebx + 0x3c]
|
||||||
|
0x4a0d23: cmp edx, 2
|
||||||
|
0x4a0d26: je 0x4a0d30
|
||||||
|
0x4a0d28: mov ecx, dword ptr [ebx + 0x40]
|
||||||
|
0x4a0d2b: cmp ecx, 2
|
||||||
|
0x4a0d2e: jne 0x4a0d64
|
||||||
|
0x4a0d30: lea eax, [ebx + 0x12c]
|
||||||
|
0x4a0d36: push eax
|
||||||
|
0x4a0d37: lea edx, [ebx + 0x260]
|
||||||
|
0x4a0d3d: push edx
|
||||||
|
0x4a0d3e: call 0x40a938
|
||||||
|
0x4a0d43: add esp, 8
|
||||||
|
0x4a0d46: lea ecx, [ebx + 0x2c8]
|
||||||
|
0x4a0d4c: push ecx
|
||||||
|
0x4a0d4d: lea eax, [ebx + 0x298]
|
||||||
|
0x4a0d53: push eax
|
||||||
|
0x4a0d54: call 0x40a7f4
|
||||||
|
0x4a0d59: add esp, 8
|
||||||
|
0x4a0d5c: xor edx, edx
|
||||||
|
0x4a0d5e: mov dword ptr [ebx + 0x77c], edx
|
||||||
|
0x4a0d64: mov ecx, dword ptr [esi + 0x128]
|
||||||
|
0x4a0d6a: mov dword ptr [edi + 0x74], ecx
|
||||||
|
0x4a0d6d: mov eax, dword ptr [esi + 0x128]
|
||||||
|
0x4a0d73: mov dword ptr [ebx + 0x6b4], eax
|
||||||
|
0x4a0d79: mov dword ptr [edi], 0x78
|
||||||
|
0x4a0d7f: jmp 0x4a11d9
|
||||||
|
|
||||||
|
===== case 3 (score/heat) @0x4a0d84..0x4a0e5b =====
|
||||||
|
0x4a0d84: mov edx, dword ptr [ebp + 0xc]
|
||||||
|
0x4a0d87: mov dword ptr [ebp - 8], edx
|
||||||
|
0x4a0d8a: push edi
|
||||||
|
0x4a0d8b: mov ecx, dword ptr [ebp - 8]
|
||||||
|
0x4a0d8e: push ecx
|
||||||
|
0x4a0d8f: push ebx
|
||||||
|
0x4a0d90: call 0x41bd60
|
||||||
|
0x4a0d95: add esp, 0xc
|
||||||
|
0x4a0d98: mov eax, dword ptr [ebp - 8]
|
||||||
|
0x4a0d9b: mov dword ptr [eax], 0x20
|
||||||
|
0x4a0da1: mov edx, dword ptr [ebp - 8]
|
||||||
|
0x4a0da4: mov word ptr [edx + 4], 0
|
||||||
|
0x4a0daa: mov ecx, dword ptr [ebp - 8]
|
||||||
|
0x4a0dad: mov eax, dword ptr [ebx + 0x654]
|
||||||
|
0x4a0db3: mov dword ptr [ecx + 0x10], eax
|
||||||
|
0x4a0db6: mov edx, dword ptr [ebp - 8]
|
||||||
|
0x4a0db9: mov ecx, dword ptr [ebx + 0x3b0]
|
||||||
|
0x4a0dbf: mov dword ptr [edx + 0x14], ecx
|
||||||
|
0x4a0dc2: mov eax, dword ptr [ebp - 8]
|
||||||
|
0x4a0dc5: mov edx, dword ptr [ebx + 0x4d8]
|
||||||
|
0x4a0dcb: mov dword ptr [eax + 0x18], edx
|
||||||
|
0x4a0dce: mov ecx, dword ptr [ebp - 8]
|
||||||
|
0x4a0dd1: mov eax, dword ptr [ecx + 0x10]
|
||||||
|
0x4a0dd4: mov dword ptr [ebx + 0x658], eax
|
||||||
|
0x4a0dda: mov edx, dword ptr [ebp - 8]
|
||||||
|
0x4a0ddd: mov ecx, dword ptr [edx + 0x14]
|
||||||
|
0x4a0de0: test ecx, ecx
|
||||||
|
0x4a0de2: jne 0x4a0e0d
|
||||||
|
0x4a0de4: push 1
|
||||||
|
0x4a0de6: lea eax, [ebx + 0x65c]
|
||||||
|
0x4a0dec: push eax
|
||||||
|
0x4a0ded: call 0x4283b8
|
||||||
|
0x4a0df2: add esp, 8
|
||||||
|
0x4a0df5: mov edx, dword ptr [ebp - 8]
|
||||||
|
0x4a0df8: mov ecx, dword ptr [edx + 0x14]
|
||||||
|
0x4a0dfb: push ecx
|
||||||
|
0x4a0dfc: lea eax, [ebx + 0x714]
|
||||||
|
0x4a0e02: push eax
|
||||||
|
0x4a0e03: call 0x41bbd8
|
||||||
|
0x4a0e08: add esp, 8
|
||||||
|
0x4a0e0b: jmp 0x4a0e3e
|
||||||
|
0x4a0e0d: mov edx, dword ptr [ebp - 8]
|
||||||
|
0x4a0e10: mov ecx, dword ptr [edx + 0x14]
|
||||||
|
0x4a0e13: dec ecx
|
||||||
|
0x4a0e14: jne 0x4a0e2e
|
||||||
|
0x4a0e16: mov eax, dword ptr [ebp - 8]
|
||||||
|
0x4a0e19: mov edx, dword ptr [eax + 0x14]
|
||||||
|
0x4a0e1c: push edx
|
||||||
|
0x4a0e1d: lea ecx, [ebx + 0x714]
|
||||||
|
0x4a0e23: push ecx
|
||||||
|
0x4a0e24: call 0x41bbd8
|
||||||
|
0x4a0e29: add esp, 8
|
||||||
|
0x4a0e2c: jmp 0x4a0e3e
|
||||||
|
0x4a0e2e: mov eax, dword ptr [ebp - 8]
|
||||||
|
0x4a0e31: mov edx, dword ptr [eax + 0x14]
|
||||||
|
0x4a0e34: push edx
|
||||||
|
0x4a0e35: push ebx
|
||||||
|
0x4a0e36: call 0x4a800c
|
||||||
|
0x4a0e3b: add esp, 8
|
||||||
|
0x4a0e3e: mov ecx, dword ptr [ebp - 8]
|
||||||
|
0x4a0e41: mov eax, dword ptr [esi + 0x128]
|
||||||
|
0x4a0e47: mov dword ptr [ecx + 0x1c], eax
|
||||||
|
0x4a0e4a: mov edx, dword ptr [esi + 0x128]
|
||||||
|
0x4a0e50: mov dword ptr [ebx + 0x6b4], edx
|
||||||
|
0x4a0e56: jmp 0x4a11d9
|
||||||
|
|
||||||
|
===== case 2 (alarm-only) @0x4a0e5b..0x4a0e9e =====
|
||||||
|
0x4a0e5b: mov ecx, dword ptr [ebp + 0xc]
|
||||||
|
0x4a0e5e: mov dword ptr [ebp - 0xc], ecx
|
||||||
|
0x4a0e61: push edi
|
||||||
|
0x4a0e62: mov eax, dword ptr [ebp - 0xc]
|
||||||
|
0x4a0e65: push eax
|
||||||
|
0x4a0e66: push ebx
|
||||||
|
0x4a0e67: call 0x41bd60
|
||||||
|
0x4a0e6c: add esp, 0xc
|
||||||
|
0x4a0e6f: mov edx, dword ptr [ebp - 0xc]
|
||||||
|
0x4a0e72: mov dword ptr [edx], 0x14
|
||||||
|
0x4a0e78: mov ecx, dword ptr [ebp - 0xc]
|
||||||
|
0x4a0e7b: mov word ptr [ecx + 4], 0
|
||||||
|
0x4a0e81: mov eax, dword ptr [ebp - 0xc]
|
||||||
|
0x4a0e84: mov edx, dword ptr [esi + 0x128]
|
||||||
|
0x4a0e8a: mov dword ptr [eax + 0x10], edx
|
||||||
|
0x4a0e8d: mov ecx, dword ptr [esi + 0x128]
|
||||||
|
0x4a0e93: mov dword ptr [ebx + 0x6b4], ecx
|
||||||
|
0x4a0e99: jmp 0x4a11d9
|
||||||
|
|
||||||
|
===== case 4 (pose + time re-sync) @0x4a0e9e..0x4a0fab =====
|
||||||
|
0x4a0e9e: mov eax, dword ptr [ebp + 0xc]
|
||||||
|
0x4a0ea1: mov dword ptr [ebp - 0x10], eax
|
||||||
|
0x4a0ea4: push edi
|
||||||
|
0x4a0ea5: mov edx, dword ptr [ebp - 0x10]
|
||||||
|
0x4a0ea8: push edx
|
||||||
|
0x4a0ea9: push ebx
|
||||||
|
0x4a0eaa: call 0x41bd60
|
||||||
|
0x4a0eaf: mov ecx, dword ptr [ebp - 0x10]
|
||||||
|
0x4a0eb2: add esp, 0xc
|
||||||
|
0x4a0eb5: lea edx, [ebx + 0x10c]
|
||||||
|
0x4a0ebb: mov dword ptr [ecx], 0x2c
|
||||||
|
0x4a0ec1: mov eax, dword ptr [ebp - 0x10]
|
||||||
|
0x4a0ec4: mov word ptr [eax + 4], 0
|
||||||
|
0x4a0eca: push edx
|
||||||
|
0x4a0ecb: call 0x40a138
|
||||||
|
0x4a0ed0: pop ecx
|
||||||
|
0x4a0ed1: lea ecx, [ebx + 0x10c]
|
||||||
|
0x4a0ed7: push ecx
|
||||||
|
0x4a0ed8: mov eax, dword ptr [ebp - 0x10]
|
||||||
|
0x4a0edb: add eax, 0x10
|
||||||
|
0x4a0ede: push eax
|
||||||
|
0x4a0edf: call 0x408f44
|
||||||
|
0x4a0ee4: add esp, 8
|
||||||
|
0x4a0ee7: lea eax, [ebx + 0x1d0]
|
||||||
|
0x4a0eed: mov edi, dword ptr [ebp - 0x10]
|
||||||
|
0x4a0ef0: add edi, 0x1c
|
||||||
|
0x4a0ef3: push eax
|
||||||
|
0x4a0ef4: push edi
|
||||||
|
0x4a0ef5: call 0x408440
|
||||||
|
0x4a0efa: add esp, 8
|
||||||
|
0x4a0efd: call 0x414b60
|
||||||
|
0x4a0f02: mov dword ptr [ebp - 0x14], eax
|
||||||
|
0x4a0f05: lea eax, [ebx + 0x778]
|
||||||
|
0x4a0f0b: mov edx, dword ptr [ebp - 0x14]
|
||||||
|
0x4a0f0e: mov ecx, dword ptr [edx]
|
||||||
|
0x4a0f10: mov dword ptr [eax], ecx
|
||||||
|
0x4a0f12: call 0x414b60
|
||||||
|
0x4a0f17: mov dword ptr [ebp - 0x18], eax
|
||||||
|
0x4a0f1a: lea eax, [ebx + 0x2e0]
|
||||||
|
0x4a0f20: mov edx, dword ptr [ebp - 0x18]
|
||||||
|
0x4a0f23: mov ecx, dword ptr [edx]
|
||||||
|
0x4a0f25: mov dword ptr [eax], ecx
|
||||||
|
0x4a0f27: lea eax, [ebx + 0x14]
|
||||||
|
0x4a0f2a: mov edx, dword ptr [ebx + 0x2e0]
|
||||||
|
0x4a0f30: mov ecx, dword ptr [eax]
|
||||||
|
0x4a0f32: sub edx, ecx
|
||||||
|
0x4a0f34: mov dword ptr [ebp - 0x68], edx
|
||||||
|
0x4a0f37: fild dword ptr [ebp - 0x68]
|
||||||
|
0x4a0f3a: fdiv dword ptr [0x52140c]
|
||||||
|
0x4a0f40: fstp dword ptr [ebp - 0x1c]
|
||||||
|
0x4a0f43: fld dword ptr [ebp - 0x1c]
|
||||||
|
0x4a0f46: fcomp dword ptr [0x4a1228]
|
||||||
|
0x4a0f4c: fnstsw ax
|
||||||
|
0x4a0f4e: sahf
|
||||||
|
0x4a0f4f: jae 0x4a0f62
|
||||||
|
0x4a0f51: mov edx, dword ptr [ebx + 0x2e0]
|
||||||
|
0x4a0f57: mov ecx, dword ptr [ebx + 0x14]
|
||||||
|
0x4a0f5a: sub edx, ecx
|
||||||
|
0x4a0f5c: add dword ptr [ebx + 0x2e0], edx
|
||||||
|
0x4a0f62: lea eax, [ebx + 0x10c]
|
||||||
|
0x4a0f68: push eax
|
||||||
|
0x4a0f69: lea edx, [ebx + 0x138]
|
||||||
|
0x4a0f6f: push edx
|
||||||
|
0x4a0f70: call 0x409968
|
||||||
|
0x4a0f75: add esp, 8
|
||||||
|
0x4a0f78: lea eax, [ebx + 0x1d0]
|
||||||
|
0x4a0f7e: lea edi, [ebx + 0x2d4]
|
||||||
|
0x4a0f84: push eax
|
||||||
|
0x4a0f85: push edi
|
||||||
|
0x4a0f86: call 0x408440
|
||||||
|
0x4a0f8b: add esp, 8
|
||||||
|
0x4a0f8e: mov eax, dword ptr [ebp - 0x10]
|
||||||
|
0x4a0f91: mov edx, dword ptr [esi + 0x128]
|
||||||
|
0x4a0f97: mov dword ptr [eax + 0x28], edx
|
||||||
|
0x4a0f9a: mov ecx, dword ptr [esi + 0x128]
|
||||||
|
0x4a0fa0: mov dword ptr [ebx + 0x6b4], ecx
|
||||||
|
0x4a0fa6: jmp 0x4a11d9
|
||||||
|
|
||||||
|
===== case 5 (subsystem alarm A) @0x4a0fab..0x4a104d =====
|
||||||
|
0x4a0fab: mov eax, dword ptr [ebp + 0xc]
|
||||||
|
0x4a0fae: mov dword ptr [ebp - 0x20], eax
|
||||||
|
0x4a0fb1: push edi
|
||||||
|
0x4a0fb2: mov edx, dword ptr [ebp - 0x20]
|
||||||
|
0x4a0fb5: push edx
|
||||||
|
0x4a0fb6: push ebx
|
||||||
|
0x4a0fb7: call 0x41bd60
|
||||||
|
0x4a0fbc: mov ecx, dword ptr [ebp - 0x20]
|
||||||
|
0x4a0fbf: add esp, 0xc
|
||||||
|
0x4a0fc2: mov dword ptr [ecx], 0x2c
|
||||||
|
0x4a0fc8: mov eax, dword ptr [ebp - 0x20]
|
||||||
|
0x4a0fcb: mov word ptr [eax + 4], 0
|
||||||
|
0x4a0fd1: mov edx, dword ptr [ebp - 0x20]
|
||||||
|
0x4a0fd4: mov ecx, dword ptr [ebx + 0x464]
|
||||||
|
0x4a0fda: mov dword ptr [edx + 0x10], ecx
|
||||||
|
0x4a0fdd: lea ecx, [ebx + 0x4a8]
|
||||||
|
0x4a0fe3: mov eax, dword ptr [ebp - 0x20]
|
||||||
|
0x4a0fe6: mov edx, dword ptr [ebx + 0x4a4]
|
||||||
|
0x4a0fec: mov dword ptr [eax + 0x14], edx
|
||||||
|
0x4a0fef: mov dword ptr [ebp - 0x24], ecx
|
||||||
|
0x4a0ff2: mov edi, dword ptr [ebp - 0x20]
|
||||||
|
0x4a0ff5: mov eax, dword ptr [ebp - 0x24]
|
||||||
|
0x4a0ff8: push eax
|
||||||
|
0x4a0ff9: add edi, 0x18
|
||||||
|
0x4a0ffc: push edi
|
||||||
|
0x4a0ffd: call 0x408440
|
||||||
|
0x4a1002: add esp, 8
|
||||||
|
0x4a1005: mov edx, dword ptr [ebp - 0x20]
|
||||||
|
0x4a1008: mov ecx, dword ptr [ebx + 0x4b4]
|
||||||
|
0x4a100e: mov dword ptr [edx + 0x24], ecx
|
||||||
|
0x4a1011: push 0x20
|
||||||
|
0x4a1013: push ebx
|
||||||
|
0x4a1014: call 0x4a800c
|
||||||
|
0x4a1019: add esp, 8
|
||||||
|
0x4a101c: push 0x4e0fd4 ; [0x4e0fd4]=0f
|
||||||
|
0x4a1021: lea eax, [ebx + 0x298]
|
||||||
|
0x4a1027: push eax
|
||||||
|
0x4a1028: call 0x40a7f4
|
||||||
|
0x4a102d: add esp, 8
|
||||||
|
0x4a1030: mov edx, dword ptr [ebp - 0x20]
|
||||||
|
0x4a1033: mov ecx, dword ptr [esi + 0x128]
|
||||||
|
0x4a1039: mov dword ptr [edx + 0x28], ecx
|
||||||
|
0x4a103c: mov eax, dword ptr [esi + 0x128]
|
||||||
|
0x4a1042: mov dword ptr [ebx + 0x6b4], eax
|
||||||
|
0x4a1048: jmp 0x4a11d9
|
||||||
|
|
||||||
|
===== case 6 (subsystem alarm B/death) @0x4a104d..0x4a10ff =====
|
||||||
|
0x4a104d: mov edx, dword ptr [ebp + 0xc]
|
||||||
|
0x4a1050: mov dword ptr [ebp - 0x28], edx
|
||||||
|
0x4a1053: push edi
|
||||||
|
0x4a1054: mov ecx, dword ptr [ebp - 0x28]
|
||||||
|
0x4a1057: push ecx
|
||||||
|
0x4a1058: push ebx
|
||||||
|
0x4a1059: call 0x41bd60
|
||||||
|
0x4a105e: mov eax, dword ptr [ebp - 0x28]
|
||||||
|
0x4a1061: add esp, 0xc
|
||||||
|
0x4a1064: mov dword ptr [eax], 0x2c
|
||||||
|
0x4a106a: mov edx, dword ptr [ebp - 0x28]
|
||||||
|
0x4a106d: mov word ptr [edx + 4], 0
|
||||||
|
0x4a1073: mov ecx, dword ptr [ebp - 0x28]
|
||||||
|
0x4a1076: mov eax, dword ptr [ebx + 0x464]
|
||||||
|
0x4a107c: mov dword ptr [ecx + 0x10], eax
|
||||||
|
0x4a107f: lea eax, [ebx + 0x4a8]
|
||||||
|
0x4a1085: mov edx, dword ptr [ebp - 0x28]
|
||||||
|
0x4a1088: mov ecx, dword ptr [ebx + 0x4a4]
|
||||||
|
0x4a108e: mov dword ptr [edx + 0x14], ecx
|
||||||
|
0x4a1091: mov dword ptr [ebp - 0x2c], eax
|
||||||
|
0x4a1094: mov edi, dword ptr [ebp - 0x28]
|
||||||
|
0x4a1097: mov eax, dword ptr [ebp - 0x2c]
|
||||||
|
0x4a109a: push eax
|
||||||
|
0x4a109b: add edi, 0x18
|
||||||
|
0x4a109e: push edi
|
||||||
|
0x4a109f: call 0x408440
|
||||||
|
0x4a10a4: mov edx, dword ptr [ebp - 0x28]
|
||||||
|
0x4a10a7: add esp, 8
|
||||||
|
0x4a10aa: mov ecx, dword ptr [ebx + 0x4b4]
|
||||||
|
0x4a10b0: lea eax, [ebx + 0x714]
|
||||||
|
0x4a10b6: mov dword ptr [edx + 0x24], ecx
|
||||||
|
0x4a10b9: push 0
|
||||||
|
0x4a10bb: push eax
|
||||||
|
0x4a10bc: call 0x41bbd8
|
||||||
|
0x4a10c1: add esp, 8
|
||||||
|
0x4a10c4: mov dword ptr [ebx + 0x658], 1
|
||||||
|
0x4a10ce: push 0x4e0fd4 ; [0x4e0fd4]=0f
|
||||||
|
0x4a10d3: lea edx, [ebx + 0x298]
|
||||||
|
0x4a10d9: push edx
|
||||||
|
0x4a10da: call 0x40a7f4
|
||||||
|
0x4a10df: add esp, 8
|
||||||
|
0x4a10e2: mov ecx, dword ptr [ebp - 0x28]
|
||||||
|
0x4a10e5: mov eax, dword ptr [esi + 0x128]
|
||||||
|
0x4a10eb: mov dword ptr [ecx + 0x28], eax
|
||||||
|
0x4a10ee: mov edx, dword ptr [esi + 0x128]
|
||||||
|
0x4a10f4: mov dword ptr [ebx + 0x6b4], edx
|
||||||
|
0x4a10fa: jmp 0x4a11d9
|
||||||
|
|
||||||
|
===== case 7 (subsystem alarm C) @0x4a10ff..0x4a117f =====
|
||||||
|
0x4a10ff: mov ecx, dword ptr [ebp + 0xc]
|
||||||
|
0x4a1102: mov dword ptr [ebp - 0x30], ecx
|
||||||
|
0x4a1105: push edi
|
||||||
|
0x4a1106: mov eax, dword ptr [ebp - 0x30]
|
||||||
|
0x4a1109: push eax
|
||||||
|
0x4a110a: push ebx
|
||||||
|
0x4a110b: call 0x41bd60
|
||||||
|
0x4a1110: mov edx, dword ptr [ebp - 0x30]
|
||||||
|
0x4a1113: add esp, 0xc
|
||||||
|
0x4a1116: mov dword ptr [edx], 0x2c
|
||||||
|
0x4a111c: mov ecx, dword ptr [ebp - 0x30]
|
||||||
|
0x4a111f: mov word ptr [ecx + 4], 0
|
||||||
|
0x4a1125: mov eax, dword ptr [ebp - 0x30]
|
||||||
|
0x4a1128: mov edx, dword ptr [ebx + 0x464]
|
||||||
|
0x4a112e: mov dword ptr [eax + 0x10], edx
|
||||||
|
0x4a1131: lea edx, [ebx + 0x4a8]
|
||||||
|
0x4a1137: mov ecx, dword ptr [ebp - 0x30]
|
||||||
|
0x4a113a: mov eax, dword ptr [ebx + 0x4a4]
|
||||||
|
0x4a1140: mov dword ptr [ecx + 0x14], eax
|
||||||
|
0x4a1143: mov dword ptr [ebp - 0x34], edx
|
||||||
|
0x4a1146: mov edi, dword ptr [ebp - 0x30]
|
||||||
|
0x4a1149: mov eax, dword ptr [ebp - 0x34]
|
||||||
|
0x4a114c: push eax
|
||||||
|
0x4a114d: add edi, 0x18
|
||||||
|
0x4a1150: push edi
|
||||||
|
0x4a1151: call 0x408440
|
||||||
|
0x4a1156: add esp, 8
|
||||||
|
0x4a1159: mov edx, dword ptr [ebp - 0x30]
|
||||||
|
0x4a115c: mov ecx, dword ptr [ebx + 0x4b4]
|
||||||
|
0x4a1162: mov dword ptr [edx + 0x24], ecx
|
||||||
|
0x4a1165: mov eax, dword ptr [ebp - 0x30]
|
||||||
|
0x4a1168: mov edx, dword ptr [esi + 0x128]
|
||||||
|
0x4a116e: mov dword ptr [eax + 0x28], edx
|
||||||
|
0x4a1171: mov ecx, dword ptr [esi + 0x128]
|
||||||
|
0x4a1177: mov dword ptr [ebx + 0x6b4], ecx
|
||||||
|
0x4a117d: jmp 0x4a11d9
|
||||||
|
|
||||||
|
===== case 8 (single scalar) @0x4a117f..0x4a11cb =====
|
||||||
|
0x4a117f: mov eax, dword ptr [ebp + 0xc]
|
||||||
|
0x4a1182: mov dword ptr [ebp - 0x38], eax
|
||||||
|
0x4a1185: push edi
|
||||||
|
0x4a1186: mov edx, dword ptr [ebp - 0x38]
|
||||||
|
0x4a1189: push edx
|
||||||
|
0x4a118a: push ebx
|
||||||
|
0x4a118b: call 0x41bd60
|
||||||
|
0x4a1190: add esp, 0xc
|
||||||
|
0x4a1193: mov ecx, dword ptr [ebp - 0x38]
|
||||||
|
0x4a1196: mov dword ptr [ecx], 0x18
|
||||||
|
0x4a119c: mov eax, dword ptr [ebp - 0x38]
|
||||||
|
0x4a119f: mov word ptr [eax + 4], 0
|
||||||
|
0x4a11a5: mov edx, dword ptr [ebp - 0x38]
|
||||||
|
0x4a11a8: mov ecx, dword ptr [ebx + 0x3f4]
|
||||||
|
0x4a11ae: mov dword ptr [edx + 0x10], ecx
|
||||||
|
0x4a11b1: mov eax, dword ptr [ebp - 0x38]
|
||||||
|
0x4a11b4: mov edx, dword ptr [esi + 0x128]
|
||||||
|
0x4a11ba: mov dword ptr [eax + 0x14], edx
|
||||||
|
0x4a11bd: mov ecx, dword ptr [esi + 0x128]
|
||||||
|
0x4a11c3: mov dword ptr [ebx + 0x6b4], ecx
|
||||||
|
0x4a11c9: jmp 0x4a11d9
|
||||||
|
|
||||||
|
===== case 1 + default + epilogue @0x4a11cb..0x4a1232 =====
|
||||||
|
0x4a11cb: push edi
|
||||||
|
0x4a11cc: mov eax, dword ptr [ebp + 0xc]
|
||||||
|
0x4a11cf: push eax
|
||||||
|
0x4a11d0: push ebx
|
||||||
|
0x4a11d1: call 0x4225a4
|
||||||
|
0x4a11d6: add esp, 0xc
|
||||||
|
0x4a11d9: mov eax, dword ptr [ebx + 0x3c]
|
||||||
|
0x4a11dc: mov edx, dword ptr [ebx + 0x40]
|
||||||
|
0x4a11df: cmp eax, edx
|
||||||
|
0x4a11e1: je 0x4a121e
|
||||||
|
0x4a11e3: cmp eax, 2
|
||||||
|
0x4a11e6: jne 0x4a121e
|
||||||
|
0x4a11e8: mov esi, ebx
|
||||||
|
0x4a11ea: push esi
|
||||||
|
0x4a11eb: lea eax, [ebp - 0x64]
|
||||||
|
0x4a11ee: push eax
|
||||||
|
0x4a11ef: call 0x436668
|
||||||
|
0x4a11f4: add esp, 8
|
||||||
|
0x4a11f7: lea edx, [ebp - 0x64]
|
||||||
|
0x4a11fa: push edx
|
||||||
|
0x4a11fb: push esi
|
||||||
|
0x4a11fc: mov ecx, dword ptr [0x4efc94] ; [0x4efc94]=0f
|
||||||
|
0x4a1202: mov eax, dword ptr [ecx + 0x38]
|
||||||
|
0x4a1205: push eax
|
||||||
|
0x4a1206: call 0x4364e4
|
||||||
|
0x4a120b: add esp, 0xc
|
||||||
|
0x4a120e: mov eax, dword ptr [ebx + 0x40]
|
||||||
|
0x4a1211: push eax
|
||||||
|
0x4a1212: add ebx, 0x2c
|
||||||
|
0x4a1215: push ebx
|
||||||
|
0x4a1216: call 0x41bbd8
|
||||||
|
0x4a121b: add esp, 8
|
||||||
|
0x4a121e: pop edi
|
||||||
|
0x4a121f: pop esi
|
||||||
|
0x4a1220: pop ebx
|
||||||
|
0x4a1221: mov esp, ebp
|
||||||
|
0x4a1223: pop ebp
|
||||||
|
0x4a1224: ret
|
||||||
|
0x4a1225: add byte ptr [eax], al
|
||||||
|
0x4a1227: add byte ptr [eax], al
|
||||||
|
0x4a1229: add byte ptr [eax], ah
|
||||||
|
0x4a122b: inc ecx
|
||||||
|
0x4a122c: push ebp
|
||||||
|
0x4a122d: mov ebp, esp
|
||||||
|
0x4a122f: add esp, -0x34
|
||||||
Reference in New Issue
Block a user