Supersedes the mislanch change inefc3e9f, which multiplied the lead round by missileCount. That produced roughly the right average total but as ONE lump on ONE zone, with no scatter and no variance -- not what the arcade does. WHAT THE BINARY DOES (all byte-verified): * MissileLauncher ctor @004bcff0: burstCount = missileCount; damageAmount /= missileCount * FireWeapon @004bcc60 spawns exactly ONE Missile -- no loop, missileCount is never read there. The salvo IS one cluster round. * Missile::Perform rolls how many of the cluster connect right before it dispatches (part_013.c:10082): b = Random(n) + n/4, clamped to n -- i.e. between a quarter of the salvo and all of it. * It then dispatches DIRECTLY at the struck entity (FUN_004be078: param_2->Dispatch(&msg)) -- NOT through the shooter's message manager. * Mech::TakeDamageMessageHandler @0x4a0439-0x4a04d8 applies the hit burstCount times, RE-ROLLING the struck zone per burst. Our handler already implements that loop faithfully (mech.cpp, task #80) -- I wrongly believed it was missing, because the KB asserts as [T1] that "burstCount is cosmetic for zone damage". That is half right: DamageZone::TakeDamage really does ignore burstCount (verified @0041e4e0), but the HANDLER honours it by calling that function repeatedly. KB corrected separately. The actual defect was that the projectile impact path hardcoded burstCount = 1, and -- worse -- routed damage through the SubsystemMessageManager, whose consolidation rebuilds the record from a stream carrying only {damageType, damageAmount, subsystemID}. DamageInformation has no burstCount field, so the cluster count was DROPPED in transit no matter what the round carried. So: dispatch projectile damage directly, as the binary does, carrying the rolled burst. This also retires the #84 double explosion architecturally -- the second blast came from the manager's bundled explosion, and projectiles no longer go through the manager at all. The MarkRoundDetonated suppression added inefc3e9fis therefore dead and is removed. ALL-WEAPON-CLASS AUDIT (scratchpad/night8/allweap.{sh,py}), one run, all classes firing at once: EXPLOSIVE (missile) 38 zone applications, bursts spread 1x2,2x6,3x9,4x4,5x5, 6x12 across ELEVEN zones -- the [n/4..n] roll plus the per-burst zone re-roll, i.e. the cluster scattering ENERGY (beam) 8 applications, burst 1 -- unchanged, no regression type4 8 applications, burst 1 -- unchanged COLLISION 0 applications reached armour -- divert intact Explosions: 10 projectile impacts produce no bundled blast; direct-fire still queues its own (11 made). NOT yet verified: cross-pod delivery. Dispatch reroutes to a replicant on its own (and the binary relies on exactly that), but the manager routing is gone, so MP damage should get a two-node run before this ships. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
242 lines
7.3 KiB
C++
242 lines
7.3 KiB
C++
//===========================================================================//
|
|
// File: messmgr.hh //
|
|
// Project: BattleTech //
|
|
// Contents: Consolidates Messages from Subsystems and Graphics Generation //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 09/30/95 JM Initial coding. //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved //
|
|
// PROPRIETARY AND CONFIDENTIAL //
|
|
//===========================================================================//
|
|
//
|
|
// GROUND TRUTH: this header is the surviving MESSMGR.HPP
|
|
// (410SRC/Telsa40/Rel410/CODE/BT/BT/MESSMGR.HPP), reproduced verbatim.
|
|
// The only additions are the //@offset reconstruction comments tying each
|
|
// data member to the byte offset observed in the shipped object (see
|
|
// messmgr.cpp for the originating @ADDR evidence). Declarations are
|
|
// UNCHANGED.
|
|
//
|
|
// Class summary (recovered):
|
|
// SubsystemMessageManager : public Subsystem
|
|
// vtable @0050b954 ClassID 0xBD3 ("SubsystemMessageManagerClassID")
|
|
// ctor @0049bca4 dtor @0049bd7c CreateStreamedSubsystem @0049be10
|
|
// object layout >= 0x130 bytes; new members begin at +0xE4.
|
|
//
|
|
#if !defined (MESSMGR_HPP)
|
|
# define MESSMGR_HPP
|
|
|
|
#if !defined (SUBSYSTM_HPP)
|
|
# include <subsystm.hpp>
|
|
#endif
|
|
|
|
#if !defined (RESOURCE_HPP)
|
|
# include <resource.hpp>
|
|
#endif
|
|
|
|
#if !defined (VCHAIN_HPP)
|
|
# include <vchain.hpp>
|
|
#endif
|
|
|
|
#if !defined (PLUG_HPP)
|
|
# include <plug.hpp>
|
|
#endif
|
|
|
|
#if !defined(ENTITYID_HPP)
|
|
# include <entityid.hpp>
|
|
#endif
|
|
|
|
class Entity;
|
|
class Mech;
|
|
class Entity__TakeDamageMessage;
|
|
|
|
//##########################################################################
|
|
//########## SubsystemMessageManager::SubsystemResource ###############
|
|
//##########################################################################
|
|
//
|
|
// Parsed by CreateStreamedSubsystem @0049be10. Stamps ClassID 0xBD3 and
|
|
// model-record size 0x38 at resource +0x20/+0x24, then reads:
|
|
// +0x30 terrainHitExplosionID ("TerrainHitExplosion", a resource lookup)
|
|
// +0x34 rendererCompensateTime ("RendererCompensateTime", a Scalar)
|
|
//
|
|
struct SubsystemMessageManager__SubsystemResource :
|
|
public Subsystem::SubsystemResource
|
|
{
|
|
ResourceDescription::ResourceID
|
|
terrainHitExplosionID; // resource +0x30
|
|
|
|
Scalar
|
|
rendererCompensateTime; // resource +0x34
|
|
};
|
|
|
|
//##########################################################################
|
|
//##################### SubsystemMessageManager ###################
|
|
//##########################################################################
|
|
class
|
|
SubsystemMessageManager :
|
|
public Subsystem
|
|
|
|
{
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Shared Data Support
|
|
//
|
|
public:
|
|
static Derivation ClassDerivations; // static @0050b6cc (BSS)
|
|
static SharedData DefaultData; // default Performance ptr @0050b6fc -> 0049b784
|
|
//
|
|
// Added to satisfy the real Simulation__SharedData 4-arg ctor
|
|
// (derivation, message-handlers, attribute-index, state-count). The
|
|
// shipped record carried only the derivation + default Performance; the
|
|
// handler set / attribute index are empty for this class.
|
|
//
|
|
static Receiver::MessageHandlerSet MessageHandlers;
|
|
static AttributeIndexSet AttributeIndex;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Death and Damage Support
|
|
//
|
|
|
|
public:
|
|
|
|
void DeathReset(Logical) {}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Model Support
|
|
//
|
|
protected:
|
|
|
|
struct CommonDamageInformation
|
|
{
|
|
Entity
|
|
*entityHit; //@0xE4 (ctor/reset -> 0)
|
|
|
|
int
|
|
damageZoneIndex; //@0xE8 (ctor/reset -> -1)
|
|
|
|
Point3D
|
|
impactPoint; //@0xEC (Point3D, 3 Scalars)
|
|
|
|
} commonDamageInformation; //@0xE4
|
|
|
|
public:
|
|
|
|
struct DamageInformation
|
|
: public Plug // Plug vtable @0050b9a8, dtor @0049c3e3, size 0x14
|
|
{
|
|
Enumeration
|
|
damageType; //@0x0C (= TakeDamageMessage+0x2C)
|
|
|
|
int
|
|
subsystemID; //@0x10 (= TakeDamageMessage+0x5C)
|
|
};
|
|
|
|
typedef void
|
|
(SubsystemMessageManager::*Performance)(Scalar time_slice);
|
|
|
|
void
|
|
SetPerformance(Performance performance)
|
|
{
|
|
Check(this);
|
|
activePerformance = (Simulation::Performance)performance;
|
|
}
|
|
void
|
|
ConsolidateAndSendDamage(Scalar time_slice); // Performance @0049b784
|
|
|
|
Mech*
|
|
GetEntity()
|
|
{Check(this); return Cast_Object(Mech*, Subsystem::GetEntity());}
|
|
|
|
protected:
|
|
|
|
Scalar
|
|
rendererCompensateTime; //@0xF8 (resource +0x34)
|
|
|
|
typedef PlugOf<ResourceDescription::ResourceID>
|
|
ResourceIDPlug;
|
|
|
|
VChainOf<ResourceIDPlug*, ResourceDescription::ResourceID>
|
|
weaponExplosions; //@0xFC (VChain hdr 0x18 bytes)
|
|
|
|
VChainOf<DamageInformation*, Scalar> damageInformation; //@0x114 (VChain hdr 0x18 bytes)
|
|
|
|
ResourceDescription::ResourceID
|
|
terrainHitExplosionID; //@0x12C (resource +0x30)
|
|
|
|
void
|
|
CreateWeaponExplosions(
|
|
Logical terrain_hit,
|
|
EntityID entity_hit,
|
|
Point3D explode_position
|
|
); // inlined into ConsolidateAndSendDamage @0049b784
|
|
|
|
//
|
|
// @0049baa0 -- per-frame flush of the accumulated weaponExplosions queue
|
|
// (own method; not a streamed override).
|
|
//
|
|
void
|
|
SendQueuedExplosions();
|
|
|
|
//
|
|
// CROSS-FAMILY shim. In the original the per-subsystem explosion resource
|
|
// id is read off the engine Subsystem (Subsystem::GetExplosionID(),
|
|
// subsystem+0x3E4). The WinTesla Subsystem does not expose it yet, so we
|
|
// resolve through this local helper until the base provides it. See
|
|
// report "CROSS-FAMILY NEEDS".
|
|
//
|
|
ResourceDescription::ResourceID
|
|
ResolveExplosionID(Subsystem *subsystem);
|
|
|
|
//
|
|
// CROSS-FAMILY shim. The original built a renderer command (FUN_004336f0)
|
|
// and submitted it to the global graphics pipe (theGraphicsPipe->Submit,
|
|
// FUN_0041acbc). WinTesla replaced the IG graphics pipe with L4D3D and the
|
|
// submission entry point is not present in these headers; isolate the
|
|
// missing call here so the queueing/timing logic compiles.
|
|
//
|
|
void
|
|
SubmitExplosion(
|
|
ResourceDescription::ResourceID explosion_id,
|
|
Scalar fire_time
|
|
);
|
|
|
|
public:
|
|
|
|
void
|
|
AddDamageMessage(
|
|
Entity *damaged_entity,
|
|
Entity__TakeDamageMessage *message
|
|
); //@0049b6d8
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Construction and Destruction Support
|
|
//
|
|
public:
|
|
|
|
typedef SubsystemMessageManager__SubsystemResource SubsystemResource;
|
|
|
|
SubsystemMessageManager(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *sub_res,
|
|
SharedData &shared_data=DefaultData
|
|
); // ctor @0049bca4
|
|
|
|
~SubsystemMessageManager(); // dtor @0049bd7c (vtable slot 0)
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
static Logical
|
|
CreateStreamedSubsystem(
|
|
ResourceFile *resource_file,
|
|
NotationFile *model_file,
|
|
const char *model_name,
|
|
const char *subsystem_name,
|
|
SubsystemResource *subsystem_resource,
|
|
NotationFile *subsystem_file,
|
|
const ResourceDirectories *directories
|
|
); // @0049be10 (ClassID 0xBD3)
|
|
};
|
|
#endif
|