Files
RP412/RP/BOOSTER.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

488 lines
12 KiB
C++

#include "rp.h"
#pragma hdrstop
#include "booster.h"
#include "..\munga\controls.h"
#include "rpcnsl.h"
#include "vtv.h"
#include "vtvmppr.h"
#include "..\munga\app.h"
#include "..\munga\hostmgr.h"
//#############################################################################
// Shared Data Support
//
Booster::SharedData
Booster::DefaultData(
Booster::GetClassDerivations(),
Booster::MessageHandlers,
Booster::GetAttributeIndex(),
Booster::StateCount
);
Derivation* Booster::GetClassDerivations()
{
static Derivation classDerivations(VTVSubsystem::GetClassDerivations(), "Booster");
return &classDerivations;
}
//#############################################################################
// Messaging Support
//
const Receiver::HandlerEntry
Booster::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(Booster, Activate),
MESSAGE_ENTRY(Booster, ConfigureMappables),
MESSAGE_ENTRY(Booster, ChooseButton)
};
Receiver::MessageHandlerSet
Booster::MessageHandlers(
ELEMENTS(Booster::MessageHandlerEntries),
Booster::MessageHandlerEntries,
VTVSubsystem::GetMessageHandlers()
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Booster::ConfigureMappablesMessageHandler(
ReceiverDataMessageOf<ControlsButton> *message
)
{
Check(this);
Check(message);
//---------------------------------------------------------------------
// If the hardwired button was pressed, process presses of the mappable
// buttons, otherwise it was released, so erase any temporary mappings
//---------------------------------------------------------------------
if (message->dataContents > 0)
{
EnterConfiguration(
NULL, // direct target (none here)
this, // receiver
ActivateMessageID, // activation message ID
ChooseButtonMessageID // configuration message ID
);
}
else
{
ExitConfiguration();
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Booster::ChooseButtonMessageHandler(
ReceiverDataMessageOf<ControlsButton> *message
)
{
if (message->dataContents > 0)
{
//
//---------------------------------------------------------------------
// Find the control manager of the vehicle, and have it turn off an
// existing mapping of a given type if it is there, otherwise it should
// create a new one
//---------------------------------------------------------------------
//
VTV* vtv = GetEntity();
Check(vtv);
VTVControlsMapper* controls =
Cast_Object(
VTVControlsMapper*,
vtv->GetSubsystem(VTV::ControlsMapperSubsystem)
);
Check(controls);
controls->AddOrErase(message->dataContents, this, ActivateMessageID);
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Booster::ActivateMessageHandler(
ReceiverDataMessageOf<ControlsButton> *message
)
{
Check(this);
Check(message);
VTV* vtv = GetEntity();
Check(vtv);
Check(application);
if (
vtv->GetSimulationState() == VTV::BurningState
|| application->GetApplicationState() != Application::RunningMission
)
{
Check_Fpu();
return;
}
if (
GetSimulationState() != BoosterBurning
&& message->dataContents > 0
&& boostersRemaining > 0
)
{
SetSimulationState(BoosterBurning);
AlwaysExecute();
lastPerformance = Now();
burnTimeRemaining = burnTimeMax;
boostersRemaining -= 1;
ForceUpdate();
vtv->ForceUpdate();
//
//---------------------------------------------------------------
// Tell the console (if there is one) that we turned on a booster
//---------------------------------------------------------------
//
Check(application);
HostManager *host_manager = application->GetHostManager();
Check(host_manager);
Host *console_host = host_manager->GetConsoleHost();
if (console_host)
{
Check(console_host);
ConsolePlayerVTVBoosterMessage booster_message(vtv->ownerID, 1);
application->SendMessage(
console_host->GetHostID(),
NetworkClient::ConsoleClientID,
&booster_message
);
}
}
Check_Fpu();
}
//#############################################################################
// Attribute Support
//
const Booster::IndexEntry
Booster::AttributePointers[]=
{
ATTRIBUTE_ENTRY(Booster, BurnTimeRemaining, burnTimeRemaining),
ATTRIBUTE_ENTRY(Booster, BoostersRemaining, boostersRemaining),
ATTRIBUTE_ENTRY(Booster, ScaleFactor, scaleFactor),
ATTRIBUTE_ENTRY(Booster, SmokeDensity, smokeDensity),
ATTRIBUTE_ENTRY(Booster, PercentDone, percentDone)
};
Booster::AttributeIndexSet& Booster::GetAttributeIndex()
{
static Booster::AttributeIndexSet attributeIndex(ELEMENTS(Booster::AttributePointers), Booster::AttributePointers, VTVSubsystem::GetAttributeIndex());
return attributeIndex;
}
//#############################################################################
// Model Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Booster::BoosterSimulation(Scalar time_slice)
{
Check(this);
//
//--------------------------------------------------------------------------
// Get pointers to the other subsystems we will have to deal with inside the
// VTV
//--------------------------------------------------------------------------
//
VTV* vtv = GetEntity();
Check(vtv);
//
//-------------------------
// Apply the Booster
//-------------------------
//
percentDone = (burnTimeMax - burnTimeRemaining) / burnTimeMax;
if(percentDone > 1.0f)
{
percentDone = 1.0f;
}
if(percentDone < 0.0f)
{
percentDone = 0.0f;
}
switch (GetSimulationState())
{
case BoosterBurning:
if (burnTimeRemaining > 0.0)
{
scaleFactor = Vector3D(1.0f, 1.0f, 1.0f);
Scalar phase = burnTimeMax - burnTimeRemaining;
if (phase < 0.2f)
{
scaleFactor *= phase/0.2f;
}
else if (burnTimeRemaining < 0.2f)
{
scaleFactor *= burnTimeRemaining;
}
smokeDensity = 1.0f;
burnTimeRemaining -= time_slice;
vtv->localAcceleration.linearMotion.z += acceleration;
vtv->boosterOn = True;
vtv->boosterScale = scaleFactor;
vtv->boosterSmokeDensity = smokeDensity;
}
else
{
SetSimulationState(DefaultState);
ForceUpdate();
vtv->ForceUpdate();
scaleFactor = Vector3D::Identity;
smokeDensity = 0.0f;
NeverExecute();
//
//----------------------------------------------------------------
// Tell the console (if there is one) that we turned off a booster
//----------------------------------------------------------------
//
Check(application);
HostManager *host_manager = application->GetHostManager();
Check(host_manager);
Host *console_host = host_manager->GetConsoleHost();
if (console_host)
{
Check(console_host);
ConsolePlayerVTVBoosterMessage booster_message(vtv->ownerID, 0);
application->SendMessage(
console_host->GetHostID(),
NetworkClient::ConsoleClientID,
&booster_message
);
}
}
break;
}
Check_Fpu();
}
//#############################################################################
// Damage Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Booster::DeathReset(int reset_command)
{
Check(this);
//
//--------------------------------------------------------------------------
// Get pointers to the other subsystems we will have to deal with inside the
// VTV
//--------------------------------------------------------------------------
//
VTV* vtv = GetEntity();
Check(vtv);
if (GetSimulationState() == BoosterBurning)
{
//
//----------------------------------------------------------------
// Tell the console (if there is one) that we turned off a booster
//----------------------------------------------------------------
//
Check(application);
HostManager *host_manager = application->GetHostManager();
Check(host_manager);
Host *console_host = host_manager->GetConsoleHost();
if (console_host)
{
Check(console_host);
ConsolePlayerVTVBoosterMessage booster_message(vtv->ownerID, 0);
application->SendMessage(
console_host->GetHostID(),
NetworkClient::ConsoleClientID,
&booster_message
);
}
}
burnTimeRemaining = 0.0f;
scaleFactor = Vector3D::Identity;
SetSimulationState(DefaultState);
if (reset_command == VTV::FootballReset)
{
boostersRemaining = maxBoosters;
}
NeverExecute();
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Booster::DeathShutdown(int)
{
//
//---------------------------------------------------
// Don't shutdown anything until we are reincarnated
//---------------------------------------------------
//
Check_Fpu();
}
//#############################################################################
// Constructor and Destructor
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Booster::Booster(
VTV *entity,
int subsystem_ID,
SubsystemResource *subsystem_resource
):
VTVSubsystem(
entity,
subsystem_ID,
subsystem_resource,
DefaultData,
NULL, // not 'direct-mapped'
Booster::ActivateMessageID // message ID to trigger booster
)
{
//-------------------------------------------
// Set values
//-------------------------------------------
maxBoosters = subsystem_resource->boosterCount;
boostersRemaining = maxBoosters;
burnTimeMax = subsystem_resource->burnTime;
acceleration = -subsystem_resource->boosterAcceleration;
burnTimeRemaining = 0.0f; // In Seconds
scaleFactor = Vector3D::Identity;
smokeDensity = 0.0f;
percentDone = 1.0f;
NeverExecute();
if (entity->GetInstance() != VTV::ReplicantInstance)
{
SetPerformance(&Booster::BoosterSimulation);
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Booster::~Booster()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
Booster::CreateStreamedSubsystem(
NotationFile *model_file,
const char *model_name,
const char *subsystem_name,
SubsystemResource *subsystem_resource,
NotationFile *subsystem_file,
const ResourceDirectories *directories
)
{
Check_Pointer(subsystem_name);
Check_Pointer(subsystem_resource);
Check(subsystem_file);
if (
!Subsystem::CreateStreamedSubsystem(
model_file,
model_name,
subsystem_name,
subsystem_resource,
subsystem_file,
directories
)
)
{
return False;
}
subsystem_resource->subsystemModelSize = sizeof(*subsystem_resource);
subsystem_resource->classID = RegisteredClass::BoosterClassID;
//
// Figure out who our voltage source is
//
if (
!subsystem_file->GetEntry(
subsystem_name,
"BoosterCount",
&subsystem_resource->boosterCount
)
)
{
DEBUG_STREAM << subsystem_name << " missing BoosterCount!\n" << std::flush;
Check_Fpu();
return False;
}
if (
!subsystem_file->GetEntry(
subsystem_name,
"BurnTime",
&subsystem_resource->burnTime
)
)
{
DEBUG_STREAM << subsystem_name << " missing BurnTime!\n" << std::flush;
Check_Fpu();
return False;
}
if (
!subsystem_file->GetEntry(
subsystem_name,
"BoosterAcceleration",
&subsystem_resource->boosterAcceleration
)
)
{
DEBUG_STREAM << subsystem_name << " missing BoosterAcceleration!\n" << std::flush;
Check_Fpu();
return False;
}
if (subsystem_resource->boosterAcceleration < 0.0f)
{
DEBUG_STREAM << subsystem_name<<" must have a positive acceleration!\n" << std::flush;
Check_Fpu();
return False;
}
Check_Fpu();
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
Booster::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}