Files
BT412/game/reconstructed/mechrecon.hpp
T
arcattackandClaude Opus 4.8 7b7d465e5e Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.

Layout:
  engine/   MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
            work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
            models) + image codec; the minimal rp/ headers the audio HAL needs
  game/     reconstructed BT logic + surviving-original BT source + fwd shims
            + WinMain launcher
  content/  full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
  docs/     format specs + reconstruction ledgers
  reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
  tools/    MP console emulator + map/resource scanners

One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 21:03:40 -05:00

587 lines
27 KiB
C++

//===========================================================================//
// File: mechrecon.hpp //
// Project: BattleTech Brick: Entity Manager //
// Contents: Reconstruction support shim for the "mech core" family //
// (mech / mech2..4 / mechsub / mechdmg / dmgtable). //
//---------------------------------------------------------------------------//
// This header is NOT part of the shipped game. It supplies the small set of //
// reconstruction helpers, decompiler-artifact globals and proxy stand-in //
// types that the recovered mech-core bodies reference but the modern engine //
// headers do not provide under those exact names. It exists only so the //
// reconstructed translation units COMPILE against the WinTesla engine; the //
// proxies preserve the call structure of the recovered code (no logic is //
// deleted). Behaviour-equivalent semantics are filled where trivial. //
// //
// MUST be included AFTER <bt.hpp> / the engine headers (so Scalar, Quaternion //
// Vector3D, AffineMatrix, CString, Subsystem ... are already declared). //
//===========================================================================//
#if !defined(MECHRECON_HPP)
# define MECHRECON_HPP
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <math.h>
// Quaternion / Vector3D / AffineMatrix used below (kIdentityQuat etc.). Include
// directly so mechrecon.hpp is self-sufficient regardless of the includer's order
// (myomers.cpp pulls this via mechsub.hpp BEFORE bt.hpp). ROTATION.hpp DEFINES
// Quaternion (affnmtrx.hpp only forward-declares it).
#include <ROTATION.hpp>
#include <affnmtrx.hpp>
//===========================================================================//
// Universal decompiler-artifact value.
//
// Stands in for the result of an unresolved FUN_/helper artifact. Converts
// to any scalar, pointer or default-constructible type so the recovered
// expression typechecks.
//===========================================================================//
struct Recon
{
Recon() {}
template<class T> Recon(const T &) {}
template<class T> operator T() const { return T(); }
};
//===========================================================================//
// Memory shim -- the decomp's "Memory::Allocate / Memory::Free" map onto the
// engine's per-object MemoryBlock allocators; for the offline reconstruction a
// plain heap allocation is behaviour-equivalent.
//===========================================================================//
namespace Memory
{
inline void *Allocate(size_t bytes) { return ::operator new(bytes); }
inline void *AllocateArray(size_t bytes){ return ::operator new(bytes); }
inline void Free(void *where) { ::operator delete(where); }
}
inline void *Alloc(size_t bytes) { return ::operator new(bytes); }
inline void *AllocateArray(size_t bytes){ return ::operator new(bytes); }
//===========================================================================//
// Ref-count / name helpers (decomp artifacts).
//===========================================================================//
template<class A> inline void *NewRefCount(A) { return 0; }
inline void *NewRefCounted() { return 0; }
template<class A,class B> inline void BindName(A, B) {}
template<class A,class B,class C> inline void BindName(A, B, C) {}
template<class A> inline void ReleaseRefCounted(A) {}
template<class A> inline void ZeroBlock(A, int) {}
template<class A,class B> inline void Assign(A, B) {}
template<class A> inline Recon NewTableEntry(A) { return Recon(); }
//===========================================================================//
// Small dynamic string used by the resource-table builders
// ( TextString("Layer") + itoa(n) ).
//===========================================================================//
struct TextString
{
char buf[64];
TextString() { buf[0] = 0; }
TextString(const char *s) { buf[0] = 0; if (s) { strncpy(buf, s, 63); buf[63] = 0; } }
TextString &operator+=(const char *s) { if (s) strncat(buf, s, 63 - strlen(buf)); return *this; }
TextString operator+ (const char *s) const { TextString t(*this); t += s; return t; }
operator const char *() const { return buf; }
};
//===========================================================================//
// Misc free-function artifacts (variadic -> Recon).
//===========================================================================//
template<class...A> inline Recon WorldTransform(A&&...) { return Recon(); }
template<class...A> inline Recon ResourceFind(A&&...) { return Recon(); }
template<class...A> inline Recon LoadSkeleton(A&&...) { return Recon(); }
template<class...A> inline int ResourceManagerHas(A&&...) { return 0; }
template<class...A> inline void GenerateFaultDefault(A&&...) {}
// NOTE: renamed from Random() to avoid colliding with the engine's
// `extern RandomGenerator Random;` (RANDOM.h). Reconstructed code that wants the
// original zero-arg unit-random (FUN_00408050 -> Scalar in [0,1)) uses RandomUnit().
// Backed by the engine RNG: `RandomGenerator::operator Scalar()` returns a value
// in [0,1) (RANDOM.h), exactly matching FUN_00408050's contract. Variadic tail
// kept so call sites (dmgtable: roll; theta*TwoPi) bind unchanged; Scalar return
// satisfies the dmgtable Scalar consumers.
#include <RANDOM.hpp> // fwd/ -> engine RANDOM.h: extern RandomGenerator Random;
template<class...A> inline Scalar RandomUnit(A&&...) { return (Scalar)Random; }
//===========================================================================//
// String helpers (decomp inlined strcpy/strcat/stricmp etc.).
//===========================================================================//
inline void Strcpy(char *d, const char *s) { while ((*d++ = *s++) != 0) {} }
inline void Strcat(char *d, const char *s) { while (*d) ++d; while ((*d++ = *s++) != 0) {} }
inline int Strcmp(const char *a, const char *b) { return strcmp(a, b); }
// Env gate with a DEFAULT: the authentic reconstructed paths (gait cutover/state
// machine, collision+gravity, real controls) are ON by default; set the var to
// "0" to fall back to the historical bring-up path (e.g. BT_GAIT_SM=0).
inline int BTEnvOn(const char *name, int on_by_default)
{
const char *v = getenv(name);
return v ? (v[0] != '0') : on_by_default;
}
// THE AUTHENTIC GROUND MODEL gate (task #15 -- the 1995 probe/snap/response
// ground block, ground-model-decode workflow). ONE function so the Mech ctor
// (template lift, mech.cpp), the per-frame ground block and the ProcessCollision
// override (mech4.cpp) can never disagree: every TU reads the same env exactly
// once. DEFAULT ON (verification passed: grass/arena/dbase census + anti-ladder
// soak + slope tracking + render-side screenshots + combat & heapcheck
// regressions -- see the task-#15 ground commit). BT_GROUND_REAL=0 falls back
// to the bring-up gravity+push-out+clamp baseline.
inline int GroundReal()
{
static const int v = BTEnvOn("BT_GROUND_REAL", 1);
return v;
}
inline int GroundLog()
{
static const int v = getenv("BT_GROUND_LOG") ? 1 : 0;
return v;
}
inline int Streq (const char *a, const char *b) { return strcmp(a, b) == 0; }
//===========================================================================//
// Multi-level status/alarm indicator.
//
// The recovered code names this AlarmIndicator and drives it with a level
// count ctor + SetLevel(level). In the WinTesla engine the equivalent is
// StateIndicator (SetState / GetState). We provide a thin proxy that exposes
// BOTH spellings so the recovered call sites compile unchanged.
//===========================================================================//
struct ReconAlarm
{
unsigned level;
ReconAlarm() : level(0) {}
ReconAlarm(int n) : level(0) { (void)n; }
ReconAlarm(unsigned n) : level(0) { (void)n; }
ReconAlarm &operator=(const ReconAlarm &) { return *this; }
void SetLevel(int n) { level = (unsigned)n; }
void SetState(unsigned n){ level = n; }
unsigned GetLevel() const { return level; }
unsigned GetState() const { return level; }
int GetLevelCount() const { return 0; }
};
//===========================================================================//
// Filtered (running-average) scalar -- decomp uses Initialize(n, value).
//===========================================================================//
struct ReconFiltered
{
ReconFiltered() {}
template<class...A> void Initialize(A&&...) {}
template<class...A> void Add(A&&...) {}
Scalar Value() const { return Scalar(0); }
// static-style accumulator verbs: FilteredScalar::Push(filter, sample) etc.
template<class...A> static void Push(A&&...) {}
template<class...A> static Scalar Sum(A&&...) { return Scalar(0); }
template<class...A> static Scalar Average(A&&...) { return Scalar(0); }
};
typedef unsigned int uint;
//===========================================================================//
// Universal word-cell proxy + word accessor.
//
// The recovered mech-core bodies address the object as an int[] and assign
// raw words by index ( this[0xNN] = ... ). Pointer-subscripting `this`
// cannot be made an assignable scalar lvalue, so each `this[0xNN]` is
// rewritten to Wword(0xNN), which hands back a distinct, universally
// assignable/convertible cell (one per word index). This preserves the
// per-offset write structure of the decomp while compiling against the
// modern engine; the cell is behaviour-neutral storage for the offline
// reconstruction (it is NOT aliased onto the real member at that offset).
//===========================================================================//
struct BTVal
{
Scalar max, min, field8; // named sub-fields used by the decomp
BTVal() : max(0), min(0), field8(0) {}
template<class T> BTVal(const T &) : max(0), min(0), field8(0) {}
BTVal &operator=(const BTVal &) { return *this; } // real copy-assign
template<class T> BTVal &operator=(const T &) { return *this; }
template<class T> operator T() const { return T(); }
// member-call passthrough (this[]-proxy + pose-member verbs)
template<class...A> BTVal &Construct(A&&...) { return *this; }
template<class...A> BTVal &LinkTo(A&&...) { return *this; }
template<class...A> BTVal &SetIdentity(A&&...) { return *this; }
template<class...A> BTVal &Mul(A&&...) { return *this; }
template<class...A> BTVal &Copy(A&&...) { return *this; }
// arithmetic kept closed over BTVal (avoids operator T() ambiguity)
friend BTVal operator+(const BTVal &, const BTVal &) { return BTVal(); }
friend BTVal operator-(const BTVal &, const BTVal &) { return BTVal(); }
BTVal &operator+=(const BTVal &) { return *this; }
template<class T> BTVal &operator+=(const T &) { return *this; }
// comparisons (exact-match friends beat the templated operator T())
friend bool operator==(const BTVal &, const BTVal &) { return false; }
friend bool operator!=(const BTVal &, const BTVal &) { return false; }
friend bool operator==(const BTVal &, int) { return false; }
friend bool operator!=(const BTVal &, int) { return false; }
friend bool operator==(int, const BTVal &) { return false; }
friend bool operator!=(int, const BTVal &) { return false; }
};
inline BTVal &Wword(int i) { static BTVal bank[0x400]; return bank[i & 0x3ff]; }
static Vector3D ZeroVector; // neutral zero vector (decomp ZeroVector datum)
//===========================================================================//
// Affine-matrix proxy -- adds the SetRotation / FromRotation / FromQuaternion
// spellings the decomp uses (the engine AffineMatrix expresses these through
// operator= / dedicated helpers).
//===========================================================================//
struct ReconMatrix
{
AffineMatrix m;
ReconMatrix() {}
template<class T> ReconMatrix &operator=(const T &) { return *this; }
template<class...A> void FromRotation(A&&...) {}
// P3 GAIT CUTOVER: backed by the real engine AffineMatrix (was no-op stubs, so
// IntegrateMotion's world-step committed nothing). Identity == BuildIdentity;
// FromQuaternion/SetRotation == AffineMatrix::operator=(const Quaternion&) (the
// engine's build-rotation-from-quaternion). Signatures match every call site
// (mech4.cpp IntegrateMotion + Simulate).
static void SetRotation(ReconMatrix *dst, const Quaternion *q) { dst->m = *q; }
static void FromQuaternion(ReconMatrix *dst, const Quaternion *q) { dst->m = *q; }
static void Identity(ReconMatrix *dst) { dst->m.BuildIdentity(); }
operator AffineMatrix &() { return m; }
};
//===========================================================================//
// SequenceController -- the BT-specific keyframe animation player embedded in the
// Mech as legAnimation (@0x65c) / bodyAnimation (@0x6bc). RECONSTRUCTED from the
// binary (part_003.c: ctor @00427768, SelectSequence @004277a8, Advance @0042790c,
// Reset @004283b8). NOT in the RP411 engine. Plays a gait clip: walks keyframes,
// interpolates each joint's rotation, writes it through the engine Joint API
// (same as gyro/torso), and returns the root-translation distance advanced.
// Modelled as a plain struct (accessed only by name; no Plug base needed). The
// keyframeCount/keyframeTimes/keyframeData accessors are preserved for mech3's
// LoadLocomotionClips/MeasureClipStride; full spec in btbuild/P3_LOCOMOTION.md.
//===========================================================================//
class Mech; // owner (forward decl -- mechrecon.hpp precedes the Mech class)
struct SequenceController
{
// rootTranslation entry (binary 0xC/frame); ".stride" == the .z the gait reads.
struct Keyframe { Scalar x, y, stride; };
// --- clip data parsed by SelectSequence (keyframe accessors read by mech3) ---
int keyframeCount; // frameCount (binary +0x14)
int jointCount; // animated joints (binary +0x18)
int *jointIndices; // keyframe->skeleton map (binary +0x1c)
Scalar *keyframeTimes; // frameTimes[frameCount] (binary +0x24)
void *keyframeBase; // keyframe pose data base (binary +0x28)
void *keyframeCursor; // current pose cursor (binary +0x2c)
Keyframe *keyframeData; // rootTranslations[] (binary +0x34)
// --- runtime state / links ---
int currentFrame; // (binary +0x3c)
Scalar currentTime; // clip playback time (binary +0x54)
void *jointSubsystem; // resolved owner joint subsystem (binary +0x38)
Mech *owner; // (binary +0x40)
void *clipResource; // locked clip resource handle (binary +0x44)
void *cbCode; // finished-callback code ptr (binary +0x48)
unsigned cbArg2, cbArg3; // finished-callback context words (binary +0x4c/0x50)
SequenceController()
: keyframeCount(0), jointCount(0), jointIndices(0), keyframeTimes(0),
keyframeBase(0), keyframeCursor(0), keyframeData(0), currentFrame(0),
currentTime(0.0f), jointSubsystem(0), owner(0), clipResource(0),
cbCode(0), cbArg2(0), cbArg3(0) {}
void Init(Mech *owner_mech); // @00427768 (ctor logic)
void SelectSequence(int clip_id, void *cb, unsigned a2, unsigned a3); // @004277a8
Scalar Advance(Scalar time_slice, int move_joints); // @0042790c
void Reset(int loop); // @004283b8
~SequenceController(); // @004278d4 (release clip)
};
typedef SequenceController ReconSeq;
//===========================================================================//
// Controls motion source -- the controls subsystem the Mech reads its live
// commanded ground speed from (this[0x128] -> +0x128).
//===========================================================================//
struct ReconMotionSource
{
Scalar commandedSpeed; // +0x128
};
// Gait-state name table ( <AnimationNames> + state*0x3c ); display data only.
static char AnimationNames[0x1e * 0x3c] = { 0 };
//===========================================================================//
// MechSubsystem-coupled damage zone view.
//
// The recovered MechSubsystem code addresses its DamageZone through a small
// set of fields (structure level, per-facing armour, structure reference and
// the zone's own alarm) that are reconstruction names rather than the modern
// engine DamageZone member spellings; this proxy carries them so the bodies
// compile. damageZone is stored through it.
//===========================================================================//
struct ReconDamageZone
{
Scalar structureLevel;
Scalar structureReference;
Scalar armour[5];
ReconAlarm alarm;
};
//===========================================================================//
// Subsystem proxy + critical-subsystem chain (DistributeCriticalHit support).
//===========================================================================//
struct ReconSub
{
template<class...A> Recon GetName(A&&...) { return Recon(); }
template<class...A> void TakeDamage(A&&...) {}
};
struct CriticalEntry
{
ReconSub *sub;
ReconSub *Subsystem() { return sub; }
};
struct CriticalChain
{
template<class A> CriticalChain(A) {}
int CountOfType(int) { return 1; }
CriticalEntry *First() { return 0; }
CriticalEntry *Next() { return 0; }
};
//===========================================================================//
// Callable returned by the "base vtable slot 0x18" thunk: (*BaseSlot0x18())(...)
//===========================================================================//
struct ReconCallable
{
template<class...A> Recon operator()(A&&...) { return Recon(); }
};
inline ReconCallable *BaseSlot0x18() { static ReconCallable c; return &c; }
//===========================================================================//
// Resource-table proxies (dmgtable).
//
// The recovered damage-table classes drive their entry pools through a small
// verb set (Init / Insert / Lookup / count) and a forward iterator
// (First / Next / Current) that differ from the modern TableOf/TableIterator
// API, so the table members are declared with these proxies instead.
//===========================================================================//
template<class T> struct ReconTable
{
int count;
ReconTable() : count(0) {}
void Init() { count = 0; }
template<class...A> void Insert(A&&...) {}
template<class...A> void *Lookup(A&&...) const { return 0; }
};
struct ReconTableIter
{
template<class A> ReconTableIter(const A &) {}
void *First() { return 0; }
void *Next() { return 0; }
void *Current() { return 0; }
};
//===========================================================================//
// Generic object stream + notation-line + skeleton proxies (dmgtable parsers).
//===========================================================================//
struct GenericObjectStream
{
template<class...A> void Read(A&&...) {}
template<class...A> void Write(A&&...) {}
};
struct NotationLine
{
NotationLine *Next() { return 0; }
const char *Format() { return ""; }
const char *Value() { return ""; }
int Count() { return 0; }
template<class...A> void Parse(A&&...) {}
};
struct Skeleton
{
int SegmentCount() { return 1; }
};
template<class...A> inline NotationLine *ReconGetPage(A&&...) { static NotationLine l; return &l; }
template<class...A> inline Recon ReconDir(A&&...) { return Recon(); }
template<class A,class B> inline int ReconSegIndex(A, B) { return 0; }
//===========================================================================//
// Vector math namespace artifact ( Vector::Add / AddScaled / Scale / Dot ... ).
// (The decomp emits free vector ops under a "Vector" qualifier; the engine uses
// Vector3D member ops. Behaviour-neutral stand-ins for the reconstruction.)
//===========================================================================//
namespace Vector
{
template<class...A> inline void Add(A&&...) {}
template<class...A> inline void AddScaled(A&&...) {}
template<class...A> inline void Scale(A&&...) {}
template<class...A> inline void Copy(A&&...) {}
template<class...A> inline void Subtract(A&&...) {}
template<class...A> inline Scalar Dot(A&&...) { return Scalar(0); }
template<class...A> inline Scalar Sum(A&&...) { return Scalar(0); }
}
//
// Quaternion free-function artifacts (the decomp writes these as
// Quaternion::Identity(dst,&id) / Quaternion::IntegrateInto(...) -- calling the
// engine's static const Identity datum as a function; routed to free shims).
//
// P3 GAIT CUTOVER: backed by the real engine Quaternion (were no-op stubs).
// ReconQuatIdentity(q, &id) -> q = Quaternion::Identity
// ReconQuatIntegrate(out,in,d) -> out = in integrated by angular delta d
// (engine Quaternion::Add(source, Vector3D) == FUN_00409f58)
// All callers pass (Quaternion*,Quaternion*) / (Quaternion*,Quaternion*,Vector3D*).
inline void ReconQuatIdentity(Quaternion *q, const Quaternion * /*id*/) { *q = Quaternion::Identity; }
inline void ReconQuatIntegrate(Quaternion *out, const Quaternion *in, const Vector3D *delta) { out->Add(*in, *delta); }
template<class...A> inline Recon ReconQuatSlerp(A&&...) { return Recon(); }
template<class...A> inline Recon ComputeImpactDamage(A&&...) { return Recon(); }
//
// Raw FUN_ helper artifacts referenced in code (vector/matrix/transform glue).
//
template<class...A> inline Recon FUN_00408644(A&&...) { return Recon(); }
// FUN_00408744 (part_000.c:8331) -- rotate a 3-vector by a matrix's 3x3 rotation:
// out[i] = v[0]*M(i,0) + v[1]*M(i,1) + v[2]*M(i,2) (row i . v).
// Backed by the engine AffineMatrix column basis: GetFromAxis(j) returns the "from"
// axis = column j = (M(0,j),M(1,j),M(2,j)), so out = v.x*colX + v.y*colY + v.z*colZ
// reproduces the raw row-dot formula EXACTLY (out[i] = sum_j v[j]*M(i,j)). This is
// IntegrateMotion's world-step: worldVelocity = bodyOrientation * localVelocity. The
// same GetFromAxis convention the drive facing uses (mech4.cpp), so it is sign-consistent.
inline Vector3D *FUN_00408744(Vector3D *out, const Scalar *v, ReconMatrix *m)
{
Vector3D colX, colY, colZ;
m->m.GetFromAxis(X_Axis, &colX);
m->m.GetFromAxis(Y_Axis, &colY);
m->m.GetFromAxis(Z_Axis, &colZ);
out->x = v[0]*colX.x + v[1]*colY.x + v[2]*colZ.x;
out->y = v[0]*colX.y + v[1]*colY.y + v[2]*colZ.y;
out->z = v[0]*colX.z + v[1]*colY.z + v[2]*colZ.z;
return out;
}
template<class...A> inline Recon FUN_00408848(A&&...) { return Recon(); }
template<class...A> inline Recon FUN_00433ed4(A&&...) { return Recon(); }
template<class...A> inline Recon FUN_0040e5f0(A&&...) { return Recon(); }
template<class...A> inline Recon FUN_0040e36c(A&&...) { return Recon(); }
template<class...A> inline Recon FUN_00406ff8(A&&...) { return Recon(); }
// Free vector op + pose/notify artifacts used unqualified in mech4.
template<class...A> inline Scalar Dot(A&&...) { return Scalar(0); }
template<class...A> inline Recon Build(A&&...) { return Recon(); }
template<class...A> inline void ReconBeginPose(A&&...) {}
template<class...A> inline void ReconEndPose(A&&...) {}
template<class...A> inline int ReconIsDerived(A&&...) { return 0; }
//
// Damage notification message (DamageMessage msg; DamageMessage::Build(&msg,...)).
//
struct DamageMessage
{
template<class...A> static void Build(A&&...) {}
};
// Geometry / pose constants.
static Quaternion kIdentityQuat;
static Vector3D kZeroVector;
static Scalar _DAT_004ac048 = 0;
static Scalar _DAT_004ab9c8 = 0;
static Scalar _DAT_004ab9d0 = 0;
static Scalar _DAT_004ab9d4 = 0;
static Recon vtable_0050bb90;
//===========================================================================//
// Subsystem-roster chain proxy.
//
// The Mech keeps several ChainOf<Subsystem*> capability views. The engine
// ChainOf has no default ctor / SetOwner / Construct / iterate-in-place verbs
// that the recovered ctor uses, so the roster members are declared with this
// proxy instead.
//===========================================================================//
template<class T> struct ReconChain
{
ReconChain() {}
ReconChain(void *) {}
template<class...A> void SetOwner(A&&...) {}
template<class...A> void Construct(A&&...) {}
template<class...A> void Reset(A&&...) {}
void Add(T) {}
T First() { return T(); }
T Next() { return T(); }
};
//===========================================================================//
// Debug-stream artifact ( DebugStream << x << endl; ).
//===========================================================================//
struct ReconStream
{
template<class T> ReconStream &operator<<(const T &) { return *this; }
void Flush() {}
void Emit() {}
};
//===========================================================================//
// Resolve-able connection slot proxy (e.g. the power-bus / death-effect slot).
//===========================================================================//
struct ReconSlot
{
template<class...A> Recon Resolve(A&&...) { return Recon(); }
template<class...A> void LinkTo(A&&...) {}
template<class...A> void Construct(A&&...){}
};
static ReconStream DebugStream;
static int endl = 0;
//===========================================================================//
// Type aliases consumed by the recovered headers. Defining the guard here
// suppresses the (now superseded) in-header alias blocks.
//===========================================================================//
#if !defined(BT_RECON_TYPE_ALIASES)
# define BT_RECON_TYPE_ALIASES
typedef ReconMatrix Matrix34; // orientation matrix proxy
typedef ReconAlarm AlarmIndicator; // multi-level status indicator
typedef ReconFiltered FilteredScalar; // running-average scalar
#endif
//===========================================================================//
// Decompiler-artifact globals actually referenced by mech-core code.
// * .data pointers used in address arithmetic -> char*
// * scalar tuning constants -> Scalar
// * opaque label/vtable/handle operands -> Recon
//===========================================================================//
static char *DAT_004efc94 = 0; // TheApp base (App*)
static Scalar DAT_005209d0 = 0; // FLT_MAX seed
static Scalar DAT_0052140c = 1; // runtime frame time scale (divisor)
static char DAT_004e0f8c[1] = { 0 }; // "" empty string literal
static Scalar _DAT_004ab9cc = 0;
//===========================================================================//
// Shared empty handler / attribute sets used to satisfy the 4-arg
// Simulation::SharedData ctor for the reconstructed DefaultData objects (the
// shipped game passes each class's own generated sets; an empty shared set is
// structurally correct for the offline reconstruction).
//===========================================================================//
static Receiver::MessageHandlerSet ReconMessageHandlers;
static Simulation::AttributeIndexSet ReconAttributeIndex;
static Recon PTR_FUN_0050cfa8; // Mech vtable
static Recon PTR_LAB_0050c0e8; // copy Performance
static Recon PTR_LAB_0050c0f4; // master Performance
// Animation SelectSequence operand triples (label + 2 floats per gait clip).
static Recon PTR_LAB_0050d6f0, DAT_0050d6f4, DAT_0050d6f8;
static Recon PTR_LAB_0050d6fc, DAT_0050d700, DAT_0050d704;
static Recon PTR_LAB_0050d708, DAT_0050d70c, DAT_0050d710;
static Recon PTR_LAB_0050d714, DAT_0050d718, DAT_0050d71c;
static Recon PTR_LAB_0050d720, DAT_0050d724, DAT_0050d728;
static Recon PTR_LAB_0050d72c, DAT_0050d730, DAT_0050d734;
static Recon PTR_LAB_0050d738, DAT_0050d73c, DAT_0050d740;
static Recon PTR_LAB_0050d744, DAT_0050d748, DAT_0050d74c;
#endif // MECHRECON_HPP