diff --git a/game/reconstructed/mech.cpp b/game/reconstructed/mech.cpp index aca1cbb..3a5c33a 100644 --- a/game/reconstructed/mech.cpp +++ b/game/reconstructed/mech.cpp @@ -399,14 +399,52 @@ Derivation Receiver::MessageHandlerSet Mech::MessageHandlers(Entity::GetMessageHandlers()); -Mech::AttributeIndexSet - Mech::AttributeIndex; +// +// Mech attribute table. DENSE PREFIX 0x15..0x21 (JointedMover::NextAttributeID +// through LinearSpeed): the built index is a dense array and Find strcmps every +// slot, so the table must be contiguous from the parent's NextAttributeID up to +// the highest id published -- no gaps. The ids the BLH cockpit does not consume +// (collision/eyepoint/reticle/footstep/anim state) bind to the shared read-only +// attrPad so the slot is a valid, named, non-crashing entry; CurrentSpeed and +// MaxRunSpeed bind to the existing gait members; LinearSpeed binds to the live +// forward-speed member the speed gauges read. (Ids 0x22..0x38 remain declared in +// the enum for later extension -- e.g. RadarRange/DuckState when the map/duck +// widgets are reconstructed -- but are NOT published yet.) +// +const Mech::IndexEntry + Mech::AttributePointers[]= +{ + ATTRIBUTE_ENTRY(Mech, MaxAcceleration, attrPad), // 0x15 + ATTRIBUTE_ENTRY(Mech, CollisionState, attrPad), // 0x16 + ATTRIBUTE_ENTRY(Mech, CollisionNormal, attrPad), // 0x17 + ATTRIBUTE_ENTRY(Mech, CollisionSpeed, attrPad), // 0x18 + ATTRIBUTE_ENTRY(Mech, CollisionMaterialType, attrPad), // 0x19 + ATTRIBUTE_ENTRY(Mech, CurrentSpeed, legCycleSpeed), // 0x1a (existing @0x348) + ATTRIBUTE_ENTRY(Mech, MaxRunSpeed, reverseStrideLength), // 0x1b (existing @0x34c = run/top speed) + ATTRIBUTE_ENTRY(Mech, EyepointRotation, attrPad), // 0x1c + ATTRIBUTE_ENTRY(Mech, TargetReticle, attrPad), // 0x1d + ATTRIBUTE_ENTRY(Mech, FootStep, attrPad), // 0x1e + ATTRIBUTE_ENTRY(Mech, AnimationState, attrPad), // 0x1f + ATTRIBUTE_ENTRY(Mech, ReplicantAnimationState, attrPad), // 0x20 + ATTRIBUTE_ENTRY(Mech, LinearSpeed, linearSpeed) // 0x21 (live forward speed) +}; + +Mech::AttributeIndexSet& + Mech::GetAttributeIndex() +{ + static Mech::AttributeIndexSet attributeIndex( + ELEMENTS(Mech::AttributePointers), + Mech::AttributePointers, + JointedMover::GetAttributeIndex() + ); + return attributeIndex; +} Mech::SharedData Mech::DefaultData( // @0050bde4 &Mech::ClassDerivations, Mech::MessageHandlers, - Mech::AttributeIndex, + Mech::GetAttributeIndex(), Mech::StateCount, (Entity::MakeHandler)Mech::Make // Entity__SharedData adds the make-callback ); @@ -532,6 +570,8 @@ Mech::Mech( hudSubsystem = 0; // this[0x16d] (0xBD6 -> HUD; was misnamed mechTechSubsystem) forwardThrottleScale = 1.0f; // @0x5c0 mapper speed scale (writer not in decomp; neutral) sensorSubsystem = 0; // this[0x1f7] (0xBBE) -- same hazard, zero it too + attrPad = 0.0f; // shared read pad for un-populated gauge attributes + linearSpeed = 0.0f; // live forward ground speed (LinearSpeed gauge); set per frame ZeroBlock(this + 0xca, 6); // this[0xca..0xcf] = 0 ZeroBlock(this + 0x153, 6); // this[0x153..0x158] = 0 diff --git a/game/reconstructed/mech.hpp b/game/reconstructed/mech.hpp index 22cdfc7..273a21c 100644 --- a/game/reconstructed/mech.hpp +++ b/game/reconstructed/mech.hpp @@ -503,9 +503,72 @@ protected: // public: static Receiver::MessageHandlerSet MessageHandlers; // SharedData ctor operand - static AttributeIndexSet AttributeIndex; // SharedData ctor operand enum { StateCount = 0x21 }; + // + // Attribute Support -- the named attributes the cockpit gauges bind to. + // The config (content/GAUGE/L4GAUGE.CFG) binds the bare names LinearSpeed / + // MaxRunSpeed / DuckState / RadarRange / RadarLinearPosition / + // RadarAngularPosition, resolved by Simulation::GetAttributePointer -> + // activeAttributeIndex->Find(name). The reconstruction shipped an EMPTY, + // unchained Mech::AttributeIndex, so EVERY bare Mech gauge (and even the + // inherited attributes) resolved to NullAttribute. + // + // The full binary id set (0x15..0x38, table VA 0x50be84) is declared so the + // published table can be extended without renumbering. The chain starts at + // JointedMover::NextAttributeID (0x15); ids MUST stay contiguous, because the + // built index is a dense array sized to max(id) and AttributeIndexSet::Find + // strcmps EVERY slot -- an unfilled slot holds a garbage entryName -> AV. + // + enum { + MaxAccelerationAttributeID = JointedMover::NextAttributeID, // 0x15 + CollisionStateAttributeID, // 0x16 + CollisionNormalAttributeID, // 0x17 + CollisionSpeedAttributeID, // 0x18 + CollisionMaterialTypeAttributeID, // 0x19 + CurrentSpeedAttributeID, // 0x1a + MaxRunSpeedAttributeID, // 0x1b + EyepointRotationAttributeID, // 0x1c + TargetReticleAttributeID, // 0x1d + FootStepAttributeID, // 0x1e + AnimationStateAttributeID, // 0x1f + ReplicantAnimationStateAttributeID, // 0x20 + LinearSpeedAttributeID, // 0x21 + ClimbRateAttributeID, // 0x22 + AccelerationLastFrameAttributeID, // 0x23 + AngularSpeedAttributeID, // 0x24 + ArmorDamageLevelAttributeID, // 0x25 + SubsystemDamageLevelAttributeID, // 0x26 + MyomerDamageLevelAttributeID, // 0x27 + TestButton1AttributeID, // 0x28 + TestButton2AttributeID, // 0x29 + TestButton3AttributeID, // 0x2a + TestButton4AttributeID, // 0x2b + TestButton5AttributeID, // 0x2c + TestButton6AttributeID, // 0x2d + ReduceButtonAttributeID, // 0x2e + RadarRangeAttributeID, // 0x2f + RadarLinearPositionAttributeID, // 0x30 + RadarAngularPositionAttributeID, // 0x31 + RearFiringAttributeID, // 0x32 + RequestDuckAnimationAttributeID, // 0x33 + UnstablePercentageAttributeID, // 0x34 + SuperStopAttributeID, // 0x35 + IncomingLockAttributeID, // 0x36 + DuckStateAttributeID, // 0x37 + DistanceToMissileAttributeID, // 0x38 + NextAttributeID // 0x39 + }; + static const IndexEntry AttributePointers[]; + static AttributeIndexSet& GetAttributeIndex(); + + // Cockpit-gauge attribute backing members (APPENDED to Mech's own region -- + // never at a locked base/gait offset). attrPad is a shared read-only 0 for + // the dense-prefix ids the BLH cockpit does not bind; linearSpeed is the live + // forward ground speed the speed readout / arc / radar consume (binary @0x81c). + Scalar attrPad; + Scalar linearSpeed; + // --- raw / engine-shim members touched by the ctor slice ------------- void *vtable; // installed Mech vtable ptr Word instanceFlags; // entity instance flags (this+0x18 region) diff --git a/game/reconstructed/mech4.cpp b/game/reconstructed/mech4.cpp index fbf50ad..fafe0a5 100644 --- a/game/reconstructed/mech4.cpp +++ b/game/reconstructed/mech4.cpp @@ -1290,6 +1290,7 @@ void // leg channel keeps running as the local sim it is in the binary // (its joint writes land first and are overwritten by the body's). const Scalar localAdv = adv * dir; + linearSpeed = (localAdv < 0.0f ? -localAdv : localAdv) * invDt; // forward ground speed -> LinearSpeed gauge Vector3D localVel(0.0f, 0.0f, -localAdv * invDt); // exact frame distance as velocity Matrix34 orient; // rotation from the heading (set @ line ~626) Matrix34::FromQuaternion(&orient, &localOrigin.angularPosition); @@ -1348,6 +1349,7 @@ void : ((throttle < 0.0f) ? -1.0f : 1.0f); localOrigin.linearPosition.x += fx * adv * dir; localOrigin.linearPosition.z += fz * adv * dir; + linearSpeed = (dt > 0.0f) ? ((adv < 0.0f ? -adv : adv) / dt) : 0.0f; // LinearSpeed gauge localToWorld = localOrigin; // rebuild with the new position gBodyAnimLog += dt;