4.10 reconstruction: real BTPlayer ctor (binary-accurate experience-level flags)
Boot ladder advances past player creation. BTPlayer ctor/dtor/Make/ TestInstance/GetExperienceLevel reconstructed from BT411's Ghidra-recovered body (@004c0bc8) backdated to 1995 idiom; the reserved[38] placeholder in BTPLAYER.HPP replaced with the real BT-own members. Key fidelity call: the game-mode flags are derived from btMission->ExperienceLevel() (the egg's per-pilot experience key) with the binary-accurate switch rows from the [T1] disassembly -- NOT from the scenario role's returnFromDeath, which BT411's port uses as a [T3] stand-in. Mapping and residual naming/[T4] uncertainty documented in BTPLAYER.NOTES.md. Live boot now runs: banner -> resources -> app ctor -> network single-user -> egg -> mission -> SetPlayerData -> BTRegistry::MakePlayer -> BTPlayer ctor (resolves team, seeds experience flags) -> halts at the base Player::DropZoneReplyMessageHandler stub (BTPlayer's own message-handler table is the next brick -- DefaultData still reuses Player::MessageHandlers). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
//===========================================================================//
|
//===========================================================================//
|
||||||
|
// File: btplayer.cpp //
|
||||||
// Project: BattleTech //
|
// Project: BattleTech //
|
||||||
|
// Contents: Implementation details for the BT player //
|
||||||
|
//---------------------------------------------------------------------------//
|
||||||
|
// Date Who Modification //
|
||||||
|
// -------- --- ---------------------------------------------------------- //
|
||||||
|
// //
|
||||||
//---------------------------------------------------------------------------//
|
//---------------------------------------------------------------------------//
|
||||||
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
||||||
// All Rights reserved worldwide //
|
// All Rights reserved worldwide //
|
||||||
@@ -13,6 +19,27 @@
|
|||||||
# include <btplayer.hpp>
|
# include <btplayer.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(BTTEAM_HPP)
|
||||||
|
# include <btteam.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(BTMSSN_HPP)
|
||||||
|
# include <btmssn.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(NTTMGR_HPP)
|
||||||
|
# include <nttmgr.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(APP_HPP)
|
||||||
|
# include <app.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
//#############################################################################
|
||||||
|
// Shared data support
|
||||||
|
//#############################################################################
|
||||||
|
//
|
||||||
Derivation
|
Derivation
|
||||||
BTPlayer::ClassDerivations(
|
BTPlayer::ClassDerivations(
|
||||||
Player::ClassDerivations,
|
Player::ClassDerivations,
|
||||||
@@ -28,22 +55,167 @@ BTPlayer::SharedData
|
|||||||
(Entity::MakeHandler)BTPlayer::Make
|
(Entity::MakeHandler)BTPlayer::Make
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
//#############################################################################
|
||||||
|
// Constructor
|
||||||
|
//
|
||||||
|
// Copies the team name out of the creation message, resolves the owning
|
||||||
|
// BTTeam, caches the mission, and derives the game-mode display / heat-model
|
||||||
|
// flags from the mission's experience level and advanced-damage flag.
|
||||||
|
//#############################################################################
|
||||||
|
//
|
||||||
BTPlayer::BTPlayer(
|
BTPlayer::BTPlayer(
|
||||||
MakeMessage *creation_message,
|
MakeMessage *creation_message,
|
||||||
SharedData &shared_data
|
SharedData &shared_data
|
||||||
):
|
):
|
||||||
Player(creation_message, shared_data)
|
Player(creation_message, shared_data)
|
||||||
{
|
{
|
||||||
Fail("BTPlayer -- btplayer.cpp not yet reconstructed");
|
consoleAttached = False;
|
||||||
|
suppressConsole = False;
|
||||||
|
currentScore = 0;
|
||||||
|
deathPending = False;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Remember our team name from the creation message.
|
||||||
|
//
|
||||||
|
strcpy(teamName, creation_message->teamName);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Resolve the BTTeam entity that owns this team name.
|
||||||
|
//
|
||||||
|
teamEntity = NULL;
|
||||||
|
EntityGroup *teams = application->GetEntityManager()->FindGroup("Teams");
|
||||||
|
if (teams)
|
||||||
|
{
|
||||||
|
ChainIteratorOf<Node*> iterator(teams->groupMembers);
|
||||||
|
BTTeam *team;
|
||||||
|
while ((team = (BTTeam *)iterator.ReadAndNext()) != NULL)
|
||||||
|
{
|
||||||
|
if (strcmp(team->teamName, teamName) == 0)
|
||||||
|
{
|
||||||
|
teamEntity = team;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeForAll = True;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Cache the mission (experience level / advanced-damage source).
|
||||||
|
//
|
||||||
|
BTMission *bt_mission =
|
||||||
|
Cast_Object(BTMission *, application->GetCurrentMission());
|
||||||
|
btMission = bt_mission;
|
||||||
|
|
||||||
|
if (GetInstance() == ReplicantInstance)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Replicant: driven by console-update messages.
|
||||||
|
//
|
||||||
|
SetPerformance(&BTPlayer::PlayerSimulation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Master: derive the game-mode flags from the mission experience
|
||||||
|
// level (novice / standard / veteran / expert) and advanced-damage
|
||||||
|
// technician flag. See BTPLAYER.NOTES.md for the flag mapping.
|
||||||
|
//
|
||||||
|
Check(bt_mission);
|
||||||
|
switch (bt_mission->ExperienceLevel())
|
||||||
|
{
|
||||||
|
case BTMission::NoviceMode:
|
||||||
|
showDamageReceived = 0;
|
||||||
|
showKills = 0;
|
||||||
|
roleReturnDelay2 = 0;
|
||||||
|
showScore = 0;
|
||||||
|
break;
|
||||||
|
case BTMission::StandardMode:
|
||||||
|
showDamageReceived = 1;
|
||||||
|
showKills = 0;
|
||||||
|
roleReturnDelay2 = 1;
|
||||||
|
showScore = 1;
|
||||||
|
break;
|
||||||
|
case BTMission::VeteranMode:
|
||||||
|
showDamageReceived = 1;
|
||||||
|
showKills = 1;
|
||||||
|
roleReturnDelay2 = 1;
|
||||||
|
showScore = 1;
|
||||||
|
break;
|
||||||
|
case BTMission::ExpertMode:
|
||||||
|
showDamageReceived = 1;
|
||||||
|
showKills = 1;
|
||||||
|
roleReturnDelay2 = 0;
|
||||||
|
showScore = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
showDamageInflicted = bt_mission->AdvancedDamageOn();
|
||||||
|
roleReturnDelay = bt_mission->AdvancedDamageOn();
|
||||||
|
roleClassIndex = bt_mission->ExperienceLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
killCount = 0;
|
||||||
|
padScore = 0;
|
||||||
|
objectiveMech = NULL;
|
||||||
|
lastPerformance = lastConsoleUpdate = lastUpdate;
|
||||||
|
|
||||||
|
Check_Fpu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//#############################################################################
|
||||||
|
//#############################################################################
|
||||||
|
//
|
||||||
BTPlayer::~BTPlayer()
|
BTPlayer::~BTPlayer()
|
||||||
{
|
{
|
||||||
|
Check(this);
|
||||||
|
Check_Fpu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//#############################################################################
|
||||||
|
// Make
|
||||||
|
//#############################################################################
|
||||||
|
//
|
||||||
BTPlayer*
|
BTPlayer*
|
||||||
BTPlayer::Make(MakeMessage *)
|
BTPlayer::Make(MakeMessage *creation_message)
|
||||||
{
|
{
|
||||||
Fail("BTPlayer::Make -- btplayer.cpp not yet reconstructed");
|
return new BTPlayer(creation_message);
|
||||||
return NULL;
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//#############################################################################
|
||||||
|
//#############################################################################
|
||||||
|
//
|
||||||
|
Logical
|
||||||
|
BTPlayer::TestInstance() const
|
||||||
|
{
|
||||||
|
return IsDerivedFrom(ClassDerivations);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//#############################################################################
|
||||||
|
// GetExperienceLevel
|
||||||
|
//#############################################################################
|
||||||
|
//
|
||||||
|
Enumeration
|
||||||
|
BTPlayer::GetExperienceLevel()
|
||||||
|
{
|
||||||
|
Check(this);
|
||||||
|
Check(btMission);
|
||||||
|
return Cast_Object(BTMission *, btMission)->ExperienceLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//#############################################################################
|
||||||
|
// PlayerSimulation -- console-update performance (not yet reconstructed).
|
||||||
|
// The constructor installs this as the replicant Performance; its body is
|
||||||
|
// exercised only on a networked console-driven run.
|
||||||
|
//#############################################################################
|
||||||
|
//
|
||||||
|
void
|
||||||
|
BTPlayer::PlayerSimulation(Scalar)
|
||||||
|
{
|
||||||
|
Fail("BTPlayer::PlayerSimulation -- btplayer.cpp not yet reconstructed");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
//##################### Forward Class Declarations #######################
|
//##################### Forward Class Declarations #######################
|
||||||
class Mech;
|
class Mech;
|
||||||
class BTTeam;
|
class BTTeam;
|
||||||
|
class Mission;
|
||||||
|
|
||||||
//###########################################################################
|
//###########################################################################
|
||||||
//####################### BTPlayer Make Message #########################
|
//####################### BTPlayer Make Message #########################
|
||||||
@@ -106,11 +107,70 @@
|
|||||||
Enumeration
|
Enumeration
|
||||||
GetExperienceLevel();
|
GetExperienceLevel();
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// Model Support
|
||||||
|
//
|
||||||
|
public:
|
||||||
|
typedef void
|
||||||
|
(BTPlayer::*Performance)(Scalar time_slice);
|
||||||
|
|
||||||
|
void
|
||||||
|
SetPerformance(Performance performance)
|
||||||
|
{
|
||||||
|
Check(this);
|
||||||
|
activePerformance = (Simulation::Performance)performance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PlayerSimulation(Scalar time_slice);
|
||||||
|
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Local Data
|
// Local Data
|
||||||
//
|
//
|
||||||
protected:
|
protected:
|
||||||
int reserved[38];
|
Mission
|
||||||
|
*btMission;
|
||||||
|
char
|
||||||
|
teamName[64];
|
||||||
|
BTTeam
|
||||||
|
*teamEntity;
|
||||||
|
Logical
|
||||||
|
freeForAll;
|
||||||
|
Logical
|
||||||
|
consoleAttached;
|
||||||
|
Logical
|
||||||
|
suppressConsole;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Game-mode flags derived in the constructor from the mission's
|
||||||
|
// experience level (novice / standard / veteran / expert) and
|
||||||
|
// advanced-damage technician flag. See BTPLAYER.NOTES.md.
|
||||||
|
//
|
||||||
|
Logical
|
||||||
|
showDamageReceived;
|
||||||
|
Logical
|
||||||
|
showKills;
|
||||||
|
Logical
|
||||||
|
showDamageInflicted;
|
||||||
|
Logical
|
||||||
|
showScore;
|
||||||
|
Scalar
|
||||||
|
roleReturnDelay;
|
||||||
|
Scalar
|
||||||
|
roleReturnDelay2;
|
||||||
|
int
|
||||||
|
roleClassIndex;
|
||||||
|
|
||||||
|
int
|
||||||
|
killCount;
|
||||||
|
int
|
||||||
|
padScore;
|
||||||
|
Mech
|
||||||
|
*objectiveMech;
|
||||||
|
Time
|
||||||
|
lastConsoleUpdate;
|
||||||
|
Logical
|
||||||
|
deathPending;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# BTPLAYER.CPP / .HPP — reconstruction notes
|
||||||
|
|
||||||
|
**Status: constructor / dtor / Make / TestInstance / GetExperienceLevel
|
||||||
|
RECONSTRUCTED; message-handler table + handlers + PlayerSimulation +
|
||||||
|
CreatePlayerVehicle still staged.**
|
||||||
|
|
||||||
|
## 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. **Message-handler table** — DefaultData currently reuses `Player::MessageHandlers`,
|
||||||
|
so BTPlayer's own handlers are unwired and the base
|
||||||
|
`Player::DropZoneReplyMessageHandler` Fails ("should not be handled by base
|
||||||
|
player class!", PLAYER.CPP:179). Next brick = BTPlayer MessageHandlerEntries[]
|
||||||
|
+ MessageHandlers + real DropZoneReplyMessageHandler (spawn handshake).
|
||||||
|
2. **DropZoneReply → CreatePlayerVehicle → Mech::Make** — the spawn chain pulls
|
||||||
|
in the mech subsystem (Mech::Make still Fail-staged).
|
||||||
|
3. VehicleDead / Score / ScoreInflicted / ScoreUpdate handlers (scoring wave),
|
||||||
|
PlayerSimulation (console update), InitializePlayerLink, CalcInflictedScore.
|
||||||
Reference in New Issue
Block a user