KB: land the EXPERIENCE-LEVELS decode from glass-cockpit (Cyd)
Brings Cyd's experience-level / simulation-mode research onto master (the KB-decode portion of glass-cockpit 4e01e83; the bundled BT410 source manifest is left for the full glass-cockpit merge). - context/experience-levels.md (NEW): the egg per-pilot 'experience' field (novice/standard/veteran/expert) is the pod's SIMULATION-FIDELITY tier, decoded end-to-end. FUN_004c0bc8 reads btMission->experienceLevel(+0xe4) and fans it into the +0x25c/+0x260/+0x26c/+0x270/+0x274 flag block: +0x25c 'sim live' (novice lockout: jams/searchlight/powersub), +0x260 the HEAT-MODEL master switch (veteran+expert; FUN_004ad7d4), +0x274 raw level (FUN_004ac9c8 = ==0 novice predicate; the valve/advanced-cockpit lockout). 4.0->4.10 drift: the viewscreen hunting-aid gate is GONE in 4.10 (HUD reads none of these flags), and movement heat is veteran+expert not expert-only. - btplayer.cpp/.hpp: CORRECTED comments/labels -- the +0x25c..+0x274 block is seeded from btMission experienceLevel/advancedDamageOn, NOT the scenario role's returnFromDeath; the 'roleClassIndex/showKills' names are scoring-era mislabels. Code logic UNCHANGED (comment-only): the ctor still reads scenarioRole (STAND-IN, defaults 2 = veteran) pending the wiring task. - Corrections swept into gauges-hud.md (ROOKIE->novice lockout), open-questions.md (player+0x260/0x274 semantics now PINNED), pod-hardware.md, subsystems.md, decomp-reference.md; CLAUDE.md router row. No code-logic change -> no rebuild needed (comment + markdown only). The runtime wiring (seed from BTMission::ExperienceLevel()) remains TODO. Co-Authored-By: Cyd <cyd@falloutshelterarcade.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -67,6 +67,7 @@ precise than anything you can infer.
|
||||
| Walking, gait, ground model, collision | `context/locomotion.md` |
|
||||
| Subsystems, the factory, heat/weapons/power | `context/subsystems.md` |
|
||||
| Damage zones, targeting, firing, death | `context/combat-damage.md` |
|
||||
| Experience / simulation modes (novice/standard/veteran/expert), heat-model + novice gates | `context/experience-levels.md` |
|
||||
| Rendering, LODs, materials, sky, shadows, beams | `context/rendering.md` |
|
||||
| The death/respawn translocation warp (tsphere vortex) | `context/translocation-warp.md` |
|
||||
| First-person cockpit canopy (*_cop) + the eyepoint camera | `context/cockpit-view.md` |
|
||||
|
||||
@@ -113,7 +113,7 @@ valid for reading the decomp, NOT for our compiled layout (see [[reconstruction-
|
||||
|---|---|---|
|
||||
| +0x11c / +0x120 | `damageZoneCount` / `damageZones[]` | inherited Entity; Mech ctor populates the array |
|
||||
| +0x124 / +0x128 | `subsystemCount` / `subsystemArray[]` | the [[subsystem-roster]] (NOT the segment table) |
|
||||
| +0x190 | **owning `BTPlayer`** (`GetPlayerLink()`) | set by `FUN_0049f624` (mech↔player bind; also `player->playerVehicle(+0x1fc)=mech`). The valve guard (`FUN_004ac9c8 →player+0x274`) + Myomers gate (`FUN_004ad7d4 →player+0x260`) read the owning player's game-mode flags (NOT the messmgr @0x434). `MECH_OWNING_PLAYER`. |
|
||||
| +0x190 | **owning `BTPlayer`** (`GetPlayerLink()`) | set by `FUN_0049f624` (mech↔player bind; also `player->playerVehicle(+0x1fc)=mech`). The valve guard (`FUN_004ac9c8 →player+0x274` = novice lockout) + heat-model gate (`FUN_004ad7d4 →player+0x260` = veteran/expert) read the owning player's EXPERIENCE flags — see [[experience-levels]] + the BTPlayer flag block below. `MECH_OWNING_PLAYER`. |
|
||||
| +0x434 (word 0x10d) | `SubsystemMessageManager` cache | the 0xBD3 damage/explosion hub (factory @10142). ✅ task #7 (`afefaee`): `mech.hpp` names this `messageManager`; the `controlsMapper` mislabel is swept — the real mapper is roster slot 0. |
|
||||
| +0x260 / +0x26c | `localOrigin` = { Point3D linearPosition; Quaternion angularPosition } | ORIGIN.h:15; position@+0x100 in some subsystem views |
|
||||
| +0x300 | segment table | skeleton `EntitySegment`s (muzzle sites, joints) |
|
||||
@@ -128,6 +128,20 @@ valid for reading the decomp, NOT for our compiled layout (see [[reconstruction-
|
||||
|
||||
`mech+0x100` (a subsystem-view of localOrigin.linearPosition): `.x@+0x100, .z@+0x108`. [T1]
|
||||
|
||||
### BTPlayer (0x294) experience/game-mode flag block (ctor @4c0bc8; see [[experience-levels]]) [T1]
|
||||
|
||||
Seeded on the master branch from `btMission(+0x1f8)->experienceLevel(+0xe4)` (egg `experience`,
|
||||
parse @4d2f3e → `BTMission+0xe4`) and `advancedDamageOn(+0xf0)`:
|
||||
|
||||
| Offset | Value by level (nov/std/vet/exp) | Verified readers |
|
||||
|---|---|---|
|
||||
| +0x25c | 0/1/1/1 — "sim live" (novice lockout) | jam roll @4bbfcc, searchlight ToggleLamp @4b860c, powersub handler @4b0efc, mech-ineffective eval part_012.c:9364 |
|
||||
| +0x260 | 0/0/1/1 — **heat-model master switch** | `FUN_004ad7d4` → Myomers @4b8d18, Emitter, heat.cpp, mislanch, projweap heat |
|
||||
| +0x264/+0x268 | = mission `advancedDamageOn` (both) | heat-family sim part_013.c:8757 |
|
||||
| +0x26c | 0/1/1/0 | none located (supercharge-clamp hypothesis [T4]) |
|
||||
| +0x270 | 0/1/1/1 | none located |
|
||||
| +0x274 | raw level 0..3 | `FUN_004ac9c8` = (==0) novice predicate (valve guard), powersub @4b21d0 |
|
||||
|
||||
### Binary ATTRIBUTE TABLES (2026-07-16, walked from the image) [T1]
|
||||
|
||||
**Row format: 16-byte `{id, namePtr, memberOffset+1, 0}`** (MIND THE ALIGNMENT — an 8-off walk
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
---
|
||||
id: experience-levels
|
||||
title: "Experience levels / simulation modes — novice, standard, veteran, expert"
|
||||
status: established
|
||||
source_sections: "decomp part_013.c:10816-10871 (@4c0bc8), part_014.c:7830-7900 (@4d2f3e), FUN_004ad7d4/FUN_004ac9c8/FUN_004bbfcc; BTMSSN.HPP (survived); Tesla40_BT_manual.pdf pp.7,11-14,21,22,24"
|
||||
related_topics: [subsystems, combat-damage, gauges-hud, pod-hardware, multiplayer, decomp-reference, open-questions]
|
||||
key_terms: [master, replicant]
|
||||
open_questions:
|
||||
- "player+0x26c (std+vet only) and +0x270 (all but novice) consumers not located — 0x26c hypothesis: myomer supercharge clamp (manual p22) [T4]"
|
||||
- "does a remote pilot's experience matter cross-pod? flags are computed only on the master branch of the BTPlayer ctor [T4]"
|
||||
- "movement-heat magnitude veteran vs expert (4.0 manual says expert-only; 4.10 gate is vet+expert) [T4]"
|
||||
---
|
||||
|
||||
# Experience levels / simulation modes
|
||||
|
||||
The egg's per-pilot `experience` field is the pod's **simulation-fidelity tier** — the thing the
|
||||
1995 site operator set per player at sign-up. It is NOT the BAS/MID/ADV control mode (a free
|
||||
in-cockpit choice, [[locomotion]]/[[pod-hardware]]) and NOT the scenario role (scoring modifiers).
|
||||
Researched end-to-end 2026-07-18; this file supersedes the older "role display toggles" /
|
||||
"ROOKIE-role lockout" readings (see Corrections below).
|
||||
|
||||
## The data path [T1]
|
||||
|
||||
1. **Egg**: pilot page key `experience` ∈ {`novice`,`standard`,`veteran`,`expert`}; required unless
|
||||
`vehicle=camera`; unknown value = hard abort. Parse @4d2f3e (part_014.c:7830-7900, strings
|
||||
@51e6f1); `tools/eggmodel.py` knows the value set.
|
||||
2. **BTMission** (`BTMSSN.HPP` survived, T0): stored at `mission+0xe4` (`experienceLevel`, accessor
|
||||
`ExperienceLevel()`); the neighboring egg key `advancedDamage` → `mission+0xf0`
|
||||
(`advancedDamageOn`) — the separate site-technician splash/collision switch (manual p13).
|
||||
3. **BTPlayer ctor @4c0bc8** (part_013.c:10816-10871): on the MASTER branch
|
||||
(`(simulationFlags & 0xc) != 4`; the replicant branch instead swaps in the console-update
|
||||
Performance) it reads `btMission(+0x1f8)->experienceLevel(+0xe4)` and fans it out:
|
||||
|
||||
| egg value | +0x25c | +0x260 | +0x26c | +0x270 | +0x274 (raw) |
|
||||
|---|---|---|---|---|---|
|
||||
| novice | 0 | 0 | 0 | 0 | 0 |
|
||||
| standard | 1 | 0 | 1 | 1 | 1 |
|
||||
| veteran | 1 | 1 | 1 | 1 | 2 |
|
||||
| expert | 1 | 1 | 0 | 1 | 3 |
|
||||
|
||||
then unconditionally `+0x264 = +0x268 = mission->advancedDamageOn(+0xf0)` (both copies). [T1]
|
||||
|
||||
## What each flag gates (binary consumers, all reached via `mech+0x190` → BTPlayer) [T1]
|
||||
|
||||
- **+0x25c — "sim live", off only for novice.** Consumers: ballistic jam roll `CheckForJam`
|
||||
@4bbfcc early-returns NO-JAM when 0 (projweap.cpp calls this `LiveFireEnabled`); Searchlight
|
||||
`ToggleLamp` @4b860c (searchlight.cpp `ControlsAllowLights`); PoweredSubsystem message handler
|
||||
@4b0efc (powersub.cpp's "message-manager short-event flag" — same flag, misattributed); the mech
|
||||
combat-ineffective evaluation (part_012.c:9364: mech state ∈ {3,4} && novice is an extra OR-term
|
||||
setting `mech+0x414`). The `#if 0` block in surviving PPC.CPP:63-95 (novice PPCs deal no damage)
|
||||
shows the original intent of the tier.
|
||||
- **+0x260 — the HEAT-MODEL master switch, ON for veteran+expert.** This is `FUN_004ad7d4`
|
||||
(`*(*(sub+0xD0)+0x190)+0x260`), the single most-called gate in the subsystem family: Myomers
|
||||
work→heat (movement heat, MyomersSimulation @4b8d18), Emitter/energy-weapon firing heat, missile
|
||||
launch heat, the heat.cpp simulation, projectile-weapon heat, and the heat-scaled part of the jam
|
||||
chance. Standard mode has NO heat consequences; that is authentic, not a port gap.
|
||||
- **+0x274 — the raw level.** `FUN_004ac9c8` = (level == 0), the NOVICE lockout used as the
|
||||
condenser-valve guard ([[gauges-hud]] task #13) and by the PoweredSubsystem handler @4b21d0
|
||||
(not-novice gate). The port's `BTPlayerRoleLocksAdvanced` bridge implements this predicate
|
||||
(correct behavior, wrong seeding — see Port state).
|
||||
- **+0x264/+0x268 — advancedDamage copies.** Read in the heat-family sim (part_013.c:8757).
|
||||
Independent of experience.
|
||||
- **+0x26c / +0x270 — consumers NOT located** via the mech→player hop. 0x26c (standard+veteran
|
||||
only) best fits the manual-p22 myomer supercharge clamp (standard locked, expert unlocked) [T4].
|
||||
|
||||
## Player-facing behavior (Tesla 4.0 manual) [T1 primary source]
|
||||
|
||||
Manual pp. 7, 11-14, 21, 22, 24 (the dedicated Simulation Modes page, manual p2, is MISSING from
|
||||
the `Tesla40_BT_manual.pdf` scan along with p3):
|
||||
- **Standard**: armor-only damage — no criticals, no generator outages, no jams, no heat concerns;
|
||||
MechTech limited to the leg-damage audio warning; viewscreen hunting aids (red hot box + guide
|
||||
arrow, 60° FOV) on; myomer supercharge locked.
|
||||
- **Veteran**: critical hits (any hit can go internal; likelihood rises as armor thins; a crit can
|
||||
kill the mech), generators take damage/go offline (reroute power), ballistic jams (manual
|
||||
clearing), full MechTech audio + smart buttons; viewscreen hunting aids OFF (radar hot box stays).
|
||||
- **Expert**: veteran + heat as a core mechanic: movement generates heat (accel/decel worst),
|
||||
heat slows recharge/top speed, incoming fire causes coolant leaks, ammo-bay fires/cook-off;
|
||||
myomer supercharge allowed.
|
||||
- Scoring identical in all modes (p4). Splash/collision damage = a separate technician setting.
|
||||
|
||||
## 4.0 → 4.10 drift [T1]
|
||||
|
||||
- **The viewscreen hunting-aid gate is GONE in 4.10**: part_014 (HUD/btl4vid TU) reads none of the
|
||||
player flags — the target hotbox/edge arrows (@4cdf6f) are gated on lock state only, every mode.
|
||||
Fits the 4.10 arcade-cities positioning.
|
||||
- **Movement heat is veteran+expert in 4.10** (the +0x260 gate), not expert-only as the 4.0 manual
|
||||
states. Whether a coefficient still differentiates them is open.
|
||||
|
||||
## Port state (as of 2026-07-18) — wiring needed [T3]
|
||||
|
||||
The reconstruction met this system piecemeal and stubbed the same gates inconsistently:
|
||||
- `btplayer.cpp` ctor seeds `roleClassIndex` from `scenarioRole->GetReturnFromDeath()` (default 2)
|
||||
— the binary seeds it from `btMission->ExperienceLevel()`. Bring-up therefore runs as VETERAN.
|
||||
Two slot errors in the port's switch vs the binary: the binary's switch never touches +0x264
|
||||
(that's advancedDamage, set after), and expert's `0` lands on +0x26c, not +0x270.
|
||||
- `HeatModelActive()` stubbed permissive `return 1` (emitter/heat/mislanch/projweap) while
|
||||
`Myomers::OwnerAdvancedDamage()` returns `False` — the SAME binary gate (+0x260) answered both
|
||||
ways: heat accrues from weapons but never from movement, and no experience below veteran can
|
||||
switch it off.
|
||||
- `LiveFireEnabled` / `ControlsAllowLights` / powersub's short-event flag = the +0x25c not-novice
|
||||
flag under three names.
|
||||
- **The fix**: one accessor family on BTPlayer named members (databinding trap — never raw-read
|
||||
`player+0x260`), seeded from `BTMission::ExperienceLevel()` + `AdvancedDamageOn()`, with all five
|
||||
stub sites pointed at it; then an egg `experience` line actually selects the sim tier as shipped.
|
||||
|
||||
## Corrections (swept 2026-07-18)
|
||||
|
||||
- `btplayer.hpp` "per-role display toggles from returnFromDeath" for 0x25c-0x274 was WRONG — the
|
||||
source is `btMission+0xe4/+0xf0`, not the role; the `showKills`/`roleClassIndex` names date from
|
||||
the scoring work and don't match the gate semantics (kept in code for now, comments corrected).
|
||||
- `gauges-hud.md` "ROOKIE-role lockout" for FUN_004ac9c8 → novice-EXPERIENCE lockout.
|
||||
- `open-questions.md` "true semantic of player+0x260/0x274 not yet pinned" → pinned here.
|
||||
|
||||
## Key Relationships
|
||||
- Feeds: [[subsystems]] (the heat model + jam/valve gates) · [[combat-damage]] (criticals tier intent) · [[gauges-hud]] (valve guard)
|
||||
- Sourced from: the egg ([[multiplayer]] egg format) · `BTMission` (BTMSSN.HPP, T0)
|
||||
- Offsets: [[decomp-reference]] §3 (mech+0x190 row + BTPlayer flag block)
|
||||
- Manual audit: [[pod-hardware]] §Manual
|
||||
@@ -150,10 +150,11 @@ moves. Diag: `BT_RADAR_LOG` ([radar] ctor probe + 1 Hz [radar-wedge] rot trace).
|
||||
## Remaining = DATA FEEDS, not widgets (deferred systems)
|
||||
**✅ The condenser valve CONTROL is LIVE (task #13, 2026-07-11) [T2]:** `MoveValve` (id 4, the
|
||||
Condenser handler table @0x50E52C — exactly one entry) registered + guarded by the REAL
|
||||
FUN_004ac9c8 = `player+0x274 roleClassIndex == 0` (the ROOKIE-role lockout; task #12's
|
||||
`BTPlayerRoleLocksAdvanced` bridge — the old "game-mode flag / likely off in a basic mission"
|
||||
hedge is superseded: bring-up role = 2 = UNLOCKED, verified live: press → valveState 1→5 →
|
||||
flow redistribution 1/6 → 5/10). Desktop: 'C' cycles the selected condenser (BT_VALVE_SLOT).
|
||||
FUN_004ac9c8 = `player+0x274 == 0` (2026-07-18 correction: +0x274 = the egg EXPERIENCE level,
|
||||
so this is the NOVICE lockout, not a "ROOKIE role" — see [[experience-levels]]; task #12's
|
||||
`BTPlayerRoleLocksAdvanced` bridge; bring-up seeding = 2 ≈ veteran = UNLOCKED, verified live:
|
||||
press → valveState 1→5 → flow redistribution 1/6 → 5/10). Desktop: 'C' cycles the selected
|
||||
condenser (BT_VALVE_SLOT).
|
||||
The **MessageBoard** feed needs **StatusMessagePool** (a NULL stub) + the per-player status
|
||||
queue. `SeekVoltageGraph`'s 4 Seek* attrs are a cluster-child (not config-called). [T2]
|
||||
|
||||
|
||||
+28
-21
@@ -151,7 +151,8 @@ register. ⚠ The audit also flags the damage-economy item as SELF-CONTRADICTOR
|
||||
btl4vid.cpp `MakeMechRenderables` reticle-build/inside pass (== arcade part_014.c:5173, Dynamic,
|
||||
bound per Searchlight `lightState` via a new `LightStatePtr()` accessor); (3) a toggle input (the
|
||||
authentic cockpit button-5→`ToggleLamp` dispatch is a controls-family reconstruction; a dev key
|
||||
stands in). Also flags a deferred **`Mech::ControlsAllowLights()`** (searchlight.hpp:158 stub).
|
||||
stands in). Also flags a deferred **`Mech::ControlsAllowLights()`** (searchlight.hpp:158 stub;
|
||||
2026-07-18: identified as the `player+0x25c` not-novice experience flag — [[experience-levels]]).
|
||||
See [[rendering]] fog section. Verified inert live: BT_FOG_LOG shows zero `SetFogStyle(2/3)`.
|
||||
- **Factory capability-roster loops 2-4 are STILL DEAD (task #57 discovery).** mech.cpp's
|
||||
post-roster loops add to `heatableSubsystems`(0x51155c)/`weaponRoster`(0x511830)/
|
||||
@@ -187,20 +188,24 @@ register. ⚠ The audit also flags the damage-economy item as SELF-CONTRADICTOR
|
||||
- **✅ `mech+0x190` IDENTIFIED (2026-07): it is the owning `BTPlayer`** (`Mech::GetPlayerLink()`,
|
||||
`MECH_OWNING_PLAYER`; ENTITY.h:430). Set by `FUN_0049f624` (the mech↔player bind: `mech+0x190 = player`
|
||||
AND `player->playerVehicle(+0x1fc) = mech`), which resolves the player from the mission player registry
|
||||
(`app+0x2c+0x54`, `FUN_0041fd18`) by the pilot key. The valve/Myomers "gates" read the owning player's
|
||||
fields at `player+0x260` and `player+0x274` (the reconstruction maps this block as `showDamageReceived@0x25c
|
||||
/ showKills@0x260 / showDamageInflicted@0x264 / roleClassIndex@0x274` in btplayer.hpp — from the SCORING
|
||||
work, so the names may NOT match the gate semantics; the true meaning + the WRITER of `player+0x260/0x274`
|
||||
are not yet pinned — part_013.c:4553-4660 is the TorsoSimulation, a different object, not the setter). So
|
||||
there is NO new subsystem to build. **The wiring (small):** point `MechSubsystem::IsDamaged()` (`FUN_004ac9c8`, valve
|
||||
guard) at `GetPlayerLink()->`(0x274) and `Myomers::OwnerAdvancedDamage()` (`FUN_004ad7d4`) at
|
||||
`GetPlayerLink()->`(0x260) — via NAMED members (databinding trap: our BTPlayer layout ≠ binary; do NOT
|
||||
raw-read `player+0x260`). ⚠ Resolve first: (a) a naming conflict — `FUN_004ad7d4` is labeled BOTH
|
||||
`HeatModelActive` (heat.hpp) AND `OwnerAdvancedDamage` (myomers.cpp); re-verify which body is which; (b)
|
||||
the true semantic of `player+0x260/0x274` vs the scoring-derived `showKills`/`roleClassIndex` names. NOTE:
|
||||
these are MODE flags — in the basic test mission the inert Myomers / dormant valve is likely AUTHENTIC
|
||||
(advanced damage off); wiring makes them RESPOND when a mission enables the mode, not necessarily change
|
||||
the basic-mission behavior. The MessageBoard feed is separate (StatusMessagePool, below).
|
||||
(`app+0x2c+0x54`, `FUN_0041fd18`) by the pilot key.
|
||||
**✅ FLAG SEMANTICS PINNED (2026-07-18) [T1]: the `player+0x25c..0x274` block = the EXPERIENCE
|
||||
LEVEL (egg `experience` novice/standard/veteran/expert), written by the BTPlayer ctor @4c0bc8
|
||||
from `btMission(+0x1f8)->experienceLevel(+0xe4)` — full mapping, consumers, and the 4.0-manual
|
||||
behavior in [[experience-levels]] (+ [[decomp-reference]] §3 flag table).** Resolved en route: the
|
||||
old "resolve first" items — `FUN_004ad7d4` (labeled both `HeatModelActive` and `OwnerAdvancedDamage`)
|
||||
is ONE body reading `player+0x260` = the heat-model master switch (veteran+expert); `FUN_004ac9c8`
|
||||
reads `player+0x274` = the novice lockout; the btplayer.hpp `showKills`/`roleClassIndex` scoring
|
||||
names indeed do NOT match the gate semantics (comments corrected in place, member names kept).
|
||||
**The wiring (small, still open):** ONE accessor family on BTPlayer named members seeded from
|
||||
`BTMission::ExperienceLevel()`/`AdvancedDamageOn()` (databinding trap: do NOT raw-read
|
||||
`player+0x260`), then point the five stub sites at it (`HeatModelActive` permissive-1 in
|
||||
emitter/heat/mislanch/projweap vs `OwnerAdvancedDamage` False in myomers — currently the SAME gate
|
||||
answered both ways; `LiveFireEnabled`/`ControlsAllowLights`/powersub short-event = the +0x25c
|
||||
flag under three names; ctor seeding from role->returnFromDeath is a bring-up stand-in that runs
|
||||
every mission as VETERAN). NOTE: these are MODE flags — an egg with `experience=standard` should
|
||||
authentically have inert movement-heat/jams; wiring makes the tier selectable, not the basic
|
||||
mission different. The MessageBoard feed is separate (StatusMessagePool, below).
|
||||
- **✅ Authentic target acquisition RECONSTRUCTED (tasks #36/#39, 2026-07-08)** — the `Reticle`
|
||||
pick-ray chain is LIVE (see [[combat-damage]] Targeting for the full port map): the crosshair =
|
||||
**torso boresight** (NO free-aim mouse — the pod stick twisted the torso; you steer to aim) →
|
||||
@@ -352,17 +357,19 @@ register. ⚠ The audit also flags the damage-economy item as SELF-CONTRADICTOR
|
||||
tables must be function-local statics INSIDE the accessor (cross-TU static-init
|
||||
order emptied the table -- see [[reconstruction-gotchas]] #9 last bullet); (b)
|
||||
**FUN_004ac9c8 is NOT IsDamaged** -- raw body: `owner(+0xD0) -> mech+0x190 player
|
||||
-> roleClassIndex(+0x274) == 0` = the ROOKIE-role lockout for advanced cockpit
|
||||
systems (port bridge BTPlayerRoleLocksAdvanced, btplayer.cpp; NULL player =
|
||||
unlocked [T3]; bring-up role defaults to 2 = unlocked). AUDIT TAIL: the other
|
||||
-> +0x274 == 0` = the NOVICE-experience lockout for advanced cockpit systems
|
||||
(2026-07-18 correction: +0x274 = the egg experience level, NOT a role class --
|
||||
see [[experience-levels]]; port bridge BTPlayerRoleLocksAdvanced, btplayer.cpp;
|
||||
NULL player = unlocked [T3]; bring-up seeding defaults to 2 ≈ veteran = unlocked).
|
||||
AUDIT TAIL: the other
|
||||
powersub.cpp sites annotated FUN_004ac9c8 (the coolant-draw gate ~:427,
|
||||
ForceShortRecovery ~:444, the Generator/PowerWatcher site ~:1085) still call the
|
||||
heat-family IsDamaged (simulationState != 0) stand-in -- each needs its raw fn
|
||||
re-checked and swapped to the role bridge where the binary calls 4ac9c8.
|
||||
- **Myomers authentic coupling** — the structural un-stub is INERT (mover feed + heat-gen no-op).
|
||||
Real coupling needs the advanced-damage gate (`OwnerAdvancedDamage`/`FUN_004ad7d4` → the owning
|
||||
**BTPlayer** `mech+0x190`+0x260, NOT 0xBD3 — see the mech+0x190 item above) + `MoverAttach` routing
|
||||
into the LIVE JointedMover (must be reconciled with the gait cutover first).
|
||||
Real coupling needs the heat-model gate (`OwnerAdvancedDamage`/`FUN_004ad7d4` → the owning
|
||||
**BTPlayer** `mech+0x190`+0x260 = veteran/expert experience, NOT 0xBD3 — see [[experience-levels]])
|
||||
+ `MoverAttach` routing into the LIVE JointedMover (must be reconciled with the gait cutover first).
|
||||
- **SeekVoltageGraph** — 4 Seek* attrs unpublished (a cluster-child, not config-called; non-blocking).
|
||||
|
||||
- **✅ DAMAGE ECONOMY — AUTHENTIC (task #8, 2026-07-11) [T1/T2].** The whole economy closes:
|
||||
|
||||
@@ -154,7 +154,10 @@ every checked control behavior:
|
||||
button 8 → ChooseNearestPilot); radar = travel-oriented, 60° vision wedge sweeps with twist,
|
||||
red hot box + callsign on contacts; **map zoom ± buttons** flank the secondary screen.
|
||||
- **Experience gates the hunting aids**: viewscreen hot box + hunting-guide arrow appear in
|
||||
STANDARD sim mode only (not veteran/expert); expert mode adds movement heat.
|
||||
STANDARD sim mode only (not veteran/expert); expert mode adds movement heat. (2026-07-18 [T1]:
|
||||
4.0→4.10 drift — in OUR 4.10 binary the HUD reads NO experience flag (hotbox/arrows are
|
||||
lock-gated in every mode) and movement heat is veteran+expert; full wiring in
|
||||
[[experience-levels]].)
|
||||
- Cockpit: 5 MFDs (Coolant UL, Engineering top, Hot Box UR, Weapon ×2) + secondary screen with
|
||||
side button columns + **EJECT button** beside the joystick + per-mech COOLANT LOOP tables
|
||||
(weapons+generators per loop 1-6) and stat sheets (tonnage/armor/reservoir liters/heat
|
||||
|
||||
@@ -57,8 +57,8 @@ Making a base byte-exact GROWS every subclass — they must be re-based TOGETHER
|
||||
- **✅ DONE (task #7, `afefaee`)** — SubsystemMessageManager 0xBD3 (a
|
||||
**damage/explosion consolidation hub** cached to `Mech[0x10d]`=0x434; the factory builds the REAL
|
||||
class and `mech.hpp` names the slot `messageManager` — the old `controlsMapper` mislabel is swept,
|
||||
the real mapper is roster slot 0. NOT the valve/advanced-damage gate — that's the owning **BTPlayer**
|
||||
@mech+0x190, see [[combat-damage]]/[[open-questions]]). [T2]
|
||||
the real mapper is roster slot 0. NOT the valve/heat-model gate — that's the owning **BTPlayer**
|
||||
@mech+0x190 carrying the EXPERIENCE-level flags, see [[experience-levels]]). [T2]
|
||||
|
||||
## The watcher electrical chain (task #57, 2026-07-13 — the torso power gate)
|
||||
The Watcher branch is POWERED indirectly: a watcher WATCHES another roster subsystem and mirrors
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -356,23 +356,29 @@ class DropZone__ReplyMessage;
|
||||
suppressConsole; // @0x258 skip console notify for this score event
|
||||
|
||||
//
|
||||
// Per-role display toggles, selected from the role's "returnFromDeath"
|
||||
// class index (scenarioRole resource +0xe4, values 0..3) at @004c0bc8.
|
||||
// EXPERIENCE-LEVEL game-mode flags (2026-07-18 [T1] — the old "per-role
|
||||
// display toggles / returnFromDeath" reading was WRONG). The ctor
|
||||
// @004c0bc8 seeds this block from btMission(+0x1f8)->experienceLevel
|
||||
// (+0xe4, the egg's per-pilot "experience" novice/standard/veteran/
|
||||
// expert) and ->advancedDamageOn(+0xf0) — NOT from the scenario role.
|
||||
// The member NAMES below date from the scoring work and do not match
|
||||
// the semantics; kept until the wiring task renames them. Binary
|
||||
// mapping (nov/std/vet/exp) + consumers: context/experience-levels.md.
|
||||
//
|
||||
Logical
|
||||
showDamageReceived; // @0x25c
|
||||
showDamageReceived; // @0x25c 0/1/1/1 "sim live" (novice lockout: jams, searchlight, powersub @4b0efc)
|
||||
Logical
|
||||
showKills; // @0x260
|
||||
showKills; // @0x260 0/0/1/1 HEAT-MODEL master switch (FUN_004ad7d4)
|
||||
Logical
|
||||
showDamageInflicted;// @0x264
|
||||
showDamageInflicted;// @0x264 = mission advancedDamageOn (copy 1; NOT part of the level switch)
|
||||
Logical
|
||||
showScore; // @0x270
|
||||
showScore; // @0x270 0/1/1/1 consumer not located
|
||||
Scalar
|
||||
roleReturnDelay; // @0x268 (role resource +0xf0)
|
||||
roleReturnDelay; // @0x268 = mission advancedDamageOn (copy 2; int in the binary)
|
||||
Scalar
|
||||
roleReturnDelay2; // @0x26c
|
||||
roleReturnDelay2; // @0x26c 0/1/1/0 consumer not located (supercharge-clamp hypothesis [T4])
|
||||
int
|
||||
roleClassIndex; // @0x274 (role resource +0xe4)
|
||||
roleClassIndex; // @0x274 raw experience level 0..3 (FUN_004ac9c8 = ==0 novice predicate)
|
||||
friend int BTPlayerRoleLocksAdvanced(void *); // the FUN_004ac9c8 bridge (task #12)
|
||||
friend void BTPlayerCountObservedDeath(void *); // observed-death tally (MP DEATHS fix)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user