aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBandyscTC <b.andysc+tc@gmail.com>2025-09-07 19:09:44 +0100
committerGitHub <noreply@github.com>2025-09-07 20:09:44 +0200
commit80437d3c79853c27ffa60b1988d1459586d18cbb (patch)
treeb4ff6a857ce206adc03a039e9df2d18a0a3e46de /src
parentce6a1b7b913120cafc7e8825f688a9f3de9e8b6a (diff)
Core/SAI: Add storedTargetId param to summon actions (#31142)
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp66
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp19
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h14
4 files changed, 80 insertions, 20 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index d5407d5f131..e1715f787b6 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -22,6 +22,7 @@
#include "Creature.h"
#include "CreatureTextMgr.h"
#include "CreatureTextMgrImpl.h"
+#include "DB2Stores.h"
#include "GameEventMgr.h"
#include "GameEventSender.h"
#include "GameObject.h"
@@ -41,6 +42,7 @@
#include "Random.h"
#include "ScriptActions.h"
#include "SmartAI.h"
+#include "SpellMgr.h"
#include "SpellAuras.h"
#include "TemporarySummon.h"
#include "Vehicle.h"
@@ -116,6 +118,11 @@ bool SmartScript::IsSmart(bool silent) const
return false;
}
+void SmartScript::ClearTargetList(uint32 id)
+{
+ _storedTargets.erase(id);
+}
+
void SmartScript::StoreTargetList(ObjectVector const& targets, uint32 id)
{
// insert or replace
@@ -1241,6 +1248,8 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
EnumFlag<SmartActionSummonCreatureFlags> flags(static_cast<SmartActionSummonCreatureFlags>(e.action.summonCreature.flags));
bool preferUnit = flags.HasFlag(SmartActionSummonCreatureFlags::PreferUnit);
+ bool attackInvoker = flags.HasFlag(SmartActionSummonCreatureFlags::AttackInvoker);
+
WorldObject* summoner = preferUnit ? unit : GetBaseObjectOrUnitInvoker(unit);
if (!summoner)
break;
@@ -1250,6 +1259,35 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
privateObjectOwner = summoner->IsPrivateObject() ? summoner->GetPrivateObjectOwner() : summoner->GetGUID();
uint32 spawnsCount = std::max(e.action.summonCreature.count, 1u);
+ if (e.action.summonCreature.storedTargetId)
+ ClearTargetList(e.action.summonCreature.storedTargetId);
+
+ SummonPropertiesEntry const* summonProperties = [&]() -> SummonPropertiesEntry const*
+ {
+ if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.action.summonCreature.createdBySpell, DIFFICULTY_NONE))
+ for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
+ if (spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON))
+ if (SummonPropertiesEntry const* summonProps = sSummonPropertiesStore.LookupEntry(spellEffectInfo.MiscValueB))
+ return summonProps;
+
+ return nullptr;
+ }();
+
+ auto DoSummon = [&](float x, float y, float z, float o, Unit* attackTarget)
+ {
+ for (uint32 counter = 0; counter < spawnsCount; counter++)
+ {
+ if (TempSummon* summon = summoner->GetMap()->SummonCreature(e.action.summonCreature.creature, { x, y, z, o }, summonProperties, Milliseconds(e.action.summonCreature.duration), summoner, e.action.summonCreature.createdBySpell, 0, privateObjectOwner))
+ {
+ summon->SetTempSummonType((TempSummonType)e.action.summonCreature.type);
+ if (e.action.summonCreature.storedTargetId)
+ AddToStoredTargetList({ summon }, e.action.summonCreature.storedTargetId);
+ if (attackInvoker && attackTarget)
+ summon->AI()->AttackStart(attackTarget);
+ }
+ }
+ };
+
float x, y, z, o;
for (WorldObject* target : targets)
{
@@ -1258,23 +1296,13 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
y += e.target.y;
z += e.target.z;
o += e.target.o;
- for (uint32 counter = 0; counter < spawnsCount; counter++)
- {
- if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, x, y, z, o, (TempSummonType)e.action.summonCreature.type, Milliseconds(e.action.summonCreature.duration), privateObjectOwner))
- if (e.action.summonCreature.attackInvoker)
- summon->AI()->AttackStart(target->ToUnit());
- }
+ DoSummon(x, y, z, o, target->ToUnit());
}
if (e.GetTargetType() != SMART_TARGET_POSITION)
break;
- for (uint32 counter = 0; counter < spawnsCount; counter++)
- {
- if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, e.target.x, e.target.y, e.target.z, e.target.o, (TempSummonType)e.action.summonCreature.type, Milliseconds(e.action.summonCreature.duration), privateObjectOwner))
- if (unit && e.action.summonCreature.attackInvoker)
- summon->AI()->AttackStart(unit);
- }
+ DoSummon(e.target.x, e.target.y, e.target.z, e.target.o, unit);
break;
}
case SMART_ACTION_SUMMON_GO:
@@ -1283,18 +1311,25 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (!summoner)
break;
+ if (e.action.summonGO.storedTargetId)
+ ClearTargetList(e.action.summonGO.storedTargetId);
+
for (WorldObject* target : targets)
{
Position pos = target->GetPositionWithOffset(Position(e.target.x, e.target.y, e.target.z, e.target.o));
QuaternionData rot = QuaternionData::fromEulerAnglesZYX(pos.GetOrientation(), 0.f, 0.f);
- summoner->SummonGameObject(e.action.summonGO.entry, pos, rot, Seconds(e.action.summonGO.despawnTime), GOSummonType(e.action.summonGO.summonType));
+ GameObject* summon = summoner->SummonGameObject(e.action.summonGO.entry, pos, rot, Seconds(e.action.summonGO.despawnTime), GOSummonType(e.action.summonGO.summonType));
+ if (e.action.summonGO.storedTargetId && summon)
+ AddToStoredTargetList({ summon }, e.action.summonGO.storedTargetId);
}
if (e.GetTargetType() != SMART_TARGET_POSITION)
break;
QuaternionData rot = QuaternionData::fromEulerAnglesZYX(e.target.o, 0.f, 0.f);
- summoner->SummonGameObject(e.action.summonGO.entry, Position(e.target.x, e.target.y, e.target.z, e.target.o), rot, Seconds(e.action.summonGO.despawnTime), GOSummonType(e.action.summonGO.summonType));
+ GameObject* summon = summoner->SummonGameObject(e.action.summonGO.entry, Position(e.target.x, e.target.y, e.target.z, e.target.o), rot, Seconds(e.action.summonGO.despawnTime), GOSummonType(e.action.summonGO.summonType));
+ if (e.action.summonGO.storedTargetId && summon)
+ AddToStoredTargetList({ summon }, e.action.summonGO.storedTargetId);
break;
}
case SMART_ACTION_KILL_UNIT:
@@ -2031,6 +2066,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
for (TempSummon* summon : summonList)
if (unit && e.action.creatureGroup.attackInvoker)
summon->AI()->AttackStart(unit);
+
+ if (e.action.creatureGroup.storedTargetId)
+ StoreTargetList({ summonList.begin(), summonList.end() }, e.action.creatureGroup.storedTargetId);
break;
}
case SMART_ACTION_SET_POWER:
diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h
index e4c4c8d3907..fd4730829ef 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.h
+++ b/src/server/game/AI/SmartScripts/SmartScript.h
@@ -81,6 +81,7 @@ class TC_GAME_API SmartScript
bool IsSmart(GameObject* g, bool silent = false) const;
bool IsSmart(bool silent = false) const;
+ void ClearTargetList(uint32 id);
void StoreTargetList(ObjectVector const& targets, uint32 id);
void AddToStoredTargetList(ObjectVector const& targets, uint32 id);
ObjectVector const* GetStoredTargetVector(uint32 id, WorldObject const& ref) const;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 3c69ddd193f..82ec392bfdb 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -1858,7 +1858,24 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
return false;
}
- TC_SAI_IS_BOOLEAN_VALID(e, e.action.summonCreature.attackInvoker);
+ if (e.action.summonCreature.createdBySpell != 0)
+ {
+ if (!IsSpellValid(e, e.action.summonCreature.createdBySpell))
+ return false;
+
+ bool propertiesFound = std::ranges::any_of(sSpellMgr->AssertSpellInfo(e.action.summonCreature.createdBySpell, DIFFICULTY_NONE)->GetEffects(),
+ [](SpellEffectInfo const& spellEffectInfo)
+ {
+ return spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON) && sSummonPropertiesStore.HasRecord(spellEffectInfo.MiscValueB);
+ });
+
+ if (!propertiesFound)
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Spell {} is not a summon creature spell.",
+ e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.summonCreature.createdBySpell);
+ return false;
+ }
+ }
break;
}
case SMART_ACTION_CALL_KILLEDMONSTER:
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 97dabdf1997..0c57aaf5415 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -465,7 +465,7 @@ enum SMART_ACTION
SMART_ACTION_ACTIVATE_GOBJECT = 9, //
SMART_ACTION_RANDOM_EMOTE = 10, // EmoteId1, EmoteId2, EmoteId3...
SMART_ACTION_CAST = 11, // SpellId, CastFlags, TriggeredFlags
- SMART_ACTION_SUMMON_CREATURE = 12, // CreatureID, summonType, duration in ms, attackInvoker, flags(SmartActionSummonCreatureFlags)
+ SMART_ACTION_SUMMON_CREATURE = 12, // CreatureID, summonType, duration in ms, stored target id, flags(SmartActionSummonCreatureFlags), count, createdBySpell
SMART_ACTION_THREAT_SINGLE_PCT = 13, // Threat%
SMART_ACTION_THREAT_ALL_PCT = 14, // Threat%
SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS = 15, // UNUSED, DO NOT REUSE
@@ -503,7 +503,7 @@ enum SMART_ACTION
SMART_ACTION_SET_VISIBILITY = 47, // on/off
SMART_ACTION_SET_ACTIVE = 48, // on/off
SMART_ACTION_ATTACK_START = 49, //
- SMART_ACTION_SUMMON_GO = 50, // GameObjectID, DespawnTime in s
+ SMART_ACTION_SUMMON_GO = 50, // GameObjectID, DespawnTime in s, summon type, stored target id
SMART_ACTION_KILL_UNIT = 51, //
SMART_ACTION_ACTIVATE_TAXI = 52, // TaxiID
SMART_ACTION_WP_START = 53, // run/walk, pathID, canRepeat, quest, despawntime
@@ -560,7 +560,7 @@ enum SMART_ACTION
SMART_ACTION_SET_GO_FLAG = 104, // UNUSED, DO NOT REUSE
SMART_ACTION_ADD_GO_FLAG = 105, // UNUSED, DO NOT REUSE
SMART_ACTION_REMOVE_GO_FLAG = 106, // UNUSED, DO NOT REUSE
- SMART_ACTION_SUMMON_CREATURE_GROUP = 107, // Group, attackInvoker
+ SMART_ACTION_SUMMON_CREATURE_GROUP = 107, // Group, attackInvoker, stored target id
SMART_ACTION_SET_POWER = 108, // PowerType, newPower
SMART_ACTION_ADD_POWER = 109, // PowerType, newPower
SMART_ACTION_REMOVE_POWER = 110, // PowerType, newPower
@@ -619,8 +619,9 @@ enum class SmartActionSummonCreatureFlags
None = 0,
PersonalSpawn = 1,
PreferUnit = 2,
+ AttackInvoker = 4,
- All = PersonalSpawn | PreferUnit,
+ All = PersonalSpawn | PreferUnit | AttackInvoker,
};
DEFINE_ENUM_FLAG(SmartActionSummonCreatureFlags);
@@ -713,9 +714,10 @@ struct SmartAction
uint32 creature;
uint32 type;
uint32 duration;
- SAIBool attackInvoker;
+ uint32 storedTargetId;
uint32 flags; // SmartActionSummonCreatureFlags
uint32 count;
+ uint32 createdBySpell;
} summonCreature;
struct
@@ -857,6 +859,7 @@ struct SmartAction
uint32 entry;
uint32 despawnTime;
uint32 summonType;
+ uint32 storedTargetId;
} summonGO;
struct
@@ -1059,6 +1062,7 @@ struct SmartAction
{
uint32 group;
uint32 attackInvoker;
+ uint32 storedTargetId;
} creatureGroup;
struct