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>
434 lines
10 KiB
C++
434 lines
10 KiB
C++
#include "rp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "crusher.h"
|
|
#include "..\munga\dropzone.h"
|
|
#include "vtv.h"
|
|
#include "..\munga\hostmgr.h"
|
|
#include "..\munga\app.h"
|
|
#include "scorzone.h"
|
|
#include "..\munga\nttmgr.h"
|
|
|
|
//#############################################################################
|
|
//############################### Crusher ##############################
|
|
//#############################################################################
|
|
|
|
//#############################################################################
|
|
// Shared Data Support
|
|
//
|
|
Derivation* Crusher::GetClassDerivations()
|
|
{ static Derivation classDerivations(RPPlayer::GetClassDerivations(), "Crusher");
|
|
return &classDerivations;
|
|
}
|
|
|
|
|
|
Crusher::SharedData
|
|
Crusher::DefaultData(
|
|
Crusher::GetClassDerivations(),
|
|
Crusher::GetMessageHandlers(),
|
|
Crusher::GetAttributeIndex(),
|
|
Crusher::StateCount,
|
|
(Crusher::MakeHandler)Crusher::Make
|
|
);
|
|
|
|
const Receiver::HandlerEntry
|
|
Crusher::MessageHandlerEntries[]=
|
|
{
|
|
MESSAGE_ENTRY(Crusher, Score),
|
|
MESSAGE_ENTRY(Crusher, DropZoneReply),
|
|
MESSAGE_ENTRY(Crusher, ScoreZoneReply)
|
|
};
|
|
|
|
Receiver::MessageHandlerSet& Crusher::GetMessageHandlers()
|
|
{
|
|
static Receiver::MessageHandlerSet messageHandlers(ELEMENTS(Crusher::MessageHandlerEntries), Crusher::MessageHandlerEntries, RPPlayer::GetMessageHandlers());
|
|
return messageHandlers;
|
|
}
|
|
|
|
//#############################################################################
|
|
// Message Support
|
|
//
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Crusher::DropZoneReplyMessageHandler(
|
|
DropZone::ReplyMessage *message
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
|
|
if (!playerVehicle)
|
|
{
|
|
CreatePlayerVehicle(message->dropZoneLocation);
|
|
InitializePlayerLink();
|
|
SetPerformance(&Crusher::PlayerSimulation);
|
|
AlwaysExecute();
|
|
deathCount = 0;
|
|
}
|
|
else if (deathCount == message->deathCount)
|
|
{
|
|
if (GetSimulationState() == MissionEndingState)
|
|
{
|
|
Check_Fpu();
|
|
return;
|
|
}
|
|
if (GetSimulationState() != DropZoneAcquiredState)
|
|
{
|
|
ResetAfterDeath(message);
|
|
Check_Fpu();
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Check_Fpu();
|
|
return;
|
|
}
|
|
DeleteAllOffensivePlayers();
|
|
ForceUpdate();
|
|
SetSimulationState(VehicleTranslocatedState);
|
|
VTV *vtv = (VTV*)playerVehicle;
|
|
Check(vtv);
|
|
vtv->Reset(message->dropZoneLocation, True);
|
|
if (goalEntity)
|
|
{
|
|
Check(goalEntity);
|
|
PointVTVTowardGoal();
|
|
vtv->ForceUpdate();
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Crusher::AddOffensivePlayer(OffensivePlayer &offensive_player)
|
|
{
|
|
Check(this);
|
|
Check(offensive_player.offensivePlayer);
|
|
RPPlayer *rp_player = offensive_player.offensivePlayer;
|
|
//
|
|
//---------------------------------------------
|
|
// Damage & Death Points awarded if ....
|
|
// This Crusher gets hit by a runner or a Blocker
|
|
// from the other team with collision Damage!
|
|
//---------------------------------------------
|
|
//
|
|
if (
|
|
(
|
|
rp_player->playerType == BlockerPlayerType
|
|
|| rp_player->playerType == RunnerPlayerType
|
|
)
|
|
&& teamID != rp_player->teamID
|
|
&& 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
|
|
Crusher::ScoreMessageHandler(ScoreMessage *message)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
Check(application);
|
|
|
|
RPPlayer::ScoreMessageHandler(message);
|
|
HostManager *host = application->GetHostManager();
|
|
Check(host);
|
|
RPPlayer *rp_player = (RPPlayer*)
|
|
host->GetEntityPointer(message->pointSender);
|
|
if (!rp_player)
|
|
{
|
|
Check_Fpu();
|
|
return;
|
|
}
|
|
|
|
Check(rp_player);
|
|
if (
|
|
rp_player->playerType == RunnerPlayerType
|
|
&& rp_player->teamID != teamID
|
|
)
|
|
{
|
|
Scalar score_award = message->scoreAward * 2.0f;
|
|
//
|
|
//------------------------------------------------------
|
|
// Create the score award and pass it on to the runner
|
|
//------------------------------------------------------
|
|
//
|
|
ScoreMessage score_message(
|
|
RPPlayer::ScoreMessageID,
|
|
sizeof(RPPlayer::ScoreMessage),
|
|
CrusherScorePointType,
|
|
score_award,
|
|
GetEntityID()
|
|
);
|
|
if (teamRunner)
|
|
{
|
|
Check(teamRunner);
|
|
teamRunner->Dispatch(&score_message);
|
|
}
|
|
}
|
|
|
|
//
|
|
// HACK - ECH 7/6/95 - Allow the player vehicle to respond to score
|
|
// messages, allows attribute system to be used for scoring
|
|
//
|
|
Check(playerVehicle);
|
|
playerVehicle->RespondToScoreMessage(message);
|
|
Check_Fpu();
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Crusher::ScoreZoneReplyMessageHandler(
|
|
ScoreZone::ReplyMessage *//message
|
|
)
|
|
{
|
|
//empty
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Crusher::PlayerSimulation(Scalar time_slice)
|
|
{
|
|
Check(this);
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Service the status message queue
|
|
//------------------------------------------------------------------------
|
|
//
|
|
StatusMessageUpdate(time_slice);
|
|
|
|
//
|
|
//-----------------------------------
|
|
// Find the runners if we haven't yet
|
|
//-----------------------------------
|
|
//
|
|
Player::PlayerSimulation(time_slice);
|
|
InitTeamRunner();
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// If we know who the enemy is, but not what his vehicle is, try to find the
|
|
// vehicle
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (enemyRunner)
|
|
{
|
|
Entity *our_vehicle = GetPlayerVehicle();
|
|
Check(our_vehicle);
|
|
if (!goalEntity)
|
|
{
|
|
goalEntity = enemyRunner->GetPlayerVehicle();
|
|
if (goalEntity)
|
|
{
|
|
PointVTVTowardGoal();
|
|
our_vehicle->ForceUpdate();
|
|
}
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Otherwise, if we aren't running yet, make sure that we are pointed in
|
|
// the correct direction - HACK
|
|
//----------------------------------------------------------------------
|
|
//
|
|
else if (
|
|
application->GetApplicationState() < Application::RunningMission
|
|
)
|
|
{
|
|
Scalar alignment = our_vehicle->localToWorld(2,2);
|
|
PointVTVTowardGoal();
|
|
if (alignment * goalEntity->localToWorld(2,2) < 0.0f)
|
|
{
|
|
our_vehicle->ForceUpdate();
|
|
}
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------
|
|
// If the game is running, set the goal properly
|
|
//----------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
goalEntity = enemyRunner->GetPlayerVehicle();
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Crusher::PointVTVTowardGoal()
|
|
{
|
|
Check(this);
|
|
Vector3D to_goal(Vector3D::Identity);
|
|
|
|
if (goalEntity)
|
|
{
|
|
//
|
|
//------------------------------
|
|
// Find the distance to the goal
|
|
//------------------------------
|
|
//
|
|
|
|
to_goal.Subtract(
|
|
goalEntity->localOrigin.linearPosition,
|
|
playerVehicle->localOrigin.linearPosition
|
|
);
|
|
|
|
Scalar length_to_goal;
|
|
length_to_goal = to_goal.LengthSquared();
|
|
|
|
//
|
|
//----------------------------
|
|
// Less than 100 meters away?
|
|
//----------------------------
|
|
//
|
|
if (length_to_goal < 10000.0f)
|
|
{
|
|
//
|
|
//-----------------------------------------------
|
|
// The goalEntity is in front of us so point in
|
|
// the same direction as the goalEntity
|
|
//-----------------------------------------------
|
|
//
|
|
playerVehicle->localOrigin.angularPosition.x = 0.0f;
|
|
playerVehicle->localOrigin.angularPosition.z = 0.0f;
|
|
if (goalEntity->localToWorld(2,2) >= 0.0f)
|
|
{
|
|
playerVehicle->localOrigin.angularPosition.y = 0.0f;
|
|
playerVehicle->localOrigin.angularPosition.w = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
playerVehicle->localOrigin.angularPosition.y = 1.0f;
|
|
playerVehicle->localOrigin.angularPosition.w = 0.0f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
//---------------------------------
|
|
// Point toward the goal Entity
|
|
// disregard and Y direction
|
|
//---------------------------------
|
|
//
|
|
playerVehicle->localOrigin.angularPosition.x = 0.0f;
|
|
playerVehicle->localOrigin.angularPosition.z = 0.0f;
|
|
//
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// is the goal in front or behind me
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
if (to_goal.z <= 0.0f)
|
|
{
|
|
playerVehicle->localOrigin.angularPosition.y = 0.0f;
|
|
playerVehicle->localOrigin.angularPosition.w = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
playerVehicle->localOrigin.angularPosition.y = 1.0f;
|
|
playerVehicle->localOrigin.angularPosition.w = 0.0f;
|
|
}
|
|
}
|
|
playerVehicle->localToWorld = playerVehicle->localOrigin;
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Crusher::Crusher(
|
|
MakeMessage *creation_message,
|
|
SharedData &shared_data
|
|
)
|
|
: RPPlayer(creation_message, shared_data)
|
|
{
|
|
StatusMessage
|
|
*message = new StatusMessage(NULL,RPStatusMessage::CrusherMessage,1e10);
|
|
Register_Object(message);
|
|
AddStatusMessage(message);
|
|
|
|
teamRunner = NULL;
|
|
enemyRunner = NULL;
|
|
Check_Fpu();
|
|
}
|
|
|
|
Crusher::~Crusher()
|
|
{
|
|
Check(this);
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Crusher*
|
|
Crusher::Make(MakeMessage *creation_message)
|
|
{
|
|
Check_Fpu();
|
|
return new Crusher(creation_message);
|
|
}
|
|
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Crusher::InitTeamRunner()
|
|
{
|
|
Check(this);
|
|
|
|
Check(application);
|
|
EntityManager *entity_mgr = application->GetEntityManager();
|
|
Check(entity_mgr);
|
|
EntityGroup *runner_group = entity_mgr->FindGroup("RunnerPlayers");
|
|
if(runner_group)
|
|
{
|
|
Check(runner_group);
|
|
ChainIteratorOf<Node*> iterator(runner_group->groupMembers);
|
|
RPPlayer *runner;
|
|
int winning_rank = 10000;
|
|
while ((runner = (RPPlayer*) iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check(runner);
|
|
if (runner->teamID == teamID)
|
|
{
|
|
teamRunner = runner;
|
|
}
|
|
else
|
|
{
|
|
if (runner->playerRanking < winning_rank)
|
|
{
|
|
enemyRunner = runner;
|
|
winning_rank = runner->playerRanking;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
Crusher::TestInstance() const
|
|
{
|
|
return IsDerivedFrom(*GetClassDerivations());
|
|
}
|