BTPlayer::CreatePlayerVehicle reconstructed (faithful; BT411's BT_SPAWN_XZ/ BT_SPAWN_ENEMY bring-up scaffolding dropped): builds the Mech::MakeMessage from the mission game-model resource and hands it to MakeAndLinkViewpointEntity. Mech::Make = new Mech(creation_message); a staged Mech ctor chains the real JointedMover base (so the model skeleton/segments stream from BTL4.RES) then Fails. This validates the entire spawn factory chain live: CreatePlayerVehicle -> MakeAndLinkViewpointEntity -> registry -> Mech::Make -> new Mech -> JointedMover base ctor (streams the mech model) -> halts at the Mech ctor (mech.cpp:66). The Mech ctor (@004a1674, 5690 bytes -- the largest function in the game) plus the subsystem roster is the next MAJOR milestone, not a brick: it needs the full 1995 Mech member layout derived first (MECH.HPP is still reserved[331]; BT411's decomp uses raw offset pokes that can't compile fresh), the subsystem class hierarchy (only GAUSS/PPC/SENSOR survive in the 4.10 archive; the rest are the measured "917 missing functions"), and the segment-table walk. Plan + scope in MECH.NOTES.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
408 lines
11 KiB
C++
408 lines
11 KiB
C++
//===========================================================================//
|
|
// File: btplayer.cpp //
|
|
// Project: BattleTech //
|
|
// Contents: Implementation details for the BT player //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include <bt.hpp>
|
|
#pragma hdrstop
|
|
|
|
#if !defined(BTPLAYER_HPP)
|
|
# include <btplayer.hpp>
|
|
#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
|
|
|
|
#if !defined(DROPZONE_HPP)
|
|
# include <dropzone.hpp>
|
|
#endif
|
|
|
|
#if !defined(MECH_HPP)
|
|
# include <mech.hpp>
|
|
#endif
|
|
|
|
#if !defined(RESOURCE_HPP)
|
|
# include <resource.hpp>
|
|
#endif
|
|
|
|
#if !defined(HOSTMGR_HPP)
|
|
# include <hostmgr.hpp>
|
|
#endif
|
|
|
|
#if !defined(MISSION_HPP)
|
|
# include <mission.hpp>
|
|
#endif
|
|
|
|
//
|
|
//#############################################################################
|
|
// Shared data support
|
|
//#############################################################################
|
|
//
|
|
Derivation
|
|
BTPlayer::ClassDerivations(
|
|
Player::ClassDerivations,
|
|
"BTPlayer"
|
|
);
|
|
|
|
const Receiver::HandlerEntry
|
|
BTPlayer::MessageHandlerEntries[]=
|
|
{
|
|
MESSAGE_ENTRY(BTPlayer,DropZoneReply),
|
|
MESSAGE_ENTRY(BTPlayer,VehicleDead),
|
|
MESSAGE_ENTRY(BTPlayer,Score),
|
|
MESSAGE_ENTRY(BTPlayer,ScoreInflicted),
|
|
MESSAGE_ENTRY(BTPlayer,ScoreUpdate)
|
|
};
|
|
|
|
BTPlayer::MessageHandlerSet
|
|
BTPlayer::MessageHandlers(
|
|
ELEMENTS(BTPlayer::MessageHandlerEntries),
|
|
BTPlayer::MessageHandlerEntries,
|
|
Player::MessageHandlers
|
|
);
|
|
|
|
BTPlayer::SharedData
|
|
BTPlayer::DefaultData(
|
|
BTPlayer::ClassDerivations,
|
|
BTPlayer::MessageHandlers,
|
|
Player::AttributeIndex,
|
|
1,
|
|
(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(
|
|
MakeMessage *creation_message,
|
|
SharedData &shared_data
|
|
):
|
|
Player(creation_message, shared_data)
|
|
{
|
|
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()
|
|
{
|
|
Check(this);
|
|
Check_Fpu();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// Make
|
|
//#############################################################################
|
|
//
|
|
BTPlayer*
|
|
BTPlayer::Make(MakeMessage *creation_message)
|
|
{
|
|
return new BTPlayer(creation_message);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
BTPlayer::TestInstance() const
|
|
{
|
|
return IsDerivedFrom(ClassDerivations);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// GetExperienceLevel
|
|
//#############################################################################
|
|
//
|
|
Enumeration
|
|
BTPlayer::GetExperienceLevel()
|
|
{
|
|
Check(this);
|
|
Check(btMission);
|
|
return Cast_Object(BTMission *, btMission)->ExperienceLevel();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// DropZoneReplyMessageHandler The spawn / respawn handshake: when the drop
|
|
// zone replies with our spawn location we create (or, on respawn, reset) the
|
|
// player's vehicle there and bind it to us.
|
|
//
|
|
// The mech placement / respawn-reset tail depends on the Mech subsystem
|
|
// (Mech::MechClassID / Mech::Reset), which is not yet reconstructed; the
|
|
// dispatch skeleton below halts at CreatePlayerVehicle -> Mech::Make on the
|
|
// first (fresh-drop) reply. See BTPLAYER.NOTES.md.
|
|
//#############################################################################
|
|
//
|
|
void
|
|
BTPlayer::DropZoneReplyMessageHandler(DropZone__ReplyMessage *message)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
|
|
if (!playerVehicle)
|
|
{
|
|
CreatePlayerVehicle(message->dropZoneLocation);
|
|
InitializePlayerLink();
|
|
|
|
//
|
|
// A piloted mech runs the combat PlayerSimulation and is a scoring
|
|
// player; a camera-ship observer runs CameraShipSimulation and never
|
|
// ranks. (Vehicle-class dispatch + mech placement deferred with the
|
|
// Mech subsystem.)
|
|
//
|
|
AlwaysExecute();
|
|
deathCount = 0;
|
|
}
|
|
else if (deathCount == message->deathCount)
|
|
{
|
|
if (GetSimulationState() == MissionEndingState)
|
|
{
|
|
Check_Fpu();
|
|
return;
|
|
}
|
|
//
|
|
// Respawn: reset the existing dead mech in place (deferred with the
|
|
// Mech subsystem).
|
|
//
|
|
}
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// CreatePlayerVehicle Build the player's mech from the mission game-model
|
|
// resource and bind it as the viewpoint entity. (An observer player gets a
|
|
// MUNGA camera ship from the base Player::CreatePlayerVehicle instead.)
|
|
//
|
|
// Constructs the Mech::MakeMessage and hands it to MakeAndLinkViewpointEntity,
|
|
// which routes through the registry to Mech::Make -> the Mech ctor (the mech
|
|
// subsystem, not yet reconstructed -- current boot frontier).
|
|
//#############################################################################
|
|
//
|
|
void
|
|
BTPlayer::CreatePlayerVehicle(Origin mech_location)
|
|
{
|
|
Check(this);
|
|
Check(application);
|
|
|
|
ResourceFile *resources = application->GetResourceFile();
|
|
Check(resources);
|
|
Check_Pointer(playerMission->GetGameModel());
|
|
|
|
HostManager *host_manager = application->GetHostManager();
|
|
Check(host_manager);
|
|
|
|
//
|
|
// Make any MUNGA-level vehicle (a camera ship for an observer player).
|
|
//
|
|
Player::CreatePlayerVehicle(mech_location);
|
|
|
|
//
|
|
// If the player still has no vehicle, build him a mech and link to it.
|
|
//
|
|
if (!playerVehicle)
|
|
{
|
|
ResourceDescription *mech_res =
|
|
resources->FindResourceDescription(
|
|
playerMission->GetGameModel(),
|
|
ResourceDescription::ModelListResourceType
|
|
);
|
|
Check(mech_res);
|
|
mech_res->Lock();
|
|
|
|
Mech::MakeMessage
|
|
create_player(
|
|
Mech::MakeMessageID,
|
|
sizeof(Mech::MakeMessage),
|
|
EntityID(host_manager->GetLocalHostID()),
|
|
(Entity::ClassID)MechClassID,
|
|
EntityID::Null,
|
|
mech_res->resourceID,
|
|
Mech::DefaultFlags,
|
|
mech_location,
|
|
Motion::Identity,
|
|
Motion::Identity,
|
|
playerMission->GetBadgeName(),
|
|
playerMission->GetColorName(),
|
|
((BTMission *)playerMission)->GetPatchName()
|
|
);
|
|
|
|
mech_res->Unlock();
|
|
|
|
playerVehicle = application->MakeAndLinkViewpointEntity(&create_player);
|
|
Register_Object(playerVehicle);
|
|
}
|
|
}
|
|
|
|
void
|
|
BTPlayer::InitializePlayerLink()
|
|
{
|
|
Fail("BTPlayer::InitializePlayerLink -- btplayer.cpp not yet reconstructed");
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// Scoring / death handlers -- exercised in combat, not during bring-up boot.
|
|
//#############################################################################
|
|
//
|
|
void
|
|
BTPlayer::VehicleDeadMessageHandler(VehicleDeadMessage *)
|
|
{
|
|
Fail("BTPlayer::VehicleDeadMessageHandler -- btplayer.cpp not yet reconstructed");
|
|
}
|
|
|
|
void
|
|
BTPlayer::ScoreMessageHandler(ScoreMessage *)
|
|
{
|
|
Fail("BTPlayer::ScoreMessageHandler -- btplayer.cpp not yet reconstructed");
|
|
}
|
|
|
|
void
|
|
BTPlayer::ScoreInflictedMessageHandler(ScoreMessage *)
|
|
{
|
|
Fail("BTPlayer::ScoreInflictedMessageHandler -- btplayer.cpp not yet reconstructed");
|
|
}
|
|
|
|
void
|
|
BTPlayer::ScoreUpdateMessageHandler(ScoreMessage *)
|
|
{
|
|
Fail("BTPlayer::ScoreUpdateMessageHandler -- btplayer.cpp not yet reconstructed");
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// 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");
|
|
}
|