A Live Cam station is selected entirely by egg data - hostType=1 on that host's entry plus vehicle=camera - so no code path announces itself and a station that fails to come up leaves a log that simply stops. RP412CAMLOG=1 traces the sequence: the stand-alone host and its type, the local player node and game model, the interest-arena and interest-manager loads, the registry choosing a director, the director making its camera ship, and the launch handshake it waits on. Off by default. What it found immediately: a camera host wedges inside InterestManager::LoadMission - the map-entity load - and never returns. Everything upstream is correct (the egg parses, hostType 1 is adopted, gameModel reads 'camera'), and the same call with a racing egg passes straight through to making the player and launching. Same map both times, so it is the local host's TYPE that the map load cannot digest, not the map. That is a defect to fix before a lobby has anything to switch on. Also recorded while chasing it: a racing -egg run sits in application state 11 with the low-priority queue never empty for its whole life, and still simulates - so CheckLoad's no-console self-launch is not what starts a stand-alone race. Worth knowing before trusting that path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
887 lines
22 KiB
C++
887 lines
22 KiB
C++
#include "munga.h"
|
|
#pragma hdrstop
|
|
|
|
#include "player.h"
|
|
#include "icom.h"
|
|
#include "camship.h"
|
|
#include "dropzone.h"
|
|
#include "mission.h"
|
|
#include "audio.h"
|
|
#include "director.h"
|
|
#include "app.h"
|
|
#include "hostmgr.h"
|
|
#include "nttmgr.h"
|
|
#include "console.h"
|
|
#include "appmsg.h"
|
|
|
|
//#############################################################################
|
|
//####################### Player::StatusMessage #########################
|
|
//#############################################################################
|
|
|
|
Player__StatusMessage::Player__StatusMessage(Player *player_involved, int message_type, Scalar display_time)
|
|
{
|
|
playerInvolved = player_involved;
|
|
messageType = message_type;
|
|
displayTime = display_time;
|
|
}
|
|
|
|
//#############################################################################
|
|
//############################### Player ################################
|
|
//#############################################################################
|
|
|
|
//#############################################################################
|
|
// Shared Data Support
|
|
//
|
|
Derivation* Player::GetClassDerivations()
|
|
{
|
|
static Derivation classDerivations(Entity::GetClassDerivations(), "Player");
|
|
return &classDerivations;
|
|
}
|
|
|
|
Player::SharedData
|
|
Player::DefaultData(
|
|
Player::GetClassDerivations(),
|
|
Player::GetMessageHandlers(),
|
|
Player::GetAttributeIndex(),
|
|
Player::StateCount,
|
|
(Entity::MakeHandler)Player::Make
|
|
);
|
|
|
|
//#############################################################################
|
|
// Attribute Support
|
|
//
|
|
|
|
const Player::IndexEntry
|
|
Player::AttributePointers[]=
|
|
{
|
|
ATTRIBUTE_ENTRY(Player, CurrentScore, currentScore),
|
|
ATTRIBUTE_ENTRY(Player, PlayerRanking, playerRanking),
|
|
ATTRIBUTE_ENTRY(Player, DropZoneLocation, dropZoneLocation),
|
|
ATTRIBUTE_ENTRY(Player, StatusMessagePointer,statusMessagePointer),
|
|
ATTRIBUTE_ENTRY(Player, PlayerBitmapIndex, playerBitmapIndex),
|
|
ATTRIBUTE_ENTRY(Player, PlayerHighlighted, playerHighlighted)
|
|
};
|
|
|
|
Player::AttributeIndexSet& Player::GetAttributeIndex()
|
|
{
|
|
static Player::AttributeIndexSet attributeIndex(ELEMENTS(Player::AttributePointers),
|
|
Player::AttributePointers,
|
|
Entity::GetAttributeIndex()
|
|
);
|
|
return attributeIndex;
|
|
}
|
|
|
|
//#############################################################################
|
|
// Message Support
|
|
//
|
|
const Receiver::HandlerEntry
|
|
Player::MessageHandlerEntries[]=
|
|
{
|
|
MESSAGE_ENTRY(Player, DropZoneReply),
|
|
MESSAGE_ENTRY(Player, Score),
|
|
MESSAGE_ENTRY(Player, VehicleDead),
|
|
MESSAGE_ENTRY(Player, MissionStarting),
|
|
MESSAGE_ENTRY(Player, MissionEnding)
|
|
};
|
|
|
|
Receiver::MessageHandlerSet& Player::GetMessageHandlers()
|
|
{
|
|
static Receiver::MessageHandlerSet messageHandlers(ELEMENTS(Player::MessageHandlerEntries), Player::MessageHandlerEntries, Entity::GetMessageHandlers());
|
|
return messageHandlers;
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Player::MissionStartingMessageHandler(Message *)
|
|
{
|
|
Check(this);
|
|
Tell("Player::MissionStartingMessageHandler - starting fade in\n");
|
|
fadeTimeRemaining = 3.0f;
|
|
SetSimulationState(MissionStartingState);
|
|
Check_Fpu();
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Player::MissionEndingMessageHandler(Message *)
|
|
{
|
|
Check(this);
|
|
fadeTimeRemaining = 3.0f;
|
|
ForceUpdate();
|
|
SetSimulationState(MissionEndingState);
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Enumeration
|
|
Player::GetAudioRepresentation(
|
|
#if DEBUG_LEVEL>0
|
|
Entity *linked_entity
|
|
#else
|
|
Entity *
|
|
#endif
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(linked_entity);
|
|
Check_Fpu();
|
|
|
|
return
|
|
(GetInstance() == MasterInstance) ?
|
|
InternalAudioRepresentation : ExternalAudioRepresentation;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Player::ScoreMessageHandler(ScoreMessage *message)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
|
|
currentScore += message->scoreAward;
|
|
|
|
//
|
|
// HACK - ECH 7/6/95 - Allow the player vehicle to respond to score
|
|
// messages, allows attribute system to be used for scoring
|
|
//
|
|
Check(playerVehicle);
|
|
playerVehicle->RespondToScoreMessage(message);
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Player::DropZoneReplyMessageHandler(
|
|
DropZone::ReplyMessage * //message
|
|
)
|
|
{
|
|
Check(this);
|
|
Fail("Drop zone reply should not be handled by base player class!\n");
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Player::CreatePlayerVehicle(Origin camera_origin)
|
|
{
|
|
Check(this);
|
|
//
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Create any MUNGA level vehicles
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
if (RPCameraLog())
|
|
{
|
|
DEBUG_STREAM << "CamLog: CreatePlayerVehicle, cameraShipPlayer="
|
|
<< (int) (IsCameraShipPlayer() ? 1 : 0) << "\n" << std::flush;
|
|
}
|
|
if (IsCameraShipPlayer())
|
|
{
|
|
Check(application);
|
|
ResourceFile *resources = application->GetResourceFile();
|
|
Check(resources);
|
|
Check_Pointer(playerMission->GetGameModel());
|
|
|
|
HostManager *host_manager = application->GetHostManager();
|
|
Check(host_manager);
|
|
ResourceDescription *camera_res =
|
|
resources->FindResourceDescription(
|
|
playerMission->GetGameModel(),
|
|
ResourceDescription::ModelListResourceType
|
|
);
|
|
if (RPCameraLog())
|
|
{
|
|
DEBUG_STREAM << "CamLog: model '" << playerMission->GetGameModel()
|
|
<< "' resource " << (camera_res ? "FOUND" : "MISSING") << "\n" << std::flush;
|
|
}
|
|
Check(camera_res);
|
|
CameraShip::MakeMessage
|
|
create_camera(
|
|
CameraShip::MakeMessageID,
|
|
sizeof(CameraShip::MakeMessage),
|
|
EntityID(host_manager->GetLocalHostID()),
|
|
CameraShipClassID,
|
|
EntityID::Null,
|
|
camera_res->resourceID,
|
|
CameraShip::DefaultFlags,
|
|
camera_origin,
|
|
Motion::Identity,
|
|
Motion::Identity
|
|
);
|
|
CameraShip *camera =
|
|
(CameraShip*)application->MakeAndLinkViewpointEntity(&create_camera);
|
|
Register_Object(camera);
|
|
playerVehicle = camera;
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Player::VehicleDeadMessageHandler(VehicleDeadMessage *message)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
Check(application);
|
|
|
|
|
|
//DEBUG_STREAM << "VEHICLEDEAD : " << endl << std::flush;
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// If we have let the player fry, send a message to the dropzone to give us
|
|
// a new location to return to
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
if (
|
|
message->deathCount == deathCount
|
|
&& GetSimulationState() != DropZoneAcquiredState)
|
|
{
|
|
DropZone *dropzone;
|
|
|
|
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// If no dropzone has been assigned to this death, find the closest one
|
|
//---------------------------------------------------------------------
|
|
//
|
|
if (message->dropZoneID == EntityID::Null)
|
|
{
|
|
|
|
//DEBUG_STREAM << " Find Closest" << endl << std::flush;
|
|
|
|
EntityManager *entity_manager = application->GetEntityManager();
|
|
Check(entity_manager);
|
|
EntityGroup *dropzones = entity_manager->FindGroup("DropZones");
|
|
Check(dropzones);
|
|
ChainIteratorOf<Node*> iterator(dropzones->groupMembers);
|
|
|
|
DropZone *closest_dropzone;
|
|
Vector3D range;
|
|
Scalar closest_range;
|
|
|
|
while ((dropzone = (DropZone*)iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check(dropzone);
|
|
|
|
if (!strnicmp(dropzone->GetDropZoneName(), "win", 3))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
closest_dropzone = dropzone;
|
|
range.Subtract(
|
|
localOrigin.linearPosition,
|
|
dropzone->localOrigin.linearPosition
|
|
);
|
|
closest_range = range.LengthSquared();
|
|
break;
|
|
}
|
|
|
|
while ((dropzone = (DropZone*)iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check(dropzone);
|
|
if (!strnicmp(dropzone->GetDropZoneName(), "win", 3))
|
|
{
|
|
continue;
|
|
}
|
|
range.Subtract(
|
|
localOrigin.linearPosition,
|
|
dropzone->localOrigin.linearPosition
|
|
);
|
|
Scalar len = range.LengthSquared();
|
|
if (len < closest_range)
|
|
{
|
|
closest_dropzone = dropzone;
|
|
closest_range = len;
|
|
}
|
|
}
|
|
message->dropZoneID = closest_dropzone->GetEntityID();
|
|
dropzone = closest_dropzone;
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------
|
|
// Otherwise, get this one from the host manager
|
|
//----------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
//DEBUG_STREAM << " Use Assigned" << endl << std::flush;
|
|
|
|
HostManager *host = application->GetHostManager();
|
|
Check(host);
|
|
dropzone =
|
|
Cast_Object(
|
|
DropZone*,
|
|
host->GetEntityPointer(message->dropZoneID)
|
|
);
|
|
}
|
|
|
|
Check(dropzone);
|
|
DropZone::AssignDropZoneMessage
|
|
request(
|
|
DropZone::AssignDropZoneMessageID,
|
|
sizeof(DropZone::AssignDropZoneMessage),
|
|
GetEntityID(),
|
|
DropZoneReplyMessageID,
|
|
deathCount
|
|
);
|
|
dropzone->Dispatch(&request);
|
|
Time when = Now();
|
|
when += 2.0f;
|
|
application->Post(HighEventPriority, this, message, when);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Player::HuntForDropZone(Scalar)
|
|
{
|
|
Check(this);
|
|
Check(playerMission);
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// See if our designated drop zone is around yet. If the dropzone group
|
|
// does not exist, then no dropzones at all are available
|
|
//----------------------------------------------------------------------
|
|
//
|
|
Check(application);
|
|
EntityManager *entity_manager = application->GetEntityManager();
|
|
Check(entity_manager);
|
|
EntityGroup *dropzones = entity_manager->FindGroup("DropZones");
|
|
if (!dropzones)
|
|
{
|
|
Check_Fpu();
|
|
return;
|
|
}
|
|
|
|
Check(dropzones);
|
|
ChainIteratorOf<Node*> iterator(dropzones->groupMembers);
|
|
DropZone *dropzone;
|
|
const char* zone_name = playerMission->GetDropZoneName();
|
|
while ((dropzone = (DropZone*)iterator.ReadAndNext()) != NULL)
|
|
{
|
|
if (!strcmp(dropzone->GetDropZoneName(), zone_name))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// If it is, reset our performance, and send a message to the drop zone to
|
|
// give us a location
|
|
//------------------------------------------------------------------------
|
|
//
|
|
if (dropzone)
|
|
{
|
|
|
|
//DEBUG_STREAM << "FOUND DROPZONE" << endl << std::flush;
|
|
|
|
Check(dropzone);
|
|
SetPerformance(&Player::DoNothingOnce);
|
|
VehicleDeadMessage
|
|
dead(
|
|
VehicleDeadMessageID,
|
|
sizeof(VehicleDeadMessage),
|
|
dropzone->GetEntityID()
|
|
);
|
|
dead.deathCount = -2;
|
|
|
|
DropZone::AssignDropZoneMessage
|
|
request(
|
|
DropZone::AssignDropZoneMessageID,
|
|
sizeof(DropZone::AssignDropZoneMessage),
|
|
GetEntityID(),
|
|
DropZoneReplyMessageID,
|
|
deathCount
|
|
);
|
|
dropzone->Dispatch(&request);
|
|
Time when = Now();
|
|
when += 2.0f;
|
|
application->Post(HighEventPriority, this, &dead, when);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Player::ManageApplicationStatus(Scalar time_slice)
|
|
{
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// If we are in the game start/stop phase, count the timer down and send the
|
|
// appropriate message to the application when done
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Check(this);
|
|
Check(application);
|
|
switch (GetSimulationState())
|
|
{
|
|
case MissionStartingState:
|
|
Verify(fadeTimeRemaining <= 3.0f);
|
|
fadeTimeRemaining -= time_slice;
|
|
if (fadeTimeRemaining <= 0.0f)
|
|
{
|
|
SetSimulationState(VehicleTranslocatedState);
|
|
Check(application);
|
|
switch (application->GetApplicationState())
|
|
{
|
|
case Application::LaunchingMission:
|
|
{
|
|
Application::RunMissionMessage message;
|
|
application->Dispatch(&message);
|
|
}
|
|
break;
|
|
case Application::ResumingMission:
|
|
{
|
|
Application::ResumeMissionMessage message;
|
|
application->Dispatch(&message);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case MissionEndingState:
|
|
fadeTimeRemaining -= time_slice;
|
|
if (fadeTimeRemaining <= 0.0f)
|
|
{
|
|
Check(application);
|
|
switch (application->GetApplicationState())
|
|
{
|
|
case Application::EndingMission:
|
|
{
|
|
// Fill in appropriate exit code here. GAH
|
|
Application::StopMissionMessage message(NullExitCodeID);
|
|
application->Dispatch(&message);
|
|
}
|
|
break;
|
|
case Application::AbortingMission:
|
|
{
|
|
// Fill in appropriate exit code here. GAH
|
|
Application::AbortMissionMessage message(NullExitCodeID);
|
|
application->Dispatch(&message);
|
|
}
|
|
break;
|
|
case Application::SuspendingMission:
|
|
{
|
|
Application::SuspendMissionMessage message;
|
|
application->Dispatch(&message);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Player::CameraShipSimulation(Scalar time_slice)
|
|
{
|
|
Check(this);
|
|
CalcRanking();
|
|
|
|
ManageApplicationStatus(time_slice);
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Player::PlayerSimulation(Scalar time_slice)
|
|
{
|
|
Check(this);
|
|
|
|
//-------------------------------
|
|
// Calculate the player's ranking
|
|
//-------------------------------
|
|
CalcRanking();
|
|
|
|
//----------------------------------
|
|
// ...manage the application status?
|
|
//----------------------------------
|
|
ManageApplicationStatus(time_slice);
|
|
|
|
//-------------------------------
|
|
// Copy vehicle position
|
|
//-------------------------------
|
|
if (playerVehicle)
|
|
{
|
|
Check(playerVehicle);
|
|
localOrigin = playerVehicle->localOrigin;
|
|
localToWorld = playerVehicle->localToWorld;
|
|
}
|
|
|
|
//---------------------------------
|
|
// Service the status message queue
|
|
//---------------------------------
|
|
StatusMessageUpdate(time_slice);
|
|
|
|
Check_Fpu();
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Player::GoToVehicle(Scalar)
|
|
{
|
|
Check(this);
|
|
if (playerVehicle)
|
|
{
|
|
Check(playerVehicle);
|
|
localOrigin = playerVehicle->localOrigin;
|
|
localToWorld = playerVehicle->localToWorld;
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
Player::CalcRanking()
|
|
{
|
|
|
|
//
|
|
//---------------------------------------
|
|
// Get all players from the entity group
|
|
//---------------------------------------
|
|
//
|
|
EntityGroup *player_group =
|
|
application->GetEntityManager()->FindGroup("Players");
|
|
if(player_group)
|
|
{
|
|
int num_players = 0;
|
|
Player *active_player;
|
|
//
|
|
//-----------------------------------------------------
|
|
// Iterate through the players add to the sorted chain
|
|
//-----------------------------------------------------
|
|
//
|
|
ChainIteratorOf<Node*> iterator(player_group->groupMembers);
|
|
VChainOf<Player*, Scalar> player_rank(NULL, False);
|
|
while ((active_player = (Player*) iterator.ReadAndNext()) != NULL)
|
|
{
|
|
if(active_player->IsScoringPlayer())
|
|
{
|
|
player_rank.AddValue(active_player, active_player->currentScore);
|
|
++num_players;
|
|
//
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Reset Player Highlighted
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
active_player->playerHighlighted = False;
|
|
}
|
|
else
|
|
{
|
|
active_player->playerRanking = -1;
|
|
}
|
|
|
|
}
|
|
--num_players;
|
|
//
|
|
//------------------------------------------------
|
|
// Iterate through the chain assigning the rank
|
|
//------------------------------------------------
|
|
//
|
|
VChainIteratorOf<Player*, Scalar> rank_iterator(player_rank);
|
|
|
|
|
|
while ((active_player = rank_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
active_player->playerRanking = num_players;
|
|
//
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// If player in first place turn on player highlighted
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
if (!active_player->playerRanking)
|
|
{
|
|
active_player->playerHighlighted = True;
|
|
}
|
|
--num_players;
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
return 1;
|
|
}
|
|
//#############################################################################
|
|
// Update Support
|
|
//
|
|
void
|
|
Player::ReadUpdateRecord(Simulation::UpdateRecord *message)
|
|
{
|
|
Check(this);
|
|
Check_Pointer(message);
|
|
Entity::ReadUpdateRecord(message);
|
|
UpdateRecord* record = (UpdateRecord*) message;
|
|
|
|
currentScore = record->currentScore;
|
|
dropZoneLocation = record->dropZoneLocation;
|
|
Check_Fpu();
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Player::WriteUpdateRecord(
|
|
Simulation::UpdateRecord *record,
|
|
int update_model
|
|
)
|
|
{
|
|
Check(this);
|
|
Check_Pointer(record);
|
|
|
|
Entity::WriteUpdateRecord(record, update_model);
|
|
|
|
UpdateRecord* update = (UpdateRecord*) record;
|
|
|
|
update->recordLength = sizeof(*update);
|
|
update->currentScore = currentScore;
|
|
update->dropZoneLocation = dropZoneLocation;
|
|
Check_Fpu();
|
|
}
|
|
|
|
|
|
//#############################################################################
|
|
// Construction and Destruction
|
|
//
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Player::Player(
|
|
Player::MakeMessage *creation_message,
|
|
Player::SharedData &virtual_data
|
|
):
|
|
Entity(creation_message, virtual_data),
|
|
statusMessageQueue(NULL)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Pointer(creation_message);
|
|
|
|
scenarioRole = NULL;
|
|
//---------------------------------
|
|
// Initialize data
|
|
//---------------------------------
|
|
statusMessagePointer = NULL;
|
|
//
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Initialize the playerMission
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
playerMission = application->GetCurrentMission();
|
|
Check(playerMission);
|
|
//
|
|
//---------------------------------
|
|
// Set the resource ID for a player
|
|
//---------------------------------
|
|
//
|
|
Check(application);
|
|
Check(application->GetResourceFile());
|
|
ResourceDescription *resource_description =
|
|
application->GetResourceFile()->FindResourceDescription(
|
|
"player",
|
|
ResourceDescription::ModelListResourceType
|
|
);
|
|
if (resource_description != NULL)
|
|
{
|
|
Verify(resourceID == ResourceDescription::NullResourceID);
|
|
resourceID = resource_description->resourceID;
|
|
}
|
|
//
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Get the host type associated with the entity ID
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
HostType host_type;
|
|
|
|
HostID host_ID = entityID.GetHostID();
|
|
Check(application);
|
|
HostManager *host_mgr = application->GetHostManager();
|
|
Check(host_mgr);
|
|
Host *local_host = host_mgr->GetLocalHost();
|
|
Check(local_host);
|
|
if (host_ID == local_host->GetHostID())
|
|
{
|
|
host_type = local_host->GetHostType();
|
|
}
|
|
else
|
|
{
|
|
HostManager::RemoteHostIterator iterator(host_mgr);
|
|
local_host = iterator.Find(host_ID);
|
|
Check(local_host);
|
|
host_type = local_host->GetHostType();
|
|
}
|
|
|
|
if (IsCameraShipPlayer())
|
|
{
|
|
//
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Make A CameraPlayers Entity Group
|
|
// since cameras are not involved in
|
|
// standard game play they need a
|
|
// separate Entity Group!
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
playerBitmapIndex = -1;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Make A Regular Players Entity Group
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Check(application);
|
|
EntityManager *entity_manager = application->GetEntityManager();
|
|
Check(entity_manager);
|
|
EntityGroup *players = entity_manager->UseGroup("Players");
|
|
Check(players);
|
|
players->Add(this);
|
|
playerBitmapIndex = creation_message->playerBitmapIndex;
|
|
}
|
|
|
|
SetValidFlag();
|
|
playerVehicle = NULL;
|
|
if (GetInstance() != ReplicantInstance)
|
|
{
|
|
Check(application->GetCurrentMission());
|
|
playerMission = application->GetCurrentMission();
|
|
SetPerformance(&Player::HuntForDropZone);
|
|
}
|
|
else
|
|
{
|
|
SetPerformance(&Player::GoToVehicle);
|
|
playerMission = NULL;
|
|
}
|
|
|
|
playerRanking = 0;
|
|
deathCount = -2;
|
|
|
|
//-------------------------------------
|
|
// Clear score
|
|
//-------------------------------------
|
|
currentScore = 0.0f;
|
|
//-------------------------------------
|
|
// Create intercom object
|
|
//-------------------------------------
|
|
Check(application);
|
|
IcomManager
|
|
*intercom_manager = application->GetIntercomManager();
|
|
Check(intercom_manager);
|
|
|
|
intercomPointer = intercom_manager->MakeIcom(GetOwnerID());
|
|
Check(intercomPointer);
|
|
// registered in MakeIcom()
|
|
|
|
playerHighlighted = False;
|
|
fadeTimeRemaining = 0.0f;
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Player* Player::Make(Player::MakeMessage *creation_message)
|
|
{
|
|
Check_Fpu();
|
|
return new Player(creation_message, DefaultData);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Player::~Player()
|
|
{
|
|
Check(this);
|
|
|
|
//--------------------------------------------
|
|
// Delete intercom object
|
|
//--------------------------------------------
|
|
Check(intercomPointer);
|
|
Unregister_Object(intercomPointer);
|
|
delete intercomPointer;
|
|
intercomPointer = NULL;
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Player::AddStatusMessage(StatusMessage *status_message)
|
|
{
|
|
Check(this);
|
|
Check_Pointer(status_message);
|
|
statusMessageQueue.Add(status_message);
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Player::StatusMessageUpdate(Scalar time_slice)
|
|
{
|
|
Check(this);
|
|
//-------------------------------------
|
|
// We handle this queue as a STACK.
|
|
// The most recent message is presented
|
|
// first, causing older messages to
|
|
// wait "below" them on the stack.
|
|
// This allows a default message to
|
|
// sit at the "bottom" of the stack
|
|
// and allow others to override it
|
|
// temporarily.
|
|
//-------------------------------------
|
|
//
|
|
ChainIteratorOf<StatusMessage*>
|
|
iterator(statusMessageQueue);
|
|
//----------------------------------------
|
|
// ...we really want iterator.GetLast(),
|
|
// but since it doesn't exist we'll
|
|
// do it directly.
|
|
//----------------------------------------
|
|
statusMessagePointer = NULL;
|
|
{
|
|
StatusMessage
|
|
*the_message;
|
|
|
|
while ((the_message = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
statusMessagePointer = the_message;
|
|
}
|
|
}
|
|
//----------------------------------------
|
|
// If a message exists, decrement the
|
|
// timer: discard it if timed out.
|
|
//----------------------------------------
|
|
if (statusMessagePointer != NULL)
|
|
{
|
|
Check_Pointer(statusMessagePointer);
|
|
|
|
statusMessagePointer->displayTime -= time_slice;
|
|
if (statusMessagePointer->displayTime <= (Scalar) 0.0f)
|
|
{
|
|
Unregister_Object(statusMessagePointer);
|
|
delete statusMessagePointer;
|
|
statusMessagePointer = NULL;
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
Logical
|
|
Player::TestInstance() const
|
|
{
|
|
return IsDerivedFrom(*GetClassDerivations());
|
|
}
|