#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()); }