Files
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

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());
}