Files
RP411/MUNGA_L4/L4APP.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

905 lines
23 KiB
C++

#include "mungal4.h"
#pragma hdrstop
#include "..\munga\camship.h"
#include "..\munga\appmsg.h"
#include "l4app.h"
#include "l4ctrl.h"
#include "l4icom.h"
#include "l4video.h"
#include "l4audrnd.h"
#include "l4grend.h"
#include "l4net.h"
#include "l4mppr.h"
#include "..\munga\player.h"
#include "..\munga\mission.h"
#include <atlbase.h>
#include <atlconv.h>
L4Application*&
l4_application = (L4Application*&)application;
const Receiver::HandlerEntry
L4Application::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(L4Application, RunMission),
MESSAGE_ENTRY(L4Application, StopMission),
MESSAGE_ENTRY(L4Application, LightsOut),
MESSAGE_ENTRY(L4Application, KeyCommand)
};
Receiver::MessageHandlerSet& L4Application::GetMessageHandlers()
{
static Receiver::MessageHandlerSet messageHandlers(ELEMENTS(L4Application::MessageHandlerEntries), L4Application::MessageHandlerEntries, Application::GetMessageHandlers());
return messageHandlers;
}
//#############################################################################
// Virtual Data support
//
Derivation* L4Application::GetClassDerivations()
{
static Derivation classDerivations(Application::GetClassDerivations(), "L4Application");
return &classDerivations;
}
L4Application::SharedData
L4Application::DefaultData(
L4Application::GetClassDerivations(),
L4Application::GetMessageHandlers()
);
//##########################################################################
//################## L4Application Static Data #######################
//##########################################################################
HINSTANCE L4Application::mhInstance = NULL;
unsigned int L4Application::mScreenWidth = 800;
unsigned int L4Application::mScreenHeight = 600;
bool L4Application::mFullscreen = true;
Logical L4Application::seeSolids = False;
CString L4Application::eggNotationFileName;
CString L4Application::spoolFileName;
unsigned long L4Application::networkCommonFlatAddress;
Logical L4Application::missionReviewMode = False;
CString L4Application::rioPlaybackFileName;
CString L4Application::rioRecordingFileName;
//
//#############################################################################
// ParseCommandLine
//#############################################################################
//
Logical
L4Application::ParseToken(
int *arguement,
int argc,
LPWSTR argv[]
)
{
USES_CONVERSION;
Check_Pointer(argv);
if (!stricmp(W2A(argv[*arguement]), "-egg"))
{
if ((*arguement+1) < argc && W2A(argv[*arguement+1])[0] != '-')
{
eggNotationFileName = W2A(argv[++(*arguement)]);
}
else
{
DEBUG_STREAM << "\nEgg file not specified after -egg\n" << std::flush << std::flush;
return False;
}
}
else if (!stricmp(W2A(argv[*arguement]), "-spool"))
{
if ((*arguement+1) < argc && W2A(argv[*arguement+1])[0] != '-')
{
spoolFileName = W2A(argv[++(*arguement)]);
}
else
{
DEBUG_STREAM << "\nSpool file not specified after -spool\n" << std::flush << std::flush;
return False;
}
}
else if (!stricmp(W2A(argv[*arguement]), "-net"))
{
if ((*arguement+1) < argc && W2A(argv[*arguement+1])[0] != '-')
{
networkCommonFlatAddress = atol(W2A(argv[++(*arguement)]));
}
else
{
DEBUG_STREAM << "\nAddress not specified after -net\n" << std::flush;
return False;
}
}
else if (!stricmp(W2A(argv[*arguement]), "-r"))
{
if ((*arguement+1) < argc && W2A(argv[*arguement+1])[0] != '-')
{
rioRecordingFileName = W2A(argv[++(*arguement)]);
CString playback = GetRIOPlaybackFileName();
if (playback && strlen(playback))
{
DEBUG_STREAM << "\nPlayback already specified!\n" << std::flush;
return False;
}
}
else
{
DEBUG_STREAM << "\nRecording file not specified after -r\n" << std::flush;
return False;
}
}
else if (!stricmp(W2A(argv[*arguement]), "-p"))
{
if ((*arguement+1) < argc && W2A(argv[*arguement+1])[0] != '-')
{
rioPlaybackFileName = W2A(argv[++(*arguement)]);
CString recording = GetRIORecordingFileName();
if (recording && strlen(recording))
{
DEBUG_STREAM << "\nRecording already specified!\n" << std::flush;
return False;
}
}
else
{
DEBUG_STREAM << "\nPlayback file not specified after -egg\n" << std::flush;
return False;
}
}
else if (!stricmp(W2A(argv[*arguement]), "-solids"))
{
seeSolids = True;
}
else if (!stricmp(W2A(argv[*arguement]), "-res"))
{
if ((*arguement+2) < argc && W2A(argv[*arguement+1])[0] != '-' && W2A(argv[*arguement+2])[0] != '-')
{
mScreenWidth = atoi(W2A(argv[++(*arguement)]));
mScreenHeight = atoi(W2A(argv[++(*arguement)]));
}
else
{
DEBUG_STREAM << "\nScreen width and height not specified after -res\n" << std::flush;
return False;
}
}
else if (!stricmp(W2A(argv[*arguement]), "-windowed"))
{
mFullscreen = false;
}
else if (
!stricmp(W2A(argv[*arguement]), "-h") || !stricmp(W2A(argv[*arguement]), "-help")
)
{
DEBUG_STREAM << "\n" << argv[0] <<
" -egg <filename> -net <memory_address> -solids -h -help\n";
return False;
}
return True;
}
//
//#############################################################################
// ParseCommandLine
//#############################################################################
//
Logical
L4Application::ParseCommandLine(
int argc,
LPWSTR argv[],
TokenParser parser
)
{
USES_CONVERSION;
Check_Pointer(argv);
//
// Process options
//
seeSolids = False;
eggNotationFileName = "";
networkCommonFlatAddress = NULL;
missionReviewMode = 0;
suppressGauges = FALSE;
if (argc > 1)
{
for (int i = 1; i < argc; ++i)
{
if (!stricmp(W2A(argv[i]), "-lc"))
{
suppressGauges = TRUE;
} else if (!stricmp(W2A(argv[i]), "-mr"))
{
suppressGauges = TRUE;
missionReviewMode = 1;
} else if (!(*parser)(&i, argc, argv))
{
return False;
}
}
}
return True;
}
//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
L4Application::TestInstance() const
{
if (!IsDerivedFrom(*GetClassDerivations()))
{
return False;
}
return True;
}
//
//#############################################################################
// L4Application
//#############################################################################
//
L4Application::L4Application(
HINSTANCE hInstance,
HWND hWnd,
ResourceFile *resource_file,
ApplicationID application_ID,
ClassID class_ID,
SharedData &shared_data
):
Application(resource_file, application_ID, class_ID, shared_data),
mIsDead(false)
{
mhInstance = hInstance; // this is a static member, the app instance should never change during execution
//ghWnd = hWnd;
divisionParameters = getenv("DPLARG");
}
//
//#############################################################################
// Initialize
//#############################################################################
//
void
L4Application::Initialize()
{
Check(this);
InitializeTillConsole();
//
// Create the console host and socket
//
L4NetworkManager *net_mgr = GetNetworkManager();
net_mgr->CreateConsoleHost();
}
//
//#############################################################################
// Initialize
//#############################################################################
//
void
L4Application::InitializeTillConsole()
{
Check(this);
Application::Initialize();
}
//
//#############################################################################
// MakeModeManager
//#############################################################################
//
ModeManager*
L4Application::MakeModeManager()
{
return new ModeManager((ModeMask)ModeManager::ModeAlwaysActive); // Normally called at top level!!
}
//
//#############################################################################
// MakeNetworkManager
//#############################################################################
//
NetworkManager*
L4Application::MakeNetworkManager()
{
return new L4NetworkManager;
}
//
//#############################################################################
// MakeControlsManager
//#############################################################################
//
ControlsManager*
L4Application::MakeControlsManager()
{
LBE4ControlsManager *manager = new LBE4ControlsManager();
Check(manager);
manager->keyboardGroup[LBE4ControlsManager::KeyboardPC].Add(ModeManager::ModeAlwaysActive, this, KeyCommandMessageID, this);
return manager;
}
//
//#############################################################################
// MakeIntercomManager
//#############################################################################
//
IcomManager*
L4Application::MakeIntercomManager()
{
L4IcomManager
*manager = new L4IcomManager();
Check(manager);
return manager;
}
//
//#############################################################################
// MakeVideoRenderer
//#############################################################################
//
VideoRenderer*
L4Application::MakeVideoRenderer()
{
if (divisionParameters)
{
return
new DPLRenderer(
ghWnd,
mScreenWidth,
mScreenHeight,
mFullscreen,
VisualInterestType,
DefaultInterestDepth
);
}
return NULL;
}
//
//#############################################################################
// MakeAudioRenderer
//#############################################################################
//
AudioRenderer*
L4Application::MakeAudioRenderer()
{
/* char *blaster1, *blaster2;
blaster1 = getenv(FRONT_CARD_ENV_VAR);
blaster2 = getenv(REAR_CARD_ENV_VAR);
if (blaster1 != NULL && blaster2 != NULL)
{
return new L4AudioRenderer(DefaultRendererRate, False);
}
return NULL;*/
return new L4AudioRenderer(DefaultRendererRate, False);
}
//
//#############################################################################
// MakeGaugeRenderer
//#############################################################################
//
GaugeRenderer*
L4Application::MakeGaugeRenderer(int *secondaryIndex, int *aux1Index, int *aux2Index)
{
char *mode_string = getenv("L4GAUGE");
if (mode_string != NULL)
{
return new L4GaugeRenderer(!mFullscreen, secondaryIndex, aux1Index, aux2Index);
}
return NULL;
}
//
//#############################################################################
// Terminate
//#############################################################################
//
void
L4Application::Terminate()
{
Check(this);
//
//--------------------------------------------------------------------------
// Turn off illumination
//--------------------------------------------------------------------------
//
PilotIllumination(False);
//
// Call inherited method
//
Application::Terminate();
}
//
//#############################################################################
// ~L4Application
//#############################################################################
//
L4Application::~L4Application()
{
}
//
//#############################################################################
// MakeAndLinkViewpointEntity
//#############################################################################
//
Entity*
L4Application::MakeAndLinkViewpointEntity(Entity::MakeMessage* message)
{
Check(this);
Check(message);
Application::MakeAndLinkViewpointEntity(message);
//
//--------------------------------------------------------------------------
// Turn on lights for pilot
// (turned off by RunMissionMessageHandler)
//--------------------------------------------------------------------------
//
PilotIllumination(True);
//
//--------------------------------------------------------------------------
// Return viewpoint entity
//--------------------------------------------------------------------------
//
return GetViewpointEntity();
}
//
//#############################################################################
// MakeViewpointEntity
//#############################################################################
//
Entity*
L4Application::MakeViewpointEntity(Entity::MakeMessage *message)
{
Entity *viewing_entity;
viewing_entity = NULL;
switch(message->classToCreate)
{
case CameraShipClassID:
viewing_entity = CameraShip::Make((CameraShip::MakeMessage*)message);
Check(viewing_entity);
CameraShip *viewing_camera = Cast_Object(CameraShip*, viewing_entity);
Check(viewing_camera);
//
// Create controls mapping object
//
CameraControlsMapper
*camera_mapper;
Verify(GetControlsManager() != NULL);
CameraControlsMapper::SubsystemResource control_subsystem_resource;
Str_Copy(
control_subsystem_resource.subsystemName,
"ControlsMapper",
sizeof(control_subsystem_resource.subsystemName)
);
control_subsystem_resource.classID = TrivialSubsystemClassID;
control_subsystem_resource.subsystemModelSize =
sizeof(control_subsystem_resource);
LBE4ControlsManager* controls = GetControlsManager();
Check(controls);
switch (controls->primaryControlType)
{
case LBE4ControlsManager::PrimaryThrustMaster:
Tell("L4Application::MakeViewpointEntity, using ThrustMaster\n");
camera_mapper =
new CameraThrustmasterMapper(
viewing_camera,
CameraShip::ControlsMapperSubsystem,
&control_subsystem_resource
);
Register_Object(camera_mapper);
viewing_camera->SetMappingSubsystem(camera_mapper);
break;
case LBE4ControlsManager::PrimaryRIO:
Tell("L4Application::MakeViewpointEntity, using RIO\n");
camera_mapper =
new CameraRIOMapper(
viewing_camera,
CameraShip::ControlsMapperSubsystem,
&control_subsystem_resource
);
Register_Object(camera_mapper);
viewing_camera->SetMappingSubsystem(camera_mapper);
break;
default:
Fail("L4Application::MakeViewpointEntity, *** NO MAPPER! ***\n");
break;
}
//
//-------------------------------------------
// Create gauges for this entity
//-------------------------------------------
//
if (GetGaugeRenderer() != NULL)
{
L4GaugeRenderer *gauge_renderer = GetGaugeRenderer();
Check(gauge_renderer);
gauge_renderer->ConfigureForModel(
"Init",
viewing_entity
);
}
break;
}
return viewing_entity;
}
//
//#############################################################################
// RunMissionMessageHandler
//#############################################################################
//
void
L4Application::RunMissionMessageHandler(RunMissionMessage *message)
{
Check(this);
Verify(message->messageID == RunMissionMessageID);
//
//--------------------------------------------------------------------------
// If the application is already running then ignore this message
//--------------------------------------------------------------------------
//
switch (GetApplicationState())
{
case RunningMission:
break;
//
//-------------------------------------
// Start the playback if it is required
//-------------------------------------
//
case LaunchingMission:
{
LBE4ControlsManager *controls = GetControlsManager();
Check(controls);
if (controls->IsRecording())
{
controls->StartRecording();
}
else if (controls->IsPlayingBack())
{
controls->StartPlayback();
}
}
break;
case WaitingForLaunch:
PilotIllumination(False);
break;
default:
Fail("Application::RunMissionMessageHandler - Not ready to run!\n");
break;
}
//
//--------------------------------------------------------------------------
// Call previous handler
//--------------------------------------------------------------------------
//
Application::RunMissionMessageHandler(message);
}
//
//#############################################################################
// StopMissionMessageHandler
//#############################################################################
//
void
L4Application::StopMissionMessageHandler(StopMissionMessage *message)
{
Check(this);
Verify(message->messageID == StopMissionMessageID);
//
//--------------------------------------------------------------------------
// Call inherited handler
//--------------------------------------------------------------------------
//
Application::StopMissionMessageHandler(message);
//
//--------------------------------------------------------------------------
// Turn on illumination
//--------------------------------------------------------------------------
//
PilotIllumination(True);
//
//--------------------------------------------------------------------------
// Post a delayed message to ourselves to turn off the illumination
//--------------------------------------------------------------------------
//
Receiver::Message
lights_out_message(LightsOutMessageID, sizeof(Receiver::Message));
Time
event_time;
event_time = Now();
event_time += 30.0f;
Post(
LowEventPriority, // priority
this, // target
&lights_out_message, // message
event_time // when
);
}
//
//#############################################################################
// KeyCommandMessageHandler
//#############################################################################
//
void
L4Application::KeyCommandMessageHandler(
ReceiverDataMessageOf<ControlsKey> *message
)
{
Check(this);
Check(message);
switch (message->dataContents)
{
//--------------------------------------------
// FrameDump from Division card to Targa file
//--------------------------------------------
case PCK_ALT_F:
{
DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
if (dpl_renderer)
{
Check(dpl_renderer);
dpl_renderer->DPLFrameDump(True); // True indicates antialiased
}
break;
}
//------------------------------------
// Report current free memory in card
//------------------------------------
case PCK_ALT_K:
{
//STUBBED: HEAP RB 1/20/07
/*DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
if (dpl_renderer)
{
Check(dpl_renderer);
dpl_renderer->DPLReportFreeMemory(DEBUG_STREAM) << std::flush;
}
DEBUG_STREAM << UserHeap::MainStorage.GetTotalHeapLeft() << '('
<< UserHeap::MainStorage.GetBiggestHeapLeft()
<< " contiguous) bytes of MUNGA core left\n"
<< UserHeap::MainStorage.GetHeapUsed() << " bytes of heap used\n";
#if defined(USE_MEMORY_ANALYSIS)
DEBUG_STREAM << UserHeap::MainStorage.GetLowestTotalHeapLeft()
<< " bytes minimum available so far\n"
<< UserHeap::MainStorage.GetMostHeapUsed()
<< " bytes maximum used so far\n";
#endif
MemoryBlockBase::UsageReport();*/
break;
}
//------------------------------------
// Report current event queue
//------------------------------------
case 'E':
{
Check(application);
application->DumpEventQueue();
break;
}
//---------------------------------------
// Report performance statistics (Alt-?)
//---------------------------------------
case PCK_ALT_SLASH:
{
DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
if (dpl_renderer)
{
Check(dpl_renderer);
dpl_renderer->DPLReportPerfStats(DEBUG_STREAM);
}
break;
}
//--------------------------
// Toggle Wireframe display
//--------------------------
case PCK_ALT_W:
{
DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
if (dpl_renderer)
{
Check(dpl_renderer);
dpl_renderer->DPLToggleWireframe();
}
break;
}
//--------------------------
// Toggle "Predator-vision"
//--------------------------
case PCK_ALT_V:
{
DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
if (dpl_renderer)
{
Check(dpl_renderer);
dpl_renderer->DPLTogglePVision();
}
break;
}
//--------------------------------------------------------------
// Toggle transparency dither pattern between random and static
//--------------------------------------------------------------
case PCK_ALT_R:
//-----------------------------
// Report position of eyepoint
//-----------------------------
case PCK_ALT_P:
DEBUG_STREAM << "Function net yet enabled.\n" << std::flush;
break;
//------------------------------
// Pass event on to Application
//------------------------------
default:
Application::KeyCommandMessageHandler(message);
break;
}
}
//
//#############################################################################
// LightsOutMessageHandler
//#############################################################################
//
#if DEBUG_LEVEL == 0
void
L4Application::LightsOutMessageHandler(Receiver::Message */*message*/)
{
#else
void
L4Application::LightsOutMessageHandler(Receiver::Message *message)
{
Check(this);
Verify(message->messageID == LightsOutMessageID);
#endif
//
//--------------------------------------------------------------------------
// Turn off illumination
//--------------------------------------------------------------------------
//
PilotIllumination(False);
}
//
//#############################################################################
// TeslaCoil
//#############################################################################
//
void
L4Application::TeslaCoil(Logical light_on)
{
Check(controlsManager);
if (light_on)
{
((LBE4ControlsManager *) controlsManager)->SetLamp(
LBE4ControlsManager::LampTesla1,
RIO::solid + RIO::state1Bright + RIO::state2Bright
);
((LBE4ControlsManager *) controlsManager)->SetLamp(
LBE4ControlsManager::LampTesla2,
RIO::solid + RIO::state1Bright + RIO::state2Bright
);
((LBE4ControlsManager *) controlsManager)->SetLamp(
LBE4ControlsManager::LampTesla3,
RIO::solid + RIO::state1Bright + RIO::state2Bright
);
}
else
{
((LBE4ControlsManager *) controlsManager)->SetLamp(LBE4ControlsManager::LampTesla1, RIO::solid + RIO::state1Off + RIO::state2Off);
((LBE4ControlsManager *) controlsManager)->SetLamp(LBE4ControlsManager::LampTesla2, RIO::solid + RIO::state1Off + RIO::state2Off);
((LBE4ControlsManager *) controlsManager)->SetLamp(LBE4ControlsManager::LampTesla3, RIO::solid + RIO::state1Off + RIO::state2Off);
}
}
//
//#############################################################################
// PilotIllumination
//#############################################################################
//
void
L4Application::PilotIllumination(Logical light_on)
{
Check(controlsManager);
TeslaCoil(light_on);
if (light_on)
{
//--------------------------------------------
// Turn on floor light
//--------------------------------------------
((LBE4ControlsManager *) controlsManager)->SetLamp(
LBE4ControlsManager::LampFloor,
RIO::solid + RIO::state1Bright + RIO::state2Bright
);
//--------------------------------------------
// Ramp all aux screens to white
//--------------------------------------------
L4GaugeRenderer *gauge_renderer = GetGaugeRenderer();
if (gauge_renderer != NULL)
{
Check(gauge_renderer);
gauge_renderer->FadeToWhite(1.5);
}
}
else
{
//--------------------------------------------
// Turn off floor light
//--------------------------------------------
((LBE4ControlsManager *) controlsManager)->SetLamp(
LBE4ControlsManager::LampFloor,
RIO::solid + RIO::state1Off + RIO::state2Off
);
//--------------------------------------------
// Ramp all aux screens to normal
//--------------------------------------------
L4GaugeRenderer *gauge_renderer = GetGaugeRenderer();
if (gauge_renderer != NULL)
{
Check(gauge_renderer);
gauge_renderer->FadeToNormal(1.5);
}
}
}
#ifdef TEST_CLASS
# include "l4app.tcp"
#endif