diff options
| author | Shauren <shauren.trinity@gmail.com> | 2020-06-15 00:26:08 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-06-15 00:26:08 +0200 |
| commit | c715e635cf3feb50ac61d30659e614aaa2cc0c63 (patch) | |
| tree | 5af30c80f8b1df3f60852adde4680951f6f55442 /src/server/game | |
| parent | abff505a6eaf3e649be506c802b80eed3dd35f3a (diff) | |
| parent | cf88f0a9735f9ba010a4ae46e848c8f1a86e17fa (diff) | |
Merge pull request #24554 from funjoker/cherry-picks
Diffstat (limited to 'src/server/game')
56 files changed, 496 insertions, 451 deletions
diff --git a/src/server/game/AI/CoreAI/CombatAI.cpp b/src/server/game/AI/CoreAI/CombatAI.cpp index 2f2461b5ab0..160b58a9742 100644 --- a/src/server/game/AI/CoreAI/CombatAI.cpp +++ b/src/server/game/AI/CoreAI/CombatAI.cpp @@ -32,11 +32,11 @@ // AggressorAI ///////////////// -int AggressorAI::Permissible(const Creature* creature) +int32 AggressorAI::Permissible(Creature const* creature) { // have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight if (!creature->IsCivilian() && !creature->IsNeutralToAll()) - return PERMIT_BASE_PROACTIVE; + return PERMIT_BASE_REACTIVE; return PERMIT_BASE_NO; } @@ -344,3 +344,11 @@ void VehicleAI::CheckConditions(uint32 diff) else m_ConditionsTimer -= diff; } + +int32 VehicleAI::Permissible(Creature const* creature) +{ + if (creature->IsVehicle()) + return PERMIT_BASE_SPECIAL; + + return PERMIT_BASE_NO; +} diff --git a/src/server/game/AI/CoreAI/CombatAI.h b/src/server/game/AI/CoreAI/CombatAI.h index 9e4e05d9544..9082ad515e8 100644 --- a/src/server/game/AI/CoreAI/CombatAI.h +++ b/src/server/game/AI/CoreAI/CombatAI.h @@ -28,7 +28,7 @@ class TC_GAME_API AggressorAI : public CreatureAI explicit AggressorAI(Creature* c) : CreatureAI(c) { } void UpdateAI(uint32) override; - static int Permissible(const Creature*); + static int32 Permissible(Creature const* creature); }; typedef std::vector<uint32> SpellVct; @@ -45,7 +45,7 @@ class TC_GAME_API CombatAI : public CreatureAI void UpdateAI(uint32 diff) override; void SpellInterrupted(uint32 spellId, uint32 unTimeMs) override; - static int Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } + static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } protected: EventMap events; @@ -71,7 +71,7 @@ struct TC_GAME_API ArcherAI : public CreatureAI void AttackStart(Unit* who) override; void UpdateAI(uint32 diff) override; - static int Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } + static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } protected: float m_minRange; @@ -85,7 +85,7 @@ struct TC_GAME_API TurretAI : public CreatureAI void AttackStart(Unit* who) override; void UpdateAI(uint32 diff) override; - static int Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } + static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } protected: float m_minRange; @@ -104,7 +104,7 @@ struct TC_GAME_API VehicleAI : public CreatureAI void AttackStart(Unit*) override { } void OnCharmed(bool apply) override; - static int Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } + static int32 Permissible(Creature const* creature); private: void LoadConditions(); diff --git a/src/server/game/AI/CoreAI/GameObjectAI.cpp b/src/server/game/AI/CoreAI/GameObjectAI.cpp index 48caa63dbce..94fe71f449d 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.cpp +++ b/src/server/game/AI/CoreAI/GameObjectAI.cpp @@ -20,11 +20,8 @@ #include "GameObject.h" #include "QuestDef.h" -//GameObjectAI::GameObjectAI(GameObject* g) : go(g) { } -int GameObjectAI::Permissible(const GameObject* go) +int32 GameObjectAI::Permissible(GameObject const* /*go*/) { - if (go->GetAIName() == "GameObjectAI") - return PERMIT_BASE_SPECIAL; return PERMIT_BASE_NO; } @@ -35,7 +32,7 @@ uint32 GameObjectAI::GetDialogStatus(Player* /*player*/) NullGameObjectAI::NullGameObjectAI(GameObject* g) : GameObjectAI(g) { } -int NullGameObjectAI::Permissible(GameObject const* /*go*/) +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 655035d505b..4bfc6c7a2f3 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.h +++ b/src/server/game/AI/CoreAI/GameObjectAI.h @@ -46,7 +46,7 @@ class TC_GAME_API GameObjectAI virtual void SetGUID(uint64 /*guid*/, int32 /*id = 0 */) { } virtual uint64 GetGUID(int32 /*id = 0 */) const { return 0; } - static int Permissible(GameObject const* go); + static int32 Permissible(GameObject const* /*go*/); // Called when a player opens a gossip dialog with the gameobject. virtual bool GossipHello(Player* /*player*/, bool /*reportUse*/) { return false; } @@ -88,6 +88,6 @@ class TC_GAME_API NullGameObjectAI : public GameObjectAI void UpdateAI(uint32 /*diff*/) override { } - static int Permissible(GameObject const* /*go*/); + 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 f9d3b96cadb..2b358945bd9 100644 --- a/src/server/game/AI/CoreAI/GuardAI.cpp +++ b/src/server/game/AI/CoreAI/GuardAI.cpp @@ -26,10 +26,10 @@ GuardAI::GuardAI(Creature* creature) : ScriptedAI(creature) { } -int GuardAI::Permissible(Creature const* creature) +int32 GuardAI::Permissible(Creature const* creature) { if (creature->IsGuard()) - return PERMIT_BASE_SPECIAL; + return PERMIT_BASE_PROACTIVE; return PERMIT_BASE_NO; } diff --git a/src/server/game/AI/CoreAI/GuardAI.h b/src/server/game/AI/CoreAI/GuardAI.h index a731e160e90..037094cff4b 100644 --- a/src/server/game/AI/CoreAI/GuardAI.h +++ b/src/server/game/AI/CoreAI/GuardAI.h @@ -27,7 +27,7 @@ class TC_GAME_API GuardAI : public ScriptedAI public: explicit GuardAI(Creature* creature); - static int Permissible(Creature const* creature); + static int32 Permissible(Creature const* creature); void UpdateAI(uint32 diff) override; bool CanSeeAlways(WorldObject const* obj) override; diff --git a/src/server/game/AI/CoreAI/PassiveAI.cpp b/src/server/game/AI/CoreAI/PassiveAI.cpp index 417a3c9bf04..5c3e8026600 100644 --- a/src/server/game/AI/CoreAI/PassiveAI.cpp +++ b/src/server/game/AI/CoreAI/PassiveAI.cpp @@ -22,6 +22,17 @@ PassiveAI::PassiveAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASS PossessedAI::PossessedAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); } NullCreatureAI::NullCreatureAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); } +int32 NullCreatureAI::Permissible(Creature const* creature) +{ + if (creature->HasNpcFlag(UNIT_NPC_FLAG_SPELLCLICK)) + return PERMIT_BASE_PROACTIVE + 50; + + if (creature->IsTrigger()) + return PERMIT_BASE_REACTIVE; + + return PERMIT_BASE_IDLE; +} + void PassiveAI::UpdateAI(uint32) { if (me->IsInCombat() && me->getAttackers().empty()) @@ -76,8 +87,24 @@ void CritterAI::EnterEvadeMode(EvadeReason why) CreatureAI::EnterEvadeMode(why); } +int32 CritterAI::Permissible(Creature const* creature) +{ + if (creature->IsCritter() && !creature->HasUnitTypeMask(UNIT_MASK_GUARDIAN)) + return PERMIT_BASE_PROACTIVE; + + return PERMIT_BASE_NO; +} + void TriggerAI::IsSummonedBy(Unit* summoner) { if (me->m_spells[0]) me->CastSpell(me, me->m_spells[0], false, nullptr, nullptr, summoner->GetGUID()); } + +int32 TriggerAI::Permissible(Creature const* creature) +{ + if (creature->IsTrigger() && creature->m_spells[0]) + return PERMIT_BASE_PROACTIVE; + + return PERMIT_BASE_NO; +} diff --git a/src/server/game/AI/CoreAI/PassiveAI.h b/src/server/game/AI/CoreAI/PassiveAI.h index 43ad670e0df..41d4c2bfb12 100644 --- a/src/server/game/AI/CoreAI/PassiveAI.h +++ b/src/server/game/AI/CoreAI/PassiveAI.h @@ -29,7 +29,7 @@ class TC_GAME_API PassiveAI : public CreatureAI void AttackStart(Unit*) override { } void UpdateAI(uint32) override; - static int Permissible(const Creature*) { return PERMIT_BASE_IDLE; } + static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } }; class TC_GAME_API PossessedAI : public CreatureAI @@ -47,7 +47,7 @@ class TC_GAME_API PossessedAI : public CreatureAI void OnCharmed(bool /*apply*/) override; - static int Permissible(const Creature*) { return PERMIT_BASE_IDLE; } + static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } }; class TC_GAME_API NullCreatureAI : public CreatureAI @@ -61,7 +61,7 @@ class TC_GAME_API NullCreatureAI : public CreatureAI void EnterEvadeMode(EvadeReason /*why*/) override { } void OnCharmed(bool /*apply*/) override { } - static int Permissible(const Creature*) { return PERMIT_BASE_IDLE; } + static int32 Permissible(Creature const* creature); }; class TC_GAME_API CritterAI : public PassiveAI @@ -71,6 +71,8 @@ class TC_GAME_API CritterAI : public PassiveAI void DamageTaken(Unit* done_by, uint32& /*damage*/) override; void EnterEvadeMode(EvadeReason why) override; + + static int32 Permissible(Creature const* creature); }; class TC_GAME_API TriggerAI : public NullCreatureAI @@ -78,6 +80,8 @@ class TC_GAME_API TriggerAI : public NullCreatureAI public: explicit TriggerAI(Creature* c) : NullCreatureAI(c) { } void IsSummonedBy(Unit* summoner) override; + + static int32 Permissible(Creature const* creature); }; #endif diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index a39e4a8dfc0..c16e1f945eb 100644 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -31,10 +31,14 @@ #include "SpellMgr.h" #include "Util.h" -int PetAI::Permissible(const Creature* creature) +int32 PetAI::Permissible(Creature const* creature) { - if (creature->IsPet()) - return PERMIT_BASE_SPECIAL; + if (creature->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN)) + { + if (reinterpret_cast<Guardian const*>(creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER) + return PERMIT_BASE_PROACTIVE; + return PERMIT_BASE_REACTIVE; + } return PERMIT_BASE_NO; } diff --git a/src/server/game/AI/CoreAI/PetAI.h b/src/server/game/AI/CoreAI/PetAI.h index c712d42651d..4455c1cd494 100644 --- a/src/server/game/AI/CoreAI/PetAI.h +++ b/src/server/game/AI/CoreAI/PetAI.h @@ -33,7 +33,7 @@ class TC_GAME_API PetAI : public CreatureAI explicit PetAI(Creature* c); void UpdateAI(uint32) override; - static int Permissible(const Creature*); + static int32 Permissible(Creature const* creature); void KilledUnit(Unit* /*victim*/) override; void AttackStart(Unit* target) override; diff --git a/src/server/game/AI/CoreAI/ReactorAI.cpp b/src/server/game/AI/CoreAI/ReactorAI.cpp index 836cc1e0358..8b15bed1908 100644 --- a/src/server/game/AI/CoreAI/ReactorAI.cpp +++ b/src/server/game/AI/CoreAI/ReactorAI.cpp @@ -18,7 +18,7 @@ #include "ReactorAI.h" #include "Creature.h" -int ReactorAI::Permissible(const Creature* creature) +int32 ReactorAI::Permissible(Creature const* creature) { if (creature->IsCivilian() || creature->IsNeutralToAll()) return PERMIT_BASE_REACTIVE; diff --git a/src/server/game/AI/CoreAI/ReactorAI.h b/src/server/game/AI/CoreAI/ReactorAI.h index fa0bd2d8ee1..be76f855781 100644 --- a/src/server/game/AI/CoreAI/ReactorAI.h +++ b/src/server/game/AI/CoreAI/ReactorAI.h @@ -29,6 +29,6 @@ class TC_GAME_API ReactorAI : public CreatureAI void MoveInLineOfSight(Unit*) override { } void UpdateAI(uint32 diff) override; - static int Permissible(const Creature*); + static int32 Permissible(Creature const* creature); }; #endif diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp index 4d2bda5faa0..c727ea45003 100644 --- a/src/server/game/AI/CoreAI/TotemAI.cpp +++ b/src/server/game/AI/CoreAI/TotemAI.cpp @@ -24,7 +24,7 @@ #include "GridNotifiersImpl.h" #include "CellImpl.h" -int TotemAI::Permissible(Creature const* creature) +int32 TotemAI::Permissible(Creature const* creature) { if (creature->IsTotem()) return PERMIT_BASE_PROACTIVE; diff --git a/src/server/game/AI/CoreAI/TotemAI.h b/src/server/game/AI/CoreAI/TotemAI.h index 2938190c771..fd25ca86df6 100644 --- a/src/server/game/AI/CoreAI/TotemAI.h +++ b/src/server/game/AI/CoreAI/TotemAI.h @@ -35,7 +35,7 @@ class TC_GAME_API TotemAI : public CreatureAI void EnterEvadeMode(EvadeReason /*why*/) override; void UpdateAI(uint32 diff) override; - static int Permissible(Creature const* creature); + static int32 Permissible(Creature const* creature); private: ObjectGuid i_victimGuid; diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index b274a4794d1..41e6ab2501d 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -204,7 +204,7 @@ class TC_GAME_API CreatureAI : public UnitAI bool m_MoveInLineOfSight_locked; }; -enum Permitions +enum Permitions : int32 { PERMIT_BASE_NO = -1, PERMIT_BASE_IDLE = 1, diff --git a/src/server/game/AI/CreatureAIFactory.h b/src/server/game/AI/CreatureAIFactory.h index 656435ad632..92e757d835d 100644 --- a/src/server/game/AI/CreatureAIFactory.h +++ b/src/server/game/AI/CreatureAIFactory.h @@ -18,66 +18,34 @@ #ifndef TRINITY_CREATUREAIFACTORY_H #define TRINITY_CREATUREAIFACTORY_H -//#include "Policies/Singleton.h" #include "ObjectRegistry.h" #include "FactoryHolder.h" -#include "GameObjectAI.h" -struct SelectableAI : public FactoryHolder<CreatureAI>, public Permissible<Creature> +typedef FactoryHolder<CreatureAI, Creature> CreatureAICreator; + +struct SelectableAI : public CreatureAICreator, public Permissible<Creature> { - SelectableAI(const char* id) : FactoryHolder<CreatureAI>(id) { } + SelectableAI(std::string const& name) : CreatureAICreator(name), Permissible<Creature>() { } }; template<class REAL_AI> struct CreatureAIFactory : public SelectableAI { - CreatureAIFactory(const char* name) : SelectableAI(name) { } + CreatureAIFactory(std::string const& name) : SelectableAI(name) { } - CreatureAI* Create(void*) const override; + inline CreatureAI* Create(Creature* c) const override + { + return new REAL_AI(c); + } - int Permit(const Creature* c) const override { return REAL_AI::Permissible(c); } + int32 Permit(Creature const* c) const override + { + return REAL_AI::Permissible(c); + } }; -template<class REAL_AI> -inline CreatureAI* -CreatureAIFactory<REAL_AI>::Create(void* data) const -{ - Creature* creature = reinterpret_cast<Creature*>(data); - return (new REAL_AI(creature)); -} - -typedef FactoryHolder<CreatureAI> CreatureAICreator; -typedef FactoryHolder<CreatureAI>::FactoryHolderRegistry CreatureAIRegistry; +typedef CreatureAICreator::FactoryHolderRegistry CreatureAIRegistry; #define sCreatureAIRegistry CreatureAIRegistry::instance() -//GO -struct SelectableGameObjectAI : public FactoryHolder<GameObjectAI>, public Permissible<GameObject> -{ - SelectableGameObjectAI(const char* id) : FactoryHolder<GameObjectAI>(id) { } -}; - -template<class REAL_GO_AI> -struct GameObjectAIFactory : public SelectableGameObjectAI -{ - GameObjectAIFactory(const char* name) : SelectableGameObjectAI(name) { } - - GameObjectAI* Create(void*) const override; - - int Permit(const GameObject* g) const override { return REAL_GO_AI::Permissible(g); } -}; - -template<class REAL_GO_AI> -inline GameObjectAI* -GameObjectAIFactory<REAL_GO_AI>::Create(void* data) const -{ - GameObject* go = reinterpret_cast<GameObject*>(data); - return (new REAL_GO_AI(go)); -} - -typedef FactoryHolder<GameObjectAI> GameObjectAICreator; -typedef FactoryHolder<GameObjectAI>::FactoryHolderRegistry GameObjectAIRegistry; - -#define sGameObjectAIRegistry GameObjectAIRegistry::instance() - #endif diff --git a/src/server/game/AI/CreatureAIRegistry.cpp b/src/server/game/AI/CreatureAIRegistry.cpp index 9aab7376ab2..34cc64af22b 100644 --- a/src/server/game/AI/CreatureAIRegistry.cpp +++ b/src/server/game/AI/CreatureAIRegistry.cpp @@ -22,10 +22,11 @@ #include "PetAI.h" #include "TotemAI.h" #include "RandomMovementGenerator.h" -#include "MovementGeneratorImpl.h" +#include "MovementGenerator.h" #include "CreatureAIRegistry.h" #include "WaypointMovementGenerator.h" #include "CreatureAIFactory.h" +#include "GameObjectAIFactory.h" #include "SmartAI.h" namespace AIRegistry @@ -47,10 +48,12 @@ namespace AIRegistry (new CreatureAIFactory<VehicleAI>("VehicleAI"))->RegisterSelf(); (new CreatureAIFactory<SmartAI>("SmartAI"))->RegisterSelf(); + (new GameObjectAIFactory<NullGameObjectAI>("NullGameObjectAI"))->RegisterSelf(); (new GameObjectAIFactory<GameObjectAI>("GameObjectAI"))->RegisterSelf(); (new GameObjectAIFactory<SmartGameObjectAI>("SmartGameObjectAI"))->RegisterSelf(); - (new MovementGeneratorFactory<RandomMovementGenerator<Creature> >(RANDOM_MOTION_TYPE))->RegisterSelf(); - (new MovementGeneratorFactory<WaypointMovementGenerator<Creature> >(WAYPOINT_MOTION_TYPE))->RegisterSelf(); + (new IdleMovementFactory())->RegisterSelf(); + (new MovementGeneratorFactory<RandomMovementGenerator<Creature>>(RANDOM_MOTION_TYPE))->RegisterSelf(); + (new MovementGeneratorFactory<WaypointMovementGenerator<Creature>>(WAYPOINT_MOTION_TYPE))->RegisterSelf(); } } diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp index 487511eff3e..b7181a35f76 100644 --- a/src/server/game/AI/CreatureAISelector.cpp +++ b/src/server/game/AI/CreatureAISelector.cpp @@ -17,130 +17,94 @@ #include "Creature.h" #include "CreatureAISelector.h" -#include "GameObject.h" -#include "PassiveAI.h" +#include "CreatureAIFactory.h" #include "Log.h" #include "MovementGenerator.h" -#include "TemporarySummon.h" -#include "CreatureAIFactory.h" + +#include "GameObject.h" +#include "GameObjectAIFactory.h" + #include "ScriptMgr.h" namespace FactorySelector { - CreatureAI* selectAI(Creature* creature) + template <class T, class Value> + inline int32 GetPermitFor(T const* obj, Value const& value) { - const CreatureAICreator* ai_factory = NULL; - - if (creature->IsPet()) - ai_factory = sCreatureAIRegistry->GetRegistryItem("PetAI"); - - //scriptname in db - if (!ai_factory) - if (CreatureAI* scriptedAI = sScriptMgr->GetCreatureAI(creature)) - return scriptedAI; + Permissible<T> const* const p = ASSERT_NOTNULL(dynamic_cast<Permissible<T> const*>(value.second.get())); + return p->Permit(obj); + } - // AIname in db - std::string ainame=creature->GetAIName(); - if (!ai_factory && !ainame.empty()) - ai_factory = sCreatureAIRegistry->GetRegistryItem(ainame); + template <class T> + struct PermissibleOrderPred + { + public: + PermissibleOrderPred(T const* obj) : _obj(obj) { } - // select by NPC flags - if (!ai_factory) + template <class Value> + bool operator()(Value const& left, Value const& right) const { - if (creature->IsVehicle()) - ai_factory = sCreatureAIRegistry->GetRegistryItem("VehicleAI"); - else if (creature->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN) && ((Guardian*)creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER) - ai_factory = sCreatureAIRegistry->GetRegistryItem("PetAI"); - else if (creature->HasNpcFlag(UNIT_NPC_FLAG_SPELLCLICK)) - ai_factory = sCreatureAIRegistry->GetRegistryItem("NullCreatureAI"); - else if (creature->IsGuard()) - ai_factory = sCreatureAIRegistry->GetRegistryItem("GuardAI"); - else if (creature->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN)) - ai_factory = sCreatureAIRegistry->GetRegistryItem("PetAI"); - else if (creature->IsTotem()) - ai_factory = sCreatureAIRegistry->GetRegistryItem("TotemAI"); - else if (creature->IsTrigger()) - { - if (creature->m_spells[0]) - ai_factory = sCreatureAIRegistry->GetRegistryItem("TriggerAI"); - else - ai_factory = sCreatureAIRegistry->GetRegistryItem("NullCreatureAI"); - } - else if (creature->IsCritter() && !creature->HasUnitTypeMask(UNIT_MASK_GUARDIAN)) - ai_factory = sCreatureAIRegistry->GetRegistryItem("CritterAI"); + return GetPermitFor(_obj, left) < GetPermitFor(_obj, right); } - // select by permit check - if (!ai_factory) - { - int best_val = -1; - typedef CreatureAIRegistry::RegistryMapType RMT; - RMT const& l = sCreatureAIRegistry->GetRegisteredItems(); - for (RMT::const_iterator iter = l.begin(); iter != l.end(); ++iter) - { - const CreatureAICreator* factory = iter->second; - const SelectableAI* p = dynamic_cast<const SelectableAI*>(factory); - ASSERT(p); - int val = p->Permit(creature); - if (val > best_val) - { - best_val = val; - ai_factory = p; - } - } - } + private: + T const* const _obj; + }; - // select NullCreatureAI if not another cases - ainame = (ai_factory == NULL) ? "NullCreatureAI" : ai_factory->key(); + template <class AI, class T> + inline FactoryHolder<AI, T> const* SelectFactory(T* obj) + { + static_assert(std::is_same<AI, CreatureAI>::value || std::is_same<AI, GameObjectAI>::value, "Invalid template parameter"); + static_assert(std::is_same<AI, CreatureAI>::value == std::is_same<T, Creature>::value, "Incompatible AI for type"); + static_assert(std::is_same<AI, GameObjectAI>::value == std::is_same<T, GameObject>::value, "Incompatible AI for type"); - TC_LOG_DEBUG("scripts", "Creature %s (%s DB GUID: " UI64FMTD ") is using AI type: %s.", creature->GetName().c_str(), creature->GetGUID().ToString().c_str(), creature->GetSpawnId(), ainame.c_str()); - return (ai_factory == NULL ? new NullCreatureAI(creature) : ai_factory->Create(creature)); - } + using AIRegistry = typename FactoryHolder<AI, T>::FactoryHolderRegistry; - MovementGenerator* selectMovementGenerator(Creature* creature) - { - MovementGeneratorRegistry& mv_registry(*MovementGeneratorRegistry::instance()); - ASSERT(creature->GetCreatureTemplate()); - const MovementGeneratorCreator* mv_factory = mv_registry.GetRegistryItem(creature->GetDefaultMovementType()); + // AIName in db + std::string const& aiName = obj->GetAIName(); + if (!aiName.empty()) + return AIRegistry::instance()->GetRegistryItem(aiName); - /* if (mv_factory == NULL) - { - int best_val = -1; - StringVector l; - mv_registry.GetRegisteredItems(l); - for (StringVector::iterator iter = l.begin(); iter != l.end(); ++iter) - { - const MovementGeneratorCreator *factory = mv_registry.GetRegistryItem((*iter).c_str()); - const SelectableMovement *p = dynamic_cast<const SelectableMovement *>(factory); - ASSERT(p != NULL); - int val = p->Permit(creature); - if (val > best_val) - { - best_val = val; - mv_factory = p; - } - } - }*/ - - return (mv_factory == NULL ? NULL : mv_factory->Create(creature)); + // select by permit check + typename AIRegistry::RegistryMapType const& items = AIRegistry::instance()->GetRegisteredItems(); + auto itr = std::max_element(items.begin(), items.end(), PermissibleOrderPred<T>(obj)); + if (itr != items.end() && GetPermitFor(obj, *itr) >= 0) + return itr->second.get(); + + // should _never_ happen, Null AI types defined as PERMIT_BASE_IDLE, it must've been found + ABORT(); + return nullptr; } - GameObjectAI* SelectGameObjectAI(GameObject* go) + CreatureAI* SelectAI(Creature* creature) { - GameObjectAICreator const* ai_factory = NULL; + // special pet case, if a tamed creature uses AIName (example SmartAI) we need to override it + if (creature->IsPet()) + return ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PetAI"))->Create(creature); // scriptname in db - if (GameObjectAI* scriptedAI = sScriptMgr->GetGameObjectAI(go)) + if (CreatureAI* scriptedAI = sScriptMgr->GetCreatureAI(creature)) return scriptedAI; - ai_factory = sGameObjectAIRegistry->GetRegistryItem(go->GetAIName()); + return SelectFactory<CreatureAI>(creature)->Create(creature); + } - //future goAI types go here + MovementGenerator* SelectMovementGenerator(Unit* unit) + { + MovementGeneratorType type = IDLE_MOTION_TYPE; + if (unit->GetTypeId() == TYPEID_UNIT) + type = unit->ToCreature()->GetDefaultMovementType(); - std::string ainame = (ai_factory == NULL || go->GetScriptId()) ? "NullGameObjectAI" : ai_factory->key(); + MovementGeneratorCreator const* mv_factory = sMovementGeneratorRegistry->GetRegistryItem(type); + return ASSERT_NOTNULL(mv_factory)->Create(unit); + } - TC_LOG_DEBUG("scripts", "%s used AI is %s.", go->GetGUID().ToString().c_str(), ainame.c_str()); + GameObjectAI* SelectGameObjectAI(GameObject* go) + { + // scriptname in db + if (GameObjectAI* scriptedAI = sScriptMgr->GetGameObjectAI(go)) + return scriptedAI; - return (ai_factory == NULL ? new NullGameObjectAI(go) : ai_factory->Create(go)); + return SelectFactory<GameObjectAI>(go)->Create(go); } } diff --git a/src/server/game/AI/CreatureAISelector.h b/src/server/game/AI/CreatureAISelector.h index d22bf0bb1e7..b4046a5e982 100644 --- a/src/server/game/AI/CreatureAISelector.h +++ b/src/server/game/AI/CreatureAISelector.h @@ -21,13 +21,14 @@ class CreatureAI; class Creature; class MovementGenerator; +class Unit; class GameObjectAI; class GameObject; namespace FactorySelector { - TC_GAME_API CreatureAI* selectAI(Creature*); - TC_GAME_API MovementGenerator* selectMovementGenerator(Creature*); - TC_GAME_API GameObjectAI* SelectGameObjectAI(GameObject*); + TC_GAME_API CreatureAI* SelectAI(Creature* creature); + TC_GAME_API MovementGenerator* SelectMovementGenerator(Unit* unit); + TC_GAME_API GameObjectAI* SelectGameObjectAI(GameObject* go); } #endif diff --git a/src/server/game/AI/GameObjectAIFactory.h b/src/server/game/AI/GameObjectAIFactory.h new file mode 100644 index 00000000000..88dcb5cbb81 --- /dev/null +++ b/src/server/game/AI/GameObjectAIFactory.h @@ -0,0 +1,54 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITY_GAMEOBJECTAIFACTORY_H +#define TRINITY_GAMEOBJECTAIFACTORY_H + +#include "ObjectRegistry.h" +#include "FactoryHolder.h" + +class GameObject; +class GameObjectAI; + +typedef FactoryHolder<GameObjectAI, GameObject> GameObjectAICreator; + +struct SelectableGameObjectAI : public GameObjectAICreator, public Permissible<GameObject> +{ + SelectableGameObjectAI(std::string const& name) : GameObjectAICreator(name), Permissible<GameObject>() { } +}; + +template<class REAL_GO_AI> +struct GameObjectAIFactory : public SelectableGameObjectAI +{ + GameObjectAIFactory(std::string const& name) : SelectableGameObjectAI(name) { } + + GameObjectAI* Create(GameObject* go) const override + { + return new REAL_GO_AI(go); + } + + int32 Permit(GameObject const* go) const override + { + return REAL_GO_AI::Permissible(go); + } +}; + +typedef GameObjectAICreator::FactoryHolderRegistry GameObjectAIRegistry; + +#define sGameObjectAIRegistry GameObjectAIRegistry::instance() + +#endif diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 71125e716a6..bde3a192642 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -537,7 +537,7 @@ bool BossAI::CanAIAttack(Unit const* target) const return CheckBoundary(target); } -void BossAI::_DespawnAtEvade(uint32 delayToRespawn, Creature* who) +void BossAI::_DespawnAtEvade(uint32 delayToRespawn /*= 30*/, Creature* who /*= nullptr*/) { if (delayToRespawn < 2) { diff --git a/src/server/game/AI/ScriptedAI/ScriptedGossip.cpp b/src/server/game/AI/ScriptedAI/ScriptedGossip.cpp index 0e0ad589518..33e69bf850c 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedGossip.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedGossip.cpp @@ -19,6 +19,7 @@ #include "Creature.h" #include "Player.h" +uint32 GetGossipActionFor(Player* player, uint32 gossipListId) { return player->PlayerTalkClass->GetGossipOptionAction(gossipListId); } void ClearGossipMenuFor(Player* player) { player->PlayerTalkClass->ClearMenus(); } // Using provided text, not from DB void AddGossipItemFor(Player* player, uint32 icon, std::string const& text, uint32 sender, uint32 action) { player->PlayerTalkClass->GetGossipMenu().AddMenuItem(-1, icon, text, sender, action, "", 0); } diff --git a/src/server/game/AI/ScriptedAI/ScriptedGossip.h b/src/server/game/AI/ScriptedAI/ScriptedGossip.h index 3032059d81b..6963155c94a 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedGossip.h +++ b/src/server/game/AI/ScriptedAI/ScriptedGossip.h @@ -86,6 +86,7 @@ enum eTradeskill GOSSIP_SENDER_SEC_STABLEMASTER = 10 }; +uint32 TC_GAME_API GetGossipActionFor(Player* player, uint32 gossipListId); void TC_GAME_API ClearGossipMenuFor(Player* player); // Using provided text, not from DB void TC_GAME_API AddGossipItemFor(Player* player, uint32 icon, std::string const& text, uint32 sender, uint32 action); diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 2dd122de1ee..065ca31bee0 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -74,6 +74,8 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c) mJustReset = false; mConditionsTimer = 0; mHasConditions = sConditionMgr->HasConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, c->GetEntry()); + + _gossipReturn = false; } bool SmartAI::IsAIControlled() const @@ -594,13 +596,6 @@ void SmartAI::JustRespawned() mFollowCreditType = 0; } -int SmartAI::Permissible(const Creature* creature) -{ - if (creature->GetAIName() == "SmartAI") - return PERMIT_BASE_SPECIAL; - return PERMIT_BASE_NO; -} - void SmartAI::JustReachedHome() { GetScript()->OnReset(); @@ -810,14 +805,16 @@ void SmartAI::SetEvadeDisabled(bool disable) bool SmartAI::GossipHello(Player* player) { + _gossipReturn = false; GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_HELLO, player); - return false; + return _gossipReturn; } bool SmartAI::GossipSelect(Player* player, uint32 menuId, uint32 gossipListId) { + _gossipReturn = false; GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_SELECT, player, menuId, gossipListId); - return false; + return _gossipReturn; } bool SmartAI::GossipSelectCode(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/, const char* /*code*/) @@ -962,13 +959,6 @@ void SmartAI::CheckConditions(uint32 diff) mConditionsTimer -= diff; } -int SmartGameObjectAI::Permissible(const GameObject* g) -{ - if (g->GetAIName() == "SmartGameObjectAI") - return PERMIT_BASE_SPECIAL; - return PERMIT_BASE_NO; -} - void SmartGameObjectAI::UpdateAI(uint32 diff) { GetScript()->OnUpdate(diff); @@ -995,16 +985,17 @@ void SmartGameObjectAI::Reset() // Called when a player opens a gossip dialog with the gameobject. bool SmartGameObjectAI::GossipHello(Player* player, bool reportUse) { - TC_LOG_DEBUG("scripts.ai", "SmartGameObjectAI::GossipHello"); + _gossipReturn = false; GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_HELLO, player, uint32(reportUse), 0, false, nullptr, me); - return false; + return _gossipReturn; } // Called when a player selects a gossip item in the gameobject's gossip menu. bool SmartGameObjectAI::GossipSelect(Player* player, uint32 sender, uint32 action) { + _gossipReturn = false; GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_SELECT, player, sender, action, false, nullptr, me); - return false; + return _gossipReturn; } // Called when a player selects a gossip with a code in the gameobject's gossip menu. diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 1c65c9633b9..070165efa40 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -158,7 +158,7 @@ class TC_GAME_API SmartAI : public CreatureAI ObjectGuid GetGUID(int32 id = 0) const override; //core related - static int Permissible(const Creature*); + static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } // Called at movepoint reached void MovepointReached(uint32 id); @@ -198,6 +198,8 @@ class TC_GAME_API SmartAI : public CreatureAI void SetWPPauseTimer(uint32 time) { mWPPauseTimer = time; } + void SetGossipReturn(bool val) { _gossipReturn = val; } + private: bool mIsCharmed; uint32 mFollowCreditType; @@ -241,19 +243,22 @@ class TC_GAME_API SmartAI : public CreatureAI void CheckConditions(uint32 diff); bool mHasConditions; uint32 mConditionsTimer; + + // Gossip + bool _gossipReturn; }; class TC_GAME_API SmartGameObjectAI : public GameObjectAI { public: - SmartGameObjectAI(GameObject* g) : GameObjectAI(g) { } + SmartGameObjectAI(GameObject* g) : GameObjectAI(g), _gossipReturn(false) { } ~SmartGameObjectAI() { } void UpdateAI(uint32 diff) override; void InitializeAI() override; void Reset() override; SmartScript* GetScript() { return &mScript; } - static int Permissible(const GameObject* g); + static int32 Permissible(GameObject const* /*go*/) { return PERMIT_BASE_NO; } bool GossipHello(Player* player, bool reportUse) override; bool GossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override; @@ -268,8 +273,13 @@ class TC_GAME_API SmartGameObjectAI : public GameObjectAI void EventInform(uint32 eventId) override; void SpellHit(Unit* unit, const SpellInfo* spellInfo) override; + void SetGossipReturn(bool val) { _gossipReturn = val; } + private: SmartScript mScript; + + // Gossip + bool _gossipReturn; }; /// Registers scripts required by the SAI scripting system diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index ebf884133a4..a1c6d3af9b6 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -2411,7 +2411,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } case SMART_ACTION_SEND_GOSSIP_MENU: { - if (!GetBaseObject()) + if (!GetBaseObject() || !IsSmart()) break; TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SEND_GOSSIP_MENU: gossipMenuId %d, gossipNpcTextId %d", @@ -2421,6 +2421,12 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (!targets) break; + // override default gossip + if (me) + ENSURE_AI(SmartAI, me->AI())->SetGossipReturn(true); + else if (go) + ENSURE_AI(SmartGameObjectAI, go->AI())->SetGossipReturn(true); + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { if (Player* player = (*itr)->ToPlayer()) diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 05931ce840e..68b3d673a15 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -562,17 +562,17 @@ enum RBACPermissions RBAC_PERM_COMMAND_RELOAD_ITEM_LOOT_TEMPLATE = 654, RBAC_PERM_COMMAND_RELOAD_ITEM_SET_NAMES = 655, RBAC_PERM_COMMAND_RELOAD_LFG_DUNGEON_REWARDS = 656, - RBAC_PERM_COMMAND_RELOAD_LOCALES_ACHIEVEMENT_REWARD = 657, - RBAC_PERM_COMMAND_RELOAD_LOCALES_CRETURE = 658, - RBAC_PERM_COMMAND_RELOAD_LOCALES_CRETURE_TEXT = 659, - RBAC_PERM_COMMAND_RELOAD_LOCALES_GAMEOBJECT = 660, - RBAC_PERM_COMMAND_RELOAD_LOCALES_GOSSIP_MENU_OPTION = 661, - RBAC_PERM_COMMAND_RELOAD_LOCALES_ITEM = 662, // deprecated since Draenor DON'T reuse - RBAC_PERM_COMMAND_RELOAD_LOCALES_ITEM_SET_NAME = 663, - RBAC_PERM_COMMAND_RELOAD_LOCALES_NPC_TEXT = 664, // deprecated since Draenor DON'T reuse - RBAC_PERM_COMMAND_RELOAD_LOCALES_PAGE_TEXT = 665, - RBAC_PERM_COMMAND_RELOAD_LOCALES_POINTS_OF_INTEREST = 666, - RBAC_PERM_COMMAND_RELOAD_QUEST_LOCALE = 667, + RBAC_PERM_COMMAND_RELOAD_ACHIEVEMENT_REWARD_LOCALE = 657, + RBAC_PERM_COMMAND_RELOAD_CRETURE_TEMPLATE_LOCALE = 658, + RBAC_PERM_COMMAND_RELOAD_CRETURE_TEXT_LOCALE = 659, + RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_TEMPLATE_LOCALE = 660, + RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU_OPTION_LOCALE = 661, + RBAC_PERM_COMMAND_RELOAD_ITEM_TEMPLATE_LOCALE = 662, // deprecated since Draenor DON'T reus + RBAC_PERM_COMMAND_RELOAD_ITEM_SET_NAME_LOCALE = 663, + RBAC_PERM_COMMAND_RELOAD_NPC_TEXT_LOCALE = 664, // deprecated since Draenor DON'T reuse + RBAC_PERM_COMMAND_RELOAD_PAGE_TEXT_LOCALE = 665, + RBAC_PERM_COMMAND_RELOAD_POINTS_OF_INTEREST_LOCALE = 666, + RBAC_PERM_COMMAND_RELOAD_QUEST_TEMPLATE_LOCALE = 667, RBAC_PERM_COMMAND_RELOAD_MAIL_LEVEL_REWARD = 668, RBAC_PERM_COMMAND_RELOAD_MAIL_LOOT_TEMPLATE = 669, RBAC_PERM_COMMAND_RELOAD_MILLING_LOOT_TEMPLATE = 670, @@ -760,6 +760,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_GO_OFFSET = 852, RBAC_PERM_COMMAND_RELOAD_CONVERSATION_TEMPLATE = 853, RBAC_PERM_COMMAND_DEBUG_CONVERSATION = 854, + RBAC_PERM_COMMAND_DEBUG_PLAY_MUSIC = 855, RBAC_PERM_COMMAND_NPC_SPAWNGROUP = 856, // reserved for dynamic_spawning RBAC_PERM_COMMAND_NPC_DESPAWNGROUP = 857, // reserved for dynamic_spawning RBAC_PERM_COMMAND_GOBJECT_SPAWNGROUP = 858, // reserved for dynamic_spawning diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp index 6e1bba5f1a9..62e37f5d76b 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp @@ -57,7 +57,7 @@ BfWGCoordGY const WGGraveYard[BATTLEFIELD_WG_GRAVEYARD_MAX] = }; uint32 const ClockWorldState[] = { 3781, 4354 }; -uint32 const WintergraspFaction[] = { 1732, 1735, 35 }; +uint32 const WintergraspFaction[] = { FACTION_ALLIANCE_GENERIC_WG, FACTION_HORDE_GENERIC_WG, FACTION_FRIENDLY }; Position const WintergraspStalkerPos = { 4948.985f, 2937.789f, 550.5172f, 1.815142f }; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp index edd6d3e67ed..31345c14048 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp @@ -384,7 +384,7 @@ void BattlegroundAB::_NodeOccupied(uint8 node, Team team) //aura should only apply to players who have accupied the node, set correct faction for trigger if (trigger) { - trigger->SetFaction(team == ALLIANCE ? 84 : 83); + trigger->SetFaction(team == ALLIANCE ? FACTION_ALLIANCE_GENERIC : FACTION_HORDE_GENERIC); trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false); } } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp index 3fc2cd2ad8d..ff37ce06346 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp @@ -757,7 +757,7 @@ void BattlegroundAV::PopulateNode(BG_AV_Nodes node) DelCreature(node + 302); return; } - trigger->SetFaction(owner == ALLIANCE ? 84 : 83); + trigger->SetFaction(owner == ALLIANCE ? FACTION_ALLIANCE_GENERIC : FACTION_HORDE_GENERIC); trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false); } } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp index c83e1ff48b1..8c4143e0ce3 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp @@ -810,7 +810,7 @@ void BattlegroundEY::EventTeamCapturedPoint(Player* player, uint32 Point) //aura should only apply to players who have accupied the node, set correct faction for trigger if (trigger) { - trigger->SetFaction(Team == ALLIANCE ? 84 : 83); + trigger->SetFaction(Team == ALLIANCE ? FACTION_ALLIANCE_GENERIC : FACTION_HORDE_GENERIC); trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false); } } diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 2d66f88a745..ba761b95ed0 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -978,7 +978,7 @@ bool Creature::AIM_Create(CreatureAI* ai /*= nullptr*/) Motion_Initialize(); - i_AI = ai ? ai : FactorySelector::selectAI(this); + i_AI = ai ? ai : FactorySelector::SelectAI(this); return true; } @@ -2048,27 +2048,34 @@ void Creature::ForcedDespawn(uint32 timeMSToDespawn, Seconds const& forceRespawn { if (timeMSToDespawn) { - ForcedDespawnDelayEvent* pEvent = new ForcedDespawnDelayEvent(*this, forceRespawnTimer); - - m_Events.AddEvent(pEvent, m_Events.CalculateTime(timeMSToDespawn)); + m_Events.AddEvent(new ForcedDespawnDelayEvent(*this, forceRespawnTimer), m_Events.CalculateTime(timeMSToDespawn)); return; } + uint32 corpseDelay = GetCorpseDelay(); + uint32 respawnDelay = GetRespawnDelay(); + // do it before killing creature DestroyForNearbyPlayers(); + bool overrideRespawnTime = false; if (IsAlive()) - setDeathState(JUST_DIED); - - bool overrideRespawnTime = true; - if (forceRespawnTimer > Seconds::zero()) { - SetRespawnTime(forceRespawnTimer.count()); - overrideRespawnTime = false; + if (forceRespawnTimer > Seconds::zero()) + { + SetCorpseDelay(0); + SetRespawnDelay(forceRespawnTimer.count()); + overrideRespawnTime = false; + } + + setDeathState(JUST_DIED); } // Skip corpse decay time RemoveCorpse(overrideRespawnTime, false); + + SetCorpseDelay(corpseDelay); + SetRespawnDelay(respawnDelay); } void Creature::DespawnOrUnsummon(uint32 msTimeToDespawn /*= 0*/, Seconds const& forceRespawnTimer /*= 0*/) @@ -2418,14 +2425,9 @@ bool Creature::_IsTargetAcceptable(Unit const* target) const Unit const* targetVictim = target->getAttackerForHelper(); // if I'm already fighting target, or I'm hostile towards the target, the target is acceptable - if (GetVictim() == target || IsHostileTo(target)) + if (IsInCombatWith(target) || IsHostileTo(target)) return true; - // a player is targeting me, but I'm not hostile towards it, and not currently attacking it, the target is not acceptable - // (players may set their victim from a distance, and doesn't mean we should attack) - if (target->GetTypeId() == TYPEID_PLAYER && targetVictim == this) - return false; - // if the target's victim is friendly, and the target is neutral, the target is acceptable if (targetVictim && IsFriendlyTo(targetVictim)) return true; @@ -2808,7 +2810,7 @@ uint8 Creature::GetLevelForTarget(WorldObject const* target) const return Unit::GetLevelForTarget(target); } -std::string Creature::GetAIName() const +std::string const& Creature::GetAIName() const { return sObjectMgr->GetCreatureTemplate(GetEntry())->AIName; } @@ -2943,20 +2945,6 @@ float Creature::GetPetChaseDistance() const return range; } -void Creature::SetPosition(float x, float y, float z, float o) -{ - // prevent crash when a bad coord is sent by the client - if (!Trinity::IsValidMapCoord(x, y, z, o)) - { - TC_LOG_DEBUG("entities.unit", "Creature::SetPosition(%f, %f, %f) .. bad coordinates!", x, y, z); - return; - } - - GetMap()->CreatureRelocation(this, x, y, z, o); - if (IsVehicle()) - GetVehicleKit()->RelocatePassengers(); -} - float Creature::GetAggroRange(Unit const* target) const { // Determines the aggro range for creatures (usually pets), used mainly for aggressive pet target selection. @@ -3217,8 +3205,7 @@ bool Creature::IsMovementPreventedByCasting() const { if (spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive()) if (spell->GetSpellInfo()->IsMoveAllowedChannel()) - if (HasUnitState(UNIT_STATE_CASTING)) - return true; + return false; } if (const_cast<Creature*>(this)->IsFocusing(nullptr, true)) diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index cc5608bfc3d..beb9ed4d64f 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -172,7 +172,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma CreatureData const* GetCreatureData() const { return m_creatureData; } CreatureAddon const* GetCreatureAddon() const; - std::string GetAIName() const; + std::string const& GetAIName() const; std::string GetScriptName() const; uint32 GetScriptId() const; @@ -282,9 +282,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma void SetCannotReachTarget(bool cannotReach) { if (cannotReach == m_cannotReachTarget) return; m_cannotReachTarget = cannotReach; m_cannotReachTimer = 0; } bool CanNotReachTarget() const { return m_cannotReachTarget; } - void SetPosition(float x, float y, float z, float o); - void SetPosition(const Position &pos) { SetPosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); } - void SetHomePosition(float x, float y, float z, float o) { m_homePosition.Relocate(x, y, z, o); } void SetHomePosition(const Position &pos) { m_homePosition.Relocate(pos); } void GetHomePosition(float& x, float& y, float& z, float& ori) const { m_homePosition.GetPosition(x, y, z, ori); } diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 4059e6e72d6..cd3ebd306ea 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -166,12 +166,9 @@ bool GameObject::AIM_Initialize() return true; } -std::string GameObject::GetAIName() const +std::string const& GameObject::GetAIName() const { - if (GameObjectTemplate const* got = sObjectMgr->GetGameObjectTemplate(GetEntry())) - return got->AIName; - - return ""; + return sObjectMgr->GetGameObjectTemplate(GetEntry())->AIName; } void GameObject::CleanupsBeforeDelete(bool finalCleanup) @@ -2121,7 +2118,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId, TriggerCastFlags trigge } else { - trigger->SetFaction(spellInfo->IsPositive() ? 35 : 14); + trigger->SetFaction(spellInfo->IsPositive() ? FACTION_FRIENDLY : FACTION_MONSTER); // Set owner guid for target if no owner available - needed by trigger auras // - trigger gets despawned and there's no caster avalible (see AuraEffect::TriggerSpell()) trigger->CastSpell(target ? target : trigger, spellInfo, triggered, nullptr, nullptr, target ? target->GetGUID() : ObjectGuid::Empty); diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index da06d1842f8..7bbf09a26ad 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -283,7 +283,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject> uint32 GetScriptId() const; GameObjectAI* AI() const { return m_AI; } - std::string GetAIName() const; + std::string const& GetAIName() const; void SetDisplayId(uint32 displayid); uint32 GetDisplayId() const { return m_gameObjectData->DisplayID; } uint8 GetNameSetId() const; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 32f2be86bd9..939d7e750d1 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2105,8 +2105,8 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid const& guid, NPCFlags npcFl if (creature->GetReactionTo(this) <= REP_UNFRIENDLY) return nullptr; - // not too far - if (!creature->IsWithinDistInMap(this, INTERACTION_DISTANCE)) + // not too far, taken from CGGameUI::SetInteractTarget + if (!creature->IsWithinDistInMap(this, creature->GetCombatReach() + 4.0f)) return nullptr; return creature; @@ -2114,33 +2114,36 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid const& guid, NPCFlags npcFl GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid const& guid) const { - if (GameObject* go = GetMap()->GetGameObject(guid)) - { - if (go->IsWithinDistInMap(this, go->GetInteractionDistance())) - return go; + if (!guid) + return nullptr; - TC_LOG_DEBUG("maps", "Player::GetGameObjectIfCanInteractWith: GameObject '%s' (%s) is too far away from player '%s' (%s) to be used by him (Distance: %f, maximal %f is allowed)", - go->GetGOInfo()->name.c_str(), go->GetGUID().ToString().c_str(), GetName().c_str(), GetGUID().ToString().c_str(), go->GetDistance(this), go->GetInteractionDistance()); - } + if (!IsInWorld()) + return nullptr; - return nullptr; + if (IsInFlight()) + return nullptr; + + // exist + GameObject* go = ObjectAccessor::GetGameObject(*this, guid); + if (!go) + return nullptr; + + if (!go->IsWithinDistInMap(this, go->GetInteractionDistance())) + return nullptr; + + return go; } GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid const& guid, GameobjectTypes type) const { - if (GameObject* go = GetMap()->GetGameObject(guid)) - { - if (go->GetGoType() == type) - { - if (go->IsWithinDistInMap(this, go->GetInteractionDistance())) - return go; + GameObject* go = GetGameObjectIfCanInteractWith(guid); + if (!go) + return nullptr; - TC_LOG_DEBUG("maps", "Player::GetGameObjectIfCanInteractWith: GameObject '%s' (%s) is too far away from player '%s' (%s) to be used by him (Distance: %f, maximal %f is allowed)", - go->GetGOInfo()->name.c_str(), go->GetGUID().ToString().c_str(), GetName().c_str(), GetGUID().ToString().c_str(), go->GetDistance(this), go->GetInteractionDistance()); - } - } + if (go->GetGoType() != type) + return nullptr; - return nullptr; + return go; } bool Player::IsUnderWater() const @@ -2201,13 +2204,13 @@ void Player::SetGameMaster(bool on) if (on) { m_ExtraFlags |= PLAYER_EXTRA_GM_ON; - SetFaction(35); + SetFaction(FACTION_FRIENDLY); AddPlayerFlag(PLAYER_FLAGS_GM); AddUnitFlag2(UNIT_FLAG2_ALLOW_CHEAT_SPELLS); if (Pet* pet = GetPet()) { - pet->SetFaction(35); + pet->SetFaction(FACTION_FRIENDLY); pet->getHostileRefManager().setOnlineOfflineState(false); } @@ -16604,7 +16607,6 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) QuestRelationBounds qr; QuestRelationBounds qir; - PlayerTalkClass->ClearMenus(); switch (questgiver->GetTypeId()) { case TYPEID_GAMEOBJECT: @@ -16832,9 +16834,7 @@ void Player::AreaExploredOrEventHappens(uint32 questId) q_status.Explored = true; m_QuestStatusSave[questId] = QUEST_DEFAULT_SAVE_TYPE; - // if we cannot complete quest send exploration succeded (to mark exploration on client) - if (!CanCompleteQuest(questId)) - SendQuestComplete(questId); + SendQuestComplete(questId); }**/ } if (CanCompleteQuest(questId)) @@ -25390,18 +25390,24 @@ void Player::ResurrectUsingRequestData() void Player::ResurrectUsingRequestDataImpl() { + // save health and mana before resurrecting, _resurrectionData can be erased + uint32 resurrectHealth = _resurrectionData->Health; + uint32 resurrectMana = _resurrectionData->Mana; + uint32 resurrectAura = _resurrectionData->Aura; + ObjectGuid resurrectGUID = _resurrectionData->GUID; + ResurrectPlayer(0.0f, false); - SetHealth(_resurrectionData->Health); - SetPower(POWER_MANA, _resurrectionData->Mana); + SetHealth(resurrectHealth); + SetPower(POWER_MANA, resurrectMana); SetPower(POWER_RAGE, 0); SetFullPower(POWER_ENERGY); SetFullPower(POWER_FOCUS); SetPower(POWER_LUNAR_POWER, 0); - if (uint32 aura = _resurrectionData->Aura) - CastSpell(this, aura, true, nullptr, nullptr, _resurrectionData->GUID); + if (uint32 aura = resurrectAura) + CastSpell(this, aura, true, nullptr, nullptr, resurrectGUID); SpawnCorpseBones(); } diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index c4c7d2a971d..c261fdef73b 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -154,8 +154,8 @@ void Transport::Update(uint32 diff) if (timer < _currentFrame->DepartureTime) { + justStopped = IsMoving(); SetMoving(false); - justStopped = true; if (_pendingStop && GetGoState() != GO_STATE_READY) { SetGoState(GO_STATE_READY); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 29f2d6433ce..6d5b164f594 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3391,7 +3391,14 @@ void Unit::_ApplyAura(AuraApplication * aurApp, uint32 effMask) // Update target aura state flag if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState()) - ModifyAuraState(aState, true); + { + uint32 aStateMask = (1 << (aState - 1)); + // force update so the new caster registers it + if ((aStateMask & PER_CASTER_AURA_STATE_MASK) && *m_unitData->AuraState & aStateMask) + ForceUpdateFieldChange(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::AuraState)); + else + ModifyAuraState(aState, true); + } if (aurApp->GetRemoveMode()) return; @@ -3484,9 +3491,19 @@ void Unit::_UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMo ToTotem()->setDeathState(JUST_DIED); } - // Remove aurastates only if were not found - if (!auraStateFound) - ModifyAuraState(auraState, false); + // Remove aurastates only if needed and were not found + if (auraState) + { + if (!auraStateFound) + ModifyAuraState(auraState, false); + else + { + // update for casters, some shouldn't 'see' the aura state + uint32 aStateMask = (1 << (auraState - 1)); + if ((aStateMask & PER_CASTER_AURA_STATE_MASK) != 0) + ForceUpdateFieldChange(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::AuraState)); + } + } aura->HandleAuraSpecificMods(aurApp, caster, false, false); @@ -5618,13 +5635,22 @@ void Unit::_removeAttacker(Unit* pAttacker) Unit* Unit::getAttackerForHelper() const // If someone wants to help, who to give them { - if (GetVictim() != NULL) - return GetVictim(); + if (Unit* victim = GetVictim()) + if (!IsControlledByPlayer() || IsInCombatWith(victim) || victim->IsInCombatWith(this)) + return victim; if (!m_attackers.empty()) return *(m_attackers.begin()); - return NULL; + if (Player* owner = GetCharmerOrOwnerPlayerOrPlayerItself()) + { + HostileRefManager& refs = owner->getHostileRefManager(); + for (Reference<Unit, ThreatManager> const& ref : refs) + if (Unit* hostile = ref.GetSource()->GetOwner()) + return hostile; + } + + return nullptr; } bool Unit::Attack(Unit* victim, bool meleeAttack) @@ -5640,6 +5666,11 @@ bool Unit::Attack(Unit* victim, bool meleeAttack) if (GetTypeId() == TYPEID_PLAYER && IsMounted()) return false; + Creature* creature = ToCreature(); + // creatures cannot attack while evading + if (creature && creature->IsInEvadeMode()) + return false; + if (HasUnitFlag(UNIT_FLAG_PACIFIED)) return false; @@ -5704,7 +5735,7 @@ bool Unit::Attack(Unit* victim, bool meleeAttack) //if (GetTypeId() == TYPEID_UNIT) // ToCreature()->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ()); - if (GetTypeId() == TYPEID_UNIT && !IsPet()) + if (creature && !IsPet()) { // should not let player enter combat by right clicking target - doesn't helps AddThreat(victim, 0.0f); @@ -5712,8 +5743,8 @@ bool Unit::Attack(Unit* victim, bool meleeAttack) if (victim->GetTypeId() == TYPEID_PLAYER) victim->SetInCombatWith(this); - ToCreature()->SendAIReaction(AI_REACTION_HOSTILE); - ToCreature()->CallAssistance(); + creature->SendAIReaction(AI_REACTION_HOSTILE); + creature->CallAssistance(); // Remove emote state - will be restored on creature reset SetEmoteState(EMOTE_ONESHOT_NONE); @@ -5728,7 +5759,7 @@ bool Unit::Attack(Unit* victim, bool meleeAttack) // Let the pet know we've started attacking someting. Handles melee attacks only // Spells such as auto-shot and others handled in WorldSession::HandleCastSpellOpcode - if (this->GetTypeId() == TYPEID_PLAYER) + if (GetTypeId() == TYPEID_PLAYER) { Pet* playerPet = this->ToPlayer()->GetPet(); @@ -8726,8 +8757,6 @@ void Unit::setDeathState(DeathState s) if (s == JUST_DIED) { - ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); - ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); // remove aurastates allowing special moves ClearAllReactives(); ClearDiminishings(); @@ -10616,13 +10645,13 @@ Player* Unit::GetSpellModOwner() const if (Player* player = const_cast<Unit*>(this)->ToPlayer()) return player; - if (IsPet() || IsTotem()) + if (HasUnitTypeMask(UNIT_MASK_PET | UNIT_MASK_TOTEM | UNIT_MASK_GUARDIAN)) { if (Unit* owner = GetOwner()) if (Player* player = owner->ToPlayer()) return player; } - return NULL; + return nullptr; } ///----------Pet responses methods----------------- diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index e38539429ae..c616ee11270 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -21,10 +21,12 @@ #include "AzeriteItem.h" #include "Chat.h" #include "Containers.h" +#include "CreatureAIFactory.h" #include "DatabaseEnv.h" #include "DB2Stores.h" #include "DisableMgr.h" #include "GameObject.h" +#include "GameObjectAIFactory.h" #include "GameTables.h" #include "GridDefines.h" #include "GossipDef.h" @@ -935,6 +937,12 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) ok = true; } + if (!cInfo->AIName.empty() && !sCreatureAIRegistry->HasItem(cInfo->AIName)) + { + TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has non-registered `AIName` '%s' set, removing", cInfo->Entry, cInfo->AIName.c_str()); + const_cast<CreatureTemplate*>(cInfo)->AIName.clear(); + } + FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction); if (!factionTemplate) { @@ -2048,6 +2056,12 @@ void ObjectMgr::LoadCreatures() TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: " UI64FMTD " Entry: %u) with `creature_template`.`flags_extra` including CREATURE_FLAG_EXTRA_INSTANCE_BIND but creature is not in instance.", guid, data.id); } + if (data.movementType >= MAX_DB_MOTION_TYPE) + { + TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: " UI64FMTD " Entry: %u) with wrong movement generator type (%u), ignored and set to IDLE.", guid, data.id, data.movementType); + data.movementType = IDLE_MOTION_TYPE; + } + if (data.spawndist < 0.0f) { TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: " UI64FMTD " Entry: %u) with `spawndist`< 0, set to 0.", guid, data.id); @@ -7061,6 +7075,11 @@ void ObjectMgr::LoadGameObjectTemplate() got.ScriptId = GetScriptId(fields[44].GetString()); // Checks + if (!got.AIName.empty() && !sGameObjectAIRegistry->HasItem(got.AIName)) + { + TC_LOG_ERROR("sql.sql", "GameObject (Entry: %u) has non-registered `AIName` '%s' set, removing", got.entry, got.AIName.c_str()); + got.AIName.clear(); + } switch (got.type) { diff --git a/src/server/game/Groups/GroupMgr.cpp b/src/server/game/Groups/GroupMgr.cpp index 314c74c1766..53d8fb5a877 100644 --- a/src/server/game/Groups/GroupMgr.cpp +++ b/src/server/game/Groups/GroupMgr.cpp @@ -203,10 +203,13 @@ void GroupMgr::LoadGroups() TC_LOG_INFO("server.loading", "Loading Group instance saves..."); { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 4 5 6 7 - QueryResult result = CharacterDatabase.Query("SELECT gi.guid, i.map, gi.instance, gi.permanent, i.difficulty, i.resettime, i.entranceId, COUNT(g.guid) " - "FROM group_instance gi INNER JOIN instance i ON gi.instance = i.id " - "LEFT JOIN character_instance ci LEFT JOIN `groups` g ON g.leaderGuid = ci.guid ON ci.instance = gi.instance AND ci.permanent = 1 GROUP BY gi.instance ORDER BY gi.guid"); + + // 0 1 2 3 4 5 6 + QueryResult result = CharacterDatabase.Query("SELECT gi.guid, i.map, gi.instance, gi.permanent, i.difficulty, i.resettime, i.entranceId, " + // 7 + "(SELECT COUNT(1) FROM character_instance ci LEFT JOIN groups g ON ci.guid = g.leaderGuid WHERE ci.instance = gi.instance AND ci.permanent = 1 LIMIT 1) " + "FROM group_instance gi LEFT JOIN instance i ON gi.instance = i.id ORDER BY guid"); + if (!result) { TC_LOG_INFO("server.loading", ">> Loaded 0 group-instance saves. DB table `group_instance` is empty!"); @@ -232,7 +235,7 @@ void GroupMgr::LoadGroups() if (!difficultyEntry || difficultyEntry->InstanceType != mapEntry->InstanceType) continue; - InstanceSave* save = sInstanceSaveMgr->AddInstanceSave(mapEntry->ID, fields[2].GetUInt32(), Difficulty(diff), time_t(fields[5].GetUInt32()), fields[6].GetUInt32(), fields[7].GetUInt64() != 0, true); + InstanceSave* save = sInstanceSaveMgr->AddInstanceSave(mapEntry->ID, fields[2].GetUInt32(), Difficulty(diff), time_t(fields[5].GetUInt32()), fields[6].GetUInt32(), fields[7].GetUInt64() == 0, true); group->BindToInstance(save, fields[3].GetBool(), true); ++count; } diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 2e7d7e81ddb..03b0f954ccd 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -189,6 +189,51 @@ enum ReputationRank REP_EXALTED = 7 }; +enum FactionTemplates +{ + FACTION_NONE = 0, + FACTION_CREATURE = 7, + FACTION_ESCORTEE_A_NEUTRAL_PASSIVE = 10, + FACTION_MONSTER = 14, + FACTION_MONSTER_2 = 16, + FACTION_TROLL_BLOODSCALP = 28, + FACTION_PREY = 31, + FACTION_ESCORTEE_H_NEUTRAL_PASSIVE = 33, + FACTION_FRIENDLY = 35, + FACTION_OGRE = 45, + FACTION_ORC_DRAGONMAW = 62, + FACTION_HORDE_GENERIC = 83, + FACTION_ALLIANCE_GENERIC = 84, + FACTION_DEMON = 90, + FACTION_ELEMENTAL = 91, + FACTION_DRAGONFLIGHT_BLACK = 103, + FACTION_ESCORTEE_N_NEUTRAL_PASSIVE = 113, + FACTION_ENEMY = 168, + FACTION_ESCORTEE_A_NEUTRAL_ACTIVE = 231, + FACTION_ESCORTEE_H_NEUTRAL_ACTIVE = 232, + FACTION_ESCORTEE_N_NEUTRAL_ACTIVE = 250, + FACTION_ESCORTEE_N_FRIEND_PASSIVE = 290, + FACTION_TITAN = 415, + FACTION_ESCORTEE_N_FRIEND_ACTIVE = 495, + FACTION_GOBLIN_DARK_IRON_BAR_PATRON = 736, + FACTION_DARK_IRON_DWARVES = 754, + FACTION_ESCORTEE_A_PASSIVE = 774, + FACTION_ESCORTEE_H_PASSIVE = 775, + FACTION_UNDEAD_SCOURGE = 974, + FACTION_EARTHEN_RING = 1726, + FACTION_ALLIANCE_GENERIC_WG = 1732, + FACTION_HORDE_GENERIC_WG = 1735, + FACTION_ARAKKOA = 1738, + FACTION_ASHTONGUE_DEATHSWORN = 1820, + FACTION_FLAYER_HUNTER = 1840, + FACTION_MONSTER_SPAR_BUDDY = 1868, + FACTION_ESCORTEE_N_ACTIVE = 1986, + FACTION_ESCORTEE_H_ACTIVE = 2046, + FACTION_UNDEAD_SCOURGE_2 = 2068, + FACTION_UNDEAD_SCOURGE_3 = 2084, + FACTION_SCARLET_CRUSADE = 2089 +}; + #define MIN_REPUTATION_RANK (REP_HATED) #define MAX_REPUTATION_RANK 8 diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 3b446733bbb..295c70039e6 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -35,9 +35,14 @@ #include "MoveSplineInit.h" #include "PathGenerator.h" +inline MovementGenerator* GetIdleMovementGenerator() +{ + return sMovementGeneratorRegistry->GetRegistryItem(IDLE_MOTION_TYPE)->Create(); +} + inline bool IsStatic(MovementGenerator* movement) { - return (movement == &si_idleMovement); + return (movement == GetIdleMovementGenerator()); } MotionMaster::~MotionMaster() @@ -75,15 +80,7 @@ void MotionMaster::Initialize() // set new default movement generator void MotionMaster::InitDefault() { - if (_owner->GetTypeId() == TYPEID_UNIT) - { - MovementGenerator* movement = FactorySelector::selectMovementGenerator(_owner->ToCreature()); - Mutate(movement == nullptr ? &si_idleMovement : movement, MOTION_SLOT_IDLE); - } - else - { - Mutate(&si_idleMovement, MOTION_SLOT_IDLE); - } + Mutate(FactorySelector::SelectMovementGenerator(_owner), MOTION_SLOT_IDLE); } void MotionMaster::UpdateMotion(uint32 diff) @@ -198,7 +195,7 @@ void MotionMaster::MoveIdle() { //! Should be preceded by MovementExpired or Clear if there's an overlying movementgenerator active if (empty() || !IsStatic(top())) - Mutate(&si_idleMovement, MOTION_SLOT_IDLE); + Mutate(GetIdleMovementGenerator(), MOTION_SLOT_IDLE); } void MotionMaster::MoveTargetedHome() diff --git a/src/server/game/Movement/MovementGenerator.cpp b/src/server/game/Movement/MovementGenerator.cpp index 5ce585b483d..661267401d2 100644 --- a/src/server/game/Movement/MovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerator.cpp @@ -16,5 +16,12 @@ */ #include "MovementGenerator.h" +#include "IdleMovementGenerator.h" MovementGenerator::~MovementGenerator() { } + +MovementGenerator* IdleMovementFactory::Create(Unit* /*object*/) const +{ + static IdleMovementGenerator instance; + return &instance; +} diff --git a/src/server/game/Movement/MovementGenerator.h b/src/server/game/Movement/MovementGenerator.h index fdf5506dd15..4af0709aa06 100755 --- a/src/server/game/Movement/MovementGenerator.h +++ b/src/server/game/Movement/MovementGenerator.h @@ -69,20 +69,28 @@ class MovementGeneratorMedium : public MovementGenerator } }; -struct SelectableMovement : public FactoryHolder<MovementGenerator, MovementGeneratorType> +typedef FactoryHolder<MovementGenerator, Unit, MovementGeneratorType> MovementGeneratorCreator; + +template<class Movement> +struct MovementGeneratorFactory : public MovementGeneratorCreator { - SelectableMovement(MovementGeneratorType movementGeneratorType) : FactoryHolder<MovementGenerator, MovementGeneratorType>(movementGeneratorType) { } + MovementGeneratorFactory(MovementGeneratorType movementGeneratorType) : MovementGeneratorCreator(movementGeneratorType) { } + + MovementGenerator* Create(Unit* /*object*/) const override + { + return new Movement(); + } }; -template<class Movement> -struct MovementGeneratorFactory : public SelectableMovement +struct IdleMovementFactory : public MovementGeneratorCreator { - MovementGeneratorFactory(MovementGeneratorType movementGeneratorType) : SelectableMovement(movementGeneratorType) { } + IdleMovementFactory() : MovementGeneratorCreator(IDLE_MOTION_TYPE) { } - MovementGenerator* Create(void *) const override; + MovementGenerator* Create(Unit* object) const override; }; -typedef FactoryHolder<MovementGenerator, MovementGeneratorType> MovementGeneratorCreator; -typedef FactoryHolder<MovementGenerator, MovementGeneratorType>::FactoryHolderRegistry MovementGeneratorRegistry; +typedef MovementGeneratorCreator::FactoryHolderRegistry MovementGeneratorRegistry; + +#define sMovementGeneratorRegistry MovementGeneratorRegistry::instance() #endif diff --git a/src/server/game/Movement/MovementGeneratorImpl.h b/src/server/game/Movement/MovementGeneratorImpl.h deleted file mode 100644 index 0b5474b22b3..00000000000 --- a/src/server/game/Movement/MovementGeneratorImpl.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information - * - * 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 - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef TRINITY_MOVEMENTGENERATOR_IMPL_H -#define TRINITY_MOVEMENTGENERATOR_IMPL_H - -#include "MovementGenerator.h" - -template<class Movement> -inline MovementGenerator* MovementGeneratorFactory<Movement>::Create(void * /*data*/) const -{ - return (new Movement()); -} - -#endif diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp index 76b1aca3cc2..43638197578 100644 --- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp @@ -20,8 +20,6 @@ #include "Creature.h" #include <G3D/g3dmath.h> -IdleMovementGenerator si_idleMovement; - // StopMoving is needed to make unit stop if its last movement generator expires // But it should not be sent otherwise there are many redundent packets void IdleMovementGenerator::Initialize(Unit* owner) diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h index 9bb58419433..773d4dc03b7 100755 --- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h @@ -31,8 +31,6 @@ class IdleMovementGenerator : public MovementGenerator MovementGeneratorType GetMovementGeneratorType() const override { return IDLE_MOTION_TYPE; } }; -TC_GAME_API extern IdleMovementGenerator si_idleMovement; - class RotateMovementGenerator : public MovementGenerator { public: diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index b912f51cf9d..72354f47b21 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -1607,7 +1607,10 @@ bool ScriptMgr::CanSpawn(ObjectGuid::LowType spawnId, uint32 entry, CreatureTemp CreatureTemplate const* baseTemplate = sObjectMgr->GetCreatureTemplate(entry); if (!baseTemplate) baseTemplate = actTemplate; - GET_SCRIPT_RET(CreatureScript, (cData ? cData->ScriptId : baseTemplate->ScriptID), tmpscript, true); + uint32 scriptId = baseTemplate->ScriptID; + if (cData && cData->ScriptId) + scriptId = cData->ScriptId; + GET_SCRIPT_RET(CreatureScript, scriptId, tmpscript, true); return tmpscript->CanSpawn(spawnId, entry, baseTemplate, actTemplate, cData, map); } diff --git a/src/server/game/Scripting/ScriptSystem.h b/src/server/game/Scripting/ScriptSystem.h index 9f5a0ef78ce..f058bf886ee 100644 --- a/src/server/game/Scripting/ScriptSystem.h +++ b/src/server/game/Scripting/ScriptSystem.h @@ -28,30 +28,6 @@ struct SplineChainLink; #define TEXT_SOURCE_RANGE -1000000 //the amount of entries each text source has available -/// @todo find better namings and definitions. -//N=Neutral, A=Alliance, H=Horde. -//NEUTRAL or FRIEND = Hostility to player surroundings (not a good definition) -//ACTIVE or PASSIVE = Hostility to environment surroundings. -enum eEscortFaction -{ - FACTION_ESCORT_A_NEUTRAL_PASSIVE = 10, - FACTION_ESCORT_H_NEUTRAL_PASSIVE = 33, - FACTION_ESCORT_N_NEUTRAL_PASSIVE = 113, - - FACTION_ESCORT_A_NEUTRAL_ACTIVE = 231, - FACTION_ESCORT_H_NEUTRAL_ACTIVE = 232, - FACTION_ESCORT_N_NEUTRAL_ACTIVE = 250, - - FACTION_ESCORT_N_FRIEND_PASSIVE = 290, - FACTION_ESCORT_N_FRIEND_ACTIVE = 495, - - FACTION_ESCORT_A_PASSIVE = 774, - FACTION_ESCORT_H_PASSIVE = 775, - - FACTION_ESCORT_N_ACTIVE = 1986, - FACTION_ESCORT_H_ACTIVE = 2046 -}; - struct ScriptPointMove { uint32 uiCreatureEntry; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index aef183d8b97..2db4d4f8b3c 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -5896,18 +5896,6 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const } else { - // Wild Growth = amount + (6 - 2*doneTicks) * ticks* amount / 100 - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags & flag128(0, 0x04000000, 0, 0)) - { - int32 addition = int32(float(damage * GetTotalTicks()) * ((6-float(2*(GetTickNumber()-1)))/100)); - - // Item - Druid T10 Restoration 2P Bonus - if (AuraEffect* aurEff = caster->GetAuraEffect(70658, 0)) - // divided by 50 instead of 100 because calculated as for every 2 tick - addition += abs(int32((addition * aurEff->GetAmount()) / 50)); - - damage += addition; - } if (isAreaAura) damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), GetBase()->GetStackAmount()) * caster->SpellHealingPctDone(target, m_spellInfo); damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), GetBase()->GetStackAmount()); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index f9c6b64e7f3..ca79aa1ac0e 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -778,6 +778,14 @@ void Spell::SelectSpellTargets() if (m_spellInfo->IsChanneled()) { + // maybe do this for all spells? + if (m_UniqueTargetInfo.empty() && m_UniqueGOTargetInfo.empty() && m_UniqueItemInfo.empty() && !m_targets.HasDst()) + { + SendCastResult(SPELL_FAILED_BAD_IMPLICIT_TARGETS); + finish(false); + return; + } + uint32 mask = (1 << effect->EffectIndex); for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { @@ -1241,10 +1249,6 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge return; float radius = effect->CalcRadius(m_caster) * m_spellValue->RadiusMod; - // if this is a proximity based aoe (Frost Nova, Psychic Scream, ...), include the caster's own combat reach - if (targetType.IsProximityBasedAoe()) - radius += GetCaster()->GetCombatReach(); - SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), effect->ImplicitTargetConditions); CallScriptObjectAreaTargetSelectHandlers(targets, effIndex, targetType); @@ -2342,7 +2346,8 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { - if (!(target->effectMask & (1 << i))) + // in case of immunity, check all effects to choose correct procFlags, as none has technically hit + if (target->effectMask && !(target->effectMask & (1 << i))) continue; if (!m_spellInfo->IsPositiveEffect(i)) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index a9fa7bfee03..b02c080fe9b 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -879,15 +879,12 @@ void Spell::EffectJump(SpellEffIndex /*effIndex*/) if (!unitTarget) return; - float x, y, z; - unitTarget->GetContactPoint(m_caster, x, y, z, CONTACT_DISTANCE); - float speedXY, speedZ; - CalculateJumpSpeeds(effectInfo, m_caster->GetExactDist2d(x, y), speedXY, speedZ); + CalculateJumpSpeeds(effectInfo, m_caster->GetExactDist2d(unitTarget), speedXY, speedZ); JumpArrivalCastArgs arrivalCast; arrivalCast.SpellId = effectInfo->TriggerSpell; arrivalCast.Target = unitTarget->GetGUID(); - m_caster->GetMotionMaster()->MoveJump(x, y, z, 0.0f, speedXY, speedZ, EVENT_JUMP, false, &arrivalCast); + m_caster->GetMotionMaster()->MoveJump(*unitTarget, speedXY, speedZ, EVENT_JUMP, false, &arrivalCast); } void Spell::EffectJumpDest(SpellEffIndex /*effIndex*/) @@ -2725,13 +2722,9 @@ void Spell::EffectTaunt(SpellEffIndex /*effIndex*/) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; - if (!unitTarget) - return; - // this effect use before aura Taunt apply for prevent taunt already attacking target // for spell as marked "non effective at already attacking target" - if (!unitTarget || !unitTarget->CanHaveThreatList() - || unitTarget->GetVictim() == m_caster) + if (!unitTarget || !unitTarget->CanHaveThreatList() || unitTarget->GetVictim() == m_caster) { SendCastResult(SPELL_FAILED_DONT_REPORT); return; diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 8dc5af047ec..084695559bd 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -75,35 +75,6 @@ bool SpellImplicitTargetInfo::IsArea() const return GetSelectionCategory() == TARGET_SELECT_CATEGORY_AREA || GetSelectionCategory() == TARGET_SELECT_CATEGORY_CONE; } -bool SpellImplicitTargetInfo::IsProximityBasedAoe() const -{ - switch (_target) - { - case TARGET_UNIT_SRC_AREA_ENTRY: - case TARGET_UNIT_SRC_AREA_ENEMY: - case TARGET_UNIT_CASTER_AREA_PARTY: - case TARGET_UNIT_SRC_AREA_ALLY: - case TARGET_UNIT_SRC_AREA_PARTY: - case TARGET_UNIT_LASTTARGET_AREA_PARTY: - case TARGET_GAMEOBJECT_SRC_AREA: - case TARGET_UNIT_CASTER_AREA_RAID: - case TARGET_CORPSE_SRC_AREA_ENEMY: - return true; - - case TARGET_UNIT_DEST_AREA_ENTRY: - case TARGET_UNIT_DEST_AREA_ENEMY: - case TARGET_UNIT_DEST_AREA_ALLY: - case TARGET_UNIT_DEST_AREA_PARTY: - case TARGET_GAMEOBJECT_DEST_AREA: - case TARGET_UNIT_TARGET_AREA_RAID_CLASS: - return false; - - default: - TC_LOG_WARN("spells", "SpellImplicitTargetInfo::IsProximityBasedAoe called a non-aoe spell"); - return false; - } -} - SpellTargetSelectionCategories SpellImplicitTargetInfo::GetSelectionCategory() const { return _data[_target].SelectionCategory; diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 4af84e40376..5a5afeff4ee 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -286,7 +286,6 @@ public: SpellImplicitTargetInfo(uint32 target); bool IsArea() const; - bool IsProximityBasedAoe() const; SpellTargetSelectionCategories GetSelectionCategory() const; SpellTargetReferenceTypes GetReferenceType() const; SpellTargetObjectTypes GetObjectType() const; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 1e2bc42c17d..f2afcdbc474 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3363,6 +3363,14 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->AttributesEx |= SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY; }); + // Blizzard (Thorim) + ApplySpellFix({ 62576, 62602 }, [](SpellInfo* spellInfo) + { + // DBC data is wrong for EFFECT_0, it's a different dynobject target than EFFECT_1 + // Both effects should be shared by the same DynObject + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_DEST_CASTER_LEFT); + }); + // Spinning Up (Mimiron) ApplySpellFix({ 63414 }, [](SpellInfo* spellInfo) { diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index fc45fa83113..7a64662c730 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1613,6 +1613,9 @@ void World::SetInitialWorldSettings() MMAP::MMapManager* mmmgr = MMAP::MMapFactory::createOrGetMMapManager(); mmmgr->InitializeThreadUnsafe(mapData); + ///- Initialize static helper structures + AIRegistry::Initialize(); + TC_LOG_INFO("server.loading", "Loading SpellInfo store..."); sSpellMgr->LoadSpellInfoStore(); @@ -2140,9 +2143,6 @@ void World::SetInitialWorldSettings() mail_timer_expires = ((DAY * IN_MILLISECONDS) / (m_timers[WUPDATE_AUCTIONS].GetInterval())); TC_LOG_INFO("server.loading", "Mail timer set to: " UI64FMTD ", mail return is called every " UI64FMTD " minutes", uint64(mail_timer), uint64(mail_timer_expires)); - ///- Initilize static helper structures - AIRegistry::Initialize(); - ///- Initialize MapManager TC_LOG_INFO("server.loading", "Starting Map System"); sMapMgr->Initialize(); |
