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>
1524 lines
35 KiB
C++
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;
|
|
}
|