Files
BT412/game/reconstructed/btl4app.cpp
T
arcattackandClaude Opus 4.8 a256813395 gauges: secondary/radar MFD composites live on a dev box (Milestone B)
The pod's secondary/radar cockpit surface now renders as an inset in the
800x600 dev window under BT_DEV_GAUGES: radar/tactical grid, SPEED/HEADING/
MAGNETIC/PROP dials, and the color-coded ARMOR DAMAGE mech schematic -- real
gauge content (nzSec=27247), composited from the shared CPU pixelBuffer.

Composite pass (engine): SVGA16::DrawDevInset palette-expands the secondary
plane into a MANAGED texture on the MAIN device and draws an XYZRHW inset quad;
BTDrawGaugeInset() reaches the gauge renderer's 'sec' port and is called from
DPLRenderer::ExecuteImplementation as the last draw before EndScene.

Three reconstruction bugs fixed to get real content:
1. BTL4Application::MakeGaugeRenderer signature mismatch (REAL fix): the
   reconstructed no-arg override only HID the 2007-engine's widened 3-arg
   virtual MakeGaugeRenderer(int*,int*,int*), so the engine built a base
   L4GaugeRenderer whose ctor never parsed gauge/l4gauge.cfg -> empty symbol
   table -> "undefined label 'bhk1Init'" -> no ports/gauges. Matched the 3-arg
   signature so it truly overrides (args ignored; BT is fullscreen). Same bug
   class as the BTL4GaugeRenderer(false,NULL,NULL,NULL) ctor fix.
2. Parse hung on undefined primitives (gated dev accommodation): the BT gauge
   primitive table (BTL4MethodDescription) is still a stub, so an unknown
   primitive -> ReportParsingError -> Fail() -> a MODAL dialog freezing the
   parse. Under BT_DEV_GAUGES, skip the unknown primitive's params so labels
   register and the base "configure" primitive builds the ports.
3. Gauge widgets AV on NULL data bindings (gated): NumericDisplayScalar's NULL
   value_pointer -> GaugeConnectionDirectOf ctor deref (bind NULL->static zero);
   RankAndScore::Execute derefs unreconstructed game state (Gauge::GuardedExecute
   SEH wrapper -> Disable(True) on first fault).

All guards gated on BT_DEV_GAUGES: default DEV un-regressed (TARGET DESTROYED,
0 crashes) and the pod path is byte-unchanged (strict Fail, no guards).

Remaining (docs/GAUGE_COMPOSITE.md): the real gauge WIDGET reconstruction
(BTL4MethodDescription method table + gauge->game-state data bindings), then
Step 2 (RP<->BT MFD port-name reconcile) + Step 3 (2-window layout).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 10:59:45 -05:00

707 lines
26 KiB
C++

//===========================================================================//
// File: btl4app.cpp //
// Project: BattleTech Brick: BattleTech LBE Application //
// Contents: BTL4Application -- the top-level LBE-mode application object. //
// Builds the registry, renderers, mode/controls managers, the //
// mission, and the player's viewpoint entity; drives the run / //
// stop mission state. //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved //
// PROPRIETARY AND CONFIDENTIAL //
//===========================================================================//
//
// RECONSTRUCTED from the shipped binary (BTL4OPT.EXE). The class declaration
// is taken VERBATIM from the surviving header BTL4APP.HPP; the method bodies
// are recovered from the Ghidra pseudo-C for the 0x4d34xx-0x4d3axx cluster
// (see all/part_014.c) and cross-checked against Red Planet's direct analog
// RP_L4\RPL4APP.cpp and the MUNGA base MUNGA\APP.cpp.
//
// The 12 functions of this object file map 1:1 onto the 12 methods declared
// in BTL4APP.HPP, in source (compiler-emission) order:
//
// @004d34c4 BTL4Application::BTL4Application (constructor)
// @004d350c BTL4Application::~BTL4Application (scalar-deleting dtor)
// @004d3538 BTL4Application::MakeRegistry
// @004d3564 BTL4Application::MakeVideoRenderer
// @004d35b0 BTL4Application::MakeAudioRenderer
// @004d3614 BTL4Application::MakeModeManager
// @004d3644 BTL4Application::MakeControlsManager
// @004d368c BTL4Application::MakeGaugeRenderer
// @004d36c4 BTL4Application::MakeMission
// @004d36f4 BTL4Application::MakeViewpointEntity (anchor; 822 bytes)
// @004d3a2c BTL4Application::RunMissionMessageHandler
// @004d3a94 BTL4Application::StopMissionMessageHandler
//
// Helper / engine-internal name mapping used below (FUN_ -> intent):
// FUN_0047b410 L4Application::L4Application (base ctor)
// FUN_0047b624 L4Application::~L4Application (base dtor)
// FUN_0047b788 L4Application::RunMissionMessageHandler (base)
// FUN_0047b864 L4Application::StopMissionMessageHandler (base)
// FUN_00402298 operator new / Mem_Alloc(size)
// FUN_004022d0 operator delete / Mem_Free(p)
// FUN_004c1548 BTRegistry::BTRegistry (0x10 bytes)
// FUN_004ceecc BTL4VideoRenderer::BTL4VideoRenderer (0x3e0 bytes)
// FUN_004d2b6c BTL4AudioRenderer::BTL4AudioRenderer (0x1b0 bytes)
// FUN_0044c2d0 ModeManager init helper (BTL4ModeManager, 0xc bytes)
// FUN_00475c18 L4ControlsManager::L4ControlsManager (0xd10 bytes)
// FUN_004cbea0 BTL4GaugeRenderer::BTL4GaugeRenderer (0x1c53c bytes)
// FUN_004d2be0 BTL4Mission::BTL4Mission (0xfc bytes)
// FUN_004dee74 getenv()
// FUN_0044e19c GetSampleRate() (reads division-params float @+0x10)
// FUN_0042d16c CameraShip::Make
// FUN_004a2d48 Mech::Make
// FUN_00476eac ControlsManager::SetJoystickDeadBand
// FUN_00476eec ControlsManager::SetThrottleDeadBand
// FUN_00476f10 ControlsManager::SetPedalsDeadBand
// FUN_0047ac5c CameraThrustmasterMapper::CameraThrustmasterMapper
// FUN_0047ad3c CameraRIOMapper::CameraRIOMapper
// FUN_0047aa78 CameraL4Mapper::CameraL4Mapper
// FUN_0042c630 CameraShip::SetMappingSubsystem
// FUN_004d21d0 MechThrustmasterMapper::MechThrustmasterMapper
// FUN_004d266c MechRIOMapper::MechRIOMapper
// FUN_00402460 (controls-mapper resource ctor / Str_Copy "ControlsMapper")
// FUN_0049fe40 Mech::SetMappingSubsystem
// FUN_00407064 ResourceFile::SearchList(id, type)
// FUN_004070dc ResourceFile::SearchList(id, name)
// FUN_00406cd0 ResourceDescription::Lock
// FUN_0047703c ControlsManager::CreateStreamedMappings
// FUN_0046ff64 GaugeRenderer::ConfigureForModel(name, entity)
// FUN_004dbb24 DEBUG_STREAM << (msg) FUN_004d9c38 << flush
// (the two together == the Tell()/Msg() macro)
// FUN_0040385c Fail(msg, file, line)
// DAT_004efc94 the global application pointer
// DAT_00524e20 the debug message stream
//
// L4Application base member offsets observed in the decomp:
// this+0x3c controls manager (GetControlsManager)
// this+0x4c gauge renderer (GetGaugeRenderer)
// this+0x50 mode manager (GetModeManager)
// this+0x68 resource file (GetResourceFile)
// this+0xd0 division-params present flag (cf. RP "divisionParameters")
// controlsManager+0xc98 primaryControlType (2==ThrustMaster, 4==RIO)
// modeManager+0x4 current mode mask modeManager+0x8 saved mode mask
//
#include <bt.hpp>
#pragma hdrstop
#if !defined(BTL4APP_HPP)
# include <btl4app.hpp>
#endif
#if !defined(BTL4VID_HPP)
# include <btl4vid.hpp>
#endif
#if !defined(BTL4ARND_HPP)
# include <btl4arnd.hpp>
#endif
#if !defined(BTL4GRND_HPP)
# include <btl4grnd.hpp>
#endif
#if !defined(BTL4MSSN_HPP)
# include <btl4mssn.hpp>
#endif
#if !defined(BTL4MODE_HPP)
# include <btl4mode.hpp>
#endif
#if !defined(BTL4MPPR_HPP)
# include <btl4mppr.hpp>
#endif
#if !defined(BTREG_HPP)
# include <btreg.hpp>
#endif
#if !defined(L4CTRL_HPP)
# include <l4ctrl.hpp> // LBE4ControlsManager
#endif
#if !defined(CAMSHIP_HPP)
# include <camship.hpp> // CameraShip
#endif
#if !defined(CAMMPPR_HPP)
# include <cammppr.hpp> // CameraControlsMapper
#endif
#if !defined(L4MPPR_HPP)
# include <l4mppr.hpp> // Camera{Thrustmaster,RIO,L4}Mapper
#endif
//
// Audio sound-card environment variables (both must be present for the
// audio renderer to be built). Observed at @004d35b0 as the live form of
// the front/rear-card check that RPL4Application left commented out.
//
#define AWE_FRONT_ENV_VAR "AWE_FRONT" // s_AWE_FRONT_0051ec1e
#define AWE_REAR_ENV_VAR "AWE_REAR" // s_AWE_REAR_0051ec28
//#############################################################################
// Message Support
//
const Receiver::HandlerEntry
BTL4Application::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(BTL4Application, RunMission),
MESSAGE_ENTRY(BTL4Application, StopMission)
};
BTL4Application::MessageHandlerSet
BTL4Application::MessageHandlers(
ELEMENTS(BTL4Application::MessageHandlerEntries),
BTL4Application::MessageHandlerEntries,
L4Application::GetMessageHandlers() // WinTesla: GetMessageHandlers() replaces the static MessageHandlers
);
//#############################################################################
// Shared Data Support
//
Derivation
BTL4Application::ClassDerivations(
L4Application::GetClassDerivations(), // WinTesla: GetClassDerivations() (returns Derivation*)
"BTL4Application"
);
BTL4Application::SharedData
BTL4Application::DefaultData(
&BTL4Application::ClassDerivations, // SharedData(Derivation*, MessageHandlerSet&)
BTL4Application::MessageHandlers
);
//
//#############################################################################
// BTL4Application @004d34c4
//#############################################################################
//
BTL4Application::BTL4Application(
HINSTANCE hInstance,
HWND hWnd,
ResourceFile *resource_file,
ClassID class_ID,
SharedData &shared_data
):
//
// Base call FUN_0047b410(this, resource_file, 1, class_ID, shared_data).
// The literal "1" is the L4 game identifier (BTL4) -- the analog of
// RPL4Application passing the RPL4 enum to L4Application. The WinTesla
// L4Application ctor additionally takes (hInstance, hWnd) up front
// (cf. RPL4Application::RPL4Application).
//
L4Application(hInstance, hWnd, resource_file, BTL4, class_ID, shared_data)
{
// vtable installed by the compiler == &PTR_FUN_0051ed9c
Tell("BTL4Application::BTL4Application\n"); // FUN_004dbb24/004d9c38
}
//
//#############################################################################
// ~BTL4Application @004d350c
//#############################################################################
//
BTL4Application::~BTL4Application()
{
// FUN_004d350c is the compiler-generated scalar-deleting destructor;
// the body is empty -- it merely reinstalls the vtable and chains to
// ~L4Application (FUN_0047b624).
}
//
//#############################################################################
// MakeRegistry @004d3538
//#############################################################################
//
Registry*
BTL4Application::MakeRegistry()
{
Check(this);
return new BTRegistry(GetResourceFile()); // FUN_00402298(0x10) -> FUN_004c1548
}
//
//#############################################################################
// MakeVideoRenderer @004d3564
//#############################################################################
//
VideoRenderer*
BTL4Application::MakeVideoRenderer()
{
//
// Only build the renderer when the division parameters are present
// (this+0xd0 != 0), exactly as RPL4Application gates on
// "divisionParameters".
//
// The DOS-era "division parameters present" flag (this+0xd0) is the
// WinTesla public char* L4Application::divisionParameters. The
// reconstructed BTL4VideoRenderer ctor (btl4vid.hpp) takes the standard
// Renderer calibration tuple (rate, complexity, priority) followed by
// the interest type/depth; it derives the window + screen geometry from
// the L4Application statics internally.
//
if (divisionParameters)
{
return
new BTL4VideoRenderer(
DefaultRendererRate, // calibration rate
MaxRendererComplexity, // calibration complexity
DefaultRendererPriority, // calibration priority
VisualInterestType, // DAT_004e8238
DefaultInterestDepth // DAT_004e823c
);
}
return NULL;
}
//
//#############################################################################
// MakeAudioRenderer @004d35b0
//#############################################################################
//
AudioRenderer*
BTL4Application::MakeAudioRenderer()
{
//
// Both AWE sound-card environment variables must be present. This is
// the live form of the front/rear-card test RPL4Application left
// commented out (blaster1/blaster2).
//
char *front_card = getenv(AWE_FRONT_ENV_VAR); // FUN_004dee74
char *rear_card = getenv(AWE_REAR_ENV_VAR);
if (front_card == NULL || rear_card == NULL)
{
return NULL;
}
//
// FUN_0044e19c read the sample rate as a float out of the division
// parameter block (@+0x10). In WinTesla that block is the public
// L4Application::divisionParameters char*; fall back to 1000.0f (the
// RP default) when it is absent. Second arg is the mission-review
// flag (the 1995 binary hard-coded it off; DAT_004fd550 == 0).
//
RendererRate sample_rate =
divisionParameters
? (RendererRate)*reinterpret_cast<float*>(divisionParameters + 0x10)
: (RendererRate)1000.0f;
return
new BTL4AudioRenderer(
sample_rate,
False
);
}
//
//#############################################################################
// MakeModeManager @004d3614
//#############################################################################
//
ModeManager*
BTL4Application::MakeModeManager()
{
// FUN_00402298(0xc) -> FUN_0044c2d0(p, 0x50421)
BTL4ModeManager
*manager = new BTL4ModeManager(BTL4ModeManager::ModeInitial);
Check(manager);
return manager;
}
//
//#############################################################################
// MakeControlsManager @004d3644
//#############################################################################
//
ControlsManager*
BTL4Application::MakeControlsManager()
{
// FUN_00402298(0xd10) -> FUN_00475c18(p)
// WinTesla renamed the DOS L4ControlsManager to LBE4ControlsManager.
LBE4ControlsManager
*manager = new LBE4ControlsManager;
Check(manager);
//
// Register this application as the controls owner / key-command
// handler. The DOS decomp showed a virtual call
// (manager+0x68)->vtbl[+0x14](-1, this, 7, this) -- "mode mask = all,
// receiver = this, message = KeyCommand (7), handler = this". In
// WinTesla that is the keyboard-group Add() the base
// L4Application::MakeControlsManager performs.
//
manager->keyboardGroup[LBE4ControlsManager::KeyboardPC].Add(
ModeManager::ModeAlwaysActive,
this,
KeyCommandMessageID,
this
);
return manager;
}
//
//#############################################################################
// MakeGaugeRenderer @004d368c
//#############################################################################
//
GaugeRenderer*
BTL4Application::MakeGaugeRenderer(int *secondaryIndex, int *aux1Index, int *aux2Index)
{
//
// Only build the gauge renderer when the L4GAUGE environment variable
// is set -- matches RPL4Application's getenv("L4GAUGE") gate.
//
// SIGNATURE NOTE: the shipped BT override (@004d368c) took no arguments,
// but the 2007 WinTesla engine WIDENED the base virtual to
// Application::MakeGaugeRenderer(int* secondaryIndex, int* aux1, int* aux2)
// (the secondary/aux surface indices for windowed mode) and calls THAT
// 3-arg virtual from Application::Initialize (APP.cpp:382). A no-arg
// method here only HIDES the virtual -- it never overrides it -- so the
// engine's L4Application::MakeGaugeRenderer ran instead and built a BASE
// L4GaugeRenderer (which never parses gauge\l4gauge.cfg -> empty symbol
// table -> "undefined label 'bhk1Init'" -> no ports). Matching the 3-arg
// signature makes this the real override. BT is fullscreen with no
// secondary/aux gauge indices, so the args are ignored (the
// BTL4GaugeRenderer ctor hardcodes windowed=false / NULL indices).
//
(void)secondaryIndex; (void)aux1Index; (void)aux2Index;
if (getenv("L4GAUGE") == NULL) // FUN_004dee74
{
return NULL;
}
return new BTL4GaugeRenderer; // FUN_00402298(0x1c53c) -> FUN_004cbea0
}
//
//#############################################################################
// MakeMission @004d36c4
//#############################################################################
//
Mission*
BTL4Application::MakeMission(
NotationFile *notation_file,
ResourceFile *resources
)
{
// FUN_00402298(0xfc) -> FUN_004d2be0(p, notation_file, resources)
return new BTL4Mission(notation_file, resources);
}
//
//#############################################################################
// MakeViewpointEntity @004d36f4
//#############################################################################
//
// Anchor function (822 bytes). Creates the viewpoint entity for the local
// player and wires up its controls mapper + gauges. Structurally identical
// to RPL4Application::MakeViewpointEntity, except the second case creates a
// Mech (class 0xbb9) instead of a VTV.
//
Entity*
BTL4Application::MakeViewpointEntity(Entity::MakeMessage *message)
{
Check(this);
// WinTesla: GetControlsManager() yields the LBE4ControlsManager
// (the renamed DOS L4ControlsManager); the deadband / primary-control
// accessors live on it, not on the ControlsManager base.
LBE4ControlsManager
*controls = (LBE4ControlsManager*)GetControlsManager(); // *(this+0x3c)
Entity
*viewing_entity = NULL;
char
*primary_mapping_name = NULL;
switch (message->classToCreate) // *(message+0x1c)
{
case CameraShipClassID: // 0x45
//===============================================================
// Create Camera ship
//===============================================================
{
CameraShip
*viewing_camera =
CameraShip::Make((CameraShip::MakeMessage*)message);
Check(viewing_camera);
viewing_entity = viewing_camera;
//------------------------------------------------------------
// Create the controls-mapping subsystem resource
//------------------------------------------------------------
CameraControlsMapper::SubsystemResource
control_subsystem_resource;
Str_Copy(
control_subsystem_resource.subsystemName,
"ControlsMapper",
sizeof(control_subsystem_resource.subsystemName)
);
control_subsystem_resource.classID = TrivialSubsystemClassID; // 0xf
control_subsystem_resource.subsystemModelSize = // 0x30
sizeof(control_subsystem_resource);
CameraControlsMapper
*camera_mapper;
switch (controls->primaryControlType) // *(controls+0xc98)
{
case LBE4ControlsManager::PrimaryThrustMaster: // 2
camera_mapper = new CameraThrustmasterMapper( // FUN_0047ac5c
viewing_camera,
CameraShip::ControlsMapperSubsystem,
&control_subsystem_resource
);
primary_mapping_name = "Thrustmaster";
break;
case LBE4ControlsManager::PrimaryRIO: // 4
camera_mapper = new CameraRIOMapper( // FUN_0047ad3c
viewing_camera,
CameraShip::ControlsMapperSubsystem,
&control_subsystem_resource
);
primary_mapping_name = "L4";
break;
default:
camera_mapper = new CameraL4Mapper( // FUN_0047aa78
viewing_camera,
CameraShip::ControlsMapperSubsystem,
&control_subsystem_resource
);
// primary mapping name is NULL
break;
}
//------------------------------------------------------------
// Attach the mapping subsystem to the entity
//------------------------------------------------------------
viewing_camera->SetMappingSubsystem(camera_mapper); // FUN_0042c630
}
break;
case MechClassID: // 0xbb9
//===============================================================
// Create Mech (the BattleTech analog of RP's VTV case)
//===============================================================
{
Mech
*viewing_mech = Mech::Make((Mech::MakeMessage*)message); // FUN_004a2d48
Check(viewing_mech);
viewing_entity = viewing_mech;
//------------------------------------------------------------
// Control deadbanding
//------------------------------------------------------------
controls->SetJoystickDeadBand(0.05f); // FUN_00476eac
controls->SetThrottleDeadBand(0.05f); // FUN_00476eec
controls->SetPedalsDeadBand(0.05f); // FUN_00476f10
MechControlsMapper
*mech_mapper;
switch (controls->primaryControlType) // *(controls+0xc98)
{
case LBE4ControlsManager::PrimaryThrustMaster: // 2
{
//
// The DOS binary heap-allocated the subsystem resource
// and ref-counted it (FUN_00402460 + puVar2[3]++). The
// WinTesla Subsystem__SubsystemResource is a plain struct
// that the Subsystem ctor copies out of, so we build it
// on the stack and name it via Str_Copy -- the exact
// idiom RP uses for its VTV/Camera mapper resources.
//
MechControlsMapper::SubsystemResource
control_subsystem_resource;
Str_Copy(
control_subsystem_resource.subsystemName,
"ControlsMapper",
sizeof(control_subsystem_resource.subsystemName)
);
control_subsystem_resource.classID = TrivialSubsystemClassID;
control_subsystem_resource.subsystemModelSize =
sizeof(control_subsystem_resource);
mech_mapper = new MechThrustmasterMapper( // FUN_004d21d0
viewing_mech,
0,
&control_subsystem_resource,
(ClassID)MechControlsMapperClassID, // 0x7dc
MechThrustmasterMapper::DefaultData // &DAT_0051dc68
);
}
primary_mapping_name = "Thrustmaster";
break;
case LBE4ControlsManager::PrimaryRIO: // 4
{
MechControlsMapper::SubsystemResource
control_subsystem_resource;
Str_Copy(
control_subsystem_resource.subsystemName,
"ControlsMapper",
sizeof(control_subsystem_resource.subsystemName)
);
control_subsystem_resource.classID = TrivialSubsystemClassID;
control_subsystem_resource.subsystemModelSize =
sizeof(control_subsystem_resource);
mech_mapper = new MechRIOMapper( // FUN_004d266c
viewing_mech,
0,
&control_subsystem_resource,
(ClassID)MechControlsMapperClassID, // 0x7dc
MechRIOMapper::DefaultData // &DAT_0051dcf0
);
}
primary_mapping_name = "L4";
break;
default:
//
// TODO(bring-up): the shipped pod binary Fail()s here when no
// RIO/Thrustmaster is detected (primaryControlType==None on a
// dev box with no joystick). To let the spawn pipeline finish
// and the mech reach the render/frame loop, fall back to the
// RIO mapper (the pod's real L4 device). Keyboard/gamepad
// remap is a separate pod-bring-up task (CLAUDE.md Phase 8).
//
DEBUG_STREAM << "*****Mech has no controls mapping -- bring-up RIO fallback*****";
{
MechControlsMapper::SubsystemResource
control_subsystem_resource;
Str_Copy(
control_subsystem_resource.subsystemName,
"ControlsMapper",
sizeof(control_subsystem_resource.subsystemName)
);
control_subsystem_resource.classID = TrivialSubsystemClassID;
control_subsystem_resource.subsystemModelSize =
sizeof(control_subsystem_resource);
mech_mapper = new MechRIOMapper(
viewing_mech,
0,
&control_subsystem_resource,
(ClassID)MechControlsMapperClassID,
MechRIOMapper::DefaultData
);
}
primary_mapping_name = "L4";
break;
}
//------------------------------------------------------------
// Attach the mapping subsystem and enable collision
//------------------------------------------------------------
viewing_mech->SetMappingSubsystem(mech_mapper); // FUN_0049fe40
viewing_mech->StartCollisionAssistant(); // vtbl[+0x38]
}
break;
}
//-------------------------------------------------------------------
// Load the control-mapping resource stream for the entity
//-------------------------------------------------------------------
if (primary_mapping_name != NULL)
{
ResourceDescription
*resource_description =
application->GetResourceFile()->SearchList( // *(DAT_004efc94+0x68)
viewing_entity->GetResourceID(), // piVar5[0x6f]
ResourceDescription::ControlMappingsListResourceType // 6
);
if (resource_description != NULL)
{
resource_description =
GetResourceFile()->SearchList( // *(this+0x68)
resource_description->resourceID,
primary_mapping_name
);
if (resource_description != NULL)
{
resource_description->Lock(); // FUN_00406cd0
controls->CreateStreamedMappings( // FUN_0047703c
viewing_entity,
(int*)resource_description->resourceAddress
);
resource_description->Unlock();
}
}
}
//-------------------------------------------------------------------
// Configure the gauges for this entity
//-------------------------------------------------------------------
BTL4GaugeRenderer
*gauge_renderer = (BTL4GaugeRenderer*)GetGaugeRenderer(); // *(this+0x4c)
if (gauge_renderer != NULL)
{
gauge_renderer->ConfigureForModel("Init", viewing_entity); // FUN_0046ff64
}
return viewing_entity;
}
//
//#############################################################################
// RunMissionMessageHandler @004d3a2c
//#############################################################################
//
void
BTL4Application::RunMissionMessageHandler(RunMissionMessage *message)
{
Tell("BTL4Application::RunMissionMessageHandler\n"); // FUN_004dbb24/004d9c38
//
// Turn on the plasma score display: save the current mode mask and
// set the ModePlasmaDisplay bit (1<<22 == 0x400000) on the mode
// manager (this+0x50).
//
BTL4ModeManager
*mode_manager = (BTL4ModeManager*)GetModeManager(); // *(this+0x50)
// WinTesla ModeManager exposes the mask through AddModeMask(), which
// stashes the old mask into previousModeMask (== the DOS "savedMode"
// = "currentMode" step) and ORs in the new bits (== "currentMode |=").
mode_manager->AddModeMask(BTL4ModeManager::ModePlasmaDisplay); // |= 0x400000
Tell("Turning Plasma Score Display On\n");
L4Application::RunMissionMessageHandler(message); // FUN_0047b788
}
//
//#############################################################################
// StopMissionMessageHandler @004d3a94
//#############################################################################
//
void
BTL4Application::StopMissionMessageHandler(StopMissionMessage *message)
{
//
// Turn off the plasma score display: save the current mode mask and
// clear the ModePlasmaDisplay bit (~0x400000 == 0xffbfffff).
//
BTL4ModeManager
*mode_manager = (BTL4ModeManager*)GetModeManager(); // *(this+0x50)
// RemoveModeMask() = stash old mask into previousModeMask (the DOS
// "savedMode = currentMode") then clear the bits ("currentMode &= ~").
mode_manager->RemoveModeMask(BTL4ModeManager::ModePlasmaDisplay); // &= 0xffbfffff
L4Application::StopMissionMessageHandler(message); // FUN_0047b864
Tell("Turning Plasma Score Display Off\n");
}