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

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

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

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

567 lines
15 KiB
C++

#include "rpl4.h"
#pragma hdrstop
#include "rpl4pb.h"
#include "..\munga_l4\l4video.h"
#include "..\munga\mission.h"
#include "..\munga_l4\l4net.h"
#include "..\munga\update.h"
#include "..\munga\renderer.h"
#include "..\munga\cammppr.h"
#include "..\munga\icom.h"
#include "..\munga\nttmgr.h"
#include "..\rp\rpplayer.h"
#include "..\munga\dropzone.h"
#include "..\rp\vtv.h"
#include "..\munga\director.h"
// RB 1/14/07
//#include <dpl\matrix.h>
//#############################################################################
//########################## RPSpoolerTask ##############################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
RPSpoolerTask::RPSpoolerTask()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPSpoolerTask::DispatchPacket(NetworkPacket *packet)
{
RPL4PlaybackApplication *playback_app =
Cast_Object(RPL4PlaybackApplication*,application);
playback_app->DispatchPacket(packet);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
long
RPSpoolerTask::GetTimeBias()
{
RPL4PlaybackApplication *playback_app =
Cast_Object(RPL4PlaybackApplication*,application);
Check_Fpu();
return playback_app->GetTimeBias();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
RPSpoolerTask::~RPSpoolerTask()
{
Check_Fpu();
}
RPL4IdleApplication::RPL4IdleApplication(HINSTANCE hInstance, HWND hWnd, ResourceFile *resource)
:RPL4Application(hInstance, hWnd, resource)
{
}
RPL4IdleApplication::~RPL4IdleApplication()
{
}
NetworkManager *RPL4IdleApplication::MakeNetworkManager()
{
Check_Fpu();
return new L4PlaybackNetworkManager;
}
Registry *RPL4IdleApplication::MakeRegistry()
{
return NULL;
}
void RPL4IdleApplication::LoadBackgroundTasks()
{
Check(this);
ApplicationTask *application_task;
application_task = new GaugeRendererTask;
Register_Object(application_task);
backgroundTasks->AddTask(application_task);
}
Logical RPL4IdleApplication::ExecuteForeground(Time start_of_frame, Scalar frame_duration)
{
RPL4Application::ExecuteForeground(start_of_frame, frame_duration);
return 0;
}
Logical RPL4IdleApplication::Shutdown(int remainingApps)
{
if (remainingApps > 1)
{
return 1;
} else
{
RPL4Application::Shutdown(remainingApps);
return 0;
}
}
void
RPL4IdleApplication::Initialize()
{
Check(this);
L4Application::InitializeTillConsole();
}
//#############################################################################
//####################### RPL4PlaybackApplication #######################
//#############################################################################
const Receiver::HandlerEntry
RPL4PlaybackApplication::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(RPL4PlaybackApplication, RunMission),
MESSAGE_ENTRY(RPL4PlaybackApplication, StopMission)
};
Receiver::MessageHandlerSet& RPL4PlaybackApplication::GetMessageHandlers()
{
static Receiver::MessageHandlerSet messageHandlers(ELEMENTS(RPL4PlaybackApplication::MessageHandlerEntries), RPL4PlaybackApplication::MessageHandlerEntries, RPL4Application::GetMessageHandlers());
return messageHandlers;
}
Derivation* RPL4PlaybackApplication::GetClassDerivations()
{
static Derivation classDerivations(RPL4Application::GetClassDerivations(), "RPL4PlaybackApplication");
return &classDerivations;
}
RPL4PlaybackApplication::SharedData
RPL4PlaybackApplication::DefaultData(
RPL4PlaybackApplication::GetClassDerivations(),
RPL4PlaybackApplication::GetMessageHandlers()
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
RPL4PlaybackApplication::RPL4PlaybackApplication(
HINSTANCE hInstance,
HWND hWnd,
ResourceFile *resource_file,
SpoolFile *spool_file
):
RPL4Application(hInstance, hWnd, resource_file, L4ApplicationClassID, DefaultData)
{
Check(spool_file);
spoolFile = spool_file;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
NetworkManager*
RPL4PlaybackApplication::MakeNetworkManager()
{
Check_Fpu();
return new L4PlaybackNetworkManager;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPL4PlaybackApplication::Initialize()
{
Check(this);
L4Application::InitializeTillConsole();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPL4PlaybackApplication::LoadBackgroundTasks()
{
Check(this);
//
//--------------------------------------------------------------------------
// Add background tasks
//--------------------------------------------------------------------------
//
ApplicationTask *application_task;
application_task = new RPSpoolerTask;
Register_Object(application_task);
backgroundTasks->AddTask(application_task);
application_task = new ProcessEventTask;
Register_Object(application_task);
backgroundTasks->AddTask(application_task);
application_task = new GaugeRendererTask;
Register_Object(application_task);
backgroundTasks->AddTask(application_task);
application_task = new CompleteCyclesTask;
Register_Object(application_task);
backgroundTasks->AddTask(application_task);
application_task = new FryDeathRowTask;
Register_Object(application_task);
backgroundTasks->AddTask(application_task);
application_task = new AudioRendererTask;
Register_Object(application_task);
backgroundTasks->AddTask(application_task);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
RPL4PlaybackApplication::ExecuteForeground(
Time start_of_frame,
Scalar frame_duration
)
{
SET_FOREGROUND_PROCESSING();
Check(this);
Verify(application == this);
if (!executeFrames || GetApplicationState() == WaitingForEgg)
{
videoRenderer->ExecuteIdle();
CLEAR_FOREGROUND_PROCESSING();
return executeFrames && !Exit_Code;
}
Time
frame_ticks;
frame_ticks = frame_duration;
if (RPL4Application::GetMissionReviewMode() == 2)
{
//
//--------------------------------------------------------------------------
// Controls Manager
//
// Poll all devices, update all control variables.
//
// This is executed before the update manager so that the
// models have valid control values. It is not necessary for
// the controls to operate at the frame rate of this loop. If
// the controls manager can run run at a lower rate it can
// throttle itself internally.
//--------------------------------------------------------------------------
//
Check(controlsManager);
controlsManager->Execute();
}
//
//--------------------------------------------------------------------------
// Update Manager
//
// Execute replicants.
// Execute master entities if they are interesting here or
// elsewhere.
// Inform interest manager of possible interest zone change.
// If the master entity has provided and update message then
// send it to replicants.
//
// This is executed before the interest manager so that the
// interest manager can merge all interest zone changes before
// broadcasting interest arena deltas and building interesting
// entity lists.
//
// This is executed before the renderers so that the watchers
// have executed on the model and are ready for use by the
// renderers.
//--------------------------------------------------------------------------
//
SET_UPDATE_MANAGER();
Check(updateManager);
updateManager->Execute(start_of_frame);
CLEAR_UPDATE_MANAGER();
//
//--------------------------------------------------------------------------
// Interest Manager
//
// Update the net interest arena.
// Calculate which interest zones should be released and which
// interest zones should be loaded
// Send a becoming uninteresting and becoming interesting
// message to the entity.
// Broadcast the interest arena change
//
// The renderer manager call, update interest origins will
// update only those interest origins required by the renderers
// executing this frame.
//
// This is executed before the renderer manager so that when
// the renderers execute they execute upon interest lists that
// are valid as of the end of a model/update frame.
//
// In theory the interest manager does not have to run every
// frame. If throttled less, this would cause fuzz at interest
// zone borders, which may or may not be acceptable depending
// on the size of the interest arena.
//--------------------------------------------------------------------------
//
Check(rendererManager);
rendererManager->UpdateInterestOrigins(start_of_frame);
Check(interestManager);
interestManager->Execute();
//
//--------------------------------------------------------------------------
// Renderer Manager
//
// Execute renderers.
// Get interest list from interest manager.
// Poll watchers.
//
// It is not necessary for all renderers to operate at the frame
// rate of this loop. If a renderer can run at a lower rate it
// does so via the renderer manager which will govern if a
// renderer executes this frame.
//--------------------------------------------------------------------------
//
SET_RENDERER_MANAGER();
Check(rendererManager);
rendererManager->Execute(start_of_frame, frame_ticks, frame_ticks);
CLEAR_RENDERER_MANAGER();
//
//--------------------------------------------------------------------------
// Intercom Manager
//--------------------------------------------------------------------------
//
Check(intercomManager);
intercomManager->Execute();
//
//--------------------------------------------------------------------------
// Execution statistics
//--------------------------------------------------------------------------
//
if (GetApplicationState() == RunningMission)
{
secondsRemainingInGame =
currentMission->GetGameLength() - (Now() - gameStarted);
}
CLEAR_FOREGROUND_PROCESSING();
Check_Fpu();
return executeFrames && !Exit_Code;
}
//
//#############################################################################
// ExecuteBackgroundTask
//#############################################################################
//
void
RPL4PlaybackApplication::ExecuteBackgroundTask()
{
Check(this);
//
// If there exists a high priority event, execute it
//
if (ProcessOneEvent(HighEventPriority))
{
return;
}
//
// Execute lower priority tasks
//
Check(backgroundTasks);
backgroundTasks->Execute();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
RPL4PlaybackApplication::~RPL4PlaybackApplication()
{
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPL4PlaybackApplication::DispatchPacket(NetworkPacket *packet)
{
Check(this);
NetworkManager *net_mgr = GetNetworkManager();
Check(net_mgr);
NetworkClient *client = net_mgr->GetNetworkClientPointer(packet->clientID);
Check(client);
client->ReceiveNetworkPacket(packet, &packet->messageData);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RPL4PlaybackApplication::RunMissionMessageHandler(
RunMissionMessage *message
)
{
Check(this);
//
//------------------------------------------------------------------------
// If the application is waiting to launch, synchronize the clock stuff up
//------------------------------------------------------------------------
//
if (GetApplicationState() == WaitingForLaunch)
{
SpoolFile *spool = GetSpoolFile();
Check(spool);
NetworkPacket *packet = (NetworkPacket*)spool->GetPointer();
Verify(packet->messageData.messageID == RunMissionMessageID);
timeBias = Now().ticks - packet->timeStamp.ticks;
spool->NextPacket();
}
RPL4Application::RunMissionMessageHandler(message);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
char winners_spot[]="win?";
void
RPL4PlaybackApplication::StopMissionMessageHandler(
StopMissionMessage *message
)
{
//STUBBED: DPL RB 1/14/07
MissionReviewApplicationManager *app_mgr = GetApplicationManager();
Check(app_mgr);
SpoolFile *spool = GetSpoolFile();
if (spool)
{
Check(spool);
app_mgr->ReleaseSpoolFile(spool);
spoolFile = NULL;
//
//------------------------
// Find the dropzone group
//------------------------
//
EntityManager *entity_manager = application->GetEntityManager();
Check(entity_manager);
EntityGroup *dropzones = entity_manager->FindGroup("DropZones");
Check(dropzones);
char *place = winners_spot+3;
Player *p;
//
//----------------------------------------------------------------------
// Move all the players into their final positions in the winners circle
//----------------------------------------------------------------------
//
for (
int rank=0;
(p = CameraDirector::FindPlayerByRank(rank)) != NULL;
++rank
)
{
//
//-----------------------------------------------------------------
// Now find the dropzone appropriate to the rank. If one cannot be
// found, ignore this vehicle
//-----------------------------------------------------------------
//
Verify(rank<10);
*place = (char)('1' + rank);
ChainIteratorOf<Node*> iterator(dropzones->groupMembers);
DropZone *dropzone;
while ((dropzone = (DropZone*)iterator.ReadAndNext()) != NULL)
{
if (!strcmp(dropzone->GetDropZoneName(), winners_spot))
{
break;
}
}
if (!dropzone)
{
continue;
}
//
//---------------------------------------------------------------------
// Get the location of this dropzone, and reset the vehicle to place it
// where specified
//---------------------------------------------------------------------
//
VTV *vtv = (VTV*)p->GetPlayerVehicle();
if (vtv->GetClassID() == VTVClassID)
{
vtv->Reset(dropzone->localOrigin, VTV::MissionReviewReset);
vtv->SetPerformance(&VTV::DoNothing);
vtv->FlushEvents();
}
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Reload the NameBitmaps for the Winners Circle
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DPLRenderer *dpl_renderer = GetVideoRenderer();
Check(dpl_renderer);
dpl_renderer->SortAndReloadNameBitmaps();
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Set the Viewing Angle to 45 Degrees for Winners Circle
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
dpl_renderer->SetViewAngle(Degree(45.0f));
//
//~~~~~~~~~~~~~~~~~~~~~~~
// Set the Lighting Angle
//~~~~~~~~~~~~~~~~~~~~~~~
//
for(int ii=0;ii<dpl_renderer->sceneLightCount;++ii)
{
//dpl_RotateDCS(dpl_renderer->sceneLightDCS[ii], 0.0, dpl_Z);
//dpl_RotateDCS(dpl_renderer->sceneLightDCS[ii], 150.0, dpl_Y);
//dpl_RotateDCS(dpl_renderer->sceneLightDCS[ii], -30.0, dpl_X);
//dpl_FlushDCS (dpl_renderer->sceneLightDCS[ii]);
}
}
//
//---------------------------------------
// Let the application stop regularly now
//---------------------------------------
//
RPL4Application::StopMissionMessageHandler(message);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
RPL4PlaybackApplication::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}