Fixes the incorrect DefaultData reuse of Player::MessageHandlers -- BTPlayer now has its own handler table (DropZoneReply, VehicleDead, Score, ScoreInflicted, ScoreUpdate; the last two add BT message IDs) chained onto the base set, matching the .data table recovered in BT411. A mission-start DropZoneReply now routes to BTPlayer::DropZoneReplyMessageHandler (the real spawn/respawn dispatch skeleton) instead of the base "should not be handled by base player class" Fail stub. Boot ladder now runs the full engine + app + network + mission + player path and reaches the spawn handshake, halting at CreatePlayerVehicle -> Mech::Make -- the Mech subsystem frontier (Mech ctor + mech2/3/4 + subsystems + weapons), the next major reconstruction milestone. Scoring/death handlers, PlayerSimulation, and the mech-placement tail staged with documented Fail bodies (BTPLAYER.NOTES.md). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
90 lines
4.7 KiB
Markdown
90 lines
4.7 KiB
Markdown
# BTPLAYER.CPP / .HPP — reconstruction notes
|
|
|
|
**Status: constructor / dtor / Make / TestInstance / GetExperienceLevel +
|
|
message-handler table + DropZoneReply dispatch RECONSTRUCTED; the scoring/death
|
|
handlers, PlayerSimulation, and CreatePlayerVehicle/InitializePlayerLink (the
|
|
Mech-subsystem frontier) still staged.**
|
|
|
|
## Message-handler table (wired 2026-07-19)
|
|
|
|
DefaultData now uses `BTPlayer::MessageHandlers` (chained onto
|
|
`Player::MessageHandlers`) instead of reusing the base set — the earlier reuse
|
|
left BTPlayer's own handlers unwired, so a DropZoneReply reached the base
|
|
`Player::DropZoneReplyMessageHandler` stub that Fails "should not be handled by
|
|
base player class!" (PLAYER.CPP:179). Table entries (BT411 .data @005130c0):
|
|
DropZoneReply, VehicleDead, Score, ScoreInflicted, ScoreUpdate. ScoreInflicted/
|
|
ScoreUpdate add two BT message IDs (`Player::NextMessageID`+0/+1). MissionStarting/
|
|
MissionEnding are inherited from Player unchanged (not re-listed — BT411 lists
|
|
them but they point at the same base handlers).
|
|
|
|
`DropZoneReplyMessageHandler` is the real spawn/respawn dispatch skeleton; its
|
|
mech-placement tail (vehicle-class performance select, Mech::Reset respawn) is
|
|
deferred with the Mech subsystem. On the first fresh-drop reply it calls
|
|
`CreatePlayerVehicle` → the current boot frontier.
|
|
|
|
## Sources
|
|
|
|
- BT411 `game/reconstructed/btplayer.cpp` (Ghidra-recovered ctor @004c0bc8,
|
|
Make @004c0ecc, dtor @004c0efc, TestInstance @004c0f28) — byte-offset
|
|
annotated body.
|
|
- Surviving 1995 headers pin every base API: PLAYER.HPP (base members
|
|
currentScore/scenarioRole/deathCount/playerMission, GetMission), SIMULATE.HPP
|
|
(lastPerformance/lastUpdate/simulationFlags/activePerformance — `lastPerformance`
|
|
is a BASE member, not BT-own), ENTITY.HPP (GetInstance/ReplicantInstance),
|
|
NTTMGR.HPP (EntityManager::FindGroup, EntityGroup::groupMembers = ChainOf<Node*>),
|
|
TEAM.HPP (Team::teamName[64], public — BTTeam inherits it), BTMSSN.HPP
|
|
(BTMission::ExperienceLevel()/AdvancedDamageOn(), enum Novice/Standard/
|
|
Veteran/Expert = 0..3), SCNROLE.HPP.
|
|
|
|
## Member layout note
|
|
|
|
The staged header's `int reserved[38]` placeholder was replaced with the real
|
|
BT-own members (btMission, teamName[64], teamEntity, freeForAll, consoleAttached,
|
|
suppressConsole, the experience-flag block, killCount/padScore, objectiveMech,
|
|
lastConsoleUpdate, deathPending). Byte offsets do NOT need to match the shipped
|
|
0x294-byte object — this is a fresh self-consistent build; only wire-format
|
|
structs (MakeMessage) must match the binary, and those are unchanged.
|
|
|
|
## Experience-level flag mapping — the [T1] correction
|
|
|
|
The ctor derives the game-mode flags from **btMission->ExperienceLevel()**
|
|
(mission+0xe4, the egg's per-pilot "experience" key), NOT from the scenario
|
|
role's returnFromDeath — see [[bt-experience-levels]]. BT411's ported ctor uses
|
|
`scenarioRole->GetReturnFromDeath()` as a stand-in and marks it [T3]; this 1995
|
|
reconstruction encodes the binary-accurate reading instead.
|
|
|
|
Binary switch rows (member ← value per level), from the [T1] disassembly:
|
|
|
|
| level | showDamageReceived (0x25c) | showKills (0x260) | roleReturnDelay2 (0x26c) | showScore (0x270) |
|
|
|----------|:--:|:--:|:--:|:--:|
|
|
| novice | 0 | 0 | 0 | 0 |
|
|
| standard | 1 | 0 | 1 | 1 |
|
|
| veteran | 1 | 1 | 1 | 1 |
|
|
| expert | 1 | 1 | 0 | 1 |
|
|
|
|
Plus `showDamageInflicted` (0x264) = `roleReturnDelay` (0x268) = advancedDamageOn.
|
|
|
|
**Member NAMES are wrong-but-kept** (they date from the earlier scoring work):
|
|
`showKills` is really the HEAT-MODEL master switch (FUN_004ad7d4), `showDamageReceived`
|
|
is the "sim live / novice lockout" gate, `showScore`/`roleReturnDelay2` consumers
|
|
not fully located ([T4]). Rename is a follow-up wiring task; the VALUES are correct.
|
|
|
|
## Deliberate differences from BT411's port
|
|
|
|
- Make: the 1995 `return new BTPlayer(creation_message);` — BT411's replicant
|
|
`SetValidFlag()` is a P6 network-bring-up addition, dropped.
|
|
- Replicant-mission caching uses `application->GetCurrentMission()` (the real
|
|
1995 accessor, PLAYER.CPP:689) instead of BT411's raw `application+0xc8`.
|
|
|
|
## Still staged (next bricks, in boot order)
|
|
|
|
1. **CreatePlayerVehicle → Mech::Make** (CURRENT FRONTIER) — the spawn chain
|
|
pulls in the whole Mech subsystem: Mech ctor + mech2/mech3/mech4, mechsub,
|
|
the subsystems (sensor, gnrator, gyro, torso, hud, myomers), and the weapons
|
|
(mechweap, ppc, gauss, projtile, missile...). Mech::Make is still Fail-staged
|
|
in MECH.CPP. This is the large game-content frontier — a major milestone, not
|
|
a single brick.
|
|
2. InitializePlayerLink, the mech-placement tail of DropZoneReply (Mech::Reset).
|
|
3. VehicleDead / Score / ScoreInflicted / ScoreUpdate handlers (scoring wave),
|
|
PlayerSimulation (console update), CalcInflictedScore.
|