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

504 lines
12 KiB
C++

#include "rp.h"
#pragma hdrstop
#include "rivet.h"
#include "..\munga\line.h"
#include "..\munga\explode.h"
#include "..\munga\boxsolid.h"
#include "..\munga\subsystm.h"
#include "..\munga\app.h"
#include "..\munga\hostmgr.h"
#include "..\munga\interest.h"
#include "..\munga\notation.h"
//#############################################################################
// Shared Data Support
//
Derivation* Rivet::GetClassDerivations()
{ static Derivation classDerivations(Mover::GetClassDerivations(), "Rivet");
return &classDerivations;
}
Rivet::SharedData
Rivet::DefaultData(
Rivet::GetClassDerivations(),
Rivet::GetMessageHandlers(),
Rivet::GetAttributeIndex(),
Rivet::StateCount,
(Entity::MakeHandler)Rivet::Make
);
//#############################################################################
// Attribute Support
//
const Rivet::IndexEntry
Rivet::AttributePointers[]=
{
ATTRIBUTE_ENTRY(Rivet, DamageData, damageData)
};
Rivet::AttributeIndexSet& Rivet::GetAttributeIndex()
{
static Rivet::AttributeIndexSet attributeIndex(ELEMENTS(Rivet::AttributePointers), Rivet::AttributePointers, Mover::GetAttributeIndex());
return attributeIndex;
}
//#############################################################################
// Model support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Rivet::MoveToTarget(Scalar time_slice)
{
Line
distance_traveled;
distance_traveled = localOrigin.linearPosition;
//
//-----------------------------------------------------------------
// Apply the standard air resistance and gravity, then project the
// Projectile motion through the time slice and look for collisions
//-----------------------------------------------------------------
//
ApplyAirResistanceAndGravity();
ApplyWorldAccelerations(time_slice);
Vector3D
motion_vector;
motion_vector.Subtract(
localOrigin.linearPosition,
distance_traveled.origin
);
distance_traveled = motion_vector;
Check(&distance_traveled);
localToWorld = localOrigin;
BoxedSolid
*target = FindBoxedSolidHitBy(&distance_traveled, shootingEntity);
//
//-------------------------------------------------------
// If the projectile hit something, sentence it to death!
//-------------------------------------------------------
//
if (target)
{
CondemnToDeathRow();
Origin
explode_origin = localOrigin;
distance_traveled.FindEnd(&explode_origin.linearPosition);
//
//-----------------------
// Find the entity we hit
//-----------------------
//
Simulation
*sim = target->GetOwningSimulation();
Check(sim);
Entity
*entity;
if (sim->IsDerivedFrom(*Subsystem::GetClassDerivations()))
{
Check((Subsystem*)sim);
entity = ((Subsystem*)sim)->GetEntity();
}
else if (sim->IsDerivedFrom(*Mover::GetClassDerivations()))
{
Mover
*mover = (Mover*)sim;
Check(mover);
Vector3D
impact_speed;
impact_speed.Subtract(worldLinearVelocity, mover->worldLinearVelocity);
Scalar
damage_scale = impact_speed.Length() / 350.0f; // HACK
damageData.damageAmount *= damage_scale*damage_scale;
entity = mover;
}
else
{
entity = (Entity*)sim;
}
Check(entity);
//
//------------------
// 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(),
shootingEntity->GetEntityID()
);
explosion_res->Unlock();
#if DEBUG_LEVEL > 0
Explosion
*exp =
#endif
Explosion::Make(&exp_message);
Register_Object(exp);
//
//------------------------------------------
// Send a damage message to the thing we hit
//------------------------------------------
//
Entity::TakeDamageMessage
take_damage(
Entity::TakeDamageMessageID,
sizeof(Entity::TakeDamageMessage),
shootingEntity->GetEntityID(),
0,
damageData
);
entity->Dispatch(&take_damage);
}
//
//---------------------------------------------
// Otherwise, see if we have to update anything
//---------------------------------------------
//
else
{
UpdateLocalMotion();
//
//------------------------------------------------------------------------
// Run the dead reckoner, and then see how far apart the two positions are
//------------------------------------------------------------------------
//
(this->*deadReckoner)();
Vector3D
error;
error.Subtract(
projectedOrigin.linearPosition,
localOrigin.linearPosition
);
if (error.LengthSquared() > 0.1f)
{
ForceUpdate();
}
}
//
//---------------------------------------------------
// If the bullet has outlived its lifetime, delete it
//---------------------------------------------------
//
if ((Now() - creationTime) > RIVET_MAXIMUM_LIFETIME)
{
CondemnToDeathRow();
}
Check_Fpu();
}
//#############################################################################
// Construction and Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Rivet::Rivet(
Rivet::MakeMessage *creation_message,
Rivet::SharedData &virtual_data
):
Mover(creation_message, virtual_data)
{
Check_Pointer(this);
//
//------------------------
// Setup the initial state
//------------------------
//
SetValidFlag();
Check(application);
Check(application->GetInterestManager());
InterestZone
*interest_zone = application->GetInterestManager()->
GetInterestZone(interestZoneID);
Check(interest_zone);
localEnvironment = interest_zone->GetEnvironment();
Check(localEnvironment);
//
//
SetDeadReckoner(&Rivet::AcceleratedDeadReckoner);
if (GetInstance() == ReplicantInstance)
{
SetPerformance(&Rivet::DeadReckon);
}
else
{
SetPerformance(&Rivet::MoveToTarget);
StartCollisionAssistant();
}
//
// Initialize the Projectile variables
//
ResourceDescription *res =
application->GetResourceFile()->SearchList(
resourceID,
ResourceDescription::GameModelResourceType
);
Check(res);
res->Lock();
ModelResource
*model = (ModelResource*)res->resourceAddress;
Check_Pointer(model);
damageData.damageType = model->damageData.damageType;
damageData.damageAmount = model->damageData.damageAmount;
damageData.damageForce = Vector3D::Identity;
damageData.surfaceNormal.x = 1.0f;
damageData.surfaceNormal.y = 0.0f;
damageData.surfaceNormal.z = 0.0f;
damageData.impactPoint = Point3D::Identity;
explosionResourceID = model->explosionResourceID;
res->Unlock();
HostManager
*host_mgr = application->GetHostManager();
Check(host_mgr);
shootingEntity =
host_mgr->GetEntityPointer(creation_message->shootingEntity);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Rivet*
Rivet::Make(Rivet::MakeMessage *creation_message)
{
return new Rivet(creation_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Rivet::~Rivet()
{
Check(this);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CreateModelResource
//
int
Rivet::CreateModelResource(
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories,
ModelResource* model
)
{
Check(resource_file);
Check_Pointer(model_name);
Check(model_file);
Check_Pointer(directories);
//
//-----------------------------------------------------------------------
// If we were not provided a buffer to write the model data into, we must
// create it ourselves. Then make sure that the mover stuff is read in
//-----------------------------------------------------------------------
//
ModelResource
*local_model = model;
if (!local_model)
{
local_model = new ModelResource;
Register_Pointer(local_model);
}
if(
Mover::CreateModelResource(
resource_file,
model_name,
model_file,
directories,
local_model
) == -1
)
{
Dump_And_Die:
if (!model)
{
Unregister_Pointer(local_model);
delete local_model;
}
Check_Fpu();
return -1;
}
//
//---------------------------------------
// Read in the damage amount for the ammo
//---------------------------------------
//
if(
!model_file->GetEntry(
"gamedata",
"DamageAmount",
&local_model->damageData.damageAmount
)
)
{
std::cout << model_name << " missing DamageAmount!\n";
goto Dump_And_Die;
}
//
//----------------------------------------------------------------------
// Read in the Model Filename of the Explosion renderable, then find its
// resource ID in the resource file
//----------------------------------------------------------------------
//
const char
*damage_type;
if(
!model_file->GetEntry(
"gamedata",
"DamageType",
&damage_type
)
)
{
std::cout << model_name << " missing DamageType!\n";
goto Dump_And_Die;
}
if (!stricmp(damage_type, "CollisionDamage"))
{
local_model->damageData.damageType = Damage::CollisionDamageType;
}
else if (!stricmp(damage_type, "BallisticDamage"))
{
local_model->damageData.damageType = Damage::BallisticDamageType;
}
else if (!stricmp(damage_type, "ExplosiveDamage"))
{
local_model->damageData.damageType = Damage::ExplosiveDamageType;
}
else if (!stricmp(damage_type, "LaserDamage"))
{
local_model->damageData.damageType = Damage::LaserDamageType;
}
else if (!stricmp(damage_type, "EnergyDamage"))
{
local_model->damageData.damageType = Damage::EnergyDamageType;
}
else
{
std::cout << model_name << " has an unknown DamageType of " << damage_type
<< std::endl;
goto Dump_And_Die;
}
//
//----------------------------
// Init damage fields
//----------------------------
//
local_model->damageData.damageForce = Vector3D::Identity;
local_model->damageData.surfaceNormal.x = 0.0f;
local_model->damageData.surfaceNormal.y = 1.0f;
local_model->damageData.surfaceNormal.z = 0.0f;
local_model->damageData.impactPoint = Vector3D::Identity;
//
//----------------------------------------------------------------------
// Read in the Model Filename of the Explosion renderable, then find its
// resource ID in the resource file
//----------------------------------------------------------------------
//
const char
*explosion;
if(
!model_file->GetEntry(
"gamedata",
"ExplosionModelFile",
&explosion
)
)
{
std::cout << model_name << " missing ExplosionModelFile!\n";
goto Dump_And_Die;
}
ResourceDescription
*res = resource_file->FindResourceDescription(
explosion,
ResourceDescription::ModelListResourceType
);
if (!res)
{
std::cout << model_name << " cannot find " << explosion
<< " in resource file!\n";
goto Dump_And_Die;
}
local_model->explosionResourceID = res->resourceID;
//
//-------------------------------------------------------------------------
// If we created the model buffer, then we have the responsibility to write
// it out to the resource file
//-------------------------------------------------------------------------
//
if (!model)
{
ResourceDescription
*new_res = resource_file->AddResource(
model_name,
ResourceDescription::GameModelResourceType,
1,
ResourceDescription::Preload,
local_model,
sizeof(*local_model)
);
Unregister_Pointer(local_model);
delete local_model;
Check(new_res);
Check_Fpu();
return new_res->resourceID;
}
else
{
Check_Fpu();
return 0;
}
}
Logical
Rivet::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}