Full input-surface audit of the PC keyboard channel. The arcade abort was the typed ampersand character (0x26), but the Win32 port feeds WM_KEYUP VIRTUAL-KEY codes into the same channel - and VK_UP is also 0x26. The hat look-up key aborted the mission: that was every mystery abort across the multiplayer test rounds. Likewise the E key (0x45, the right pedal!) dumped the event queue on every release. Disarmed: plain 0x26 and E are swallowed at the L4 layer; the abort answers only to the deliberate Alt+Q chord (translated to the legacy engine code, so APP.cpp is untouched); the debug toggles (wireframe Alt+W, predator vision Alt+V, frame dump Alt+F, perf stats, event queue on Alt+E now) arm only with RP412DEVKEYS=1. The cheat-string manager has no PC-keyboard strings and the trace-log keys are compiled out of release - both inert. Verified live: a volley of VK_UP releases mid-race leaves the mission running; Alt+Q aborts on demand. Docs and the dist README updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
981 lines
26 KiB
C++
981 lines
26 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"
|
|
//
|
|
// Minimal stand-in for ATL's <atlconv.h> USES_CONVERSION / W2A macros.
|
|
// VC++ Express and the Windows SDK do not ship ATL, and the only ATL feature
|
|
// this file used was wide-to-ANSI conversion of command-line tokens below.
|
|
// L4WideToAnsi mirrors ATL's W2A semantics: each use produces an independent
|
|
// buffer that stays valid until the end of the enclosing full-expression.
|
|
//
|
|
namespace
|
|
{
|
|
class L4WideToAnsi
|
|
{
|
|
public:
|
|
explicit L4WideToAnsi(const wchar_t* wide) : mBuffer(0)
|
|
{
|
|
int needed = (wide != 0)
|
|
? ::WideCharToMultiByte(CP_ACP, 0, wide, -1, 0, 0, 0, 0)
|
|
: 0;
|
|
if (needed <= 0)
|
|
{
|
|
needed = 1;
|
|
}
|
|
mBuffer = new char[needed];
|
|
if (wide == 0 ||
|
|
::WideCharToMultiByte(CP_ACP, 0, wide, -1, mBuffer, needed, 0, 0) <= 0)
|
|
{
|
|
mBuffer[0] = '\0';
|
|
}
|
|
}
|
|
~L4WideToAnsi() { delete [] mBuffer; }
|
|
operator char*() { return mBuffer; }
|
|
private:
|
|
char* mBuffer;
|
|
L4WideToAnsi(const L4WideToAnsi&); // non-copyable
|
|
L4WideToAnsi& operator=(const L4WideToAnsi&);
|
|
};
|
|
}
|
|
|
|
#define USES_CONVERSION ((void)0)
|
|
#define W2A(w) (static_cast<char*>(L4WideToAnsi(w)))
|
|
|
|
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);
|
|
|
|
//
|
|
// The debug keys are for developers: RP412DEVKEYS=1 arms them.
|
|
// Players get exactly one chord - Alt+Q, the deliberate abort.
|
|
//
|
|
static int dev_keys = -1;
|
|
if (dev_keys < 0)
|
|
{
|
|
const char *dev_value = getenv("RP412DEVKEYS");
|
|
dev_keys = (dev_value != NULL && atoi(dev_value) != 0) ? 1 : 0;
|
|
}
|
|
|
|
switch (message->dataContents)
|
|
{
|
|
//----------------------------------------------------------------
|
|
// Abort the mission, deliberately. The engine's legacy abort char
|
|
// is '&' (0x26) - but WM_KEYUP feeds VIRTUAL-KEY codes into this
|
|
// channel and VK_UP is also 0x26, so the plain code is swallowed
|
|
// below and the abort answers only to this chord.
|
|
//----------------------------------------------------------------
|
|
case PCK_ALT_Q:
|
|
message->dataContents = '&';
|
|
Application::KeyCommandMessageHandler(message);
|
|
break;
|
|
|
|
//----------------------------------------------------------------
|
|
// Swallowed collisions: 0x26 is VK_UP (the hat look-up key!) as
|
|
// well as a typed ampersand; 'E' (0x45 = the right-pedal key) was
|
|
// the event-queue dump. Neither may reach the engine handler.
|
|
//----------------------------------------------------------------
|
|
case '&':
|
|
case 'E':
|
|
break;
|
|
|
|
//------------------------------------
|
|
// Report current event queue (moved
|
|
// off the pedal key)
|
|
//------------------------------------
|
|
case PCK_ALT_E:
|
|
{
|
|
if (!dev_keys) break;
|
|
Check(application);
|
|
application->DumpEventQueue();
|
|
break;
|
|
}
|
|
|
|
//--------------------------------------------
|
|
// FrameDump from Division card to Targa file
|
|
//--------------------------------------------
|
|
case PCK_ALT_F:
|
|
{
|
|
if (!dev_keys) break;
|
|
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:
|
|
{
|
|
if (!dev_keys) break;
|
|
//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 performance statistics (Alt-?)
|
|
//---------------------------------------
|
|
case PCK_ALT_SLASH:
|
|
{
|
|
if (!dev_keys) break;
|
|
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:
|
|
{
|
|
if (!dev_keys) break;
|
|
DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
|
|
if (dpl_renderer)
|
|
{
|
|
Check(dpl_renderer);
|
|
dpl_renderer->DPLToggleWireframe();
|
|
}
|
|
break;
|
|
}
|
|
//--------------------------
|
|
// Toggle "Predator-vision"
|
|
//--------------------------
|
|
case PCK_ALT_V:
|
|
{
|
|
if (!dev_keys) break;
|
|
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
|