Files
RP411/RP/RPPLAYER.cpp
T
CydandClaude Opus 4.8 4abbf8879f Initial import of Red Planet v4.10 Win32 source
Imports the current Win32 source for the pod-racing game 'Red Planet',
built on the MUNGA engine and its L4 (Win32/DirectX) platform layer:

- MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend
- RP / RP_L4: Red Planet game logic and Win32 application
- DivLoader, Setup1: asset loader and installer project
- lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies

Removed stale Subversion metadata and added .gitignore/.gitattributes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 07:59:51 -05:00

1382 lines
33 KiB
C++

#include "rp.h"
#pragma hdrstop
#include "rpplayer.h"
#include "..\munga\dropzone.h"
#include "..\munga\mission.h"
#include "scorzone.h"
#include "rpcnsl.h"
#include "..\munga\app.h"
#include "vtv.h"
#include "..\munga\hostmgr.h"
#include "..\munga\nttmgr.h"
//#############################################################################
//######################## RPPlayer__StatusMessage ######################
//#############################################################################
MemoryBlock *RPPlayer__StatusMessage::GetAllocatedMemory()
{
static MemoryBlock allocatedMemory(sizeof(RPPlayer__StatusMessage), RPPlayer__StatusMessage::numberOfAllocatedBlocks, RPPlayer__StatusMessage::numberOfAllocatedBlocks);
return &allocatedMemory;
}
//#############################################################################
//############################### RPPlayer ##############################
//#############################################################################
//#############################################################################
// Message Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// General PlayerType Message Handlers
//
const Receiver::HandlerEntry
RPPlayer::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(RPPlayer, TakeDamage),
MESSAGE_ENTRY(RPPlayer, VehicleDead),
MESSAGE_ENTRY(RPPlayer, Score),
MESSAGE_ENTRY(RPPlayer, DropZoneReply),
MESSAGE_ENTRY(RPPlayer, ScoreZoneReply),
MESSAGE_ENTRY(RPPlayer, MissionStarting),
MESSAGE_ENTRY(RPPlayer, MissionEnding)
};
Receiver::MessageHandlerSet& RPPlayer::GetMessageHandlers()
{
static Receiver::MessageHandlerSet messageHandlers(ELEMENTS(RPPlayer::MessageHandlerEntries), RPPlayer::MessageHandlerEntries, Player::GetMessageHandlers());
return messageHandlers;
}
//#############################################################################
// Shared Data Support
//
Derivation* RPPlayer::GetClassDerivations()
{ static Derivation classDerivations(Player::GetClassDerivations(), "RPPlayer");
return &classDerivations;
}
RPPlayer::SharedData
RPPlayer::DefaultData(
RPPlayer::GetClassDerivations(),
RPPlayer::GetMessageHandlers(),
RPPlayer::GetAttributeIndex(),
RPPlayer::StateCount,
(RPPlayer::MakeHandler)RPPlayer::Make
);
//#############################################################################
// Attribute Support
//
const RPPlayer::IndexEntry
RPPlayer::AttributePointers[]=
{
ATTRIBUTE_ENTRY(RPPlayer, GoalEntity, goalEntity)
};
RPPlayer::AttributeIndexSet& RPPlayer::GetAttributeIndex()
{
static RPPlayer::AttributeIndexSet attributeIndex(ELEMENTS(RPPlayer::AttributePointers),
RPPlayer::AttributePointers,
Player::GetAttributeIndex()
);
return attributeIndex;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
static Origin first_drop;
Entity *first_goal;
void
RPPlayer::MissionStartingMessageHandler(Message *message)
{
Check(this);
Check(message);
Player::MissionStartingMessageHandler(message);
Check(application);
if (application->GetApplicationState() == Application::ResumingMission)
{
Check(playerVehicle);
if (playerVehicle->IsDerivedFrom(*VTV::GetClassDerivations()))
{
currentScore = 1000.0f;
}
}
else
{
first_goal = goalEntity;
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPPlayer::MissionEndingMessageHandler(Message *message)
{
Player::MissionEndingMessageHandler(message);
Check(application);
HostManager *host_manager = application->GetHostManager();
Check(host_manager);
Host *console_host = host_manager->GetConsoleHost();
if (console_host)
{
Check(console_host);
if (application->GetApplicationState() == Application::EndingMission)
{
ConsoleApplicationEndMissionMessage
score_message(ownerID, (int)currentScore);
application->SendMessage(
console_host->GetHostID(),
NetworkClient::ConsoleClientID,
&score_message
);
}
else
{
ConsoleApplicationAbortMissionMessage
score_message(ownerID);
application->SendMessage(
console_host->GetHostID(),
NetworkClient::ConsoleClientID,
&score_message
);
}
}
lastConsoleUpdate -= 15.0f;
Check(application);
if (application->GetApplicationState() == Application::SuspendingMission)
{
Check(playerVehicle);
if (playerVehicle->IsDerivedFrom(*VTV::GetClassDerivations()))
{
if (first_goal != goalEntity)
{
ScoreZone::ProcessScoreZoneRequestMessage
message(
ScoreZone::ProcessScoreZoneRequestMessageID,
sizeof(ScoreZone::ProcessScoreZoneRequestMessage),
GetEntityID(),
ScoreZoneReplyMessageID,
goalEntity->localOrigin.linearPosition
);
goalEntity->Dispatch(&message);
}
VTV *vtv = (VTV*) playerVehicle;
Check(vtv);
vtv->Reset(first_drop, True);
ForceUpdate();
}
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void RPPlayer::CreatePlayerVehicle(Origin vtv_location)
{
Check(this);
Check(&vtv_location);
Check(application);
ResourceFile *resources = application->GetResourceFile();
Check(resources);
Check_Pointer(playerMission->GetGameModel());
HostManager *host_manager = application->GetHostManager();
Check(host_manager);
//
// Create MUNGA level vehicles
//
Player::CreatePlayerVehicle(vtv_location);
//
//-----------------------------------------------------------------------
// If the player has made no vehicle yet, make him a new one and link the
// player to it
//-----------------------------------------------------------------------
//
if (!playerVehicle)
{
ResourceDescription *vtv_res =
resources->FindResourceDescription(
playerMission->GetGameModel(),
ResourceDescription::ModelListResourceType
);
Check(vtv_res);
vtv_res->Lock();
VTV::MakeMessage
create_player(
VTV::MakeMessageID,
sizeof(VTV::MakeMessage),
EntityID(host_manager->GetLocalHostID()),
VTV::VTVClassID,
EntityID::Null,
vtv_res->resourceID,
VTV::DefaultFlags|VTV::InitialStasisFlag,
vtv_location,
Motion::Identity,
Motion::Identity,
playerMission->GetBadgeName(),
playerMission->GetColorName()
);
vtv_res->Unlock();
playerVehicle = application->MakeAndLinkViewpointEntity(&create_player);
Register_Object(playerVehicle);
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void RPPlayer::InitializePlayerLink()
{
Check(this);
PlayerLinkMessage player_link_message (
PlayerLinkMessageID,
sizeof(PlayerLinkMessage),
this->GetEntityID()
);
Check(playerVehicle);
playerVehicle->Dispatch(&player_link_message);
playerVehicle->DispatchToReplicants(&player_link_message);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void RPPlayer::SetGoalToFirstScoreZone()
{
//
//----------------------------------------------------------
// Change the goalEntity to the first sequential scorezone
//----------------------------------------------------------
//
EntityGroup *score_zone_group =
application->GetEntityManager()->FindGroup("ActiveScoreZones");
if(score_zone_group)
{
ChainIteratorOf<Node*> iterator(score_zone_group->groupMembers);
ScoreZone *score_zone;
while ((score_zone = (ScoreZone*)iterator.ReadAndNext()) != NULL)
{
if (
(
(score_zone->scoreZoneType == LocalSequential) ||
(score_zone->scoreZoneType == GlobalSequential)
) &&
score_zone->sequenceNumber == 1
)
{
goalEntity = score_zone;
break;
}
}
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void RPPlayer::PointVTVTowardGoal()
{
Check(this);
if (!goalEntity)
{
return;
}
Vector3D to_goal;
to_goal.Subtract(
goalEntity->localOrigin.linearPosition,
playerVehicle->localOrigin.linearPosition
);
UnitVector current_heading;
playerVehicle->localToWorld.GetFromAxis(Z_Axis, &current_heading);
Scalar length_to_goal;
length_to_goal = to_goal.LengthSquared();
if (length_to_goal > SMALL)
{
Scalar dot_prod;
dot_prod = (to_goal * current_heading) / Sqrt(length_to_goal);
if (dot_prod >= 0.0f)
{
Quaternion turn_around;
Quaternion y_roll(0.0f,1.0f,0.0f,0.0);
Check(playerVehicle);
turn_around.Multiply(
playerVehicle->localOrigin.angularPosition,
y_roll
);
playerVehicle->localOrigin.angularPosition = turn_around;
playerVehicle->localToWorld = playerVehicle->localOrigin;
playerVehicle->ForceUpdate();
}
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void RPPlayer::ResetAfterDeath(DropZone::ReplyMessage *message)
{
Check(this);
Check(message);
Check(application);
message->deathCount = ++deathCount;
ForceUpdate();
SetSimulationState(DropZoneAcquiredState);
dropZoneLocation = message->dropZoneLocation;
Time when = Now();
when += 1.0f;
application->Post(HighEventPriority, this, message, when);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPPlayer::DropZoneReplyMessageHandler(
DropZone::ReplyMessage *message
)
{
Check(this);
Check(message);
//
//-----------------------------------------------------------------------
// If the player has made no vehicle yet, make him a new one and link the
// player to it
//-----------------------------------------------------------------------
//
if (!playerVehicle)
{
first_drop = message->dropZoneLocation;
CreatePlayerVehicle(message->dropZoneLocation);
InitializePlayerLink();
SetGoalToFirstScoreZone();
switch(playerVehicle->GetClassID())
{
case VTVClassID:
SetPerformance(&RPPlayer::PlayerSimulation);
break;
case CameraShipClassID:
SetPerformance(&RPPlayer::CameraShipSimulation);
playerRanking = -1;
break;
}
AlwaysExecute();
deathCount = 0;
}
//
//-------------------------------------------------------------------------
// Otherwise, just set the new position of the VTV and turn off the burning
// stuff.
//-------------------------------------------------------------------------
//
else if (deathCount == message->deathCount)
{
if (GetSimulationState() == MissionEndingState)
{
Check_Fpu();
return;
}
if (GetSimulationState() != DropZoneAcquiredState)
{
ResetAfterDeath(message);
return;
}
}
//
//---------------------------------
// Make sure we ignore old messages
//---------------------------------
//
else
{
Check_Fpu();
return;
}
//
//-----------------------------------
// Delete All offensivePlayers
//-----------------------------------
//
DeleteAllOffensivePlayers();
ForceUpdate();
SetSimulationState(VehicleTranslocatedState);
if (playerVehicle->GetClassID() == VTVClassID)
{
VTV *vtv = (VTV*)playerVehicle;
Check(vtv);
vtv->Reset(message->dropZoneLocation, VTV::RegularReset);
}
//
//---------------------------------------------------
// Always Point vtv in the direction of the scorezone
//---------------------------------------------------
//
PointVTVTowardGoal();
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// GetPlayer
//
RPPlayer*
RPPlayer::GetPlayer(EntityID playerID)
{
Check(this);
Check(&playerID);
//
//---------------------------------------------------
// Get the pointer to the RPPlayer from the playerID
//---------------------------------------------------
//
Check(application);
HostManager *host = application->GetHostManager();
Check(host);
RPPlayer *rp_player = Cast_Object(
RPPlayer*,
host->GetEntityPointer(playerID)
);
Check(rp_player);
Check_Fpu();
return rp_player;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPPlayer::DeleteAllOffensivePlayers()
{
VChainIteratorOf<OffensivePlayer*, Enumeration>
iterator(offensivePlayerList);
OffensivePlayer
*current_player;
while ((current_player = iterator.GetCurrent()) != NULL)
{
Unregister_Object(current_player);
delete current_player;
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPPlayer::CleanUpOffensivePlayers()
{
VChainIteratorOf<OffensivePlayer*, Enumeration>
iterator(offensivePlayerList);
OffensivePlayer
*current_player;
while ((current_player = iterator.GetCurrent()) != NULL)
{
Check(current_player);
if(Now() - current_player->timeStamp >= 2.0f)
{
OffensivePlayer *stale_player = iterator.GetCurrent();
Unregister_Object(stale_player);
delete stale_player;
}
else
{
iterator.Next();
}
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPPlayer::TakeDamageMessageHandler (TakeDamageMessage *message)
{
Check(this);
Check(message);
//
//-------------------------------------------------------
// Scale the damage amount to point loss on this vehicle
//-------------------------------------------------------
//
VTV*
our_vtv = (VTV*)playerVehicle;
Check(our_vtv);
if (GetSimulationState() != MissionEndingState)
{
Scalar score_loss = message->damageData.damageAmount;
if (message->damageData.damageType == Damage::CollisionDamageType)
{
score_loss *= our_vtv->deathConstant;
}
ScoreMessage score_message(
RPPlayer::ScoreMessageID,
sizeof(RPPlayer::ScoreMessageID),
DamageScoreLossPointType,
-score_loss,
GetEntityID()
);
Dispatch(&score_message);
//
//-----------------------------------------------------------
// Clean up the list, and look for a player to give points to
//-----------------------------------------------------------
//
CleanUpOffensivePlayers();
VChainIteratorOf<OffensivePlayer*, Enumeration>
iterator(offensivePlayerList);
if(iterator.GetCurrent())
{
//
//--------------------------------------------------------
// Send a score message to the player at the top
// of the offensivePlayer list the points for this damage
//--------------------------------------------------------
//
OffensivePlayer *top_player = iterator.GetCurrent();
RPPlayer *player_points = top_player->offensivePlayer;
if (
top_player->deathBonus
&& top_player->timeStamp < ((RPPlayer*)our_vtv)->lastPerformance
&& top_player->offensivePlayer != this
)
{
if (top_player->deathBonus < 0.0f)
{
score_loss = -score_loss;
}
ScoreMessage score_message(
RPPlayer::ScoreMessageID,
sizeof(RPPlayer::ScoreMessage),
DamageBonusPointType,
score_loss,
GetEntityID()
);
if (score_loss < 0.0f)
{
score_message.scoreType = DropZoneHitType;
}
player_points->Dispatch(&score_message);
Check(application);
HostManager *host_manager = application->GetHostManager();
Check(host_manager);
Host *console_host = host_manager->GetConsoleHost();
if (console_host)
{
Check(console_host);
ConsolePlayerVTVDamagedMessage
scored_message(
ownerID,
player_points->ownerID,
score_loss,
score_loss
);
application->SendMessage(
console_host->GetHostID(),
NetworkClient::ConsoleClientID,
&scored_message
);
}
}
}
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPPlayer::AddOffensivePlayer(OffensivePlayer &offensive_player)
{
Check(this);
Check(&offensive_player);
//
//----------------------------------------------------------------
// Calculate the deathBonus based on playerType and damageType
//----------------------------------------------------------------
//
if(offensive_player.damageType == Damage::CollisionDamageType)
{
offensive_player.deathBonus = 500.0f;
}
else
{
offensive_player.deathBonus = 0.0f;
}
offensivePlayerList.AddValue(
&offensive_player,
offensive_player.damageType
);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPPlayer::ScoreMessageHandler(ScoreMessage *message)
{
Check(this);
Check(message);
Check(playerVehicle);
if (GetSimulationState() == MissionEndingState)
{
return;
}
//
//-------------------------------------------------------------------------
// If this is a score zone message, tell the console (if there is one) that
// we scored
//-------------------------------------------------------------------------
//
Check(application);
HostManager *host_manager = application->GetHostManager();
Check(host_manager);
switch (message->scoreType)
{
case ScoreZonePointType:
{
Host
*console_host = host_manager->GetConsoleHost();
if (console_host)
{
Check(console_host);
ConsolePlayerVTVScoredMessage
scored_message(ownerID);
application->SendMessage(
console_host->GetHostID(),
NetworkClient::ConsoleClientID,
&scored_message
);
}
//-------------------------------------
// Inform pilot of score zone entry
//-------------------------------------
RPPlayer
*player =
(RPPlayer*)host_manager->GetEntityPointer(message->pointSender);
Check(player);
if (player->playerType != RunnerPlayerType)
{
RPStatusMessage *message = new RPStatusMessage(NULL, RPStatusMessage::ScoreZoneMessage, 6.0f);
Register_Object(message);
AddStatusMessage((StatusMessage *) message);
}
}
break;
case DeathBonusPointType:
case DropZoneKillType:
{
//-------------------------------------
// Inform pilot of killer's identity
//-------------------------------------
RPPlayer
*killer =
(RPPlayer*)host_manager->GetEntityPointer(message->pointSender);
Check(killer);
RPStatusMessage *message = new RPStatusMessage(killer, RPStatusMessage::DestroyedMessage, 6.0f);
Register_Object(message);
AddStatusMessage((StatusMessage *) message);
}
break;
}
Player::ScoreMessageHandler(message);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPPlayer::VehicleDeadMessageHandler(VehicleDeadMessage *message)
{
Check(this);
Check(message);
if (GetSimulationState() == MissionEndingState)
{
Check_Fpu();
return;
}
//
//-------------------------------------------------------------------------
// If this is not the initial death notice, or we are still looking for our
// initial dropzone, let the player handler do its thing
//-------------------------------------------------------------------------
//
if (message->deathCount != -1)
{
Player::VehicleDeadMessageHandler(message);
Check_Fpu();
return;
}
//
//-------------------------
// Reset the VTV subsystems
//-------------------------
//
Check(playerVehicle);
VTV
*vtv = (VTV*) playerVehicle;
Check(vtv);
if ((playerType == CrusherPlayerType) ||
(playerType == BlockerPlayerType)
)
{
vtv->DeathShutdown(VTV::FootballReset);
}
else
{
vtv->DeathShutdown(VTV::RegularReset);
}
//
//----------------------------------------------------
// See if any other players get points for this death
//----------------------------------------------------
//
CleanUpOffensivePlayers();
HostID
killer_id = ownerID;
VChainIteratorOf<OffensivePlayer*, Enumeration>
iterator(offensivePlayerList);
if (iterator.GetCurrent())
{
//
//----------------------------------------------------
// Yes, send score messages...
//----------------------------------------------------
//
OffensivePlayer
*offensive_player = iterator.GetCurrent();
Check(offensive_player);
ScoreMessage
score_message(
RPPlayer::ScoreMessageID,
sizeof(RPPlayer::ScoreMessage),
DeathBonusPointType,
offensive_player->deathBonus,
GetEntityID()
);
if (offensive_player->deathBonus < 0.0f)
{
score_message.scoreType = DropZoneKillType;
}
RPPlayer
*other_player = offensive_player->offensivePlayer;
Check(other_player);
other_player->Dispatch(&score_message);
Check(application);
HostManager *host_manager = application->GetHostManager();
Check(host_manager);
Host *console_host = host_manager->GetConsoleHost();
if (console_host)
{
Check(console_host);
ConsolePlayerVTVDamagedMessage
scored_message(
ownerID,
other_player->ownerID,
offensive_player->deathBonus,
offensive_player->deathBonus
);
application->SendMessage(
console_host->GetHostID(),
NetworkClient::ConsoleClientID,
&scored_message
);
}
//
//----------------------------------------------------
// ...keep track of the killer...
//----------------------------------------------------
//
killer_id = other_player->ownerID;
//
//----------------------------------------------------
// ...and send a notice to the pilot.
//----------------------------------------------------
//
RPStatusMessage *message = new RPStatusMessage(other_player, RPStatusMessage::DestroyedByMessage, 6.0f);
Register_Object(message);
AddStatusMessage((StatusMessage *)message);
}
else
{
//
//----------------------------------------------------
// No, tell the pilot that it was self-induced.
//----------------------------------------------------
//
RPStatusMessage *message = new RPStatusMessage(NULL, RPStatusMessage::PilotErrorMessage, 6.0f);
Register_Object(message);
AddStatusMessage((StatusMessage *) message);
}
//
//------------------------------------------------
// Tell the console (if there is one) that we died
//------------------------------------------------
//
Check(application);
HostManager
*host_manager = application->GetHostManager();
Check(host_manager);
Host
*console_host = host_manager->GetConsoleHost();
if (console_host)
{
Check(console_host);
ConsolePlayerVTVKilledMessage killed_message(ownerID, killer_id);
application->SendMessage(
console_host->GetHostID(),
NetworkClient::ConsoleClientID,
&killed_message
);
}
//
//------------------------------------------------------------------------
// Send a score message of deathpointloss, and notify ourselves again in 5
// seconds so we can begin looking for the drop zone
//------------------------------------------------------------------------
//
ScoreMessage
score_message(
RPPlayer::ScoreMessageID,
sizeof(RPPlayer::ScoreMessage),
DeathScoreLossPointType,
-vtv->deathScoreLoss,
GetEntityID()
);
Dispatch(&score_message);
Time when = Now();
when += 5.0f;
message->deathCount = deathCount;
application->Post(HighEventPriority, this, message, when);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPPlayer::ScoreZoneReplyMessageHandler(
ScoreZone::ReplyMessage *message
)
{
Check(this);
Check(message);
if (GetSimulationState() == MissionEndingState)
{
Check_Fpu();
return;
}
//
//-------------------------------------------------
// Send Score message if score zone was covered
//-------------------------------------------------
//
ScoreMessage
score_message(
RPPlayer::ScoreMessageID,
sizeof(RPPlayer::ScoreMessageID),
ScoreZonePointType,
message->pointValue,
GetEntityID()
);
Dispatch(&score_message);
//
//--------------------------------------------------------------------
// Change the goalEntity to the new sequential scorezone if necessary
//--------------------------------------------------------------------
//
EntityGroup
*score_zone_group =
application->GetEntityManager()->FindGroup("ActiveScoreZones");
if(score_zone_group)
{
ChainIteratorOf<Node*>
iterator(score_zone_group->groupMembers);
ScoreZone
*score_zone;
while ((score_zone = (ScoreZone*) iterator.ReadAndNext()) != NULL)
{
Check(score_zone);
if (
(score_zone->scoreZoneType == LocalSequential) ||
(score_zone->scoreZoneType == GlobalSequential)
)
{
goalEntity = score_zone;
}
}
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPPlayer::PlayerSimulation(Scalar time_slice)
{
Check(this);
Check(application);
Check(application->GetEntityManager());
Check(playerVehicle);
//
//------------------------------------------------------------------------
// Check for our synchronization signal
//------------------------------------------------------------------------
//
if (
(GetSimulationState() == MissionStartingState) &&
((fadeTimeRemaining - time_slice) <= 0.0f)
)
{
lastConsoleUpdate = Now();
}
if (!goalEntity)
{
SetGoalToFirstScoreZone();
PointVTVTowardGoal();
}
//
//------------------------------------------------------------------------
// Call PlayerSimulation
//------------------------------------------------------------------------
//
Player::PlayerSimulation(time_slice);
if (
application->GetApplicationState() != Application::RunningMission
&& application->GetApplicationState() != Application::EndingMission
)
{
return;
}
//
//------------------------------------------------------------------------
// Update everybody once per second
//------------------------------------------------------------------------
//
if (lastPerformance - lastUpdate >= 1.0f)
{
ForceUpdate();
}
//
//------------------------------------------------------------------------
// Update the console every 15 seconds
//------------------------------------------------------------------------
//
if (lastPerformance - lastConsoleUpdate >= 15.0f)
{
lastConsoleUpdate = lastPerformance;
//
//---------------------------------------------
// Tell the console (if there is one) our score
//---------------------------------------------
//
Check(application);
HostManager *host_manager = application->GetHostManager();
Check(host_manager);
Host *console_host = host_manager->GetConsoleHost();
if (console_host)
{
Check(console_host);
ConsolePlayerVTVScoreUpdateMessage
score_message(ownerID, (int)currentScore);
application->SendMessage(
console_host->GetHostID(),
NetworkClient::ConsoleClientID,
&score_message
);
}
}
//
//------------------------------------------------------------------------
// See if there are any zones to check
//------------------------------------------------------------------------
//
if (
GetSimulationState() != MissionEndingState
&& application->GetApplicationState() == Application::RunningMission
)
{
EntityGroup *score_zone_group =
application->GetEntityManager()->FindGroup("ActiveScoreZones");
if(!score_zone_group)
{
Check_Fpu();
return;
}
//
//----------------------------------
// If VTV is in a BurningState ie. dead
// Exit from loop and don't check
// score zones
//----------------------------------
//
VTV *vtv = (VTV*)playerVehicle;
Check(vtv);
if (vtv->GetSimulationState() == VTV::BurningState)
{
Check_Fpu();
return;
}
//
//----------------------------------
// Make an iterator and send the
// "do I get points" message to
// all the active score zones
//----------------------------------
//
Check(score_zone_group);
ChainIteratorOf<Node*>
iterator(score_zone_group->groupMembers);
ScoreZone::ProcessScoreZoneRequestMessage
message(
ScoreZone::ProcessScoreZoneRequestMessageID,
sizeof(ScoreZone::ProcessScoreZoneRequestMessage),
GetEntityID(),
ScoreZoneReplyMessageID,
playerVehicle->localOrigin.linearPosition
);
ScoreZone
*score_zone;
while ((score_zone = (ScoreZone*)iterator.ReadAndNext()) != NULL)
{
score_zone->Dispatch(&message);
}
//
//---------------------------------
// Get Points for speed if
// going in the right direction
//---------------------------------
//
AccumulateSpeedPoints(time_slice);
Check_Fpu();
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
RPPlayer::CalcRanking()
{
Check(this);
Player::CalcRanking();
Check_Fpu();
return 1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPPlayer::CalcFootballRanking()
{
//
//---------------------------------------
// Get all players from the Runner group
//---------------------------------------
//
EntityGroup
*runner_group =
application->GetEntityManager()->FindGroup("RunnerPlayers");
Check(runner_group);
Player *active_runner;
//
//-----------------------------------------------------
// Iterate through the players add to the sorted chain
//-----------------------------------------------------
//
ChainIteratorOf<Node*>
iterator(runner_group->groupMembers);
VChainOf<Player*, Scalar>
player_rank(NULL, False);
while ((active_runner = (Player*) iterator.ReadAndNext()) != NULL)
{
player_rank.AddValue(active_runner, active_runner->currentScore);
}
int num_runners = iterator.GetSize() - 1;
//
//------------------------------------------------
// Iterate through the chain assigning the rank
//------------------------------------------------
//
VChainIteratorOf<Player*, Scalar>
rank_iterator(player_rank);
while ((active_runner = rank_iterator.ReadAndNext()) != NULL)
{
active_runner->playerRanking = num_runners;
--num_runners;
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPPlayer::AccumulateSpeedPoints(Scalar time_slice)
{
Check(this);
Scalar
compression=1.0f;
if(scoreCompression)
{
Scalar
top_score=-1.0f;
EntityGroup
*player_group =
application->GetEntityManager()->FindGroup("Players");
Check(player_group);
Player
*active_player;
//
//-----------------------------------------------------
// Iterate through the players find top ranked player
//-----------------------------------------------------
//
ChainIteratorOf<Node*>
iterator(player_group->groupMembers);
while ((active_player = (Player*) iterator.ReadAndNext()) != NULL)
{
if (active_player->playerRanking == 0)
{
top_score = active_player->currentScore;
break;
}
}
if (currentScore < (top_score - 400.0f))
{
compression *= ( (top_score - currentScore) + 400.0f)/800;
}
}
//
//------------------------------------------------------
// Get Points for speed if going in the right direction
//------------------------------------------------------
//
Check(playerVehicle);
Check(goalEntity);
Vector3D
to_goal,
current_heading;
VTV
*vtv = Cast_Object(VTV*, playerVehicle);
to_goal.Subtract(
vtv->localOrigin.linearPosition,
goalEntity->localOrigin.linearPosition);
current_heading = vtv->worldLinearVelocity;
Scalar
length_to_goal,
length_current_heading;
length_to_goal = to_goal.LengthSquared();
length_current_heading = current_heading.LengthSquared();
if (length_to_goal > SMALL && length_current_heading > SMALL)
{
Scalar
dot_prod = (to_goal * current_heading) /
(Sqrt(length_to_goal) * Sqrt(length_current_heading));
if (dot_prod <= 0.985f)
{
Scalar
speed_bonus = length_current_heading;
speed_bonus /= POINTS_SPEED_RATIO;
speed_bonus *= time_slice * compression;
//
//-------------------------------------------
// Send a score message with the speed bonus
//-------------------------------------------
//
ScoreMessage
score_message(
RPPlayer::ScoreMessageID,
sizeof(RPPlayer::ScoreMessageID),
SpeedBonusPointType,
speed_bonus,
GetEntityID()
);
if (!vtv->insideWorld)
{
score_message.scoreAward = -speed_bonus;
score_message.scoreType = OutOfBoundsType;
}
Dispatch(&score_message);
}
}
Check_Fpu();
}
//#############################################################################
// Construction and Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
RPPlayer::RPPlayer(
RPPlayer::MakeMessage *creation_message,
SharedData &shared_data
):
Player(creation_message, shared_data),
offensivePlayerList(NULL, 0)
{
currentScore = 1000.0f;
lastConsoleUpdate = Now();
goalEntity = NULL;
//
//--------------------------------
// Get the info from the mission
//--------------------------------
//
teamID = creation_message->teamID;
scoreCompression = creation_message->scoreCompression;
playerType = (PlayerType) creation_message->playerType;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
RPPlayer*
RPPlayer::Make(RPPlayer::MakeMessage *creation_message)
{
return new RPPlayer(creation_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
RPPlayer::~RPPlayer()
{
Check(this);
DeleteAllOffensivePlayers();
Check_Fpu();
}
//#############################################################################
// Offensive Player
//
RPPlayer__OffensivePlayer::RPPlayer__OffensivePlayer(RPPlayer *offensive_player, int damage_type, Time time_stamp)
{
//
//-----------------------------------------
// Initialize the offensivePlayer fields
//-----------------------------------------
//
offensivePlayer = offensive_player;
damageType = damage_type;
timeStamp = time_stamp;
deathBonus = 0.0f;
Check_Fpu();
}
//#############################################################################
// RP Status message
//
RPPlayer__StatusMessage::RPPlayer__StatusMessage(
RPPlayer *player_involved,
int message_type,
Scalar display_time,
Scalar damage_amount
) :
Player__StatusMessage(
(Player *) player_involved,
message_type,
display_time
)
{
damageAmount = damage_amount;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
RPPlayer::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}