Files
BT412/game/reconstructed/projtile.hpp
T
arcattackandClaude Opus 4.8 7b7d465e5e Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.

Layout:
  engine/   MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
            work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
            models) + image codec; the minimal rp/ headers the audio HAL needs
  game/     reconstructed BT logic + surviving-original BT source + fwd shims
            + WinMain launcher
  content/  full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
  docs/     format specs + reconstruction ledgers
  reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
  tools/    MP console emulator + map/resource scanners

One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 21:03:40 -05:00

164 lines
7.1 KiB
C++

//============================================================================//
// File: projtile.hpp //
// Project: BattleTech //
// Contents: In-flight projectile entity base (position/velocity/lifetime/ //
// collision); parent of Missile. //
//----------------------------------------------------------------------------//
// 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
// @004be1bc-@004be3b4 in part_013.c). NO surviving header exists for this base
// -- only the test fragment PROJTILE.TCP (Projectile::TestClass). The class
// declaration is INFERRED from:
// * the decompiled ctor @004be1bc, dtor @004be358 and allocator @004be384
// * the derived Missile (missile.hpp/cpp), whose integrator @004bef78 reads
// these base fields (position @0x100, velocity @0x1DC, segment/world @0x300)
// * PROJTILE.TCP (Projectile::TestClass -- note: takes NO argument)
// Member names past the Entity base are best-effort and flagged.
//
// Inheritance chain established from the decomp:
// Entity (FUN_004234f0 base ctor) -> Projectile (vtable @00512a5c, 0x340)
// -> Missile (vtable @00512f2c, 0x368)
// The ctor stamps vtable PTR_FUN_00512a5c, registers the projectile into the
// owning world-segment table, snapshots the launch kinematics out of the spawn
// descriptor, and installs one of two Performance variants (authoritative vs
// network-ghost) selected by the entity flags (this+0x28 & 0xC == 4).
//
// Object byte offsets (this is an int* in the decomp, word index in parens).
// Everything below +0x300 is the Entity base (transform @0x100, velocity @0x1DC,
// thrust-velocity @0x1E8, born/spawn ticks @0x10/@0x14, status flags @0x18).
//
#if !defined (PROJTILE_HPP)
# define PROJTILE_HPP
# if !defined(ENTITY_HPP)
# include <entity.hpp> // Projectile : Entity
# endif
# if !defined(POINT3D_HPP)
# include <point3d.hpp>
# endif
//######################### Forward Class Declarations ########################
class Mech;
class Segment;
//###########################################################################
//######################### CLASS -- Projectile #######################
//###########################################################################
//
// (vtable @00512a5c, ctor @004be1bc, dtor @004be358, allocator @004be384.)
//
class Projectile:
public Entity
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data Support
//
public:
static Derivation ClassDerivations; // IsDerivedFrom tag 0x512980
static Receiver::MessageHandlerSet MessageHandlers;
static AttributeIndexSet AttributeIndex;
static SharedData DefaultData; // resolved as &DAT_005129b0
// Entity factory hook (Entity::SharedData requires a MakeHandler).
static Entity *Make(MakeMessage *creation_message);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Model Support
//
public:
typedef void
(Projectile::*Performance)(Scalar time_slice);
// The default per-frame integrate-and-collide pass. Installed by the
// ctor as the active Performance: PTR_LAB_005129e8 when authoritative
// (flags & 0xC == 4), PTR_LAB_005129f4 for a network ghost. Missile
// supplies its own override (Missile::MoveAndCollide @004bef78).
void
MoveAndCollide(Scalar time_slice);
void
SetPerformance(Performance performance)
{
Check(this);
activePerformance = (Simulation::Performance)performance;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// TestClass Support (PROJTILE.TCP)
//
public:
static Logical
TestClass(); // PROJTILE.TCP: returns True
Logical
TestInstance() const; // @004be3b4
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:
Projectile( // @004be1bc
int owner, // spawning weapon / streamed-entity ctx
const char *spawn_descriptor // launch descriptor record
);
~Projectile(); // @004be358
// @004be384 -- allocate (0x340 bytes) and construct with &DAT_005129b0.
static Projectile *
New(int spawn_context);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Model / animation update binding (Entity sub-object)
//
// this[0x94..0x97] = a bound member-function ("model update" callback,
// PTR_FUN_005129dc) invoked each frame; 0x250 is its context pointer.
//
protected:
void *modelUpdateContext; // @0x250 (word 0x94)
// hosted-subsystem roster (used by Missile; Projectile-level per the decomp)
int subsystemCount; // @0x124 (word 0x49)
Subsystem **subsystems; // @0x128 (word 0x4a)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Recovered internal helpers (engine-internal artifacts in the decomp;
// declared here so the recovered ctor / integrator compile. Bodies are
// reconstructed structurally -- the world/segment/motion plumbing lives in
// the Entity engine layer).
//
protected:
void InitSegmentLink(void *link); // FUN_0041db7c
void SetStatusLevel(int level); // FUN_0041bbd8 (status alarm)
void *ResolveWorld(void *app_context); // owning world / segment system
void *ResolveMotionSource(void *app_context); // FUN_00433ed4
void BindModelUpdate(void *callback); // bind model-update member fn
void IntegrateMotion(); // FUN_00421b2c
void AdvanceModel(Scalar time_slice); // FUN_00421bac
Entity *CollisionQuery(Scalar time_slice); // FUN_0042291c
void Retire(); // FUN_0042061c
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Projectile-specific data appended past the Entity base (offsets best-effort).
//
protected:
void *world; // @0x300 (word 0xC0) owning world / segment system
Segment *currentSegment; // @0x304 (word 0xC1) segment node for this cell
int segmentIndex; // @0x308 (word 0xC2) descriptor +0x84
int sourceEntity; // @0x30C (word 0xC3) descriptor +0x88 (firing entity)
int sourceWeapon; // @0x310 (word 0xC4) descriptor +0x8C (firing weapon)
Point3D launchPosition; // @0x314 (word 0xC5) descriptor +0x90
Vector3D launchVelocity; // @0x320 (word 0xC8) descriptor +0x9C
Vector3D aimDirection; // @0x32C (word 0xCB) descriptor +0xA8
int modelIndex; // @0x338 (word 0xCE) descriptor +0xB4 (tracer/LOD model)
int damageRecord; // @0x33C (word 0xCF) descriptor +0xB8 (damage/team id)
};
#endif