#include "munga.h" #pragma hdrstop #include "exptbl.h" #include "namelist.h" #include "registry.h" #include "app.h" #include "explode.h" #include "damage.h" #include "notation.h" #include "fileutil.h" #include "renderer.h" //############################################################################## //###################### Class ExplosionTableEntry ######################## //############################################################################## //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ExplosionTableEntry::CreateExplosion( const EntityID &entity_hit_ID, const EntityID &creating_entity_ID, const Point3D &explode_position ) { Check(this); Origin explode_origin(Origin::Identity); explode_origin = explode_position; // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Create the explosion MakeMessage //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Explosion::MakeMessage exp_message( Explosion::MakeMessageID, sizeof(Explosion::MakeMessage), RegisteredClass::ExplosionClassID, EntityID::Null, explosionResourceID, Explosion::DefaultFlags, explode_origin, entity_hit_ID, creating_entity_ID ); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Calculate actual time based on time_delay //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Time when = Now(); when += timeDelay; Check(application); Registry *registry; registry = application->GetRegistry(); Check_Pointer(registry); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Create a MakeEntityMessage //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Registry::MakeEntityMessage *registry_message; registry_message = Registry::MakeEntityMessage::Make(&exp_message); Register_Object(registry_message); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Post entity message to the registry //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // #if 0 // ECH 1/28/96 application->Post( DefaultEventPriority, registry, registry_message, when ); #else application->Post( CreationEventPriority, registry, registry_message, when ); #endif Unregister_Object(registry_message); delete registry_message; Check_Fpu(); } //############################################################################## // Construction/Destruction // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ExplosionTableEntry::ExplosionTableEntry(MemoryStream *exp_stream) { // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Read in the data from the stream //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // *exp_stream >> damageLevel >> explosionResourceID >> graphicState; *exp_stream >> timeDelay; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ExplosionTableEntry::~ExplosionTableEntry() { } //############################################################################## // Tool Support // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical ExplosionTableEntry::CreateStreamedExplosion( ResourceFile *resource_file, CString exp_file_name, NotationFile *exp_file, CString exp_page_name, MemoryStream *explosion_stream ) { Check(exp_file); // //~~~~~~~~~~~~~~~~~~~~ // Get the DamageLevel //~~~~~~~~~~~~~~~~~~~~ // Scalar damage_level; if (!exp_file->GetEntry( exp_page_name, "DamageLevel", &damage_level ) ) { damage_level = -1.0f; } *explosion_stream << damage_level; // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Get the Explosion Model File //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // const char *explosion_model_file; if (!exp_file->GetEntry( exp_page_name, "ExplosionModelFile", &explosion_model_file ) ) { DEBUG_STREAM <FindResourceDescription( explosion_model_file, ResourceDescription::ModelListResourceType ); if (!res) { std::cout << exp_file_name << " cannot find " << explosion_model_file << " in resource file!\n"; return False; } // //~~~~~~~~~~~~~~~~~~~~~~~~~ // Write out the resourceID //~~~~~~~~~~~~~~~~~~~~~~~~~ // *explosion_stream << res->resourceID; // //~~~~~~~~~~~~~~~~~~~~~~~~~~ // Read in the Graphic State //~~~~~~~~~~~~~~~~~~~~~~~~~~ // const char *graphic_state_char; Enumeration graphic_state; if (exp_file->GetEntry( exp_page_name, "GraphicState", &graphic_state_char ) ) { if (!strcmp(graphic_state_char, "Destroyed")) { graphic_state = DamageZone::DestroyedGraphicState; } else if (!strcmp(graphic_state_char, "Gone")) { graphic_state = DamageZone::GoneGraphicState; } } else { graphic_state = DamageZone::ExistsGraphicState; } *explosion_stream << graphic_state; // //~~~~~~~~~~~~~~~~~~~~ // Get the TimeDelay //~~~~~~~~~~~~~~~~~~~~ // Scalar time_delay; if (!exp_file->GetEntry( exp_page_name, "TimeDelay", &time_delay ) ) { time_delay = 0.0f; } *explosion_stream << time_delay; return True; } //############################################################################## //######################## Class ExplosionTable ########################### //############################################################################## //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical ExplosionTable::CrossedDamageLevelThreshold( Scalar old_value, Scalar new_value ) { ExplosionTableIterator iterator(this); ExplosionTableEntry *current_exp; while ((current_exp = iterator.ReadAndNext()) != NULL) { if ( (old_value < current_exp->GetDamageLevel()) && (new_value >= current_exp->GetDamageLevel()) ) { return True; } } return False; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ExplosionTableEntry* ExplosionTable::SelectDamageLevelEntry(Scalar damage_level) { ExplosionTableIterator iterator(this); ExplosionTableEntry *current_exp; // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Choose ExplosionTableEntry by damage Level //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // while ((current_exp = iterator.ReadAndNext()) != NULL) { if (damage_level < current_exp->GetDamageLevel()) { Check_Fpu(); return current_exp; } } Check_Fpu(); return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ExplosionTableEntry* ExplosionTable::SelectGraphicStateEntry(Enumeration graphic_state) { ExplosionTableIterator iterator(this); ExplosionTableEntry *current_entry; while((current_entry = iterator.ReadAndNext() ) != NULL) { // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Display Explosion if an Entry Exists //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // if (current_entry->GetGraphicState() == graphic_state) { Check_Fpu(); return current_entry; } } Check_Fpu(); return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ExplosionTable::CreateExplosion( ExplosionTableEntry *explosion_entry, const EntityID &entity_hit_ID, const EntityID &creating_entity_ID, Point3D explode_position ) { Check(this); Check(explosion_entry); explosion_entry->CreateExplosion( entity_hit_ID, creating_entity_ID, explode_position ); } //############################################################################## // Construction/Destruction // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ExplosionTable::ExplosionTable(MemoryStream *exp_stream): TableOf(NULL, True) { int entry_count; *exp_stream >> entry_count; // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Create all of the ExplosionTableEntries //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ExplosionTableEntry *exp_entry; for(int ii=0;iiMakePageList(); Register_Object(exp_namelist); if (!exp_namelist->EntryCount()) { DEBUG_STREAM << exp_file << " is empty or missing \n"<EntryCount(); *explosion_stream << entry_count; NameList::Entry *exp_entry = exp_namelist->GetFirstEntry(); while(exp_entry) { // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // While more pages Add ExplosionEntries to the stream //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ExplosionTableEntry::CreateStreamedExplosion( resource_file, exp_filename, exp_file, exp_entry->GetName(), explosion_stream ); exp_entry = exp_entry->GetNextEntry(); } Unregister_Object(exp_namelist); delete exp_namelist; return True; } //########################################################################## //###################### EntityEffectWatcher ######################### //########################################################################## //############################################################################## // Construction/Destruction // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // EntityEffectWatcher::EntityEffectWatcher( Entity *entity_watched ) { entityWatched = entity_watched; entityWatched->AddEffectWatcher(this); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Init array to hold previous damageLevel values //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Verify(entityWatched->damageZoneCount > 0); oldDamageLevel = new Scalar[entityWatched->damageZoneCount]; Register_Pointer(oldDamageLevel); for(int ii=0;iidamageZoneCount;++ii) { oldDamageLevel[ii] = 0.0f; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // EntityEffectWatcher::~EntityEffectWatcher() { Unregister_Pointer(oldDamageLevel); delete[] oldDamageLevel; } //############################################################################## // Execute // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void EntityEffectWatcher::Execute() { Check(this); Check(entityWatched); Check_Pointer(entityWatched->damageZones); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Check the flags to see if any damageZones // have been modified since the last Execute was called //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DamageZone *current_zone; ExplosionTable *exp_table; ExplosionTableEntry *exp_entry(NULL); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Traverse damageZones looking for Changes //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // for (int ii=0;iidamageZoneCount; ++ii) { current_zone = entityWatched->damageZones[ii]; Check(current_zone); ResourceDescription::ResourceID exp_res; exp_table = current_zone->GetExplosionTable(); Check(exp_table); // //~~~~~~~~~~~~~~~~~~~ // Check Damage Level //~~~~~~~~~~~~~~~~~~~ // if (current_zone->DamageLevelChanged()) { exp_entry = exp_table->SelectDamageLevelEntry(current_zone->damageLevel); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // If delta was large enough signal an update //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // if ( exp_table->CrossedDamageLevelThreshold( oldDamageLevel[ii], current_zone->damageLevel ) && (entityWatched->GetInstance() == Entity::MasterInstance) ) { entityWatched->ForceUpdate(Entity::DamageZoneUpdateModelFlag); } oldDamageLevel[ii] = current_zone->damageLevel; } // //~~~~~~~~~~~~~~~~~~~~ // Check Graphic State //~~~~~~~~~~~~~~~~~~~~ // if (current_zone->GraphicStateChanged()) { exp_entry = exp_table->SelectGraphicStateEntry( current_zone->GetGraphicState() ); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Always update for a graphic state change //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // if (entityWatched->GetInstance() == Entity::MasterInstance) { entityWatched->ForceUpdate(Entity::DamageZoneUpdateModelFlag); } } // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Notify RendererManager of Any Change //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // if (exp_entry) { Check(exp_entry); exp_res = exp_entry->GetExplosionResourceID(); Check(application); Check(application->GetRendererManager()); application->GetRendererManager()->StartEntityEffect( entityWatched, current_zone, exp_res ); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Reset the DamageZone::changedFlags if // I am a master and no update occurred OR // if I am a replicant //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // if ( ( (entityWatched->GetInstance() == Entity::MasterInstance) && !entityWatched->DamageZoneUpdateModelFlagSet() ) || ( (entityWatched->GetInstance() == Entity::ReplicantInstance) ) ) { current_zone->ResetChangedFlags(); } } exp_entry = NULL; } Check_Fpu(); } //############################################################################## // Test Support // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical EntityEffectWatcher::TestInstance() const { Check(entityWatched); return True; }