From dc6af8cef65298aa441494fa66dce8e49196a1fb Mon Sep 17 00:00:00 2001 From: arcattack Date: Tue, 7 Jul 2026 07:45:57 -0500 Subject: [PATCH] vehicleSubSystems: reconstruct the stubbed connection helpers from decomp Replace the return-0 stubs with the real functions: - ResolveLink (FUN_00417ab4) = SubsystemConnection::Resolve (two-level deref of the plug's bound link); an unbound plug resolves to 0, the authentic no-source branch. - FindLinkedSubsystem (FUN_0041bf44) = GetAttributePointer(index) via the engine Simulation attribute-index system (the cooling-loop master at slot 3). - IsGeneratorDerived (FUN_0041a1a4) = the real IsDerivedFrom(PoweredSubsystem ClassDerivations 0x50f4bc) via a new powersub.cpp bridge BTIsPoweredSubsystem (shared with the aux-screen filter) -> the generator stateLamp now builds. So the cooling/power/voltage connections resolve real data when the plug is bound, instead of always reading 0. Build clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- game/reconstructed/btl4gau2.cpp | 51 ++++++++++++++++++++++----------- game/reconstructed/powersub.cpp | 11 +++++-- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/game/reconstructed/btl4gau2.cpp b/game/reconstructed/btl4gau2.cpp index e0dfa07..64db794 100644 --- a/game/reconstructed/btl4gau2.cpp +++ b/game/reconstructed/btl4gau2.cpp @@ -124,13 +124,21 @@ static void *AttributePointerOf(void *subsystem, const char *name) } // -// FUN_00417ab4 -- follow a SharedData/plug link to the resolved subsystem (voltage -// source / cooling master). The reconstruction stubs this everywhere (see -// emitter.cpp) because the roster plug-binding pass is not yet reconstructed; -// matched here so the cluster connections read the safe "no source" branch -// (*destination = 0) until the plug binding lands. BEST-EFFORT (marked). +// FUN_00417ab4 -- SubsystemConnection::Resolve: follow the plug's bound link to the +// resolved subsystem. The link is `*(plug+8)`; the resolved subsystem is +// `*(link+8)`. An unbound plug (link == 0) resolves to 0 -- the authentic +// behaviour when a subsystem has no attached voltage source / cooling master (the +// connection then reads its "no source" branch, *destination = 0). // -static void *ResolveLink(void *plug) { (void)plug; return 0; } +static void *ResolveLink(void *plug) +{ + if (plug == 0) + return 0; + void *link = *(void **)((char *)plug + 8); + if (link == 0) + return 0; + return *(void **)((char *)link + 8); +} // // Bridge (defined in powersub.cpp) that reads the engineering-screen assignment @@ -143,20 +151,31 @@ static void *ResolveLink(void *plug) { (void)plug; return 0; } extern bool BTGetSubsystemAuxScreen(Subsystem *sub, int *screen, int *placement, char *label64); // -// FUN_0041bf44 -- fetch the subsystem linked at slot N (used by the cooling-loop -// lamp to find its cooling master). Stubbed to match ResolveLink above. +// FUN_0041bf44 -- GetAttributePointer(index): a pointer to the subsystem's Nth +// attribute member (the cooling-loop lamp reaches its cooling-master link at +// attribute slot 3), or 0 if the index is out of range. The engine exposes this +// via Simulation::GetAttributePointer(AttributeID); a miss returns &NullAttribute, +// normalised to 0. // -static void *FindLinkedSubsystem(void *subsystem, int slot) { (void)subsystem; (void)slot; return 0; } +static void *FindLinkedSubsystem(void *subsystem, int slot) +{ + if (subsystem == 0) + return 0; + void *p = ((Simulation *)subsystem)->GetAttributePointer((Simulation::AttributeID)slot); + if (p == (void *)&Simulation::NullAttribute) + return 0; + return p; +} // -// FUN_0041a1a4 IsDerivedFrom(0x50f4bc == Generator's ClassDerivations). Gates the -// SubsystemCluster's generator stateLamp. BEST-EFFORT: the Generator -// ClassDerivations object is owned by the (separately-reconstructed) gnrator TU -// which must not be pulled into this gauge TU (stub-collision, see btl4gaug.hpp), -// so the check is stubbed to False -- the generator-only stateLamp is simply not -// built. Lands with a shared IsDerivedFrom accessor. +// FUN_0041a1a4 IsDerivedFrom(0x50f4bc == PoweredSubsystem's ClassDerivations). +// Gates the SubsystemCluster's generator stateLamp. Every subsystem that reaches +// a SubsystemCluster passed the vehicleSubSystems type filter (BTGetSubsystemAuxScreen +// -> the SAME IsDerivedFrom(PoweredSubsystem) check), so this is always True here; +// the real check is done in powersub.cpp via BTIsPoweredSubsystem for robustness. // -static Logical IsGeneratorDerived(Subsystem *) { return False; } +extern bool BTIsPoweredSubsystem(Subsystem *sub); +static Logical IsGeneratorDerived(Subsystem *sub) { return BTIsPoweredSubsystem(sub) ? True : False; } //########################################################################### diff --git a/game/reconstructed/powersub.cpp b/game/reconstructed/powersub.cpp index e42b391..a6e607f 100644 --- a/game/reconstructed/powersub.cpp +++ b/game/reconstructed/powersub.cpp @@ -1269,11 +1269,16 @@ Subsystem *CreatePoweredSubsystem(Mech *owner, int id, void *seg) // non-PoweredSubsystem-derived subsystems (== the FUN_0041a1a4 / 0x50f4bc type // filter the vehicleSubSystems Make applies before dispatch). // +// FUN_0041a1a4(sub->classDerivations, 0x50f4bc) -- is the subsystem PoweredSubsystem- +// derived? (The vehicleSubSystems type filter + the generator stateLamp gate.) +bool BTIsPoweredSubsystem(Subsystem *sub) +{ + return sub != NULL && sub->IsDerivedFrom(*PoweredSubsystem::GetClassDerivations()); +} + bool BTGetSubsystemAuxScreen(Subsystem *sub, int *screen, int *placement, char *label64) { - if (sub == NULL) - return false; - if (!sub->IsDerivedFrom(*PoweredSubsystem::GetClassDerivations())) // FUN_0041a1a4(...,0x50f4bc) + if (!BTIsPoweredSubsystem(sub)) // FUN_0041a1a4(...,0x50f4bc) return false; PoweredSubsystem *ps = (PoweredSubsystem *)sub; if (screen != NULL) *screen = ps->auxScreenNumber; // +0x104