aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/AI
diff options
context:
space:
mode:
authorariel- <ariel-@users.noreply.github.com>2017-06-19 23:20:06 -0300
committerariel- <ariel-@users.noreply.github.com>2017-06-19 23:20:06 -0300
commit85a7d5ce9ac68b30da2277cc91d4b70358f1880d (patch)
treedf3d2084ee2e35008903c03178039b9c986e2d08 /src/server/game/AI
parent052fc24315ace866ea1cf610e85df119b68100c9 (diff)
Core: ported headers cleanup from master branch
Diffstat (limited to 'src/server/game/AI')
-rw-r--r--src/server/game/AI/CoreAI/CombatAI.cpp13
-rw-r--r--src/server/game/AI/CoreAI/CombatAI.h2
-rw-r--r--src/server/game/AI/CoreAI/GameObjectAI.cpp11
-rw-r--r--src/server/game/AI/CoreAI/GameObjectAI.h14
-rw-r--r--src/server/game/AI/CoreAI/GuardAI.cpp15
-rw-r--r--src/server/game/AI/CoreAI/GuardAI.h1
-rw-r--r--src/server/game/AI/CoreAI/PetAI.cpp22
-rw-r--r--src/server/game/AI/CoreAI/ReactorAI.cpp2
-rw-r--r--src/server/game/AI/CoreAI/ReactorAI.h2
-rw-r--r--src/server/game/AI/CoreAI/TotemAI.cpp4
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.cpp102
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.h120
-rw-r--r--src/server/game/AI/CreatureAI.cpp28
-rw-r--r--src/server/game/AI/CreatureAI.h21
-rw-r--r--src/server/game/AI/CreatureAIFactory.h3
-rw-r--r--src/server/game/AI/CreatureAIImpl.h24
-rw-r--r--src/server/game/AI/CreatureAIRegistry.cpp15
-rw-r--r--src/server/game/AI/GameObjectAIFactory.h3
-rw-r--r--src/server/game/AI/PlayerAI/PlayerAI.cpp39
-rw-r--r--src/server/game/AI/PlayerAI/PlayerAI.h27
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.cpp56
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.h39
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp23
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedEscortAI.h7
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp22
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h7
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp29
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.h24
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp243
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h213
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp222
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h215
32 files changed, 874 insertions, 694 deletions
diff --git a/src/server/game/AI/CoreAI/CombatAI.cpp b/src/server/game/AI/CoreAI/CombatAI.cpp
index 86858de04dd..f7143591060 100644
--- a/src/server/game/AI/CoreAI/CombatAI.cpp
+++ b/src/server/game/AI/CoreAI/CombatAI.cpp
@@ -17,11 +17,16 @@
*/
#include "CombatAI.h"
-#include "SpellMgr.h"
-#include "SpellInfo.h"
-#include "Vehicle.h"
+#include "ConditionMgr.h"
+#include "Creature.h"
+#include "CreatureAIImpl.h"
+#include "Log.h"
+#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "Player.h"
+#include "SpellInfo.h"
+#include "SpellMgr.h"
+#include "Vehicle.h"
/////////////////
// AggressorAI
@@ -232,7 +237,7 @@ TurretAI::TurretAI(Creature* c) : CreatureAI(c)
me->m_SightDistance = me->m_CombatDistance;
}
-bool TurretAI::CanAIAttack(const Unit* /*who*/) const
+bool TurretAI::CanAIAttack(Unit const* /*who*/) const
{
/// @todo use one function to replace it
if (!me->IsWithinCombatRange(me->GetVictim(), me->m_CombatDistance)
diff --git a/src/server/game/AI/CoreAI/CombatAI.h b/src/server/game/AI/CoreAI/CombatAI.h
index 86e95e0b209..872d02b1531 100644
--- a/src/server/game/AI/CoreAI/CombatAI.h
+++ b/src/server/game/AI/CoreAI/CombatAI.h
@@ -20,8 +20,6 @@
#define TRINITY_COMBATAI_H
#include "CreatureAI.h"
-#include "CreatureAIImpl.h"
-#include "ConditionMgr.h"
class Creature;
diff --git a/src/server/game/AI/CoreAI/GameObjectAI.cpp b/src/server/game/AI/CoreAI/GameObjectAI.cpp
index 204f4c16275..4d511cdc353 100644
--- a/src/server/game/AI/CoreAI/GameObjectAI.cpp
+++ b/src/server/game/AI/CoreAI/GameObjectAI.cpp
@@ -17,5 +17,16 @@
*/
#include "GameObjectAI.h"
+#include "CreatureAI.h"
+
+int32 GameObjectAI::Permissible(GameObject const* /*go*/)
+{
+ return PERMIT_BASE_NO;
+}
NullGameObjectAI::NullGameObjectAI(GameObject* g) : GameObjectAI(g) { }
+
+int32 NullGameObjectAI::Permissible(GameObject const* /*go*/)
+{
+ return PERMIT_BASE_IDLE;
+}
diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h
index 84ead51cc91..80ab11d6792 100644
--- a/src/server/game/AI/CoreAI/GameObjectAI.h
+++ b/src/server/game/AI/CoreAI/GameObjectAI.h
@@ -20,11 +20,11 @@
#define TRINITY_GAMEOBJECTAI_H
#include "Define.h"
-#include <list>
-#include "Object.h"
#include "QuestDef.h"
-#include "GameObject.h"
-#include "CreatureAI.h"
+
+class GameObject;
+class Unit;
+class SpellInfo;
class TC_GAME_API GameObjectAI
{
@@ -45,7 +45,7 @@ class TC_GAME_API GameObjectAI
virtual void SetGUID(uint64 /*guid*/, int32 /*id = 0 */) { }
virtual uint64 GetGUID(int32 /*id = 0 */) const { return 0; }
- static int32 Permissible(GameObject const* /*go*/) { return PERMIT_BASE_NO; }
+ static int32 Permissible(GameObject const* go);
// Called when a player opens a gossip dialog with the gameobject.
virtual bool GossipHello(Player* /*player*/) { return false; }
@@ -81,7 +81,7 @@ class TC_GAME_API GameObjectAI
virtual void OnLootStateChanged(uint32 /*state*/, Unit* /*unit*/) { }
virtual void OnStateChanged(uint32 /*state*/) { }
virtual void EventInform(uint32 /*eventId*/) { }
- virtual void SpellHit(Unit* /*unit*/, const SpellInfo* /*spellInfo*/) { }
+ virtual void SpellHit(Unit* /*unit*/, SpellInfo const* /*spellInfo*/) { }
};
class TC_GAME_API NullGameObjectAI : public GameObjectAI
@@ -91,6 +91,6 @@ class TC_GAME_API NullGameObjectAI : public GameObjectAI
void UpdateAI(uint32 /*diff*/) override { }
- static int32 Permissible(GameObject const* /*go*/) { return PERMIT_BASE_IDLE; }
+ static int32 Permissible(GameObject const* go);
};
#endif
diff --git a/src/server/game/AI/CoreAI/GuardAI.cpp b/src/server/game/AI/CoreAI/GuardAI.cpp
index 1da03952dc9..f216059e492 100644
--- a/src/server/game/AI/CoreAI/GuardAI.cpp
+++ b/src/server/game/AI/CoreAI/GuardAI.cpp
@@ -17,9 +17,16 @@
*/
#include "GuardAI.h"
+#include "Creature.h"
#include "Errors.h"
+#include "Log.h"
+#include "MotionMaster.h"
#include "Player.h"
+GuardAI::GuardAI(Creature* creature) : ScriptedAI(creature)
+{
+}
+
int32 GuardAI::Permissible(Creature const* creature)
{
if (creature->IsGuard())
@@ -28,7 +35,13 @@ int32 GuardAI::Permissible(Creature const* creature)
return PERMIT_BASE_NO;
}
-GuardAI::GuardAI(Creature* creature) : ScriptedAI(creature) { }
+void GuardAI::UpdateAI(uint32 /*diff*/)
+{
+ if (!UpdateVictim())
+ return;
+
+ DoMeleeAttackIfReady();
+}
bool GuardAI::CanSeeAlways(WorldObject const* obj)
{
diff --git a/src/server/game/AI/CoreAI/GuardAI.h b/src/server/game/AI/CoreAI/GuardAI.h
index 0b0ac1f0983..77b83340c91 100644
--- a/src/server/game/AI/CoreAI/GuardAI.h
+++ b/src/server/game/AI/CoreAI/GuardAI.h
@@ -29,6 +29,7 @@ class TC_GAME_API GuardAI : public ScriptedAI
explicit GuardAI(Creature* creature);
static int32 Permissible(Creature const* creature);
+ void UpdateAI(uint32 diff) override;
bool CanSeeAlways(WorldObject const* obj) override;
void EnterEvadeMode(EvadeReason /*why*/) override;
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp
index f27f9a0adb9..1fad18a2713 100644
--- a/src/server/game/AI/CoreAI/PetAI.cpp
+++ b/src/server/game/AI/CoreAI/PetAI.cpp
@@ -17,17 +17,19 @@
*/
#include "PetAI.h"
+#include "Creature.h"
#include "Errors.h"
+#include "Group.h"
+#include "Log.h"
+#include "MotionMaster.h"
+#include "ObjectAccessor.h"
#include "Pet.h"
#include "Player.h"
#include "Spell.h"
-#include "ObjectAccessor.h"
#include "SpellHistory.h"
+#include "SpellInfo.h"
#include "SpellMgr.h"
-#include "Creature.h"
#include "Util.h"
-#include "Group.h"
-#include "SpellInfo.h"
int32 PetAI::Permissible(Creature const* creature)
{
@@ -264,7 +266,7 @@ void PetAI::UpdateAllies()
if (!owner)
return;
- Group* group = NULL;
+ Group* group = nullptr;
if (Player* player = owner->ToPlayer())
group = player->GetGroup();
@@ -280,7 +282,7 @@ void PetAI::UpdateAllies()
m_AllySet.insert(me->GetGUID());
if (group) //add group
{
- for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
+ for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
{
Player* Target = itr->GetSource();
if (!Target || !Target->IsInMap(owner) || !group->SameSubGroup(owner->ToPlayer(), Target))
@@ -389,7 +391,7 @@ Unit* PetAI::SelectNextTarget(bool allowAutoSelect) const
// Passive pets don't do next target selection
if (me->HasReactState(REACT_PASSIVE))
- return NULL;
+ return nullptr;
// Check pet attackers first so we don't drag a bunch of targets to the owner
if (Unit* myAttacker = me->getAttackerForHelper())
@@ -398,7 +400,7 @@ Unit* PetAI::SelectNextTarget(bool allowAutoSelect) const
// Not sure why we wouldn't have an owner but just in case...
if (!me->GetCharmerOrOwner())
- return NULL;
+ return nullptr;
// Check owner attackers
if (Unit* ownerAttacker = me->GetCharmerOrOwner()->getAttackerForHelper())
@@ -421,7 +423,7 @@ Unit* PetAI::SelectNextTarget(bool allowAutoSelect) const
}
// Default - no valid targets
- return NULL;
+ return nullptr;
}
void PetAI::HandleReturnMovement()
@@ -568,7 +570,7 @@ bool PetAI::CanAttack(Unit* target)
if (me->GetVictim() && me->GetVictim() != target)
{
// Check if our owner selected this target and clicked "attack"
- Unit* ownerTarget = NULL;
+ Unit* ownerTarget = nullptr;
if (Player* owner = me->GetCharmerOrOwner()->ToPlayer())
ownerTarget = owner->GetSelectedUnit();
else
diff --git a/src/server/game/AI/CoreAI/ReactorAI.cpp b/src/server/game/AI/CoreAI/ReactorAI.cpp
index 8ad251776b6..0f2e7437104 100644
--- a/src/server/game/AI/CoreAI/ReactorAI.cpp
+++ b/src/server/game/AI/CoreAI/ReactorAI.cpp
@@ -16,8 +16,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "ByteBuffer.h"
#include "ReactorAI.h"
+#include "Creature.h"
int32 ReactorAI::Permissible(Creature const* creature)
{
diff --git a/src/server/game/AI/CoreAI/ReactorAI.h b/src/server/game/AI/CoreAI/ReactorAI.h
index 412849a955b..db1f60fc263 100644
--- a/src/server/game/AI/CoreAI/ReactorAI.h
+++ b/src/server/game/AI/CoreAI/ReactorAI.h
@@ -21,8 +21,6 @@
#include "CreatureAI.h"
-class Unit;
-
class TC_GAME_API ReactorAI : public CreatureAI
{
public:
diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp
index a44c4532e60..da484e20983 100644
--- a/src/server/game/AI/CoreAI/TotemAI.cpp
+++ b/src/server/game/AI/CoreAI/TotemAI.cpp
@@ -64,14 +64,14 @@ void TotemAI::UpdateAI(uint32 /*diff*/)
// SPELLMOD_RANGE not applied in this place just because not existence range mods for attacking totems
// pointer to appropriate target if found any
- Unit* victim = i_victimGuid ? ObjectAccessor::GetUnit(*me, i_victimGuid) : NULL;
+ Unit* victim = i_victimGuid ? ObjectAccessor::GetUnit(*me, i_victimGuid) : nullptr;
// Search victim if no, not attackable, or out of range, or friendly (possible in case duel end)
if (!victim ||
!victim->isTargetableForAttack() || !me->IsWithinDistInMap(victim, max_range) ||
me->IsFriendlyTo(victim) || !me->CanSeeOrDetect(victim))
{
- victim = NULL;
+ victim = nullptr;
Trinity::NearestAttackableUnitInObjectRangeCheck u_check(me, me, max_range);
Trinity::UnitLastSearcher<Trinity::NearestAttackableUnitInObjectRangeCheck> checker(me, victim, u_check);
Cell::VisitAllObjects(me, checker, max_range);
diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp
index 055abc99d96..9f13f7901bc 100644
--- a/src/server/game/AI/CoreAI/UnitAI.cpp
+++ b/src/server/game/AI/CoreAI/UnitAI.cpp
@@ -17,14 +17,15 @@
*/
#include "UnitAI.h"
-#include "Player.h"
#include "Creature.h"
-#include "SpellAuras.h"
+#include "CreatureAIImpl.h"
+#include "MotionMaster.h"
+#include "Player.h"
+#include "Spell.h"
#include "SpellAuraEffects.h"
-#include "SpellMgr.h"
+#include "SpellAuras.h"
#include "SpellInfo.h"
-#include "Spell.h"
-#include "CreatureAIImpl.h"
+#include "SpellMgr.h"
void UnitAI::AttackStart(Unit* victim)
{
@@ -40,6 +41,12 @@ void UnitAI::AttackStart(Unit* victim)
}
}
+void UnitAI::InitializeAI()
+{
+ if (!me->isDead())
+ Reset();
+}
+
void UnitAI::AttackStartCaster(Unit* victim, float dist)
{
if (victim && me->Attack(victim, false))
@@ -112,37 +119,9 @@ float UnitAI::DoGetSpellMaxRange(uint32 spellId, bool positive)
return spellInfo ? spellInfo->GetMaxRange(positive) : 0;
}
-void UnitAI::DoAddAuraToAllHostilePlayers(uint32 spellid)
-{
- if (me->IsInCombat())
- {
- ThreatContainer::StorageType threatlist = me->getThreatManager().getThreatList();
- for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
- {
- if (Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
- if (unit->GetTypeId() == TYPEID_PLAYER)
- me->AddAura(spellid, unit);
- }
- }
-}
-
-void UnitAI::DoCastToAllHostilePlayers(uint32 spellid, bool triggered)
-{
- if (me->IsInCombat())
- {
- ThreatContainer::StorageType threatlist = me->getThreatManager().getThreatList();
- for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
- {
- if (Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
- if (unit->GetTypeId() == TYPEID_PLAYER)
- me->CastSpell(unit, spellid, triggered);
- }
- }
-}
-
void UnitAI::DoCast(uint32 spellId)
{
- Unit* target = NULL;
+ Unit* target = nullptr;
switch (AISpellInfo[spellId].target)
{
@@ -211,7 +190,12 @@ void UnitAI::DoCastAOE(uint32 spellId, bool triggered)
if (!triggered && me->HasUnitState(UNIT_STATE_CASTING))
return;
- me->CastSpell((Unit*)NULL, spellId, triggered);
+ me->CastSpell((Unit*)nullptr, spellId, triggered);
+}
+
+uint32 UnitAI::GetDialogStatus(Player* /*player*/)
+{
+ return DIALOG_STATUS_SCRIPTED_NO_STATUS;
}
#define UPDATE_TARGET(a) {if (AIInfo->target<a) AIInfo->target=a;}
@@ -221,11 +205,9 @@ void UnitAI::FillAISpellInfo()
AISpellInfo = new AISpellInfoType[sSpellMgr->GetSpellInfoStoreSize()];
AISpellInfoType* AIInfo = AISpellInfo;
- const SpellInfo* spellInfo;
-
for (uint32 i = 0; i < sSpellMgr->GetSpellInfoStoreSize(); ++i, ++AIInfo)
{
- spellInfo = sSpellMgr->GetSpellInfo(i);
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(i);
if (!spellInfo)
continue;
@@ -267,6 +249,45 @@ void UnitAI::FillAISpellInfo()
}
}
+ThreatManager& UnitAI::GetThreatManager()
+{
+ return me->getThreatManager();
+}
+
+bool DefaultTargetSelector::operator()(Unit const* target) const
+{
+ if (!me)
+ return false;
+
+ if (!target)
+ return false;
+
+ if (m_playerOnly && (target->GetTypeId() != TYPEID_PLAYER))
+ return false;
+
+ if (m_dist > 0.0f && !me->IsWithinCombatRange(target, m_dist))
+ return false;
+
+ if (m_dist < 0.0f && me->IsWithinCombatRange(target, -m_dist))
+ return false;
+
+ if (m_aura)
+ {
+ if (m_aura > 0)
+ {
+ if (!target->HasAura(m_aura))
+ return false;
+ }
+ else
+ {
+ if (target->HasAura(-m_aura))
+ return false;
+ }
+ }
+
+ return true;
+}
+
SpellTargetSelector::SpellTargetSelector(Unit* caster, uint32 spellId) :
_caster(caster), _spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(sSpellMgr->GetSpellInfo(spellId), caster))
{
@@ -384,3 +405,8 @@ bool FarthestTargetSelector::operator()(Unit const* target) const
return true;
}
+
+void SortByDistanceTo(Unit* reference, std::list<Unit*>& targets)
+{
+ targets.sort(Trinity::ObjectDistanceOrderPred(reference));
+}
diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h
index 0e0d2200280..d164b9fe6d5 100644
--- a/src/server/game/AI/CoreAI/UnitAI.h
+++ b/src/server/game/AI/CoreAI/UnitAI.h
@@ -19,16 +19,29 @@
#ifndef TRINITY_UNITAI_H
#define TRINITY_UNITAI_H
-#include "Define.h"
-#include "Unit.h"
#include "Containers.h"
#include "EventMap.h"
-#include "QuestDef.h"
-#include <list>
+#include "ObjectGuid.h"
+#include "ThreatManager.h"
+
+#define CAST_AI(a, b) (dynamic_cast<a*>(b))
+#define ENSURE_AI(a,b) (EnsureAI<a>(b))
+
+template<class T, class U>
+T* EnsureAI(U* ai)
+{
+ T* cast_ai = dynamic_cast<T*>(ai);
+ ASSERT(cast_ai);
+ return cast_ai;
+};
class Player;
class Quest;
+class SpellInfo;
+class Unit;
struct AISpellInfoType;
+enum DamageEffectType : uint8;
+enum SpellEffIndex : uint8;
//Selection method used by SelectTarget
enum SelectAggroTarget
@@ -41,9 +54,9 @@ enum SelectAggroTarget
};
// default predicate function to select target based on distance, player and/or aura criteria
-struct TC_GAME_API DefaultTargetSelector : public std::unary_function<Unit*, bool>
+struct TC_GAME_API DefaultTargetSelector
{
- const Unit* me;
+ Unit const* me;
float m_dist;
bool m_playerOnly;
int32 m_aura;
@@ -54,44 +67,12 @@ struct TC_GAME_API DefaultTargetSelector : public std::unary_function<Unit*, boo
// aura: if 0: ignored, if > 0: the target shall have the aura, if < 0, the target shall NOT have the aura
DefaultTargetSelector(Unit const* unit, float dist, bool playerOnly, int32 aura) : me(unit), m_dist(dist), m_playerOnly(playerOnly), m_aura(aura) { }
- bool operator()(Unit const* target) const
- {
- if (!me)
- return false;
-
- if (!target)
- return false;
-
- if (m_playerOnly && (target->GetTypeId() != TYPEID_PLAYER))
- return false;
-
- if (m_dist > 0.0f && !me->IsWithinCombatRange(target, m_dist))
- return false;
-
- if (m_dist < 0.0f && me->IsWithinCombatRange(target, -m_dist))
- return false;
-
- if (m_aura)
- {
- if (m_aura > 0)
- {
- if (!target->HasAura(m_aura))
- return false;
- }
- else
- {
- if (target->HasAura(-m_aura))
- return false;
- }
- }
-
- return true;
- }
+ bool operator()(Unit const* target) const;
};
// Target selector for spell casts checking range, auras and attributes
/// @todo Add more checks from Spell::CheckCast
-struct TC_GAME_API SpellTargetSelector : public std::unary_function<Unit*, bool>
+struct TC_GAME_API SpellTargetSelector
{
public:
SpellTargetSelector(Unit* caster, uint32 spellId);
@@ -105,7 +86,7 @@ struct TC_GAME_API SpellTargetSelector : public std::unary_function<Unit*, bool>
// Very simple target selector, will just skip main target
// NOTE: When passing to UnitAI::SelectTarget remember to use 0 as position for random selection
// because tank will not be in the temporary list
-struct TC_GAME_API NonTankTargetSelector : public std::unary_function<Unit*, bool>
+struct TC_GAME_API NonTankTargetSelector
{
public:
NonTankTargetSelector(Unit* source, bool playerOnly = true) : _source(source), _playerOnly(playerOnly) { }
@@ -137,12 +118,14 @@ struct TC_GAME_API FarthestTargetSelector
bool operator()(Unit const* target) const;
private:
- const Unit* _me;
+ Unit const* _me;
float _dist;
bool _playerOnly;
bool _inLos;
};
+TC_GAME_API void SortByDistanceTo(Unit* reference, std::list<Unit*>& targets);
+
class TC_GAME_API UnitAI
{
protected:
@@ -155,7 +138,7 @@ class TC_GAME_API UnitAI
virtual void AttackStart(Unit* /*target*/);
virtual void UpdateAI(uint32 diff) = 0;
- virtual void InitializeAI() { if (!me->isDead()) Reset(); }
+ virtual void InitializeAI();
virtual void Reset() { }
@@ -172,15 +155,16 @@ class TC_GAME_API UnitAI
Unit* SelectTarget(SelectAggroTarget targetType, uint32 position = 0, float dist = 0.0f, bool playerOnly = false, int32 aura = 0);
// Select the targets satisfying the predicate.
// predicate shall extend std::unary_function<Unit*, bool>
- template<class PREDICATE> Unit* SelectTarget(SelectAggroTarget targetType, uint32 position, PREDICATE const& predicate)
+ template<class PREDICATE>
+ Unit* SelectTarget(SelectAggroTarget targetType, uint32 position, PREDICATE const& predicate)
{
- ThreatContainer::StorageType const& threatlist = me->getThreatManager().getThreatList();
+ ThreatContainer::StorageType const& threatlist = GetThreatManager().getThreatList();
if (position >= threatlist.size())
return nullptr;
std::list<Unit*> targetList;
Unit* currentVictim = nullptr;
- if (auto currentVictimReference = me->getThreatManager().getCurrentVictim())
+ if (auto currentVictimReference = GetThreatManager().getCurrentVictim())
{
currentVictim = currentVictimReference->getTarget();
@@ -189,42 +173,38 @@ class TC_GAME_API UnitAI
targetList.push_back(currentVictim);
}
- for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
+ for (HostileReference* hostileRef : threatlist)
{
- if (currentVictim != nullptr && (*itr)->getTarget() != currentVictim && predicate((*itr)->getTarget()))
- targetList.push_back((*itr)->getTarget());
- else if (currentVictim == nullptr && predicate((*itr)->getTarget()))
- targetList.push_back((*itr)->getTarget());
+ if (currentVictim != nullptr && hostileRef->getTarget() != currentVictim && predicate(hostileRef->getTarget()))
+ targetList.push_back(hostileRef->getTarget());
+ else if (currentVictim == nullptr && predicate(hostileRef->getTarget()))
+ targetList.push_back(hostileRef->getTarget());
}
if (position >= targetList.size())
return nullptr;
if (targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
- targetList.sort(Trinity::ObjectDistanceOrderPred(me));
+ SortByDistanceTo(me, targetList);
switch (targetType)
{
case SELECT_TARGET_NEAREST:
case SELECT_TARGET_TOPAGGRO:
{
- std::list<Unit*>::iterator itr = targetList.begin();
+ auto itr = targetList.begin();
std::advance(itr, position);
return *itr;
}
case SELECT_TARGET_FARTHEST:
case SELECT_TARGET_BOTTOMAGGRO:
{
- std::list<Unit*>::reverse_iterator ritr = targetList.rbegin();
+ auto ritr = targetList.rbegin();
std::advance(ritr, position);
return *ritr;
}
case SELECT_TARGET_RANDOM:
- {
- std::list<Unit*>::iterator itr = targetList.begin();
- std::advance(itr, urand(position, targetList.size() - 1));
- return *itr;
- }
+ return Trinity::Containers::SelectRandomContainerElement(targetList);
default:
break;
}
@@ -236,21 +216,22 @@ class TC_GAME_API UnitAI
// Select the targets satifying the predicate.
// predicate shall extend std::unary_function<Unit*, bool>
- template <class PREDICATE> void SelectTargetList(std::list<Unit*>& targetList, PREDICATE const& predicate, uint32 maxTargets, SelectAggroTarget targetType)
+ template <class PREDICATE>
+ void SelectTargetList(std::list<Unit*>& targetList, PREDICATE const& predicate, uint32 maxTargets, SelectAggroTarget targetType)
{
- ThreatContainer::StorageType const& threatlist = me->getThreatManager().getThreatList();
+ ThreatContainer::StorageType const& threatlist = GetThreatManager().getThreatList();
if (threatlist.empty())
return;
- for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
- if (predicate((*itr)->getTarget()))
- targetList.push_back((*itr)->getTarget());
+ for (HostileReference* hostileRef : threatlist)
+ if (predicate(hostileRef->getTarget()))
+ targetList.push_back(hostileRef->getTarget());
if (targetList.size() < maxTargets)
return;
if (targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
- targetList.sort(Trinity::ObjectDistanceOrderPred(me));
+ SortByDistanceTo(me, targetList);
if (targetType == SELECT_TARGET_FARTHEST || targetType == SELECT_TARGET_BOTTOMAGGRO)
targetList.reverse();
@@ -280,11 +261,9 @@ class TC_GAME_API UnitAI
void AttackStartCaster(Unit* victim, float dist);
- void DoAddAuraToAllHostilePlayers(uint32 spellid);
void DoCast(uint32 spellId);
void DoCast(Unit* victim, uint32 spellId, bool triggered = false);
void DoCastSelf(uint32 spellId, bool triggered = false) { DoCast(me, spellId, triggered); }
- void DoCastToAllHostilePlayers(uint32 spellid, bool triggered = false);
void DoCastVictim(uint32 spellId, bool triggered = false);
void DoCastAOE(uint32 spellId, bool triggered = false);
@@ -305,7 +284,7 @@ class TC_GAME_API UnitAI
virtual bool GossipSelect(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/) { return false; }
// Called when a player selects a gossip with a code in the creature's gossip menu.
- virtual bool GossipSelectCode(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/, const char* /*code*/) { return false; }
+ virtual bool GossipSelectCode(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/, char const* /*code*/) { return false; }
// Called when a player accepts a quest from the creature.
virtual void QuestAccept(Player* /*player*/, Quest const* /*quest*/) { }
@@ -317,12 +296,13 @@ class TC_GAME_API UnitAI
virtual void OnGameEvent(bool /*start*/, uint16 /*eventId*/) { }
// Called when the dialog status between a player and the creature is requested.
- virtual uint32 GetDialogStatus(Player* /*player*/) { return DIALOG_STATUS_SCRIPTED_NO_STATUS; }
-
+ virtual uint32 GetDialogStatus(Player* /*player*/);
private:
UnitAI(UnitAI const& right) = delete;
UnitAI& operator=(UnitAI const& right) = delete;
+
+ ThreatManager& GetThreatManager();
};
#endif
diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp
index 281795c0ed1..7ecee7cc14c 100644
--- a/src/server/game/AI/CreatureAI.cpp
+++ b/src/server/game/AI/CreatureAI.cpp
@@ -17,16 +17,20 @@
*/
#include "CreatureAI.h"
-#include "CreatureAIImpl.h"
+#include "AreaBoundary.h"
#include "Creature.h"
-#include "World.h"
-#include "SpellMgr.h"
-#include "Vehicle.h"
+#include "CreatureAIImpl.h"
+#include "CreatureTextMgr.h"
+#include "Language.h"
#include "Log.h"
+#include "Map.h"
#include "MapReference.h"
+#include "MotionMaster.h"
#include "Player.h"
-#include "CreatureTextMgr.h"
-#include "Language.h"
+#include "SpellMgr.h"
+#include "TemporarySummon.h"
+#include "Vehicle.h"
+#include "World.h"
//Disable CreatureAI when charmed
void CreatureAI::OnCharmed(bool apply)
@@ -39,7 +43,15 @@ void CreatureAI::OnCharmed(bool apply)
}
AISpellInfoType* UnitAI::AISpellInfo;
-AISpellInfoType* GetAISpellInfo(uint32 i) { return &CreatureAI::AISpellInfo[i]; }
+AISpellInfoType* GetAISpellInfo(uint32 i) { return &UnitAI::AISpellInfo[i]; }
+
+CreatureAI::CreatureAI(Creature* creature) : UnitAI(creature), me(creature), _boundary(nullptr), _negateBoundary(false), m_MoveInLineOfSight_locked(false)
+{
+}
+
+CreatureAI::~CreatureAI()
+{
+}
void CreatureAI::Talk(uint8 id, WorldObject const* whisperTarget /*= nullptr*/)
{
@@ -391,7 +403,7 @@ void CreatureAI::SetBoundary(CreatureBoundary const* boundary, bool negateBounda
me->DoImmediateBoundaryCheck();
}
-Creature* CreatureAI::DoSummon(uint32 entry, const Position& pos, uint32 despawnTime, TempSummonType summonType)
+Creature* CreatureAI::DoSummon(uint32 entry, Position const& pos, uint32 despawnTime, TempSummonType summonType)
{
return me->SummonCreature(entry, pos, summonType, despawnTime);
}
diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h
index 79bcefb3946..a787082bf9d 100644
--- a/src/server/game/AI/CreatureAI.h
+++ b/src/server/game/AI/CreatureAI.h
@@ -19,17 +19,19 @@
#ifndef TRINITY_CREATUREAI_H
#define TRINITY_CREATUREAI_H
-#include "Creature.h"
#include "UnitAI.h"
-#include "AreaBoundary.h"
#include "Common.h"
+#include "ObjectDefines.h"
-class WorldObject;
-class Unit;
+class AreaBoundary;
class Creature;
-class Player;
+class DynamicObject;
+class GameObject;
class PlayerAI;
-class SpellInfo;
+class WorldObject;
+struct Position;
+
+typedef std::vector<AreaBoundary const*> CreatureBoundary;
#define TIME_INTERVAL_LOOK 5000
#define VISIBILITY_RANGE 10000
@@ -65,7 +67,6 @@ enum SCEquip
EQUIP_UNEQUIP = 0
};
-typedef std::vector<AreaBoundary const*> CreatureBoundary;
class TC_GAME_API CreatureAI : public UnitAI
{
protected:
@@ -92,11 +93,11 @@ class TC_GAME_API CreatureAI : public UnitAI
EVADE_REASON_OTHER
};
- void Talk(uint8 id, WorldObject const* whisperTarget = nullptr);
+ explicit CreatureAI(Creature* creature);
- explicit CreatureAI(Creature* creature) : UnitAI(creature), me(creature), _boundary(nullptr), _negateBoundary(false), m_MoveInLineOfSight_locked(false) { }
+ virtual ~CreatureAI();
- virtual ~CreatureAI() { }
+ void Talk(uint8 id, WorldObject const* whisperTarget = nullptr);
/// == Reactions At =================================
diff --git a/src/server/game/AI/CreatureAIFactory.h b/src/server/game/AI/CreatureAIFactory.h
index 6681ba8bc89..feb73ce11de 100644
--- a/src/server/game/AI/CreatureAIFactory.h
+++ b/src/server/game/AI/CreatureAIFactory.h
@@ -22,6 +22,9 @@
#include "ObjectRegistry.h"
#include "FactoryHolder.h"
+class Creature;
+class CreatureAI;
+
typedef FactoryHolder<CreatureAI, Creature> CreatureAICreator;
struct SelectableAI : public CreatureAICreator, public Permissible<Creature>
diff --git a/src/server/game/AI/CreatureAIImpl.h b/src/server/game/AI/CreatureAIImpl.h
index e0346eac10a..b2036d815bd 100644
--- a/src/server/game/AI/CreatureAIImpl.h
+++ b/src/server/game/AI/CreatureAIImpl.h
@@ -17,17 +17,13 @@
#ifndef CREATUREAIIMPL_H
#define CREATUREAIIMPL_H
-#include "Common.h"
-#include "Define.h"
-#include "TemporarySummon.h"
-#include "CreatureAI.h"
-#include "SpellMgr.h"
-
-#include <functional>
+#include "Random.h"
#include <type_traits>
+class WorldObject;
+
template<typename First, typename Second, typename... Rest>
-static inline First const& RAND(First const& first, Second const& second, Rest const&... rest)
+inline First const& RAND(First const& first, Second const& second, Rest const&... rest)
{
std::reference_wrapper<typename std::add_const<First>::type> const pack[] = { first, second, rest... };
return pack[urand(0, sizeof...(rest) + 1)].get();
@@ -65,5 +61,15 @@ struct AISpellInfoType
AISpellInfoType* GetAISpellInfo(uint32 i);
-#endif
+TC_GAME_API bool InstanceHasScript(WorldObject const* obj, char const* scriptName);
+
+template <class AI, class T>
+AI* GetInstanceAI(T* obj, char const* scriptName)
+{
+ if (InstanceHasScript(obj, scriptName))
+ return new AI(obj);
+
+ return nullptr;
+}
+#endif
diff --git a/src/server/game/AI/CreatureAIRegistry.cpp b/src/server/game/AI/CreatureAIRegistry.cpp
index 25dcd98c5db..a89c410a93b 100644
--- a/src/server/game/AI/CreatureAIRegistry.cpp
+++ b/src/server/game/AI/CreatureAIRegistry.cpp
@@ -16,19 +16,20 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "PassiveAI.h"
-#include "ReactorAI.h"
+#include "CreatureAIFactory.h"
+#include "GameObjectAIFactory.h"
+
#include "CombatAI.h"
#include "GuardAI.h"
+#include "PassiveAI.h"
#include "PetAI.h"
+#include "ReactorAI.h"
+#include "SmartAI.h"
#include "TotemAI.h"
-#include "RandomMovementGenerator.h"
+
#include "MovementGenerator.h"
-#include "CreatureAIRegistry.h"
+#include "RandomMovementGenerator.h"
#include "WaypointMovementGenerator.h"
-#include "CreatureAIFactory.h"
-#include "GameObjectAIFactory.h"
-#include "SmartAI.h"
namespace AIRegistry
{
diff --git a/src/server/game/AI/GameObjectAIFactory.h b/src/server/game/AI/GameObjectAIFactory.h
index 2ff799ab7ea..a52f4279223 100644
--- a/src/server/game/AI/GameObjectAIFactory.h
+++ b/src/server/game/AI/GameObjectAIFactory.h
@@ -21,6 +21,9 @@
#include "ObjectRegistry.h"
#include "FactoryHolder.h"
+class GameObject;
+class GameObjectAI;
+
typedef FactoryHolder<GameObjectAI, GameObject> GameObjectAICreator;
struct SelectableGameObjectAI : public GameObjectAICreator, public Permissible<GameObject>
diff --git a/src/server/game/AI/PlayerAI/PlayerAI.cpp b/src/server/game/AI/PlayerAI/PlayerAI.cpp
index 0edd6097026..589b7162c3f 100644
--- a/src/server/game/AI/PlayerAI/PlayerAI.cpp
+++ b/src/server/game/AI/PlayerAI/PlayerAI.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2017 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -16,8 +16,16 @@
*/
#include "PlayerAI.h"
+#include "Creature.h"
+#include "Item.h"
+#include "MotionMaster.h"
+#include "ObjectAccessor.h"
+#include "Player.h"
+#include "Spell.h"
#include "SpellAuras.h"
#include "SpellAuraEffects.h"
+#include "SpellHistory.h"
+#include "SpellMgr.h"
static const uint8 NUM_TALENT_TREES = 3;
static const uint8 NUM_SPEC_ICONICS = 3;
@@ -496,6 +504,20 @@ static const uint32 SPEC_ICONICS[MAX_CLASSES][NUM_TALENT_TREES][NUM_SPEC_ICONICS
}
};
+PlayerAI::PlayerAI(Player* player) : UnitAI(player), me(player),
+ _selfSpec(PlayerAI::GetPlayerSpec(player)),
+ _isSelfHealer(PlayerAI::IsPlayerHealer(player)),
+ _isSelfRangedAttacker(PlayerAI::IsPlayerRangedAttacker(player))
+{
+}
+
+Creature* PlayerAI::GetCharmer() const
+{
+ if (me->GetCharmerGUID().IsCreature())
+ return ObjectAccessor::GetCreature(*me, me->GetCharmerGUID());
+ return nullptr;
+}
+
uint8 PlayerAI::GetPlayerSpec(Player const* who)
{
if (!who)
@@ -664,6 +686,13 @@ PlayerAI::TargetedSpell PlayerAI::SelectSpellCast(PossibleSpellVector& spells)
return selected;
}
+void PlayerAI::DoCastAtTarget(TargetedSpell spell)
+{
+ SpellCastTargets targets;
+ targets.SetUnitTarget(spell.second);
+ spell.first->prepare(&targets);
+}
+
void PlayerAI::DoRangedAttackIfReady()
{
if (me->HasUnitState(UNIT_STATE_CASTING))
@@ -735,13 +764,19 @@ void PlayerAI::CancelAllShapeshifts()
me->RemoveOwnedAura(aura, AURA_REMOVE_BY_CANCEL);
}
-struct UncontrolledTargetSelectPredicate : public std::unary_function<Unit*, bool>
+Unit* PlayerAI::SelectAttackTarget() const
+{
+ return me->GetCharmer() ? me->GetCharmer()->GetVictim() : nullptr;
+}
+
+struct UncontrolledTargetSelectPredicate
{
bool operator()(Unit const* target) const
{
return !target->HasBreakableByDamageCrowdControlAura();
}
};
+
Unit* SimpleCharmedPlayerAI::SelectAttackTarget() const
{
if (Unit* charmer = me->GetCharmer())
diff --git a/src/server/game/AI/PlayerAI/PlayerAI.h b/src/server/game/AI/PlayerAI/PlayerAI.h
index fce24b2dc0e..8afc5ab3ce9 100644
--- a/src/server/game/AI/PlayerAI/PlayerAI.h
+++ b/src/server/game/AI/PlayerAI/PlayerAI.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2017 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -19,24 +19,18 @@
#define TRINITY_PLAYERAI_H
#include "UnitAI.h"
-#include "Player.h"
-#include "Spell.h"
-#include "Creature.h"
+
+class Spell;
class TC_GAME_API PlayerAI : public UnitAI
{
public:
- explicit PlayerAI(Player* player) : UnitAI(static_cast<Unit*>(player)), me(player), _selfSpec(PlayerAI::GetPlayerSpec(player)), _isSelfHealer(PlayerAI::IsPlayerHealer(player)), _isSelfRangedAttacker(PlayerAI::IsPlayerRangedAttacker(player)) { }
+ explicit PlayerAI(Player* player);
void OnCharmed(bool /*apply*/) override { } // charm AI application for players is handled by Unit::SetCharmedBy / Unit::RemoveCharmedBy
- Creature* GetCharmer() const
- {
- if (ObjectGuid charmerGUID = me->GetCharmerGUID())
- if (charmerGUID.IsCreature())
- return ObjectAccessor::GetCreature(*me, charmerGUID);
- return nullptr;
- }
+ Creature* GetCharmer() const;
+
// helper functions to determine player info
// Return values range from 0 (left-most spec) to 2 (right-most spec). If two specs have the same number of talent points, the left-most of those specs is returned.
static uint8 GetPlayerSpec(Player const* who);
@@ -85,14 +79,9 @@ class TC_GAME_API PlayerAI : public UnitAI
This invalidates the vector, and empties it to prevent accidental misuse. */
TargetedSpell SelectSpellCast(PossibleSpellVector& spells);
/* Helper method - casts the included spell at the included target */
- inline void DoCastAtTarget(TargetedSpell spell)
- {
- SpellCastTargets targets;
- targets.SetUnitTarget(spell.second);
- spell.first->prepare(&targets);
- }
+ void DoCastAtTarget(TargetedSpell spell);
- virtual Unit* SelectAttackTarget() const { return me->GetCharmer() ? me->GetCharmer()->GetVictim() : nullptr; }
+ virtual Unit* SelectAttackTarget() const;
void DoRangedAttackIfReady();
void DoAutoAttackIfReady();
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
index 5464b99f8c9..d32ac53cb9f 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
@@ -17,13 +17,19 @@
*/
#include "ScriptedCreature.h"
-#include "Spell.h"
-#include "GridNotifiers.h"
-#include "GridNotifiersImpl.h"
+#include "AreaBoundary.h"
#include "Cell.h"
#include "CellImpl.h"
-#include "ObjectMgr.h"
-#include "AreaBoundary.h"
+#include "DBCStores.h"
+#include "GridNotifiers.h"
+#include "GridNotifiersImpl.h"
+#include "InstanceScript.h"
+#include "Log.h"
+#include "MotionMaster.h"
+#include "ObjectAccessor.h"
+#include "Spell.h"
+#include "SpellMgr.h"
+#include "TemporarySummon.h"
// Spell summary for ScriptedAI::SelectSpell
struct TSpellSummary
@@ -32,6 +38,16 @@ struct TSpellSummary
uint8 Effects; // set of enum SelectEffect
} extern* SpellSummary;
+void SummonList::Summon(Creature const* summon)
+{
+ storage_.push_back(summon->GetGUID());
+}
+
+void SummonList::Despawn(Creature const* summon)
+{
+ storage_.remove(summon->GetGUID());
+}
+
void SummonList::DoZoneInCombat(uint32 entry, float maxRangeToNearestTarget)
{
for (StorageType::iterator i = storage_.begin(); i != storage_.end();)
@@ -97,6 +113,16 @@ bool SummonList::HasEntry(uint32 entry) const
return false;
}
+void SummonList::DoActionImpl(int32 action, StorageType const& summons)
+{
+ for (auto const& guid : summons)
+ {
+ Creature* summon = ObjectAccessor::GetCreature(*me, guid);
+ if (summon && summon->IsAIEnabled)
+ summon->AI()->DoAction(action);
+ }
+}
+
ScriptedAI::ScriptedAI(Creature* creature) : CreatureAI(creature),
IsFleeing(false),
_isCombatMovementAllowed(true)
@@ -179,6 +205,16 @@ Creature* ScriptedAI::DoSpawnCreature(uint32 entry, float offsetX, float offsetY
return me->SummonCreature(entry, me->GetPositionX() + offsetX, me->GetPositionY() + offsetY, me->GetPositionZ() + offsetZ, angle, TempSummonType(type), despawntime);
}
+bool ScriptedAI::HealthBelowPct(uint32 pct) const
+{
+ return me->HealthBelowPct(pct);
+}
+
+bool ScriptedAI::HealthAbovePct(uint32 pct) const
+{
+ return me->HealthAbovePct(pct);
+}
+
SpellInfo const* ScriptedAI::SelectSpell(Unit* target, uint32 school, uint32 mechanic, SelectTargetType targets, uint32 powerCostMin, uint32 powerCostMax, float rangeMin, float rangeMax, SelectEffect effects)
{
//No target so we can't cast
@@ -444,6 +480,11 @@ void BossAI::_JustDied()
instance->SetBossState(_bossId, DONE);
}
+void BossAI::_JustReachedHome()
+{
+ me->setActive(false);
+}
+
void BossAI::_EnterCombat()
{
if (instance)
@@ -507,6 +548,11 @@ void BossAI::UpdateAI(uint32 diff)
DoMeleeAttackIfReady();
}
+bool BossAI::CanAIAttack(Unit const* target) const
+{
+ return CheckBoundary(target);
+}
+
void BossAI::_DespawnAtEvade(uint32 delayToRespawn /*= 30*/, Creature* who /*= nullptr*/)
{
if (delayToRespawn < 2)
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
index b4db664a980..3b24203a146 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
@@ -19,23 +19,11 @@
#ifndef SCRIPTEDCREATURE_H_
#define SCRIPTEDCREATURE_H_
-#include "Creature.h"
#include "CreatureAI.h"
-#include "CreatureAIImpl.h"
-#include "InstanceScript.h"
+#include "Creature.h" // convenience include for scripts, all uses of ScriptedCreature also need Creature (except ScriptedCreature itself doesn't need Creature)
+#include "DBCEnums.h"
#include "TaskScheduler.h"
-#define CAST_AI(a, b) (dynamic_cast<a*>(b))
-#define ENSURE_AI(a,b) (EnsureAI<a>(b))
-
-template<class T, class U>
-T* EnsureAI(U* ai)
-{
- T* cast_ai = dynamic_cast<T*>(ai);
- ASSERT(cast_ai);
- return cast_ai;
-};
-
class InstanceScript;
class TC_GAME_API SummonList
@@ -95,13 +83,13 @@ public:
storage_.clear();
}
- void Summon(Creature const* summon) { storage_.push_back(summon->GetGUID()); }
- void Despawn(Creature const* summon) { storage_.remove(summon->GetGUID()); }
+ void Summon(Creature const* summon);
+ void Despawn(Creature const* summon);
void DespawnEntry(uint32 entry);
void DespawnAll();
template <typename T>
- void DespawnIf(T const &predicate)
+ void DespawnIf(T const& predicate)
{
storage_.remove_if(predicate);
}
@@ -112,12 +100,7 @@ public:
// We need to use a copy of SummonList here, otherwise original SummonList would be modified
StorageType listCopy = storage_;
Trinity::Containers::RandomResize<StorageType, Predicate>(listCopy, std::forward<Predicate>(predicate), max);
- for (StorageType::iterator i = listCopy.begin(); i != listCopy.end(); )
- {
- Creature* summon = ObjectAccessor::GetCreature(*me, *i++);
- if (summon && summon->IsAIEnabled)
- summon->AI()->DoAction(info);
- }
+ DoActionImpl(info, listCopy);
}
void DoZoneInCombat(uint32 entry = 0, float maxRangeToNearestTarget = 250.0f);
@@ -125,6 +108,8 @@ public:
bool HasEntry(uint32 entry) const;
private:
+ void DoActionImpl(int32 action, StorageType const& summons);
+
Creature* me;
StorageType storage_;
};
@@ -256,8 +241,8 @@ struct TC_GAME_API ScriptedAI : public CreatureAI
//Spawns a creature relative to me
Creature* DoSpawnCreature(uint32 entry, float offsetX, float offsetY, float offsetZ, float angle, uint32 type, uint32 despawntime);
- bool HealthBelowPct(uint32 pct) const { return me->HealthBelowPct(pct); }
- bool HealthAbovePct(uint32 pct) const { return me->HealthAbovePct(pct); }
+ bool HealthBelowPct(uint32 pct) const;
+ bool HealthAbovePct(uint32 pct) const;
//Returns spells that meet the specified criteria from the creatures spell list
SpellInfo const* SelectSpell(Unit* target, uint32 school, uint32 mechanic, SelectTargetType targets, uint32 powerCostMin, uint32 powerCostMax, float rangeMin, float rangeMax, SelectEffect effect);
@@ -369,13 +354,13 @@ class TC_GAME_API BossAI : public ScriptedAI
void JustDied(Unit* /*killer*/) override { _JustDied(); }
void JustReachedHome() override { _JustReachedHome(); }
- bool CanAIAttack(Unit const* target) const override { return CheckBoundary(target); }
+ bool CanAIAttack(Unit const* target) const override;
protected:
void _Reset();
void _EnterCombat();
void _JustDied();
- void _JustReachedHome() { me->setActive(false); }
+ void _JustReachedHome();
void _DespawnAtEvade(uint32 delayToRespawn = 30, Creature* who = nullptr);
void _DespawnAtEvade(Seconds const& time, Creature* who = nullptr) { _DespawnAtEvade(uint32(time.count()), who); }
diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
index 085ef9c4047..6f5b7f1aa71 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
@@ -23,10 +23,14 @@ SDComment:
SDCategory: Npc
EndScriptData */
-#include "Player.h"
-#include "ScriptedCreature.h"
#include "ScriptedEscortAI.h"
+#include "Creature.h"
#include "Group.h"
+#include "Log.h"
+#include "Map.h"
+#include "MotionMaster.h"
+#include "ObjectAccessor.h"
+#include "Player.h"
enum Points
{
@@ -39,7 +43,7 @@ npc_escortAI::npc_escortAI(Creature* creature) : ScriptedAI(creature),
m_uiPlayerCheckTimer(1000),
m_uiEscortState(STATE_ESCORT_NONE),
MaxPlayerDistance(DEFAULT_MAX_PLAYER_DISTANCE),
- m_pQuestForEscort(NULL),
+ m_pQuestForEscort(nullptr),
m_bIsActiveAttacker(true),
m_bIsRunning(false),
m_bCanInstantRespawn(false),
@@ -65,6 +69,11 @@ void npc_escortAI::AttackStart(Unit* who)
}
}
+Player* npc_escortAI::GetPlayerForEscort()
+{
+ return ObjectAccessor::GetPlayer(*me, m_uiPlayerGUID);
+}
+
//see followerAI
bool npc_escortAI::AssistPlayerInCombatAgainst(Unit* who)
{
@@ -148,7 +157,7 @@ void npc_escortAI::JustDied(Unit* /*killer*/)
{
if (Group* group = player->GetGroup())
{
- for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
+ for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
if (Player* member = groupRef->GetSource())
if (member->IsInMap(player))
member->FailQuest(m_pQuestForEscort->GetQuestId());
@@ -186,7 +195,7 @@ void npc_escortAI::EnterEvadeMode(EvadeReason /*why*/)
me->RemoveAllAuras();
me->DeleteThreatList();
me->CombatStop(true);
- me->SetLootRecipient(NULL);
+ me->SetLootRecipient(nullptr);
if (HasEscortState(STATE_ESCORT_ESCORTING))
{
@@ -209,7 +218,7 @@ bool npc_escortAI::IsPlayerOrGroupInRange()
{
if (Group* group = player->GetGroup())
{
- for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
+ for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
if (Player* member = groupRef->GetSource())
if (me->IsWithinDistInMap(member, GetMaxPlayerDistance()))
return true;
@@ -431,7 +440,7 @@ void npc_escortAI::SetRun(bool on)
}
/// @todo get rid of this many variables passed in function.
-void npc_escortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false */, ObjectGuid playerGUID /* = 0 */, Quest const* quest /* = NULL */, bool instantRespawn /* = false */, bool canLoopPath /* = false */, bool resetWaypoints /* = true */)
+void npc_escortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false */, ObjectGuid playerGUID /* = 0 */, Quest const* quest /* = nullptr */, bool instantRespawn /* = false */, bool canLoopPath /* = false */, bool resetWaypoints /* = true */)
{
if (me->GetVictim())
{
diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h
index e1bf3af5343..754d96dced9 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h
@@ -19,8 +19,11 @@
#ifndef SC_ESCORTAI_H
#define SC_ESCORTAI_H
+#include "ScriptedCreature.h"
#include "ScriptSystem.h"
+class Quest;
+
#define DEFAULT_MAX_PLAYER_DISTANCE 50
struct Escort_Waypoint
@@ -88,7 +91,7 @@ struct TC_GAME_API npc_escortAI : public ScriptedAI
virtual void WaypointReached(uint32 pointId) = 0;
virtual void WaypointStart(uint32 /*pointId*/) { }
- void Start(bool isActiveAttacker = true, bool run = false, ObjectGuid playerGUID = ObjectGuid::Empty, Quest const* quest = NULL, bool instantRespawn = false, bool canLoopPath = false, bool resetWaypoints = true);
+ void Start(bool isActiveAttacker = true, bool run = false, ObjectGuid playerGUID = ObjectGuid::Empty, Quest const* quest = nullptr, bool instantRespawn = false, bool canLoopPath = false, bool resetWaypoints = true);
void SetRun(bool on = true);
void SetEscortPaused(bool on);
@@ -106,7 +109,7 @@ struct TC_GAME_API npc_escortAI : public ScriptedAI
ObjectGuid GetEventStarterGUID() const { return m_uiPlayerGUID; }
protected:
- Player* GetPlayerForEscort() { return ObjectAccessor::GetPlayer(*me, m_uiPlayerGUID); }
+ Player* GetPlayerForEscort();
private:
bool AssistPlayerInCombatAgainst(Unit* who);
diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
index 79c3c17d610..d18876fc439 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
@@ -23,10 +23,14 @@ SDComment: This AI is under development
SDCategory: Npc
EndScriptData */
-#include "Player.h"
-#include "ScriptedCreature.h"
#include "ScriptedFollowerAI.h"
+#include "Creature.h"
#include "Group.h"
+#include "Log.h"
+#include "Map.h"
+#include "MotionMaster.h"
+#include "ObjectAccessor.h"
+#include "Player.h"
const float MAX_PLAYER_DISTANCE = 100.0f;
@@ -38,7 +42,7 @@ enum Points
FollowerAI::FollowerAI(Creature* creature) : ScriptedAI(creature),
m_uiUpdateFollowTimer(2500),
m_uiFollowState(STATE_FOLLOW_NONE),
- m_pQuestForFollow(NULL)
+ m_pQuestForFollow(nullptr)
{ }
void FollowerAI::AttackStart(Unit* who)
@@ -146,7 +150,7 @@ void FollowerAI::JustDied(Unit* /*killer*/)
{
if (Group* group = player->GetGroup())
{
- for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
+ for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
if (Player* member = groupRef->GetSource())
if (member->IsInMap(player))
member->FailQuest(m_pQuestForFollow->GetQuestId());
@@ -174,7 +178,7 @@ void FollowerAI::EnterEvadeMode(EvadeReason /*why*/)
me->RemoveAllAuras();
me->DeleteThreatList();
me->CombatStop(true);
- me->SetLootRecipient(NULL);
+ me->SetLootRecipient(nullptr);
if (HasFollowState(STATE_FOLLOW_INPROGRESS))
{
@@ -224,7 +228,7 @@ void FollowerAI::UpdateAI(uint32 uiDiff)
if (Group* group = player->GetGroup())
{
- for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
+ for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
{
Player* member = groupRef->GetSource();
if (member && me->IsWithinDistInMap(member, MAX_PLAYER_DISTANCE))
@@ -282,7 +286,7 @@ void FollowerAI::MovementInform(uint32 motionType, uint32 pointId)
}
}
-void FollowerAI::StartFollow(Player* player, uint32 factionForFollower, const Quest* quest)
+void FollowerAI::StartFollow(Player* player, uint32 factionForFollower, Quest const* quest)
{
if (me->GetVictim())
{
@@ -330,7 +334,7 @@ Player* FollowerAI::GetLeaderForFollower()
{
if (Group* group = player->GetGroup())
{
- for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
+ for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
{
Player* member = groupRef->GetSource();
if (member && me->IsWithinDistInMap(member, MAX_PLAYER_DISTANCE) && member->IsAlive())
@@ -345,7 +349,7 @@ Player* FollowerAI::GetLeaderForFollower()
}
TC_LOG_DEBUG("scripts", "FollowerAI GetLeader can not find suitable leader.");
- return NULL;
+ return nullptr;
}
void FollowerAI::SetFollowComplete(bool bWithEndEvent)
diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h
index 6b5b06490f0..7fe877a7589 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h
@@ -19,8 +19,11 @@
#ifndef SC_FOLLOWERAI_H
#define SC_FOLLOWERAI_H
+#include "ScriptedCreature.h"
#include "ScriptSystem.h"
+class Quest;
+
enum eFollowState
{
STATE_FOLLOW_NONE = 0x000,
@@ -55,7 +58,7 @@ class TC_GAME_API FollowerAI : public ScriptedAI
void UpdateAI(uint32) override; //the "internal" update, calls UpdateFollowerAI()
virtual void UpdateFollowerAI(uint32); //used when it's needed to add code in update (abilities, scripted events, etc)
- void StartFollow(Player* player, uint32 factionForFollower = 0, const Quest* quest = NULL);
+ void StartFollow(Player* player, uint32 factionForFollower = 0, Quest const* quest = nullptr);
void SetFollowPaused(bool bPaused); //if special event require follow mode to hold/resume during the follow
void SetFollowComplete(bool bWithEndEvent = false);
@@ -75,7 +78,7 @@ class TC_GAME_API FollowerAI : public ScriptedAI
uint32 m_uiUpdateFollowTimer;
uint32 m_uiFollowState;
- const Quest* m_pQuestForFollow; //normally we have a quest
+ Quest const* m_pQuestForFollow; //normally we have a quest
};
#endif
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index df5fe1d6b7b..682f92f1ee6 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -15,15 +15,16 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "DatabaseEnv.h"
-#include "ObjectMgr.h"
-#include "ObjectDefines.h"
-#include "GridDefines.h"
-#include "GridNotifiers.h"
-#include "SpellMgr.h"
-#include "Cell.h"
-#include "Group.h"
#include "SmartAI.h"
+#include "Creature.h"
+#include "DBCStructure.h"
+#include "GameObject.h"
+#include "Group.h"
+#include "Log.h"
+#include "MotionMaster.h"
+#include "ObjectAccessor.h"
+#include "PetDefines.h"
+#include "Player.h"
#include "ScriptMgr.h"
#include "Vehicle.h"
@@ -530,7 +531,7 @@ void SmartAI::MoveInLineOfSight(Unit* who)
CreatureAI::MoveInLineOfSight(who);
}
-bool SmartAI::CanAIAttack(const Unit* /*who*/) const
+bool SmartAI::CanAIAttack(Unit const* /*who*/) const
{
return !(me->HasReactState(REACT_PASSIVE));
}
@@ -663,12 +664,12 @@ void SmartAI::AttackStart(Unit* who)
}
}
-void SmartAI::SpellHit(Unit* unit, const SpellInfo* spellInfo)
+void SmartAI::SpellHit(Unit* unit, SpellInfo const* spellInfo)
{
GetScript()->ProcessEventsFor(SMART_EVENT_SPELLHIT, unit, 0, 0, false, spellInfo);
}
-void SmartAI::SpellHitTarget(Unit* target, const SpellInfo* spellInfo)
+void SmartAI::SpellHitTarget(Unit* target, SpellInfo const* spellInfo)
{
GetScript()->ProcessEventsFor(SMART_EVENT_SPELLHIT_TARGET, target, 0, 0, false, spellInfo);
}
@@ -816,7 +817,7 @@ bool SmartAI::GossipSelect(Player* player, uint32 menuId, uint32 gossipListId)
return _gossipReturn;
}
-bool SmartAI::GossipSelectCode(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/, const char* /*code*/)
+bool SmartAI::GossipSelectCode(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/, char const* /*code*/)
{
return false;
}
@@ -1005,7 +1006,7 @@ bool SmartGameObjectAI::GossipSelect(Player* player, uint32 sender, uint32 actio
}
// Called when a player selects a gossip with a code in the gameobject's gossip menu.
-bool SmartGameObjectAI::GossipSelectCode(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/, const char* /*code*/)
+bool SmartGameObjectAI::GossipSelectCode(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/, char const* /*code*/)
{
return false;
}
@@ -1055,7 +1056,7 @@ void SmartGameObjectAI::EventInform(uint32 eventId)
GetScript()->ProcessEventsFor(SMART_EVENT_GO_EVENT_INFORM, nullptr, eventId);
}
-void SmartGameObjectAI::SpellHit(Unit* unit, const SpellInfo* spellInfo)
+void SmartGameObjectAI::SpellHit(Unit* unit, SpellInfo const* spellInfo)
{
GetScript()->ProcessEventsFor(SMART_EVENT_SPELLHIT, unit, 0, 0, false, spellInfo);
}
diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h
index e295f1bc7c4..b5ed74c4edb 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.h
+++ b/src/server/game/AI/SmartScripts/SmartAI.h
@@ -18,15 +18,13 @@
#ifndef TRINITY_SMARTAI_H
#define TRINITY_SMARTAI_H
-#include "Common.h"
-#include "Creature.h"
+#include "Define.h"
#include "CreatureAI.h"
-#include "Unit.h"
-#include "Spell.h"
-
-#include "SmartScript.h"
-#include "SmartScriptMgr.h"
#include "GameObjectAI.h"
+#include "Position.h"
+#include "SmartScript.h"
+
+struct WayPoint;
enum SmartEscortState
{
@@ -100,10 +98,10 @@ class TC_GAME_API SmartAI : public CreatureAI
void MoveInLineOfSight(Unit* who) override;
// Called when hit by a spell
- void SpellHit(Unit* unit, const SpellInfo* spellInfo) override;
+ void SpellHit(Unit* unit, SpellInfo const* spellInfo) override;
// Called when spell hits a target
- void SpellHitTarget(Unit* target, const SpellInfo* spellInfo) override;
+ void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override;
// Called at any Damage from any attacker (before damage apply)
void DamageTaken(Unit* doneBy, uint32& damage) override;
@@ -142,7 +140,7 @@ class TC_GAME_API SmartAI : public CreatureAI
void OnCharmed(bool apply) override;
// Called when victim is in line of sight
- bool CanAIAttack(const Unit* who) const override;
+ bool CanAIAttack(Unit const* who) const override;
// Used in scripts to share variables
void DoAction(int32 param = 0) override;
@@ -180,7 +178,7 @@ class TC_GAME_API SmartAI : public CreatureAI
bool GossipHello(Player* player) override;
bool GossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override;
- bool GossipSelectCode(Player* player, uint32 menuId, uint32 gossipListId, const char* code) override;
+ bool GossipSelectCode(Player* player, uint32 menuId, uint32 gossipListId, char const* code) override;
void QuestAccept(Player* player, Quest const* quest) override;
void QuestReward(Player* player, Quest const* quest, uint32 opt) override;
void OnGameEvent(bool start, uint16 eventId) override;
@@ -262,7 +260,7 @@ class TC_GAME_API SmartGameObjectAI : public GameObjectAI
bool GossipHello(Player* player) override;
bool OnReportUse(Player* player) override;
bool GossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override;
- bool GossipSelectCode(Player* player, uint32 menuId, uint32 gossipListId, const char* code) override;
+ bool GossipSelectCode(Player* player, uint32 menuId, uint32 gossipListId, char const* code) override;
void QuestAccept(Player* player, Quest const* quest) override;
void QuestReward(Player* player, Quest const* quest, uint32 opt) override;
void Destroyed(Player* player, uint32 eventId) override;
@@ -271,7 +269,7 @@ class TC_GAME_API SmartGameObjectAI : public GameObjectAI
void OnGameEvent(bool start, uint16 eventId) override;
void OnLootStateChanged(uint32 state, Unit* unit) override;
void EventInform(uint32 eventId) override;
- void SpellHit(Unit* unit, const SpellInfo* spellInfo) override;
+ void SpellHit(Unit* unit, SpellInfo const* spellInfo) override;
void SetGossipReturn(bool val) { _gossipReturn = val; }
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 6dc0bd62256..fe86978b0db 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -15,27 +15,31 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "Cell.h"
+#include "SmartScript.h"
#include "CellImpl.h"
#include "ChatTextBuilder.h"
+#include "Creature.h"
#include "CreatureTextMgr.h"
-#include "DatabaseEnv.h"
+#include "CreatureTextMgrImpl.h"
+#include "GameEventMgr.h"
+#include "GameObject.h"
#include "GossipDef.h"
-#include "GridDefines.h"
-#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "Group.h"
#include "InstanceScript.h"
#include "Language.h"
-#include "ObjectDefines.h"
+#include "Log.h"
+#include "Map.h"
+#include "MotionMaster.h"
+#include "ObjectAccessor.h"
#include "ObjectMgr.h"
-#include "ScriptedCreature.h"
-#include "ScriptedGossip.h"
+#include "Random.h"
#include "SmartAI.h"
-#include "SmartScript.h"
+#include "SpellAuras.h"
#include "SpellMgr.h"
+#include "TemporarySummon.h"
#include "Vehicle.h"
-#include "GameEventMgr.h"
+#include <G3D/Quat.h>
SmartScript::SmartScript()
{
@@ -57,6 +61,97 @@ SmartScript::~SmartScript()
{
}
+bool SmartScript::IsSmart(Creature* c /*= nullptr*/)
+{
+ bool smart = true;
+ if (c && c->GetAIName() != "SmartAI")
+ smart = false;
+
+ if (!me || me->GetAIName() != "SmartAI")
+ smart = false;
+
+ if (!smart)
+ TC_LOG_ERROR("sql.sql", "SmartScript: Action target Creature (GUID: %u Entry: %u) is not using SmartAI, action called by Creature (GUID: %u Entry: %u) skipped to prevent crash.", c ? c->GetSpawnId() : 0, c ? c->GetEntry() : 0, me ? me->GetSpawnId() : 0, me ? me->GetEntry() : 0);
+
+ return smart;
+}
+
+bool SmartScript::IsSmartGO(GameObject* g /*= nullptr*/)
+{
+ bool smart = true;
+ if (g && g->GetAIName() != "SmartGameObjectAI")
+ smart = false;
+
+ if (!go || go->GetAIName() != "SmartGameObjectAI")
+ smart = false;
+ if (!smart)
+ TC_LOG_ERROR("sql.sql", "SmartScript: Action target GameObject (GUID: %u Entry: %u) is not using SmartGameObjectAI, action called by GameObject (GUID: %u Entry: %u) skipped to prevent crash.", g ? g->GetSpawnId() : 0, g ? g->GetEntry() : 0, go ? go->GetSpawnId() : 0, go ? go->GetEntry() : 0);
+
+ return smart;
+}
+
+void SmartScript::StoreTargetList(ObjectVector const& targets, uint32 id)
+{
+ // insert or replace
+ _storedTargets.erase(id);
+ _storedTargets.emplace(id, ObjectGuidVector(targets));
+}
+
+ObjectVector const* SmartScript::GetStoredTargetVector(uint32 id, WorldObject const& ref) const
+{
+ auto itr = _storedTargets.find(id);
+ if (itr != _storedTargets.end())
+ return itr->second.GetObjectVector(ref);
+ return nullptr;
+}
+
+void SmartScript::StoreCounter(uint32 id, uint32 value, uint32 reset)
+{
+ CounterMap::iterator itr = mCounterList.find(id);
+ if (itr != mCounterList.end())
+ {
+ if (reset == 0)
+ itr->second += value;
+ else
+ itr->second = value;
+ }
+ else
+ mCounterList.insert(std::make_pair(id, value));
+
+ ProcessEventsFor(SMART_EVENT_COUNTER_SET, nullptr, id);
+}
+
+uint32 SmartScript::GetCounterValue(uint32 id) const
+{
+ CounterMap::const_iterator itr = mCounterList.find(id);
+ if (itr != mCounterList.end())
+ return itr->second;
+ return 0;
+}
+
+GameObject* SmartScript::FindGameObjectNear(WorldObject* searchObject, ObjectGuid::LowType guid) const
+{
+ auto bounds = searchObject->GetMap()->GetGameObjectBySpawnIdStore().equal_range(guid);
+ if (bounds.first == bounds.second)
+ return nullptr;
+
+ return bounds.first->second;
+}
+
+Creature* SmartScript::FindCreatureNear(WorldObject* searchObject, ObjectGuid::LowType guid) const
+{
+ auto bounds = searchObject->GetMap()->GetCreatureBySpawnIdStore().equal_range(guid);
+ if (bounds.first == bounds.second)
+ return nullptr;
+
+ auto creatureItr = std::find_if(bounds.first, bounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair)
+ {
+ return pair.second->IsAlive();
+ });
+
+ return creatureItr != bounds.second ? creatureItr->second : bounds.first->second;
+}
+
void SmartScript::OnReset()
{
ResetBaseObject();
@@ -73,7 +168,37 @@ void SmartScript::OnReset()
mCounterList.clear();
}
-void SmartScript::ProcessEventsFor(SMART_EVENT e, Unit* unit, uint32 var0, uint32 var1, bool bvar, const SpellInfo* spell, GameObject* gob)
+void SmartScript::ResetBaseObject()
+{
+ WorldObject* lookupRoot = me;
+ if (!lookupRoot)
+ lookupRoot = go;
+
+ if (lookupRoot)
+ {
+ if (!meOrigGUID.IsEmpty())
+ {
+ if (Creature* m = ObjectAccessor::GetCreature(*lookupRoot, meOrigGUID))
+ {
+ me = m;
+ go = nullptr;
+ }
+ }
+
+ if (!goOrigGUID.IsEmpty())
+ {
+ if (GameObject* o = ObjectAccessor::GetGameObject(*lookupRoot, goOrigGUID))
+ {
+ me = nullptr;
+ go = o;
+ }
+ }
+ }
+ goOrigGUID.Clear();
+ meOrigGUID.Clear();
+}
+
+void SmartScript::ProcessEventsFor(SMART_EVENT e, Unit* unit, uint32 var0, uint32 var1, bool bvar, SpellInfo const* spell, GameObject* gob)
{
for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i)
{
@@ -87,7 +212,7 @@ void SmartScript::ProcessEventsFor(SMART_EVENT e, Unit* unit, uint32 var0, uint3
}
}
-void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, uint32 var1, bool bvar, const SpellInfo* spell, GameObject* gob)
+void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, uint32 var1, bool bvar, SpellInfo const* spell, GameObject* gob)
{
// calc random
if (e.GetEventType() != SMART_EVENT_LINK && e.event.event_chance < 100 && e.event.event_chance)
@@ -314,7 +439,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_RANDOM_EMOTE:
{
std::vector<uint32> emotes;
- std::copy_if(e.action.randomEmote.emotes.begin(), e.action.randomEmote.emotes.end(),
+ std::copy_if(std::begin(e.action.randomEmote.emotes), std::end(e.action.randomEmote.emotes),
std::back_inserter(emotes), [](uint32 emote) { return emote != 0; });
for (WorldObject* target : targets)
@@ -736,7 +861,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
break;
std::vector<uint32> phases;
- std::copy_if(e.action.randomPhase.phases.begin(), e.action.randomPhase.phases.end(),
+ std::copy_if(std::begin(e.action.randomPhase.phases), std::end(e.action.randomPhase.phases),
std::back_inserter(phases), [](uint32 phase) { return phase != 0; });
uint32 phase = Trinity::Containers::SelectRandomContainerElement(phases);
@@ -1064,14 +1189,14 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
for (WorldObject* target : targets)
{
Position pos = target->GetPositionWithOffset(Position(e.target.x, e.target.y, e.target.z, e.target.o));
- G3D::Quat rot = G3D::Matrix3::fromEulerAnglesZYX(pos.GetOrientation(), 0.f, 0.f);
+ QuaternionData rot = QuaternionData::fromEulerAnglesZYX(pos.GetOrientation(), 0.f, 0.f);
GetBaseObject()->SummonGameObject(e.action.summonGO.entry, pos, rot, e.action.summonGO.despawnTime);
}
if (e.GetTargetType() != SMART_TARGET_POSITION)
break;
- G3D::Quat rot = G3D::Matrix3::fromEulerAnglesZYX(e.target.o, 0.f, 0.f);
+ QuaternionData rot = QuaternionData::fromEulerAnglesZYX(e.target.o, 0.f, 0.f);
GetBaseObject()->SummonGameObject(e.action.summonGO.entry, Position(e.target.x, e.target.y, e.target.z, e.target.o), rot, e.action.summonGO.despawnTime);
break;
}
@@ -1350,7 +1475,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
std::copy(std::begin(eInfo->ItemEntry), std::end(eInfo->ItemEntry), std::begin(slot));
}
else
- std::copy(std::begin(e.action.equip.slots), std::end(e.action.equip.slots), std::begin(slot));
+ {
+ slot[0] = e.action.equip.slot1;
+ slot[1] = e.action.equip.slot2;
+ slot[2] = e.action.equip.slot3;
+ }
for (uint32 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i)
if (!e.action.equip.mask || (e.action.equip.mask & (1 << i)))
@@ -1498,7 +1627,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
break;
ObjectVector casters;
- GetTargets(casters, CreateEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, 0, 0, SMART_ACTION_NONE, 0, 0, 0, 0, 0, 0, (SMARTAI_TARGETS)e.action.crossCast.targetType, e.action.crossCast.targetParam1, e.action.crossCast.targetParam2, e.action.crossCast.targetParam3, 0), unit);
+ GetTargets(casters, CreateSmartEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, 0, 0, SMART_ACTION_NONE, 0, 0, 0, 0, 0, 0, (SMARTAI_TARGETS)e.action.crossCast.targetType, e.action.crossCast.targetParam1, e.action.crossCast.targetParam2, e.action.crossCast.targetParam3, 0), unit);
for (WorldObject* caster : casters)
{
@@ -1533,7 +1662,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST:
{
std::vector<uint32> actionLists;
- std::copy_if(e.action.randTimedActionList.actionLists.begin(), e.action.randTimedActionList.actionLists.end(),
+ std::copy_if(std::begin(e.action.randTimedActionList.actionLists), std::end(e.action.randTimedActionList.actionLists),
std::back_inserter(actionLists), [](uint32 actionList) { return actionList != 0; });
uint32 id = Trinity::Containers::SelectRandomContainerElement(actionLists);
@@ -1738,9 +1867,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (e.action.sendGossipMenu.gossipMenuId)
player->PrepareGossipMenu(GetBaseObject(), e.action.sendGossipMenu.gossipMenuId, true);
else
- ClearGossipMenuFor(player);
+ player->PlayerTalkClass->ClearMenus();
- SendGossipMenuFor(player, e.action.sendGossipMenu.gossipNpcTextId, GetBaseObject()->GetGUID());
+ player->PlayerTalkClass->SendGossipMenu(e.action.sendGossipMenu.gossipNpcTextId, GetBaseObject()->GetGUID());
}
}
break;
@@ -1861,7 +1990,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_START_CLOSEST_WAYPOINT:
{
std::vector<uint32> waypoints;
- std::copy_if(e.action.closestWaypointFromList.wps.begin(), e.action.closestWaypointFromList.wps.end(),
+ std::copy_if(std::begin(e.action.closestWaypointFromList.wps), std::end(e.action.closestWaypointFromList.wps),
std::back_inserter(waypoints), [](uint32 wp) { return wp != 0; });
float distanceToClosest = std::numeric_limits<float>::max();
@@ -1904,7 +2033,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_RANDOM_SOUND:
{
std::vector<uint32> sounds;
- std::copy_if(e.action.randomSound.sounds.begin(), e.action.randomSound.sounds.end(),
+ std::copy_if(std::begin(e.action.randomSound.sounds), std::end(e.action.randomSound.sounds),
std::back_inserter(sounds), [](uint32 sound) { return sound != 0; });
bool onlySelf = e.action.randomSound.onlySelf != 0;
@@ -1975,7 +2104,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
case SMART_ACTION_TRIGGER_RANDOM_TIMED_EVENT:
{
uint32 eventId = urand(e.action.randomTimedEvent.minId, e.action.randomTimedEvent.maxId);
- ProcessEventsFor((SMART_EVENT)SMART_EVENT_TIMED_EVENT_TRIGGERED, NULL, eventId);
+ ProcessEventsFor((SMART_EVENT)SMART_EVENT_TIMED_EVENT_TRIGGERED, nullptr, eventId);
break;
}
@@ -2015,7 +2144,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
}
-void SmartScript::ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit, uint32 var0, uint32 var1, bool bvar, const SpellInfo* spell, GameObject* gob)
+void SmartScript::ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit, uint32 var0, uint32 var1, bool bvar, SpellInfo const* spell, GameObject* gob)
{
// We may want to execute action rarely and because of this if condition is not fulfilled the action will be rechecked in a long time
if (sConditionMgr->IsObjectMeetingSmartEventConditions(e.entryOrGuid, e.event_id, e.source_type, unit, GetBaseObject()))
@@ -2105,10 +2234,10 @@ void SmartScript::InstallTemplate(SmartScriptHolder const& e)
void SmartScript::AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 phaseMask)
{
- mInstallEvents.push_back(CreateEvent(e, event_flags, event_param1, event_param2, event_param3, event_param4, action, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, t, target_param1, target_param2, target_param3, phaseMask));
+ mInstallEvents.push_back(CreateSmartEvent(e, event_flags, event_param1, event_param2, event_param3, event_param4, action, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, t, target_param1, target_param2, target_param3, phaseMask));
}
-SmartScriptHolder SmartScript::CreateEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 phaseMask)
+SmartScriptHolder SmartScript::CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 phaseMask)
{
SmartScriptHolder script;
script.event.type = e;
@@ -2373,13 +2502,13 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
}
case SMART_TARGET_CLOSEST_CREATURE:
{
- if (Creature* target = GetClosestCreatureWithEntry(baseObject, e.target.closest.entry, float(e.target.closest.dist ? e.target.closest.dist : 100), !e.target.closest.dead))
+ if (Creature* target = baseObject->FindNearestCreature(e.target.closest.entry, float(e.target.closest.dist ? e.target.closest.dist : 100), !e.target.closest.dead))
targets.push_back(target);
break;
}
case SMART_TARGET_CLOSEST_GAMEOBJECT:
{
- if (GameObject* target = GetClosestGameObjectWithEntry(baseObject, e.target.closest.entry, float(e.target.closest.dist ? e.target.closest.dist : 100)))
+ if (GameObject* target = baseObject->FindNearestGameObject(e.target.closest.entry, float(e.target.closest.dist ? e.target.closest.dist : 100)))
targets.push_back(target);
break;
}
@@ -2496,7 +2625,7 @@ void SmartScript::GetWorldObjectsInDist(ObjectVector& targets, float dist) const
Cell::VisitAllObjects(obj, searcher, dist);
}
-void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, uint32 var1, bool bvar, const SpellInfo* spell, GameObject* gob)
+void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, uint32 var1, bool bvar, SpellInfo const* spell, GameObject* gob)
{
if (!e.active && e.GetEventType() != SMART_EVENT_LINK)
return;
@@ -3182,6 +3311,62 @@ void SmartScript::InstallEvents()
}
}
+void SmartScript::RemoveStoredEvent(uint32 id)
+{
+ if (!mStoredEvents.empty())
+ {
+ for (auto i = mStoredEvents.begin(); i != mStoredEvents.end(); ++i)
+ {
+ if (i->event_id == id)
+ {
+ mStoredEvents.erase(i);
+ return;
+ }
+ }
+ }
+}
+
+WorldObject* SmartScript::GetBaseObject() const
+{
+ WorldObject* obj = nullptr;
+ if (me)
+ obj = me;
+ else if (go)
+ obj = go;
+ return obj;
+}
+
+bool SmartScript::IsUnit(WorldObject* obj)
+{
+ return obj && (obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_PLAYER);
+}
+
+bool SmartScript::IsPlayer(WorldObject* obj)
+{
+ return obj && obj->GetTypeId() == TYPEID_PLAYER;
+}
+
+bool SmartScript::IsCreature(WorldObject* obj)
+{
+ return obj && obj->GetTypeId() == TYPEID_UNIT;
+}
+
+bool SmartScript::IsCharmedCreature(WorldObject* obj)
+{
+ if (!obj)
+ return false;
+
+ if (Creature* creatureObj = obj->ToCreature())
+ return creatureObj->IsCharmed();
+
+ return false;
+}
+
+bool SmartScript::IsGameObject(WorldObject* obj)
+{
+ return obj && obj->GetTypeId() == TYPEID_GAMEOBJECT;
+}
+
void SmartScript::OnUpdate(uint32 const diff)
{
if ((mScriptType == SMART_SCRIPT_TYPE_CREATURE || mScriptType == SMART_SCRIPT_TYPE_GAMEOBJECT) && !GetBaseObject())
diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h
index cf10f7d15f4..b0269bc45c2 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.h
+++ b/src/server/game/AI/SmartScripts/SmartScript.h
@@ -18,15 +18,16 @@
#ifndef TRINITY_SMARTSCRIPT_H
#define TRINITY_SMARTSCRIPT_H
-#include "Common.h"
-#include "Creature.h"
-#include "CreatureAI.h"
-#include "Unit.h"
-#include "Spell.h"
-#include "GridNotifiers.h"
-
+#include "Define.h"
#include "SmartScriptMgr.h"
-//#include "SmartAI.h"
+
+class Creature;
+class GameObject;
+class Player;
+class SpellInfo;
+class Unit;
+class WorldObject;
+struct AreaTriggerEntry;
class TC_GAME_API SmartScript
{
@@ -38,61 +39,27 @@ class TC_GAME_API SmartScript
void GetScript();
void FillScript(SmartAIEventList e, WorldObject* obj, AreaTriggerEntry const* at);
- void ProcessEventsFor(SMART_EVENT e, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellInfo* spell = nullptr, GameObject* gob = nullptr);
- void ProcessEvent(SmartScriptHolder& e, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellInfo* spell = nullptr, GameObject* gob = nullptr);
+ void ProcessEventsFor(SMART_EVENT e, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, SpellInfo const* spell = nullptr, GameObject* gob = nullptr);
+ void ProcessEvent(SmartScriptHolder& e, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, SpellInfo const* spell = nullptr, GameObject* gob = nullptr);
bool CheckTimer(SmartScriptHolder const& e) const;
static void RecalcTimer(SmartScriptHolder& e, uint32 min, uint32 max);
void UpdateTimer(SmartScriptHolder& e, uint32 const diff);
static void InitTimer(SmartScriptHolder& e);
- void ProcessAction(SmartScriptHolder& e, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellInfo* spell = nullptr, GameObject* gob = nullptr);
- void ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellInfo* spell = nullptr, GameObject* gob = nullptr);
+ void ProcessAction(SmartScriptHolder& e, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, SpellInfo const* spell = nullptr, GameObject* gob = nullptr);
+ void ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, SpellInfo const* spell = nullptr, GameObject* gob = nullptr);
void GetTargets(ObjectVector& targets, SmartScriptHolder const& e, Unit* invoker = nullptr) const;
void GetWorldObjectsInDist(ObjectVector& objects, float dist) const;
void InstallTemplate(SmartScriptHolder const& e);
- static SmartScriptHolder CreateEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 phaseMask = 0);
+ static SmartScriptHolder CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 phaseMask = 0);
void AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 phaseMask = 0);
void SetPathId(uint32 id) { mPathId = id; }
uint32 GetPathId() const { return mPathId; }
- WorldObject* GetBaseObject() const
- {
- WorldObject* obj = nullptr;
- if (me)
- obj = me;
- else if (go)
- obj = go;
- return obj;
- }
-
- static bool IsUnit(WorldObject* obj)
- {
- return obj && (obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_PLAYER);
- }
-
- static bool IsPlayer(WorldObject* obj)
- {
- return obj && obj->GetTypeId() == TYPEID_PLAYER;
- }
-
- static bool IsCreature(WorldObject* obj)
- {
- return obj && obj->GetTypeId() == TYPEID_UNIT;
- }
-
- static bool IsCharmedCreature(WorldObject* obj)
- {
- if (!obj)
- return false;
-
- if (Creature* creatureObj = obj->ToCreature())
- return creatureObj->IsCharmed();
-
- return false;
- }
-
- static bool IsGameObject(WorldObject* obj)
- {
- return obj && obj->GetTypeId() == TYPEID_GAMEOBJECT;
- }
+ WorldObject* GetBaseObject() const;
+ static bool IsUnit(WorldObject* obj);
+ static bool IsPlayer(WorldObject* obj);
+ static bool IsCreature(WorldObject* obj);
+ static bool IsCharmedCreature(WorldObject* obj);
+ static bool IsGameObject(WorldObject* obj);
void OnUpdate(const uint32 diff);
void OnMoveInLineOfSight(Unit* who);
@@ -102,127 +69,20 @@ class TC_GAME_API SmartScript
void DoFindFriendlyMissingBuff(std::vector<Creature*>& creatures, float range, uint32 spellid) const;
Unit* DoFindClosestFriendlyInRange(float range, bool playerOnly) const;
- void StoreTargetList(ObjectVector const& targets, uint32 id)
- {
- // insert or replace
- _storedTargets.erase(id);
- _storedTargets.emplace(id, ObjectGuidVector(targets));
- }
-
- bool IsSmart(Creature* c = nullptr)
- {
- bool smart = true;
- if (c && c->GetAIName() != "SmartAI")
- smart = false;
-
- if (!me || me->GetAIName() != "SmartAI")
- smart = false;
-
- if (!smart)
- TC_LOG_ERROR("sql.sql", "SmartScript: Action target Creature (GUID: %u Entry: %u) is not using SmartAI, action called by Creature (GUID: %u Entry: %u) skipped to prevent crash.", c ? c->GetSpawnId() : 0, c ? c->GetEntry() : 0, me ? me->GetSpawnId() : 0, me ? me->GetEntry() : 0);
+ bool IsSmart(Creature* c = nullptr);
+ bool IsSmartGO(GameObject* g = nullptr);
- return smart;
- }
+ void StoreTargetList(ObjectVector const& targets, uint32 id);
+ ObjectVector const* GetStoredTargetVector(uint32 id, WorldObject const& ref) const;
- bool IsSmartGO(GameObject* g = nullptr)
- {
- bool smart = true;
- if (g && g->GetAIName() != "SmartGameObjectAI")
- smart = false;
+ void StoreCounter(uint32 id, uint32 value, uint32 reset);
+ uint32 GetCounterValue(uint32 id) const;
- if (!go || go->GetAIName() != "SmartGameObjectAI")
- smart = false;
- if (!smart)
- TC_LOG_ERROR("sql.sql", "SmartScript: Action target GameObject (GUID: %u Entry: %u) is not using SmartGameObjectAI, action called by GameObject (GUID: %u Entry: %u) skipped to prevent crash.", g ? g->GetSpawnId() : 0, g ? g->GetEntry() : 0, go ? go->GetSpawnId() : 0, go ? go->GetEntry() : 0);
-
- return smart;
- }
-
- ObjectVector const* GetStoredTargetVector(uint32 id, WorldObject const& ref) const
- {
- auto itr = _storedTargets.find(id);
- if (itr != _storedTargets.end())
- return itr->second.GetObjectVector(ref);
- return nullptr;
- }
-
- void StoreCounter(uint32 id, uint32 value, uint32 reset)
- {
- CounterMap::iterator itr = mCounterList.find(id);
- if (itr != mCounterList.end())
- {
- if (reset == 0)
- itr->second += value;
- else
- itr->second = value;
- }
- else
- mCounterList.insert(std::make_pair(id, value));
-
- ProcessEventsFor(SMART_EVENT_COUNTER_SET, nullptr, id);
- }
-
- uint32 GetCounterValue(uint32 id) const
- {
- CounterMap::const_iterator itr = mCounterList.find(id);
- if (itr != mCounterList.end())
- return itr->second;
- return 0;
- }
-
- GameObject* FindGameObjectNear(WorldObject* searchObject, ObjectGuid::LowType guid) const
- {
- auto bounds = searchObject->GetMap()->GetGameObjectBySpawnIdStore().equal_range(guid);
- if (bounds.first == bounds.second)
- return nullptr;
-
- return bounds.first->second;
- }
-
- Creature* FindCreatureNear(WorldObject* searchObject, ObjectGuid::LowType guid) const
- {
- auto bounds = searchObject->GetMap()->GetCreatureBySpawnIdStore().equal_range(guid);
- if (bounds.first == bounds.second)
- return nullptr;
-
- auto creatureItr = std::find_if(bounds.first, bounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair)
- {
- return pair.second->IsAlive();
- });
-
- return creatureItr != bounds.second ? creatureItr->second : bounds.first->second;
- }
+ GameObject* FindGameObjectNear(WorldObject* searchObject, ObjectGuid::LowType guid) const;
+ Creature* FindCreatureNear(WorldObject* searchObject, ObjectGuid::LowType guid) const;
void OnReset();
- void ResetBaseObject()
- {
- WorldObject* lookupRoot = me;
- if (!lookupRoot)
- lookupRoot = go;
-
- if (lookupRoot)
- {
- if (!meOrigGUID.IsEmpty())
- {
- if (Creature* m = ObjectAccessor::GetCreature(*lookupRoot, meOrigGUID))
- {
- me = m;
- go = nullptr;
- }
- }
-
- if (!goOrigGUID.IsEmpty())
- {
- if (GameObject* o = ObjectAccessor::GetGameObject(*lookupRoot, goOrigGUID))
- {
- me = nullptr;
- go = o;
- }
- }
- }
- goOrigGUID.Clear();
- meOrigGUID.Clear();
- }
+ void ResetBaseObject();
//TIMED_ACTIONLIST (script type 9 aka script9)
void SetScript9(SmartScriptHolder& e, uint32 entry);
@@ -265,20 +125,7 @@ class TC_GAME_API SmartScript
SMARTAI_TEMPLATE mTemplate;
void InstallEvents();
- void RemoveStoredEvent(uint32 id)
- {
- if (!mStoredEvents.empty())
- {
- for (auto i = mStoredEvents.begin(); i != mStoredEvents.end(); ++i)
- {
- if (i->event_id == id)
- {
- mStoredEvents.erase(i);
- return;
- }
- }
- }
- }
+ void RemoveStoredEvent(uint32 id);
};
#endif
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index d2910208155..31282a934ac 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -15,18 +15,20 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "SmartScriptMgr.h"
+#include "CreatureTextMgr.h"
#include "DatabaseEnv.h"
-#include "ObjectMgr.h"
-#include "GridDefines.h"
-#include "GridNotifiers.h"
-#include "InstanceScript.h"
-#include "SpellMgr.h"
-#include "Cell.h"
+#include "DBCStores.h"
#include "GameEventMgr.h"
-#include "CreatureTextMgr.h"
+#include "InstanceScript.h"
+#include "Log.h"
+#include "MotionMaster.h"
+#include "ObjectAccessor.h"
+#include "ObjectMgr.h"
#include "SpellInfo.h"
-
-#include "SmartScriptMgr.h"
+#include "SpellMgr.h"
+#include "Timer.h"
+#include "UnitDefines.h"
SmartWaypointMgr* SmartWaypointMgr::instance()
{
@@ -380,6 +382,43 @@ void SmartAIMgr::LoadSmartAIFromDB()
UnLoadHelperStores();
}
+SmartAIEventList SmartAIMgr::GetScript(int32 entry, SmartScriptType type)
+{
+ SmartAIEventList temp;
+ if (mEventMap[uint32(type)].find(entry) != mEventMap[uint32(type)].end())
+ return mEventMap[uint32(type)][entry];
+ else
+ {
+ if (entry > 0)//first search is for guid (negative), do not drop error if not found
+ TC_LOG_DEBUG("scripts.ai", "SmartAIMgr::GetScript: Could not load Script for Entry %d ScriptType %u.", entry, uint32(type));
+ return temp;
+ }
+}
+
+SmartScriptHolder& SmartAIMgr::FindLinkedSourceEvent(SmartAIEventList& list, uint32 eventId)
+{
+ SmartAIEventList::iterator itr = std::find_if(list.begin(), list.end(),
+ [eventId](SmartScriptHolder& source) { return source.link == eventId; });
+
+ if (itr != list.end())
+ return *itr;
+
+ static SmartScriptHolder SmartScriptHolderDummy;
+ return SmartScriptHolderDummy;
+}
+
+SmartScriptHolder& SmartAIMgr::FindLinkedEvent(SmartAIEventList& list, uint32 link)
+{
+ SmartAIEventList::iterator itr = std::find_if(list.begin(), list.end(),
+ [link](SmartScriptHolder& linked) { return linked.event_id == link && linked.GetEventType() == SMART_EVENT_LINK; });
+
+ if (itr != list.end())
+ return *itr;
+
+ static SmartScriptHolder SmartScriptHolderDummy;
+ return SmartScriptHolderDummy;
+}
+
bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e)
{
if (std::abs(e.target.o) > 2 * float(M_PI))
@@ -463,6 +502,116 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e)
return true;
}
+bool SmartAIMgr::IsMinMaxValid(SmartScriptHolder const& e, uint32 min, uint32 max)
+{
+ if (max < min)
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses min/max params wrong (%u/%u), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), min, max);
+ return false;
+ }
+ return true;
+}
+
+bool SmartAIMgr::NotNULL(SmartScriptHolder const& e, uint32 data)
+{
+ if (!data)
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u Parameter can not be NULL, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
+ return false;
+ }
+ return true;
+}
+
+bool SmartAIMgr::IsCreatureValid(SmartScriptHolder const& e, uint32 entry)
+{
+ if (!sObjectMgr->GetCreatureTemplate(entry))
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Creature entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
+ return false;
+ }
+ return true;
+}
+
+bool SmartAIMgr::IsQuestValid(SmartScriptHolder const& e, uint32 entry)
+{
+ if (!sObjectMgr->GetQuestTemplate(entry))
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Quest entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
+ return false;
+ }
+ return true;
+}
+
+bool SmartAIMgr::IsGameObjectValid(SmartScriptHolder const& e, uint32 entry)
+{
+ if (!sObjectMgr->GetGameObjectTemplate(entry))
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent GameObject entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
+ return false;
+ }
+ return true;
+}
+
+bool SmartAIMgr::IsSpellValid(SmartScriptHolder const& e, uint32 entry)
+{
+ if (!sSpellMgr->GetSpellInfo(entry))
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Spell entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
+ return false;
+ }
+ return true;
+}
+
+bool SmartAIMgr::IsItemValid(SmartScriptHolder const& e, uint32 entry)
+{
+ if (!sItemStore.LookupEntry(entry))
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Item entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
+ return false;
+ }
+ return true;
+}
+
+bool SmartAIMgr::IsTextEmoteValid(SmartScriptHolder const& e, uint32 entry)
+{
+ if (!sEmotesTextStore.LookupEntry(entry))
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Text Emote entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
+ return false;
+ }
+ return true;
+}
+
+bool SmartAIMgr::IsEmoteValid(SmartScriptHolder const& e, uint32 entry)
+{
+ if (!sEmotesStore.LookupEntry(entry))
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Emote entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
+ return false;
+ }
+ return true;
+}
+
+bool SmartAIMgr::IsAreaTriggerValid(SmartScriptHolder const& e, uint32 entry)
+{
+ if (!sAreaTriggerStore.LookupEntry(entry))
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent AreaTrigger entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
+ return false;
+ }
+ return true;
+}
+
+bool SmartAIMgr::IsSoundValid(SmartScriptHolder const& e, uint32 entry)
+{
+ if (!sSoundEntriesStore.LookupEntry(entry))
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Sound entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
+ return false;
+ }
+ return true;
+}
+
bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
{
if (e.event.type >= SMART_EVENT_END)
@@ -916,7 +1065,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
}
case SMART_ACTION_RANDOM_EMOTE:
{
- if (std::all_of(e.action.randomEmote.emotes.begin(), e.action.randomEmote.emotes.end(), [](uint32 emote) { return emote == 0; }))
+ if (std::all_of(std::begin(e.action.randomEmote.emotes), std::end(e.action.randomEmote.emotes), [](uint32 emote) { return emote == 0; }))
{
TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u does not have any non-zero emote",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
@@ -930,7 +1079,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
}
case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST:
{
- if (std::all_of(e.action.randTimedActionList.actionLists.begin(), e.action.randTimedActionList.actionLists.end(), [](uint32 actionList) { return actionList == 0; }))
+ if (std::all_of(std::begin(e.action.randTimedActionList.actionLists), std::end(e.action.randTimedActionList.actionLists), [](uint32 actionList) { return actionList == 0; }))
{
TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u does not have any non-zero action list",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
@@ -940,7 +1089,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
}
case SMART_ACTION_START_CLOSEST_WAYPOINT:
{
- if (std::all_of(e.action.closestWaypointFromList.wps.begin(), e.action.closestWaypointFromList.wps.end(), [](uint32 wp) { return wp == 0; }))
+ if (std::all_of(std::begin(e.action.closestWaypointFromList.wps), std::end(e.action.closestWaypointFromList.wps), [](uint32 wp) { return wp == 0; }))
{
TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u does not have any non-zero waypoint id",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
@@ -950,7 +1099,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
}
case SMART_ACTION_RANDOM_SOUND:
{
- if (std::all_of(e.action.randomSound.sounds.begin(), e.action.randomSound.sounds.end(), [](uint32 sound) { return sound == 0; }))
+ if (std::all_of(std::begin(e.action.randomSound.sounds), std::end(e.action.randomSound.sounds), [](uint32 sound) { return sound == 0; }))
{
TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u does not have any non-zero sound",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
@@ -1032,14 +1181,14 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
break;
case SMART_ACTION_RANDOM_PHASE:
{
- if (std::all_of(e.action.randomPhase.phases.begin(), e.action.randomPhase.phases.end(), [](uint32 phase) { return phase == 0; }))
+ if (std::all_of(std::begin(e.action.randomPhase.phases), std::end(e.action.randomPhase.phases), [](uint32 phase) { return phase == 0; }))
{
TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u does not have any non-zero phase",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
return false;
}
- if (std::any_of(e.action.randomPhase.phases.begin(), e.action.randomPhase.phases.end(), [](uint32 phase) { return phase >= SMART_EVENT_PHASE_MAX; }))
+ if (std::any_of(std::begin(e.action.randomPhase.phases), std::end(e.action.randomPhase.phases), [](uint32 phase) { return phase >= SMART_EVENT_PHASE_MAX; }))
{
TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u attempts to set invalid phase, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
return false;
@@ -1164,21 +1313,21 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
return false;
break;
case SMART_ACTION_WP_START:
+ {
+ if (!sSmartWaypointMgr->GetPath(e.action.wpStart.pathID))
{
- if (!sSmartWaypointMgr->GetPath(e.action.wpStart.pathID))
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Creature %d Event %u Action %u uses non-existent WaypointPath id %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpStart.pathID);
- return false;
- }
- if (e.action.wpStart.quest && !IsQuestValid(e, e.action.wpStart.quest))
- return false;
- if (e.action.wpStart.reactState > REACT_AGGRESSIVE)
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Creature %d Event %u Action %u uses invalid React State %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpStart.reactState);
- return false;
- }
- break;
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Creature %d Event %u Action %u uses non-existent WaypointPath id %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpStart.pathID);
+ return false;
+ }
+ if (e.action.wpStart.quest && !IsQuestValid(e, e.action.wpStart.quest))
+ return false;
+ if (e.action.wpStart.reactState > REACT_AGGRESSIVE)
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Creature %d Event %u Action %u uses invalid React State %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpStart.reactState);
+ return false;
}
+ break;
+ }
case SMART_ACTION_CREATE_TIMED_EVENT:
{
if (!IsMinMaxValid(e, e.action.timeEvent.min, e.action.timeEvent.max))
@@ -1419,7 +1568,7 @@ void SmartAIMgr::LoadHelperStores()
{
uint32 oldMSTime = getMSTime();
- SpellInfo const* spellInfo = NULL;
+ SpellInfo const* spellInfo = nullptr;
for (uint32 i = 0; i < sSpellMgr->GetSpellInfoStoreSize(); ++i)
{
spellInfo = sSpellMgr->GetSpellInfo(i);
@@ -1473,3 +1622,18 @@ CacheSpellContainerBounds SmartAIMgr::GetCreateItemSpellContainerBounds(uint32 i
return CreateItemSpellStore.equal_range(itemId);
}
+ObjectGuidVector::ObjectGuidVector(ObjectVector const& objectVector) : _objectVector(objectVector)
+{
+ _guidVector.reserve(_objectVector.size());
+ for (WorldObject* obj : _objectVector)
+ _guidVector.push_back(obj->GetGUID());
+}
+
+void ObjectGuidVector::UpdateObjects(WorldObject const& ref) const
+{
+ _objectVector.clear();
+
+ for (ObjectGuid const& guid : _guidVector)
+ if (WorldObject* obj = ObjectAccessor::GetWorldObject(ref, guid))
+ _objectVector.push_back(obj);
+}
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 29b76ae0dd9..7a1433bc7fb 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -18,14 +18,14 @@
#ifndef TRINITY_SMARTSCRIPTMGR_H
#define TRINITY_SMARTSCRIPTMGR_H
-#include "Common.h"
-#include "Creature.h"
-#include "CreatureAI.h"
-#include "Unit.h"
-#include "Spell.h"
+#include "Define.h"
+#include "ObjectGuid.h"
+#include <map>
+#include <string>
+#include <unordered_map>
-//#include "SmartScript.h"
-//#include "SmartAI.h"
+class WorldObject;
+enum SpellEffIndex : uint8;
struct WayPoint
{
@@ -646,7 +646,7 @@ struct SmartAction
struct
{
- std::array<uint32, SMART_ACTION_PARAM_COUNT> emotes;
+ uint32 emotes[SMART_ACTION_PARAM_COUNT];
} randomEmote;
struct
@@ -739,7 +739,7 @@ struct SmartAction
struct
{
- std::array<uint32, SMART_ACTION_PARAM_COUNT> phases;
+ uint32 phases[SMART_ACTION_PARAM_COUNT];
} randomPhase;
struct
@@ -930,7 +930,9 @@ struct SmartAction
{
uint32 entry;
uint32 mask;
- std::array<uint32, MAX_EQUIPMENT_ITEMS> slots;
+ uint32 slot1;
+ uint32 slot2;
+ uint32 slot3;
} equip;
struct
@@ -964,7 +966,7 @@ struct SmartAction
struct
{
- std::array<uint32, SMART_ACTION_PARAM_COUNT> actionLists;
+ uint32 actionLists[SMART_ACTION_PARAM_COUNT];
} randTimedActionList;
struct
@@ -1074,12 +1076,12 @@ struct SmartAction
struct
{
- std::array<uint32, SMART_ACTION_PARAM_COUNT> wps;
+ uint32 wps[SMART_ACTION_PARAM_COUNT];
} closestWaypointFromList;
struct
{
- std::array<uint32, SMART_ACTION_PARAM_COUNT - 1> sounds;
+ uint32 sounds[SMART_ACTION_PARAM_COUNT - 1];
uint32 onlySelf;
} randomSound;
@@ -1500,12 +1502,7 @@ typedef std::vector<WorldObject*> ObjectVector;
class ObjectGuidVector
{
public:
- explicit ObjectGuidVector(ObjectVector const& objectVector) : _objectVector(objectVector)
- {
- _guidVector.reserve(_objectVector.size());
- for (WorldObject* obj : _objectVector)
- _guidVector.push_back(obj->GetGUID());
- }
+ explicit ObjectGuidVector(ObjectVector const& objectVector);
ObjectVector const* GetObjectVector(WorldObject const& ref) const
{
@@ -1520,14 +1517,7 @@ class ObjectGuidVector
mutable ObjectVector _objectVector;
//sanitize vector using _guidVector
- void UpdateObjects(WorldObject const& ref) const
- {
- _objectVector.clear();
-
- for (ObjectGuid const& guid : _guidVector)
- if (WorldObject* obj = ObjectAccessor::GetWorldObject(ref, guid))
- _objectVector.push_back(obj);
- }
+ void UpdateObjects(WorldObject const& ref) const;
};
typedef std::unordered_map<uint32, ObjectGuidVector> ObjectVectorMap;
@@ -1575,42 +1565,11 @@ class TC_GAME_API SmartAIMgr
void LoadSmartAIFromDB();
- SmartAIEventList GetScript(int32 entry, SmartScriptType type)
- {
- SmartAIEventList temp;
- if (mEventMap[uint32(type)].find(entry) != mEventMap[uint32(type)].end())
- return mEventMap[uint32(type)][entry];
- else
- {
- if (entry > 0)//first search is for guid (negative), do not drop error if not found
- TC_LOG_DEBUG("scripts.ai", "SmartAIMgr::GetScript: Could not load Script for Entry %d ScriptType %u.", entry, uint32(type));
- return temp;
- }
- }
+ SmartAIEventList GetScript(int32 entry, SmartScriptType type);
- static SmartScriptHolder& FindLinkedSourceEvent(SmartAIEventList& list, uint32 eventId)
- {
- SmartAIEventList::iterator itr = std::find_if(list.begin(), list.end(),
- [eventId](SmartScriptHolder& source) { return source.link == eventId; });
+ static SmartScriptHolder& FindLinkedSourceEvent(SmartAIEventList& list, uint32 eventId);
- if (itr != list.end())
- return *itr;
-
- static SmartScriptHolder SmartScriptHolderDummy;
- return SmartScriptHolderDummy;
- }
-
- static SmartScriptHolder& FindLinkedEvent(SmartAIEventList& list, uint32 link)
- {
- SmartAIEventList::iterator itr = std::find_if(list.begin(), list.end(),
- [link](SmartScriptHolder& linked) { return linked.event_id == link && linked.GetEventType() == SMART_EVENT_LINK; });
-
- if (itr != list.end())
- return *itr;
-
- static SmartScriptHolder SmartScriptHolderDummy;
- return SmartScriptHolderDummy;
- }
+ static SmartScriptHolder& FindLinkedEvent(SmartAIEventList& list, uint32 link);
private:
//event stores
@@ -1619,127 +1578,19 @@ class TC_GAME_API SmartAIMgr
bool IsEventValid(SmartScriptHolder& e);
bool IsTargetValid(SmartScriptHolder const& e);
- bool IsMinMaxValid(SmartScriptHolder const& e, uint32 min, uint32 max)
- {
- if (max < min)
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses min/max params wrong (%u/%u), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), min, max);
- return false;
- }
- return true;
- }
-
- /*inline bool IsPercentValid(SmartScriptHolder e, int32 pct)
- {
- if (pct < -100 || pct > 100)
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u has invalid Percent set (%d), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), pct);
- return false;
- }
- return true;
- }*/
-
- bool NotNULL(SmartScriptHolder const& e, uint32 data)
- {
- if (!data)
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u Parameter can not be NULL, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
- return false;
- }
- return true;
- }
-
- bool IsCreatureValid(SmartScriptHolder const& e, uint32 entry)
- {
- if (!sObjectMgr->GetCreatureTemplate(entry))
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Creature entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
- return false;
- }
- return true;
- }
-
- bool IsQuestValid(SmartScriptHolder const& e, uint32 entry)
- {
- if (!sObjectMgr->GetQuestTemplate(entry))
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Quest entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
- return false;
- }
- return true;
- }
-
- bool IsGameObjectValid(SmartScriptHolder const& e, uint32 entry)
- {
- if (!sObjectMgr->GetGameObjectTemplate(entry))
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent GameObject entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
- return false;
- }
- return true;
- }
-
- bool IsSpellValid(SmartScriptHolder const& e, uint32 entry)
- {
- if (!sSpellMgr->GetSpellInfo(entry))
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Spell entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
- return false;
- }
- return true;
- }
-
- bool IsItemValid(SmartScriptHolder const& e, uint32 entry)
- {
- if (!sItemStore.LookupEntry(entry))
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Item entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
- return false;
- }
- return true;
- }
-
- bool IsTextEmoteValid(SmartScriptHolder const& e, uint32 entry)
- {
- if (!sEmotesTextStore.LookupEntry(entry))
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Text Emote entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
- return false;
- }
- return true;
- }
-
- bool IsEmoteValid(SmartScriptHolder const& e, uint32 entry)
- {
- if (!sEmotesStore.LookupEntry(entry))
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Emote entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
- return false;
- }
- return true;
- }
-
- bool IsAreaTriggerValid(SmartScriptHolder const& e, uint32 entry)
- {
- if (!sAreaTriggerStore.LookupEntry(entry))
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent AreaTrigger entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
- return false;
- }
- return true;
- }
-
- bool IsSoundValid(SmartScriptHolder const& e, uint32 entry)
- {
- if (!sSoundEntriesStore.LookupEntry(entry))
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Sound entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
- return false;
- }
- return true;
- }
-
- bool IsTextValid(SmartScriptHolder const& e, uint32 id);
+ static bool IsMinMaxValid(SmartScriptHolder const& e, uint32 min, uint32 max);
+
+ static bool NotNULL(SmartScriptHolder const& e, uint32 data);
+ static bool IsCreatureValid(SmartScriptHolder const& e, uint32 entry);
+ static bool IsQuestValid(SmartScriptHolder const& e, uint32 entry);
+ static bool IsGameObjectValid(SmartScriptHolder const& e, uint32 entry);
+ static bool IsSpellValid(SmartScriptHolder const& e, uint32 entry);
+ static bool IsItemValid(SmartScriptHolder const& e, uint32 entry);
+ static bool IsTextEmoteValid(SmartScriptHolder const& e, uint32 entry);
+ static bool IsEmoteValid(SmartScriptHolder const& e, uint32 entry);
+ static bool IsAreaTriggerValid(SmartScriptHolder const& e, uint32 entry);
+ static bool IsSoundValid(SmartScriptHolder const& e, uint32 entry);
+ static bool IsTextValid(SmartScriptHolder const& e, uint32 id);
// Helpers
void LoadHelperStores();