diff --git a/restoration/source410/BT/EMITTER.CPP b/restoration/source410/BT/EMITTER.CPP index 7f68f579..15185618 100644 --- a/restoration/source410/BT/EMITTER.CPP +++ b/restoration/source410/BT/EMITTER.CPP @@ -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; } diff --git a/restoration/source410/BT/HEAT.CPP b/restoration/source410/BT/HEAT.CPP index 18942e6a..13fde9ba 100644 --- a/restoration/source410/BT/HEAT.CPP +++ b/restoration/source410/BT/HEAT.CPP @@ -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; } //########################################################################### diff --git a/restoration/source410/BT/MECHSUB.CPP b/restoration/source410/BT/MECHSUB.CPP index 022b3d0a..b3a91ab9 100644 --- a/restoration/source410/BT/MECHSUB.CPP +++ b/restoration/source410/BT/MECHSUB.CPP @@ -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; } // diff --git a/restoration/source410/BT/MECHTECH.CPP b/restoration/source410/BT/MECHTECH.CPP index 026a5075..24181708 100644 --- a/restoration/source410/BT/MECHTECH.CPP +++ b/restoration/source410/BT/MECHTECH.CPP @@ -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 -#pragma hdrstop -#if !defined(MECHTECH_HPP) -# include -#endif -#if !defined(MECH_HPP) -# include -#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 +#pragma hdrstop +#if !defined(MECHTECH_HPP) +# include +#endif +#if !defined(MECH_HPP) +# include +#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 (" couldn't locate .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; +} diff --git a/restoration/source410/BT/MECHWEAP.CPP b/restoration/source410/BT/MECHWEAP.CPP index fa8e8d71..7fa848ff 100644 --- a/restoration/source410/BT/MECHWEAP.CPP +++ b/restoration/source410/BT/MECHWEAP.CPP @@ -11,6 +11,10 @@ #include #pragma hdrstop +#if !defined(COLOR_HPP) +# include // RGBColor + Convert_From_Ascii (PipColor) +#endif + #if !defined(MECHWEAP_HPP) # include #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; } diff --git a/restoration/source410/BT/MESSMGR.CPP b/restoration/source410/BT/MESSMGR.CPP index cbb3acb3..4969c769 100644 --- a/restoration/source410/BT/MESSMGR.CPP +++ b/restoration/source410/BT/MESSMGR.CPP @@ -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; } diff --git a/restoration/source410/BT/MISLANCH.CPP b/restoration/source410/BT/MISLANCH.CPP index 565bdf58..b7a50768 100644 --- a/restoration/source410/BT/MISLANCH.CPP +++ b/restoration/source410/BT/MISLANCH.CPP @@ -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; } diff --git a/restoration/source410/BT/POWERSUB.CPP b/restoration/source410/BT/POWERSUB.CPP index dc27c290..6ff69708 100644 --- a/restoration/source410/BT/POWERSUB.CPP +++ b/restoration/source410/BT/POWERSUB.CPP @@ -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; +} diff --git a/restoration/source410/BT/PROJWEAP.CPP b/restoration/source410/BT/PROJWEAP.CPP index 29efed1e..2a2a8465 100644 --- a/restoration/source410/BT/PROJWEAP.CPP +++ b/restoration/source410/BT/PROJWEAP.CPP @@ -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; +} diff --git a/restoration/source410/BT/PROJWEAP.HPP b/restoration/source410/BT/PROJWEAP.HPP index 27796546..bdb56ef4 100644 --- a/restoration/source410/BT/PROJWEAP.HPP +++ b/restoration/source410/BT/PROJWEAP.HPP @@ -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 -# endif -# if !defined(POINT3D_HPP) -# include -# 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 +# endif +# if !defined(POINT3D_HPP) +# include +# 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 diff --git a/restoration/source410/BT/SENSOR.CPP b/restoration/source410/BT/SENSOR.CPP index 0d95b17c..fe9ca433 100644 --- a/restoration/source410/BT/SENSOR.CPP +++ b/restoration/source410/BT/SENSOR.CPP @@ -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; }