BT410 Phase 5.3.11: weapon heat consequences -- jams + thermal shutdowns LIVE
The heat economy now bites back, verified under sustained fire: - Ballistic gate 1 (@4bbd36): destroyed-state or own-sink FailureHeat pins full recoil + the unavailable alarm (the NoAmmo roach-motel re-asserts). - CheckForJam (@4bbfcc): p = 0.41*T/failT clamped [minJamChance, 1.0], rolled per granted shot against the MUNGA uniform Random. Interim heat-degraded gate stands in for the deferred LiveFireEnabled novice switch (the exact spurious-cold-jam trap the BT411 port documented). VERIFIED: SRM6s jam at T~1200-1320 after riding past the authored 1000-degree threshold, and stay jammed (mission-reset recovery only) -- authentic. - Emitter hard gate (@4baab9): FailureHeat drops the beam state + charge each frame; SELF-RECOVERING once conduction cools the sink below failure. VERIFIED: the PPC settles into an emergent thermal duty cycle -- fire at ~1930K, spike to 2562K, shutdown, cool, refire -- firing exactly as fast as its sink sheds heat; the lasers oscillate around ~2200K. Zero Fail. Deferred: LiveFireEnabled/HeatModelOff experience gates, mech-disabled gate halves, coolant depletion, jam recovery via mission reset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -190,6 +190,29 @@ void
|
|||||||
//
|
//
|
||||||
PoweredSubsystem::PoweredSubsystemSimulation(time_slice);
|
PoweredSubsystem::PoweredSubsystemSimulation(time_slice);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Hard failure (@4baab9): weapon DESTROYED or its own sink at FailureHeat
|
||||||
|
// -> drop the beam state and the charge, and hold there. Unlike the
|
||||||
|
// ballistic roach-motel this recovers by itself: once conduction cools the
|
||||||
|
// sink below the failure threshold the gate stops firing and the weapon
|
||||||
|
// resumes from Loading. (The owning-mech-disabled half joins with the
|
||||||
|
// damage wave.)
|
||||||
|
//
|
||||||
|
if (GetSimulationState() == 1 || GetHeatState() == FailureHeat)
|
||||||
|
{
|
||||||
|
if (getenv("BT_MECH_LOG") && GetWeaponState() != LoadingState)
|
||||||
|
{
|
||||||
|
DEBUG_STREAM << "[fire] '" << GetName()
|
||||||
|
<< "' THERMAL SHUTDOWN (T=" << CurrentTemperatureOf()
|
||||||
|
<< ")" << endl << flush;
|
||||||
|
}
|
||||||
|
ResetFiringState();
|
||||||
|
chargeLevel = 0.0f;
|
||||||
|
ComputeOutputVoltage();
|
||||||
|
Check_Fpu();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
static int forceFire = -1;
|
static int forceFire = -1;
|
||||||
if (forceFire < 0)
|
if (forceFire < 0)
|
||||||
|
|||||||
@@ -81,9 +81,30 @@ threshold: the authentic fire-discipline game. SRM salvos spike +641K and
|
|||||||
cross degradation after three. Condensers absorb and pass to the central
|
cross degradation after three. Condensers absorb and pass to the central
|
||||||
bank. Neutral run: sensor Ready/100%, mech holds, zero Fail.
|
bank. Neutral run: sensor Ready/100%, mech holds, zero Fail.
|
||||||
|
|
||||||
|
## Heat consequences (Phase 5.3.11, 2026-07-22)
|
||||||
|
|
||||||
|
The weapon-side consequences are wired and VERIFIED under sustained fire:
|
||||||
|
|
||||||
|
- **Ballistic gate 1** (@4bbd36): weapon destroyed-state or its own sink at
|
||||||
|
FailureHeat pins full recoil + the unavailable alarm (the NoAmmo roach-motel
|
||||||
|
re-asserts). (Mech-disabled half joins the damage wave.)
|
||||||
|
- **CheckForJam** (@4bbfcc): `p = 0.41·T/failT` clamped [minJamChance, 1.0],
|
||||||
|
rolled per granted shot against the MUNGA uniform `Random`. Interim gate:
|
||||||
|
heat-degraded only (stands in for the deferred `LiveFireEnabled` novice
|
||||||
|
switch AND the trivially-true `heatLoad>0` early-out — the exact spurious-
|
||||||
|
cold-jam trap the BT411 port documented). Verified: SRM6s jam at
|
||||||
|
T≈1200-1320 (24%+ rolls past the 1000° threshold), stay jammed.
|
||||||
|
- **Emitter hard gate** (@4baab9): FailureHeat drops the beam state + charge
|
||||||
|
each frame; SELF-RECOVERING — conduction cools the sink below 2000° and the
|
||||||
|
weapon resumes from Loading. Verified: the PPC settles into an emergent
|
||||||
|
thermal duty cycle (fire at ~1930° → spike 2562° → shutdown → cool → refire);
|
||||||
|
the lasers oscillate around ~2200°.
|
||||||
|
|
||||||
## Still deferred
|
## Still deferred
|
||||||
|
|
||||||
UpdateCoolant / BalanceCoolant (coolant depletion + venting), the HeatModelOff
|
UpdateCoolant / BalanceCoolant (coolant depletion + venting), the
|
||||||
experience gate (novice mode), the electrical charge model (TrackSeekVoltage /
|
HeatModelOff / LiveFireEnabled experience gates (novice mode), the electrical
|
||||||
voltage sag / I²R), gate 1 + the heat-scaled jam roll in the weapon FSMs, the
|
charge model (TrackSeekVoltage / voltage sag / I²R), the mech-disabled halves
|
||||||
central sink's forward-linked drain, Condenser MoveValve handling.
|
of the weapon gates (damage wave), the central sink's forward-linked drain,
|
||||||
|
Condenser MoveValve handling, jam recovery via ResetToInitialState (mission
|
||||||
|
reset path).
|
||||||
|
|||||||
@@ -23,6 +23,10 @@
|
|||||||
# include <ammobin.hpp>
|
# include <ammobin.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(RANDOM_HPP)
|
||||||
|
# include <random.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
Derivation
|
Derivation
|
||||||
ProjectileWeapon::ClassDerivations(
|
ProjectileWeapon::ClassDerivations(
|
||||||
MechWeapon::ClassDerivations,
|
MechWeapon::ClassDerivations,
|
||||||
@@ -159,6 +163,48 @@ void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//#############################################################################
|
||||||
|
// CheckForJam -- the heat-scaled jam roll (binary @4bbfcc):
|
||||||
|
// p = 0.41 * currentTemperature / failureTemperature,
|
||||||
|
// clamped to [minJamChance, 1.0], rolled against a uniform random.
|
||||||
|
// A jammed launcher clears only on ResetToInitialState (mission reset).
|
||||||
|
//
|
||||||
|
// TWO interim gates stand in for deferred systems (the BT411 port hit exactly
|
||||||
|
// this): the authentic leading gate is LiveFireEnabled() -- the player
|
||||||
|
// experience switch (novice mode = no jams), which needs the player-link
|
||||||
|
// accessor wave -- and the binary's own `heatLoad <= 0` early-out is trivially
|
||||||
|
// true once the heat model runs. Until LiveFireEnabled lands, gate the roll
|
||||||
|
// on the sink actually being heat-degraded, so cold weapons fire reliably and
|
||||||
|
// jams appear exactly when the heat economy says the weapon is cooking.
|
||||||
|
//#############################################################################
|
||||||
|
//
|
||||||
|
Logical
|
||||||
|
ProjectileWeapon::CheckForJam()
|
||||||
|
{
|
||||||
|
Check(this);
|
||||||
|
|
||||||
|
if (GetHeatState() < DegradationHeat) // interim LiveFireEnabled stand-in
|
||||||
|
{
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scalar p = (0.41f * CurrentTemperatureOf()) / failureTemperature;
|
||||||
|
if (minJamChance <= p)
|
||||||
|
{
|
||||||
|
if (p > 1.0f)
|
||||||
|
{
|
||||||
|
p = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p = minJamChance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (p > (Scalar)Random) ? True : False;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
//#############################################################################
|
//#############################################################################
|
||||||
// ProjectileWeaponSimulation The ballistic per-frame fire state machine
|
// ProjectileWeaponSimulation The ballistic per-frame fire state machine
|
||||||
@@ -209,6 +255,24 @@ void
|
|||||||
//
|
//
|
||||||
Logical trigger = CheckFireEdge();
|
Logical trigger = CheckFireEdge();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Gate 1 (@4bbd36): weapon DESTROYED or its own sink at FailureHeat -> pin
|
||||||
|
// full recoil + the unavailable alarm. No return -- the frame continues
|
||||||
|
// into the state machine (whose NoAmmo case re-asserts). (The owning-mech-
|
||||||
|
// disabled half joins with the damage wave.)
|
||||||
|
//
|
||||||
|
if (GetSimulationState() == 1 || GetHeatState() == FailureHeat)
|
||||||
|
{
|
||||||
|
if (getenv("BT_MECH_LOG") && GetWeaponState() != NoAmmoState)
|
||||||
|
{
|
||||||
|
DEBUG_STREAM << "[fire] '" << GetName()
|
||||||
|
<< "' -> UNAVAILABLE (gate1: heatState=" << GetHeatState()
|
||||||
|
<< " T=" << CurrentTemperatureOf() << ")" << endl << flush;
|
||||||
|
}
|
||||||
|
recoil = rechargeRate;
|
||||||
|
weaponAlarm.SetLevel(NoAmmoState);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Gate 2: the linked AmmoBin. Empty (or missing) -> pin unavailable EVERY
|
// Gate 2: the linked AmmoBin. Empty (or missing) -> pin unavailable EVERY
|
||||||
// frame while dry.
|
// frame while dry.
|
||||||
@@ -244,6 +308,16 @@ void
|
|||||||
{
|
{
|
||||||
weaponAlarm.SetLevel(NoAmmoState);
|
weaponAlarm.SetLevel(NoAmmoState);
|
||||||
}
|
}
|
||||||
|
else if (CheckForJam())
|
||||||
|
{
|
||||||
|
weaponAlarm.SetLevel(JammedState);
|
||||||
|
if (getenv("BT_MECH_LOG"))
|
||||||
|
{
|
||||||
|
DEBUG_STREAM << "[fire] '" << GetName()
|
||||||
|
<< "' JAMMED (T=" << CurrentTemperatureOf()
|
||||||
|
<< ")" << endl << flush;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
weaponAlarm.SetLevel(LoadingState);
|
weaponAlarm.SetLevel(LoadingState);
|
||||||
|
|||||||
@@ -77,6 +77,8 @@
|
|||||||
|
|
||||||
void
|
void
|
||||||
ProjectileWeaponSimulation(Scalar time_slice);
|
ProjectileWeaponSimulation(Scalar time_slice);
|
||||||
|
Logical
|
||||||
|
CheckForJam();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef ProjectileWeapon__SubsystemResource SubsystemResource;
|
typedef ProjectileWeapon__SubsystemResource SubsystemResource;
|
||||||
|
|||||||
Reference in New Issue
Block a user