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>
This commit is contained in:
@@ -0,0 +1,520 @@
|
||||
//===========================================================================//
|
||||
// File: mechtech.cpp //
|
||||
// Project: BattleTech Brick: Entity Manager //
|
||||
// Contents: MechTech -- the mech's subsystem-monitor / diagnostics subsystem //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved //
|
||||
// PROPRIETARY AND CONFIDENTIAL //
|
||||
//===========================================================================//
|
||||
//
|
||||
// RECONSTRUCTED from the shipped binary. Behaviour follows the Ghidra
|
||||
// pseudo-C for the @004ad124-@004ad6c9 cluster; the public interface and the
|
||||
// member / type names are GROUND TRUTH from the surviving MECHTECH.HPP.
|
||||
// Each non-trivial method cites its originating @ADDR.
|
||||
//
|
||||
// What MechTech does:
|
||||
// At construction it walks the owning Mech's segment roster and, for every
|
||||
// damageable MechSubsystem (those flagged with segment-bit 0x8), allocates a
|
||||
// SubsystemMonitor and threads it onto the `subsystemMonitors` chain. Each
|
||||
// frame the registered Performance (TechnicalAssistance @004ad33c) iterates
|
||||
// that chain, samples each watched subsystem's status flags, and -- whenever
|
||||
// a status bit changes -- posts an "alert" / "clear" message into the
|
||||
// cockpit status / MFD message sink. Set alerts carry the `alarmModel`
|
||||
// resource; the per-cell wooHoo timer latches an alert for a duration so the
|
||||
// readout doesn't flicker.
|
||||
//
|
||||
// Binary identity (mech.cpp's switch mislabelled these -- corrected here):
|
||||
// MechTech == ClassID 0xBDC, ctor @004ad228, size 0x104,
|
||||
// vtable @0050e3a0.
|
||||
// (mech.cpp's "MechTech" @004b7f94 / 0xBD6 is actually the HUD
|
||||
// torso-horizon gimbal display and is NOT this class.)
|
||||
//
|
||||
// Helper-function name mapping (engine internals referenced by the decomp):
|
||||
// FUN_0041c52c Subsystem base constructor
|
||||
// FUN_0041c684 Subsystem::CreateStreamedSubsystem
|
||||
// FUN_0041c648 Subsystem destructor
|
||||
// FUN_0041a1a4 IsDerivedFrom(classDerivations)
|
||||
// FUN_004022d0 operator delete (global heap)
|
||||
// FUN_00415e90 Plug constructor FUN_00415ed8 Plug destructor
|
||||
// FUN_004de998 array-construct N elements (count, stride, ..., elem-init)
|
||||
// FUN_004ad619 trivial element-init thunk (returns its arg)
|
||||
// FUN_00402f74 MemoryBlock::New(&block) FUN_00402f98 MemoryBlock::Delete(&block,p)
|
||||
// FUN_00417be0 / 00417c0c / 00417d00 / 00417d28 / 00417d54
|
||||
// ChainOf<> / chain-iterator internals (ctor/dtor/iter)
|
||||
// FUN_004ad621 ChainOf<SubsystemMonitor*> ctor (vtable @0050e398)
|
||||
// FUN_004ad640 ChainOf<> dtor
|
||||
// FUN_004ad68b chain iterator ctor (vtable @0050e348)
|
||||
// FUN_004ad6c9 chain iterator dtor
|
||||
// FUN_00402f74(0x50e248) ... SubsystemMonitor::operator new
|
||||
// FUN_00404088 NotationFile::Read(section,key,&string)
|
||||
// FUN_00406ff8 ResourceFile::ResolveModel(name,...) -> ResourceID*
|
||||
// FUN_004dbb24 DebugStream << (error reporting)
|
||||
// FUN_004366b8 build "status cleared" cockpit message
|
||||
// FUN_00436688 build "status set" cockpit message (carries alarmModel)
|
||||
// FUN_004364e4 dispatch cockpit/MFD message to the status sink
|
||||
// DAT_004efc94 the running Application/World; (+0x38) == status sink
|
||||
//
|
||||
|
||||
#include <bt.hpp>
|
||||
#pragma hdrstop
|
||||
|
||||
#if !defined(MECHTECH_HPP)
|
||||
# include <mechtech.hpp>
|
||||
#endif
|
||||
#if !defined(APP_HPP)
|
||||
# include <app.hpp>
|
||||
#endif
|
||||
#if !defined(TESTBT_HPP)
|
||||
# include <testbt.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
//###########################################################################
|
||||
//###########################################################################
|
||||
// MechTech::SubsystemMonitor
|
||||
//###########################################################################
|
||||
//###########################################################################
|
||||
|
||||
//#############################################################################
|
||||
// Memory Allocation Support
|
||||
//
|
||||
// Static MemoryBlock @0050e248 (zero-filled in .data, primed at runtime).
|
||||
//
|
||||
MemoryBlock
|
||||
MechTech::SubsystemMonitor::AllocatedMemory(
|
||||
sizeof(MechTech__SubsystemMonitor), // record size (0x80)
|
||||
8, // initial record count
|
||||
8, // growth delta
|
||||
"MechTech::SubsystemMonitor"
|
||||
);
|
||||
|
||||
|
||||
//#############################################################################
|
||||
// Construction / Destruction
|
||||
//
|
||||
// @004ad124 -- construct a monitor bound to one watched MechSubsystem.
|
||||
//
|
||||
// FUN_00415e90(this,1) -> Plug base ctor
|
||||
// *this = &PTR_FUN_0050e3d0 -> SubsystemMonitor vtable
|
||||
// FUN_004de998(this+0xC, 0x10, 7, 1, ...) -> placement-build statusArray[7]
|
||||
// this[0x7C] = subsystem -> monitoredSubsystem
|
||||
// loop x7: zero {currentStatus,wooHooed,startTime,wooHooEnd}
|
||||
//
|
||||
MechTech__SubsystemMonitor::MechTech__SubsystemMonitor(MechSubsystem *subsystem)
|
||||
:
|
||||
Plug()
|
||||
{
|
||||
monitoredSubsystem = subsystem;
|
||||
|
||||
for (int i = 0; i < MechSubsystem::TechStatusTypeCount; ++i) // 7
|
||||
{
|
||||
statusArray[i].currentStatus = 0;
|
||||
statusArray[i].wooHooed = 0;
|
||||
statusArray[i].startTime = 0L; // Time::operator=(long)
|
||||
statusArray[i].wooHooEnd = 0L; // Time::operator=(long)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @004ad180 -- destructor + deleting-destructor thunk. Re-seats the vtable,
|
||||
// runs the Plug base teardown (FUN_00415ed8) and, when invoked as the
|
||||
// deleting destructor (flag bit 0), returns the storage to the MemoryBlock.
|
||||
//
|
||||
MechTech__SubsystemMonitor::~MechTech__SubsystemMonitor()
|
||||
{
|
||||
// Plug base + AllocatedMemory.Delete(this) handled by the generated
|
||||
// deleting-destructor thunk (FUN_00402f98(&AllocatedMemory, this)).
|
||||
}
|
||||
|
||||
|
||||
//###########################################################################
|
||||
//###########################################################################
|
||||
// MechTech
|
||||
//###########################################################################
|
||||
//###########################################################################
|
||||
|
||||
//#############################################################################
|
||||
// Shared Data Support
|
||||
//
|
||||
// DefaultData @0050e270 ClassDerivations @0050e280
|
||||
//
|
||||
Derivation
|
||||
MechTech::ClassDerivations(
|
||||
Subsystem::GetClassDerivations(), // MUNGA Subsystem exposes a Derivation* getter
|
||||
"MechTech"
|
||||
);
|
||||
|
||||
Receiver::MessageHandlerSet
|
||||
MechTech::MessageHandlers;
|
||||
|
||||
MechTech::AttributeIndexSet
|
||||
MechTech::AttributeIndex;
|
||||
|
||||
MechTech::SharedData
|
||||
MechTech::DefaultData(
|
||||
&MechTech::ClassDerivations,
|
||||
MechTech::MessageHandlers,
|
||||
MechTech::AttributeIndex,
|
||||
MechTech::StateCount
|
||||
);
|
||||
|
||||
|
||||
//#############################################################################
|
||||
// Construction / Destruction
|
||||
//
|
||||
// @004ad228 (mech.cpp allocates 0x104 bytes and calls this for ClassID 0xBDC).
|
||||
//
|
||||
// FUN_0041c52c(...) -> Subsystem base ctor
|
||||
// *this = &PTR_FUN_0050e3a0 -> MechTech vtable
|
||||
// FUN_004ad621(this+0xE4, 0) -> subsystemMonitors chain ctor
|
||||
//
|
||||
// A live (non-copy / non-destroyed) instance -- (entity flags & 0xC) == 0 --
|
||||
// installs the per-frame Performance and builds its monitor roster; a copy
|
||||
// just flags itself dormant (this[10] |= 2).
|
||||
//
|
||||
MechTech::MechTech(
|
||||
Mech *entity,
|
||||
int subsystem_id,
|
||||
SubsystemResource *model,
|
||||
SharedData &shared_data
|
||||
):
|
||||
Subsystem(entity, subsystem_id, model, shared_data),
|
||||
subsystemMonitors(0) // FUN_004ad621(this+0xE4, 0) -- Chain(Node* == 0)
|
||||
{
|
||||
Check(entity);
|
||||
Check_Pointer(model);
|
||||
|
||||
segmentFlags = 0;
|
||||
|
||||
// (entity+0x28 & 0xC) == 0 -- owner is a live primary, not a copy/template.
|
||||
// CROSS-FAMILY: the original reads the owning Mech's per-segment flags
|
||||
// (Mech::GetSegmentFlags); mapped here to the entity's simulationFlags.
|
||||
if ((entity->simulationFlags & SegmentCopyMask) == 0)
|
||||
{
|
||||
SetPerformance(&MechTech::TechnicalAssistance); // this[7..9] = {&TechnicalAssistance,0,0} @0050e2b0
|
||||
|
||||
alarmModel = model->alarmModel; // res +0x30 -> this+0x100
|
||||
wooHooMinimumDuration = model->wooHooMinimumDuration; // res +0x34 -> this+0xF4
|
||||
wooHooDurationRange = model->wooHooDurationRange; // res +0x38 -> this+0xF8
|
||||
wooHooChance = model->wooHooChance; // res +0x3C -> this+0xFC
|
||||
|
||||
//
|
||||
// Walk the owner's subsystem roster and attach a monitor to every
|
||||
// damageable MechSubsystem. (Binary walked a Mech-specific segment
|
||||
// table at owner+0x124/+0x128 whose entries are these subsystem
|
||||
// objects; the engine exposes the same roster via Entity::GetSubsystem.)
|
||||
//
|
||||
for (int seg = entity->GetSubsystemCount() - 1; seg >= 0; --seg)
|
||||
{
|
||||
Subsystem *sub = entity->GetSubsystem(seg);
|
||||
if (
|
||||
sub != 0
|
||||
&& sub->IsDerivedFrom(MechSubsystem::ClassDerivations) // FUN_0041a1a4(**sub[3], 0x50de2c)
|
||||
&& sub->damageZone != 0 // damageable segment (segment bit 0x8)
|
||||
)
|
||||
{
|
||||
SubsystemMonitor *monitor =
|
||||
new SubsystemMonitor((MechSubsystem *)sub); // MemoryBlock @0050e248
|
||||
subsystemMonitors.Add(monitor); // (*this[0x39].vt[1])(...)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
segmentFlags |= DormantInstanceFlag; // this[10] |= 2 -- dormant (copy / template instance)
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//
|
||||
// @004ad1b8 -- destructor + deleting-destructor thunk.
|
||||
//
|
||||
// *this = &PTR_FUN_0050e3a0
|
||||
// FUN_004ad68b/FUN_004ad6c9 ... walk + tear down the monitor chain,
|
||||
// FUN_004ad640(this+0xE4, 2) -> subsystemMonitors dtor,
|
||||
// FUN_0041c648(this, 0) -> ~Subsystem.
|
||||
//
|
||||
MechTech::~MechTech()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
//
|
||||
// Release every SubsystemMonitor still on the chain, then the chain
|
||||
// itself; ~Subsystem finishes the base teardown.
|
||||
//
|
||||
ChainIteratorOf<SubsystemMonitor*> iterator(&subsystemMonitors);
|
||||
for (
|
||||
iterator.First();
|
||||
SubsystemMonitor *monitor = iterator.GetCurrent();
|
||||
/* Remove() re-seats currentLink */
|
||||
)
|
||||
{
|
||||
iterator.Remove();
|
||||
delete monitor;
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//###########################################################################
|
||||
// TestInstance -- MechTech
|
||||
//
|
||||
// @004ad470 -> FUN_0041a1a4(**this[3], 0x50e280)
|
||||
//
|
||||
Logical
|
||||
MechTech::TestInstance() const
|
||||
{
|
||||
return IsDerivedFrom(ClassDerivations);
|
||||
}
|
||||
|
||||
|
||||
//#############################################################################
|
||||
// Per-frame Performance
|
||||
//
|
||||
|
||||
//
|
||||
// @004ad33c -- TechnicalAssistance: poll every monitored subsystem's status
|
||||
// flags and emit cockpit/MFD status messages on change.
|
||||
//
|
||||
// Decomp shape:
|
||||
// sink = *(DAT_004efc94 + 0x38); // the status / MFD message sink
|
||||
// for (monitor in subsystemMonitors) // iterator FUN_004ad68b
|
||||
// {
|
||||
// sub = monitor->monitoredSubsystem; // monitor[0x7C]
|
||||
// flags = sub->GetStatusFlags(); // vtable slot @+0x30
|
||||
// for (type = 0; type < 7; ++type) // TechStatusTypeCount
|
||||
// {
|
||||
// bit = flags & 1;
|
||||
// cell = &monitor->statusArray[type];
|
||||
// if (cell->wooHooed) // an alert is latched
|
||||
// {
|
||||
// if (cell->wooHooEnd < GetTime()) cell->wooHooed = 0; // expired
|
||||
// else bit = cell->currentStatus; // hold
|
||||
// }
|
||||
// if (bit != cell->currentStatus) // status changed -> report
|
||||
// {
|
||||
// Mech *owner = GetEntity();
|
||||
// if (bit == 0) // cleared
|
||||
// FUN_004364e4(sink, owner, BuildClear(owner, sub, type));
|
||||
// else // set (carries alarmModel)
|
||||
// FUN_004364e4(sink, owner, BuildSet(owner, sub, type, alarmModel));
|
||||
// }
|
||||
// cell->currentStatus = bit;
|
||||
// flags >>= 1;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// NOTE (best-effort): the actual latch -- setting cell->wooHooed /
|
||||
// cell->wooHooEnd from wooHooChance / wooHooMinimumDuration /
|
||||
// wooHooDurationRange -- lives inside the message-builder helpers
|
||||
// (FUN_00436688 et al.), which are part of the HUD/message brick and were
|
||||
// not captured in this window. TechnicalAssistance only *clears* expired
|
||||
// latches and detects edges.
|
||||
//
|
||||
void
|
||||
MechTech::TechnicalAssistance(Scalar /*time_slice*/)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
Mech *owner = GetEntity();
|
||||
void *sink = StatusMessageSink(); // *(DAT_004efc94 + 0x38)
|
||||
|
||||
ChainIteratorOf<SubsystemMonitor*> it(&subsystemMonitors); // FUN_004ad68b
|
||||
SubsystemMonitor *monitor;
|
||||
for (
|
||||
it.First();
|
||||
(monitor = it.GetCurrent()) != 0;
|
||||
it.Next()
|
||||
)
|
||||
{
|
||||
MechSubsystem *sub = monitor->monitoredSubsystem;
|
||||
LWord flags = sub->GetStatusFlags(); // vt[+0x30]
|
||||
|
||||
for (int type = 0; type < MechSubsystem::TechStatusTypeCount; ++type)
|
||||
{
|
||||
int bit = (int)(flags & 1);
|
||||
StatusInfo &cell = monitor->statusArray[type];
|
||||
|
||||
if (cell.wooHooed != 0)
|
||||
{
|
||||
if (cell.wooHooEnd.ticks < GetTime().ticks) // this+0x10 == current time (integer tick compare)
|
||||
{
|
||||
cell.wooHooed = 0; // latch expired
|
||||
}
|
||||
else
|
||||
{
|
||||
bit = cell.currentStatus; // hold the latched state
|
||||
}
|
||||
}
|
||||
|
||||
if (bit != cell.currentStatus)
|
||||
{
|
||||
if (bit == 0)
|
||||
{
|
||||
ReportStatusCleared(sink, owner, sub, type); // FUN_004366b8 + FUN_004364e4
|
||||
}
|
||||
else
|
||||
{
|
||||
ReportStatusSet(sink, owner, sub, type, alarmModel);// FUN_00436688 + FUN_004364e4
|
||||
}
|
||||
}
|
||||
|
||||
cell.currentStatus = bit;
|
||||
flags >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CreateStreamedSubsystem -- MechTech
|
||||
//
|
||||
// @004ad48c
|
||||
//
|
||||
// FUN_0041c684(...) -> Subsystem::CreateStreamedSubsystem
|
||||
// resource->subsystemModelSize = 0x40 (res[0x24] = 0x40)
|
||||
// resource->classID = 0xBDC (res[0x20] = 0x0BDC)
|
||||
// resource->alarmModel = -1 (res+0x30)
|
||||
// resource->wooHoo{Min,Range,Chance} = 0 (res+0x34,+0x38,+0x3C)
|
||||
//
|
||||
// "AlarmModel" is optional: if absent (and alarmModel still -1) the parse
|
||||
// succeeds with no alarm. If present, the named model is resolved against
|
||||
// the resource file; failure reports "<name> couldn't locate <name>.mod".
|
||||
//
|
||||
Logical
|
||||
MechTech::CreateStreamedSubsystem(
|
||||
NotationFile *model_file,
|
||||
const char *model_name,
|
||||
const char *subsystem_name,
|
||||
SubsystemResource *subsystem_resource,
|
||||
NotationFile *subsystem_file,
|
||||
const ResourceDirectories *directories,
|
||||
ResourceFile *resource_file
|
||||
)
|
||||
{
|
||||
if (
|
||||
!Subsystem::CreateStreamedSubsystem( // FUN_0041c684
|
||||
model_file, model_name, subsystem_name,
|
||||
subsystem_resource, subsystem_file, directories
|
||||
)
|
||||
)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
subsystem_resource->subsystemModelSize = sizeof(*subsystem_resource); // 0x40
|
||||
subsystem_resource->classID = RegisteredClass::MechTechClassID; // 0xBDC
|
||||
|
||||
subsystem_resource->alarmModel = -1;
|
||||
subsystem_resource->wooHooMinimumDuration = 0.0f;
|
||||
subsystem_resource->wooHooDurationRange = 0.0f;
|
||||
subsystem_resource->wooHooChance = 0.0f;
|
||||
|
||||
//
|
||||
// "AlarmModel" -- optional model name resolved to a resource id.
|
||||
//
|
||||
const char *alarmModelName = 0;
|
||||
if (
|
||||
subsystem_resource->alarmModel == -1
|
||||
&& !subsystem_file->GetEntry(subsystem_name, "AlarmModel", &alarmModelName) // FUN_00404088(param_5,param_3,"AlarmModel",&local_8)
|
||||
)
|
||||
{
|
||||
return True; // no alarm model specified -- fine
|
||||
}
|
||||
|
||||
//
|
||||
// Resolve the named model to a resource id. The binary calls
|
||||
// FUN_00406ff8(resource_file, name, 1, -1) ("ResolveModel"); the engine
|
||||
// ResourceFile exposes FindResourceDescription instead.
|
||||
// TODO(verify): confirm the resource type used for the alarm .mod.
|
||||
//
|
||||
ResourceDescription *description =
|
||||
resource_file->FindResourceDescription(
|
||||
alarmModelName,
|
||||
ResourceDescription::GameModelResourceType
|
||||
);
|
||||
|
||||
if (description == 0)
|
||||
{
|
||||
// @004ad48c: "<subsystem_name> couldn't locate <name>.mod"
|
||||
// (original logged via DebugStream / FUN_004dbb24 -- HUD/diag brick).
|
||||
return False;
|
||||
}
|
||||
|
||||
subsystem_resource->alarmModel = description->resourceID;
|
||||
Check_Fpu();
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
//#############################################################################
|
||||
// Status reporting support
|
||||
//
|
||||
// CROSS-FAMILY stubs. The shipped code dispatches cockpit/MFD status messages
|
||||
// through the running Application/World status sink (DAT_004efc94 + 0x38) using
|
||||
// the HUD message builders FUN_004366b8 ("status cleared") / FUN_00436688
|
||||
// ("status set", carries alarmModel) and dispatcher FUN_004364e4. Those live
|
||||
// in the cockpit-message brick (btl4gaug / app), not reconstructed here, so the
|
||||
// bodies are stubs that satisfy the call sites in TechnicalAssistance.
|
||||
//
|
||||
|
||||
//
|
||||
// @0050e248-era global: the status / MFD message sink == *(DAT_004efc94 + 0x38).
|
||||
//
|
||||
void*
|
||||
MechTech::StatusMessageSink()
|
||||
{
|
||||
return 0; // TODO(cross-family): *(theApplication + 0x38) -- HUD status sink
|
||||
}
|
||||
|
||||
//
|
||||
// Engine current time (binary read this+0x10; the WinTesla clock is Now()).
|
||||
//
|
||||
Time
|
||||
MechTech::GetTime() const
|
||||
{
|
||||
return Now();
|
||||
}
|
||||
|
||||
//
|
||||
// FUN_004366b8 (build "status cleared" message) + FUN_004364e4 (dispatch).
|
||||
//
|
||||
void
|
||||
MechTech::ReportStatusCleared(
|
||||
void * /*sink*/,
|
||||
Mech * /*owner*/,
|
||||
MechSubsystem * /*sub*/,
|
||||
int /*type*/
|
||||
)
|
||||
{
|
||||
// TODO(cross-family): build + dispatch the cockpit "status cleared" message.
|
||||
}
|
||||
|
||||
//
|
||||
// FUN_00436688 (build "status set" message, carries alarmModel) + FUN_004364e4.
|
||||
//
|
||||
void
|
||||
MechTech::ReportStatusSet(
|
||||
void * /*sink*/,
|
||||
Mech * /*owner*/,
|
||||
MechSubsystem * /*sub*/,
|
||||
int /*type*/,
|
||||
ResourceDescription::ResourceID /*alarm_model*/
|
||||
)
|
||||
{
|
||||
// TODO(cross-family): build + dispatch the cockpit "status set" message.
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// WAVE 2 factory bridge -- MechTech (factory case 0xBDC, "HeatableSubsystem"
|
||||
// label; the case currently builds the heat base + discards the pointer).
|
||||
//===========================================================================//
|
||||
Subsystem *CreateMechTechSubsystem(Mech *owner, int id, void *seg)
|
||||
{
|
||||
Check(sizeof(MechTech) <= 0x140);
|
||||
return (Subsystem *) new (Memory::Allocate(0x140))
|
||||
MechTech(owner, id, (MechTech::SubsystemResource *)seg, MechTech::DefaultData);
|
||||
}
|
||||
Reference in New Issue
Block a user