diff options
author | Meji <alvaro.megias@outlook.com> | 2023-07-09 11:59:35 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-09 11:59:35 +0200 |
commit | d015711fbb7a8bf57f7bb64ba8113c942d5125de (patch) | |
tree | 1f89cd7221e829a6c49f80208e8e7508d2f6e1c0 | |
parent | 996485e90e2a1ae75a4b93b33bd807f85060ca26 (diff) |
Core/SAI: Implemented new source type SMART_SCRIPT_TYPE_EVENT (3) (#28816)
-rw-r--r-- | sql/updates/world/master/2023_07_09_01_world.sql | 6 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartAI.cpp | 16 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.cpp | 106 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.h | 5 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.cpp | 12 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.h | 28 | ||||
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Events/GameEventSender.cpp | 5 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 69 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 13 | ||||
-rw-r--r-- | src/server/game/Scripting/ScriptMgr.cpp | 28 | ||||
-rw-r--r-- | src/server/game/Scripting/ScriptMgr.h | 18 |
12 files changed, 244 insertions, 64 deletions
diff --git a/sql/updates/world/master/2023_07_09_01_world.sql b/sql/updates/world/master/2023_07_09_01_world.sql new file mode 100644 index 00000000000..1107b0db29b --- /dev/null +++ b/sql/updates/world/master/2023_07_09_01_world.sql @@ -0,0 +1,6 @@ +DROP TABLE IF EXISTS `event_script_names`; +CREATE TABLE `event_script_names` ( + `Id` int unsigned NOT NULL, + `ScriptName` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 372ba77f711..3918f415f9d 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -1242,10 +1242,26 @@ public: } }; +class SmartEventTrigger : public EventScript +{ +public: + SmartEventTrigger() : EventScript("SmartEventTrigger") { } + + void OnTrigger(WorldObject* object, WorldObject* invoker, uint32 eventId) override + { + TC_LOG_DEBUG("scripts.ai", "Event {} is using SmartEventTrigger script", eventId); + SmartScript script; + // Set invoker as BaseObject if there isn't target for GameEvents::Trigger + script.OnInitialize(Coalesce<WorldObject>(object, invoker), nullptr, nullptr, nullptr, eventId); + script.ProcessEventsFor(SMART_EVENT_SEND_EVENT_TRIGGER, invoker->ToUnit(), 0, 0, false, nullptr, invoker->ToGameObject()); + } +}; + void AddSC_SmartScripts() { new SmartTrigger(); new SmartAreaTriggerEntityScript(); new SmartScene(); new SmartQuest(); + new SmartEventTrigger(); } diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 47c5dd279fd..b27e0847c3f 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -54,6 +54,7 @@ SmartScript::SmartScript() areaTrigger = nullptr; sceneTemplate = nullptr; quest = nullptr; + event = 0; mEventPhase = 0; mPathId = 0; mTextTimer = 0; @@ -217,6 +218,7 @@ void SmartScript::ResetBaseObject() me = m; go = nullptr; areaTrigger = nullptr; + player = nullptr; } } @@ -227,6 +229,7 @@ void SmartScript::ResetBaseObject() me = nullptr; go = o; areaTrigger = nullptr; + player = nullptr; } } } @@ -3169,6 +3172,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui case SMART_EVENT_FOLLOW_COMPLETED: case SMART_EVENT_ON_SPELLCLICK: case SMART_EVENT_ON_DESPAWN: + case SMART_EVENT_SEND_EVENT_TRIGGER: ProcessAction(e, unit, var0, var1, bvar, spell, gob); break; case SMART_EVENT_GOSSIP_HELLO: @@ -3910,7 +3914,7 @@ void SmartScript::RetryLater(SmartScriptHolder& e, bool ignoreChanceRoll) e.runOnce = false; } -void SmartScript::FillScript(SmartAIEventList e, WorldObject* obj, AreaTriggerEntry const* at, SceneTemplate const* scene, Quest const* quest) +void SmartScript::FillScript(SmartAIEventList e, WorldObject* obj, AreaTriggerEntry const* at, SceneTemplate const* scene, Quest const* quest, uint32 event) { if (e.empty()) { @@ -3922,6 +3926,8 @@ void SmartScript::FillScript(SmartAIEventList e, WorldObject* obj, AreaTriggerEn TC_LOG_DEBUG("scripts.ai", "SmartScript: EventMap for SceneId {} is empty but is using SmartScript.", scene->SceneId); if (quest) TC_LOG_DEBUG("scripts.ai", "SmartScript: EventMap for Quest {} is empty but is using SmartScript.", quest->GetQuestId()); + if (event) + TC_LOG_DEBUG("scripts.ai", "SmartScript: EventMap for Event {} is empty but is using SmartScript.", event); return; } for (SmartScriptHolder& scriptholder : e) @@ -3969,43 +3975,49 @@ void SmartScript::FillScript(SmartAIEventList e, WorldObject* obj, AreaTriggerEn void SmartScript::GetScript() { SmartAIEventList e; - if (me) - { - e = sSmartScriptMgr->GetScript(-((int32)me->GetSpawnId()), mScriptType); - if (e.empty()) - e = sSmartScriptMgr->GetScript((int32)me->GetEntry(), mScriptType); - FillScript(std::move(e), me, nullptr, nullptr, nullptr); - } - else if (go) - { - e = sSmartScriptMgr->GetScript(-((int32)go->GetSpawnId()), mScriptType); - if (e.empty()) - e = sSmartScriptMgr->GetScript((int32)go->GetEntry(), mScriptType); - FillScript(std::move(e), go, nullptr, nullptr, nullptr); - } - else if (trigger) - { - e = sSmartScriptMgr->GetScript((int32)trigger->ID, mScriptType); - FillScript(std::move(e), nullptr, trigger, nullptr, nullptr); - } - else if (areaTrigger) - { - e = sSmartScriptMgr->GetScript((int32)areaTrigger->GetEntry(), mScriptType); - FillScript(std::move(e), areaTrigger, nullptr, nullptr, nullptr); - } - else if (sceneTemplate) - { - e = sSmartScriptMgr->GetScript(sceneTemplate->SceneId, mScriptType); - FillScript(std::move(e), nullptr, nullptr, sceneTemplate, nullptr); - } - else if (quest) + + // We must use script type to avoid ambiguities + switch (mScriptType) { - e = sSmartScriptMgr->GetScript(quest->GetQuestId(), mScriptType); - FillScript(std::move(e), nullptr, nullptr, nullptr, quest); + case SMART_SCRIPT_TYPE_CREATURE: + e = sSmartScriptMgr->GetScript(-((int32)me->GetSpawnId()), mScriptType); + if (e.empty()) + e = sSmartScriptMgr->GetScript((int32)me->GetEntry(), mScriptType); + FillScript(std::move(e), me, nullptr, nullptr, nullptr, 0); + break; + case SMART_SCRIPT_TYPE_GAMEOBJECT: + e = sSmartScriptMgr->GetScript(-((int32)go->GetSpawnId()), mScriptType); + if (e.empty()) + e = sSmartScriptMgr->GetScript((int32)go->GetEntry(), mScriptType); + FillScript(std::move(e), go, nullptr, nullptr, nullptr, 0); + break; + case SMART_SCRIPT_TYPE_AREATRIGGER_ENTITY: + case SMART_SCRIPT_TYPE_AREATRIGGER_ENTITY_SERVERSIDE: + e = sSmartScriptMgr->GetScript((int32)areaTrigger->GetEntry(), mScriptType); + FillScript(std::move(e), areaTrigger, nullptr, nullptr, nullptr, 0); + break; + case SMART_SCRIPT_TYPE_AREATRIGGER: + e = sSmartScriptMgr->GetScript((int32)trigger->ID, mScriptType); + FillScript(std::move(e), nullptr, trigger, nullptr, nullptr, 0); + break; + case SMART_SCRIPT_TYPE_SCENE: + e = sSmartScriptMgr->GetScript(sceneTemplate->SceneId, mScriptType); + FillScript(std::move(e), nullptr, nullptr, sceneTemplate, nullptr, 0); + break; + case SMART_SCRIPT_TYPE_QUEST: + e = sSmartScriptMgr->GetScript(quest->GetQuestId(), mScriptType); + FillScript(std::move(e), nullptr, nullptr, nullptr, quest, 0); + break; + case SMART_SCRIPT_TYPE_EVENT: + e = sSmartScriptMgr->GetScript((int32)event, mScriptType); + FillScript(std::move(e), nullptr, nullptr, nullptr, nullptr, event); + break; + default: + break; } } -void SmartScript::OnInitialize(WorldObject* obj, AreaTriggerEntry const* at, SceneTemplate const* scene, Quest const* qst) +void SmartScript::OnInitialize(WorldObject* obj, AreaTriggerEntry const* at, SceneTemplate const* scene, Quest const* qst, uint32 evnt) { if (at) { @@ -4049,6 +4061,32 @@ void SmartScript::OnInitialize(WorldObject* obj, AreaTriggerEntry const* at, Sce TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is Quest with id {}, triggered by player {}", qst->GetQuestId(), player->GetGUID().ToString()); } + else if (evnt) + { + mScriptType = SMART_SCRIPT_TYPE_EVENT; + event = evnt; + + if (obj->IsPlayer()) + { + player = obj->ToPlayer(); + TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is Event {}, triggered by player {}", event, player->GetGUID().ToString()); + } + else if (obj->IsCreature()) + { + me = obj->ToCreature(); + TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is Event {}, triggered by creature {}", event, me->GetEntry()); + } + else if (obj->IsGameObject()) + { + go = obj->ToGameObject(); + TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is Event {}, triggered by gameobject {}", event, go->GetEntry()); + } + else + { + TC_LOG_ERROR("misc", "SmartScript::OnInitialize: source is Event {}, missing trigger WorldObject", event); + return; + } + } else if (obj) // Handle object based scripts { switch (obj->GetTypeId()) diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index 7a92199c7a8..6e3068e5f38 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -38,9 +38,9 @@ class TC_GAME_API SmartScript SmartScript(); ~SmartScript(); - void OnInitialize(WorldObject* obj, AreaTriggerEntry const* at = nullptr, SceneTemplate const* scene = nullptr, Quest const* qst = nullptr); + void OnInitialize(WorldObject* obj, AreaTriggerEntry const* at = nullptr, SceneTemplate const* scene = nullptr, Quest const* qst = nullptr, uint32 evnt = 0); void GetScript(); - void FillScript(SmartAIEventList e, WorldObject* obj, AreaTriggerEntry const* at, SceneTemplate const* scene, Quest const* quest); + void FillScript(SmartAIEventList e, WorldObject* obj, AreaTriggerEntry const* at, SceneTemplate const* scene, Quest const* quest, uint32 event = 0); void ProcessEventsFor(SMART_EVENT e, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, SpellInfo const* spell = nullptr, GameObject* gob = nullptr, std::string const& varString = ""); void ProcessEvent(SmartScriptHolder& e, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, SpellInfo const* spell = nullptr, GameObject* gob = nullptr, std::string const& varString = ""); @@ -122,6 +122,7 @@ class TC_GAME_API SmartScript AreaTrigger* areaTrigger; SceneTemplate const* sceneTemplate; Quest const* quest; + uint32 event; SmartScriptType mScriptType; uint32 mEventPhase; diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 9ae7999e86f..b20f669bcd8 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -137,6 +137,15 @@ void SmartAIMgr::LoadSmartAIFromDB() } break; } + case SMART_SCRIPT_TYPE_EVENT: + { + if (!sObjectMgr->IsValidEvent((uint32)temp.entryOrGuid)) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Event id ({}) does not exist, skipped loading.", uint32(temp.entryOrGuid)); + continue; + } + break; + } case SMART_SCRIPT_TYPE_QUEST: { if (!sObjectMgr->GetQuestTemplate((uint32)temp.entryOrGuid)) @@ -451,6 +460,7 @@ SmartScriptHolder& SmartAIMgr::FindLinkedEvent(SmartAIEventList& list, uint32 li case SMART_EVENT_SCENE_TRIGGER: case SMART_EVENT_SCENE_CANCEL: case SMART_EVENT_SCENE_COMPLETE: + case SMART_EVENT_SEND_EVENT_TRIGGER: return true; default: return false; @@ -804,6 +814,7 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e) case SMART_EVENT_ON_SPELL_FAILED: return sizeof(SmartEvent::spellCast); case SMART_EVENT_ON_SPELL_START: return sizeof(SmartEvent::spellCast); case SMART_EVENT_ON_DESPAWN: return NO_PARAMS; + case SMART_EVENT_SEND_EVENT_TRIGGER: return NO_PARAMS; default: TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} is using an event with no unused params specified in SmartAIMgr::CheckUnusedEventParams(), please report this.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); @@ -1442,6 +1453,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_EVENT_SCENE_CANCEL: case SMART_EVENT_SCENE_COMPLETE: case SMART_EVENT_SCENE_TRIGGER: + case SMART_EVENT_SEND_EVENT_TRIGGER: break; // Unused case SMART_EVENT_TARGET_HEALTH_PCT: diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 9406fbedb00..966b5fd2b0f 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -186,8 +186,9 @@ enum SMART_EVENT SMART_EVENT_ON_SPELL_FAILED = 84, // SpellID, CooldownMin, CooldownMax SMART_EVENT_ON_SPELL_START = 85, // SpellID, CooldownMin, CooldownMax SMART_EVENT_ON_DESPAWN = 86, // NONE + SMART_EVENT_SEND_EVENT_TRIGGER = 87, // NONE - SMART_EVENT_END = 87 + SMART_EVENT_END = 88 }; struct SmartEvent @@ -1444,18 +1445,18 @@ struct SmartTarget enum SmartScriptType { - SMART_SCRIPT_TYPE_CREATURE = 0, //done - SMART_SCRIPT_TYPE_GAMEOBJECT = 1, //done - SMART_SCRIPT_TYPE_AREATRIGGER = 2, //done - SMART_SCRIPT_TYPE_EVENT = 3, // - SMART_SCRIPT_TYPE_GOSSIP = 4, // - SMART_SCRIPT_TYPE_QUEST = 5, //done - SMART_SCRIPT_TYPE_SPELL = 6, // - SMART_SCRIPT_TYPE_TRANSPORT = 7, // - SMART_SCRIPT_TYPE_INSTANCE = 8, // - SMART_SCRIPT_TYPE_TIMED_ACTIONLIST = 9, // - SMART_SCRIPT_TYPE_SCENE = 10, //done - SMART_SCRIPT_TYPE_AREATRIGGER_ENTITY = 11, + SMART_SCRIPT_TYPE_CREATURE = 0, + SMART_SCRIPT_TYPE_GAMEOBJECT = 1, + SMART_SCRIPT_TYPE_AREATRIGGER = 2, + SMART_SCRIPT_TYPE_EVENT = 3, + SMART_SCRIPT_TYPE_GOSSIP = 4, // NYI + SMART_SCRIPT_TYPE_QUEST = 5, + SMART_SCRIPT_TYPE_SPELL = 6, // NYI + SMART_SCRIPT_TYPE_TRANSPORT = 7, // NYI + SMART_SCRIPT_TYPE_INSTANCE = 8, // NYI + SMART_SCRIPT_TYPE_TIMED_ACTIONLIST = 9, + SMART_SCRIPT_TYPE_SCENE = 10, + SMART_SCRIPT_TYPE_AREATRIGGER_ENTITY = 11, SMART_SCRIPT_TYPE_AREATRIGGER_ENTITY_SERVERSIDE = 12, SMART_SCRIPT_TYPE_MAX }; @@ -1582,6 +1583,7 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] = {SMART_EVENT_ON_SPELL_FAILED, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_ON_SPELL_START, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_ON_DESPAWN, SMART_SCRIPT_TYPE_MASK_CREATURE }, + {SMART_EVENT_SEND_EVENT_TRIGGER, SMART_SCRIPT_TYPE_MASK_EVENT } }; enum SmartEventFlags diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 72bb7094edc..6a13177d4b5 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -270,7 +270,7 @@ public: } }(); if (eventId) - GameEvents::Trigger(eventId, &_owner, nullptr); + GameEvents::Trigger(eventId, &_owner, &_owner); if (_autoCycleBetweenStopFrames) { diff --git a/src/server/game/Events/GameEventSender.cpp b/src/server/game/Events/GameEventSender.cpp index 038f7d50a4e..da1dd86601e 100644 --- a/src/server/game/Events/GameEventSender.cpp +++ b/src/server/game/Events/GameEventSender.cpp @@ -21,6 +21,7 @@ #include "Map.h" #include "ObjectMgr.h" #include "Player.h" +#include "ScriptMgr.h" #include "Util.h" #include "ZoneScript.h" @@ -37,7 +38,8 @@ void GameEvents::Trigger(uint32 gameEventId, WorldObject* source, WorldObject* t if (zoneScript) zoneScript->ProcessEvent(target, gameEventId, source); - Map* map = refForMapAndZoneScript->GetMap(); + sScriptMgr->OnEventTrigger(target, source, gameEventId); + if (GameObject* goTarget = Object::ToGameObject(target)) if (GameObjectAI* goAI = goTarget->AI()) goAI->EventInform(gameEventId); @@ -45,6 +47,7 @@ void GameEvents::Trigger(uint32 gameEventId, WorldObject* source, WorldObject* t if (Player* sourcePlayer = Object::ToPlayer(source)) TriggerForPlayer(gameEventId, sourcePlayer); + Map* map = refForMapAndZoneScript->GetMap(); TriggerForMap(gameEventId, map, source, target); } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 7605cb6b698..c8e548d1a39 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -5832,24 +5832,24 @@ void ObjectMgr::LoadSpellScripts() } } -void ObjectMgr::LoadEventScripts() +void ObjectMgr::LoadEventSet() { - LoadScripts(SCRIPTS_EVENT); + _eventStore.clear(); - std::set<uint32> evt_scripts; - // Load all possible script entries from gameobjects + // Load all possible event ids from gameobjects for (auto const& gameObjectTemplatePair : _gameObjectTemplateStore) if (uint32 eventId = gameObjectTemplatePair.second.GetEventScriptId()) - evt_scripts.insert(eventId); + _eventStore.insert(eventId); - // Load all possible script entries from spells + // Load all possible event ids from spells for (SpellNameEntry const* spellNameEntry : sSpellNameStore) if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(spellNameEntry->ID, DIFFICULTY_NONE)) for (SpellEffectInfo const& spellEffectInfo : spell->GetEffects()) if (spellEffectInfo.IsEffect(SPELL_EFFECT_SEND_EVENT)) if (spellEffectInfo.MiscValue) - evt_scripts.insert(spellEffectInfo.MiscValue); + _eventStore.insert(spellEffectInfo.MiscValue); + // Load all possible event ids from taxi path nodes for (size_t path_idx = 0; path_idx < sTaxiPathNodesByPath.size(); ++path_idx) { for (size_t node_idx = 0; node_idx < sTaxiPathNodesByPath[path_idx].size(); ++node_idx) @@ -5857,21 +5857,58 @@ void ObjectMgr::LoadEventScripts() TaxiPathNodeEntry const* node = sTaxiPathNodesByPath[path_idx][node_idx]; if (node->ArrivalEventID) - evt_scripts.insert(node->ArrivalEventID); + _eventStore.insert(node->ArrivalEventID); if (node->DepartureEventID) - evt_scripts.insert(node->DepartureEventID); + _eventStore.insert(node->DepartureEventID); } } +} + +void ObjectMgr::LoadEventScripts() +{ + // Set of valid events referenced in several sources + LoadEventSet(); + + // Deprecated + LoadScripts(SCRIPTS_EVENT); // Then check if all scripts are in above list of possible script entries for (ScriptMapMap::const_iterator itr = sEventScripts.begin(); itr != sEventScripts.end(); ++itr) { - std::set<uint32>::const_iterator itr2 = evt_scripts.find(itr->first); - if (itr2 == evt_scripts.end()) - TC_LOG_ERROR("sql.sql", "Table `event_scripts` has script (Id: {}) not referring to any gameobject_template type 10 data2 field, type 3 data6 field, type 13 data 2 field or any spell effect {}", + if (!IsValidEvent(itr->first)) + TC_LOG_ERROR("sql.sql", "Table `event_scripts` has script (Id: {}) not referring to any gameobject_template (type 3 data6 field, type 7 data3 field, type 10 data2 field, type 13 data2 field, type 50 data7 field), any taxi path node or any spell effect {}", itr->first, SPELL_EFFECT_SEND_EVENT); } + + uint32 oldMSTime = getMSTime(); + + _eventScriptStore.clear(); // Reload case + + QueryResult result = WorldDatabase.Query("SELECT Id, ScriptName FROM event_script_names"); + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 event scripts. DB table `event_script_names` is empty."); + return; + } + + do + { + Field* fields = result->Fetch(); + + uint32 eventId = fields[0].GetUInt32(); + std::string const scriptName = fields[1].GetString(); + + if (!IsValidEvent(eventId)) + { + TC_LOG_ERROR("sql.sql", "Event (ID: {}) not referring to any gameobject_template (type 3 data6 field, type 7 data3 field, type 10 data2 field, type 13 data2 field, type 50 data7 field), any taxi path node or any spell effect {}", + eventId, SPELL_EFFECT_SEND_EVENT); + continue; + } + _eventScriptStore[eventId] = GetScriptId(scriptName); + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded {} event scripts in {} ms", _eventScriptStore.size(), GetMSTimeDiffToNow(oldMSTime)); } //Load WP Scripts @@ -8982,6 +9019,14 @@ SpellScriptsBounds ObjectMgr::GetSpellScriptsBounds(uint32 spellId) return SpellScriptsBounds(_spellScriptsStore.equal_range(spellId)); } +uint32 ObjectMgr::GetEventScriptId(uint32 eventId) const +{ + EventScriptContainer::const_iterator i = _eventScriptStore.find(eventId); + if (i != _eventScriptStore.end()) + return i->second; + return 0; +} + // this allows calculating base reputations to offline players, just by race and class int32 ObjectMgr::GetBaseReputationOf(FactionEntry const* factionEntry, uint8 race, uint8 playerClass) const { diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index f0b35c6aafa..2cd8185dd26 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1096,6 +1096,9 @@ class TC_GAME_API ObjectMgr typedef std::unordered_map<uint64, AccessRequirement> AccessRequirementContainer; + typedef std::set<uint32> EventContainer; + typedef std::unordered_map<uint32, uint32> EventScriptContainer; + typedef std::unordered_map<uint32, RepRewardRate > RepRewardRateContainer; typedef std::unordered_map<uint32, ReputationOnKillEntry> RepOnKillContainer; typedef std::unordered_map<uint32, RepSpilloverTemplate> RepSpilloverTemplateContainer; @@ -1218,6 +1221,11 @@ class TC_GAME_API ObjectMgr return _gameObjectForQuestStore.find(entry) != _gameObjectForQuestStore.end(); } + bool IsValidEvent(uint32 eventId) const + { + return _eventStore.find(eventId) != _eventStore.end(); + } + NpcText const* GetNpcText(uint32 textID) const; QuestGreeting const* GetQuestGreeting(TypeID type, uint32 id) const; QuestGreetingLocale const* GetQuestGreetingLocale(TypeID type, uint32 id) const; @@ -1238,6 +1246,7 @@ class TC_GAME_API ObjectMgr AreaTriggerStruct const* GetMapEntranceTrigger(uint32 Map) const; uint32 GetAreaTriggerScriptId(uint32 trigger_id) const; + uint32 GetEventScriptId(uint32 eventId) const; SpellScriptsBounds GetSpellScriptsBounds(uint32 spellId); RepRewardRate const* GetRepRewardRate(uint32 factionId) const @@ -1810,6 +1819,9 @@ class TC_GAME_API ObjectMgr DungeonEncounterContainer _dungeonEncounterStore; std::unordered_map<uint32, WorldSafeLocsEntry> _worldSafeLocs; + EventContainer _eventStore; + EventScriptContainer _eventScriptStore; + RepRewardRateContainer _repRewardRateStore; RepOnKillContainer _repOnKillStore; RepSpilloverTemplateContainer _repSpilloverTemplateStore; @@ -1864,6 +1876,7 @@ class TC_GAME_API ObjectMgr std::unordered_map<uint32, std::vector<TerrainSwapInfo*>> _terrainSwapInfoByMap; private: + void LoadEventSet(); void LoadScripts(ScriptsType type); void LoadQuestRelationsHelper(QuestRelations& map, QuestRelationsReverse* reverseMap, std::string const& table); QuestRelationResult GetQuestRelationsFrom(QuestRelations const& map, uint32 key, bool onlyActive) const { return { map.equal_range(key), onlyActive }; } diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index ea370b4efb4..1dfaa9aeb67 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -87,7 +87,7 @@ struct is_script_database_bound<AreaTriggerScript> template<> struct is_script_database_bound<BattlefieldScript> - : std::true_type { }; + : std::true_type { }; template<> struct is_script_database_bound<BattlegroundScript> @@ -137,6 +137,10 @@ template<> struct is_script_database_bound<WorldStateScript> : std::true_type { }; +template<> +struct is_script_database_bound<EventScript> + : std::true_type { }; + enum Spells { SPELL_HOTSWAP_VISUAL_SPELL_EFFECT = 40162 // 59084 @@ -2358,6 +2362,15 @@ void ScriptMgr::OnWorldStateValueChange(WorldStateTemplate const* worldStateTemp tmpscript->OnValueChange(worldStateTemplate->Id, oldValue, newValue, map); } +// Event +void ScriptMgr::OnEventTrigger(WorldObject* object, WorldObject* invoker, uint32 eventId) +{ + ASSERT(invoker); + + GET_SCRIPT(EventScript, sObjectMgr->GetEventScriptId(eventId), tmpscript); + tmpscript->OnTrigger(object, invoker, eventId); +} + SpellScriptLoader::SpellScriptLoader(char const* name) : ScriptObject(name) { @@ -3209,6 +3222,18 @@ void WorldStateScript::OnValueChange(int32 /*worldStateId*/, int32 /*oldValue*/, { } +EventScript::EventScript(char const* name) + : ScriptObject(name) +{ + ScriptRegistry<EventScript>::Instance()->AddScript(this); +} + +EventScript::~EventScript() = default; + +void EventScript::OnTrigger(WorldObject* /*object*/, WorldObject* /*invoker*/, uint32 /*eventId*/) +{ +} + // Specialize for each script type class like so: template class TC_GAME_API ScriptRegistry<SpellScriptLoader>; template class TC_GAME_API ScriptRegistry<ServerScript>; @@ -3243,3 +3268,4 @@ template class TC_GAME_API ScriptRegistry<ConversationScript>; template class TC_GAME_API ScriptRegistry<SceneScript>; template class TC_GAME_API ScriptRegistry<QuestScript>; template class TC_GAME_API ScriptRegistry<WorldStateScript>; +template class TC_GAME_API ScriptRegistry<EventScript>; diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 631b5320cd6..f20652607b2 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -990,6 +990,20 @@ class TC_GAME_API WorldStateScript : public ScriptObject virtual void OnValueChange(int32 worldStateId, int32 oldValue, int32 newValue, Map const* map); }; +class TC_GAME_API EventScript : public ScriptObject +{ + protected: + + explicit EventScript(char const* name); + + public: + + ~EventScript(); + + // Called when a game event is triggered + virtual void OnTrigger(WorldObject* object, WorldObject* invoker, uint32 eventId); +}; + // Manages registration, loading, and execution of scripts. class TC_GAME_API ScriptMgr { @@ -1296,6 +1310,10 @@ class TC_GAME_API ScriptMgr void OnWorldStateValueChange(WorldStateTemplate const* worldStateTemplate, int32 oldValue, int32 newValue, Map const* map); + public: /* EventScript */ + + void OnEventTrigger(WorldObject* object, WorldObject* invoker, uint32 eventId); + private: uint32 _scriptCount; bool _scriptIdUpdated; |