The pod hall stood the finishers on a numbered platform when the race ended. All of it shipped in this repo and none of it ever ran here: the stand geometry, the eight ranked dropzones win1-win8 in every one of the 11 maps, and the sequence that places the racers on them. The sequence lived on RPL4PlaybackApplication - the mission-review build - behind a spool file, so the app the pods actually race has never called it. RPL4Application now has its own StopMission handler that ranks the finishers, drops each onto their spot, freezes them, re-sorts the name plates into finishing order and frames a camera on the stand. It fires once: StopMission arrives twice, from the console at the buzzer and again from the player when the ending fade expires, and only the first is the end of the race. Ranking works in football as well as a race. CalcFootballRanking ranks only the RunnerPlayers group, which would have placed the runners and stopped - but nothing calls it. What runs is Player::CalcRanking, every frame, over every scoring player by score. Three pieces of the original had been stubbed out in the D3D9 port and are restored: SetViewAngle was an empty function, so the 45 degrees the sequence asks for did nothing. It now rebuilds the projection the way DPLReadINIPage does and pushes it, and sets viewRatio, which nothing had written since the DPL body was commented out. winnersCircleFogStyle was an empty case. The stand sits far off the track in open ground where the track's own fog leaves it dark; this is the blue-violet the original used, with the fog pushed back to 100/1050 and the clip plane pulled to 1100. The end-of-mission fade had to be told to stand down. It multiplies the fog colour and both fog distances toward zero every frame - correct when a race just ends, fatal to anything shown afterwards. That fade is what made the podium a black screen, and it took a while to find because every frame was being built and presented correctly the whole time. The presentation camera overrides D3DTS_VIEW between the eye renderable writing it and ExecuteImplementation reading it back for the draw calls, so no CameraShip is needed. It builds with LookAt LH, not RH: the projection is LH, and RH aims the camera the opposite way - ask to look down at the stand and you get the sky behind you. The engine's own eye renderable is right to use RH, because its forward and up come out of the entity matrix already in that convention. The mission is held open 11 seconds rather than 3. That fade timer is the only thing keeping the simulation and the renderer alive once the race is over, and it has no upper bound on the ending path. Switches, all off-by-default behaviour aside: RP412PODIUM=0 skips it, RP412PODIUMCAM=0 keeps the cockpit view, RP412PODIUMSTANDOFF/HEIGHT/AIM frame the shot, RP412MISSIONSECONDS overrides the menu game length (the shortest it offers is 3:00, a long wait when what you are testing is the buzzer), and RP412RENDERDIAG=1 reports what a frame is made of. Verified end to end on Wiseguy's Wake: the stand, its tiers, the blue 2 and 3, the red 4 through 8 and all eight name bays, held steady for the full 11 seconds and then handing off to the results screen. Known gaps: the name plates are blank, because the player1-8 textures are runtime name bitmaps that do not resolve as files in this port, and your own vehicle has no exterior model - you see the others, not yourself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1419 lines
35 KiB
C++
1419 lines
35 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"
|
|
|
|
//
|
|
// How long the mission stays up after the buzzer, for the Winners Circle.
|
|
// This timer is the only thing holding the simulation and the renderer
|
|
// open once the race is over - when it runs out the player dispatches the
|
|
// StopMission that retires the application. The stock 3 seconds is the
|
|
// fade; the rest is the podium. Kept under the +30s LightsOut post so that
|
|
// never fires while the stand is up.
|
|
//
|
|
const Scalar winnersCircleHoldTime = 11.0f;
|
|
|
|
//#############################################################################
|
|
//######################## 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);
|
|
|
|
// feed the in-process console the same final score a real console
|
|
// gets (no-op when none is registered)
|
|
if (gConsoleScoreSink != NULL &&
|
|
application->GetApplicationState() == Application::EndingMission)
|
|
{
|
|
(*gConsoleScoreSink)((int) ownerID, (int) currentScore);
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Hold the mission open for the Winners Circle.
|
|
//
|
|
// The base handler sets a 3 second fade, and when it runs out the
|
|
// player dispatches the StopMission that retires the application and
|
|
// takes the renderer with it. That is the only thing keeping the sim
|
|
// and the renderer alive after the race, so the podium gets exactly as
|
|
// long as this timer says. Sim and render both keep running throughout
|
|
// EndingMission - neither has a case for it that bails out.
|
|
//
|
|
// Only on a clean finish: an abort should still leave promptly.
|
|
//
|
|
if (application->GetApplicationState() == Application::EndingMission)
|
|
{
|
|
fadeTimeRemaining = winnersCircleHoldTime;
|
|
}
|
|
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());
|
|
}
|