//===========================================================================// // File: Entity.cpp // //---------------------------------------------------------------------------// // Date Who Modification // // -------- --- ---------------------------------------------------------- // // 11/29/94 JMA Initial coding. // // 08/25/97 JMA Infrastructure changes // // 08/25/97 ECH Infrastructure changes // //---------------------------------------------------------------------------// // Copyright (C) 1994-97, Virtual World Entertainment, Inc. // // All Rights reserved worldwide // // This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL // //===========================================================================// #include "AdeptHeaders.hpp" #include "EntityManager.hpp" #include "EntityAttribute.hpp" #include "RendererManager.hpp" #include "VideoComponentWeb.hpp" #include "EntityClassData.hpp" #include "Map.hpp" #include "Application.hpp" #include #include #include "DamageObject.hpp" #include "GameModelAttribute.hpp" #include "NameTable.hpp" #include "CollisionVolume.hpp" #include "CollisionGrid.hpp" #include "Zone.hpp" #include "Tile.hpp" #include #include //#define HUNT_BUG "jmalbert" //#define TIME_BUG "your_loginname_here" extern int g_nMR; char g_LastEntity[255] = ""; //############################################################################# //############################# Entity ################################## //############################################################################# HGOSHEAP Entity::s_Heap = NULL, Entity::s_CollisionHeap = NULL; Entity::ClassData* Entity::DefaultData = NULL; const Receiver::MessageEntry Entity::MessageEntries[]= { MESSAGE_ENTRY(Entity, Destroy), MESSAGE_ENTRY(Entity, Update), MESSAGE_ENTRY(Entity, TakeDamage), MESSAGE_ENTRY(Entity, BecomeInteresting) }; int Entity::s_EntitiesSynced; DWORD Entity_Count; DECLARE_TIMER(static, Renderer_Loading); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::InitializeClass() { Verify(!s_Heap); s_Heap = gos_CreateMemoryHeap("Entities", 0, g_LibraryHeap); Check_Pointer(s_Heap); Verify(!s_CollisionHeap); s_CollisionHeap = gos_CreateMemoryHeap("Collision", 0, g_LibraryHeap); Check_Pointer(s_CollisionHeap); Check_Object(ExecutionStateEngine::DefaultData); Verify(!DefaultData); DefaultData = new ClassData( EntityClassID, "Adept::Entity", BaseClass::DefaultData, ELEMENTS(MessageEntries), MessageEntries, Entity::Make, Entity::CreateMessage::ConstructCreateMessage, ExecutionStateEngine::DefaultData, Entity::GameModel::ConstructGameModel, (Entity::GameModel::Factory)GameModel::ConstructOBBStream, Entity::GameModel::ReadAndVerify, Entity::GameModel::WriteToText, Entity::GameModel::SaveGameModel ); Check_Object(DefaultData); INDIRECT_STATE_ATTRIBUTE( Entity, ExecutionState, executionState, Entity__ExecutionStateEngine ); CUSTOM_DIRECT_ATTRIBUTE( Entity, IsDestroyed, isDestroyed, int, IntClassID ); CUSTOM_DIRECT_ATTRIBUTE( Entity, VisualRepresentation, visualRepresentation, int, IntClassID ); DIRECT_ATTRIBUTE( Entity, LightIntensity, lightIntensity, Scalar ); CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE( Entity__GameModel, Collider, collider, bool, BoolClassID ); CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE( Entity__GameModel, CanBeWalkedOn, canBeWalkedOn, bool, BoolClassID ); CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE( Entity__GameModel, CanBeShot, canBeShot, bool, BoolClassID ); CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE( Entity__GameModel, WaterSurface, waterSurface, bool, BoolClassID ); CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE( Entity__GameModel, OBBCollides, OBBCollides, bool, BoolClassID ); { AttributeEntry *attribute_entry = new LocalToWorldAttributeEntry( LocalToWorldAttributeID, "LocalToWorld" ); Check_Object(attribute_entry); Check_Object(DefaultData); DefaultData->attributeTable.AddAttributeEntry(attribute_entry); } #if !defined(NO_STATS) AddStatistic("Entities", "entities", gos_DWORD, &Entity_Count, 0); AddStatistic("Entities Sync'd", "entities", gos_DWORD, &s_EntitiesSynced, Stat_AutoReset); #endif Initialize_Timer(Renderer_Loading, "Renderer Loading"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::TerminateClass() { Check_Object(DefaultData); delete DefaultData; DefaultData = NULL; Check_Pointer(s_CollisionHeap); gos_DestroyMemoryHeap(s_CollisionHeap); s_CollisionHeap = NULL; Check_Pointer(s_Heap); gos_DestroyMemoryHeap(s_Heap); s_Heap = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity::ClassData* Entity::GetClassData() { return Cast_Pointer(ClassData*, classData); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity* Entity::Make( const CreateMessage *message, ReplicatorID *base_id ) { gos_PushCurrentHeap(s_Heap); Entity *new_entity = new Entity(DefaultData, message, base_id, NULL); Check_Object(new_entity); gos_PopCurrentHeap(); return new_entity; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Replicator::CreateMessage* Entity::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file) { Check_Object(this); Check_Object(stream); // //----------------------------------- // Make sure that the stuff is synced //----------------------------------- // #if 0 SyncMatrices(true); #endif // //--------------------------------------------------------------------- // Make sure there is enough room for the factory request on the stream //--------------------------------------------------------------------- // stream->AllocateBytes(sizeof(CreateMessage)); BaseClass::SaveMakeMessage(stream, res_file); CreateMessage *message = Cast_Pointer(CreateMessage*, stream->GetPointer()); message->messageLength = sizeof(*message); // //---------------------- // Save the data list ID //---------------------- // Verify(dataListResource.DoesResourceExist()); message->dataListID = dataListResource.GetResourceID(); // //------------------------------------- // Save the initial state of the entity //------------------------------------- // message->localToParent = initialLocalToParent; message->initialAge = static_cast(lastExecuted - lastParameterization); Check_Object(executionState); executionState->Save(&message->executionState); // //-------------------------------- // Save the Save the instance Name //-------------------------------- // if(NameTable::GetInstance()) { Check_Object(NameTable::GetInstance()); message->nameID = NameTable::GetInstance()->FindID(instanceName); } else { message->nameID = NameTable::NullObjectID; } // //---------------------- //Save out the Alignment //---------------------- // message->alignment = alignment; return message; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::Reuse( const CreateMessage *message, ReplicatorID *base_id ) { Check_Object(this); Check_Object(message); // //----------------------------------------- // Verify that an entity can be created now //----------------------------------------- // BaseClass::Reuse(message, base_id); #ifdef _ARMOR Application *app = Application::GetInstance(); Check_Object(app); Verify(!app->InPreCollisionPhase()); #endif #if defined(HUNT_BUG) SPEW((HUNT_BUG, "Reusing %s(+", GetClassString())); Spew(HUNT_BUG, GetReplicatorID()); if (owningConnection==Connection::Local) SPEW((HUNT_BUG, "*+")); switch (GetReplicatorMode()) { case MasterMode: SPEW((HUNT_BUG, ") as master")); break; case IndependentMode: SPEW((HUNT_BUG, ") as independent")); break; case HermitMode: SPEW((HUNT_BUG, ") as hermit")); break; case ReplicantMode: SPEW((HUNT_BUG, ") as replicant")); break; case ClientMasterMode: SPEW((HUNT_BUG, ") as ClientMasterMode")); break; case ServerMasterMode: SPEW((HUNT_BUG, ") as ServerMasterMode")); break; } #endif // //---------------------- // Set up the data list and //---------------------- // lastExecuted = gos_GetElapsedTime(); lastParameterization = lastExecuted - message->initialAge; SetInterestMask(DormantInterestLevel); updateFlags = 0; #if defined(TIME_BUG) SPEW((TIME_BUG, "Reusing %s(+", GetClassString())); Spew(TIME_BUG, GetReplicatorID()); SPEW((TIME_BUG, ") at time %f", lastExecuted.GetSeconds())); #endif lightIntensity = 0.0f; // //---------------------------------------------------------------------- // Set up the game model and set the flags that come from the game model //---------------------------------------------------------------------- // Verify(dataListResource.DoesResourceExist()); Verify(gameModelResource.DoesResourceExist()); const GameModel *model = GetGameModel(); Check_Object(model); replicatorFlags &= ~GameModelMask; replicatorFlags |= model->defaultFlags; if (IsACollider() && IsTileBound()) replicatorFlags &= ~ColliderFlag; // //-------------------------- // Create the locator object //-------------------------- // Check_Object(VideoRenderer::Instance); Resource element_stream(model->elementResourceID); Verify(element_stream.DoesResourceExist()); // //------------------------- // Read in the entity state //------------------------- // gos_PushCurrentHeap(ElementRenderer::g_Heap); Check_Object(entityElement); #ifdef _DEBUG {static void* s_p = (void*)0x08f40500; if (s_p == (void*)this) { int n = 0; n++; n--; }} #endif // _DEBUG entityElement->SetClientData(this); unsigned state; element_stream >> state; entityElement->SetElementState(state); element_stream >> entityElement->m_localOBB; Verify(!solidVolume); Verify(!hierarchicalVolume); // //------------------------------------------------------------------- // Read a state change from stream, but if it has no changes, kill it //------------------------------------------------------------------- // ElementRenderer::StateChange *states = new ElementRenderer::StateChange( &element_stream, ElementRenderer::CurrentERFVersion ); Check_Object(states); if (states->IsRealStateChange()) entityElement->AdoptStateChange(states); else { Check_Object(states); delete states; } gos_PopCurrentHeap(); // //------------------------------- // Set the position of the entity //------------------------------- // initialLocalToParent = message->localToParent; entityElement->SetLocalToParent(message->localToParent); NeedMatrixSync(); // //------------------------------ // Load up the execution engines //------------------------------ // Check_Object(executionState); executionState->Reuse(&message->executionState); // //------------------------------------------------ //Load the instance Name if it exists in the Table //------------------------------------------------ // objectID = message->nameID; dontHit = NULL; if (oldCollisions) { delete oldCollisions; oldCollisions = NULL; } Verify(!newCollisions); alignment = message->alignment; isDestroyed = 0; // if (visualRepresentation == PrestineBothState || visualRepresentation == DestroyedBothState ) // visualRepresentation=PrestineBothState; // else visualRepresentation=PrestineInternalState; ClearDestroyedFlag(); ClearTriedToMoveOffMapThisFrameFlag(); RendererComponentWeb *renderer_web = GetComponentWeb(RendererManager::VideoRendererType); if(renderer_web) { VideoComponentWeb *video_web = Cast_Object(VideoComponentWeb *, renderer_web); video_web->CleanDamage(); } ExecuteChildComponentWebs(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::Respawn(CreateMessage *message) { Check_Object(this); Check_Object(message); BaseClass::Respawn(message); // //----------------------------------------- // Verify that an entity can be created now //----------------------------------------- // #ifdef _ARMOR Application *app = Application::GetInstance(); Check_Object(app); Verify(!app->InPreCollisionPhase()); #endif #if defined(HUNT_BUG) SPEW((HUNT_BUG, "Reusing %s(+", GetClassString())); Spew(HUNT_BUG, GetReplicatorID()); if (owningConnection==Connection::Local) SPEW((HUNT_BUG, "*+")); switch (GetReplicatorMode()) { case MasterMode: SPEW((HUNT_BUG, ") as master")); break; case IndependentMode: SPEW((HUNT_BUG, ") as independent")); break; case HermitMode: SPEW((HUNT_BUG, ") as hermit")); break; case ReplicantMode: SPEW((HUNT_BUG, ") as replicant")); break; case ClientMasterMode: SPEW((HUNT_BUG, ") as ClientMasterMode")); break; case ServerMasterMode: SPEW((HUNT_BUG, ") as ServerMasterMode")); break; } #endif // //---------------------- // Set up the data list and //---------------------- // lastExecuted = gos_GetElapsedTime(); lastParameterization = lastExecuted - message->initialAge; updateFlags = 0; #if defined(TIME_BUG) SPEW((TIME_BUG, "Reusing %s(+", GetClassString())); Spew(TIME_BUG, GetReplicatorID()); SPEW((TIME_BUG, ") at time %f", lastExecuted.GetSeconds())); #endif lightIntensity = 0.0f; // //---------------------------------------------------------------------- // Set up the game model and set the flags that come from the game model //---------------------------------------------------------------------- // Verify(dataListResource.DoesResourceExist()); Verify(gameModelResource.DoesResourceExist()); replicatorFlags &= InterestLevelMask|GameModelMask; replicatorFlags |= message->replicatorFlags & ~(InterestLevelMask|GameModelMask); if (IsACollider() && IsTileBound()) replicatorFlags &= ~ColliderFlag; // here we go... // if we are the server than we own everything.. if (owningConnection != Connection::Hermit) { Verify(GetReplicatorMode() != HermitMode); SetReplicatorMode(MasterMode); if (Network::GetInstance()->AmIServer()) { // if we don't own it and it is a master it will be the ServerMasterMode ( the receiver of a ClientMaster ) if ((owningConnection != Connection::Local) && (owningConnection != Connection::Hermit)) { if (GetReplicatorMode() == MasterMode) SetReplicatorMode(ServerMasterMode); } } else { // we are a client so we don't own anything. if ((owningConnection == Connection::Local) && (GetReplicatorMode() == MasterMode)) { SetReplicatorMode(ClientMasterMode); } else if ((owningConnection != Connection::Local) && GetReplicatorMode() == MasterMode) { SetReplicatorMode(ReplicantMode); } } } if (damageBit != -1) { EntityManager::GetInstance()->SetNetworkDamageBit(false, damageBit); } // //------------------------------- // Set the position of the entity //------------------------------- // initialLocalToParent = message->localToParent; entityElement->SetLocalToParent(message->localToParent); NeedMatrixSync(); // //------------------------------ // Load up the execution engines //------------------------------ // if(executionState) executionState->Reuse(&message->executionState); // //------------------------------------------------ //Load the instance Name if it exists in the Table //------------------------------------------------ // alignment = message->alignment; isDestroyed = 0; visualRepresentation=PrestineState; ClearDestroyedFlag(); ClearTriedToMoveOffMapThisFrameFlag(); if (oldCollisions) { delete oldCollisions; oldCollisions = NULL; } Verify(!newCollisions); m_whoShotMeLast = ReplicatorID::Null; m_weaponShotMeLast = -1; RendererComponentWeb *renderer_web = GetComponentWeb(RendererManager::VideoRendererType); if(renderer_web) { VideoComponentWeb *video_web = Cast_Object(VideoComponentWeb *, renderer_web); video_web->CleanDamage(); } ExecuteChildComponentWebs(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SentenceToDeathRow() { Check_Object(this); Check_Object(EntityManager::GetInstance()); if (!EntityManager::GetInstance()->deathRow.IsPlugMember(this)) EntityManager::GetInstance()->deathRow.Add(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity * Entity::CreateEntity( MemoryStream *stream, ReplicatorID *base_id, bool use_armory ) { Check_Object(stream); Entity::CreateMessage *message = Cast_Pointer(Entity::CreateMessage*, stream->GetPointer()); Entity *entity; #if 0 if(use_armory) { Check_Object(EntityManager::GetInstance()); if ((entity = EntityManager::GetInstance()->RequestFromArmory(message->dataListID)) != NULL) { Check_Object(entity); entity->Reuse(message); entity->PostReuse(); return entity; } } #endif RegisteredClass::ClassID class_id = message->classID; Entity::ClassData *class_data = Cast_Pointer(Entity::ClassData*, RegisteredClass::FindClassData(class_id)); Check_Object(class_data); entity = Cast_Object( Entity*, (*class_data->replicatorFactory)(message, base_id) ); Check_Object(entity); #if 0 Check_Object(EntityManager::GetInstance()); EntityManager::GetInstance()->EntityCreation(entity); #endif #if defined(LAB_ONLY) class_data->creationCount++; #endif return entity; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity::Entity( ClassData *class_data, const CreateMessage *message, ReplicatorID *base_id, ElementRenderer::Element *element ): Replicator(class_data, message, base_id), parentEntity(NULL), childEntityChain(NULL), m_deathEntity(NULL) { Check_Pointer(this); Check_Object(message); minTileRow=maxTileRow=0xff; minTileColumn=maxTileColumn=0xff; collisionAllowed=true; executionState = NULL; // //----------------------------------------- // Verify that an entity can be created now //----------------------------------------- // #ifdef _ARMOR Application *app = Application::GetInstance(); Check_Object(app); Verify(!app->InPreCollisionPhase()); #endif ++Entity_Count; #if defined(HUNT_BUG) SPEW((HUNT_BUG, "Creating %s(+", GetClassString())); Spew(HUNT_BUG, GetReplicatorID()); if (owningConnection==Connection::Local) SPEW((HUNT_BUG, "*+")); switch (GetReplicatorMode()) { case MasterMode: SPEW((HUNT_BUG, ") as master")); break; case IndependentMode: SPEW((HUNT_BUG, ") as independent")); break; case HermitMode: SPEW((HUNT_BUG, ") as hermit")); break; case ReplicantMode: SPEW((HUNT_BUG, ") as replicant")); break; case ClientMasterMode: SPEW((HUNT_BUG, ") as ClientMasterMode")); break; case ServerMasterMode: SPEW((HUNT_BUG, ") as ServerMasterMode")); break; } #endif // //---------------------- // Set up the data list and //---------------------- // lastExecuted = gos_GetElapsedTime(); lastParameterization = lastExecuted - message->initialAge; updateFlags = 0; #if defined(TIME_BUG) SPEW((TIME_BUG, "Creating %s(+", GetClassString())); Spew(TIME_BUG, GetReplicatorID()); SPEW((TIME_BUG, ") at time %f", lastExecuted.GetSeconds())); #endif isPlayerVehicle = false; lightIntensity = 0.0f; // //---------------------------------------------------------------------- // Set up the game model and set the flags that come from the game model //---------------------------------------------------------------------- // dataListResource.FindID(message->dataListID); Verify(dataListResource.DoesResourceExist()); ResourceID *data_list = Cast_Pointer(ResourceID*, dataListResource.GetPointer()); gameModelResource.FindID(*data_list); Verify(gameModelResource.DoesResourceExist()); const GameModel *model = GetGameModel(); Check_Object(model); replicatorFlags &= ~GameModelMask; replicatorFlags |= model->defaultFlags; if (IsACollider() && IsTileBound()) replicatorFlags &= ~ColliderFlag; SetInterestMask(DormantInterestLevel); // //------------------------------------------------ //Load the instance Name if it exists in the Table //------------------------------------------------ // if(NameTable::GetInstance()) { Check_Object(NameTable::GetInstance()); instanceName = NameTable::GetInstance()->FindName(message->nameID); NameTable::GetInstance()->SetData(message->nameID, this); // entityElement->SetName(instanceName); #if defined(LAB_ONLY) if (!instanceName) g_LastEntity[0] = '\0'; else { strncpy(g_LastEntity, instanceName, sizeof(g_LastEntity)-1); g_LastEntity[sizeof(g_LastEntity)-1] = '\0'; } #endif } else { instanceName = NULL; // entityElement->SetName(dataListResource.GetName()); #if defined(LAB_ONLY) g_LastEntity[0] = '\0'; #endif } // //-------------------------- // Create the locator object //-------------------------- // Check_Object(VideoRenderer::Instance); Resource element_stream(model->elementResourceID); Verify(element_stream.DoesResourceExist()); gos_PushCurrentHeap(ElementRenderer::GroupElement::s_Heap); if (element) { Check_Object(element); entityElement = element; } else { entityElement = new ElementRenderer::GroupElement; Check_Object(entityElement); } Check_Object(entityElement); #ifdef _DEBUG {static void* s_p = (void*)0x08f40500; if (s_p == (void*)this) { int n = 0; n++; n--; }} #endif // _DEBUG entityElement->SetClientData(this); unsigned state; element_stream >> state; entityElement->SetElementState(state); element_stream >> entityElement->m_localOBB; solidVolume = NULL; hierarchicalVolume = NULL; // //------------------------------------------------------------------- // Read a state change from stream, but if it has no changes, kill it //------------------------------------------------------------------- // ElementRenderer::StateChange *states = new ElementRenderer::StateChange( &element_stream, ElementRenderer::CurrentERFVersion ); Check_Object(states); if (states->IsRealStateChange()) entityElement->AdoptStateChange(states); else { Check_Object(states); delete states; } gos_PopCurrentHeap(); // //------------------------------- // Set the position of the entity //------------------------------- // initialLocalToParent = message->localToParent; entityElement->SetLocalToParent(message->localToParent); NeedMatrixSync(); // //------------------------------ // Load up the execution engines //------------------------------ // ExecutionStateEngine::ClassData *execution_class = class_data->executionStateClass; Check_Pointer(execution_class); executionState = execution_class->Make(this, &message->executionState); Check_Object(executionState); objectID = message->nameID; dontHit = NULL; damageBit = -1; damageObject = NULL; alignment = message->alignment; isDestroyed = 0; visualRepresentation=PrestineState; m_doesNeedToUpdateWebs = false; if(IsDestroyed()) { isDestroyed = 1; SetDestroyedRepresentation(); } ClearTriedToMoveOffMapThisFrameFlag(); oldCollisions = NULL; newCollisions = NULL; m_whoShotMeLast = ReplicatorID::Null; m_weaponShotMeLast = -1; for (unsigned i=0; iShouldWebBeKilled()) { Check_Object(web); delete web; componentWebs[i] = NULL; } } } } { DESTRUCTOR("Entity::Element"); // //------------------- // Delete the element //------------------- // Check_Object(entityElement); delete entityElement; } if (executionState) { DESTRUCTOR("Entity::ExecutionState"); // //---------------------------- // Remove the execution states //---------------------------- // Check_Object(executionState); delete executionState; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::DestroyMessageHandler(const Message *message) { Check_Object(this); Check_Object(message); Verify(message->messageID == DestroyMessageID); // //----------------- // Destroy children //----------------- // STOP(("Not implemented")); #if 0 DeleteChildEntities(); #endif // //--------------------------- // Entered into deathrow once //--------------------------- // Check_Object(EntityManager::GetInstance()); if (!EntityManager::GetInstance()->deathRow.IsPlugMember(this)) { EntityManager::GetInstance()->deathRow.Add(this); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::UpdateMessageHandler(const UpdateMessage *message) { Check_Object(this); Check_Object(message); Verify(GetReplicatorMode() == ReplicantMode); SetNewLocalToParent(message->localToParent); SyncMatrices(true); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool Entity::FriendlyFire(const TakeDamageMessage *message) { return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::TakeDamageMessageHandler(const TakeDamageMessage *message) { Check_Object(this); Check_Object(message); Verify(message->messageID == TakeDamageMessageID); if(damageObject) { if (!FriendlyFire(message)) { Check_Pointer(damageObject); damageObject->TakeDamage((TakeDamageMessage *)message, this); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::BecomeInterestingMessageHandler(const BecomeInterestingMessage *message) { Check_Object(this); Check_Object(message); Verify(message->messageID == BecomeInterestingMessageID); Verify(message->m_render); // //-------------------------------------------------------------------------- // Find the zone the entity lives in. If the zone is no longer interesting, // ignore the message //-------------------------------------------------------------------------- // ElementRenderer::Element *element = GetElement(); Check_Object(element); element = element->GetParentElement(); Check_Object(element); if (element->GetClassID() == TileClassID) { element = element->GetParentElement(); Check_Object(element); element = element->GetParentElement(); Check_Object(element); } Zone *zone = Cast_Object(Zone*, element); // //------------------ // Is this the hole? //------------------ // Entity::InterestLevel zone_interest = zone->GetInterestLevel(), entity_interest = GetInterestLevel(); switch ((zone_interest<<2) | entity_interest) { case (Entity::DormantInterestLevel<<2)|Entity::DormantInterestLevel: STOP(("Dormant:Dormant is unhandled")); break; case (Entity::DormantInterestLevel<<2)|Entity::SimulationInterestLevel: STOP(("Dormant:Simulation is unhandled")); break; case (Entity::DormantInterestLevel<<2)|Entity::RenderingInterestLevel: STOP(("Dormant:Rendering is unhandled")); break; case (Entity::SimulationInterestLevel<<2)|Entity::DormantInterestLevel: STOP(("Simulation:Dormant is unhandled")); break; case (Entity::RenderingInterestLevel<<2)|Entity::DormantInterestLevel: Verify(zone->m_dormant.IsPlugMember(this)); Verify(!zone->m_simulated.IsPlugMember(this)); Verify(!zone->m_rendered.IsPlugMember(this)); zone->m_dormant.Remove(this); zone->m_rendered.Add(this); BecomeInteresting(true); break; case (Entity::SimulationInterestLevel<<2)|Entity::SimulationInterestLevel: case (Entity::SimulationInterestLevel<<2)|Entity::RenderingInterestLevel: Verify(!zone->m_dormant.IsPlugMember(this)); Verify(zone->m_simulated.IsPlugMember(this)); Verify(!zone->m_rendered.IsPlugMember(this)); break; case (Entity::RenderingInterestLevel<<2)|Entity::SimulationInterestLevel: Verify(!zone->m_dormant.IsPlugMember(this)); Verify(zone->m_simulated.IsPlugMember(this)); Verify(!zone->m_rendered.IsPlugMember(this)); zone->m_simulated.Remove(this); zone->m_rendered.Add(this); BecomeInteresting(true); break; case (Entity::RenderingInterestLevel<<2)|Entity::RenderingInterestLevel: Verify(!zone->m_dormant.IsPlugMember(this)); if (zone->m_simulated.IsPlugMember(this)) { Verify(!zone->m_rendered.IsPlugMember(this)); zone->m_simulated.Remove(this); zone->m_rendered.Add(this); } else { Verify(!zone->m_simulated.IsPlugMember(this)); Verify(zone->m_rendered.IsPlugMember(this)); } break; default: STOP(("Illegal interest level setting")); break; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::RequestUpdate(int update_flags) { Check_Object(this); Verify(update_flags != 0); Verify(GetReplicatorMode() == MasterMode); Verify(owningConnection == Connection::Local); #if defined(HUNT_BUG) SPEW((HUNT_BUG, "Requesting Update for %s(+", GetClassString())); Spew(HUNT_BUG, GetReplicatorID()); SPEW((HUNT_BUG, ")")); #endif if (!updateFlags) { updateFlags = update_flags; Check_Object(EntityManager::GetInstance()); EntityManager::GetInstance()->RequestUpdate(this); } else updateFlags |= update_flags; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity::UpdateMessage* Entity::ConstructUpdate(Stuff::MemoryStream *stream) { Check_Object(this); Check_Object(stream); Verify(updateFlags); Verify(GetReplicatorMode() == MasterMode); Verify(owningConnection == Connection::Local); #if defined(HUNT_BUG) SPEW((HUNT_BUG, "Constructing Update for %s(+", GetClassString())); Spew(HUNT_BUG, GetReplicatorID()); SPEW((HUNT_BUG, ")")); #endif // //------------------------------------------------------------ // Make sure there is enough room for the update on the stream //------------------------------------------------------------ // stream->AllocateBytes(sizeof(UpdateMessage)); UpdateMessage *message = new(stream->GetPointer()) UpdateMessage( replicatorID, GetLocalToWorld() ); return message; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SetInterestLevel(InterestLevel interest) { Check_Object(this); // //--------------------------------------------- // Tell the zone to update our interest setting //--------------------------------------------- // ElementRenderer::Element *element = GetElement(); Check_Object(element); Zone *zone = Cast_Object(Zone*, element->GetParentElement()); zone->SetInterestLevel(this, interest); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::BindToZone() { Check_Object(this); // //------------------------------------------ // If we are already zone bound, just return //------------------------------------------ // if (!IsTileBound()) return; // //--------------------------------------------------------------------- // We are tile bound now, so find the tile through our element's parent //--------------------------------------------------------------------- // ElementRenderer::Element *element = GetElement(); Check_Object(element); Tile *tile = Cast_Object(Tile*, element->GetParentElement()); ElementRenderer::Element *mid = tile->GetParentElement(); Check_Object(mid); Zone *zone = Cast_Object(Zone*, mid->GetParentElement()); // //---------------------------------------------------------------- // Unhook the collision, change the flag and hook it back up again //---------------------------------------------------------------- // zone->DetachChild(element); replicatorFlags &= ~TileBoundFlag; zone->AttachChild(element); element->Sync(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::BindToTile() { Check_Object(this); // //------------------------------------------ // If we are already tile bound, just return //------------------------------------------ // if (IsTileBound()) return; // //--------------------------------------------------------------------- // We are tile bound now, so find the tile through our element's parent //--------------------------------------------------------------------- // ElementRenderer::Element *element = GetElement(); Check_Object(element); Zone *zone = Cast_Object(Zone*, element->GetParentElement()); // //---------------------------------------------------------------- // Unhook the collision, change the flag and hook it back up again //---------------------------------------------------------------- // zone->DetachChild(element); replicatorFlags |= TileBoundFlag; zone->AttachChild(element); element->Sync(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SetCollisionMask(CollisionMask mask) { Check_Object(this); Verify(GetParentEntity() == Map::GetInstance()); // //---------------------------------- // Find the zone we are connected to //---------------------------------- // ElementRenderer::Element *element = GetElement(); Check_Object(element); element = element->GetParentElement(); Check_Object(element); if (element->GetClassID() == TileClassID) { element = element->GetParentElement(); Check_Object(element); element = element->GetParentElement(); Check_Object(element); } Zone *zone = Cast_Object(Zone*, element); // //----------------------------------------------------------------------- // Unhook from the current zone and reattach to it after setting our mask //----------------------------------------------------------------------- // zone->UnhookCollision(this); replicatorFlags &= ~AlwaysCollidesMask; replicatorFlags |= mask; zone->HookUpCollision(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SetDestroyedFlag(int damage_mode) { Check_Object(this); replicatorFlags |= DestroyedFlag; // MSL 5.05 Torso if((damage_mode == InternalDamageObject::DestructionDamageMode) || (damage_mode == InternalDamageObject::DetachableDamageMode) || (damage_mode == InternalDamageObject::ArmLeftDamageMode) || (damage_mode == InternalDamageObject::ArmRightDamageMode)) { if (solidVolume) { Check_Object(solidVolume); if (!solidVolume->IsDestroyed()) solidVolume->Destroy(); } if (hierarchicalVolume) { Check_Object(hierarchicalVolume); if (!hierarchicalVolume->IsDestroyed()) hierarchicalVolume->Destroy(); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SetTriedToMoveOffMapThisFrameFlag() { Check_Object(this); replicatorFlags |= TriedToMoveOffMapThisFrameFlag; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SetDestroyedRepresentation() { Check_Object(this); if(visualRepresentation == PrestineState) visualRepresentation = DestroyedState; else if(visualRepresentation == PrestineInternalState) visualRepresentation = DestroyedInternalState; else if(visualRepresentation == PrestineBothState) visualRepresentation = DestroyedBothState; else if(visualRepresentation == PrestineNoneState) visualRepresentation = DestroyedNoneState; m_doesNeedToUpdateWebs = true; //THIS CAN'T BE CALLED HERE EVER!!!!!!! //ExecuteChildComponentWebs(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SetInternalRepresentation() { Check_Object(this); if(visualRepresentation == PrestineState || visualRepresentation == PrestineBothState || visualRepresentation == PrestineNoneState) visualRepresentation = PrestineInternalState; else if(visualRepresentation == DestroyedState || visualRepresentation == DestroyedBothState || visualRepresentation == DestroyedNoneState) visualRepresentation = DestroyedInternalState; ChainIteratorOf iterator(&childEntityChain); Entity *entity; while((entity = iterator.ReadAndNext()) != NULL) { Check_Object(entity); entity->SetInternalRepresentation(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SetBothRepresentation() { Check_Object(this); if(visualRepresentation == PrestineState || visualRepresentation == PrestineInternalState || visualRepresentation == PrestineNoneState) visualRepresentation = PrestineBothState; else if(visualRepresentation == DestroyedState || visualRepresentation == DestroyedInternalState || visualRepresentation == DestroyedNoneState) visualRepresentation = DestroyedBothState; ChainIteratorOf iterator(&childEntityChain); Entity *entity; while((entity = iterator.ReadAndNext()) != NULL) { Check_Object(entity); entity->SetBothRepresentation(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SetNoneRepresentation() { Check_Object(this); if(visualRepresentation == PrestineState || visualRepresentation == PrestineInternalState || visualRepresentation == PrestineBothState) visualRepresentation = PrestineNoneState; else if(visualRepresentation == DestroyedState || visualRepresentation == DestroyedInternalState || visualRepresentation == DestroyedBothState) visualRepresentation = DestroyedNoneState; ChainIteratorOf iterator(&childEntityChain); Entity *entity; while((entity = iterator.ReadAndNext()) != NULL) { Check_Object(entity); entity->SetNoneRepresentation(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SetExternalRepresentation() { Check_Object(this); if(visualRepresentation == PrestineInternalState || visualRepresentation == PrestineBothState || visualRepresentation == PrestineNoneState) visualRepresentation = PrestineState; else if(visualRepresentation == DestroyedInternalState || visualRepresentation == DestroyedBothState || visualRepresentation == DestroyedNoneState) visualRepresentation = DestroyedState; ChainIteratorOf iterator(&childEntityChain); Entity *entity; while((entity = iterator.ReadAndNext()) != NULL) { Check_Object(entity); entity->SetExternalRepresentation(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::ClearDestroyedFlag() { Check_Object(this); replicatorFlags &= ~DestroyedFlag; if (solidVolume) { Check_Object(solidVolume); solidVolume->Restore(); } if (hierarchicalVolume) { Check_Object(hierarchicalVolume); hierarchicalVolume->Restore(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::ClearTriedToMoveOffMapThisFrameFlag() { Check_Object(this); replicatorFlags &= ~TriedToMoveOffMapThisFrameFlag; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SetDamageObject(DamageObject *damage_object) { Check_Object(this); Check_Object(damage_object); ChainIteratorOf iterator(&childEntityChain); Entity *entity; // //-------------------------------------------------------------------- //Need to set the damage object and the damage object for its children //-------------------------------------------------------------------- // while((entity = iterator.ReadAndNext()) != NULL) { Check_Object(entity); if(entity->damageObject == NULL) { entity->SetDamageObject(damage_object); } } damageObject = damage_object; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::DestroyChildren(int damage_mode) { Check_Object(this); DestroyDamageObjects(); ChainIteratorOf iterator(&childEntityChain); Entity *entity; while((entity = iterator.ReadAndNext()) != NULL) { Check_Object(entity); entity->DestroyChildren(damage_mode); } Entity::ReactToDestruction(damage_mode, 0); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool Entity::IsDestroyable() { if (damageObject != NULL) return true; return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::ReactToDestruction(int damage_mode,int damage_type) { Check_Object(this); isDestroyed = 1; SetDestroyedRepresentation(); SetDestroyedFlag(damage_mode); if (damageBit != -1) { //SPEW(("jerryeds", "ENTITY DESTROYED - TILE : %d : %d", minTileRow, minTileColumn)); EntityManager::GetInstance()->SetNetworkDamageBit(true, damageBit); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::ApplyVisualDamage(const TakeDamageMessage *message, int armor_zone) { Check_Object(this); Check_Object(message); if (message->quickDamage) return; // //------------------------------------------------------------------- //Apply a procedural Damage Effect to ourselves if we have not before //------------------------------------------------------------------- // if(!IsDestroyed()) { Check_Object(VideoRenderer::Instance); LinearMatrix4D damage_matrix = LinearMatrix4D::Identity; Point3D damage_location; RendererComponentWeb *renderer_web = GetComponentWeb(RendererManager::VideoRendererType); if(renderer_web) { VideoComponentWeb *video_web = Cast_Object(VideoComponentWeb *, renderer_web); damage_location.MultiplyByInverse(message->hitOffset, GetLocalToWorld()); damage_matrix.BuildTranslation(damage_location); Vector3D damage_rotation; damage_rotation.Negate(message->normal); damage_matrix.AlignLocalAxisToWorldVector(damage_rotation, Z_Axis, Y_Axis, X_Axis); Scalar radius = message->amountOfDamage * 0.1f; Clamp(radius, 0.5f, 1.0f); if(armor_zone == DamageObject::DefaultArmorZone) { if(!HasPlacedDamageDecal()) { MidLevelRenderer::MLRTexture *texture = (*MidLevelRenderer::MLRTexturePool::Instance)((const char *)"scorch"); if(texture) { Check_Object(texture); damage_matrix(3,0) -= damage_matrix(2,0); damage_matrix(3,1) -= damage_matrix(2,1); damage_matrix(3,2) -= damage_matrix(2,2); radius *= 5.0f; video_web->ApplyDamageDecal(damage_matrix, radius, texture); SetDamageDecalFlag(); } } } else video_web->ApplyDamage(damage_matrix, radius); } else { Entity *entity_to_check = GetParentEntity(); // traverse parents looking for a web while (entity_to_check!=NULL) { // stop at the map if (entity_to_check == Map::GetInstance()) { break; } else { // stop at a parent with a web RendererComponentWeb *renderer_web = entity_to_check->GetComponentWeb(RendererManager::VideoRendererType); if (renderer_web != NULL) { entity_to_check->ApplyVisualDamage(message,armor_zone); break; } } entity_to_check = entity_to_check->GetParentEntity(); } } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AttributeEntry* Entity::GetAttributeEntry(AttributeID attribute_ID) { ClassData *class_data = Cast_Pointer(ClassData*, classData); Check_Object(class_data); return class_data->attributeTable.GetAttributeEntry(attribute_ID); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AttributeEntry* Entity::GetAttributeEntry(const char *attribute_name) { ClassData *class_data = Cast_Pointer(ClassData*, classData); Check_Object(class_data); return class_data->attributeTable.GetAttributeEntry(attribute_name); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::GetGameModelResourceFromDataListID( Resource *resource, const ResourceID &data_list ) { Resource stream(data_list); Verify(stream.GetSize() >= sizeof(ResourceID)); ResourceID resource_id; stream >> resource_id; resource->FindID(resource_id); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // RegisteredClass::ClassID Entity::GetClassIDFromDataListID(const ResourceID &model_list) { Resource resource; GetGameModelResourceFromDataListID(&resource, model_list); GameModel *model = Cast_Pointer(GameModel*,resource.GetPointer()); return model->classID; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::AddChild(Entity *entity) { Check_Object(this); Check_Object(entity); // //----------------------------- // Hook up the entity hierarchy //----------------------------- // Verify(!entity->parentEntity); entity->parentEntity = this; childEntityChain.Add(entity); entity->NeedMatrixSync(); ElementRenderer::Element *child_element = entity->GetElement(); Check_Object(child_element); Check_Object(entityElement); entityElement->AttachChild(child_element); // //--------------------------------------------------- // If are bounds are not locked, calculate them again //--------------------------------------------------- // if ( !entityElement->AreBoundsLocked() && entityElement->GetCullMode() == ElementRenderer::Element::VolumeCullMode ) { entityElement->NeedNewBounds(); NeedMatrixSync(); } #if defined(HUNT_BUG) SPEW((0, "Attaching %s(+", entity->GetClassString())); Spew(0, entity->GetReplicatorID()); SPEW((0, ") to %s(+", GetClassString())); Spew(0, GetReplicatorID()); SPEW((0, ")")); #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::RemoveChild(Entity *entity) { Check_Object(this); Check_Object(entity); // //----------------------------- // Unhook the locator hierarchy //----------------------------- // entity->parentEntity = NULL; childEntityChain.Remove(entity); entity->NeedMatrixSync(); ElementRenderer::Element *element = entity->GetElement(); Check_Object(element); entityElement->DetachChild(element); #if defined(HUNT_BUG) SPEW((0, "Attaching %s(+", entity->GetClassString())); Spew(0, entity->GetReplicatorID()); SPEW((0, ") to %s(+", GetClassString())); Spew(0, GetReplicatorID()); SPEW((0, ")")); #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SetNewLocalToParent(const Stuff::LinearMatrix4D &new_local_to_world) { Check_Object(this); Check_Object(entityElement); Check_Object(parentEntity); ClearTriedToMoveOffMapThisFrameFlag(); // //----------------------------------------------------------- // If our parent isn't the map, set the dirty flag and matrix //----------------------------------------------------------- // if (parentEntity != Map::GetInstance()) { entityElement->SetLocalToParent(new_local_to_world); replicatorFlags |= DirtyMatrixFlag; } // //---------------------------------------------------------------------- // If we are parented to the map, the zone is dirty, and then bodge in a // check to make sure nothing leaves the map //---------------------------------------------------------------------- // else { Point3D translation(new_local_to_world); Check_Object(Map::GetInstance()); if (Map::GetInstance()->FindZone(translation) == -1) { LinearMatrix4D adjusted_matrix = new_local_to_world; const LinearMatrix4D &old_matrix = GetLocalToWorld(); adjusted_matrix(3,0) = old_matrix(3,0); adjusted_matrix(3,2) = old_matrix(3,2); entityElement->SetLocalToParent(adjusted_matrix); replicatorFlags |= DirtyMatrixFlag | TriedToMoveOffMapThisFrameFlag; } else { entityElement->SetLocalToParent(new_local_to_world); replicatorFlags |= DirtyMatrixFlag|DirtyZoneFlag|PostCollisionFlag; } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::ChildPreCollisionChanged(Entity *entity) { Check_Object(this); Check_Object(entity); STOP(("This function should be overridden!")); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::DeleteChildEntities() { Check_Object(this); childEntityChain.DeletePlugs(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SetComponentWeb( unsigned renderer_id, RendererComponentWeb *web ) { Check_Object(this); if(componentWebs[renderer_id]) { delete componentWebs[renderer_id]; } componentWebs[renderer_id] = web; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::ExecuteComponentWebs() { Check_Object(this); POSTCOLLISION_LOGIC("Entity::Execute Webs"); // //---------------------------- // Execute each registered web //---------------------------- // for (unsigned i=1; iExecuteWatcherComponents(); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::BecomeInteresting(bool render_me) { Check_Object(this); // //-------------------------------------- // Tell the renderers we are interesting //-------------------------------------- // LOAD_LOGIC("Become Interesting::Entity"); Start_Timer(Renderer_Loading); Check_Object(RendererManager::Instance); RendererManager::Instance->EntityIsInteresting(this, render_me); // //------------------------------------------------------------------------ // The entity version will just load the solid volumes. Go ahead and load // the stream resource that should be indicated in the game model //------------------------------------------------------------------------ // if (!solidVolume && !hierarchicalVolume) { LOAD_LOGIC("Become Interesting::Entity::Load Collision Volumes"); const GameModel *game_model = GetGameModel(); Check_Object(game_model); #if defined(LAB_ONLY) if (!instanceName) g_LastEntity[0] = '\0'; else { strncpy(g_LastEntity, instanceName, sizeof(g_LastEntity)-1); g_LastEntity[sizeof(g_LastEntity)-1] = '\0'; } #endif // //------------------------------- // Load in the solid if it exists //------------------------------- // if (game_model->obbStreamResourceID != ResourceID::Null) { Resource obb_stream(game_model->obbStreamResourceID); Verify(obb_stream.DoesResourceExist()); gos_PushCurrentHeap(s_CollisionHeap); solidVolume = new CollisionVolume( this, &obb_stream, CollisionVolume::ReadOBBVersion(&obb_stream) ); Check_Object(solidVolume); gos_PopCurrentHeap(); } } // //------------------------------------------------------ // Mark our interest level according to the render level //------------------------------------------------------ // #if defined ARMOR if (render_me) Verify(!Application::GetInstance()->m_localMissionParameters.m_runDedicated); #endif { LOAD_LOGIC("Become Interesting::Entity::Set Interest Mask"); SetInterestMask((render_me) ? RenderingInterestLevel : SimulationInterestLevel); #if defined(_ARMOR) ElementRenderer::Element *element = GetElement(); Check_Object(element); element = element->GetParentElement(); if (element) { if (element->GetClassID() == TileClassID) { element = element->GetParentElement(); Check_Object(element); element = element->GetParentElement(); Check_Object(element); } if (element->GetClassID() == ZoneClassID) { Zone *zone = Cast_Object(Zone*, element); Verify(!zone->m_dormant.IsPlugMember(this)); if (render_me && zone->GetInterestLevel() == RenderingInterestLevel) { Verify(!zone->m_simulated.IsPlugMember(this)); Verify(zone->m_rendered.IsPlugMember(this)); } else { Verify(zone->m_simulated.IsPlugMember(this)); Verify(!zone->m_rendered.IsPlugMember(this)); } } } #endif } Stop_Timer(Renderer_Loading); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::BecomeUninteresting() { Check_Object(this); // //---------------------------- // Execute each registered web //---------------------------- // for (unsigned i=1; iShouldWebBeKilled()) { Check_Object(web); delete web; componentWebs[i] = NULL; } } } // //------------------------ // Delete the solid volume //------------------------ // if (solidVolume) { Check_Object(solidVolume); delete solidVolume; solidVolume = NULL; } if (hierarchicalVolume) { Check_Object(hierarchicalVolume); delete hierarchicalVolume; hierarchicalVolume = NULL; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // const ResourceID& Entity::GetRendererDataResourceID(int renderer_type) { Check_Object(this); ResourceID *data_list = Cast_Pointer(ResourceID*, dataListResource.GetPointer()); Check_Pointer(data_list); Check_Object(RendererManager::Instance); Verify( 0 <= renderer_type && renderer_type < RendererManager::Instance->GetModelListSize() ); return data_list[renderer_type]; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int Entity::GetExecutionSlot() { Check_Object(this); return DefaultExecutionSlot; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::PreCollisionExecute(Time till) { Check_Object(this); Verify(!EntityManager::GetInstance()->isExecutionSuspended); Verify(GetInterestLevel() != DormantInterestLevel); collisionAllowed=true; // //------------------------------------------------------------------------ // Check to see if a post collision pass in necessary. If so, attach this // entity to the entitymanager post collision chain //------------------------------------------------------------------------ // if (IsUsingPostCollision()) { Check_Object(EntityManager::GetInstance()); EntityManager::GetInstance()->RequestPostCollisionExecution(this); } else { lastExecuted = till; #if defined(TIME_BUG) SPEW((TIME_BUG, "PreCollisionOnly execution of %s(+", GetClassString())); Spew(TIME_BUG, GetReplicatorID()); SPEW((TIME_BUG, ") at time %f", lastExecuted.GetSeconds())); #endif } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool Entity::CollisionHandler( Stuff::LinearMatrix4D *new_position, Stuff::DynamicArrayOf *collisions ) { Check_Object(this); Check_Object(collisions); Verify(GetInterestLevel() != DormantInterestLevel); Verify(EntityManager::GetInstance()->IsInPostCollisionExecution(this)); newCollisions = collisions; SPEW((0, "%s should override CollisionHandler", (char*)GetClassString() )); return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SyncMatrices(bool update_matrix) { Check_Object(this); SYNC_LOGIC("Entity"); #if defined(HUNT_BUG) bool old_update=update_matrix; if (update_matrix) { SPEW((0, "Entity::SyncMatrices %s(+", GetClassString())); Spew(0, GetReplicatorID()); SPEW((0, ")")); } #endif Set_Statistic(s_EntitiesSynced, s_EntitiesSynced+1); // //----------------------------------------- // If we have a dirty locator, sync with it //----------------------------------------- // if (IsMatrixDirty()) { if (update_matrix) { Check_Object(entityElement); entityElement->Sync(); update_matrix = false; } ClearNeedMatrixSync(); } // //----------------------------- // Sync our children's locators //----------------------------- // if (!childEntityChain.IsEmpty()) { ChainIteratorOf children(&childEntityChain); Entity *child; while ((child = children.ReadAndNext()) != NULL) { Check_Object(child); child->SyncMatrices(update_matrix); } } #if defined(HUNT_BUG) if (old_update) SPEW((0, "")); #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::SyncMatricesFirstLevelOnly(bool update_matrix) { Check_Object(this); // DANGER DANGER DANGER!!!!!!!!!!!!!!!!!!!!!!!! // THIS IS A NETWORK HACK // USE IT AT OWN RISK #if defined(HUNT_BUG) bool old_update=update_matrix; if (update_matrix) { SPEW((0, "Entity::SyncMatrices %s(+", GetClassString())); Spew(0, GetReplicatorID()); SPEW((0, ")")); } #endif // //----------------------------------------- // If we have a dirty locator, sync with it //----------------------------------------- // if (IsMatrixDirty()) { if (update_matrix) { Check_Object(entityElement); entityElement->Sync(); update_matrix = false; } ClearNeedMatrixSync(); } #if defined(HUNT_BUG) if (old_update) SPEW((0, "")); #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::PostCollisionExecute(Time till) { Check_Object(this); Verify(GetInterestLevel() != DormantInterestLevel); POSTCOLLISION_LOGIC("Entity"); // //---------------------------------------------------------------------- // Remove the old collision list if it exists, then swap to the new list // for next time //---------------------------------------------------------------------- // if (oldCollisions) delete oldCollisions; oldCollisions = newCollisions; newCollisions = NULL; // //--------------------------------------------------------------------- // If the zone is dirty, let the map figure out where the entity should // live //--------------------------------------------------------------------- // if (IsZoneDirty()) { POSTCOLLISION_LOGIC("Entity::UpdateZone"); Verify(parentEntity == Map::GetInstance()); Check_Object(Map::GetInstance()); Map::GetInstance()->UpdateZone(this); Verify(!IsZoneDirty()); } // //------------------------------------------------------------------- // Execute the component webs and update the simulation frame counter //------------------------------------------------------------------- // ExecuteComponentWebs(); lastExecuted = till; #if defined(TIME_BUG) SPEW((TIME_BUG, "PostCollision execution of %s(+", GetClassString())); Spew(TIME_BUG, GetReplicatorID()); SPEW((TIME_BUG, ") at time %f", lastExecuted.GetSeconds())); #endif if(m_doesNeedToUpdateWebs) { m_doesNeedToUpdateWebs = false; ExecuteChildComponentWebs(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::PlaceOnEntity( LinearMatrix4D *position, Motion3D *velocity, const LinearMatrix4D& initial_offset, const Motion3D& initial_velocity ) { Check_Object(this); Check_Object(position); Check_Object(velocity); STOP(("Not implemented")); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::FollowAndBillBoard( Stuff::LinearMatrix4D *position, Stuff::UnitVector3D *direction ) { Check_Object(this); Check_Object(position); Check_Object(direction); LinearMatrix4D new_local_to_parent = *position; Point3D new_translation; new_translation = *position; new_local_to_parent.BuildTranslation(new_translation); new_local_to_parent.AlignLocalAxisToWorldVector(*direction, Y_Axis, Z_Axis, X_Axis); SetNewLocalToParent(new_local_to_parent); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::EnterNeverExecuteState() { Check_Object(this); Verify(!newCollisions); if(parentEntity) { Check_Object(parentEntity); parentEntity->ChildPreCollisionChanged(this); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::LeaveNeverExecuteState() { Check_Object(this); lastExecuted = gos_GetElapsedTime(); collisionAllowed = false; if(parentEntity) { Check_Object(parentEntity); parentEntity->ChildPreCollisionChanged(this); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity* Entity::ProjectLine( Line3D *line, CollisionMask mask, Point3D *target_offset, Normal3D *normal ) { Check_Object(this); Check_Object(line); Check_Pointer(target_offset); Check_Pointer(normal); Check_Object(Map::GetInstance()); CollisionQuery query(line, normal, mask, this); return CollisionGrid::Instance->ProjectLine(&query); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool Entity::IsWithin( Entity *target, Scalar distance, bool ignorey ) { Check_Object(this); Check_Object(target); Vector3D target_line = Vector3D::Identity; Point3D our_position; Point3D target_position; our_position = GetLocalToWorld(); target_position = target->GetLocalToWorld(); if ((our_position.y < -1500) || (target_position.y < -1500)) // units in hell are never near each other return false; if (ignorey) { our_position.y = 0; target_position.y = 0; } target_line.Subtract(target_position, our_position); return target_line.GetLengthSquared() <= (distance * distance); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Scalar Entity::GetDistanceFrom(Entity *target) { Check_Object(this); Check_Object(target); Vector3D target_line = Vector3D::Identity; Point3D our_position; Point3D target_position; our_position = GetLocalToWorld(); target_position = target->GetLocalToWorld(); target_line.Subtract(target_position, our_position); return target_line.GetLength(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Scalar Entity::GetDistanceSquaredFrom(Entity *target, bool ignore_y) { Check_Object(this); Check_Object(target); Vector3D target_line = Vector3D::Identity; Point3D our_position; Point3D target_position; our_position = GetLocalToWorld(); target_position = target->GetLocalToWorld(); target_line.Subtract(target_position, our_position); if(ignore_y) target_line.y = 0.0f; return target_line.GetLengthSquared(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::ExecuteChildComponentWebs() { Check_Object(this); ChainIteratorOf iterator(&childEntityChain); Entity *entity; while((entity = iterator.ReadAndNext()) != NULL) { Check_Object(entity); entity->ExecuteChildComponentWebs(); } ExecuteComponentWebs(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::RemoveCollision() { Check_Object(this); SetCollisionMask(NeverCollidesMask); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool Entity::IsNeverExecuteState() { Check_Object(this); Check_Object(executionState); if (executionState->GetState() == Entity::ExecutionStateEngine::NeverExecuteState) { return true; } return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::TestInstance() { Verify(IsDerivedFrom(DefaultData)); ResourceID *data_list = Cast_Pointer(ResourceID*, dataListResource.GetPointer()); if (data_list != NULL) { Check_Object(RendererManager::Instance); size_t len = RendererManager::Instance->GetModelListSize(); for (size_t i = 0; i < len; i++) { if (data_list[i] != ResourceID::Null) { Resource resource(data_list[i]); Verify(resource.DoesResourceExist()); } } } }