From 2d92b338d714b36fdae5d8dd811abf724abd43a9 Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Fri, 22 May 2026 07:58:23 -0300 Subject: [PATCH] feat(Core/SmartAI): add SMART_ACTION_INC_DATA (242) (#25922) Co-authored-by: Claude Opus 4.7 (1M context) --- src/server/game/AI/SmartScripts/SmartAI.cpp | 11 +++++++ src/server/game/AI/SmartScripts/SmartAI.h | 2 ++ .../game/AI/SmartScripts/SmartScript.cpp | 29 +++++++++++++++++++ .../game/AI/SmartScripts/SmartScriptMgr.cpp | 2 ++ .../game/AI/SmartScripts/SmartScriptMgr.h | 3 +- .../Globals/GameObjectSummonGroupTest.cpp | 3 +- 6 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index f84e84c34..1eb4233d9 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -1369,6 +1369,7 @@ void SmartGameObjectAI::UpdateAI(uint32 diff) void SmartGameObjectAI::InitializeAI() { GetScript()->OnInitialize(me); + aiDataSet.clear(); // Xinef: do not call respawn event if go is not spawned if (me->isSpawned()) @@ -1437,9 +1438,19 @@ void SmartGameObjectAI::SetData(uint32 id, uint32 value, WorldObject* invoker) gob = invoker->ToGameObject(); } + aiDataSet[id] = value; GetScript()->ProcessEventsFor(SMART_EVENT_DATA_SET, unit, id, value, false, nullptr, gob); } +uint32 SmartGameObjectAI::GetData(uint32 id) const +{ + std::unordered_map::const_iterator itr = aiDataSet.find(id); + if (itr != aiDataSet.end()) + return itr->second; + + return 0; +} + void SmartGameObjectAI::SetScript9(SmartScriptHolder& e, uint32 entry, WorldObject* invoker) { if (invoker) diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 64e208b0d..5a8ec52bc 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -304,6 +304,7 @@ public: void Destroyed(Player* player, uint32 eventId) override; void SetData(uint32 id, uint32 value) override { SetData(id, value, nullptr); } void SetData(uint32 id, uint32 value, WorldObject* invoker); + uint32 GetData(uint32 id) const override; void SetScript9(SmartScriptHolder& e, uint32 entry, WorldObject* invoker); void OnGameEvent(bool start, uint16 eventId) override; void OnStateChanged(uint32 state, Unit* unit) override; @@ -324,6 +325,7 @@ public: protected: SmartScript mScript; + std::unordered_map aiDataSet; }; /// Registers scripts required by the SAI scripting system diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 81bfa0c04..ee060c635 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1463,6 +1463,35 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } break; } + case SMART_ACTION_INC_DATA: + { + WorldObject* invoker = me ? static_cast(me) : static_cast(go); + + for (WorldObject* target : targets) + { + if (Creature* cTarget = target->ToCreature()) + { + if (SmartAI* smartAI = CAST_AI(SmartAI, cTarget->AI())) + { + uint32 const newValue = smartAI->GetData(e.action.setData.field) + e.action.setData.data; + smartAI->SetData(e.action.setData.field, newValue, invoker); + } + else + LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_INC_DATA is not using SmartAI, skipping"); + } + else if (GameObject* oTarget = target->ToGameObject()) + { + if (SmartGameObjectAI* smartGOAI = CAST_AI(SmartGameObjectAI, oTarget->AI())) + { + uint32 const newValue = smartGOAI->GetData(e.action.setData.field) + e.action.setData.data; + smartGOAI->SetData(e.action.setData.field, newValue, invoker); + } + else + LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_INC_DATA is not using SmartGameObjectAI, skipping"); + } + } + break; + } case SMART_ACTION_MOVE_FORWARD: { if (!me) diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index f2bb0bedd..2f96485c7 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -759,6 +759,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e) case SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL: return sizeof(SmartAction::morphOrMount); case SMART_ACTION_SET_INGAME_PHASE_MASK: return sizeof(SmartAction::ingamePhaseMask); case SMART_ACTION_SET_DATA: return sizeof(SmartAction::setData); + case SMART_ACTION_INC_DATA: return sizeof(SmartAction::setData); case SMART_ACTION_MOVE_FORWARD: return sizeof(SmartAction::moveRandom); case SMART_ACTION_ATTACK_STOP: return NO_PARAMS; case SMART_ACTION_SET_VISIBILITY: return sizeof(SmartAction::visibility); @@ -1975,6 +1976,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_THREAT_SINGLE_PCT: case SMART_ACTION_SET_INST_DATA64: case SMART_ACTION_SET_DATA: + case SMART_ACTION_INC_DATA: case SMART_ACTION_MOVE_FORWARD: case SMART_ACTION_ESCORT_PAUSE: case SMART_ACTION_SET_FLY: diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index c265f582e..1105fe559 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -726,8 +726,9 @@ enum SMART_ACTION SMART_ACTION_SET_ANIM_TIER = 239, // animtier SMART_ACTION_SET_GOSSIP_MENU = 240, // gossipMenuId SMART_ACTION_SUMMON_GAMEOBJECT_GROUP = 241, // group + SMART_ACTION_INC_DATA = 242, // field, increment (uses aiDataSet, wipe-safe across evade) - SMART_ACTION_AC_END = 242, // placeholder + SMART_ACTION_AC_END = 243, // placeholder }; enum class SmartActionSummonCreatureFlags diff --git a/src/test/server/game/Globals/GameObjectSummonGroupTest.cpp b/src/test/server/game/Globals/GameObjectSummonGroupTest.cpp index 97664bc89..5deb59e9a 100644 --- a/src/test/server/game/Globals/GameObjectSummonGroupTest.cpp +++ b/src/test/server/game/Globals/GameObjectSummonGroupTest.cpp @@ -110,7 +110,8 @@ TEST_F(GameObjectSummonGroupTest, DifferentGroupsAreIndependent) TEST_F(GameObjectSummonGroupTest, SmartActionEnumValue) { EXPECT_EQ(SMART_ACTION_SUMMON_GAMEOBJECT_GROUP, 241); - EXPECT_EQ(SMART_ACTION_AC_END, 242); + EXPECT_EQ(SMART_ACTION_INC_DATA, 242); + EXPECT_EQ(SMART_ACTION_AC_END, 243); } TEST_F(GameObjectSummonGroupTest, SmartActionUnionSize)