//============================================================================// // File: mislanch.hpp // // Project: BattleTech // // Contents: Weapon Which Launches a missile // // Derived From Projectile Weapon // //----------------------------------------------------------------------------// // Date Who Modification // // -------- --- ------------------------------------------------------------// // 04/13/95 JM Initial coding. // //----------------------------------------------------------------------------// // Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved // // PROPRIETARY AND CONFIDENTIAL // //============================================================================// // // RECONSTRUCTED from the shipped binary (Ghidra pseudo-C, module cluster // @004bcff0-@004bd08c in part_013.c) cross-referenced HEAVILY against the // SURVIVING MISLANCH.HPP and the reconstructed mechweap.hpp base. The class // declaration below is the surviving header; the only additions are the byte // offsets observed in the decompiled object (see mislanch.cpp for @ADDRs). // // Inheritance chain established from the decomp: // MechWeapon (mechweap.cpp, vtable @00511d2c) // -> ProjectileWeapon (ctor @004bc3fc, vtable @0051242c) ammo/jam/tracer // -> MissileLauncher (ctor @004bcff0, vtable @00512570) // // The MissileLauncher ctor (@004bcff0) chains ProjectileWeapon::ProjectileWeapon // (@004bc3fc), installs PTR_FUN_00512570, then reads the two launcher-specific // resource fields MissileCount (+0x1d0) and MuzzleVelocity (+0x1d4, Vector3D) // and divides the configured damage by missileCount (per-missile damage). // #if !defined (MISLANCH_HPP) # define MISLANCH_HPP # if !defined(PROJWEAP_HPP) # include # endif class Missile; //################# MissileLauncher SubsystemResource ################### // // Extends the ProjectileWeapon resource. Parsed by CreateStreamedSubsystem // @004bd08c (which chains ProjectileWeapon::CreateStreamedSubsystem @004bc7cc). // Record offsets are relative to the streamed subsystem record: // +0x1d0 "MissileCount" int // +0x1d4 "MuzzleVelocity" Vector3D (3 floats) // struct MissileLauncher__SubsystemResource: public ProjectileWeapon::SubsystemResource { int missileCount; // +0x1d0 "MissileCount" Vector3D muzzleVelocity; // +0x1d4 "MuzzleVelocity" }; //########################################################################### //################# CLASS -- MissileLauncher ########################## //########################################################################### // // (vtable @00512570, ctor @004bcff0, dtor @004bd060.) // class MissileLauncher: public ProjectileWeapon { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Messaging Support // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Shared Data Support // public: static Derivation ClassDerivations; static Receiver::MessageHandlerSet& GetMessageHandlers(); // inherits ProjectileWeapon's (task #6) static AttributeIndexSet AttributeIndex; static SharedData DefaultData; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Attribute Support // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Damage Support // public: void TakeDamage(Damage &damage); // inherits MechWeapon::TakeDamage (vtable slot 6, @004b964c) void DeathReset(Logical full_reset); // best-effort -- chains ProjectileWeapon reset @004bbaf8 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Replication Support (PORT record extension -- missile-visibility wave) // // In the 1995 binary a fired Missile was a REPLICATED WORLD ENTITY (its // own update records, tag 0x78), so the peer pod rendered the round from // entity replication and the launcher's record stayed the MechWeapon // base. The port's flying round is a LOCAL tracked projectile // (BTPushProjectile) -- invisible to peers -- so the launcher's record // carries the SALVO EVENT instead: a fire counter + the aim point + the // round count. The replicant-side reader edge-detects the counter and // launches a VISUAL-ONLY mirror salvo (damage 0; the master's own rounds // deliver damage cross-pod through TakeDamage). Both nodes run this // port, so the extended wire format is self-consistent. Salvo STATE // lives in a port-side table (mislanch.cpp) -- the object layout is // byte-locked to the 0x44C factory alloc and must not grow. // public: struct MissileLauncher__UpdateRecord: public MechWeapon::UpdateRecord { int salvoCounter; // fires since spawn (edge-detected by peers) int salvoRounds; // missiles in the salvo (authored missileCount) Point3D salvoTarget; // the aim point the salvo flew at }; typedef MissileLauncher__UpdateRecord UpdateRecord; void WriteUpdateRecord(Simulation__UpdateRecord *message, int update_model); // base-typed param (task #51 override rule) void ReadUpdateRecord(Simulation__UpdateRecord *message); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Model Support // public: typedef void (MissileLauncher::*Performance)(Scalar time_slice); void SetPerformance(Performance performance) { Check(this); activePerformance = (Simulation::Performance)performance; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Construction and Destruction // public: typedef MissileLauncher__SubsystemResource SubsystemResource; MissileLauncher( // @004bcff0 Mech *owner, int subsystem_ID, SubsystemResource *subsystem_resource, SharedData &default_data = DefaultData ); ~MissileLauncher(); // @004bd060 Logical TestInstance() const; static Logical CreateStreamedSubsystem( // @004bd08c 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 ); // local stuff protected: // @004bcc60 (ProjectileWeapon spawn path) -- builds the streamed-entity // spawn descriptor for ONE Missile (entity ClassID 0xBD0), seeds it with // muzzleVelocity + the per-missile Damage (authored/missileCount) and the // burstCount cluster-hit roll, and hands it to the entity manager. // (task #60 correction: ONE spawn per trigger pull, NOT missileCount // spawns -- burstCount carries the cluster count to the single missile; // the PORT re-expresses this as N flying rounds, see mislanch.cpp.) void FireWeapon(); // The ONLY own field: missileCount@0x448 (ctor param_1[0x112]). The former // salvoCount@0x3d4 was a SHADOW of the inherited MechWeapon damageData.burstCount // (@0x3A8+0x2C), and muzzleVelocity@0x410 an ALIAS of the inherited ProjectileWeapon // launchVelocity -- both re-declared as own members put them at wrong (appended) // offsets; removed. Object ends 0x44C. int missileCount; // @0x448 (this[0x112]) -- how many missiles per salvo (LAST field) friend struct MissileLauncherLayoutCheck; }; struct MissileLauncherLayoutCheck { static_assert(offsetof(MissileLauncher, missileCount) == 0x448, "MissileLauncher::missileCount @0x448 (ProjectileWeapon must end 0x448)"); static_assert(sizeof(MissileLauncher) == 0x44C, "sizeof(MissileLauncher) 0x44C (== factory alloc)"); }; #endif