//===========================================================================// // File: thermalsight.hpp // // Project: BattleTech // // Contents: ThermalSight (thermal / infra-red vision mode) subsystem // //---------------------------------------------------------------------------// // Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved // // PROPRIETARY AND CONFIDENTIAL // //===========================================================================// // // RECONSTRUCTED from the shipped binary (Ghidra pseudo-C, recovered shard // part_013.c). NO THERMALSIGHT.HPP survived; the class body is inferred from // usage and the embedded string pool. Each method cites its @ADDR. // // IDENTIFICATION: // * mech3.cpp factory map: ThermalSight::CreateStreamedSubsystem @004b87d4, // DefaultData &DAT_00511228. // * vtable @00511498 (slot0 dtor @004b8794), ctor @004b8718. // * CreateStreamedSubsystem @004b87d4 stamps classID 0x0BDE and streamed // model size 0xF4; it parses NO thermal-specific model fields. // * String pool @00511474 ("ThermalSight", "LightOn", "LightState"). // ClassDerivations name "ThermalSight" @00511238. // * Its per-frame update toggles the GLOBAL "pvision" (pixel/thermal vision) // render flag via FUN_0045fe44 (which prints "pvision ON"/"pvision OFF", // strings @004f2f9d/@004f2fa8) -- confirming this is the cockpit IR/thermal // view-mode subsystem rather than a world light. // // BASE CLASS: // ThermalSight IS-A PowerWatcher (powersub.hpp): ctor @004b8718 chains to the // PowerWatcher ctor FUN_004b18a4 with &DAT_00511228, and // CreateStreamedSubsystem chains to PowerWatcher::CreateStreamedSubsystem // FUN_004b198c. Shared base 0..0x1D8; own members begin at 0x1D8. Exposes // one queryable attribute "LightState". Unlike Searchlight it does NOT // override the network-replication slots (6/7) -- it inherits the base. // #if !defined(THERMALSIGHT_HPP) # define THERMALSIGHT_HPP #if !defined(POWERSUB_HPP) #include "powersub.hpp" #endif //########################################################################## //##################### Local multi-level alarm shim ################# //########################################################################## // // CROSS-FAMILY: heat.hpp does `typedef GaugeAlarm AlarmIndicator;` but the // engine GaugeAlarm (GAUGALRM.h) has a PROTECTED ctor/dtor and no // Initialize/Finalize/SetLevel; the mech.hpp/mechrecon.hpp alias resolves // AlarmIndicator to ReconAlarm, which also lacks Initialize/Finalize. Until // the heat family provides a real multi-level AlarmIndicator, this module owns // a tiny faithful stand-in for ITS OWN alarm member (it does NOT redefine the // AlarmIndicator typedef). // #if !defined(BT_LOCAL_ALARM_SHIM) # define BT_LOCAL_ALARM_SHIM struct BtAlarm { int level; BtAlarm() : level(0) {} void Initialize(int /*levels*/) { level = 0; } // FUN_0041b9ec void Finalize() {} // FUN_0041baa4 void SetLevel(int n) { level = n; } // FUN_0041bbd8 int GetLevel() const { return level; } }; #endif //########################################################################## //#################### ThermalSight::SubsystemResource ############### //########################################################################## // // Empty extension of the PowerWatcher resource (CreateStreamedSubsystem // @004b87d4 reads no thermal-specific fields). // struct ThermalSight__SubsystemResource: public PowerWatcher::SubsystemResource { }; //########################################################################## //######################### ThermalSight ############################# //########################################################################## class ThermalSight: public PowerWatcher { friend struct ThermalSightLayoutCheck; // compile-time offset locks (thermalsight.cpp) //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Shared Data Support // // DefaultData @00511228, ClassDerivations @00511238 ("ThermalSight"). // public: static Derivation ClassDerivations; // @00511238 static SharedData DefaultData; // @00511228 static Receiver::MessageHandlerSet MessageHandlers; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Attribute Support // // AttributePointers IndexEntry table @00511270: // id 4 "LightState" -> @0x1D8 (offset encoded 0x1D9 == 0x1D8|1) // public: enum { LightStateAttributeID = PowerWatcher::NextAttributeID, // 4 NextAttributeID }; private: static const IndexEntry AttributePointers[]; // @00511270 protected: static AttributeIndexSet& GetAttributeIndex(); // @00511270 table (task #16) //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Local data. // protected: int thermalActive; // @0x1D8 reported IR mode on/off (gated by power + heat); "LightState" int requestedOn; // @0x1DC init 0; on/off input consumed by ThermalSightSimulation BtAlarm stateAlarm; // @0x1E0 2-level indicator (size 0x54) //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BT segment / base-state compatibility shims (CROSS-FAMILY). // // Logically belong on the shared bases (Subsystem::GetSegmentFlags, // PowerWatcher::HostShutDown / WatchedVoltageLevel, HeatSink::HeatStateLevel) // plus the cockpit view-mode hooks (the locally-viewed-mech viewport and the // global "pvision" thermal toggle, FUN_0045fe44). Backed locally so this // module compiles; see report. // public: // De-shimmed (WAVE 4 un-stub): the 5 CROSS-FAMILY backing fields // (segmentFlags/hostShutDown/watchedVoltageLevel/heatStateLevel/ // localViewport) + struct BtViewport are DELETED. They duplicated // engine-base state AND -- via the old shadow `segmentFlags` (seeded 0) -- // made the ctor gate ((0&0xC)==0 && (0&0x100)!=0) FALSE, so // ThermalSightSimulation was NEVER installed. Accessors now read the REAL // inherited base members (mirrors torso.hpp / searchlight.hpp): // HostShutDown <- MechSubsystem::simulationState == Destroyed (this+0x40) // WatchedVoltageLevel <- PowerWatcher::watchdogAlarm level (this+0x198) // HeatStateLevel <- HeatWatcher::heatAlarm level (this+0x140) // The cockpit IR view-mode RENDER hooks have no ported target and stay // clearly-marked no-ops for bring-up (thermalActive/stateAlarm are still // computed faithfully): // IsLocallyViewed() -- was localViewport->viewingThisMech (L4 viewport // global PTR_DAT_004fd4b8+0x48); no ported accessor. // ToggleGlobalThermalVision() -- was FUN_0045fe44 (global "pvision" // palette flip); the D3D9 renderer has no pvision. Logical HostShutDown() const { return simulationState == 1; /* Destroyed */ } int WatchedVoltageLevel() const { return watchdogAlarm.GetLevel(); } // @0x198 int HeatStateLevel() const { return heatAlarm.GetLevel(); } // @0x140 Logical IsLocallyViewed() const { return False; } // bring-up no-op (see above) void ToggleGlobalThermalVision() {} // bring-up no-op (pvision unported) //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Simulation Support // public: typedef void (ThermalSight::*Performance)(Scalar time_slice); void SetPerformance(Performance performance) { Check(this); activePerformance = (Simulation::Performance)performance; } void ThermalSightSimulation(Scalar time_slice); // @004b8648 (Performance, PTR @00511290) //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Test Class Support // public: static Logical TestClass(Mech&); Logical TestInstance() const; // @004b881c //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Construction and Destruction // // vtable @00511498 differs from the PowerWatcher base only in slot0 (dtor) // and the inherited PowerWatcher slots 9/10 (@004b179c / @004b1804); no // further virtual overrides. // public: typedef ThermalSight__SubsystemResource SubsystemResource; ThermalSight( Mech *owner, int subsystem_ID, SubsystemResource *subsystem_resource, SharedData &shared_data = DefaultData ); // @004b8718 ~ThermalSight(); // @004b8794 static int CreateStreamedSubsystem( // @004b87d4 NotationFile *model_file, const char *model_name, const char *subsystem_name, SubsystemResource *subsystem_resource, NotationFile *subsystem_file, const ResourceDirectories *directories, int passes = 1 ); }; #endif