#include "rp.h" #pragma hdrstop #include "demopack.h" #include "..\munga\line.h" #include "..\munga\explode.h" #include "..\munga\boxsolid.h" #include "..\munga\collasst.h" #include "..\munga\app.h" #include "..\munga\interest.h" #include "vtv.h" #include "..\munga\hostmgr.h" #include "..\munga\notation.h" //############################################################################# // Shared Data Support // Derivation* DemolitionPack::GetClassDerivations() { static Derivation classDerivations(Rivet::GetClassDerivations(), "DemolitionPack"); return &classDerivations; } DemolitionPack::SharedData DemolitionPack::DefaultData( DemolitionPack::GetClassDerivations(), DemolitionPack::GetMessageHandlers(), DemolitionPack::GetAttributeIndex(), DemolitionPack::StateCount, (Entity::MakeHandler)DemolitionPack::Make ); //############################################################################# // Attribute Support // #if 0 const DemolitionPack::IndexEntry DemolitionPack::AttributePointers[]= { ATTRIBUTE_ENTRY(DemolitionPack, DamageData, damageData) }; DemolitionPack::AttributeIndexSet& DemolitionPack::GetAttributeIndex() { static DemolitionPack::AttributeIndexSet attributeIndex(ELEMENTS(DemolitionPack::AttributePointers), DemolitionPack::AttributePointers, Mover::GetAttributeIndex()); return attributeIndex; } #endif //############################################################################# // Model support // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DemolitionPack::MoveAndHunt(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(); Point3D old_position(localOrigin.linearPosition); ApplyWorldAccelerations(time_slice); // //-------------------- // Do a collision test //-------------------- // MoveCollisionVolume(); BoxedSolidCollisionList* collision_list = GetCurrentCollisions(); // //--------------------------------------------------------------------- // If our solid didn't hit anything, and we are going fast enough, do a // ray-cast //--------------------------------------------------------------------- // if (!collision_list->GetCollisionCount()) { Line line; line = localOrigin.linearPosition; Vector3D step; step.Subtract(localOrigin.linearPosition, old_position); line = step; Scalar diameter = collisionTemplate->maxX - collisionTemplate->minX; if (diameter < line.length) { CollideCenterOfMotion(&line, collision_list); } } // //------------------------------- // Process each of the collisions //------------------------------- // Damage collision_damage; ProcessCollisionList( collision_list, time_slice, old_position, &collision_damage ); (this->*deadReckoner)(); Vector3D error; error.Subtract( projectedOrigin.linearPosition, localOrigin.linearPosition ); if (error.LengthSquared() > 0.5f) { ForceUpdate(); } // //---------------------- // Hunt for VTVs to kill //---------------------- // Check_Fpu(); Hunt(time_slice); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DemolitionPack::Hunt(Scalar) { if ((lastPerformance - creationTime) >= fuseTime) { // //--------------------------------- // Test against the tangible movers //--------------------------------- // Check(collisionAssistant); CollisionAssistant::MovingEntityIterator iterator(collisionAssistant); Entity *entity; Check(collisionVolume); while ((entity = iterator.ReadAndNext()) != NULL) { // //------------------------------------------ // If the mover is not within range, no boom //------------------------------------------ // Vector3D range; range.Subtract( entity->localOrigin.linearPosition, localOrigin.linearPosition ); if ((range.LengthSquared() >= detectionRadiusSquared) && ((lastPerformance - creationTime) <= (fuseTime + 60.0f))) { continue; } // //---------------------------------- // We got a boom! Make an explosion //---------------------------------- // CondemnToDeathRow(); 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, localOrigin, 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 whoever we hit //---------------------------------------------- // if ((lastPerformance - creationTime) <= (fuseTime + 60.0f)) { iterator.First(); while ((entity = iterator.ReadAndNext()) != NULL) { if (entity->GetClassID() == RegisteredClass::VTVClassID) { VTV *vtv = Cast_Object(VTV*, entity); Damage damage_data; damage_data.damageForce.Subtract( vtv->localOrigin.linearPosition, localOrigin.linearPosition ); if (damage_data.damageForce.LengthSquared() > blastRadiusSquared) { continue; } damage_data.damageForce.Normalize(damage_data.damageForce); damage_data.damageForce *= concussiveForce; damage_data.damageAmount = damageData.damageAmount; damage_data.damageType = Damage::ExplosiveDamageType; // //------------------------------------------ // Send a damage message to the thing we hit //------------------------------------------ // Entity::TakeDamageMessage take_damage( Entity::TakeDamageMessageID, sizeof(Entity::TakeDamageMessage), shootingEntity->GetEntityID(), 0, damage_data ); entity->Dispatch(&take_damage); } } break; } } } Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DemolitionPack::ProcessCollision( Scalar time_slice, BoxedSolidCollision &collision, const Point3D &old_position, Damage *damage ) { Scalar penetration,r; Scalar elasticity = elasticityCoefficient; Scalar friction = frictionCoefficient; // //------------------------------------------------------------------------- // If we have hit a mover, adjust our velocity relative to it, unless we // have collided with the VTV what dropped us, in which case we will ignore // the hit //------------------------------------------------------------------------- // BoxedSolid *box = collision.GetTreeVolume(); Check(box); Simulation *sim = box->GetOwningSimulation(); Mover *mover = NULL; if (sim && sim->IsDerivedFrom(*Mover::GetClassDerivations())) { mover = (Mover*)sim; Check(mover); if (mover == shootingEntity) { Check_Fpu(); return; } worldLinearVelocity -= mover->worldLinearVelocity; } // //-------------------------------------------------------------------- // If we really have a collision, do a static bounce off of the normal // generated //-------------------------------------------------------------------- // if ( collisionVolume->ProcessCollision( collision, worldLinearVelocity, lastCollisionList, &damage->surfaceNormal, &penetration ) ) { Max_Clamp(penetration, time_slice); r = penetration / time_slice; Check_Fpu(); StaticBounce( old_position, time_slice, r, damage->surfaceNormal, &elasticity, minimumBounceSpeed, &friction ); // //-------------------------- // Determine collision state //-------------------------- // if (!elasticity && !friction && !mover) { SetPerformance(&DemolitionPack::Hunt); worldLinearVelocity = Vector3D::Identity; worldLinearAcceleration = Vector3D::Identity; localVelocity = Motion::Identity; localAcceleration = Motion::Identity; ForceUpdate(); mover = NULL; } } if (mover) { worldLinearVelocity += mover->worldLinearVelocity; } Check_Fpu(); } //############################################################################# // Construction and Destruction // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DemolitionPack::DemolitionPack( DemolitionPack::MakeMessage *creation_message, DemolitionPack::SharedData &virtual_data ): Rivet(creation_message, virtual_data) { Check_Pointer(this); // //------------------------ // Setup the initial state //------------------------ // SetValidFlag(); InterestZone *interest_zone; Check(application); Check(application->GetInterestManager()); interest_zone = application->GetInterestManager()->GetInterestZone(interestZoneID); Check(interest_zone); localEnvironment = interest_zone->GetEnvironment(); Check(localEnvironment); // // SetDeadReckoner(&DemolitionPack::AcceleratedDeadReckoner); if (GetInstance() == ReplicantInstance) { SetPerformance(&DemolitionPack::DeadReckon); } else { SetPerformance(&DemolitionPack::MoveAndHunt); } // // Initialize the Projectile variables // ResourceDescription *res = application->GetResourceFile()->SearchList( resourceID, ResourceDescription::GameModelResourceType ); Check(res); res->Lock(); ModelResource* model = (ModelResource*)res->resourceAddress; Check_Pointer(model); blastRadiusSquared = model->blastRadiusSquared; detectionRadiusSquared = model->detectionRadiusSquared; fuseTime = model->fuseTime; concussiveForce = model->concussiveForce; damageData = model->damageData; explosionResourceID = model->explosionResourceID; res->Unlock(); HostManager *host_mgr = application->GetHostManager(); Check(host_mgr); shootingEntity = host_mgr->GetEntityPointer(creation_message->shootingEntity); Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DemolitionPack* DemolitionPack::Make(DemolitionPack::MakeMessage *creation_message) { return new DemolitionPack(creation_message); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DemolitionPack::~DemolitionPack() { Check(this); Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CreateModelResource // int DemolitionPack::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( Rivet::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", "BlastRadius", &local_model->blastRadiusSquared ) ) { std::cout << model_name << " missing BlastRadius!\n"; goto Dump_And_Die; } { local_model->blastRadiusSquared *= local_model->blastRadiusSquared; } if( !model_file->GetEntry( "gamedata", "DetectionRadius", &local_model->detectionRadiusSquared ) ) { std::cout << model_name << " missing DetectionRadius!\n"; goto Dump_And_Die; } else { local_model->detectionRadiusSquared *= local_model->detectionRadiusSquared; } if( !model_file->GetEntry( "gamedata", "ConcussiveForce", &local_model->concussiveForce ) ) { std::cout << model_name << " missing ConcussiveForce!\n"; goto Dump_And_Die; } if( !model_file->GetEntry( "gamedata", "FuseTime", &local_model->fuseTime ) ) { std::cout << model_name << " missing FuseTime!\n"; goto Dump_And_Die; } // //------------------------------------------------------------------------- // 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 DemolitionPack::TestInstance() const { return IsDerivedFrom(*GetClassDerivations()); }