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>
1382 lines
33 KiB
C++
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, ¤t_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());
|
|
}
|