The 5.3.99 open question is closed the way the binary closes it, not with a
divisor. Two pieces:
THE DIVERT (damage hub @0x4a0368): type-0 Collision damage NEVER reaches the
armor zones. Our handler was routing wall crashes through the same
cylinder-lottery path as enemy fire, which is why 24k-point kinetic numbers
one-shot vital zones. The binary short-circuits them into
THE DISTRIBUTOR (@0049ffcc): the manual's "collision damage" technician
setting. Gated on the owning player's advanced-damage flag; priced against
a 100 km/h reference impact --
scale = (2000 / mass) / (100 km/h)^2 / (1 - elasticity^2)
amount = raw * scale; under 0.5 the tap is FREE
n = Round(amount * 2) sub-hits of amount/n each
-- and applied as rattle crits to random INTERNAL subsystems (HeatSink /
Gyroscope / Torso families only), drawn by cumulative
collisionCriticalHitWeight against a [0,1) roll. An un-won roll lands
nowhere; the binary does not normalize the weights, so neither do we.
LIVE, same arena mission as 5.3.99's four-death run:
[colldmg] rattle 0.677919 pts in 1 sub-hits (scale=3.6e-05)
[crash] BLOCK dmg=18831.1 iv2=711.428 KNOCKDOWN
[crash] BLOCK dmg=331.878 iv2=12.549 (x6, pressed against a wall)
deaths: ZERO (was four)
An 18.8k-point crash becomes 0.68 points of internal rattle; the low-speed
wall grind prices as free taps under the 0.5 floor; the knockdown stagger
still fires above the velocity threshold. Walls now block, stagger, and
rattle -- they no longer execute.
Plumbing: MechSubsystem::CollisionCritWeight() accessor (the weight was
already streamed at +0x10C, protected), Mech::DistributeCollisionDamage
declared, random.hpp include.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
233 lines
7.2 KiB
C++
233 lines
7.2 KiB
C++
//===========================================================================//
|
|
// File: mechsub.hpp //
|
|
// Project: BattleTech //
|
|
// Contents: Implementation details for mech subsystems //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#if !defined(MECHSUB_HPP)
|
|
# define MECHSUB_HPP
|
|
|
|
# if !defined(SUBSYSTM_HPP)
|
|
# include <subsystm.hpp>
|
|
# endif
|
|
|
|
# if !defined(ALARM_HPP)
|
|
# include <alarm.hpp>
|
|
# endif
|
|
|
|
//##################### Forward Class Declarations #######################
|
|
class Mech;
|
|
class Damage;
|
|
|
|
//###########################################################################
|
|
//#################### MechSubsystem Model Resource #####################
|
|
//###########################################################################
|
|
|
|
struct MechSubsystem__SubsystemResource:
|
|
public Subsystem::SubsystemResource
|
|
{
|
|
Scalar armorByFacing[5];
|
|
Scalar structureReference;
|
|
int vitalSubsystemIndex;
|
|
char videoObjectName[128];
|
|
ResourceDescription::ResourceID
|
|
alarmModel;
|
|
int alarmModelReserved[2];
|
|
int printSimulationState;
|
|
Scalar collisionCriticalHitWeight;
|
|
Scalar criticalReference;
|
|
};
|
|
|
|
//###########################################################################
|
|
//########################## MechSubsystem ##############################
|
|
//###########################################################################
|
|
|
|
class MechSubsystem:
|
|
public Subsystem
|
|
{
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Shared Data Support
|
|
//
|
|
public:
|
|
static Derivation ClassDerivations;
|
|
static SharedData DefaultData;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Attribute Support. The shipped pool puts ConfigureActivePress
|
|
// immediately after the class name MechSubsystem, i.e. it is this
|
|
// class's one attribute and the FIRST id past Subsystem's. BTL4.RES
|
|
// binds it on Avionics, Myomers and every weapon -- all of which chain
|
|
// through here. The member has been in this class all along; only the
|
|
// publication was missing.
|
|
//
|
|
// Everything downstream shifts by one, which is the AUTHENTIC shape:
|
|
// with this row in place MechWeapon needs exactly ONE bridging pad to
|
|
// land PercentDone on its binary-pinned 0x12 (it needed three before
|
|
// ReportLeak and this were published).
|
|
//
|
|
public:
|
|
enum {
|
|
ConfigureActivePressAttributeID = Subsystem::NextAttributeID, // 2
|
|
NextAttributeID // 3
|
|
};
|
|
|
|
static const IndexEntry AttributePointers[];
|
|
static AttributeIndexSet AttributeIndex;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Status model
|
|
//
|
|
public:
|
|
enum TechStatusType {
|
|
Destroyed = 0,
|
|
Damaged = 1,
|
|
CoolantLeaking = 2,
|
|
Overheating = 3,
|
|
AmmoBurning = 4,
|
|
Jammed = 5,
|
|
BadPower = 6,
|
|
TechStatusTypeCount
|
|
};
|
|
|
|
//
|
|
// The subsystem SIMULATION states (binary PrintState @4ac8c0 string
|
|
// pool: "Destroyed" @0050df7f, "Exploding" @0050df8c). DestroyedState
|
|
// (1) is the hard-failure gate every weapon simulation checks
|
|
// (`GetSimulationState() == 1` -- emitter @4baab9, ballistic @4bbd36).
|
|
//
|
|
enum {
|
|
DestroyedState = Simulation::DefaultState + 1,
|
|
ExplodingState,
|
|
MechSubsystemStateCount
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Test Class Support
|
|
//
|
|
public:
|
|
static Logical
|
|
TestClass(Mech &);
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Construction and Destruction
|
|
//
|
|
public:
|
|
typedef MechSubsystem__SubsystemResource SubsystemResource;
|
|
|
|
MechSubsystem(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
const char *subsystem_name,
|
|
RegisteredClass::ClassID class_id,
|
|
SharedData &shared_data = DefaultData
|
|
);
|
|
|
|
MechSubsystem(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
);
|
|
|
|
~MechSubsystem();
|
|
|
|
static int
|
|
CreateStreamedSubsystem(
|
|
NotationFile *model_file,
|
|
const char *model_name,
|
|
const char *subsystem_name,
|
|
SubsystemResource *subsystem_resource,
|
|
NotationFile *subsystem_file,
|
|
const ResourceDirectories *directories,
|
|
int passes = 1
|
|
);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Damage support
|
|
//
|
|
public:
|
|
virtual void
|
|
TakeDamage(Damage &damage);
|
|
|
|
Scalar
|
|
GetSubsystemDamageLevel() const;
|
|
void
|
|
SetSubsystemDamageLevel(Scalar level);
|
|
void
|
|
ForceCriticalFailure();
|
|
|
|
//
|
|
// Critical-hit application (binary @4ac07c): run the damage through
|
|
// TakeDamage and return how much the subsystem's own zone level
|
|
// actually moved (the crit accountant charges it against the entry's
|
|
// damagePercentage allotment).
|
|
//
|
|
Scalar
|
|
ApplyDamageAndMeasure(Damage &damage);
|
|
|
|
//
|
|
// The collision-rattle draw weight (binary subsystem+0x10C) -- read
|
|
// by Mech::DistributeCollisionDamage's cumulative roll.
|
|
//
|
|
Scalar
|
|
CollisionCritWeight() const
|
|
{ Check(this); return collisionCriticalHitWeight; }
|
|
|
|
Logical
|
|
IsVitalSubsystem() const { Check(this); return vitalSubsystem; }
|
|
|
|
//
|
|
// The respawn restore (engine base virtual, SUBSYSTM.HPP:184 -- the
|
|
// pair with DeathShutdown). Mech::Reset sweeps every roster slot;
|
|
// the base heals the subsystem's private zone and clears the
|
|
// Destroyed simulation state (the weapon hard gate). full_reset is
|
|
// the binary's reset_command (every recovered override ignores it).
|
|
//
|
|
virtual void
|
|
DeathReset(Logical full_reset);
|
|
|
|
//
|
|
// The NOVICE-experience lockout predicate (binary @4ac9c8): a novice
|
|
// pilot's advanced cockpit controls (condenser valves, coolant flush,
|
|
// cooling toggles) are locked out. Owner mech -> playerLink ->
|
|
// experience level == novice. Unlinked mechs read UNLOCKED.
|
|
//
|
|
Logical
|
|
NoviceLockout();
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Local Data
|
|
//
|
|
protected:
|
|
Mech
|
|
*owner;
|
|
AlarmIndicator
|
|
statusAlarm;
|
|
Logical
|
|
vitalSubsystem;
|
|
ResourceDescription::ResourceID
|
|
alarmModel;
|
|
Scalar
|
|
criticalReference;
|
|
Scalar
|
|
collisionCriticalHitWeight;
|
|
Logical
|
|
printSimulationState;
|
|
int
|
|
configureActivePress;
|
|
SubsystemResource
|
|
*resource;
|
|
};
|
|
|
|
#endif
|