//===========================================================================// // File: mislanch.cpp // // Project: BattleTech Brick: Mech weapons // // Contents: MissileLauncher -- a projectile weapon that fires missile salvos // //---------------------------------------------------------------------------// // Copyright (C) 1995, Virtual World Entertainment, Inc. // // All Rights reserved worldwide // // This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL // //===========================================================================// #include #pragma hdrstop #if !defined(MISLANCH_HPP) # include #endif #if !defined(MECH_HPP) # include #endif #if !defined(MISSILE_HPP) # include #endif #if !defined(APP_HPP) # include #endif #if !defined(HOSTMGR_HPP) # include #endif // // STAGED launch speed (the binary derives it from the authored // MuzzleVelocity vector -- the muzzle wave). // static const Scalar kMissileLaunchSpeed = 150.0f; // u/s Derivation MissileLauncher::ClassDerivations( ProjectileWeapon::ClassDerivations, "MissileLauncher" ); MissileLauncher::SharedData MissileLauncher::DefaultData( MissileLauncher::ClassDerivations, Subsystem::MessageHandlers, Subsystem::AttributeIndex, Subsystem::StateCount ); MissileLauncher::MissileLauncher( Mech *owner, int subsystem_ID, SubsystemResource *subsystem_resource, SharedData &default_data ): ProjectileWeapon(owner, subsystem_ID, subsystem_resource, default_data) { Check(owner); Check_Pointer(subsystem_resource); missileCount = subsystem_resource->missileCount; // // A salvo delivers missileCount missiles; split the per-shot damage across // the salvo. (The per-missile launch mechanics live in FireWeapon, staged.) // if (missileCount > 0) { damageData.burstCount = missileCount; damageData.damageAmount = damageData.damageAmount / (Scalar)missileCount; } Check_Fpu(); } MissileLauncher::~MissileLauncher() { } Logical MissileLauncher::TestInstance() const { return IsDerivedFrom(ClassDerivations); } // //############################################################################# // Damage / death. //############################################################################# // void MissileLauncher::TakeDamage(Damage &damage) { Check(this); ProjectileWeapon::TakeDamage(damage); } void MissileLauncher::DeathReset(Logical /*full_reset*/) { Check(this); } // // The missile-salvo discharge. Not yet reconstructed. // void MissileLauncher::FireWeapon() { Check(this); // // PARTIAL (binary @004bcc60): the authentic body launches missileCount // Missile entities toward the owner's target (each carrying the salvo-split // damageData) and dumps the firing heat. The Missile entity spawn needs // the entity-spawn + targeting waves; the view/target gate, ammo pull and // recoil all live in the CALLER (ProjectileWeaponSimulation's Loaded case). // // Ballistic heatCostToFire is stored 1e7-unit-NATIVE in the stream (SRM6 // reads 5.06e7 = +641K on its own sink -- the same design magnitude as the // PPC's +632K); dump it raw, under the heat-model experience gate (novice / // standard fire generates no heat -- authentic). (The EMITTER's authored // value is small and its 1e7 comes from the energy algebra.) if (HeatModelActive()) { AddPendingHeat(heatCostToFire); } // // The salvo launch (binary @004bcc60): ONE cluster Missile entity per // trigger, spawned through the Mover make machinery -- the MakeMessage's // resourceID is this weapon's projectile GameModel (explosionResourceID // @0x3e4), so the Mover base streams the authored mass/drag. The round // carries the salvo-split cluster damage record (burstCount = // missileCount rides into the gyro bounce + splash) and homes via its // Seeker; the proximity fuse delivers the damage ONCE (the arcade // economy, BT411 task #62). Muzzle = the mech origin STAGED (the // authored MuzzleVelocity arc through the MOUNT segment frame is the // muzzle wave). If the projectile model resource is absent the launch // falls back to the 5.3.16 instant-hit delivery. // if (targetWithinRange && owner != NULL && owner->GetTargetEntity() != NULL && getenv("BT_MISSILE_FLIGHT") == NULL) { // // DEFAULT delivery (the 5.3.18a arcade economy): the instant-hit // cluster message. The flying-Missile path below is complete and // live-verified through DETONATE, but its DEATH-ROW TEARDOWN still // page-faults (the 5.3.18 frontier, MISSILE.NOTES.md) -- opt in // with BT_MISSILE_FLIGHT=1 until the dtor chain is closed. // SendDamage(owner->GetTargetEntity(), damageData); } else if (targetWithinRange && owner != NULL && owner->GetTargetEntity() != NULL) { // // The MakeMessage's resourceID must be a resource FAMILY id -- the // Mover base ctor runs its own SearchList(resourceID, GameModel), // and SearchList CRASHES (engine @0x414938) when the id isn't in // the top-level directory (member resources resolve only through // their family head). The streamed explosionModelFile is a small // INDEX (SRM6 reads 17) into a model list -- decoding it into the // real projectile family is the projectile-model brick. Until // then the round spawns on the OWNER's family (its GameModel // member provably streams every boot -- the mech model params); // our staged flight integration reads none of the Mover mass/drag. // { HostManager *host_manager = application->GetHostManager(); Check(host_manager); Origin muzzle = owner->localOrigin; Mover::MakeMessage spawn_round( Entity::MakeMessageID, sizeof(Mover::MakeMessage), EntityID(host_manager->GetLocalHostID()), (Entity::ClassID)MissileClassID, EntityID::Null, owner->GetResourceID(), Entity::DefaultFlags, muzzle, Motion::Identity, Motion::Identity ); Missile *round = new Missile(&spawn_round); Register_Object(round); round->Launch( owner, owner->GetTargetEntity(), damageData, kMissileLaunchSpeed ); } } if (getenv("BT_MECH_LOG")) { DEBUG_STREAM << "[fire] '" << GetName() << "' FIRED (salvo of " << missileCount << ", recharge=" << rechargeRate << "s heat+=" << heatCostToFire << ")" << endl << flush; } } // // Model-load-time construction. Not yet reconstructed. // Logical MissileLauncher::CreateStreamedSubsystem( ResourceFile *, NotationFile *, const char *, const char *, SubsystemResource *, NotationFile *, const ResourceDirectories *, int ) { Fail("MissileLauncher::CreateStreamedSubsystem -- mislanch.cpp not yet reconstructed"); return False; }