State
Summary:
Heat stroke phase lifecycle is internally inconsistent: corrupts the global disease counter, freezes bias in yellow, leaks stamina modifiers, force-wakes unconsciousness and is invisible to the thermometer
Description:
Heatstroke has accounting/state bugs across its four phase modifiers and its integration points. All citations from scripts/ 1.30.164200.56.
The disease counter itself is a single int on the player, gated >= 1 for ALL disease icons:
// playerbase.c:1093-1101 — no floor
void IncreaseDiseaseCount()
{
m_DiseaseCount++;
}
void DecreaseDiseaseCount()
{
m_DiseaseCount--;
}
// playerbase.c:1121
return m_DiseaseCount >= 1;Heat stroke phases update it asymmetrically: phase 1 decrements on deactivate but never increments on activate, and phase 2 increments on activate but never decrements on deactivate:
// heatstroke.c:74 — phase 1
player.DecreaseDiseaseCount();
// heatstroke.c:115 / 118-123 — phase 2 increments; OnDeactivate has no decrement
player.IncreaseDiseaseCount();Negative disease count hides every disease icon. Each comfort cycle peaking below bias 0.4 leaks -1. Over a hot season m_DiseaseCount drifts deeply negative (only reset on spawn, playerbase.c:7962) and every icon-bearing disease (cholera, salmonella, influenza) runs iconless.
Bias pins at 0.4 in yellow with mid hydration, phase 2 toggle-floods the counter. In the yellow comfort zone with water between 1000 and SL_WATER_HIGH (3500), bias grows below 0.4 and drains at/above it:
// heatcomfortmdfr.c:106-111
if (thermalBiasValue < HeatStrokeMdfr.STAGE_THRESHOLDS[1])
thermalBiasHandler.Add(PlayerConstants.THERMAL_BIAS_POSITIVE_HC_LOW_INCREMENT * deltaT); // 0.00022
else
thermalBiasHandler.Add(-PlayerConstants.THERMAL_BIAS_POSITIVE_HC_DECREMENT * deltaT); // 0.0001Growth step per 3 s modifier tick (0.00066) exceeds the drain step (0.0003), so bias oscillates 0.3999-0.4005; phase 2 (ActivateCondition > 0.4 / DeactivateCondition <= 0.4, heatstroke.c:100-108) retoggles every ~6 s, each activation firing a fresh IncreaseDiseaseCount() and fever blur flickers.
Bias freezes in yellow at full hydration. The same branch (heatcomfortmdfr.c:95-113) has no case for waterValue >= SL_WATER_HIGH, and the only drain zone for the entire heat stroke system is heat comfort ≤ 0.15. A player resting in shade, fully hydrated, holds banked bias indefinitely at values anywhere in 0.4-0.85 - no in-game signal.
Phase 3 leaks VOMIT_EXHAUSTION stamina modifiers. The vomit path activates recovery+depletion exhaustion modifiers (heatstroke.c:211-215) and the removal runs only in OnTick (219-229). If phase 3 deactivates first bias < 0.6, e.g. one head wash applies −0.175 instantly - OnDeactivate (heatstroke.c:180-184) cleans only DISEASE_PNEUMONIA. Stale entry persists for the rest of the life: recovery ×0.5, depletion ×1.3. Contrast cholera, which cleans both pairs in OnDeactivate (cholera.c:49-57).
Vomit drains apply at queue time, animation is deferred. QueueUpPrimarySymptom spawns and returns at queue time (statemanager.c:534-566); VomitSymptom.CanActivate gates only the animation, later (vomitstate.c:71-74). Heat stroke applies water −70 / energy −55 and arms the exhaustion modifiers in the queueing tick (heatstroke.c:198-216), so a player in a no-action state can lose stats with no symptom shown.
Phase 4 force-wakes unconsciousness from any source. The block runs its wake logic on the raw player.IsUnconscious() disjunct:
// heatstroke.c:370
if ((thermalBias > 0.75 && canTriggerUnconsciousness) || player.IsUnconscious())
...
player.RequestUnconsciousness(false);A player unconscious from shock/bleed/UI while bias > 0.6 pops awake after 5-10 s instead of resolving their own cause.
The thermometer cannot see heat stroke at all. It reads elevated temperature only for MODIFIER_SYNC_FEVER (thermometer.c:3-16), which activates for cholera/influenza/wound infection only (fever.c:22-25). Heat stroke syncs MODIFIER_SYNC_HEAT_STROKE (heatstroke.c:38) - never checked. Real heat stroke IS acute thermoregulatory failure: core temperature rises (medical hallmark ≥ 40 °C), the same measurable sign a thermometer detects in the cholera case. The one diagnostic item for body temperature reads normal at every stage, including terminal.
Hot climate, yellow heat comfort, water 1000-3500 -> bias pins at 0.4, phase 2 toggles every ~6 s, fever blur flickers, GetDiseaseCount() climbs (Issue 2; also floods Issue 1 in the positive direction).
Alternatively let short comfort cycles peak below 0.4 -> each leaks -1 (Issue 1); any contracted disease then shows no icon.
Full hydration (≥3500) + yellow comfort -> banked bias never drains (Issue 3).
Enter stage 3, vomit (arms exhaustion), then drop bias < 0.6 within the window (e.g. head wash -0.175) -> stamina recovery ×0.5 / depletion ×1.3 for the rest of the life (Issue 4).
Reach bias > 0.75, go unconscious from any non–heat stroke cause while phase 4 is active -> force-woken after 5-10 s (Issue 6).
Any stage: thermometer on the player reads normal (Issue 7).
Expected result:
heat stroke accounting mirrors itself per phase; the counter never leaves [0, N]; a nominally-active phase toggles at most per threshold crossing, not continuously; yellow-with-full-hydration drains bias like other zones; OnDeactivate cleans every modifier OnActivate/OnTick can start; phase 4 manages only unconsciousness it caused; the thermometer shows elevated temperature during a real thermoregulatory-failure disease.
Actual result:
count drifts in both directions unboundedly and suppresses ALL disease icons; phase 2 toggle-floods it ~6/min; yellow+full hydration holds banked bias forever; phase 3 can strand permanent stamina penalties; vomits can drain without animating; foreign unconsciousness is force-broken; thermometer blind to the one disease defined by raised core temperature.
Suggested fix:
Floor the counter (Math.Max(0, m_DiseaseCount - 1)) and match increments/decrements per phase (or count heat stroke as one logical disease).
Hysteresis on the 0.4 boundary (grow while < 0.4, drain only when ≥ 0.45) and a DoOnce guard before IncreaseDiseaseCount() (influenza.c:64).
Drain yellow at full hydration by the white-zone decrement.
Add DeactivateRecoveryModifier/DeactivateDepletionModifier(VOMIT_EXHAUSTION) to HeatStrokePhase3Mdfr.OnDeactivate.
Move vomit drains + exhaustion arming to symptom activation (OnAnimationStart), gated by the same condition as the animation.
Gate phase 4's wake on a modifier-owned flag instead of raw player.IsUnconscious().
Extend the thermometer check with MODIFIER_SYNC_HEAT_STROKE, temperature scaled to stage (38.5 °C → 40+ °C).
Activity
Quick note:
I ran some Monte Carlo tests on the code after I saw really inconsistent behaviour of heatstroke in game and became convinced there was some sort of bug in the math or something and surfaced these.
You are not signed in. Please sign in to see more details and to reply.
State