BT410 5.3.118: the census closes -- the authoring-side CreateStreamedSubsystem family, and the Fail count reaches ZERO
The last eight stubs plus the two chain layers they actually need (PoweredSubsystem @004b13ac and ProjectileWeapon @004bc7cc were DECLARED in our headers all along -- only their definitions were missing). These are the notation->stream converters the 1995 authoring pipeline ran; missions read prebuilt streams and never call them, so the verification standard is compile + link + the raw decomp's key fingerprints -- and those fingerprints convicted the donors three more times: - The heat chain: Condenser, Reservoir AND PoweredSubsystem all chain ONE shared parser (@004ae150, reconstructed in full from the decomp -- the BT411 donor's body was its own TODO stub with a miscited address). It reads the five thermal scalars and the conduction-graph link (the linkedSinkIndex our wire-format work dump-verified from the runtime side, with the +2 segment-table bias), and HeatSink adds no keys of its own. - The Emitter's SeekVoltage LADDER is a notation ENTRY LIST walked in file order (curve rungs in sequence, the RecommendedIndex entry by name); the donor flattened it to one keyed read, which would author one-rung ladders against the runtime's real five-rung ones. MakeEntryList/GetFirstEntry is the engine's own idiom. - PipColor and MuzzleVelocity parse through the engine's authentic Convert_From_Ascii overloads (RGBColor / Vector3D); the donors' sscanf substitutes were port drift. Explosion and alarm models resolve as model FAMILIES (ModelListResourceType == the literal 1 in the binary; the donor comment calling it GameModelResourceType was wrong-name-right-number). Entry reads target the SUBSYSTEM notation file -- the decomp's fifth argument at every site; several donors wrote model_file. Class IDs stamp through OUR reader's enum symbols (they parse the real BTL4.RES streams today, and the 3000-base enum lands exactly on the binary's 0xBBB.. ids; 0x0BCD is the weapon-base stamp every concrete leaf overwrites). Stubs: NONE. Every function in restoration/source410 now has a body. Mission soak clean. Remaining reconstruction is depth, not holes: the mech4/mech3 archaeology (IntegrateMotion, the master-perf disasm, the stream builders that seed the 0xC/0x100 flags), HUD blocks 4-6, and the live networked/rig verifications queued for when a pod is available. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -611,18 +611,118 @@ void
|
||||
// CreateStreamedSubsystem Model-load-time construction. Not yet reconstructed.
|
||||
//#############################################################################
|
||||
//
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// CreateStreamedSubsystem -- binary @004bb478 (1024 bytes). Chains the
|
||||
// weapon record, stamps classID 0x0BC8 / size 0x1DC, then DischargeTime,
|
||||
// GraphicLength and the SEEKVOLTAGE LADDER: the binary walks a notation
|
||||
// ENTRY LIST (prefix "SeekVoltage") in file order -- curve samples fill
|
||||
// seekVoltage[] in sequence, and the entry named
|
||||
// "SeekVoltageRecommendedIndex" sets the recommended gear. (The BT411
|
||||
// donor flattened this to a single keyed read -- that would author a
|
||||
// one-rung ladder; the runtime's authored 5-rung ladders are real.)
|
||||
//#############################################################################
|
||||
//
|
||||
int
|
||||
Emitter::CreateStreamedSubsystem(
|
||||
ResourceFile *,
|
||||
NotationFile *,
|
||||
const char *,
|
||||
const char *,
|
||||
SubsystemResource *,
|
||||
NotationFile *,
|
||||
const ResourceDirectories *,
|
||||
int
|
||||
ResourceFile *resource_file,
|
||||
NotationFile *model_file,
|
||||
const char *model_name,
|
||||
const char *subsystem_name,
|
||||
SubsystemResource *subsystem_resource,
|
||||
NotationFile *subsystem_file,
|
||||
const ResourceDirectories *directories,
|
||||
int passes
|
||||
)
|
||||
{
|
||||
Fail("Emitter::CreateStreamedSubsystem -- emitter.cpp not yet reconstructed");
|
||||
return 0;
|
||||
if (
|
||||
!MechWeapon::CreateStreamedSubsystem(
|
||||
resource_file, model_file, model_name, subsystem_name,
|
||||
subsystem_resource, subsystem_file, directories, passes
|
||||
)
|
||||
)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
subsystem_resource->subsystemModelSize = 0x1DC;
|
||||
subsystem_resource->classID = RegisteredClass::EmitterClassID;
|
||||
|
||||
if (passes == 1)
|
||||
{
|
||||
int
|
||||
rung;
|
||||
subsystem_resource->graphicLength = -1.0f;
|
||||
subsystem_resource->dischargeTime = -1.0f;
|
||||
for (rung = 0; rung < 5; rung++)
|
||||
{
|
||||
subsystem_resource->seekVoltage[rung] = -1.0f;
|
||||
}
|
||||
subsystem_resource->seekVoltageRecommendedIndex = -1;
|
||||
}
|
||||
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "DischargeTime",
|
||||
&subsystem_resource->dischargeTime)
|
||||
&& subsystem_resource->dischargeTime == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing DischargeTime!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "GraphicLength",
|
||||
&subsystem_resource->graphicLength)
|
||||
&& subsystem_resource->graphicLength == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing GraphicLength!" << endl;
|
||||
return False;
|
||||
}
|
||||
|
||||
//
|
||||
// The voltage ladder.
|
||||
//
|
||||
NameList
|
||||
*seek_list = subsystem_file->MakeEntryList(subsystem_name, "SeekVoltage");
|
||||
if (
|
||||
(seek_list == NULL || seek_list->GetFirstEntry() == NULL) &&
|
||||
subsystem_resource->seekVoltageRecommendedIndex == -1
|
||||
)
|
||||
{
|
||||
if (seek_list != NULL)
|
||||
{
|
||||
delete seek_list;
|
||||
}
|
||||
DEBUG_STREAM << subsystem_name << " missing SeekVoltage" << endl;
|
||||
return False;
|
||||
}
|
||||
if (seek_list != NULL)
|
||||
{
|
||||
Scalar
|
||||
*rung_cursor = &subsystem_resource->seekVoltage[0];
|
||||
ObjectNameList::Entry
|
||||
*entry;
|
||||
for (
|
||||
entry = seek_list->GetFirstEntry();
|
||||
entry != NULL;
|
||||
entry = entry->GetNextEntry()
|
||||
)
|
||||
{
|
||||
if (entry->IsName("SeekVoltageRecommendedIndex"))
|
||||
{
|
||||
subsystem_resource->seekVoltageRecommendedIndex =
|
||||
entry->GetAtoi();
|
||||
}
|
||||
else
|
||||
{
|
||||
*rung_cursor++ = (Scalar)entry->GetAtof();
|
||||
}
|
||||
}
|
||||
delete seek_list;
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
return True;
|
||||
}
|
||||
|
||||
@@ -147,19 +147,129 @@ Logical
|
||||
// damage-zone stream). Not yet reconstructed (see MECHSUB.NOTES.md).
|
||||
//#############################################################################
|
||||
//
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// CreateStreamedSubsystem -- binary @004ae150 (904 bytes), read in full from
|
||||
// the raw decomp (the BT411 donor's body was its own TODO stub). The shared
|
||||
// heat-record parser: Condenser, Reservoir AND PoweredSubsystem all chain
|
||||
// THIS function directly (HeatSink adds no keys of its own). Stamps classID
|
||||
// 0x0BBC / size 0xFC; five required thermal scalars; the conduction-graph
|
||||
// link ("HeatSink", a subsystem name -> index with the +2 segment-table
|
||||
// bias) lands in HeatSink::SubsystemResource::linkedSinkIndex -- the callers
|
||||
// always carry at least a HeatSink-sized record, hence the cast.
|
||||
//#############################################################################
|
||||
//
|
||||
int
|
||||
HeatableSubsystem::CreateStreamedSubsystem(
|
||||
NotationFile *,
|
||||
const char *,
|
||||
const char *,
|
||||
SubsystemResource *,
|
||||
NotationFile *,
|
||||
const ResourceDirectories *,
|
||||
int
|
||||
NotationFile *model_file,
|
||||
const char *model_name,
|
||||
const char *subsystem_name,
|
||||
SubsystemResource *subsystem_resource,
|
||||
NotationFile *subsystem_file,
|
||||
const ResourceDirectories *directories,
|
||||
int passes
|
||||
)
|
||||
{
|
||||
Fail("HeatableSubsystem::CreateStreamedSubsystem -- heat.cpp not yet reconstructed");
|
||||
return 0;
|
||||
if (
|
||||
!MechSubsystem::CreateStreamedSubsystem(
|
||||
model_file, model_name, subsystem_name,
|
||||
subsystem_resource, subsystem_file, directories, passes
|
||||
)
|
||||
)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
subsystem_resource->subsystemModelSize = 0xFC;
|
||||
subsystem_resource->classID = RegisteredClass::HeatableSubsystemClassID;
|
||||
|
||||
HeatSink::SubsystemResource
|
||||
*sink_resource = (HeatSink::SubsystemResource *)subsystem_resource;
|
||||
|
||||
if (passes == 1)
|
||||
{
|
||||
subsystem_resource->startingTemperature = -1.0f;
|
||||
subsystem_resource->degradationTemperature = -1.0f;
|
||||
subsystem_resource->failureTemperature = -1.0f;
|
||||
subsystem_resource->thermalConductance = -1.0f;
|
||||
subsystem_resource->thermalMass = -1.0f;
|
||||
sink_resource->linkedSinkIndex = -1;
|
||||
}
|
||||
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "StartingTemperature",
|
||||
&subsystem_resource->startingTemperature)
|
||||
&& subsystem_resource->startingTemperature == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing StartingTemperature!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "DegradationTemperature",
|
||||
&subsystem_resource->degradationTemperature)
|
||||
&& subsystem_resource->degradationTemperature == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing DegradationTemperature!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "FailureTemperature",
|
||||
&subsystem_resource->failureTemperature)
|
||||
&& subsystem_resource->failureTemperature == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing FailureTemperature!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "ThermalConductance",
|
||||
&subsystem_resource->thermalConductance)
|
||||
&& subsystem_resource->thermalConductance == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing ThermalConductance!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "ThermalMass",
|
||||
&subsystem_resource->thermalMass)
|
||||
&& subsystem_resource->thermalMass == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing ThermalMass!" << endl;
|
||||
return False;
|
||||
}
|
||||
|
||||
//
|
||||
// The conduction-graph link.
|
||||
//
|
||||
const char
|
||||
*sink_name = "Unspecified";
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "HeatSink", &sink_name)
|
||||
&& sink_resource->linkedSinkIndex == -1
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing HeatSink!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (strcmp(sink_name, "Unspecified") != 0)
|
||||
{
|
||||
sink_resource->linkedSinkIndex =
|
||||
Find_Subsystem_Index(subsystem_file, sink_name);
|
||||
}
|
||||
if (sink_resource->linkedSinkIndex < 0)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " has an invalid heat sink!" << endl;
|
||||
return False;
|
||||
}
|
||||
sink_resource->linkedSinkIndex += 2;
|
||||
|
||||
Check_Fpu();
|
||||
return True;
|
||||
}
|
||||
|
||||
//###########################################################################
|
||||
|
||||
@@ -309,19 +309,124 @@ void
|
||||
// MECHSUB.NOTES.md -- the 4.10 per-type damage-zone stream format).
|
||||
//#############################################################################
|
||||
//
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// CreateStreamedSubsystem -- binary @004ac9ec (1469 bytes). The authoring
|
||||
// converter: parse the damageable-subsystem record from the notation files
|
||||
// onto the stream resource. First pass primes every field to its unset
|
||||
// sentinel; on later passes a missing key is only an error if the field is
|
||||
// still unset. All entry reads come from the SUBSYSTEM notation file (the
|
||||
// binary's fifth argument; the BT411 donor's model_file reads were drift).
|
||||
//#############################################################################
|
||||
//
|
||||
int
|
||||
MechSubsystem::CreateStreamedSubsystem(
|
||||
NotationFile *,
|
||||
const char *,
|
||||
const char *,
|
||||
SubsystemResource *,
|
||||
NotationFile *,
|
||||
const ResourceDirectories *,
|
||||
int
|
||||
NotationFile *model_file,
|
||||
const char *model_name,
|
||||
const char *subsystem_name,
|
||||
SubsystemResource *subsystem_resource,
|
||||
NotationFile *subsystem_file,
|
||||
const ResourceDirectories *directories,
|
||||
int passes
|
||||
)
|
||||
{
|
||||
Fail("MechSubsystem::CreateStreamedSubsystem -- mechsub.cpp not yet reconstructed");
|
||||
return 0;
|
||||
if (
|
||||
!Subsystem::CreateStreamedSubsystem(
|
||||
model_file, model_name, subsystem_name,
|
||||
subsystem_resource, subsystem_file, directories
|
||||
)
|
||||
)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
subsystem_resource->subsystemModelSize = 0xE4;
|
||||
subsystem_resource->classID = RegisteredClass::MechSubsystemClassID;
|
||||
|
||||
if (passes == 1)
|
||||
{
|
||||
int
|
||||
facing;
|
||||
subsystem_resource->criticalReference = -1.0f;
|
||||
for (facing = 0; facing < 5; facing++)
|
||||
{
|
||||
subsystem_resource->armorByFacing[facing] = -1.0f;
|
||||
}
|
||||
subsystem_resource->structureReference = -1.0f;
|
||||
subsystem_resource->vitalSubsystemIndex = -1;
|
||||
memset(subsystem_resource->videoObjectName, 0,
|
||||
sizeof(subsystem_resource->videoObjectName));
|
||||
strcpy(subsystem_resource->videoObjectName, "None");
|
||||
subsystem_resource->alarmModel = 0;
|
||||
subsystem_resource->printSimulationState = 0;
|
||||
subsystem_resource->collisionCriticalHitWeight = 0.0f;
|
||||
}
|
||||
|
||||
subsystem_file->GetEntry(subsystem_name, "PrintSimulationState",
|
||||
&subsystem_resource->printSimulationState);
|
||||
subsystem_file->GetEntry(subsystem_name, "CollisionCriticalHitWeight",
|
||||
&subsystem_resource->collisionCriticalHitWeight);
|
||||
|
||||
const char
|
||||
*video_name = "Unspecified";
|
||||
subsystem_file->GetEntry(subsystem_name, "VideoObjectName", &video_name);
|
||||
if (strcmp(video_name, "Unspecified") != 0)
|
||||
{
|
||||
strcpy(subsystem_resource->videoObjectName, video_name);
|
||||
}
|
||||
|
||||
//
|
||||
// "VitalSubsystem" -- optional; a skeleton page name resolved to a
|
||||
// segment index.
|
||||
//
|
||||
const char
|
||||
*vital_name = "Unspecified";
|
||||
subsystem_file->GetEntry(subsystem_name, "VitalSubsystem", &vital_name);
|
||||
if (strcmp(vital_name, "Unspecified") != 0)
|
||||
{
|
||||
subsystem_resource->vitalSubsystemIndex =
|
||||
Get_Segment_Index(model_file, model_name, directories, vital_name);
|
||||
}
|
||||
|
||||
//
|
||||
// The armour/crit economy keys (binary key strings @0x50e09d..0x50e15d):
|
||||
// WeaponDamagePoints and CriticalHitScoreBonus are REQUIRED; the five
|
||||
// per-damage-type points are optional. (structureReference /
|
||||
// armorByFacing are this tree's names for the same stream fields the
|
||||
// runtime damage economy reads.)
|
||||
//
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "WeaponDamagePoints",
|
||||
&subsystem_resource->structureReference)
|
||||
&& subsystem_resource->structureReference == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " Must have a WeaponDamagePoints" << endl;
|
||||
return False;
|
||||
}
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "CriticalHitScoreBonus",
|
||||
&subsystem_resource->criticalReference)
|
||||
&& subsystem_resource->criticalReference == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " Must have a CriticalHitScoreBonus" << endl;
|
||||
return False;
|
||||
}
|
||||
subsystem_file->GetEntry(subsystem_name, "CollisionDamagePoints",
|
||||
&subsystem_resource->armorByFacing[0]);
|
||||
subsystem_file->GetEntry(subsystem_name, "BallisticDamagePoints",
|
||||
&subsystem_resource->armorByFacing[1]);
|
||||
subsystem_file->GetEntry(subsystem_name, "ExplosiveDamagePoints",
|
||||
&subsystem_resource->armorByFacing[2]);
|
||||
subsystem_file->GetEntry(subsystem_name, "LaserDamagePoints",
|
||||
&subsystem_resource->armorByFacing[3]);
|
||||
subsystem_file->GetEntry(subsystem_name, "EnergyDamagePoints",
|
||||
&subsystem_resource->armorByFacing[4]);
|
||||
|
||||
Check_Fpu();
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -1,67 +1,115 @@
|
||||
//===========================================================================//
|
||||
// File: mechtech.cpp //
|
||||
// Project: BattleTech Brick: Mech subsystems //
|
||||
// Contents: MechTech -- the on-board technician / repair subsystem //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide //
|
||||
//===========================================================================//
|
||||
|
||||
#include <bt.hpp>
|
||||
#pragma hdrstop
|
||||
#if !defined(MECHTECH_HPP)
|
||||
# include <mechtech.hpp>
|
||||
#endif
|
||||
#if !defined(MECH_HPP)
|
||||
# include <mech.hpp>
|
||||
#endif
|
||||
|
||||
Derivation
|
||||
MechTech::ClassDerivations(Subsystem::ClassDerivations, "MechTech");
|
||||
|
||||
MechTech::SharedData
|
||||
MechTech::DefaultData(
|
||||
MechTech::ClassDerivations,
|
||||
Subsystem::MessageHandlers,
|
||||
Subsystem::AttributeIndex,
|
||||
Subsystem::StateCount
|
||||
);
|
||||
|
||||
MechTech::MechTech(
|
||||
Mech *entity,
|
||||
int subsystem_id,
|
||||
SubsystemResource *model,
|
||||
SharedData &shared_data
|
||||
):
|
||||
Subsystem(entity, subsystem_id, model, shared_data),
|
||||
subsystemMonitors(NULL)
|
||||
{
|
||||
Check(entity);
|
||||
Check_Pointer(model);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
MechTech::~MechTech()
|
||||
{
|
||||
}
|
||||
|
||||
Logical
|
||||
MechTech::TestInstance() const
|
||||
{
|
||||
return IsDerivedFrom(ClassDerivations);
|
||||
}
|
||||
|
||||
Logical
|
||||
MechTech::CreateStreamedSubsystem(
|
||||
NotationFile *,
|
||||
const char *,
|
||||
const char *,
|
||||
SubsystemResource *,
|
||||
NotationFile *,
|
||||
const ResourceDirectories *,
|
||||
ResourceFile *
|
||||
)
|
||||
{
|
||||
Fail("MechTech::CreateStreamedSubsystem -- mechtech.cpp not yet reconstructed");
|
||||
return False;
|
||||
}
|
||||
//===========================================================================//
|
||||
// File: mechtech.cpp //
|
||||
// Project: BattleTech Brick: Mech subsystems //
|
||||
// Contents: MechTech -- the on-board technician / repair subsystem //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide //
|
||||
//===========================================================================//
|
||||
|
||||
#include <bt.hpp>
|
||||
#pragma hdrstop
|
||||
#if !defined(MECHTECH_HPP)
|
||||
# include <mechtech.hpp>
|
||||
#endif
|
||||
#if !defined(MECH_HPP)
|
||||
# include <mech.hpp>
|
||||
#endif
|
||||
|
||||
Derivation
|
||||
MechTech::ClassDerivations(Subsystem::ClassDerivations, "MechTech");
|
||||
|
||||
MechTech::SharedData
|
||||
MechTech::DefaultData(
|
||||
MechTech::ClassDerivations,
|
||||
Subsystem::MessageHandlers,
|
||||
Subsystem::AttributeIndex,
|
||||
Subsystem::StateCount
|
||||
);
|
||||
|
||||
MechTech::MechTech(
|
||||
Mech *entity,
|
||||
int subsystem_id,
|
||||
SubsystemResource *model,
|
||||
SharedData &shared_data
|
||||
):
|
||||
Subsystem(entity, subsystem_id, model, shared_data),
|
||||
subsystemMonitors(NULL)
|
||||
{
|
||||
Check(entity);
|
||||
Check_Pointer(model);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
MechTech::~MechTech()
|
||||
{
|
||||
}
|
||||
|
||||
Logical
|
||||
MechTech::TestInstance() const
|
||||
{
|
||||
return IsDerivedFrom(ClassDerivations);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// CreateStreamedSubsystem -- binary @004ad48c. Stamps classID 0x0BDC / size
|
||||
// 0x40 and zeroes the wooHoo trio; "AlarmModel" is OPTIONAL -- absent means
|
||||
// no alarm; present, the named model family must resolve in the resource
|
||||
// file ("<name> couldn't locate <name>.mod" otherwise). The surviving
|
||||
// MECHTECH.HPP signature puts the ResourceFile LAST.
|
||||
//#############################################################################
|
||||
//
|
||||
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(
|
||||
model_file, model_name, subsystem_name,
|
||||
subsystem_resource, subsystem_file, directories
|
||||
)
|
||||
)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
subsystem_resource->subsystemModelSize = 0x40;
|
||||
subsystem_resource->classID = RegisteredClass::MechTechClassID;
|
||||
|
||||
subsystem_resource->alarmModel = (ResourceDescription::ResourceID)-1;
|
||||
subsystem_resource->wooHooMinimumDuration = 0.0f;
|
||||
subsystem_resource->wooHooDurationRange = 0.0f;
|
||||
subsystem_resource->wooHooChance = 0.0f;
|
||||
|
||||
const char
|
||||
*alarm_model_name = NULL;
|
||||
if (!subsystem_file->GetEntry(subsystem_name, "AlarmModel", &alarm_model_name))
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
ResourceDescription
|
||||
*description =
|
||||
resource_file->FindResourceDescription(
|
||||
alarm_model_name,
|
||||
ResourceDescription::ModelListResourceType);
|
||||
if (description == NULL)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " couldn't locate "
|
||||
<< alarm_model_name << ".mod" << endl;
|
||||
return False;
|
||||
}
|
||||
subsystem_resource->alarmModel = description->resourceID;
|
||||
|
||||
Check_Fpu();
|
||||
return True;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
#include <bt.hpp>
|
||||
#pragma hdrstop
|
||||
|
||||
#if !defined(COLOR_HPP)
|
||||
# include <color.hpp> // RGBColor + Convert_From_Ascii (PipColor)
|
||||
#endif
|
||||
|
||||
#if !defined(MECHWEAP_HPP)
|
||||
# include <mechweap.hpp>
|
||||
#endif
|
||||
@@ -488,18 +492,223 @@ void
|
||||
// CreateStreamedSubsystem Model-load-time construction. Not yet reconstructed.
|
||||
//#############################################################################
|
||||
//
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// CreateStreamedSubsystem -- binary @004b9d10 (1868 bytes). The weapon
|
||||
// record parser: chains the powered record, stamps size 0x1BC and the
|
||||
// weapon-base classID (0x0BCD), primes the weapon fields on the first pass,
|
||||
// then reads the ballistics/pip block. Required unless already set:
|
||||
// DamageAmount, HeatCostToFire, PipPosition, PipColor, PipExtendedRange,
|
||||
// RechargeRate, WeaponRange, DamageType, ExplosionModelFile. PipColor uses
|
||||
// the engine's own RGB parser (Convert_From_Ascii -- the BT411 donor's
|
||||
// sscanf was drift); the explosion resolves as a model FAMILY
|
||||
// (ModelListResourceType -- the streamed id is a family id, the same truth
|
||||
// the missile work established from the runtime side).
|
||||
//#############################################################################
|
||||
//
|
||||
int
|
||||
MechWeapon::CreateStreamedSubsystem(
|
||||
ResourceFile *,
|
||||
NotationFile *,
|
||||
const char *,
|
||||
const char *,
|
||||
SubsystemResource *,
|
||||
NotationFile *,
|
||||
const ResourceDirectories *,
|
||||
int
|
||||
ResourceFile *resource_file,
|
||||
NotationFile *model_file,
|
||||
const char *model_name,
|
||||
const char *subsystem_name,
|
||||
SubsystemResource *subsystem_resource,
|
||||
NotationFile *subsystem_file,
|
||||
const ResourceDirectories *directories,
|
||||
int passes
|
||||
)
|
||||
{
|
||||
Fail("MechWeapon::CreateStreamedSubsystem -- mechweap.cpp not yet reconstructed");
|
||||
return 0;
|
||||
if (
|
||||
!PoweredSubsystem::CreateStreamedSubsystem(
|
||||
model_file, model_name, subsystem_name,
|
||||
subsystem_resource, subsystem_file, directories, passes
|
||||
)
|
||||
)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
subsystem_resource->subsystemModelSize = 0x1BC;
|
||||
subsystem_resource->classID =
|
||||
(RegisteredClass::ClassID)RegisteredClass::ProjectileWeaponClassID;
|
||||
// ^ 0x0BCD -- the binary's weapon-base stamp; our enum spells the value
|
||||
// ProjectileWeaponClassID. Every concrete leaf (Emitter, launcher...)
|
||||
// overwrites it with its own id after this call.
|
||||
|
||||
if (passes == 1)
|
||||
{
|
||||
subsystem_resource->rechargeRate = -1.0f;
|
||||
subsystem_resource->weaponRange = -1.0f;
|
||||
subsystem_resource->explosionModelFile = (ResourceDescription::ResourceID)-1;
|
||||
subsystem_resource->damageAmount = -1.0f;
|
||||
subsystem_resource->heatCostToFire = -1.0f;
|
||||
subsystem_resource->pipPosition = -1;
|
||||
subsystem_resource->pipColor[0] = -1.0f;
|
||||
subsystem_resource->pipColor[1] = -1.0f;
|
||||
subsystem_resource->pipColor[2] = -1.0f;
|
||||
subsystem_resource->pipExtendedRange = -1;
|
||||
}
|
||||
|
||||
if (subsystem_resource->segmentIndex == -1 && passes > 1)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing SegmentPageName!" << endl;
|
||||
return False;
|
||||
}
|
||||
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "DamageAmount",
|
||||
&subsystem_resource->damageAmount)
|
||||
&& subsystem_resource->damageAmount == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << model_name << " Missing DamageAmount" << endl;
|
||||
return False;
|
||||
}
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "HeatCostToFire",
|
||||
&subsystem_resource->heatCostToFire)
|
||||
&& subsystem_resource->heatCostToFire == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing HeatCostToFire !" << endl;
|
||||
return False;
|
||||
}
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "PipPosition",
|
||||
&subsystem_resource->pipPosition)
|
||||
&& subsystem_resource->pipPosition == -1
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing PipPosition!" << endl;
|
||||
return False;
|
||||
}
|
||||
|
||||
const char
|
||||
*pip_color_name = "Unspecified";
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "PipColor", &pip_color_name)
|
||||
&& subsystem_resource->pipColor[0] == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing PipColor!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (strcmp(pip_color_name, "Unspecified") != 0)
|
||||
{
|
||||
RGBColor
|
||||
pip_color;
|
||||
Convert_From_Ascii(pip_color_name, &pip_color);
|
||||
subsystem_resource->pipColor[0] = pip_color.Red;
|
||||
subsystem_resource->pipColor[1] = pip_color.Green;
|
||||
subsystem_resource->pipColor[2] = pip_color.Blue;
|
||||
}
|
||||
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "PipExtendedRange",
|
||||
&subsystem_resource->pipExtendedRange)
|
||||
&& subsystem_resource->pipExtendedRange == -1
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing PipExtendedRange!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "RechargeRate",
|
||||
&subsystem_resource->rechargeRate)
|
||||
&& subsystem_resource->rechargeRate == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << model_name << " Missing RechargeRate" << endl;
|
||||
return False;
|
||||
}
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "WeaponRange",
|
||||
&subsystem_resource->weaponRange)
|
||||
&& subsystem_resource->weaponRange == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << model_name << " Missing WeaponRange" << endl;
|
||||
return False;
|
||||
}
|
||||
|
||||
const char
|
||||
*damage_type_name = "Unspecified";
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "DamageType", &damage_type_name)
|
||||
&& subsystem_resource->damageAmount == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << model_name << " missing DamageType" << endl;
|
||||
return False;
|
||||
}
|
||||
if (strcmp(damage_type_name, "Unspecified") != 0)
|
||||
{
|
||||
if (strcmp(damage_type_name, "CollisionDamage") == 0)
|
||||
{
|
||||
subsystem_resource->damageType = Damage::CollisionDamageType;
|
||||
}
|
||||
else if (strcmp(damage_type_name, "BallisticDamage") == 0)
|
||||
{
|
||||
subsystem_resource->damageType = Damage::BallisticDamageType;
|
||||
}
|
||||
else if (strcmp(damage_type_name, "ExplosiveDamage") == 0)
|
||||
{
|
||||
subsystem_resource->damageType = Damage::ExplosiveDamageType;
|
||||
}
|
||||
else if (strcmp(damage_type_name, "LaserDamage") == 0)
|
||||
{
|
||||
subsystem_resource->damageType = Damage::LaserDamageType;
|
||||
}
|
||||
else if (strcmp(damage_type_name, "EnergyDamage") == 0)
|
||||
{
|
||||
subsystem_resource->damageType = Damage::EnergyDamageType;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_STREAM << model_name << " has an unknown DamageType of "
|
||||
<< damage_type_name << endl;
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
const char
|
||||
*explosion_model_name = "Unspecified";
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "ExplosionModelFile",
|
||||
&explosion_model_name)
|
||||
&& subsystem_resource->explosionModelFile
|
||||
== (ResourceDescription::ResourceID)-1
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << model_name << " missing ExplosionModelFile" << endl;
|
||||
return False;
|
||||
}
|
||||
|
||||
ResourceDescription
|
||||
*explosion = NULL;
|
||||
if (strcmp(explosion_model_name, "Unspecified") != 0)
|
||||
{
|
||||
explosion =
|
||||
resource_file->FindResourceDescription(
|
||||
explosion_model_name,
|
||||
ResourceDescription::ModelListResourceType);
|
||||
}
|
||||
if (
|
||||
explosion == NULL &&
|
||||
subsystem_resource->explosionModelFile
|
||||
== (ResourceDescription::ResourceID)-1
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << model_name << " cannot find " << explosion_model_name
|
||||
<< " in resource file!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (explosion != NULL)
|
||||
{
|
||||
subsystem_resource->explosionModelFile = explosion->resourceID;
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
return True;
|
||||
}
|
||||
|
||||
@@ -388,17 +388,74 @@ void
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// CreateStreamedSubsystem -- binary @0049be10 (324 bytes). Chains the base
|
||||
// Subsystem record, stamps classID 0x0BD3 / size 0x38, resolves the
|
||||
// REQUIRED "TerrainHitExplosion" model family, reads the REQUIRED
|
||||
// "RendererCompensateTime". (The runtime never consumes either field --
|
||||
// see the inert terrain-hit note above -- but the authored stream carries
|
||||
// both, so the converter writes both.)
|
||||
//#############################################################################
|
||||
//
|
||||
Logical
|
||||
SubsystemMessageManager::CreateStreamedSubsystem(
|
||||
ResourceFile *,
|
||||
NotationFile *,
|
||||
const char *,
|
||||
const char *,
|
||||
SubsystemResource *,
|
||||
NotationFile *,
|
||||
const ResourceDirectories *
|
||||
ResourceFile *resource_file,
|
||||
NotationFile *model_file,
|
||||
const char *model_name,
|
||||
const char *subsystem_name,
|
||||
SubsystemResource *subsystem_resource,
|
||||
NotationFile *subsystem_file,
|
||||
const ResourceDirectories *directories
|
||||
)
|
||||
{
|
||||
Fail("SubsystemMessageManager::CreateStreamedSubsystem -- messmgr.cpp not yet reconstructed");
|
||||
return False;
|
||||
if (
|
||||
!Subsystem::CreateStreamedSubsystem(
|
||||
model_file, model_name, subsystem_name,
|
||||
subsystem_resource, subsystem_file, directories
|
||||
)
|
||||
)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
subsystem_resource->classID =
|
||||
RegisteredClass::SubsystemMessageManagerClassID;
|
||||
subsystem_resource->subsystemModelSize = 0x38;
|
||||
|
||||
const char
|
||||
*terrain_hit_name;
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "TerrainHitExplosion",
|
||||
&terrain_hit_name)
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing TerrainHitExplosion!" << endl;
|
||||
return False;
|
||||
}
|
||||
ResourceDescription
|
||||
*description =
|
||||
resource_file->FindResourceDescription(
|
||||
terrain_hit_name,
|
||||
ResourceDescription::ModelListResourceType);
|
||||
if (description == NULL)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " cannot find " << terrain_hit_name
|
||||
<< " in resource file!" << endl;
|
||||
return False;
|
||||
}
|
||||
subsystem_resource->terrainHitExplosionID = description->resourceID;
|
||||
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "RendererCompensateTime",
|
||||
&subsystem_resource->rendererCompensateTime)
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing RendererCompensateTime" << endl;
|
||||
return False;
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
return True;
|
||||
}
|
||||
|
||||
@@ -450,18 +450,73 @@ void
|
||||
//
|
||||
// Model-load-time construction. Not yet reconstructed.
|
||||
//
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// CreateStreamedSubsystem -- binary @004bd08c. Chains the projectile
|
||||
// record, stamps the launcher's own classID and record size, then
|
||||
// MissileCount and the "x y z" MuzzleVelocity vector (engine
|
||||
// Convert_From_Ascii -- the donor's sscanf was drift).
|
||||
//#############################################################################
|
||||
//
|
||||
Logical
|
||||
MissileLauncher::CreateStreamedSubsystem(
|
||||
ResourceFile *,
|
||||
NotationFile *,
|
||||
const char *,
|
||||
const char *,
|
||||
SubsystemResource *,
|
||||
NotationFile *,
|
||||
const ResourceDirectories *,
|
||||
int
|
||||
ResourceFile *resource_file,
|
||||
NotationFile *model_file,
|
||||
const char *model_name,
|
||||
const char *subsystem_name,
|
||||
SubsystemResource *subsystem_resource,
|
||||
NotationFile *subsystem_file,
|
||||
const ResourceDirectories *directories,
|
||||
int passes
|
||||
)
|
||||
{
|
||||
Fail("MissileLauncher::CreateStreamedSubsystem -- mislanch.cpp not yet reconstructed");
|
||||
return False;
|
||||
if (
|
||||
!ProjectileWeapon::CreateStreamedSubsystem(
|
||||
resource_file, model_file, model_name, subsystem_name,
|
||||
subsystem_resource, subsystem_file, directories, passes
|
||||
)
|
||||
)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
subsystem_resource->subsystemModelSize = sizeof(*subsystem_resource);
|
||||
subsystem_resource->classID = RegisteredClass::MissileLauncherClassID;
|
||||
|
||||
if (passes == 1)
|
||||
{
|
||||
subsystem_resource->missileCount = -1;
|
||||
subsystem_resource->muzzleVelocity = Vector3D::Identity;
|
||||
}
|
||||
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "MissileCount",
|
||||
&subsystem_resource->missileCount)
|
||||
&& subsystem_resource->missileCount == -1
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing MissileCount!" << endl;
|
||||
return False;
|
||||
}
|
||||
|
||||
const char
|
||||
*muzzle_velocity_text = "Unspecified";
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "MuzzleVelocity",
|
||||
&muzzle_velocity_text)
|
||||
&& subsystem_resource->muzzleVelocity == Vector3D::Identity
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing MuzzleVelocity!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (strcmp(muzzle_velocity_text, "Unspecified") != 0)
|
||||
{
|
||||
Convert_From_Ascii(
|
||||
muzzle_velocity_text, &subsystem_resource->muzzleVelocity);
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
return True;
|
||||
}
|
||||
|
||||
@@ -883,3 +883,136 @@ void
|
||||
{
|
||||
UpdateWatch();
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// CreateStreamedSubsystem -- binary @004b13ac (declared in POWERSUB.HPP all
|
||||
// along; the definition was the gap). Chains the shared heat-record parser
|
||||
// (@004ae150 -- HeatSink adds no keys, so the chain call is Heatable's),
|
||||
// stamps classID 0x0BC2 / size 0x190, then the electrical block: the
|
||||
// REQUIRED "VoltageSource" subsystem link (+2 segment-table bias), the
|
||||
// thermal resistivity, the aux/eng screen plumbing the cockpit reads
|
||||
// (AuxScreenPlacement optional; AuxScreenNumber/labels required), and
|
||||
// "StartTime".
|
||||
//#############################################################################
|
||||
//
|
||||
int
|
||||
PoweredSubsystem::CreateStreamedSubsystem(
|
||||
NotationFile *model_file,
|
||||
const char *model_name,
|
||||
const char *subsystem_name,
|
||||
SubsystemResource *subsystem_resource,
|
||||
NotationFile *subsystem_file,
|
||||
const ResourceDirectories *directories,
|
||||
int passes
|
||||
)
|
||||
{
|
||||
if (
|
||||
!HeatableSubsystem::CreateStreamedSubsystem(
|
||||
model_file, model_name, subsystem_name,
|
||||
subsystem_resource, subsystem_file, directories, passes
|
||||
)
|
||||
)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
subsystem_resource->subsystemModelSize = 0x190;
|
||||
subsystem_resource->classID = RegisteredClass::PoweredSubsystemClassID;
|
||||
|
||||
if (passes == 1)
|
||||
{
|
||||
subsystem_resource->voltageSourceIndex = -1;
|
||||
subsystem_resource->thermalResistivityCoefficient = -1.0f;
|
||||
subsystem_resource->auxScreenNumber = -1;
|
||||
subsystem_resource->auxScreenPlacement = -1;
|
||||
memset(subsystem_resource->auxScreenLabel, 0,
|
||||
sizeof(subsystem_resource->auxScreenLabel));
|
||||
memset(subsystem_resource->engScreenLabel, 0,
|
||||
sizeof(subsystem_resource->engScreenLabel));
|
||||
subsystem_resource->startTime = -1.0f;
|
||||
}
|
||||
|
||||
const char
|
||||
*voltage_source_name = "Unspecified";
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "VoltageSource",
|
||||
&voltage_source_name)
|
||||
&& subsystem_resource->voltageSourceIndex == -1
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing VoltageSource!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (strcmp(voltage_source_name, "Unspecified") != 0)
|
||||
{
|
||||
subsystem_resource->voltageSourceIndex =
|
||||
Find_Subsystem_Index(subsystem_file, voltage_source_name);
|
||||
}
|
||||
if (subsystem_resource->voltageSourceIndex < 0)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " has an invalid voltage source!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (strcmp(voltage_source_name, "Unspecified") != 0)
|
||||
{
|
||||
subsystem_resource->voltageSourceIndex += 2;
|
||||
}
|
||||
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "ThermalResistivityCoefficient",
|
||||
&subsystem_resource->thermalResistivityCoefficient)
|
||||
&& subsystem_resource->thermalResistivityCoefficient == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing ThermalResistivityCoefficient!" << endl;
|
||||
return False;
|
||||
}
|
||||
|
||||
subsystem_file->GetEntry(subsystem_name, "AuxScreenPlacement",
|
||||
&subsystem_resource->auxScreenPlacement);
|
||||
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "AuxScreenNumber",
|
||||
&subsystem_resource->auxScreenNumber)
|
||||
&& subsystem_resource->auxScreenNumber == -1
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing AuxScreenNumber!" << endl;
|
||||
return False;
|
||||
}
|
||||
|
||||
const char
|
||||
*label;
|
||||
if (subsystem_file->GetEntry(subsystem_name, "AuxScreenLabel", &label))
|
||||
{
|
||||
strcpy(subsystem_resource->auxScreenLabel, label);
|
||||
}
|
||||
else if (subsystem_resource->auxScreenLabel[0] == '\0')
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing AuxScreenLabel!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (subsystem_file->GetEntry(subsystem_name, "EngScreenLabel", &label))
|
||||
{
|
||||
strcpy(subsystem_resource->engScreenLabel, label);
|
||||
}
|
||||
else if (subsystem_resource->engScreenLabel[0] == '\0')
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing EngScreenLabel!" << endl;
|
||||
return False;
|
||||
}
|
||||
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "StartTime",
|
||||
&subsystem_resource->startTime)
|
||||
&& subsystem_resource->startTime == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing StartTime!" << endl;
|
||||
return False;
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
return True;
|
||||
}
|
||||
|
||||
@@ -483,3 +483,113 @@ void
|
||||
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// CreateStreamedSubsystem -- binary @004bc7cc (declared in PROJWEAP.HPP all
|
||||
// along; the definition was the gap). Chains the weapon record, keeps the
|
||||
// weapon-base classID (the concrete launcher re-stamps after), size 0x1D0,
|
||||
// then the projectile block: TracerInterval, the REQUIRED "AmmoBin"
|
||||
// subsystem link (+2 segment-table bias), MinTimeOfFlight, MinJamChance,
|
||||
// MinVoltagePercentToFire.
|
||||
//#############################################################################
|
||||
//
|
||||
int
|
||||
ProjectileWeapon::CreateStreamedSubsystem(
|
||||
ResourceFile *resource_file,
|
||||
NotationFile *model_file,
|
||||
const char *model_name,
|
||||
const char *subsystem_name,
|
||||
SubsystemResource *subsystem_resource,
|
||||
NotationFile *subsystem_file,
|
||||
const ResourceDirectories *directories,
|
||||
int passes
|
||||
)
|
||||
{
|
||||
if (
|
||||
!MechWeapon::CreateStreamedSubsystem(
|
||||
resource_file, model_file, model_name, subsystem_name,
|
||||
subsystem_resource, subsystem_file, directories, passes
|
||||
)
|
||||
)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
subsystem_resource->subsystemModelSize = 0x1D0;
|
||||
|
||||
if (passes == 1)
|
||||
{
|
||||
subsystem_resource->tracerInterval = -1;
|
||||
subsystem_resource->ammoBinIndex = -1;
|
||||
subsystem_resource->minTimeOfFlight = -1.0f;
|
||||
subsystem_resource->minVoltagePercentToFire = -1.0f;
|
||||
subsystem_resource->minJamChance = -1.0f;
|
||||
}
|
||||
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "TracerInterval",
|
||||
&subsystem_resource->tracerInterval)
|
||||
&& subsystem_resource->tracerInterval == -1
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing TracerInterval!" << endl;
|
||||
return False;
|
||||
}
|
||||
|
||||
const char
|
||||
*ammo_bin_name = "Unspecified";
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "AmmoBin", &ammo_bin_name)
|
||||
&& subsystem_resource->ammoBinIndex == -1
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing AmmoBin!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (strcmp(ammo_bin_name, "Unspecified") != 0)
|
||||
{
|
||||
subsystem_resource->ammoBinIndex =
|
||||
Find_Subsystem_Index(subsystem_file, ammo_bin_name);
|
||||
}
|
||||
if (subsystem_resource->ammoBinIndex < 0)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " has an invalid Ammo Bin!" << endl;
|
||||
return False;
|
||||
}
|
||||
if (strcmp(ammo_bin_name, "Unspecified") != 0)
|
||||
{
|
||||
subsystem_resource->ammoBinIndex += 2;
|
||||
}
|
||||
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "MinTimeOfFlight",
|
||||
&subsystem_resource->minTimeOfFlight)
|
||||
&& subsystem_resource->minTimeOfFlight == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing MinTimeOfFlight !" << endl;
|
||||
return False;
|
||||
}
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "MinJamChance",
|
||||
&subsystem_resource->minJamChance)
|
||||
&& subsystem_resource->minJamChance == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing MinJamChance !" << endl;
|
||||
return False;
|
||||
}
|
||||
if (
|
||||
!subsystem_file->GetEntry(subsystem_name, "MinVoltagePercentToFire",
|
||||
&subsystem_resource->minVoltagePercentToFire)
|
||||
&& subsystem_resource->minVoltagePercentToFire == -1.0f
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << subsystem_name << " missing MinVoltagePercentToFire !" << endl;
|
||||
return False;
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
return True;
|
||||
}
|
||||
|
||||
@@ -1,126 +1,142 @@
|
||||
//===========================================================================//
|
||||
// File: projweap.hpp //
|
||||
// Project: BattleTech Brick: Mech weapons //
|
||||
// Contents: ProjectileWeapon -- the ballistic (ammo-fed) weapon base //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide //
|
||||
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
||||
//===========================================================================//
|
||||
|
||||
#if !defined(PROJWEAP_HPP)
|
||||
# define PROJWEAP_HPP
|
||||
|
||||
# if !defined(MECHWEAP_HPP)
|
||||
# include <mechweap.hpp>
|
||||
# endif
|
||||
# if !defined(POINT3D_HPP)
|
||||
# include <point3d.hpp>
|
||||
# endif
|
||||
|
||||
//##################### Forward Class Declarations #######################
|
||||
class Mech;
|
||||
|
||||
//###########################################################################
|
||||
//################ ProjectileWeapon Model Resource #####################
|
||||
//###########################################################################
|
||||
|
||||
//
|
||||
// WIRE-VERIFIED layout (raw-stream dump, TEST.EGG SRM6s): tracerInterval
|
||||
// reads 1, ammoBinIndex the true bin roster slot (27/29), minTimeOfFlight
|
||||
// 0.5, minVoltagePercentToFire 0.3, minJamChance 0.05, and
|
||||
// MissileLauncher's missileCount lands on 6 (an SRM6!). (The interim
|
||||
// alignment pad is gone -- the ancestry shortfall was the HeatSink
|
||||
// linkedSinkIndex + the MechWeapon pip tail, both now real fields.)
|
||||
//
|
||||
struct ProjectileWeapon__SubsystemResource:
|
||||
public MechWeapon::SubsystemResource
|
||||
{
|
||||
int tracerInterval;
|
||||
int ammoBinIndex;
|
||||
Scalar minTimeOfFlight;
|
||||
Scalar minVoltagePercentToFire;
|
||||
Scalar minJamChance;
|
||||
};
|
||||
|
||||
//###########################################################################
|
||||
//######################### ProjectileWeapon ###########################
|
||||
//###########################################################################
|
||||
|
||||
class ProjectileWeapon:
|
||||
public MechWeapon
|
||||
{
|
||||
public:
|
||||
static Derivation ClassDerivations;
|
||||
static SharedData DefaultData;
|
||||
|
||||
static Logical
|
||||
TestClass(Mech &);
|
||||
Logical
|
||||
TestInstance() const;
|
||||
|
||||
virtual void
|
||||
FireWeapon();
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Per-frame simulation (the ballistic fire state machine).
|
||||
//
|
||||
public:
|
||||
typedef void
|
||||
(ProjectileWeapon::*Performance)(Scalar time_slice);
|
||||
void
|
||||
SetPerformance(Performance performance)
|
||||
{
|
||||
Check(this);
|
||||
activePerformance = (Simulation::Performance)performance;
|
||||
}
|
||||
|
||||
void
|
||||
ProjectileWeaponSimulation(Scalar time_slice);
|
||||
Logical
|
||||
CheckForJam();
|
||||
|
||||
//
|
||||
// The "sim live" novice lockout (the owning BTPlayer's simLive
|
||||
// experience flag): novice ballistics never jam.
|
||||
//
|
||||
Logical
|
||||
LiveFireEnabled();
|
||||
|
||||
public:
|
||||
typedef ProjectileWeapon__SubsystemResource SubsystemResource;
|
||||
|
||||
ProjectileWeapon(
|
||||
Mech *owner,
|
||||
int subsystem_ID,
|
||||
SubsystemResource *subsystem_resource,
|
||||
SharedData &shared_data = DefaultData
|
||||
);
|
||||
~ProjectileWeapon();
|
||||
|
||||
//
|
||||
// The linked bin's round count, or -1 when no bin is linked. The
|
||||
// cockpit's ammo readout needs this from BT_L4 and the link itself
|
||||
// is protected (the binary read the resolved bin's count direct).
|
||||
//
|
||||
int
|
||||
GetAmmoCount();
|
||||
|
||||
protected:
|
||||
SubsystemConnection ammoBinLink;
|
||||
int tracerInterval;
|
||||
int tracerCounter;
|
||||
int ejectState;
|
||||
Scalar totalTimeToEject;
|
||||
Scalar timeToEject;
|
||||
Scalar percentOfEject;
|
||||
Scalar minJamChance;
|
||||
Scalar minTimeOfFlight;
|
||||
Scalar minVoltagePercentToFire;
|
||||
Vector3D launchVelocity;
|
||||
Vector3D tracerOrigin;
|
||||
Point3D leadPosition;
|
||||
int tracerModelHandle;
|
||||
};
|
||||
|
||||
#endif
|
||||
//===========================================================================//
|
||||
// File: projweap.hpp //
|
||||
// Project: BattleTech Brick: Mech weapons //
|
||||
// Contents: ProjectileWeapon -- the ballistic (ammo-fed) weapon base //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide //
|
||||
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
||||
//===========================================================================//
|
||||
|
||||
#if !defined(PROJWEAP_HPP)
|
||||
# define PROJWEAP_HPP
|
||||
|
||||
# if !defined(MECHWEAP_HPP)
|
||||
# include <mechweap.hpp>
|
||||
# endif
|
||||
# if !defined(POINT3D_HPP)
|
||||
# include <point3d.hpp>
|
||||
# endif
|
||||
|
||||
//##################### Forward Class Declarations #######################
|
||||
class Mech;
|
||||
|
||||
//###########################################################################
|
||||
//################ ProjectileWeapon Model Resource #####################
|
||||
//###########################################################################
|
||||
|
||||
//
|
||||
// WIRE-VERIFIED layout (raw-stream dump, TEST.EGG SRM6s): tracerInterval
|
||||
// reads 1, ammoBinIndex the true bin roster slot (27/29), minTimeOfFlight
|
||||
// 0.5, minVoltagePercentToFire 0.3, minJamChance 0.05, and
|
||||
// MissileLauncher's missileCount lands on 6 (an SRM6!). (The interim
|
||||
// alignment pad is gone -- the ancestry shortfall was the HeatSink
|
||||
// linkedSinkIndex + the MechWeapon pip tail, both now real fields.)
|
||||
//
|
||||
struct ProjectileWeapon__SubsystemResource:
|
||||
public MechWeapon::SubsystemResource
|
||||
{
|
||||
int tracerInterval;
|
||||
int ammoBinIndex;
|
||||
Scalar minTimeOfFlight;
|
||||
Scalar minVoltagePercentToFire;
|
||||
Scalar minJamChance;
|
||||
};
|
||||
|
||||
//###########################################################################
|
||||
//######################### ProjectileWeapon ###########################
|
||||
//###########################################################################
|
||||
|
||||
class ProjectileWeapon:
|
||||
public MechWeapon
|
||||
{
|
||||
public:
|
||||
static Derivation ClassDerivations;
|
||||
static SharedData DefaultData;
|
||||
|
||||
static Logical
|
||||
TestClass(Mech &);
|
||||
Logical
|
||||
TestInstance() const;
|
||||
|
||||
virtual void
|
||||
FireWeapon();
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Per-frame simulation (the ballistic fire state machine).
|
||||
//
|
||||
public:
|
||||
typedef void
|
||||
(ProjectileWeapon::*Performance)(Scalar time_slice);
|
||||
void
|
||||
SetPerformance(Performance performance)
|
||||
{
|
||||
Check(this);
|
||||
activePerformance = (Simulation::Performance)performance;
|
||||
}
|
||||
|
||||
void
|
||||
ProjectileWeaponSimulation(Scalar time_slice);
|
||||
Logical
|
||||
CheckForJam();
|
||||
|
||||
//
|
||||
// The "sim live" novice lockout (the owning BTPlayer's simLive
|
||||
// experience flag): novice ballistics never jam.
|
||||
//
|
||||
Logical
|
||||
LiveFireEnabled();
|
||||
|
||||
public:
|
||||
typedef ProjectileWeapon__SubsystemResource SubsystemResource;
|
||||
|
||||
//
|
||||
// The authoring-side stream converter (binary @004bc7cc); defined in
|
||||
// projweap.cpp.
|
||||
//
|
||||
static int
|
||||
CreateStreamedSubsystem(
|
||||
ResourceFile *resource_file,
|
||||
NotationFile *model_file,
|
||||
const char *model_name,
|
||||
const char *subsystem_name,
|
||||
SubsystemResource *subsystem_resource,
|
||||
NotationFile *subsystem_file,
|
||||
const ResourceDirectories *directories,
|
||||
int passes = 1
|
||||
);
|
||||
|
||||
ProjectileWeapon(
|
||||
Mech *owner,
|
||||
int subsystem_ID,
|
||||
SubsystemResource *subsystem_resource,
|
||||
SharedData &shared_data = DefaultData
|
||||
);
|
||||
~ProjectileWeapon();
|
||||
|
||||
//
|
||||
// The linked bin's round count, or -1 when no bin is linked. The
|
||||
// cockpit's ammo readout needs this from BT_L4 and the link itself
|
||||
// is protected (the binary read the resolved bin's count direct).
|
||||
//
|
||||
int
|
||||
GetAmmoCount();
|
||||
|
||||
protected:
|
||||
SubsystemConnection ammoBinLink;
|
||||
int tracerInterval;
|
||||
int tracerCounter;
|
||||
int ejectState;
|
||||
Scalar totalTimeToEject;
|
||||
Scalar timeToEject;
|
||||
Scalar percentOfEject;
|
||||
Scalar minJamChance;
|
||||
Scalar minTimeOfFlight;
|
||||
Scalar minVoltagePercentToFire;
|
||||
Vector3D launchVelocity;
|
||||
Vector3D tracerOrigin;
|
||||
Point3D leadPosition;
|
||||
int tracerModelHandle;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -238,17 +238,38 @@ void
|
||||
// (see MECHSUB.NOTES.md -- the 4.10 subsystem stream format).
|
||||
//#############################################################################
|
||||
//
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// CreateStreamedSubsystem -- binary @004b1dcc: chain the powered-record
|
||||
// parser, stamp classID 0x0BC3 / size 0x190. The Sensor record is an empty
|
||||
// extension of the PoweredSubsystem record.
|
||||
//#############################################################################
|
||||
//
|
||||
int
|
||||
Sensor::CreateStreamedSubsystem(
|
||||
NotationFile *,
|
||||
const char *,
|
||||
const char *,
|
||||
SubsystemResource *,
|
||||
NotationFile *,
|
||||
const ResourceDirectories *,
|
||||
int
|
||||
NotationFile *model_file,
|
||||
const char *model_name,
|
||||
const char *subsystem_name,
|
||||
SubsystemResource *subsystem_resource,
|
||||
NotationFile *subsystem_file,
|
||||
const ResourceDirectories *directories,
|
||||
int passes
|
||||
)
|
||||
{
|
||||
Fail("Sensor::CreateStreamedSubsystem -- sensor.cpp not yet reconstructed");
|
||||
return 0;
|
||||
if (
|
||||
!PoweredSubsystem::CreateStreamedSubsystem(
|
||||
model_file, model_name, subsystem_name,
|
||||
subsystem_resource, subsystem_file, directories, passes
|
||||
)
|
||||
)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
subsystem_resource->subsystemModelSize = 0x190;
|
||||
subsystem_resource->classID = RegisteredClass::SensorClassID;
|
||||
|
||||
Check_Fpu();
|
||||
return True;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user