diff --git a/.gitignore b/.gitignore index a340e857..8ebea943 100644 --- a/.gitignore +++ b/.gitignore @@ -95,6 +95,7 @@ ipch/ # Exceptions: CMakeSettings.json +CMakeUserPresets.json *.vcxproj *.filters *.cmake diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 55b3b3b5..59f6e0e0 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -83,6 +83,7 @@ #include "ItemComponent.h" #include "GhostComponent.h" #include "AchievementVendorComponent.h" +#include "VanityUtilities.h" // Table includes #include "CDComponentsRegistryTable.h" @@ -1271,6 +1272,7 @@ void Entity::Update(const float deltaTime) { auto timerName = timer.GetName(); m_Timers.erase(m_Timers.begin() + timerPosition); GetScript()->OnTimerDone(this, timerName); + VanityUtilities::OnTimerDone(this, timerName); TriggerEvent(eTriggerEventType::TIMER_DONE, this); } else { @@ -1334,6 +1336,7 @@ void Entity::OnCollisionProximity(LWOOBJID otherEntity, const std::string& proxN if (!other) return; GetScript()->OnProximityUpdate(this, other, proxName, status); + VanityUtilities::OnProximityUpdate(this, other, proxName, status); RocketLaunchpadControlComponent* rocketComp = GetComponent(); if (!rocketComp) return; diff --git a/dGame/dComponents/ProximityMonitorComponent.cpp b/dGame/dComponents/ProximityMonitorComponent.cpp index 3338dd43..bd2b65f6 100644 --- a/dGame/dComponents/ProximityMonitorComponent.cpp +++ b/dGame/dComponents/ProximityMonitorComponent.cpp @@ -38,7 +38,7 @@ void ProximityMonitorComponent::SetProximityRadius(dpEntity* entity, const std:: m_ProximitiesData.insert(std::make_pair(name, entity)); } -const std::unordered_set& ProximityMonitorComponent::GetProximityObjects(const std::string& name) { +const std::unordered_set& ProximityMonitorComponent::GetProximityObjects(const std::string& name) const { const auto iter = m_ProximitiesData.find(name); if (iter == m_ProximitiesData.cend()) { diff --git a/dGame/dComponents/ProximityMonitorComponent.h b/dGame/dComponents/ProximityMonitorComponent.h index e80f1b5b..2de9fca6 100644 --- a/dGame/dComponents/ProximityMonitorComponent.h +++ b/dGame/dComponents/ProximityMonitorComponent.h @@ -46,7 +46,7 @@ public: * @param name the proximity name to retrieve physics objects for * @return a set of physics entity object IDs for this name */ - const std::unordered_set& GetProximityObjects(const std::string& name); + const std::unordered_set& GetProximityObjects(const std::string& name) const; /** * Checks if the passed object is in proximity of the named proximity sensor diff --git a/dGame/dUtilities/VanityUtilities.cpp b/dGame/dUtilities/VanityUtilities.cpp index 8ae9246d..48d3c0da 100644 --- a/dGame/dUtilities/VanityUtilities.cpp +++ b/dGame/dUtilities/VanityUtilities.cpp @@ -59,9 +59,9 @@ void VanityUtilities::SpawnVanity() { for (const auto& npc : objects) { if (npc.m_ID == LWOOBJID_EMPTY) continue; - if (npc.m_LOT == 176){ + if (npc.m_LOT == 176) { Game::zoneManager->RemoveSpawner(npc.m_ID); - } else{ + } else { auto* entity = Game::entityManager->GetEntity(npc.m_ID); if (!entity) continue; entity->Smash(LWOOBJID_EMPTY, eKillType::VIOLENT); @@ -86,14 +86,14 @@ void VanityUtilities::SpawnVanity() { float rate = GeneralUtils::GenerateRandomNumber(0, 1); if (location.m_Chance < rate) continue; - if (object.m_LOT == 176){ + if (object.m_LOT == 176) { object.m_ID = SpawnSpawner(object, location); } else { // Spawn the NPC auto* objectEntity = SpawnObject(object, location); if (!objectEntity) continue; object.m_ID = objectEntity->GetObjectID(); - if (!object.m_Phrases.empty()){ + if (!object.m_Phrases.empty()) { objectEntity->SetVar>(u"chats", object.m_Phrases); SetupNPCTalk(objectEntity); } @@ -107,7 +107,7 @@ LWOOBJID SpawnSpawner(const VanityObject& object, const VanityObjectLocation& lo // guratantee we have no collisions do { obj.id = ObjectIDManager::GenerateObjectID(); - } while(Game::zoneManager->GetSpawner(obj.id)); + } while (Game::zoneManager->GetSpawner(obj.id)); obj.position = location.m_Position; obj.rotation = location.m_Rotation; obj.settings = object.m_Config; @@ -146,7 +146,7 @@ Entity* SpawnObject(const VanityObject& object, const VanityObjectLocation& loca } void ParseXml(const std::string& file) { - if (loadedFiles.contains(file)){ + if (loadedFiles.contains(file)) { LOG("Trying to load vanity file %s twice!!!", file.c_str()); return; } @@ -232,7 +232,7 @@ void ParseXml(const std::string& file) { auto* configElement = object->FirstChildElement("config"); std::vector keys = {}; std::vector config = {}; - if(configElement) { + if (configElement) { for (auto* key = configElement->FirstChildElement("key"); key != nullptr; key = key->NextSiblingElement("key")) { // Get the config data @@ -240,7 +240,7 @@ void ParseXml(const std::string& file) { if (!data) continue; LDFBaseData* configData = LDFBaseData::DataFromString(data); - if (configData->GetKey() == u"useLocationsAsRandomSpawnPoint" && configData->GetValueType() == eLDFType::LDF_TYPE_BOOLEAN){ + if (configData->GetKey() == u"useLocationsAsRandomSpawnPoint" && configData->GetValueType() == eLDFType::LDF_TYPE_BOOLEAN) { useLocationsAsRandomSpawnPoint = static_cast(configData); continue; } @@ -250,7 +250,7 @@ void ParseXml(const std::string& file) { } if (!keys.empty()) config.push_back(new LDFData>(u"syncLDF", keys)); - VanityObject objectData { + VanityObject objectData{ .m_Name = name, .m_LOT = lot, .m_Equipment = inventory, @@ -288,7 +288,7 @@ void ParseXml(const std::string& file) { continue; } - VanityObjectLocation locationData { + VanityObjectLocation locationData{ .m_Position = { x.value(), y.value(), z.value() }, .m_Rotation = { rw.value(), rx.value(), ry.value(), rz.value() }, }; @@ -403,26 +403,39 @@ void SetupNPCTalk(Entity* npc) { npc->SetProximityRadius(20.0f, "talk"); } -void NPCTalk(Entity* npc) { - auto* proximityMonitorComponent = npc->GetComponent(); +void VanityUtilities::OnProximityUpdate(Entity* entity, Entity* other, const std::string& proxName, const std::string& name) { + if (proxName != "talk") return; + const auto* const proximityMonitorComponent = entity->GetComponent(); + if (!proximityMonitorComponent) return; - if (!proximityMonitorComponent->GetProximityObjects("talk").empty()) { - const auto& chats = npc->GetVar>(u"chats"); - - if (chats.empty()) { - return; - } - - const auto& selected - = chats[GeneralUtils::GenerateRandomNumber(0, static_cast(chats.size() - 1))]; - - GameMessages::SendNotifyClientZoneObject( - npc->GetObjectID(), u"sendToclient_bubble", 0, 0, npc->GetObjectID(), selected, UNASSIGNED_SYSTEM_ADDRESS); + if (name == "ENTER" && !entity->HasTimer("talk")) { + NPCTalk(entity); } +} + +void VanityUtilities::OnTimerDone(Entity* npc, const std::string& name) { + if (name == "talk") { + const auto* const proximityMonitorComponent = npc->GetComponent(); + if (!proximityMonitorComponent || proximityMonitorComponent->GetProximityObjects("talk").empty()) return; + + NPCTalk(npc); + } +} + +void NPCTalk(Entity* npc) { + const auto& chats = npc->GetVar>(u"chats"); + + if (chats.empty()) return; + + const auto& selected + = chats[GeneralUtils::GenerateRandomNumber(0, static_cast(chats.size() - 1))]; + + GameMessages::SendNotifyClientZoneObject( + npc->GetObjectID(), u"sendToclient_bubble", 0, 0, npc->GetObjectID(), selected, UNASSIGNED_SYSTEM_ADDRESS); Game::entityManager->SerializeEntity(npc); const float nextTime = GeneralUtils::GenerateRandomNumber(15, 60); - npc->AddCallbackTimer(nextTime, [npc]() { NPCTalk(npc); }); + npc->AddTimer("talk", nextTime); } diff --git a/dGame/dUtilities/VanityUtilities.h b/dGame/dUtilities/VanityUtilities.h index a1d00501..8044fb92 100644 --- a/dGame/dUtilities/VanityUtilities.h +++ b/dGame/dUtilities/VanityUtilities.h @@ -31,4 +31,8 @@ namespace VanityUtilities { std::string ParseMarkdown( const std::string& file ); + + void OnProximityUpdate(Entity* entity, Entity* other, const std::string& proxName, const std::string& name); + + void OnTimerDone(Entity* entity, const std::string& name); };