KB: EXPERIENCE LEVELS decoded -- the 0x25c block is the simulation-mode flags

The egg's per-pilot 'experience' (novice/standard/veteran/expert) is the
pod's simulation-fidelity tier -- stored at BTMission+0xe4 and seeded into
the BTPlayer ctor's flag block @4c0bc8 [T1].  The old 'per-role display
toggles / returnFromDeath' reading was WRONG: the source is
mission->experienceLevel, and the neighboring pair copies
mission->advancedDamageOn (the egg's technician splash/collision switch),
not role floats.  Known consumers: 0x260 = the HEAT-MODEL master switch
(FUN_004ad7d4), 0x25c = the novice sim-lockout (jams/searchlight/powersub),
0x274 = the raw level (FUN_004ac9c8 ==0 novice predicate).

NEW established topic context/experience-levels.md (data path, binary flag
rows per level, manual cross-refs, corrections log) + router row; sweeps in
decomp-reference/gauges-hud/open-questions/pod-hardware/subsystems.
btplayer.cpp/.hpp re-annotated with the corrected semantics; the guarded
role-based seeding stays as a marked [T3] stand-in (slot drift vs the
binary switch documented inline) until the wiring task points it at
BTMission::ExperienceLevel().

(Research by the parallel context session; committed from the glass line.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-18 22:45:37 -05:00
co-authored by Claude Fable 5
parent 171c993147
commit 4e01e83563
12 changed files with 51391 additions and 54 deletions
+28 -16
View File
@@ -1303,12 +1303,21 @@ BTPlayer::BTPlayer(
else
{
//
// Master: choose the HUD display toggles from the role class index.
// Master: derive the game-mode flags from the EXPERIENCE level.
//
// TODO(bring-up): scenarioRole is NULL here because the role lookup above
// (btMission->GetRoleRegistry()->Lookup) is still stubbed out. Guard the deref
// so mission load proceeds; default index 2 = show all stats (freeforall).
roleClassIndex = scenarioRole ? scenarioRole->GetReturnFromDeath() : 2; // this[0x9d] <- role+0xe4
// CORRECTED SOURCE (2026-07-18 [T1]): the binary reads
// btMission->experienceLevel (mission+0xe4, the egg's per-pilot
// "experience" 0..3 = novice/standard/veteran/expert) — NOT the role's
// returnFromDeath (the old reading). See context/experience-levels.md.
//
// STAND-IN [T3]: still seeded from the role (default 2 ≈ VETERAN) until
// the wiring task points this at BTMission::ExperienceLevel(). Known
// slot drift vs the binary switch: the binary never touches
// showDamageInflicted(0x264) here (that's the advancedDamage copy, set
// below), and expert's 0 lands on roleReturnDelay2(0x26c), not
// showScore(0x270) — binary rows: nov 0,0,0,0 / std 1,0,1,1 /
// vet 1,1,1,1 / exp 1,1,0,1 for (0x25c,0x260,0x26c,0x270).
roleClassIndex = scenarioRole ? scenarioRole->GetReturnFromDeath() : 2; // this[0x9d] <- mission+0xe4 in the binary
switch (roleClassIndex)
{
case 0:
@@ -1327,9 +1336,11 @@ BTPlayer::BTPlayer(
break;
}
// role+0xf0 ("returnDelay") has no field in the WinTesla ScenarioRole;
// initialised to 0 here. CROSS-FAMILY -- see report. BEST-EFFORT.
roleReturnDelay = roleReturnDelay2 = 0.0f; // this[0x99],[0x9a] <- role+0xf0
// CORRECTED (2026-07-18 [T1]): the binary sets this[0x99]/[0x9a]
// (0x264/0x268) = btMission->advancedDamageOn (mission+0xf0, the egg
// "advancedDamage" technician flag) — an int pair, not role floats.
// 0 here = advanced damage OFF, which matches the bring-up eggs. [T3]
roleReturnDelay = roleReturnDelay2 = 0.0f; // this[0x99],[0x9a] <- mission+0xf0 in the binary
}
killCount = 0; // this[0x9f]
@@ -1589,14 +1600,15 @@ void BTPostKillScore(Entity *victim, Scalar damage) // Step 7: KILL (+ MP deat
//
// FUN_004ac9c8 [T1]: `return *(*(*(sub+0xD0) + 0x190) + 0x274) == 0` -- the
// subsystem's owner Mech -> the owning BTPlayer (mech+0x190, GetPlayerLink)
// -> roleClassIndex (+0x274, role resource +0xE4). TRUE = the ROOKIE role
// (class 0) LOCKS the advanced cockpit systems (generator routing, coolant
// valves); nonzero role classes unlock them. The old reconstruction
// mislabeled this fn "Subsystem::IsDamaged" -- with healthy subsystems at
// simulationState==1, that stand-in gated the power-routing handlers OFF
// permanently. A NULL player (the target dummy / unbound solo mech) would AV
// in the binary (every pod mech has a player); the port reads NULL as
// UNLOCKED so dev rigs work [T3].
// -> +0x274 = the raw EXPERIENCE level (egg "experience", mission+0xe4; the
// old "roleClassIndex / role resource" reading was wrong -- see
// context/experience-levels.md). TRUE = NOVICE experience LOCKS the advanced
// cockpit systems (generator routing, coolant valves); standard and above
// unlock them. The old reconstruction mislabeled this fn
// "Subsystem::IsDamaged" -- with healthy subsystems at simulationState==1,
// that stand-in gated the power-routing handlers OFF permanently. A NULL
// player (the target dummy / unbound solo mech) would AV in the binary (every
// pod mech has a player); the port reads NULL as UNLOCKED so dev rigs work [T3].
//
int BTPlayerRoleLocksAdvanced(void *owner_mech)
{