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

402 lines
10 KiB
C++

#include "rp.h"
#pragma hdrstop
#include "thruster.h"
#include "vtvmppr.h"
#include "..\munga\boxsolid.h"
#include "vtv.h"
//#############################################################################
// Shared Data Support
//
Thruster::SharedData
Thruster::DefaultData(
Thruster::GetClassDerivations(),
Thruster::GetMessageHandlers(),
Thruster::GetAttributeIndex(),
Thruster::StateCount
);
Derivation* Thruster::GetClassDerivations()
{
static Derivation classDerivations(Subsystem::GetClassDerivations(), "Thruster");
return &classDerivations;
}
//#############################################################################
// Attribute Support
//
const Thruster::IndexEntry
Thruster::AttributePointers[]=
{
ATTRIBUTE_ENTRY(Thruster, ThrusterOffset, thrusterOffset),
ATTRIBUTE_ENTRY(Thruster, ThrusterPosition, thrusterPosition),
ATTRIBUTE_ENTRY(Thruster, CurrentAcceleration, currentAcceleration),
ATTRIBUTE_ENTRY(Thruster, CurrentHeight, currentHeight),
ATTRIBUTE_ENTRY(Thruster, MaxThrusterRotationRate, maxThrusterRotationRate),
ATTRIBUTE_ENTRY(Thruster, MomentArm, momentArm),
ATTRIBUTE_ENTRY(Thruster, MomentArmLength, momentArmLength)
};
Thruster::AttributeIndexSet& Thruster::GetAttributeIndex()
{
static Thruster::AttributeIndexSet attributeIndex(ELEMENTS(Thruster::AttributePointers),
Thruster::AttributePointers,
Subsystem::GetAttributeIndex()
);
return attributeIndex;
}
//#############################################################################
// Model Support
//
void
Thruster::PrimeThruster(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);
if (vtv->GetSimulationState() == VTV::BurningState)
{
Check_Fpu();
return;
}
VTVControlsMapper* controls =
Cast_Object(
VTVControlsMapper*,
vtv->GetSubsystem(VTV::ControlsMapperSubsystem)
);
Check(controls);
Vector3D power_demand = controls->powerDemand;
//
//-------------------------------------------------------------------
// Rotate the engines so that they can match to power demand requests
//-------------------------------------------------------------------
//
Scalar desire,new_rad;
if (
controls->controlMode == VTVControlsMapper::BasicMode
&& Small_Enough(vtv->localVelocity.linearMotion.z, 1.0f)
)
{
desire = 0.0f;
}
else if (Small_Enough(power_demand.z) && Small_Enough(power_demand.y))
{
desire = 0.0f;
}
else
{
desire = Arctan(power_demand.z, power_demand.y);
}
Check(thrusterPosition);
if (thrusterPosition->GetRadians() < desire)
{
new_rad =
thrusterPosition->GetRadians()
+ time_slice * maxThrusterRotationRate;
Max_Clamp(new_rad, desire);
vtv->thrusterAngle = new_rad;
}
else if (thrusterPosition->GetRadians() > desire)
{
new_rad =
thrusterPosition->GetRadians()
- time_slice * maxThrusterRotationRate;
Min_Clamp(new_rad, desire);
vtv->thrusterAngle = new_rad;
}
thrusterPosition->SetRotation(vtv->thrusterAngle);
if (!Close_Enough(desire, updatedPosition, 10.0f*RAD_PER_DEG))
{
ForceUpdate();
updatedPosition = desire;
}
//
//-------------------------------------------------------------------
// Calculate the vertical thrust based upon the height of each engine
//-------------------------------------------------------------------
//
Verify(vtv->GetMoverCollisionRoot());
BoundingBoxTreeNode *tree = vtv->GetMoverCollisionRoot();
currentHeight = 0.0f;
Point3D test_point;
test_point.Multiply(thrusterOffset, vtv->localToWorld);
tree->FindBoundingBoxUnder(test_point, &currentHeight);
Vector3D force;
force.Multiply(power_demand, currentAcceleration);
if (power_demand.y > SMALL)
{
Vector3D ge = Vector3D::Identity;
ge.y =
vtv->groundEffectRange * power_demand.y * powerScale
/ (1.0f + vtv->groundEffectDomainSquared*currentHeight*currentHeight);
Check_Fpu();
Vector3D local_ge;
local_ge.MultiplyByInverse(ge, vtv->localToWorld);
force += local_ge;
}
#if defined(WOOBLY)
vtv->ApplyLocalAcceleration(force, momentArm);
#else
vtv->localAcceleration.linearMotion += force;
#endif
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Thruster::SlaveThruster(Scalar)
{
Check(this);
//
//--------------------------------------------------------------------------
// Get pointers to the other subsystems we will have to deal with inside the
// VTV
//--------------------------------------------------------------------------
//
VTV* vtv = GetEntity();
Check(vtv);
if (vtv->GetSimulationState() == VTV::BurningState)
{
Check_Fpu();
return;
}
VTVControlsMapper* controls =
Cast_Object(
VTVControlsMapper*,
vtv->GetSubsystem(VTV::ControlsMapperSubsystem)
);
Check(controls);
Vector3D power_demand = controls->powerDemand;
//
//-------------------------------------------------------------------
// Rotate the engines so that they can match to power demand requests
//-------------------------------------------------------------------
//
thrusterPosition->SetRotation(vtv->thrusterAngle);
//
//-------------------------------------------------------------------
// Calculate the vertical thrust based upon the height of each engine
//-------------------------------------------------------------------
//
Verify(vtv->GetMoverCollisionRoot());
BoundingBoxTreeNode *tree = vtv->GetMoverCollisionRoot();
currentHeight = 0.0f;
Point3D test_point;
test_point.Multiply(thrusterOffset, vtv->localToWorld);
tree->FindBoundingBoxUnder(test_point, &currentHeight);
Vector3D force;
force.Multiply(power_demand, currentAcceleration);
if (power_demand.y > SMALL)
{
Vector3D ge = Vector3D::Identity;
ge.y =
vtv->groundEffectRange * power_demand.y * powerScale
/ (1.0f + vtv->groundEffectDomainSquared*currentHeight*currentHeight);
Check_Fpu();
Vector3D local_ge;
local_ge.MultiplyByInverse(ge, vtv->localToWorld);
force += local_ge;
}
#if defined(WOOBLY)
vtv->ApplyLocalAcceleration(force, momentArm);
#else
vtv->localAcceleration.linearMotion += force;
#endif
Check_Fpu();
}
//#############################################################################
// Model Support
//
void
Thruster::PrimeDeadReckon(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);
if (vtv->GetSimulationState() == VTV::BurningState)
{
Check_Fpu();
return;
}
Check(thrusterPosition);
Scalar new_rad;
if (thrusterPosition->GetRadians() < updatedPosition)
{
new_rad =
thrusterPosition->GetRadians()
+ time_slice * maxThrusterRotationRate;
Max_Clamp(new_rad, updatedPosition);
vtv->thrusterAngle = new_rad;
}
else if (thrusterPosition->GetRadians() > updatedPosition)
{
new_rad =
thrusterPosition->GetRadians()
- time_slice * maxThrusterRotationRate;
Min_Clamp(new_rad, updatedPosition);
vtv->thrusterAngle = new_rad;
}
thrusterPosition->SetRotation(vtv->thrusterAngle);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Thruster::SlaveDeadReckon(Scalar)
{
Check(this);
//
//--------------------------------------------------------------------------
// Get pointers to the other subsystems we will have to deal with inside the
// VTV
//--------------------------------------------------------------------------
//
VTV* vtv = GetEntity();
Check(vtv);
if (vtv->GetSimulationState() == VTV::BurningState)
{
Check_Fpu();
return;
}
thrusterPosition->SetRotation(vtv->thrusterAngle);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Thruster::ReadUpdateRecord(Simulation::UpdateRecord *message)
{
Check(this);
Check_Pointer(message);
Subsystem::ReadUpdateRecord(message);
UpdateRecord* record = (UpdateRecord*) message;
updatedPosition = record->thrusterRotation;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Thruster::WriteUpdateRecord(Simulation::UpdateRecord *record, int update_model)
{
Check(this);
Check_Pointer(record);
Subsystem::WriteUpdateRecord(record, update_model);
UpdateRecord* update = (UpdateRecord*) record;
update->recordLength = sizeof(*update);
update->thrusterRotation = updatedPosition;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Thruster::Thruster(
VTV *owner,
int subsystem_ID,
SubsystemResource *subsystem_resource
):
Subsystem(owner, subsystem_ID, subsystem_resource, DefaultData)
{
if (owner->GetInstance() != VTV::ReplicantInstance)
{
if (subsystem_resource->primeThruster)
{
SetPerformance(&Thruster::PrimeThruster);
}
else
{
SetPerformance(&Thruster::SlaveThruster);
}
}
else if (subsystem_resource->primeThruster)
{
SetPerformance(&Thruster::PrimeDeadReckon);
}
else
{
SetPerformance(&Thruster::SlaveDeadReckon);
}
//
// Get the offset from the linear matrix by peeliong
// off the translation part
//
EntitySegment *segment = owner->GetSegment(segmentIndex);
momentArm = thrusterOffset = segment->GetBaseOffset();
thrusterOffset.y = owner->GetCollisionTemplate()->minY;
momentArm.y = 0.0f;
momentArmLength = momentArm.Length();
powerScale = 0.0f;
//
// Get the thruster position from the joint subsystem of the VTV
//
JointSubsystem *joint_subsystem = owner->GetJointSubsystem();
Check(joint_subsystem);
thrusterPosition = joint_subsystem->GetJoint(subsystem_resource->jointIndex);
currentAcceleration = 0.0f;
currentHeight = 0.0f;
maxThrusterRotationRate = subsystem_resource->maxThrusterRotationRate;
updatedPosition = 0.0f;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Thruster::~Thruster()
{
Check(this);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
Thruster::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}