Files
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

1524 lines
35 KiB
C++

#include "rp.h"
#pragma hdrstop
#include "weapsys.h"
#include "rivet.h"
#include "demopack.h"
#include "..\munga\line.h"
#include "..\munga\explode.h"
#include "..\munga\boxsolid.h"
#include "vtvmppr.h"
#include "vtv.h"
#include "..\munga\app.h"
//#############################################################################
// Shared Data Support
//
GenericGun::SharedData
GenericGun::DefaultData(
GenericGun::GetClassDerivations(),
GenericGun::MessageHandlers,
GenericGun::GetAttributeIndex(),
GenericGun::StateCount
);
Derivation* GenericGun::GetClassDerivations()
{
static Derivation classDerivations(VTVSubsystem::GetClassDerivations(), "GenericGun");
return &classDerivations;
}
//#############################################################################
// Messaging Support
//
const Receiver::HandlerEntry
GenericGun::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(GenericGun, ConfigureMappables),
MESSAGE_ENTRY(GenericGun, ChooseButton)
};
Receiver::MessageHandlerSet
GenericGun::MessageHandlers(
ELEMENTS(GenericGun::MessageHandlerEntries),
GenericGun::MessageHandlerEntries,
VTVSubsystem::GetMessageHandlers()
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GenericGun::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(
&triggerState, // direct target
this, // receiver
(Receiver::MessageID) 0, // activation message ID (none here)
ChooseButtonMessageID // configuration message ID
);
}
else
{
ExitConfiguration();
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GenericGun::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, &triggerState);
}
Check_Fpu();
}
//#############################################################################
// Attribute Support
//
const GenericGun::IndexEntry
GenericGun::AttributePointers[]=
{
ATTRIBUTE_ENTRY(GenericGun, TriggerState, triggerState),
ATTRIBUTE_ENTRY(GenericGun, PercentDone, percentDone)
};
GenericGun::AttributeIndexSet& GenericGun::GetAttributeIndex()
{
static GenericGun::AttributeIndexSet attributeIndex(ELEMENTS(GenericGun::AttributePointers),
GenericGun::AttributePointers,
VTVSubsystem::GetAttributeIndex()
);
return attributeIndex;
}
//#############################################################################
// Model Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void GenericGun::CalcAmmoOrigin(Origin *ammo_origin)
{
Check(this);
VTV *vtv = GetEntity();
Check(vtv);
//
//-------------------------------
// Check if we are looking behind
//-------------------------------
//
VTVControlsMapper *ctrl_sub =
(VTVControlsMapper *) vtv->GetSubsystem(VTV::ControlsMapperSubsystem);
LinearMatrix site_transform;
if(ctrl_sub->lookBehind > 0)
{
site_transform = siteRearTransform;
}
else
{
site_transform = siteFrontTransform;
}
LinearMatrix temp;
temp.Multiply(site_transform, vtv->localToWorld);
*ammo_origin = temp;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GenericGun::GenericGunSimulation(Scalar)
{
VTV *vtv = GetEntity();
Check(vtv);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// General Firing Simulation
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if ( (triggerState > 0) && (vtv->GetSimulationState() != VTV::BurningState) )
{
Fire();
SetSimulationState(Firing);
}
else
{
SetSimulationState(DefaultState);
}
Check_Fpu();
}
//#############################################################################
// Construction And Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GenericGun::GenericGun(
VTV *owner,
int subsystem_ID,
SubsystemResource *sub_res,
SharedData &shared_data
):
VTVSubsystem(
owner,
subsystem_ID,
sub_res,
shared_data,
&triggerState, // direct mapping for controls
(Receiver::MessageID) 0 // assumes no event mapping
)
{
Check(owner);
Check_Pointer(sub_res);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get the Resource Variables
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ammoVideoResourceID = sub_res->ammoVideoResourceID;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Initialize the Trigger to Released
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
triggerState = -1;
oldTriggerState = triggerState;
SetPerformance(&GenericGun::GenericGunSimulation);
SetSimulationState(DefaultState);
percentDone = 0.0f;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Assumption: No Joints in between a Gun and the
// root node of a vtv, so we can get the
// transformation matrix to get to the
// position of the site so we know where
// the bullet is to come out of
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EntitySegment *site_front_segment = owner->GetSegment(sub_res->segmentIndex);
Check(site_front_segment);
siteFrontTransform = site_front_segment->GetSegmentToEntity();
if(sub_res->rearSiteIndex == -1)
{
siteRearTransform = siteFrontTransform;
}
else
{
EntitySegment *site_rear_segment = owner->GetSegment(sub_res->rearSiteIndex);
Check(site_rear_segment);
siteRearTransform = site_rear_segment->GetSegmentToEntity();
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GenericGun::~GenericGun()
{
Check(this);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
GenericGun::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CreateStreamedSubsystem
//
int
GenericGun::CreateStreamedSubsystem(
NotationFile *model_file,
const char *model_name,
const char *subsystem_name,
SubsystemResource *subsystem_resource,
NotationFile *subsystem_file,
ResourceFile *resource_file,
const ResourceDirectories *directories
)
{
Check(model_file);
Check_Pointer(model_name);
Check_Pointer(subsystem_name);
Check_Pointer(subsystem_resource);
Check(subsystem_file);
Check(resource_file);
Check_Pointer(directories);
if (
!Subsystem::CreateStreamedSubsystem(
model_file,
model_name,
subsystem_name,
subsystem_resource,
subsystem_file,
directories
)
)
{
Check_Fpu();
return False;
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Save the model size and classID
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
subsystem_resource->subsystemModelSize = sizeof(*subsystem_resource);
subsystem_resource->classID = RegisteredClass::RivetGunClassID;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get the name of the ammo model file which holds
// all the info about the type of ammo this gun shoots
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char *ammo_model_file;
if(
!subsystem_file->GetEntry(
subsystem_name,
"AmmoModelFile",
&ammo_model_file
)
)
{
DEBUG_STREAM << subsystem_name << "missing AmmoModelFile!\n" << std::flush;
Check_Fpu();
return False;
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Find the description of the ammo in the current resource file
// Note: The ammo must be build before the gun which uses it
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription *rivet_desc =
resource_file->FindResourceDescription(
ammo_model_file,
ResourceDescription::ModelListResourceType
);
if(!rivet_desc)
{
DEBUG_STREAM <<
ammo_model_file << " must be std::declared before "<< model_name <<
" in the .bld file" << std::endl << std::flush;
Check_Fpu();
return False;
}
subsystem_resource->ammoVideoResourceID = rivet_desc->resourceID;
const char *rear_site_name;
if(
!subsystem_file->GetEntry(
subsystem_name,
"RearSiteName",
&rear_site_name
)
)
{
subsystem_resource->rearSiteIndex = -1;
}
else
{
subsystem_resource->rearSiteIndex = Get_Segment_Index(
model_file,
model_name,
directories,
rear_site_name);
}
Check_Fpu();
return True;
}
//############################################################################
//################ Class Rivet Gun ##################################
//############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data Support
//
RivetGun::SharedData
RivetGun::DefaultData(
RivetGun::GetClassDerivations(),
RivetGun::MessageHandlers,
RivetGun::GetAttributeIndex(),
RivetGun::StateCount
);
Derivation* RivetGun::GetClassDerivations()
{
static Derivation classDerivations(GenericGun::GetClassDerivations(), "RivetGun");
return &classDerivations;
}
//#############################################################################
// Attribute Support
//
const RivetGun::IndexEntry
RivetGun::AttributePointers[]=
{
ATTRIBUTE_ENTRY(RivetGun, TimeToLoaded, timeToLoaded),
ATTRIBUTE_ENTRY(RivetGun, AmmoCount, ammoCount)
};
RivetGun::AttributeIndexSet& RivetGun::GetAttributeIndex()
{
static RivetGun::AttributeIndexSet attributeIndex(ELEMENTS(RivetGun::AttributePointers),
RivetGun::AttributePointers,
GenericGun::GetAttributeIndex()
);
return attributeIndex;
}
//#############################################################################
// Construction And Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
RivetGun::RivetGun(
VTV *owner,
int subsystem_ID,
SubsystemResource *sub_res,
SharedData &shared_data
)
: GenericGun(owner, subsystem_ID, sub_res, shared_data)
{
Check(owner);
Check_Pointer(sub_res);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get Resource Info
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
maxAmmoCount = sub_res->ammoCount;
ammoCount = maxAmmoCount;
loadTime = sub_res->loadTime;
muzzleVelocity = sub_res->muzzleVelocity;
timeToLoaded = loadTime;
SetPerformance(&RivetGun::RivetGunSimulation);
SetSimulationState(Loading);
Check_Fpu();
}
RivetGun::~RivetGun()
{
Check(this);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
RivetGun::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void RivetGun::CalcAmmoMotion(Motion *ammo_motion)
{
Check(this);
VTV *vtv = GetEntity();
Check(vtv);
*ammo_motion = vtv->localVelocity;
ammo_motion->linearMotion.x += muzzleVelocity.x;
ammo_motion->linearMotion.y += muzzleVelocity.y;
ammo_motion->linearMotion.z -= muzzleVelocity.z;
ammo_motion->angularMotion = Vector3D::Identity;
Check_Fpu();
}
//#############################################################################
// Damage Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RivetGun::DeathReset(int reset_command)
{
//
//---------------------------------------------------
// Make sure we are not firing and reset variables
//---------------------------------------------------
//
Check(this);
if (reset_command == VTV::FootballReset)
{
ammoCount = maxAmmoCount;
timeToLoaded = 0.0f;
SetSimulationState(Loaded);
}
else
{
SetSimulationState(Loading);
}
Check_Fpu();
}
//#############################################################################
// Model Support
//
void
RivetGun::RivetGunSimulation(Scalar time_slice)
{
Check(this);
VTV *vtv = GetEntity();
Check(vtv);
percentDone = (loadTime - timeToLoaded)/ loadTime;
Check_Fpu();
if(percentDone > 1.0f)
{
percentDone = 1.0f;
}
if(percentDone < 0.0f)
{
percentDone = 0.0f;
}
Verify(percentDone >= 0.0f);
Verify(percentDone <= 1.0f);
switch(GetSimulationState())
{
case NoAmmo:
Gun_NoAmmo:
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If there is no ammo and we are trying to fire--Misfire
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if( (triggerState > 0) && (vtv->GetSimulationState() != VTV::BurningState) )
{
SetSimulationState(MisFire);
SetSimulationState(NoAmmo);
}
break;
case Loading:
Gun_Loading:
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// See if there is any Ammo Left
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if(ammoCount <= 0)
{
SetSimulationState(NoAmmo);
goto Gun_NoAmmo;
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Ensure we don't run over our time slice
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar time_left = time_slice - timeToLoaded;
timeToLoaded -= time_slice;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If we are done loading update the time slice
// and goto the firing state
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if(timeToLoaded <= 0.0f)
{
timeToLoaded = 0.0f;
time_slice = time_left;
SetSimulationState(Loaded);
goto Gun_Loaded;
}
break;
}
case Loaded:
Gun_Loaded:
if(
(triggerState > 0)
&&
(vtv->GetSimulationState() != VTV::BurningState)
)
{
goto Gun_Firing;
}
break;
case Firing:
Gun_Firing:
SetSimulationState(Firing);
Fire();
SetSimulationState(Loading);
goto Gun_Loading;
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
RivetGun::Fire()
{
Check(this);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// std::decrement ammoCount and reset the loadTime
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
--ammoCount;
timeToLoaded = loadTime;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get the entity and it's current position
// Add this to the siteTransform to determine
// where to shoot the rivet from
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Motion rivet_motion;
CalcAmmoMotion(&rivet_motion);
//
//-----------------------------
// Move the rivet to the site
//-----------------------------
//
Origin rivet_localOrigin;
CalcAmmoOrigin(&rivet_localOrigin);
VTV *vtv = GetEntity();
Check(vtv);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a New Rivet Whose properties are listed in the
// Resource File
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Rivet::MakeMessage
create_rivet(
Rivet::MakeMessageID,
sizeof(Rivet::MakeMessage),
(Entity::ClassID) Rivet::RivetClassID,
RivetGunClassID,
ammoVideoResourceID,
Rivet::DefaultFlags,
rivet_localOrigin,
rivet_motion,
Motion::Identity,
vtv->GetEntityID()
);
#if DEBUG_LEVEL>0
Rivet* my_rivet = Rivet::Make(&create_rivet);
Register_Object(my_rivet);
#else
Rivet::Make(&create_rivet);
#endif
Check_Fpu();
return 1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CreateStreamedSubsystem
//
int
RivetGun::CreateStreamedSubsystem(
NotationFile *model_file,
const char *model_name,
const char *subsystem_name,
SubsystemResource *subsystem_resource,
NotationFile *subsystem_file,
ResourceFile *resource_file,
const ResourceDirectories *directories
)
{
if (
!GenericGun::CreateStreamedSubsystem(
model_file,
model_name,
subsystem_name,
subsystem_resource,
subsystem_file,
resource_file,
directories
)
)
{
Check_Fpu();
return False;
}
subsystem_resource->subsystemModelSize = sizeof(*subsystem_resource);
subsystem_resource->classID = RegisteredClass::RivetGunClassID;
if(
!subsystem_file->GetEntry(
subsystem_name,
"LoadTime",
&subsystem_resource->loadTime
)
)
{
DEBUG_STREAM << subsystem_name << "missing LoadTime!\n" << std::flush;
return False;
}
if(
!subsystem_file->GetEntry(
subsystem_name,
"AmmoCount",
&subsystem_resource->ammoCount
)
)
{
DEBUG_STREAM << subsystem_name << "missing AmmoCount!\n" << std::flush;
Check_Fpu();
return False;
}
const char* muzzle_velocity;
if(
!subsystem_file->GetEntry(
subsystem_name,
"MuzzleVelocity",
&muzzle_velocity
)
)
{
DEBUG_STREAM << subsystem_name << "missing MuzzleVelocity!\n" << std::flush;
Check_Fpu();
return False;
}
else
{
Convert_From_Ascii(muzzle_velocity, &subsystem_resource->muzzleVelocity);
}
Check_Fpu();
return True;
}
//############################################################################
//################ Class Laser Gun ##################################
//############################################################################
//#############################################################################
// Shared Data Support
//
LaserGun::SharedData
LaserGun::DefaultData(
LaserGun::GetClassDerivations(),
LaserGun::MessageHandlers,
LaserGun::GetAttributeIndex(),
LaserGun::StateCount
);
Derivation* LaserGun::GetClassDerivations()
{ static Derivation classDerivations(GenericGun::GetClassDerivations(), "LaserGun");
return &classDerivations;
}
//#############################################################################
// Attribute Support
//
const LaserGun::IndexEntry
LaserGun::AttributePointers[]=
{
ATTRIBUTE_ENTRY(LaserGun, FrontLaserOn, frontLaserOn),
ATTRIBUTE_ENTRY(LaserGun, RearLaserOn, rearLaserOn),
ATTRIBUTE_ENTRY(LaserGun, LaserScale, laserScale)
};
LaserGun::AttributeIndexSet& LaserGun::GetAttributeIndex()
{
static LaserGun::AttributeIndexSet attributeIndex(ELEMENTS(LaserGun::AttributePointers),
LaserGun::AttributePointers,
GenericGun::GetAttributeIndex()
);
return attributeIndex;
}
//#############################################################################
// Model Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LaserGun::ReadUpdateRecord(Simulation::UpdateRecord *update_record)
{
Check(this);
Check_Pointer(update_record);
GenericGun::ReadUpdateRecord(update_record);
UpdateRecord *laser_update = (UpdateRecord*) update_record;
laserScale = laser_update->laserScale;
frontLaserOn = laser_update->frontLaserOn;
rearLaserOn = laser_update->rearLaserOn;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LaserGun::WriteUpdateRecord(
Simulation::UpdateRecord *update_record,
int update_model
)
{
Check(this);
Check_Pointer(update_record);
GenericGun::WriteUpdateRecord(update_record, update_model);
UpdateRecord *laser_update = (UpdateRecord*) update_record;
laser_update->recordLength = sizeof(*laser_update);
laser_update->laserScale = laserScale;
laser_update->frontLaserOn = frontLaserOn;
laser_update->rearLaserOn = rearLaserOn;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LaserGun::CalcPercentDone()
{
percentDone = chargeLevel / maxChargeLevel;
Verify(percentDone >= 0.0f);
Verify(percentDone <= 1.0f);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LaserGun::ChargingSimulation(Scalar time_slice)
{
Check(this);
VTV *vtv = GetEntity();
Check(vtv);
chargeLevel += chargePerSecond * time_slice;
if (chargeLevel >= maxChargeLevel)
{
chargeLevel = maxChargeLevel;
SetSimulationState(DefaultState);
}
if (triggerState > 0 && vtv->GetSimulationState() != VTV::BurningState)
{
Fire();
}
CalcPercentDone();
// Check_Fpu(); See CalcPercentDone, above.
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LaserGun::PulseFiringSimulation(Scalar time_slice)
{
Check(this);
VTV *vtv = GetEntity();
Check(vtv);
pulseDuration -= time_slice;
if (pulseDuration <= 0.0f)
{
if (triggerState > 0 && vtv->GetSimulationState() != VTV::BurningState)
{
Fire();
}
else
{
frontLaserOn = False;
rearLaserOn = False;
ForceUpdate();
SetSimulationState(Charging);
SetPerformance(&LaserGun::ChargingSimulation);
}
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LaserGun::FiringSimulation(Scalar time_slice)
{
//
//-----------------------------------------------------------------------
// If our time with the laser is done, look at the trigger state and jump
// to either the charging or pulsing state
//-----------------------------------------------------------------------
//
laserDuration -= time_slice;
if (laserDuration <= 0.0f)
{
SetSimulationState(PulseFiring);
SetPerformance(&LaserGun::PulseFiringSimulation);
pulseDuration = maxPulseDuration;
frontLaserOn = False;
rearLaserOn = False;
ForceUpdate();
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
LaserGun::Fire()
{
Check(this);
//
//---------------------------------------------
// Make sure we have enough power before firing
//---------------------------------------------
//
Scalar drain = drainPerSecond;
if (chargeLevel < drain)
{
SetSimulationState(Misfire);
return False;
}
chargeLevel -= drain;
SetPerformance(&LaserGun::FiringSimulation);
laserDuration = maxLaserDuration;
SetSimulationState(Firing);
ForceUpdate();
//
//------------------------------
// Calculate the max laser line
//-----------------------------
//
Origin laser_origin;
CalcAmmoOrigin(&laser_origin);
//
//-------------------------------
// Check if we are looking behind
//-------------------------------
//
Vector3D z_axis;
VTV *vtv = GetEntity();
Check(vtv);
VTVControlsMapper *ctrl_sub =
(VTVControlsMapper *) vtv->GetSubsystem(VTV::ControlsMapperSubsystem);
if (ctrl_sub->lookBehind > 0)
{
z_axis.x = 0.0; z_axis.y = 0.0f; z_axis.z = 1.0;
rearLaserOn = True;
}
else
{
z_axis.x = 0.0f; z_axis.y = 0.0f; z_axis.z = -1.0f;
frontLaserOn = True;
}
Vector3D line_direction;
line_direction.Multiply( z_axis , vtv->localToWorld);
UnitVector unit_direction;
unit_direction = line_direction;
Line
laser_line(laser_origin.linearPosition, unit_direction, maxLaserLength);
Check(&laser_line);
//
//------------------------------------
// See if the laser line hit anything
//------------------------------------
//
BoxedSolid* target = vtv->FindBoxedSolidHitBy(&laser_line, vtv);
laserScale.z = laser_line.length / 100.0f;
Check_Fpu();
if (target)
{
//
//-----------------------
// Find the entity we hit
//-----------------------
//
Simulation *sim = target->GetOwningSimulation();
Check(sim);
Entity *entity;
if (sim->IsDerivedFrom(*Subsystem::GetClassDerivations()))
{
Subsystem *subsys = (Subsystem*)sim;
Check(subsys);
entity = subsys->GetEntity();
}
else
{
entity = (Entity*)sim;
}
Check(entity);
//
//--------------------------------------------
// Make the explosion at the end of the laser
//--------------------------------------------
//
Origin
explode_origin = laser_origin;
laser_line.FindEnd(&explode_origin.linearPosition);
//
//------------------
// Make an Explosion
//------------------
//
Check(application);
ResourceFile
*resource_file = application->GetResourceFile();
Check(resource_file);
ResourceDescription
*explosion_res =
resource_file->FindResourceDescription(explosionResourceID);
Check(explosion_res);
explosion_res->Lock();
Explosion::MakeMessage
exp_message(
Explosion::MakeMessageID,
sizeof(Explosion::MakeMessage),
ExplosionClassID,
EntityID::Null,
explosion_res->resourceID,
Explosion::DefaultFlags,
explode_origin,
entity->GetEntityID(),
owningEntity->GetEntityID()
);
explosion_res->Unlock();
#if DEBUG_LEVEL>0
Explosion
*exp =
#endif
Explosion::Make(&exp_message);
Register_Object(exp);
//
//--------------------------------------------------------
// Initialize the Positional info in the damage structure
//--------------------------------------------------------
//
damageData.damageForce = Vector3D::Identity;
damageData.impactPoint = explode_origin.linearPosition;
//
//------------------------------------------
// Send a damage message to the thing we hit
//------------------------------------------
//
Entity::TakeDamageMessage
take_damage(
Entity::TakeDamageMessageID,
sizeof(Entity::TakeDamageMessage),
vtv->GetEntityID(),
0,
damageData
);
entity->Dispatch(&take_damage);
Check_Fpu();
return True;
}
else
{
Check_Fpu();
return False;
}
}
//#############################################################################
// Damage Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LaserGun::DeathReset(int reset_command)
{
Check(this);
if (reset_command == VTV::FootballReset)
{
chargeLevel = maxChargeLevel;
}
frontLaserOn = False;
rearLaserOn = False;
laserScale.x = 1.0f;
laserScale.y = 1.0f;
laserScale.z = 1.0f;
SetSimulationState(Charging);
SetPerformance(&LaserGun::ChargingSimulation);
ForceUpdate();
Check_Fpu();
}
//#############################################################################
// Construction And Destruction
//
LaserGun::LaserGun(
VTV *owner,
int subsystem_ID,
SubsystemResource *sub_res,
SharedData &shared_data
)
: GenericGun(owner, subsystem_ID, sub_res, shared_data)
{
Check(owner);
Check_Pointer(&sub_res);
//
//------------------------------------
// get values from subsystem resource
//------------------------------------
//
maxChargeLevel = 1.0f;
maxLaserLength = sub_res->laserLength;
fullChargeDuration = sub_res->fullChargeDuration;
chargePerSecond = sub_res->chargePerSecond;
explosionResourceID = sub_res->explosionResourceID;
maxLaserDuration = sub_res->laserDuration;
maxPulseDuration = sub_res->pulseDuration;
Scalar cycle_time = maxLaserDuration + maxPulseDuration;
damageData = sub_res->damageData;
damageData.damageAmount *= cycle_time;
drainPerSecond = sub_res->drainPerSecond * cycle_time;
//
//-----------------------
// Init local variables
//-----------------------
//
chargeLevel = 1.0f;
percentDone = 1.0f;
laserDuration = 0.0f;
hitSomething = False;
frontLaserOn = False;
rearLaserOn = False;
laserScale.x = 1.0f;
laserScale.y = 1.0f;
laserScale.z = 1.0f;
pulseDuration = 0.0f;
SetPerformance(&LaserGun::ChargingSimulation);
if (owner->GetInstance() == VTV::ReplicantInstance)
{
ExecuteOnUpdate();
}
SetSimulationState(Charging);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
LaserGun::~LaserGun()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
LaserGun::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CreateStreamedSubsystem
//
int
LaserGun::CreateStreamedSubsystem(
NotationFile *model_file,
const char *model_name,
const char *subsystem_name,
SubsystemResource *subsystem_resource,
NotationFile *subsystem_file,
ResourceFile *resource_file,
const ResourceDirectories *directories
)
{
if (
!GenericGun::CreateStreamedSubsystem(
model_file,
model_name,
subsystem_name,
subsystem_resource,
subsystem_file,
resource_file,
directories
)
)
{
Check_Fpu();
return False;
}
subsystem_resource->subsystemModelSize = sizeof(*subsystem_resource);
subsystem_resource->classID = RegisteredClass::LaserDrillClassID;
if(
!subsystem_file->GetEntry(
subsystem_name,
"ChargePerSecond",
&subsystem_resource->chargePerSecond
)
)
{
DEBUG_STREAM << subsystem_name << "missing ChargePerSecond!\n" << std::flush;
Check_Fpu();
return False;
}
if(
!subsystem_file->GetEntry(
subsystem_name,
"DrainPerSecond",
&subsystem_resource->drainPerSecond
)
)
{
DEBUG_STREAM << subsystem_name << "missing DrainPerSecond!\n" << std::flush;
Check_Fpu();
return False;
}
if(
!subsystem_file->GetEntry(
subsystem_name,
"DamageAmount",
&subsystem_resource->damageData.damageAmount
)
)
{
DEBUG_STREAM << subsystem_name << "missing DamageAmount!\n" << std::flush;
Check_Fpu();
return False;
}
else
{
//
//-------------------------
// Initialize damage fields
//-------------------------
//
subsystem_resource->damageData.damageType = Damage::LaserDamageType;
subsystem_resource->damageData.damageForce = Vector3D::Identity;
subsystem_resource->damageData.surfaceNormal.x = 0.0f;
subsystem_resource->damageData.surfaceNormal.y = 1.0f;
subsystem_resource->damageData.surfaceNormal.z = 0.0f;
subsystem_resource->damageData.impactPoint = Vector3D::Identity;
}
if(
!subsystem_file->GetEntry(
subsystem_name,
"FullChargeDuration",
&subsystem_resource->fullChargeDuration
)
)
{
DEBUG_STREAM << subsystem_name << "missing FullChargeDuration!\n" << std::flush;
Check_Fpu();
return False;
}
else
{
//
//-----------------
// Calc chargeLevel
//-----------------
//
subsystem_resource->chargeLevel =
subsystem_resource->fullChargeDuration /
subsystem_resource->drainPerSecond;
}
if(
!subsystem_file->GetEntry(
subsystem_name,
"PulseDuration",
&subsystem_resource->pulseDuration
)
)
{
DEBUG_STREAM << subsystem_name << "missing PulseDuration!\n" << std::flush;
Check_Fpu();
return False;
}
if(
!subsystem_file->GetEntry(
subsystem_name,
"LaserLength",
&subsystem_resource->laserLength
)
)
{
DEBUG_STREAM << subsystem_name << "missing LaserLength!\n" << std::flush;
Check_Fpu();
return False;
}
if(
!subsystem_file->GetEntry(
subsystem_name,
"LaserDuration",
&subsystem_resource->laserDuration
)
)
{
DEBUG_STREAM << subsystem_name << "missing LaserDuration!\n" << std::flush;
Check_Fpu();
return False;
}
//
//----------------------------------------------------------------------
// Read in the Model Filename of the Explosion renderable, then find its
// resource ID in the resource file
//----------------------------------------------------------------------
//
const char *explosion;
if(
!subsystem_file->GetEntry(
subsystem_name,
"ExplosionModelFile",
&explosion
)
)
{
std::cout << model_name << " missing ExplosionModelFile!\n" << std::flush;
Check_Fpu();
return False;
}
ResourceDescription *res =
resource_file->FindResourceDescription(
explosion,
ResourceDescription::ModelListResourceType
);
if (!res)
{
std::cout << model_name << " cannot find " << explosion
<< " in resource file!\n" << std::flush;
Check_Fpu();
return False;
}
subsystem_resource->explosionResourceID = res->resourceID;
return True;
}
//############################################################################
//################ Class DemolitionPackDropper ########################
//############################################################################
//#############################################################################
// Shared Data Support
//
DemolitionPackDropper::SharedData
DemolitionPackDropper::DefaultData(
DemolitionPackDropper::GetClassDerivations(),
DemolitionPackDropper::MessageHandlers,
DemolitionPackDropper::GetAttributeIndex(),
DemolitionPackDropper::StateCount
);
Derivation* DemolitionPackDropper::GetClassDerivations()
{ static Derivation classDerivations(RivetGun::GetClassDerivations(), "DemolitionPackDropper");
return &classDerivations;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
DemolitionPackDropper::DeathReset(int)
{
//
//---------------------------------------------------
// Make sure we are not firing and reset variables
//---------------------------------------------------
//
Check(this);
SetSimulationState(Loading);
Check_Fpu();
}
//#############################################################################
// Construction And Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DemolitionPackDropper::DemolitionPackDropper(
VTV *owner,
int subsystem_ID,
SubsystemResource *sub_res,
SharedData &shared_data
)
: RivetGun(owner, subsystem_ID, sub_res, shared_data)
{ }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DemolitionPackDropper::~DemolitionPackDropper()
{
Check(this);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
DemolitionPackDropper::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
DemolitionPackDropper::Fire()
{
Check(this);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// std::decrement ammoCount and reset the loadTime
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
--ammoCount;
timeToLoaded = loadTime;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get the entity and it's current position
// Add this to the siteTransform to determine
// where to shoot the rivet from
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Motion mine_motion;
CalcAmmoMotion(&mine_motion);
//
//-----------------------------
// Move the rivet to the site
//-----------------------------
//
Origin mine_localOrigin;
CalcAmmoOrigin(&mine_localOrigin);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a New Mine Whose properties are listed in the
// Resource File
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
VTV *vtv = GetEntity();
Check(vtv);
DemolitionPack::MakeMessage
create_mine(
DemolitionPack::MakeMessageID,
sizeof(Rivet::MakeMessage),
(Entity::ClassID) DemolitionPack::DemolitionPackClassID,
DemolitionPackDropperClassID,
ammoVideoResourceID,
DemolitionPack::DefaultFlags,
mine_localOrigin,
mine_motion,
Motion::Identity,
vtv->GetEntityID()
);
#if DEBUG_LEVEL>0
DemolitionPack* my_mine = DemolitionPack::Make(&create_mine);
Register_Object(my_mine);
#else
DemolitionPack::Make(&create_mine);
#endif
Check_Fpu();
return 1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CreateStreamedSubsystem
//
int
DemolitionPackDropper::CreateStreamedSubsystem(
NotationFile *model_file,
const char *model_name,
const char *subsystem_name,
SubsystemResource *subsystem_resource,
NotationFile *subsystem_file,
ResourceFile *resource_file,
const ResourceDirectories *directories
)
{
if (
!RivetGun::CreateStreamedSubsystem(
model_file,
model_name,
subsystem_name,
subsystem_resource,
subsystem_file,
resource_file,
directories
)
)
{
Check_Fpu();
return False;
}
subsystem_resource->subsystemModelSize = sizeof(*subsystem_resource);
subsystem_resource->classID = RegisteredClass::DemolitionPackDropperClassID;
Check_Fpu();
return True;
}