diff options
| author | ariel- <ariel-@users.noreply.github.com> | 2017-06-19 23:20:06 -0300 |
|---|---|---|
| committer | ariel- <ariel-@users.noreply.github.com> | 2017-06-19 23:20:06 -0300 |
| commit | 85a7d5ce9ac68b30da2277cc91d4b70358f1880d (patch) | |
| tree | df3d2084ee2e35008903c03178039b9c986e2d08 /src/server/game/AI | |
| parent | 052fc24315ace866ea1cf610e85df119b68100c9 (diff) | |
Core: ported headers cleanup from master branch
Diffstat (limited to 'src/server/game/AI')
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(); |
