diff options
Diffstat (limited to 'src')
160 files changed, 3134 insertions, 907 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(); diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 11417b305a5..81bc3e533e1 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -61,6 +61,7 @@ public: { "cinematic", rbac::RBAC_PERM_COMMAND_DEBUG_PLAY_CINEMATIC, false, &HandleDebugPlayCinematicCommand, "" }, { "movie", rbac::RBAC_PERM_COMMAND_DEBUG_PLAY_MOVIE, false, &HandleDebugPlayMovieCommand, "" }, { "sound", rbac::RBAC_PERM_COMMAND_DEBUG_PLAY_SOUND, false, &HandleDebugPlaySoundCommand, "" }, + { "music", rbac::RBAC_PERM_COMMAND_DEBUG_PLAY_MUSIC, false, &HandleDebugPlayMusicCommand, "" }, }; static std::vector<ChatCommand> debugSendCommandTable = { @@ -117,8 +118,8 @@ public: static bool HandleDebugPlayCinematicCommand(ChatHandler* handler, char const* args) { - // USAGE: .debug play cinematic #cinematicid - // #cinematicid - ID decimal number from CinemaicSequences.dbc (1st column) + // USAGE: .debug play cinematic #cinematicId + // #cinematicId - ID decimal number from CinemaicSequences.dbc (1st column) if (!*args) { handler->SendSysMessage(LANG_BAD_VALUE); @@ -126,12 +127,12 @@ public: return false; } - uint32 id = atoul(args); + uint32 cinematicId = atoul(args); - CinematicSequencesEntry const* cineSeq = sCinematicSequencesStore.LookupEntry(id); + CinematicSequencesEntry const* cineSeq = sCinematicSequencesStore.LookupEntry(cinematicId); if (!cineSeq) { - handler->PSendSysMessage(LANG_CINEMATIC_NOT_EXIST, id); + handler->PSendSysMessage(LANG_CINEMATIC_NOT_EXIST, cinematicId); handler->SetSentErrorMessage(true); return false; } @@ -139,7 +140,7 @@ public: // Dump camera locations if (std::vector<FlyByCamera> const* flyByCameras = GetFlyByCameras(cineSeq->Camera[0])) { - handler->PSendSysMessage("Waypoints for sequence %u, camera %u", id, cineSeq->Camera[0]); + handler->PSendSysMessage("Waypoints for sequence %u, camera %u", cinematicId, cineSeq->Camera[0]); uint32 count = 1; for (FlyByCamera const& cam : *flyByCameras) { @@ -149,14 +150,14 @@ public: handler->PSendSysMessage(SZFMTD " waypoints dumped", flyByCameras->size()); } - handler->GetSession()->GetPlayer()->SendCinematicStart(id); + handler->GetSession()->GetPlayer()->SendCinematicStart(cinematicId); return true; } static bool HandleDebugPlayMovieCommand(ChatHandler* handler, char const* args) { - // USAGE: .debug play movie #movieid - // #movieid - ID decimal number from Movie.dbc (1st column) + // USAGE: .debug play movie #movieId + // #movieId - ID decimal number from Movie.dbc (1st column) if (!*args) { handler->SendSysMessage(LANG_BAD_VALUE); @@ -164,24 +165,24 @@ public: return false; } - uint32 id = atoul(args); + uint32 movieId = atoul(args); - if (!sMovieStore.LookupEntry(id)) + if (!sMovieStore.LookupEntry(movieId)) { - handler->PSendSysMessage(LANG_MOVIE_NOT_EXIST, id); + handler->PSendSysMessage(LANG_MOVIE_NOT_EXIST, movieId); handler->SetSentErrorMessage(true); return false; } - handler->GetSession()->GetPlayer()->SendMovieStart(id); + handler->GetSession()->GetPlayer()->SendMovieStart(movieId); return true; } //Play sound static bool HandleDebugPlaySoundCommand(ChatHandler* handler, char const* args) { - // USAGE: .debug playsound #soundid - // #soundid - ID decimal number from SoundEntries.dbc (1st column) + // USAGE: .debug playsound #soundId + // #soundId - ID decimal number from SoundEntries.dbc (1st column) if (!*args) { handler->SendSysMessage(LANG_BAD_VALUE); @@ -198,6 +199,8 @@ public: return false; } + Player* player = handler->GetSession()->GetPlayer(); + Unit* unit = handler->getSelectedUnit(); if (!unit) { @@ -206,15 +209,42 @@ public: return false; } - if (!handler->GetSession()->GetPlayer()->GetTarget().IsEmpty()) - unit->PlayDistanceSound(soundId, handler->GetSession()->GetPlayer()); + if (player->GetTarget().IsEmpty()) + unit->PlayDistanceSound(soundId, player); else - unit->PlayDirectSound(soundId, handler->GetSession()->GetPlayer()); + unit->PlayDirectSound(soundId, player); handler->PSendSysMessage(LANG_YOU_HEAR_SOUND, soundId); return true; } + static bool HandleDebugPlayMusicCommand(ChatHandler* handler, char const* args) + { + // USAGE: .debug play music #musicId + // #musicId - ID decimal number from SoundEntries.dbc (1st column) + if (!*args) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + + uint32 musicId = atoul(args); + if (!sSoundKitStore.LookupEntry(musicId)) + { + handler->PSendSysMessage(LANG_SOUND_NOT_EXIST, musicId); + handler->SetSentErrorMessage(true); + return false; + } + + Player* player = handler->GetSession()->GetPlayer(); + + player->PlayDirectMusic(musicId, player); + + handler->PSendSysMessage(LANG_YOU_HEAR_SOUND, musicId); + return true; + } + static bool HandleDebugSendSpellFailCommand(ChatHandler* handler, char const* args) { if (!*args) diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 595af9223bc..4d818db8f9d 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -891,7 +891,7 @@ public: const_cast<CreatureData*>(data)->posZ = z; const_cast<CreatureData*>(data)->orientation = o; } - creature->SetPosition(x, y, z, o); + creature->UpdatePosition(x, y, z, o); creature->GetMotionMaster()->Initialize(); if (creature->IsAlive()) // dead creature will reset movement generator at respawn { diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 8917a50951f..ccb032f6c02 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -111,13 +111,13 @@ public: { "item_random_bonus_list_template", rbac::RBAC_PERM_COMMAND_RELOAD_ITEM_RANDOM_BONUS_LIST_TEMPLATE, true, &HandleReloadItemRandomBonusListTemplatesCommand, "" }, { "item_loot_template", rbac::RBAC_PERM_COMMAND_RELOAD_ITEM_LOOT_TEMPLATE, true, &HandleReloadLootTemplatesItemCommand, "" }, { "lfg_dungeon_rewards", rbac::RBAC_PERM_COMMAND_RELOAD_LFG_DUNGEON_REWARDS, true, &HandleReloadLfgRewardsCommand, "" }, - { "locales_achievement_reward", rbac::RBAC_PERM_COMMAND_RELOAD_LOCALES_ACHIEVEMENT_REWARD, true, &HandleReloadLocalesAchievementRewardCommand, "" }, - { "locales_creature", rbac::RBAC_PERM_COMMAND_RELOAD_LOCALES_CRETURE, true, &HandleReloadLocalesCreatureCommand, "" }, - { "locales_creature_text", rbac::RBAC_PERM_COMMAND_RELOAD_LOCALES_CRETURE_TEXT, true, &HandleReloadLocalesCreatureTextCommand, "" }, - { "locales_gameobject", rbac::RBAC_PERM_COMMAND_RELOAD_LOCALES_GAMEOBJECT, true, &HandleReloadLocalesGameobjectCommand, "" }, - { "locales_gossip_menu_option", rbac::RBAC_PERM_COMMAND_RELOAD_LOCALES_GOSSIP_MENU_OPTION, true, &HandleReloadLocalesGossipMenuOptionCommand, "" }, - { "locales_page_text", rbac::RBAC_PERM_COMMAND_RELOAD_LOCALES_PAGE_TEXT, true, &HandleReloadLocalesPageTextCommand, "" }, - { "locales_points_of_interest", rbac::RBAC_PERM_COMMAND_RELOAD_LOCALES_POINTS_OF_INTEREST, true, &HandleReloadLocalesPointsOfInterestCommand, "" }, + { "achievement_reward_locale", rbac::RBAC_PERM_COMMAND_RELOAD_ACHIEVEMENT_REWARD_LOCALE, true, &HandleReloadLocalesAchievementRewardCommand, "" }, + { "creature_template_locale", rbac::RBAC_PERM_COMMAND_RELOAD_CRETURE_TEMPLATE_LOCALE, true, &HandleReloadLocalesCreatureCommand, "" }, + { "creature_text_locale", rbac::RBAC_PERM_COMMAND_RELOAD_CRETURE_TEXT_LOCALE, true, &HandleReloadLocalesCreatureTextCommand, "" }, + { "gameobject_template_locale", rbac::RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_TEMPLATE_LOCALE, true, &HandleReloadLocalesGameobjectCommand, "" }, + { "gossip_menu_option_locale", rbac::RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU_OPTION_LOCALE, true, &HandleReloadLocalesGossipMenuOptionCommand, "" }, + { "page_text_locale", rbac::RBAC_PERM_COMMAND_RELOAD_PAGE_TEXT_LOCALE, true, &HandleReloadLocalesPageTextCommand, "" }, + { "points_of_interest_locale", rbac::RBAC_PERM_COMMAND_RELOAD_POINTS_OF_INTEREST_LOCALE, true, &HandleReloadLocalesPointsOfInterestCommand, "" }, { "mail_level_reward", rbac::RBAC_PERM_COMMAND_RELOAD_MAIL_LEVEL_REWARD, true, &HandleReloadMailLevelRewardCommand, "" }, { "mail_loot_template", rbac::RBAC_PERM_COMMAND_RELOAD_MAIL_LOOT_TEMPLATE, true, &HandleReloadLootTemplatesMailCommand, "" }, { "milling_loot_template", rbac::RBAC_PERM_COMMAND_RELOAD_MILLING_LOOT_TEMPLATE, true, &HandleReloadLootTemplatesMillingCommand, "" }, @@ -128,7 +128,7 @@ public: { "points_of_interest", rbac::RBAC_PERM_COMMAND_RELOAD_POINTS_OF_INTEREST, true, &HandleReloadPointsOfInterestCommand, "" }, { "prospecting_loot_template", rbac::RBAC_PERM_COMMAND_RELOAD_PROSPECTING_LOOT_TEMPLATE, true, &HandleReloadLootTemplatesProspectingCommand, "" }, { "quest_greeting", rbac::RBAC_PERM_COMMAND_RELOAD_QUEST_GREETING, true, &HandleReloadQuestGreetingCommand, "" }, - { "quest_locale", rbac::RBAC_PERM_COMMAND_RELOAD_QUEST_LOCALE, true, &HandleReloadQuestLocaleCommand, "" }, + { "quest_locale", rbac::RBAC_PERM_COMMAND_RELOAD_QUEST_TEMPLATE_LOCALE, true, &HandleReloadQuestLocaleCommand, "" }, { "quest_poi", rbac::RBAC_PERM_COMMAND_RELOAD_QUEST_POI, true, &HandleReloadQuestPOICommand, "" }, { "quest_template", rbac::RBAC_PERM_COMMAND_RELOAD_QUEST_TEMPLATE, true, &HandleReloadQuestTemplateCommand, "" }, { "rbac", rbac::RBAC_PERM_COMMAND_RELOAD_RBAC, true, &HandleReloadRBACCommand, "" }, @@ -997,9 +997,9 @@ public: static bool HandleReloadLocalesAchievementRewardCommand(ChatHandler* handler, const char* /*args*/) { - TC_LOG_INFO("misc", "Re-Loading Locales Achievement Reward Data..."); + TC_LOG_INFO("misc", "Re-Loading Achievement Reward Data Locale..."); sAchievementMgr->LoadRewardLocales(); - handler->SendGlobalGMSysMessage("DB table `locales_achievement_reward` reloaded."); + handler->SendGlobalGMSysMessage("DB table `achievement_reward_locale` reloaded."); return true; } @@ -1013,49 +1013,49 @@ public: static bool HandleReloadLocalesCreatureCommand(ChatHandler* handler, const char* /*args*/) { - TC_LOG_INFO("misc", "Re-Loading Locales Creature ..."); + TC_LOG_INFO("misc", "Re-Loading Creature Template Locale..."); sObjectMgr->LoadCreatureLocales(); - handler->SendGlobalGMSysMessage("DB table `locales_creature` reloaded."); + handler->SendGlobalGMSysMessage("DB table `creature_template_locale` reloaded."); return true; } static bool HandleReloadLocalesCreatureTextCommand(ChatHandler* handler, const char* /*args*/) { - TC_LOG_INFO("misc", "Re-Loading Locales Creature Texts..."); + TC_LOG_INFO("misc", "Re-Loading Creature Texts Locale..."); sCreatureTextMgr->LoadCreatureTextLocales(); - handler->SendGlobalGMSysMessage("DB table `locales_creature_text` reloaded."); + handler->SendGlobalGMSysMessage("DB table `creature_text_locale` reloaded."); return true; } static bool HandleReloadLocalesGameobjectCommand(ChatHandler* handler, const char* /*args*/) { - TC_LOG_INFO("misc", "Re-Loading Locales Gameobject ... "); + TC_LOG_INFO("misc", "Re-Loading Gameobject Template Locale... "); sObjectMgr->LoadGameObjectLocales(); - handler->SendGlobalGMSysMessage("DB table `locales_gameobject` reloaded."); + handler->SendGlobalGMSysMessage("DB table `gameobject_template_locale` reloaded."); return true; } static bool HandleReloadLocalesGossipMenuOptionCommand(ChatHandler* handler, const char* /*args*/) { - TC_LOG_INFO("misc", "Re-Loading Locales Gossip Menu Option ... "); + TC_LOG_INFO("misc", "Re-Loading Gossip Menu Option Locale... "); sObjectMgr->LoadGossipMenuItemsLocales(); - handler->SendGlobalGMSysMessage("DB table `locales_gossip_menu_option` reloaded."); + handler->SendGlobalGMSysMessage("DB table `gossip_menu_option_locale` reloaded."); return true; } static bool HandleReloadLocalesPageTextCommand(ChatHandler* handler, const char* /*args*/) { - TC_LOG_INFO("misc", "Re-Loading Locales Page Text ... "); + TC_LOG_INFO("misc", "Re-Loading Page Text Locale... "); sObjectMgr->LoadPageTextLocales(); - handler->SendGlobalGMSysMessage("DB table `locales_page_text` reloaded."); + handler->SendGlobalGMSysMessage("DB table `page_text_locale` reloaded."); return true; } static bool HandleReloadLocalesPointsOfInterestCommand(ChatHandler* handler, const char* /*args*/) { - TC_LOG_INFO("misc", "Re-Loading Locales Points Of Interest ... "); + TC_LOG_INFO("misc", "Re-Loading Points Of Interest Locale... "); sObjectMgr->LoadPointOfInterestLocales(); - handler->SendGlobalGMSysMessage("DB table `locales_points_of_interest` reloaded."); + handler->SendGlobalGMSysMessage("DB table `points_of_interest_locale` reloaded."); return true; } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp index 3851a74d263..14c6ec900db 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp @@ -588,7 +588,7 @@ public: //spell by trap has effect61, this indicate the bar go hostile if (Unit* tmp = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_PHALANX))) - tmp->SetFaction(14); + tmp->SetFaction(FACTION_MONSTER); //for later, this event(s) has alot more to it. //optionally, DONE can trigger bar to go hostile. diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_coren_direbrew.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_coren_direbrew.cpp index 923b771b04b..39cf1b6345a 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_coren_direbrew.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_coren_direbrew.cpp @@ -99,8 +99,6 @@ enum DirebrewEvents enum DirebrewMisc { - COREN_DIREBREW_FACTION_HOSTILE = 736, - COREN_DIREBREW_FACTION_FRIEND = 35, GOSSIP_ID = 11388, GO_MOLE_MACHINE_TRAP = 188509, GOSSIP_OPTION_FIGHT = 0, @@ -145,7 +143,7 @@ public: { _Reset(); me->AddUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); - me->SetFaction(COREN_DIREBREW_FACTION_FRIEND); + me->SetFaction(FACTION_FRIENDLY); events.SetPhase(PHASE_ALL); for (uint8 i = 0; i < MAX_ANTAGONISTS; ++i) @@ -168,7 +166,7 @@ public: { events.SetPhase(PHASE_ONE); me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); - me->SetFaction(COREN_DIREBREW_FACTION_HOSTILE); + me->SetFaction(FACTION_GOBLIN_DARK_IRON_BAR_PATRON); me->SetInCombatWithZone(); EntryCheckPredicate pred(NPC_ANTAGONIST); @@ -359,7 +357,7 @@ public: void Reset() override { - me->SetFaction(COREN_DIREBREW_FACTION_HOSTILE); + me->SetFaction(FACTION_GOBLIN_DARK_IRON_BAR_PATRON); DoCastAOE(SPELL_MOLE_MACHINE_EMERGE, true); me->SetInCombatWithZone(); } @@ -401,7 +399,7 @@ public: break; case ACTION_ANTAGONIST_HOSTILE: me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); - me->SetFaction(COREN_DIREBREW_FACTION_HOSTILE); + me->SetFaction(FACTION_GOBLIN_DARK_IRON_BAR_PATRON); me->SetInCombatWithZone(); break; default: diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp index 9015420d079..5017f5e48bd 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp @@ -75,7 +75,7 @@ class boss_emperor_dagran_thaurissan : public CreatureScript if (Creature* moira = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_MOIRA))) { moira->AI()->EnterEvadeMode(); - moira->SetFaction(35); + moira->SetFaction(FACTION_FRIENDLY); } } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_tomb_of_seven.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_tomb_of_seven.cpp index d5af35b77b0..7d709fdaf42 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_tomb_of_seven.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_tomb_of_seven.cpp @@ -149,7 +149,7 @@ class boss_doomrel : public CreatureScript { Initialize(); - me->SetFaction(FACTION_FRIEND); + me->SetFaction(FACTION_FRIENDLY); // was set before event start, so set again me->AddUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); @@ -239,7 +239,7 @@ class boss_doomrel : public CreatureScript case GOSSIP_ACTION_INFO_DEF + 2: CloseGossipMenuFor(player); //start event here - me->SetFaction(FACTION_HOSTILE); + me->SetFaction(FACTION_DARK_IRON_DWARVES); me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); me->AI()->AttackStart(player); diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/instance_blackrock_depths.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/instance_blackrock_depths.cpp index 219414e29a7..85a38917f2b 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/instance_blackrock_depths.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/instance_blackrock_depths.cpp @@ -354,7 +354,7 @@ public: { if (Creature* boss = instance->GetCreature(TombBossGUIDs[TombEventCounter])) { - boss->SetFaction(FACTION_HOSTILE); + boss->SetFaction(FACTION_DARK_IRON_DWARVES); boss->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); if (Unit* target = boss->SelectNearestTarget(500)) boss->AI()->AttackStart(target); @@ -380,7 +380,7 @@ public: boss->GetMotionMaster()->MoveTargetedHome(); boss->SetLootRecipient(NULL); } - boss->SetFaction(FACTION_FRIEND); + boss->SetFaction(FACTION_FRIENDLY); } } GhostKillCount = 0; diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp index e5c2d97a9d4..f9f81e46efe 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp @@ -190,7 +190,7 @@ public: me->SetVisible(true); me->SetNpcFlags(UNIT_NPC_FLAG_GOSSIP); - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); me->SetStandState(UNIT_STAND_STATE_SIT_HIGH_CHAIR); me->RemoveAura(SPELL_NEFARIANS_BARRIER); } @@ -207,7 +207,7 @@ public: Talk(SAY_GAMESBEGIN_2); - me->SetFaction(103); + me->SetFaction(FACTION_DRAGONFLIGHT_BLACK); me->SetNpcFlags(UNIT_NPC_FLAG_NONE); DoCast(me, SPELL_NEFARIANS_BARRIER); me->SetStandState(UNIT_STAND_STATE_STAND); @@ -342,7 +342,7 @@ public: CreatureID = Entry[urand(0, 4)]; if (Creature* dragon = me->SummonCreature(CreatureID, DrakeSpawnLoc[i])) { - dragon->SetFaction(103); + dragon->SetFaction(FACTION_DRAGONFLIGHT_BLACK); dragon->AI()->AttackStart(me->GetVictim()); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp index 184b64a9cde..e5b49dd8910 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp @@ -75,7 +75,7 @@ public: { Initialize(); creature->AddNpcFlag(UNIT_NPC_FLAG_GOSSIP); - creature->SetFaction(35); + creature->SetFaction(FACTION_FRIENDLY); creature->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); } @@ -153,7 +153,7 @@ public: events.ScheduleEvent(EVENT_SPEECH_4, 16000); break; case EVENT_SPEECH_4: - me->SetFaction(103); + me->SetFaction(FACTION_DRAGONFLIGHT_BLACK); if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID)) AttackStart(player); break; diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp index cd1aeef7b97..72eb8f43cb9 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp @@ -55,7 +55,6 @@ enum Spells enum Extras { OPTION_ID_YOU_CHALLENGED_US = 0, - FACTION_FRIENDLY = 35, MENU_OPTION_YOU_CHALLENGED_US = 4108 }; diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp index 4e245db8aad..3e73c1e162e 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp @@ -175,7 +175,7 @@ class boss_ragnaros : public CreatureScript { //Become unbanished again me->SetReactState(REACT_AGGRESSIVE); - me->SetFaction(14); + me->SetFaction(FACTION_MONSTER); me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->SetEmoteState(EMOTE_ONESHOT_NONE); me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); @@ -253,7 +253,7 @@ class boss_ragnaros : public CreatureScript me->InterruptNonMeleeSpells(false); //Root self //DoCast(me, 23973); - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->SetEmoteState(EMOTE_STATE_SUBMERGED); me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE); diff --git a/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp b/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp index 28bdb8e9056..c3a65c24fab 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp @@ -1382,7 +1382,7 @@ void boss_julianne::boss_julianneAI::UpdateAI(uint32 diff) { Talk(SAY_JULIANNE_AGGRO); me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetFaction(16); + me->SetFaction(FACTION_MONSTER_2); AggroYellTimer = 0; } else AggroYellTimer -= diff; } @@ -1410,7 +1410,7 @@ void boss_julianne::boss_julianneAI::UpdateAI(uint32 diff) ENSURE_AI(boss_romulo::boss_romuloAI, pRomulo->AI())->Phase = PHASE_ROMULO; DoZoneInCombat(pRomulo); - pRomulo->SetFaction(16); + pRomulo->SetFaction(FACTION_MONSTER_2); } SummonedRomulo = true; } else SummonRomuloTimer -= diff; diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp index 9fa6e43ae5d..1a379d8676e 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp @@ -217,7 +217,7 @@ public: { float x = KaelLocations[0][0]; float y = KaelLocations[0][1]; - me->SetPosition(x, y, LOCATION_Z, 0.0f); + me->UpdatePosition(x, y, LOCATION_Z, 0.0f); ThreatContainer::StorageType threatlist = me->getThreatManager().getThreatList(); ThreatContainer::StorageType::const_iterator i = threatlist.begin(); for (i = threatlist.begin(); i != threatlist.end(); ++i) @@ -454,7 +454,7 @@ public: Initialize(); me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetFaction(14); + me->SetFaction(FACTION_MONSTER); DoCast(me, SPELL_FLAMESTRIKE2, true); } @@ -659,7 +659,7 @@ public: me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->SetDisableGravity(true); - me->SetFaction(14); + me->SetFaction(FACTION_MONSTER); DoCast(me, SPELL_ARCANE_SPHERE_PASSIVE, true); } diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp index d7e50807867..9134885bd46 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -129,7 +129,7 @@ public: { Initialize(); events.Reset(); - me->SetFaction(7); + me->SetFaction(FACTION_CREATURE); me->AddUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); me->SetStandState(UNIT_STAND_STATE_KNEEL); me->LoadEquipment(0, true); @@ -235,7 +235,7 @@ public: wait_timer -= diff; else { - me->SetFaction(14); + me->SetFaction(FACTION_MONSTER); me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); phase = PHASE_ATTACKING; @@ -484,8 +484,7 @@ enum Says_VBM enum Misc_VBN { - QUEST_DEATH_CHALLENGE = 12733, - FACTION_HOSTILE = 2068 + QUEST_DEATH_CHALLENGE = 12733 }; class npc_death_knight_initiate : public CreatureScript @@ -563,7 +562,7 @@ public: { if (m_uiDuelTimer <= uiDiff) { - me->SetFaction(FACTION_HOSTILE); + me->SetFaction(FACTION_UNDEAD_SCOURGE_2); if (Unit* unit = ObjectAccessor::GetUnit(*me, m_uiDuelerGUID)) AttackStart(unit); @@ -789,7 +788,7 @@ public: { charmer->RemoveAurasDueToSpell(SPELL_EFFECT_STOLEN_HORSE); caster->RemoveNpcFlag(UNIT_NPC_FLAG_SPELLCLICK); - caster->SetFaction(35); + caster->SetFaction(FACTION_FRIENDLY); DoCast(caster, SPELL_CALL_DARK_RIDER, true); if (Creature* Dark_Rider = me->FindNearestCreature(NPC_DARK_RIDER_OF_ACHERUS, 15)) ENSURE_AI(npc_dark_rider_of_acherus::npc_dark_rider_of_acherusAI, Dark_Rider->AI())->InitDespawnHorse(caster); diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp index 255e709ae90..461d326dd3e 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp @@ -621,7 +621,7 @@ public: { Unit* temp = me->SummonCreature(NPC_ACHERUS_GHOUL, (me->GetPositionX() - 20) + rand32() % 40, (me->GetPositionY() - 20) + rand32() % 40, me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); temp->SetWalk(false); - temp->SetFaction(2084); + temp->SetFaction(FACTION_UNDEAD_SCOURGE_3); uiGhoulGUID[uiSummon_counter] = temp->GetGUID(); ++uiSummon_counter; } @@ -639,7 +639,7 @@ public: { Unit* temp = me->SummonCreature(NPC_RAMPAGING_ABOMINATION, (me->GetPositionX() - 20) + rand32() % 40, (me->GetPositionY() - 20) + rand32() % 40, me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); temp->SetWalk(false); - temp->SetFaction(2084); + temp->SetFaction(FACTION_UNDEAD_SCOURGE_3); uiAbominationGUID[uiSummon_counter] = temp->GetGUID(); ++uiSummon_counter; } @@ -657,7 +657,7 @@ public: { Unit* temp = me->SummonCreature(NPC_WARRIOR_OF_THE_FROZEN_WASTES, (me->GetPositionX() - 20) + rand32() % 40, (me->GetPositionY() - 20) + rand32() % 40, me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); temp->SetWalk(false); - temp->SetFaction(2084); + temp->SetFaction(FACTION_UNDEAD_SCOURGE_3); uiWarriorGUID[uiSummon_counter] = temp->GetGUID(); ++uiSummon_counter; } @@ -675,7 +675,7 @@ public: { Unit* temp = me->SummonCreature(NPC_FLESH_BEHEMOTH, (me->GetPositionX() - 20) + rand32() % 40, (me->GetPositionY() - 20) + rand32() % 40, me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); temp->SetWalk(false); - temp->SetFaction(2084); + temp->SetFaction(FACTION_UNDEAD_SCOURGE_3); uiBehemothGUID[uiSummon_counter] = temp->GetGUID(); ++uiSummon_counter; } @@ -1507,7 +1507,7 @@ public: if (!temp) { temp = me->SummonCreature(NPC_ACHERUS_GHOUL, LightofDawnLoc[0].GetPositionWithOffset({ float(rand32() % 30), float(rand32() % 30), 0.0f, 0.0f }), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); - temp->SetFaction(2084); + temp->SetFaction(FACTION_UNDEAD_SCOURGE_3); uiGhoulGUID[i] = temp->GetGUID(); } } @@ -1517,7 +1517,7 @@ public: if (!temp) { temp = me->SummonCreature(NPC_WARRIOR_OF_THE_FROZEN_WASTES, LightofDawnLoc[0].GetPositionWithOffset({ float(rand32() % 30), float(rand32() % 30), 0.0f, 0.0f }), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); - temp->SetFaction(2084); + temp->SetFaction(FACTION_UNDEAD_SCOURGE_3); uiAbominationGUID[i] = temp->GetGUID(); } } @@ -1527,7 +1527,7 @@ public: if (!temp) { temp = me->SummonCreature(NPC_RAMPAGING_ABOMINATION, LightofDawnLoc[0].GetPositionWithOffset({ float(rand32() % 30), float(rand32() % 30), 0.0f, 0.0f }), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); - temp->SetFaction(2084); + temp->SetFaction(FACTION_UNDEAD_SCOURGE_3); uiWarriorGUID[i] = temp->GetGUID(); } } @@ -1537,7 +1537,7 @@ public: if (!temp) { temp = me->SummonCreature(NPC_FLESH_BEHEMOTH, LightofDawnLoc[0].GetPositionWithOffset({ float(rand32() % 30), float(rand32() % 30), 0.0f, 0.0f }), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); - temp->SetFaction(2084); + temp->SetFaction(FACTION_UNDEAD_SCOURGE_3); uiBehemothGUID[i] = temp->GetGUID(); } } @@ -1549,7 +1549,7 @@ public: if (!temp) { temp = me->SummonCreature(NPC_DEFENDER_OF_THE_LIGHT, LightofDawnLoc[0].GetPositionWithOffset({ float(rand32() % 30), float(rand32() % 30), 0.0f, 0.0f }), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); - temp->SetFaction(2089); + temp->SetFaction(FACTION_SCARLET_CRUSADE); me->AddThreat(temp, 0.0f); uiDefenderGUID[i] = temp->GetGUID(); } @@ -1560,7 +1560,7 @@ public: if (!temp) { temp = me->SummonCreature(NPC_RIMBLAT_EARTHSHATTER, LightofDawnLoc[0].GetPositionWithOffset({ float(rand32() % 30), float(rand32() % 30), 0.0f, 0.0f }), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); - temp->SetFaction(2089); + temp->SetFaction(FACTION_SCARLET_CRUSADE); me->AddThreat(temp, 0.0f); uiEarthshatterGUID[i] = temp->GetGUID(); } @@ -1569,7 +1569,7 @@ public: if (!temp) { temp = me->SummonCreature(NPC_KORFAX_CHAMPION_OF_THE_LIGHT, LightofDawnLoc[0].GetPositionWithOffset({ float(rand32() % 30), float(rand32() % 30), 0.0f, 0.0f }), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 600000); - temp->SetFaction(2089); + temp->SetFaction(FACTION_SCARLET_CRUSADE); me->AddThreat(temp, 0.0f); uiKorfaxGUID = temp->GetGUID(); } @@ -1577,7 +1577,7 @@ public: if (!temp) { temp = me->SummonCreature(NPC_LORD_MAXWELL_TYROSUS, LightofDawnLoc[0].GetPositionWithOffset({ float(rand32() % 30), float(rand32() % 30), 0.0f, 0.0f }), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 600000); - temp->SetFaction(2089); + temp->SetFaction(FACTION_SCARLET_CRUSADE); me->AddThreat(temp, 0.0f); uiMaxwellGUID = temp->GetGUID(); } @@ -1585,7 +1585,7 @@ public: if (!temp) { temp = me->SummonCreature(NPC_COMMANDER_ELIGOR_DAWNBRINGER, LightofDawnLoc[0].GetPositionWithOffset({ float(rand32() % 30), float(rand32() % 30), 0.0f, 0.0f }), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 600000); - temp->SetFaction(2089); + temp->SetFaction(FACTION_SCARLET_CRUSADE); me->AddThreat(temp, 0.0f); uiEligorGUID = temp->GetGUID(); } @@ -1593,7 +1593,7 @@ public: if (!temp) { temp = me->SummonCreature(NPC_RAYNE, LightofDawnLoc[0].GetPositionWithOffset({ float(rand32() % 30), float(rand32() % 30), 0.0f, 0.0f }), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); - temp->SetFaction(2089); + temp->SetFaction(FACTION_SCARLET_CRUSADE); me->AddThreat(temp, 0.0f); uiRayneGUID = temp->GetGUID(); } diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp index fea8c330b9c..e97f8a8454d 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp @@ -78,7 +78,7 @@ public: x -= 3.5f; y -= 5.0f; me->GetMotionMaster()->Clear(false); - me->SetPosition(x, y, z, 0.0f); + me->UpdatePosition(x, y, z, 0.0f); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp index d27c334a0de..75ff54ac3eb 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp @@ -805,7 +805,7 @@ public: { float x, y, z; me->GetPosition(x, y, z); //this visual aura some under ground - me->SetPosition(x, y, z + 0.35f, 0.0f); + me->UpdatePosition(x, y, z + 0.35f, 0.0f); debuffGUID.Clear(); Despawn(); Creature* debuff = DoSpawnCreature(HELPER, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 14500); diff --git a/src/server/scripts/EasternKingdoms/ShadowfangKeep/boss_apothecary_hummel.cpp b/src/server/scripts/EasternKingdoms/ShadowfangKeep/boss_apothecary_hummel.cpp index a1714085160..1cfbabb638d 100644 --- a/src/server/scripts/EasternKingdoms/ShadowfangKeep/boss_apothecary_hummel.cpp +++ b/src/server/scripts/EasternKingdoms/ShadowfangKeep/boss_apothecary_hummel.cpp @@ -56,6 +56,7 @@ enum ApothecarySays SAY_CALL_BAXTER = 3, SAY_CALL_FRYE = 4, SAY_HUMMEL_DEATH = 5, + SAY_SUMMON_ADDS = 6, SAY_BAXTER_DEATH = 0, SAY_FRYE_DEATH = 0 }; @@ -77,8 +78,6 @@ enum ApothecaryMisc { ACTION_START_EVENT = 1, ACTION_START_FIGHT = 2, - FACTION_APOTHECARY_HOSTILE = 14, - FACTION_APOTHECARY_FRIENDLY = 35, GOSSIP_OPTION_START = 0, GOSSIP_MENU_HUMMEL = 10847, QUEST_YOUVE_BEEN_SERVED = 14488, @@ -119,7 +118,7 @@ class boss_apothecary_hummel : public CreatureScript _deadCount = 0; _isDead = false; events.SetPhase(PHASE_ALL); - me->SetFaction(FACTION_APOTHECARY_FRIENDLY); + me->SetFaction(FACTION_FRIENDLY); me->SummonCreatureGroup(1); } @@ -138,7 +137,7 @@ class boss_apothecary_hummel : public CreatureScript events.ScheduleEvent(EVENT_HUMMEL_SAY_0, Milliseconds(1)); me->AddUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); - me->SetFaction(FACTION_APOTHECARY_HOSTILE); + me->SetFaction(FACTION_MONSTER); DummyEntryCheckPredicate pred; summons.DoAction(ACTION_START_EVENT, pred); } @@ -226,6 +225,7 @@ class boss_apothecary_hummel : public CreatureScript events.ScheduleEvent(EVENT_PERFUME_SPRAY, Milliseconds(3640)); events.ScheduleEvent(EVENT_CHAIN_REACTION, Seconds(15)); + Talk(SAY_SUMMON_ADDS); std::vector<Creature*> trashs; me->GetCreatureListWithEntryInGrid(trashs, NPC_CROWN_APOTHECARY); for (Creature* crea : trashs) @@ -294,7 +294,7 @@ struct npc_apothecary_genericAI : public ScriptedAI if (action == ACTION_START_EVENT) { me->AddUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); - me->SetFaction(FACTION_APOTHECARY_HOSTILE); + me->SetFaction(FACTION_MONSTER); me->GetMotionMaster()->MovePoint(1, _movePos); } else if (action == ACTION_START_FIGHT) diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp index e7ee54390ed..0a0f528ffdd 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp @@ -161,7 +161,7 @@ public: if (Creature* Sath = ObjectAccessor::GetCreature(*me, SathGUID)) Sath->AI()->EnterEvadeMode(); - me->SetFaction(14); + me->SetFaction(FACTION_MONSTER); if (!bJustReset) //first reset at create { me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); @@ -388,7 +388,7 @@ public: switch (TalkSequence) { case 1: - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); TalkTimer = 1000; break; case 2: @@ -676,7 +676,7 @@ public: void JustDied(Unit* /*killer*/) override { Talk(SAY_SATH_DEATH); - me->SetPosition(me->GetPositionX(), me->GetPositionY(), DRAGON_REALM_Z, me->GetOrientation()); + me->UpdatePosition(me->GetPositionX(), me->GetPositionY(), DRAGON_REALM_Z, me->GetOrientation()); TeleportAllPlayersBack(); if (Creature* Kalecgos = ObjectAccessor::GetCreature(*me, KalecgosGUID)) { diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp index 0eff7cda638..146ebefceaf 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp @@ -294,7 +294,7 @@ public: me->RemoveDynObject(SPELL_RING_OF_BLUE_FLAMES); for (uint8 i = 0; i < 4; ++i) if (GameObject* pOrb = GetOrb(i)) - pOrb->SetFaction(0); + pOrb->SetFaction(FACTION_NONE); } void EmpowerOrb(bool all) @@ -311,7 +311,7 @@ public: if (GameObject* pOrb = GetOrb(i)) { pOrb->CastSpell(me, SPELL_RING_OF_BLUE_FLAMES); - pOrb->SetFaction(35); + pOrb->SetFaction(FACTION_FRIENDLY); pOrb->setActive(true); pOrb->Refresh(); } @@ -323,7 +323,7 @@ public: if (GameObject* pOrb = GetOrb(urand(0, 3))) { pOrb->CastSpell(me, SPELL_RING_OF_BLUE_FLAMES); - pOrb->SetFaction(35); + pOrb->SetFaction(FACTION_FRIENDLY); pOrb->setActive(true); pOrb->Refresh(); @@ -381,7 +381,7 @@ class go_orb_of_the_blue_flight : public GameObjectScript { player->SummonCreature(NPC_POWER_OF_THE_BLUE_DRAGONFLIGHT, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 121000); player->CastSpell(player, SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT, false); - me->SetFaction(0); + me->SetFaction(FACTION_NONE); if (Creature* pKalec = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_KALECGOS_KJ))) ENSURE_AI(boss_kalecgos_kj::boss_kalecgos_kjAI, pKalec->AI())->SetRingOfBlueFlames(); diff --git a/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp b/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp index 1b301d553dc..6d2e392e18d 100644 --- a/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp +++ b/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp @@ -100,7 +100,7 @@ class boss_archaedas : public CreatureScript Initialize(); instance->SetData(0, 5); // respawn any dead minions - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->SetControlled(true, UNIT_STATE_ROOT); me->AddAura(SPELL_FREEZE_ANIM, me); @@ -116,14 +116,14 @@ class boss_archaedas : public CreatureScript minion->CastSpell(minion, SPELL_ARCHAEDAS_AWAKEN, true); minion->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); minion->SetControlled(false, UNIT_STATE_ROOT); - minion->SetFaction(14); + minion->SetFaction(FACTION_MONSTER); minion->RemoveAura(SPELL_MINION_FREEZE_ANIM); } } void EnterCombat(Unit* /*who*/) override { - me->SetFaction(14); + me->SetFaction(FACTION_MONSTER); me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->SetControlled(false, UNIT_STATE_ROOT); } @@ -272,7 +272,7 @@ class npc_archaedas_minions : public CreatureScript void EnterCombat(Unit* /*who*/) override { - me->SetFaction(14); + me->SetFaction(FACTION_MONSTER); me->RemoveAllAuras(); me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->SetControlled(false, UNIT_STATE_ROOT); @@ -352,7 +352,7 @@ class npc_stonekeepers : public CreatureScript void Reset() override { - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->SetControlled(true, UNIT_STATE_ROOT); me->RemoveAllAuras(); @@ -361,7 +361,7 @@ class npc_stonekeepers : public CreatureScript void EnterCombat(Unit* /*who*/) override { - me->SetFaction(14); + me->SetFaction(FACTION_FRIENDLY); me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->SetControlled(false, UNIT_STATE_ROOT); } diff --git a/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp b/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp index ac3d2aa110f..0b6128af171 100644 --- a/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp +++ b/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp @@ -149,7 +149,7 @@ class instance_uldaman : public InstanceMapScript void SetFrozenState(Creature* creature) { - creature->SetFaction(35); + creature->SetFaction(FACTION_FRIENDLY); creature->RemoveAllAuras(); creature->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); creature->SetControlled(true, UNIT_STATE_ROOT); @@ -184,7 +184,7 @@ class instance_uldaman : public InstanceMapScript if (!target || !target->IsAlive()) continue; target->SetControlled(false, UNIT_STATE_ROOT); - target->SetFaction(14); + target->SetFaction(FACTION_MONSTER); target->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); target->RemoveAura(SPELL_MINION_FREEZE_ANIM); @@ -205,11 +205,11 @@ class instance_uldaman : public InstanceMapScript for (GuidVector::const_iterator i = archaedasWallMinions.begin(); i != archaedasWallMinions.end(); ++i) { Creature* target = instance->GetCreature(*i); - if (!target || !target->IsAlive() || target->GetFaction() == 14) + if (!target || !target->IsAlive() || target->GetFaction() == FACTION_MONSTER) continue; target->SetControlled(false, UNIT_STATE_ROOT); target->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - target->SetFaction(14); + target->SetFaction(FACTION_MONSTER); target->RemoveAura(SPELL_MINION_FREEZE_ANIM); archaedas->CastSpell(target, SPELL_AWAKEN_VAULT_WALKER, true); target->CastSpell(target, SPELL_ARCHAEDAS_AWAKEN, true); @@ -269,7 +269,7 @@ class instance_uldaman : public InstanceMapScript if (!ironaya) return; - ironaya->SetFaction(415); + ironaya->SetFaction(FACTION_TITAN); ironaya->SetControlled(false, UNIT_STATE_ROOT); ironaya->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp index 3ad749d537d..f9cd1192777 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp @@ -93,7 +93,6 @@ enum Misc DATA_OHGANOT_SO_FAST = 5762, - FACTION_NONE = 1665 }; enum SummonGroups diff --git a/src/server/scripts/EasternKingdoms/zone_arathi_highlands.cpp b/src/server/scripts/EasternKingdoms/zone_arathi_highlands.cpp index f9f0985b416..0225040f053 100644 --- a/src/server/scripts/EasternKingdoms/zone_arathi_highlands.cpp +++ b/src/server/scripts/EasternKingdoms/zone_arathi_highlands.cpp @@ -56,8 +56,7 @@ enum ProfessorPhizzlethorpe QUEST_SUNKEN_TREASURE = 665, QUEST_GOGGLE_BOGGLE = 26050, // Creatures - NPC_VENGEFUL_SURGE = 2776, - FACTION_SUNKEN_TREASURE = 113 + NPC_VENGEFUL_SURGE = 2776 }; class npc_professor_phizzlethorpe : public CreatureScript @@ -113,7 +112,7 @@ class npc_professor_phizzlethorpe : public CreatureScript { Talk(SAY_PROGRESS_1, player); npc_escortAI::Start(false, false, player->GetGUID(), quest); - me->SetFaction(FACTION_SUNKEN_TREASURE); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE); } } diff --git a/src/server/scripts/EasternKingdoms/zone_ghostlands.cpp b/src/server/scripts/EasternKingdoms/zone_ghostlands.cpp index fd4617bb183..b00f3a0ee9d 100644 --- a/src/server/scripts/EasternKingdoms/zone_ghostlands.cpp +++ b/src/server/scripts/EasternKingdoms/zone_ghostlands.cpp @@ -52,8 +52,7 @@ enum RangerLilatha GO_CAGE = 181152, NPC_CAPTAIN_HELIOS = 16220, NPC_MUMMIFIED_HEADHUNTER = 16342, - NPC_SHADOWPINE_ORACLE = 16343, - FACTION_QUEST_ESCAPE = 113 + NPC_SHADOWPINE_ORACLE = 16343 }; class npc_ranger_lilatha : public CreatureScript @@ -132,7 +131,7 @@ public: { if (quest->GetQuestId() == QUEST_ESCAPE_FROM_THE_CATACOMBS) { - me->SetFaction(FACTION_QUEST_ESCAPE); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE); Start(true, false, player->GetGUID()); } } diff --git a/src/server/scripts/EasternKingdoms/zone_hinterlands.cpp b/src/server/scripts/EasternKingdoms/zone_hinterlands.cpp index 3fd9345ef0e..96f5b757c88 100644 --- a/src/server/scripts/EasternKingdoms/zone_hinterlands.cpp +++ b/src/server/scripts/EasternKingdoms/zone_hinterlands.cpp @@ -45,9 +45,7 @@ enum eOOX SAY_OOX_END = 4, QUEST_RESQUE_OOX_09 = 836, NPC_MARAUDING_OWL = 7808, - NPC_VILE_AMBUSHER = 7809, - FACTION_ESCORTEE_A = 774, - FACTION_ESCORTEE_H = 775 + NPC_VILE_AMBUSHER = 7809 }; class npc_oox09hl : public CreatureScript @@ -79,7 +77,7 @@ public: if (quest->GetQuestId() == QUEST_RESQUE_OOX_09) { me->SetStandState(UNIT_STAND_STATE_STAND); - me->SetFaction(player->GetTeam() == ALLIANCE ? FACTION_ESCORTEE_A : FACTION_ESCORTEE_H); + me->SetFaction(player->GetTeam() == ALLIANCE ? FACTION_ESCORTEE_A_PASSIVE : FACTION_ESCORTEE_H_PASSIVE); Talk(SAY_OOX_START, player); npc_escortAI::Start(false, false, player->GetGUID(), quest); } diff --git a/src/server/scripts/EasternKingdoms/zone_stranglethorn_vale.cpp b/src/server/scripts/EasternKingdoms/zone_stranglethorn_vale.cpp index 16306014b1d..5015ff30cc2 100644 --- a/src/server/scripts/EasternKingdoms/zone_stranglethorn_vale.cpp +++ b/src/server/scripts/EasternKingdoms/zone_stranglethorn_vale.cpp @@ -39,8 +39,6 @@ enum Yenniku { SPELL_YENNIKUS_RELEASE = 3607, QUEST_SAVING_YENNIKU = 592, - FACTION_HORDE_GENERIC = 83, - FACTION_TROLL_BLOODSCALP = 28 }; class npc_yenniku : public CreatureScript diff --git a/src/server/scripts/EasternKingdoms/zone_undercity.cpp b/src/server/scripts/EasternKingdoms/zone_undercity.cpp index 56cc8d49c25..f28570dc5d5 100644 --- a/src/server/scripts/EasternKingdoms/zone_undercity.cpp +++ b/src/server/scripts/EasternKingdoms/zone_undercity.cpp @@ -150,7 +150,7 @@ public: if (Creature* target = ObjectAccessor::GetCreature(*summoned, targetGUID)) { target->GetMotionMaster()->MoveJump(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ() + 15.0f, me->GetOrientation(), 0); - target->SetPosition(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0.0f); + target->UpdatePosition(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0.0f); summoned->CastSpell(target, SPELL_RIBBON_OF_SOULS, false); } @@ -298,7 +298,7 @@ public: { me->SetDisableGravity(true); me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW, me->GetDistance(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW) / (5000 * 0.001f)); - me->SetPosition(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW, me->GetOrientation()); + me->UpdatePosition(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW, me->GetOrientation()); EventMove = false; } else EventMoveTimer -= diff; } diff --git a/src/server/scripts/EasternKingdoms/zone_wetlands.cpp b/src/server/scripts/EasternKingdoms/zone_wetlands.cpp index 856080be6fa..f192a4bcf8f 100644 --- a/src/server/scripts/EasternKingdoms/zone_wetlands.cpp +++ b/src/server/scripts/EasternKingdoms/zone_wetlands.cpp @@ -39,7 +39,6 @@ EndContentData */ enum TapokeSlim { QUEST_MISSING_DIPLO_PT11 = 1249, - FACTION_ENEMY = 168, SPELL_STEALTH = 1785, SPELL_CALL_FRIENDS = 16457, //summons 1x friend NPC_SLIMS_FRIEND = 4971, diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp index 823ddd33aa9..39a1cbd7dde 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp @@ -917,7 +917,7 @@ void hyjalAI::HideNearPos(float x, float y) for (std::list<Creature*>::const_iterator itr = creatures.begin(); itr != creatures.end(); ++itr) { (*itr)->SetVisible(false); - (*itr)->SetFaction(35);//make them friendly so mobs won't attack them + (*itr)->SetFaction(FACTION_FRIENDLY);//make them friendly so mobs won't attack them } } } @@ -995,7 +995,7 @@ void hyjalAI::DoOverrun(uint32 faction, const uint32 diff) if ((*itr) && (*itr)->IsAlive()) { (*itr)->CastSpell(*itr, SPELL_TELEPORT_VISUAL, true); - (*itr)->SetFaction(35);//make them friendly so mobs won't attack them + (*itr)->SetFaction(FACTION_FRIENDLY);//make them friendly so mobs won't attack them (*itr)->AddUnitFlag(UNIT_FLAG_NON_ATTACKABLE); } } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp index 00ff25951df..4e280a1ca18 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp @@ -1175,7 +1175,7 @@ public: me->GetPosition(x, y, z); me->UpdateGroundPositionZ(x, y, z); me->GetMotionMaster()->MovePoint(0, x, y, z); - me->SetPosition(x, y, z, 0); + me->UpdatePosition(x, y, z, 0); } void EnterCombat(Unit* /*who*/) override { } @@ -1293,7 +1293,7 @@ public: me->GetPosition(x, y, z); me->UpdateGroundPositionZ(x, y, z); me->GetMotionMaster()->MovePoint(0, x, y, z); - me->SetPosition(x, y, z, 0); + me->UpdatePosition(x, y, z, 0); hyjal_trashAI::JustDied(killer); } diff --git a/src/server/scripts/Kalimdor/Maraudon/boss_noxxion.cpp b/src/server/scripts/Kalimdor/Maraudon/boss_noxxion.cpp index cb715b6f1e2..298a3535107 100644 --- a/src/server/scripts/Kalimdor/Maraudon/boss_noxxion.cpp +++ b/src/server/scripts/Kalimdor/Maraudon/boss_noxxion.cpp @@ -82,7 +82,7 @@ public: if (Invisible && InvisibleTimer <= diff) { //Become visible again - me->SetFaction(14); + me->SetFaction(FACTION_MONSTER); me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); //Noxxion model me->SetDisplayId(11172); @@ -122,7 +122,7 @@ public: //Interrupt any spell casting //me->m_canMove = true; me->InterruptNonMeleeSpells(false); - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); // Invisible Model me->SetDisplayId(11686); diff --git a/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp b/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp index 2c1059a9bd9..6d1f4c70be9 100644 --- a/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp +++ b/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp @@ -58,8 +58,6 @@ enum Belnistrasz EVENT_FIREBALL = 5, EVENT_FROST_NOVA = 6, - FACTION_ESCORT = 250, - PATH_ESCORT = 871710, POINT_REACH_IDOL = 17, @@ -137,7 +135,7 @@ public: eventInProgress = true; Talk(SAY_QUEST_ACCEPTED); me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); - me->SetFaction(FACTION_ESCORT); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_ACTIVE); me->GetMotionMaster()->MovePath(PATH_ESCORT, false); } } diff --git a/src/server/scripts/Kalimdor/RazorfenKraul/instance_razorfen_kraul.cpp b/src/server/scripts/Kalimdor/RazorfenKraul/instance_razorfen_kraul.cpp index 19c999033d7..470908d9a5d 100644 --- a/src/server/scripts/Kalimdor/RazorfenKraul/instance_razorfen_kraul.cpp +++ b/src/server/scripts/Kalimdor/RazorfenKraul/instance_razorfen_kraul.cpp @@ -57,7 +57,7 @@ public: switch (go->GetEntry()) { case 21099: DoorWardGUID = go->GetGUID(); break; - case 20920: go->SetFaction(0); break; // big fat fugly hack + case 20920: go->SetFaction(FACTION_NONE); break; // big fat fugly hack } } diff --git a/src/server/scripts/Kalimdor/RazorfenKraul/razorfen_kraul.cpp b/src/server/scripts/Kalimdor/RazorfenKraul/razorfen_kraul.cpp index 3f1ed9792ff..68d11185f33 100644 --- a/src/server/scripts/Kalimdor/RazorfenKraul/razorfen_kraul.cpp +++ b/src/server/scripts/Kalimdor/RazorfenKraul/razorfen_kraul.cpp @@ -58,7 +58,7 @@ public: { Start(true, false, player->GetGUID()); Talk(SAY_READY, player); - me->SetFaction(113); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE); } } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp index 340ae314f92..59d33f235f4 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp @@ -1042,7 +1042,7 @@ public: if (!target->HasAura(SPELL_DIGESTIVE_ACID)) { - me->SetPosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); + me->UpdatePosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); if (Creature* pPortal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) { pPortal->SetReactState(REACT_PASSIVE); @@ -1159,7 +1159,7 @@ public: if (!target->HasAura(SPELL_DIGESTIVE_ACID)) { - me->SetPosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); + me->UpdatePosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); if (Creature* pPortal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) { pPortal->SetReactState(REACT_PASSIVE); diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp index 3495a1a6d2b..067f326e011 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp @@ -111,7 +111,7 @@ public: //Cast me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE); me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); DoCast(me, SPELL_DIRTMOUND_PASSIVE); Submerged = true; @@ -134,7 +134,7 @@ public: if (Submerged && Back_Timer <= diff) { me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetFaction(14); + me->SetFaction(FACTION_MONSTER); DoCastVictim(SPELL_GROUND_RUPTURE); diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp index 4dd49bb1c66..b27a339ed7b 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp @@ -227,8 +227,8 @@ struct boss_twinemperorsAI : public ScriptedAI thisPos.Relocate(me); Position otherPos; otherPos.Relocate(pOtherBoss); - pOtherBoss->SetPosition(thisPos); - me->SetPosition(otherPos); + pOtherBoss->UpdatePosition(thisPos); + me->UpdatePosition(otherPos); SetAfterTeleport(); ENSURE_AI(boss_twinemperorsAI, pOtherBoss->AI())->SetAfterTeleport(); @@ -332,7 +332,7 @@ struct boss_twinemperorsAI : public ScriptedAI if (c->isDead()) { c->Respawn(); - c->SetFaction(7); + c->SetFaction(FACTION_CREATURE); c->RemoveAllAuras(); } if (c->IsWithinDistInMap(me, ABUSE_BUG_RANGE)) @@ -427,7 +427,7 @@ public: void CastSpellOnBug(Creature* target) override { - target->SetFaction(14); + target->SetFaction(FACTION_MONSTER); target->AI()->AttackStart(me->getThreatManager().getHostilTarget()); target->AddAura(SPELL_MUTATE_BUG, target); target->SetFullHealth(); @@ -518,7 +518,7 @@ public: void CastSpellOnBug(Creature* target) override { - target->SetFaction(14); + target->SetFaction(FACTION_MONSTER); target->AddAura(SPELL_EXPLODEBUG, target); target->SetFullHealth(); } diff --git a/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp b/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp index e3019c885bd..2c99ade96d3 100644 --- a/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp +++ b/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp @@ -329,7 +329,7 @@ public: Talk(SAY_MAKE_PREPARATIONS); - me->SetFaction(250); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_ACTIVE); me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); Start(false, false, player->GetGUID()); diff --git a/src/server/scripts/Kalimdor/ZulFarrak/boss_zum_rah.cpp b/src/server/scripts/Kalimdor/ZulFarrak/boss_zum_rah.cpp index f8b39df3d93..03443d77c6f 100644 --- a/src/server/scripts/Kalimdor/ZulFarrak/boss_zum_rah.cpp +++ b/src/server/scripts/Kalimdor/ZulFarrak/boss_zum_rah.cpp @@ -48,11 +48,6 @@ enum Events EVENT_HEALING_WAVE = 4 }; -enum Faction -{ - ZUMRAH_FRIENDLY_FACTION = 35 -}; - class boss_zum_rah : public CreatureScript { public: @@ -74,7 +69,7 @@ public: void Reset() override { - me->SetFaction(ZUMRAH_FRIENDLY_FACTION); // areatrigger sets faction to enemy + me->SetFaction(FACTION_FRIENDLY); // areatrigger sets faction to enemy Initialize(); } diff --git a/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.cpp b/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.cpp index 6b74f7d0221..3589c70fbec 100644 --- a/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.cpp +++ b/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.cpp @@ -43,13 +43,6 @@ EndContentData */ ## npc_sergeant_bly ######*/ -enum blyAndCrewFactions -{ - FACTION_HOSTILE = 14, - FACTION_FRIENDLY = 35, //while in cages (so the trolls won't attack them while they're caged) - FACTION_FREED = 250 //after release (so they'll be hostile towards trolls) -}; - enum blySays { SAY_1 = 0, @@ -120,7 +113,7 @@ public: Text_Timer = 5000; break; case 3: - me->SetFaction(FACTION_HOSTILE); + me->SetFaction(FACTION_MONSTER); if (Player* target = ObjectAccessor::GetPlayer(*me, PlayerGUID)) AttackStart(target); @@ -165,7 +158,7 @@ public: { if (Creature* crew = ObjectAccessor::GetCreature(*me, instance->GetGuidData(entry))) if (crew->IsAlive()) - crew->SetFaction(FACTION_HOSTILE); + crew->SetFaction(FACTION_MONSTER); } bool GossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override @@ -239,7 +232,7 @@ public: crew->SetWalk(true); crew->SetHomePosition(x, y, z, 0); crew->GetMotionMaster()->MovePoint(1, x, y, z); - crew->SetFaction(FACTION_FREED); + crew->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_ACTIVE); } } }; diff --git a/src/server/scripts/Kalimdor/zone_ashenvale.cpp b/src/server/scripts/Kalimdor/zone_ashenvale.cpp index 854e5322667..5fcf56a797e 100644 --- a/src/server/scripts/Kalimdor/zone_ashenvale.cpp +++ b/src/server/scripts/Kalimdor/zone_ashenvale.cpp @@ -44,7 +44,6 @@ enum RuulSnowhoof NPC_THISTLEFUR_TOTEMIC = 3922, NPC_THISTLEFUR_PATHFINDER = 3926, QUEST_FREEDOM_TO_RUUL = 6482, - FACTION_QUEST = 113, GO_CAGE = 178147 }; @@ -84,7 +83,7 @@ public: { if (quest->GetQuestId() == QUEST_FREEDOM_TO_RUUL) { - me->SetFaction(FACTION_QUEST); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE); npc_escortAI::Start(true, false, player->GetGUID()); } } @@ -227,7 +226,7 @@ public: if (quest->GetQuestId() == QUEST_VORSHA) { Talk(SAY_MUG_START1); - me->SetFaction(FACTION_QUEST); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE); npc_escortAI::Start(true, false, player->GetGUID()); } } diff --git a/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp b/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp index b834317359b..4bef27b450a 100644 --- a/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp +++ b/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp @@ -188,7 +188,6 @@ enum Overgrind AREA_COVE = 3579, AREA_ISLE = 3639, QUEST_GNOMERCY = 9537, - FACTION_HOSTILE = 14, SPELL_DYNAMITE = 7978 }; @@ -233,7 +232,7 @@ public: bool GossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override { CloseGossipMenuFor(player); - me->SetFaction(FACTION_HOSTILE); + me->SetFaction(FACTION_MONSTER); me->Attack(player, true); return false; } @@ -339,8 +338,7 @@ enum Magwin EVENT_STAND = 3, EVENT_TALK_END = 4, EVENT_COWLEN_TALK = 5, - QUEST_A_CRY_FOR_HELP = 9528, - FACTION_QUEST = 113 + QUEST_A_CRY_FOR_HELP = 9528 }; class npc_magwin : public CreatureScript @@ -405,7 +403,7 @@ public: case EVENT_ACCEPT_QUEST: if (Player* player = ObjectAccessor::GetPlayer(*me, _player)) Talk(SAY_START, player); - me->SetFaction(FACTION_QUEST); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE); _events.ScheduleEvent(EVENT_START_ESCORT, Seconds(1)); break; case EVENT_START_ESCORT: diff --git a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp index 99cc3ce925c..88429574c30 100644 --- a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp +++ b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp @@ -99,7 +99,6 @@ enum Hendel EMOTE_SURRENDER = 4, QUEST_MISSING_DIPLO_PT16 = 1324, - FACTION_HOSTILE = 168, //guessed, may be different NPC_SENTRY = 5184, //helps hendel NPC_JAINA = 4968, //appears once hendel gives up @@ -149,7 +148,7 @@ public: void QuestAccept(Player* /*player*/, Quest const* quest) override { if (quest->GetQuestId() == QUEST_MISSING_DIPLO_PT16) - me->SetFaction(FACTION_HOSTILE); + me->SetFaction(FACTION_ENEMY); } }; diff --git a/src/server/scripts/Kalimdor/zone_silithus.cpp b/src/server/scripts/Kalimdor/zone_silithus.cpp index bf1dc96d5e4..661eef0ad1f 100644 --- a/src/server/scripts/Kalimdor/zone_silithus.cpp +++ b/src/server/scripts/Kalimdor/zone_silithus.cpp @@ -54,9 +54,6 @@ enum EternalBoard { QUEST_A_PAWN_ON_THE_ETERNAL_BOARD = 8519, - FACTION_HOSTILE = 14, - FACTION_FRIENDLY = 35, - EVENT_AREA_RADIUS = 65, // 65yds EVENT_COOLDOWN = 500000, // in ms. appears after event completed or failed (should be = Adds despawn time) @@ -985,7 +982,7 @@ public: Merithra->SetNpcFlags(UNIT_NPC_FLAG_NONE); Merithra->SetStandState(UNIT_STAND_STATE_STAND); Merithra->SetDisplayId(MERITHRA_NIGHT_ELF_FORM); - Merithra->SetFaction(35); + Merithra->SetFaction(FACTION_FRIENDLY); } if (Caelestrasz) @@ -993,7 +990,7 @@ public: Caelestrasz->SetNpcFlags(UNIT_NPC_FLAG_NONE); Caelestrasz->SetStandState(UNIT_STAND_STATE_STAND); Caelestrasz->SetDisplayId(CAELESTRASZ_NIGHT_ELF_FORM); - Caelestrasz->SetFaction(35); + Caelestrasz->SetFaction(FACTION_FRIENDLY); } if (Arygos) @@ -1001,7 +998,7 @@ public: Arygos->SetNpcFlags(UNIT_NPC_FLAG_NONE); Arygos->SetStandState(UNIT_STAND_STATE_STAND); Arygos->SetDisplayId(ARYGOS_GNOME_FORM); - Arygos->SetFaction(35); + Arygos->SetFaction(FACTION_FRIENDLY); } if (Anachronos) diff --git a/src/server/scripts/Kalimdor/zone_tanaris.cpp b/src/server/scripts/Kalimdor/zone_tanaris.cpp index 78d64e4d21a..6a070468b38 100644 --- a/src/server/scripts/Kalimdor/zone_tanaris.cpp +++ b/src/server/scripts/Kalimdor/zone_tanaris.cpp @@ -90,7 +90,7 @@ public: void Reset() override { Initialize(); - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); } void SendItem(Unit* receiver) @@ -120,7 +120,7 @@ public: { if (SwitchFactionTimer <= diff) { - me->SetFaction(91); + me->SetFaction(FACTION_ELEMENTAL); isFriendly = false; } else SwitchFactionTimer -= diff; } @@ -362,7 +362,7 @@ public: { if (quest->GetQuestId() == Q_OOX17) { - me->SetFaction(113); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE); me->SetFullHealth(); me->SetStandState(UNIT_STAND_STATE_STAND); me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); diff --git a/src/server/scripts/Kalimdor/zone_the_barrens.cpp b/src/server/scripts/Kalimdor/zone_the_barrens.cpp index fd602f78a6d..734f14e65f4 100644 --- a/src/server/scripts/Kalimdor/zone_the_barrens.cpp +++ b/src/server/scripts/Kalimdor/zone_the_barrens.cpp @@ -87,8 +87,7 @@ enum Gilthares SAY_GIL_FREED = 7, QUEST_FREE_FROM_HOLD = 898, - AREA_MERCHANT_COAST = 391, - FACTION_ESCORTEE = 232 //guessed, possible not needed for this quest + AREA_MERCHANT_COAST = 391 }; class npc_gilthares : public CreatureScript @@ -150,7 +149,7 @@ public: { if (quest->GetQuestId() == QUEST_FREE_FROM_HOLD) { - me->SetFaction(FACTION_ESCORTEE); + me->SetFaction(FACTION_ESCORTEE_H_NEUTRAL_ACTIVE); me->SetStandState(UNIT_STAND_STATE_STAND); Talk(SAY_GIL_START, player); diff --git a/src/server/scripts/Kalimdor/zone_winterspring.cpp b/src/server/scripts/Kalimdor/zone_winterspring.cpp index d29175c8985..81b79d276cb 100644 --- a/src/server/scripts/Kalimdor/zone_winterspring.cpp +++ b/src/server/scripts/Kalimdor/zone_winterspring.cpp @@ -587,7 +587,7 @@ public: if (quest->GetQuestId() == QUEST_GUARDIANS_ALTAR) { Talk(SAY_QUEST_START); - me->SetFaction(FACTION_ESCORT_A_NEUTRAL_PASSIVE); + me->SetFaction(FACTION_ESCORTEE_A_NEUTRAL_PASSIVE); Start(false, false, player->GetGUID(), quest); } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp index 81dcf1846a6..895b9e15cc4 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp @@ -195,7 +195,7 @@ public: { damage = 0; EnterEvadeMode(); - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); bDone = true; } } @@ -323,7 +323,7 @@ public: { damage = 0; EnterEvadeMode(); - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); bDone = true; } } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index 868bb4e07c8..34af2872fdd 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -226,7 +226,7 @@ class boss_anubarak_trial : public CreatureScript for (int i = 0; i < 10; i++) if (Creature* scarab = me->SummonCreature(NPC_SCARAB, AnubarakLoc[1].GetPositionX()+urand(0, 50)-25, AnubarakLoc[1].GetPositionY()+urand(0, 50)-25, AnubarakLoc[1].GetPositionZ())) { - scarab->SetFaction(31); + scarab->SetFaction(FACTION_PREY); scarab->GetMotionMaster()->MoveRandom(10); } } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index d4976c75255..cdf2feee3e8 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -204,7 +204,6 @@ enum Actions enum Misc { DATA_MADE_A_MESS = 45374613, // 4537, 4613 are achievement IDs - FACTION_SCOURGE = 974, GOSSIP_MENU_MURADIN_BRONZEBEARD = 10934, GOSSIP_MENU_HIGH_OVERLORD_SAURFANG = 10952 @@ -463,7 +462,7 @@ class boss_deathbringer_saurfang : public CreatureScript { case EVENT_INTRO_ALLIANCE_2: me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetFaction(FACTION_SCOURGE); + me->SetFaction(FACTION_UNDEAD_SCOURGE); Talk(SAY_INTRO_ALLIANCE_2); break; case EVENT_INTRO_ALLIANCE_3: @@ -476,7 +475,7 @@ class boss_deathbringer_saurfang : public CreatureScript break; case EVENT_INTRO_HORDE_2: me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetFaction(FACTION_SCOURGE); + me->SetFaction(FACTION_UNDEAD_SCOURGE); Talk(SAY_INTRO_HORDE_2); break; case EVENT_INTRO_HORDE_4: diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp index f4e8d4e10b1..638c600905f 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp @@ -57,62 +57,68 @@ enum ScriptTexts enum Spells { // Lady Deathwhisper - SPELL_MANA_BARRIER = 70842, - SPELL_SHADOW_BOLT = 71254, - SPELL_DEATH_AND_DECAY = 71001, - SPELL_DOMINATE_MIND = 71289, - SPELL_DOMINATE_MIND_SCALE = 71290, - SPELL_FROSTBOLT = 71420, - SPELL_FROSTBOLT_VOLLEY = 72905, - SPELL_TOUCH_OF_INSIGNIFICANCE = 71204, - SPELL_SUMMON_SHADE = 71363, - SPELL_SHADOW_CHANNELING = 43897, - SPELL_DARK_TRANSFORMATION_T = 70895, - SPELL_DARK_EMPOWERMENT_T = 70896, - SPELL_DARK_MARTYRDOM_T = 70897, - SPELL_SUMMON_SPIRITS = 72478, + SPELL_MANA_BARRIER = 70842, + SPELL_SHADOW_BOLT = 71254, + SPELL_DEATH_AND_DECAY = 71001, + SPELL_DOMINATE_MIND = 71289, + SPELL_DOMINATE_MIND_SCALE = 71290, + SPELL_FROSTBOLT = 71420, + SPELL_FROSTBOLT_VOLLEY = 72905, + SPELL_TOUCH_OF_INSIGNIFICANCE = 71204, + SPELL_SUMMON_SHADE = 71363, + SPELL_SHADOW_CHANNELING = 43897, + SPELL_DARK_TRANSFORMATION_T = 70895, + SPELL_DARK_EMPOWERMENT_T = 70896, + SPELL_DARK_MARTYRDOM_T = 70897, + SPELL_SUMMON_SPIRITS = 72478, // Achievement - SPELL_FULL_HOUSE = 72827, // does not exist in dbc but still can be used for criteria check + SPELL_FULL_HOUSE = 72827, // does not exist in dbc but still can be used for criteria check // Both Adds - SPELL_TELEPORT_VISUAL = 41236, - SPELL_CLEAR_ALL_DEBUFFS = 34098, - SPELL_FULL_HEAL = 17683, - SPELL_PERMANENT_FEIGN_DEATH = 70628, + SPELL_TELEPORT_VISUAL = 41236, + SPELL_CLEAR_ALL_DEBUFFS = 34098, + SPELL_FULL_HEAL = 17683, + SPELL_PERMANENT_FEIGN_DEATH = 70628, // Fanatics - SPELL_DARK_TRANSFORMATION = 70900, - SPELL_NECROTIC_STRIKE = 70659, - SPELL_SHADOW_CLEAVE = 70670, - SPELL_VAMPIRIC_MIGHT = 70674, - SPELL_FANATIC_S_DETERMINATION = 71235, - SPELL_DARK_MARTYRDOM_FANATIC = 71236, + SPELL_DARK_TRANSFORMATION = 70900, + SPELL_NECROTIC_STRIKE = 70659, + SPELL_SHADOW_CLEAVE = 70670, + SPELL_VAMPIRIC_MIGHT = 70674, + SPELL_FANATIC_S_DETERMINATION = 71235, + SPELL_DARK_MARTYRDOM_FANATIC = 71236, + SPELL_DARK_MARTYRDOM_FANATIC_25N = 72495, + SPELL_DARK_MARTYRDOM_FANATIC_10H = 72496, + SPELL_DARK_MARTYRDOM_FANATIC_25H = 72497, // Adherents - SPELL_DARK_EMPOWERMENT = 70901, - SPELL_FROST_FEVER = 67767, - SPELL_DEATHCHILL_BOLT = 70594, - SPELL_DEATHCHILL_BLAST = 70906, - SPELL_CURSE_OF_TORPOR = 71237, - SPELL_SHROUD_OF_THE_OCCULT = 70768, - SPELL_ADHERENT_S_DETERMINATION = 71234, - SPELL_DARK_MARTYRDOM_ADHERENT = 70903, + SPELL_DARK_EMPOWERMENT = 70901, + SPELL_FROST_FEVER = 67767, + SPELL_DEATHCHILL_BOLT = 70594, + SPELL_DEATHCHILL_BLAST = 70906, + SPELL_CURSE_OF_TORPOR = 71237, + SPELL_SHROUD_OF_THE_OCCULT = 70768, + SPELL_ADHERENT_S_DETERMINATION = 71234, + SPELL_DARK_MARTYRDOM_ADHERENT = 70903, + SPELL_DARK_MARTYRDOM_ADHERENT_25N = 72498, + SPELL_DARK_MARTYRDOM_ADHERENT_10H = 72499, + SPELL_DARK_MARTYRDOM_ADHERENT_25H = 72500, // Vengeful Shade - SPELL_VENGEFUL_BLAST = 71544, - SPELL_VENGEFUL_BLAST_PASSIVE = 71494, - SPELL_VENGEFUL_BLAST_25N = 72010, - SPELL_VENGEFUL_BLAST_10H = 72011, - SPELL_VENGEFUL_BLAST_25H = 72012, + SPELL_VENGEFUL_BLAST = 71544, + SPELL_VENGEFUL_BLAST_PASSIVE = 71494, + SPELL_VENGEFUL_BLAST_25N = 72010, + SPELL_VENGEFUL_BLAST_10H = 72011, + SPELL_VENGEFUL_BLAST_25H = 72012, // Darnavan - SPELL_BLADESTORM = 65947, - SPELL_CHARGE = 65927, - SPELL_INTIMIDATING_SHOUT = 65930, - SPELL_MORTAL_STRIKE = 65926, - SPELL_SHATTERING_THROW = 65940, - SPELL_SUNDER_ARMOR = 65936, + SPELL_BLADESTORM = 65947, + SPELL_CHARGE = 65927, + SPELL_INTIMIDATING_SHOUT = 65930, + SPELL_MORTAL_STRIKE = 65926, + SPELL_SHATTERING_THROW = 65940, + SPELL_SUNDER_ARMOR = 65936, }; enum EventTypes @@ -359,7 +365,7 @@ class boss_lady_deathwhisper : public CreatureScript { if (darnavan->IsAlive()) { - darnavan->SetFaction(35); + darnavan->SetFaction(FACTION_FRIENDLY); darnavan->CombatStop(true); darnavan->GetMotionMaster()->MoveIdle(); darnavan->SetReactState(REACT_PASSIVE); @@ -640,6 +646,9 @@ class npc_cult_fanatic : public CreatureScript DoCastSelf(SPELL_DARK_MARTYRDOM_FANATIC); break; case SPELL_DARK_MARTYRDOM_FANATIC: + case SPELL_DARK_MARTYRDOM_FANATIC_25N: + case SPELL_DARK_MARTYRDOM_FANATIC_10H: + case SPELL_DARK_MARTYRDOM_FANATIC_25H: _scheduler .Schedule(Seconds(2), [this](TaskContext /*context*/) { @@ -739,6 +748,9 @@ class npc_cult_adherent : public CreatureScript DoCastSelf(SPELL_DARK_MARTYRDOM_ADHERENT); break; case SPELL_DARK_MARTYRDOM_ADHERENT: + case SPELL_DARK_MARTYRDOM_ADHERENT_25N: + case SPELL_DARK_MARTYRDOM_ADHERENT_10H: + case SPELL_DARK_MARTYRDOM_ADHERENT_25H: _scheduler .Schedule(Seconds(2), [this](TaskContext /*context*/) { diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp index 0a7857225ad..97ba864358a 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -264,7 +264,7 @@ class ValithriaDespawner : public BasicEvent creature->SetRespawnDelay(10); if (CreatureData const* data = creature->GetCreatureData()) - creature->SetPosition(data->posX, data->posY, data->posZ, data->orientation); + creature->UpdatePosition(data->posX, data->posY, data->posZ, data->orientation); creature->DespawnOrUnsummon(); creature->SetCorpseDelay(corpseDelay); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index 1e857d6164c..1462ebc1df1 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -358,7 +358,7 @@ class FrostwingGauntletRespawner creature->SetRespawnDelay(2); if (CreatureData const* data = creature->GetCreatureData()) - creature->SetPosition(data->posX, data->posY, data->posZ, data->orientation); + creature->UpdatePosition(data->posX, data->posY, data->posZ, data->orientation); creature->DespawnOrUnsummon(); creature->SetCorpseDelay(corpseDelay); diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index 0aa77ef0eb2..cb85a35c884 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -175,12 +175,6 @@ enum Seats SEAT_0 = 0 }; -enum Factions -{ - // Needed for melee hover disks /when Nexus Lords die/ - FACTION_FRIENDLY = 35 -}; - enum Actions { // Malygos diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp index a75650dd6ba..48b1772ea95 100644 --- a/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp +++ b/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp @@ -261,7 +261,7 @@ public: for (uint8 n = 0; n < 3; ++n) time[n] = 0; me->GetMotionMaster()->Clear(); - me->SetPosition(CenterOfRoom.GetPositionX(), CenterOfRoom.GetPositionY(), CenterOfRoom.GetPositionZ(), CenterOfRoom.GetOrientation()); + me->UpdatePosition(CenterOfRoom.GetPositionX(), CenterOfRoom.GetPositionY(), CenterOfRoom.GetPositionZ(), CenterOfRoom.GetOrientation()); DoCast(me, SPELL_TELESTRA_BACK); me->SetVisible(true); if (Phase == 1) diff --git a/src/server/scripts/Northrend/Nexus/Nexus/instance_nexus.cpp b/src/server/scripts/Northrend/Nexus/Nexus/instance_nexus.cpp index 857ce9c32b4..5b3228e6413 100644 --- a/src/server/scripts/Northrend/Nexus/Nexus/instance_nexus.cpp +++ b/src/server/scripts/Northrend/Nexus/Nexus/instance_nexus.cpp @@ -23,11 +23,6 @@ #include "nexus.h" #include "Player.h" -enum Factions -{ - FACTION_HOSTILE_FOR_ALL = 16 -}; - class instance_nexus : public InstanceMapScript { public: @@ -61,31 +56,31 @@ class instance_nexus : public InstanceMapScript // Alliance npcs are spawned by default, if you are alliance, you will fight against horde npcs. case NPC_ALLIANCE_BERSERKER: if (ServerAllowsTwoSideGroups()) - creature->SetFaction(FACTION_HOSTILE_FOR_ALL); + creature->SetFaction(FACTION_MONSTER_2); if (_teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_HORDE_BERSERKER); break; case NPC_ALLIANCE_RANGER: if (ServerAllowsTwoSideGroups()) - creature->SetFaction(FACTION_HOSTILE_FOR_ALL); + creature->SetFaction(FACTION_MONSTER_2); if (_teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_HORDE_RANGER); break; case NPC_ALLIANCE_CLERIC: if (ServerAllowsTwoSideGroups()) - creature->SetFaction(FACTION_HOSTILE_FOR_ALL); + creature->SetFaction(FACTION_MONSTER_2); if (_teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_HORDE_CLERIC); break; case NPC_ALLIANCE_COMMANDER: if (ServerAllowsTwoSideGroups()) - creature->SetFaction(FACTION_HOSTILE_FOR_ALL); + creature->SetFaction(FACTION_MONSTER_2); if (_teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_HORDE_COMMANDER); break; case NPC_COMMANDER_STOUTBEARD: if (ServerAllowsTwoSideGroups()) - creature->SetFaction(FACTION_HOSTILE_FOR_ALL); + creature->SetFaction(FACTION_MONSTER_2); if (_teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_COMMANDER_KOLURG); break; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 3f622a72c83..201655985d1 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -538,7 +538,7 @@ class boss_algalon_the_observer : public CreatureScript damage = 0; me->SetReactState(REACT_PASSIVE); me->AttackStop(); - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); DoCast(me, SPELL_SELF_STUN); events.Reset(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp index 09240de5649..004760c07ee 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -780,7 +780,7 @@ class boss_flame_leviathan_safety_container : public CreatureScript me->GetPosition(x, y, z); z = me->GetMap()->GetHeight(me->GetPhaseShift(), x, y, z); me->GetMotionMaster()->MovePoint(0, x, y, z); - me->SetPosition(x, y, z, 0); + me->UpdatePosition(x, y, z, 0); } void UpdateAI(uint32 /*diff*/) override diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp index 33e346e0c94..e0a73d09571 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp @@ -226,7 +226,7 @@ class npc_iron_roots : public CreatureScript SetCombatMovement(false); me->ApplySpellImmune(0, IMMUNITY_ID, 49560, true); // Death Grip - me->SetFaction(14); + me->SetFaction(FACTION_MONSTER); me->SetReactState(REACT_PASSIVE); } @@ -270,6 +270,7 @@ class boss_freya : public CreatureScript { boss_freyaAI(Creature* creature) : BossAI(creature, BOSS_FREYA) { + _encounterFinished = false; Initialize(); memset(elementalTimer, 0, sizeof(elementalTimer)); diffTimer = 0; @@ -312,9 +313,13 @@ class boss_freya : public CreatureScript bool checkElementalAlive[2]; bool trioDefeated[2]; bool random[3]; + bool _encounterFinished; void Reset() override { + if (_encounterFinished) + return; + _Reset(); Initialize(); } @@ -595,6 +600,11 @@ class boss_freya : public CreatureScript void JustDied(Unit* /*killer*/) override { + if (_encounterFinished) + return; + + _encounterFinished = true; + //! Freya's chest is dynamically spawned on death by different spells. const uint32 summonSpell[2][4] = { @@ -606,15 +616,15 @@ class boss_freya : public CreatureScript me->CastSpell((Unit*)NULL, summonSpell[me->GetMap()->GetDifficultyID() - DIFFICULTY_10_N][elderCount], true); Talk(SAY_DEATH); + me->SetReactState(REACT_PASSIVE); - _JustDied(); - me->RemoveAllAuras(); + me->InterruptNonMeleeSpells(true); + me->RemoveAllAttackers(); me->AttackStop(); - me->SetFaction(35); - me->DeleteThreatList(); - me->CombatStop(true); + me->SetFaction(FACTION_FRIENDLY); me->DespawnOrUnsummon(7500); me->CastSpell(me, SPELL_KNOCK_ON_WOOD_CREDIT, true); + _JustDied(); for (uint8 n = 0; n < 3; ++n) { diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp index a320994dc07..6635ece7ee9 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp @@ -408,7 +408,7 @@ class boss_hodir : public CreatureScript DoCastAOE(SPELL_KILL_CREDIT, true); /// need to be cast before changing boss faction /// spell will target enemies only - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); me->DespawnOrUnsummon(10000); _JustDied(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp index cfe2d3879d1..76acc9e7c45 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp @@ -180,7 +180,7 @@ class boss_ignis : public CreatureScript { if (summon->GetEntry() == NPC_IRON_CONSTRUCT) { - summon->SetFaction(16); + summon->SetFaction(FACTION_MONSTER_2); summon->SetReactState(REACT_AGGRESSIVE); summon->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED | UNIT_FLAG_STUNNED | UNIT_FLAG_IMMUNE_TO_PC)); summon->SetControlled(false, UNIT_STATE_ROOT); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index 690a1ecdbfc..b23e296f0df 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -638,7 +638,7 @@ class boss_mimiron : public CreatureScript case EVENT_OUTTRO_1: me->RemoveAurasDueToSpell(SPELL_SLEEP_VISUAL_1); DoCast(me, SPELL_SLEEP_VISUAL_2); - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); events.ScheduleEvent(EVENT_OUTTRO_2, 3000); break; case EVENT_OUTTRO_2: diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp index a833e13aeec..825718bd3ee 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp @@ -15,27 +15,427 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "MoveSplineInit.h" +#include "Player.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "TypeContainerVisitor.h" +#include "CellImpl.h" +#include "GridNotifiersImpl.h" #include "ulduar.h" +#include "SpellAuras.h" +#include "SpellMgr.h" +#include <G3D/Vector3.h> +#include "AreaBoundary.h" +#include "InstanceScript.h" +#include "ObjectAccessor.h" +#include "MotionMaster.h" + +enum Spells +{ + // Thorim + SPELL_SHEATH_OF_LIGHTNING = 62276, + SPELL_STORMHAMMER = 62042, + SPELL_STORMHAMMER_SIF = 64767, + SPELL_STORMHAMMER_BOOMERANG = 64909, + SPELL_DEAFENING_THUNDER = 62470, + SPELL_CHARGE_ORB = 62016, + SPELL_SUMMON_LIGHTNING_ORB = 62391, + SPELL_LIGHTNING_DESTRUCTION = 62393, + SPELL_TOUCH_OF_DOMINION = 62507, + SPELL_TOUCH_OF_DOMINION_TRIGGERED = 62565, + SPELL_CHAIN_LIGHTNING = 62131, + SPELL_LIGHTNING_ORB_CHARGED = 62186, // wrong duration, triggered spell should handle lightning release + SPELL_LIGHTNING_CHARGE = 62279, + SPELL_LIGHTNING_RELEASE = 62466, + SPELL_LIGHTNING_PILLAR_2 = 62976, // caster high position, target low position + SPELL_LIGHTNING_PILLAR_1 = 63238, // caster high position, target low position + SPELL_UNBALANCING_STRIKE = 62130, + SPELL_BERSERK_PHASE_1 = 62560, + SPELL_BERSERK_PHASE_2 = 62555, + SPELL_ACTIVATE_LIGHTNING_ORB_PERIODIC = 62184, + + // Credits + SPELL_CREDIT_SIFFED = 64980, + SPELL_CREDIT_KILL = 64985, + + // Lightning Field + SPELL_LIGHTNING_FIELD = 64972, + SPELL_LIGHTNING_BEAM_CHANNEL = 45537, + + // Sif + SPELL_BLIZZARD = 62577, + SPELL_BLINK = 62578, + SPELL_FROSTBOLT_VOLLEY = 62580, + SPELL_FROSTBOLT = 62583, + SPELL_FROSTNOVA = 62597, + SPELL_SIF_TRANSFORM = 64778, + + // Runic Colossus + SPELL_SMASH = 62339, + SPELL_RUNIC_BARRIER = 62338, + SPELL_RUNIC_CHARGE = 62613, + SPELL_RUNIC_SMASH = 62465, + SPELL_RUNIC_SMASH_RIGHT = 62057, + SPELL_RUNIC_SMASH_LEFT = 62058, + + // Ancient Rune Giant + SPELL_RUNIC_FORTIFICATION = 62942, + SPELL_RUNE_DETONATION = 62526, + SPELL_STOMP = 62411 +}; + +enum Phases +{ + PHASE_NULL, + PHASE_1, + PHASE_2 +}; + +enum Events +{ + // Thorim + EVENT_SAY_AGGRO_2 = 1, + EVENT_SAY_SIF_START, + EVENT_START_SIF_CHANNEL, + EVENT_STORMHAMMER, + EVENT_CHARGE_ORB, + EVENT_SUMMON_ADDS, + EVENT_BERSERK, + EVENT_JUMPDOWN, + EVENT_UNBALANCING_STRIKE, + EVENT_CHAIN_LIGHTNING, + EVENT_START_PERIODIC_CHARGE, + EVENT_LIGHTNING_CHARGE, + EVENT_ACTIVATE_LIGHTNING_FIELD, + EVENT_OUTRO_1, + EVENT_OUTRO_2, + EVENT_OUTRO_3, + + // Runic Colossus + EVENT_RUNIC_BARRIER, + EVENT_SMASH, + EVENT_RUNIC_CHARGE, + EVENT_RUNIC_SMASH, + + // Ancient Rune Giant + EVENT_RUNIC_FORTIFICATION, + EVENT_STOMP, + EVENT_RUNE_DETONATION, + + // Arena NPC + EVENT_PRIMARY_ABILITY, + EVENT_SECONDARY_ABILITY, + EVENT_THIRD_ABILITY, + EVENT_ABILITY_CHARGE, + + // Sif + EVENT_BLINK, + EVENT_FROST_NOVA, + EVENT_FROSTBOLT, + EVENT_FROSTBOLT_VOLLEY, + EVENT_BLIZZARD +}; enum Yells { - SAY_AGGRO = 0, - SAY_SPECIAL_1 = 1, - SAY_SPECIAL_2 = 2, - SAY_SPECIAL_3 = 3, - SAY_JUMPDOWN = 4, - SAY_SLAY = 5, - SAY_BERSERK = 6, - SAY_WIPE = 7, - SAY_DEATH = 8, - SAY_END_NORMAL_1 = 9, - SAY_END_NORMAL_2 = 10, - SAY_END_NORMAL_3 = 11, - SAY_END_HARD_1 = 12, - SAY_END_HARD_2 = 13, - SAY_END_HARD_3 = 14 + // Thorim + SAY_AGGRO_1 = 0, + SAY_AGGRO_2 = 1, + SAY_SPECIAL = 2, + SAY_JUMPDOWN = 3, + SAY_SLAY = 4, + SAY_BERSERK = 5, + SAY_WIPE = 6, + SAY_DEATH = 7, + SAY_END_NORMAL_1 = 8, + SAY_END_NORMAL_2 = 9, + SAY_END_NORMAL_3 = 10, + SAY_END_HARD_1 = 11, + SAY_END_HARD_2 = 12, + SAY_END_HARD_3 = 13, + + // Runic Colossus + EMOTE_RUNIC_BARRIER = 0, + + // Ancient Rune Giant + EMOTE_RUNIC_MIGHT = 0, + + // Sif + SAY_SIF_START = 0, + SAY_SIF_DESPAWN = 1, + SAY_SIF_EVENT = 2 +}; + +enum PreAddSpells +{ + SPELL_ACID_BREATH = 62315, + SPELL_SWEEP = 62316, + + SPELL_DEVASTATE = 62317, + SPELL_HEROIC_SWIPE = 62444, + SPELL_SUNDER_ARMOR = 57807, + + SPELL_BARBED_SHOT = 62318, + SPELL_SHOOT = 16496, + + SPELL_RENEW = 62333, + SPELL_GREATER_HEAL = 62334, /// 61965 + SPELL_CIRCLE_OF_HEALING = 61964, + + SPELL_HOLY_SMITE = 62335, + + SPELL_LEAP = 61934, + + SPELL_CHARGE = 32323, + SPELL_MORTAL_STRIKE = 35054, + SPELL_WHIRLWIND = 33500, + + SPELL_LOW_BLOW = 62326, + SPELL_PUMMEL = 38313, + + SPELL_RUNIC_LIGHTNING = 62327, + SPELL_RUNIC_MENDING = 62328, + SPELL_RUNIC_SHIELD = 62321, + + SPELL_RUNIC_STRIKE = 62322, + SPELL_AURA_OF_CELERITY = 62320, + + SPELL_IMPALE = 62331, + SPELL_WHIRLING_TRIP = 64151, + + SPELL_CLEAVE = 42724, + SPELL_HAMSTRING = 48639, + SPELL_SHIELD_SMASH = 62332, +}; + +enum TrashTypes +{ + // Pre Phase Trash + BEHEMOTH, + MERCENARY_CAPTAIN, + MERCENARY_SOLDIER, + + // Arena Phase Trash + DARK_RUNE_CHAMPION, + DARK_RUNE_WARBRINGER, + DARK_RUNE_COMMONER, + DARK_RUNE_EVOKER, + + // Hall Way Trash + IRON_RING_GUARD, + IRON_HONOR_GUARD, + + // Shared + DARK_RUNE_ACOLYTE +}; + +struct ThorimTrashInfo +{ + uint32 Type; + uint32 Entry; + uint32 PrimaryAbility; + uint32 SecondaryAbility; + uint32 ThirdAbility; +}; + +uint8 const ThorimTrashCount = 13; +ThorimTrashInfo const StaticThorimTrashInfo[ThorimTrashCount] = +{ + // Pre Phase + { BEHEMOTH, NPC_JORMUNGAR_BEHEMOTH, SPELL_ACID_BREATH, SPELL_SWEEP, 0 }, + { MERCENARY_CAPTAIN, NPC_MERCENARY_CAPTAIN_A, SPELL_DEVASTATE, SPELL_HEROIC_SWIPE, SPELL_SUNDER_ARMOR }, + { MERCENARY_SOLDIER, NPC_MERCENARY_SOLDIER_A, SPELL_BARBED_SHOT, SPELL_SHOOT, 0 }, + { DARK_RUNE_ACOLYTE, NPC_DARK_RUNE_ACOLYTE_PRE, SPELL_RENEW, SPELL_GREATER_HEAL, SPELL_CIRCLE_OF_HEALING }, + { MERCENARY_CAPTAIN, NPC_MERCENARY_CAPTAIN_H, SPELL_DEVASTATE, SPELL_HEROIC_SWIPE, SPELL_SUNDER_ARMOR }, + { MERCENARY_SOLDIER, NPC_MERCENARY_SOLDIER_H, SPELL_BARBED_SHOT, SPELL_SHOOT, 0 }, + + // Arena Phase + { DARK_RUNE_CHAMPION, NPC_DARK_RUNE_CHAMPION, SPELL_MORTAL_STRIKE, SPELL_WHIRLWIND, 0 }, + { DARK_RUNE_WARBRINGER, NPC_DARK_RUNE_WARBRINGER, SPELL_RUNIC_STRIKE, 0, 0 }, + { DARK_RUNE_EVOKER, NPC_DARK_RUNE_EVOKER, SPELL_RUNIC_LIGHTNING, SPELL_RUNIC_SHIELD, SPELL_RUNIC_MENDING }, + { DARK_RUNE_COMMONER, NPC_DARK_RUNE_COMMONER, SPELL_LOW_BLOW, SPELL_PUMMEL, 0 }, + + // Hall Way + { IRON_RING_GUARD, NPC_IRON_RING_GUARD, SPELL_WHIRLING_TRIP, SPELL_IMPALE, 0 }, + { IRON_HONOR_GUARD, NPC_IRON_HONOR_GUARD, SPELL_CLEAVE, SPELL_SHIELD_SMASH, 0 }, + { DARK_RUNE_ACOLYTE, NPC_DARK_RUNE_ACOLYTE, SPELL_RENEW, SPELL_GREATER_HEAL, 0 } +}; + +enum Actions +{ + ACTION_INCREASE_PREADDS_COUNT, + ACTION_ACTIVATE_RUNIC_SMASH, + ACTION_ACTIVATE_ADDS, + ACTION_PILLAR_CHARGED, + ACTION_START_HARD_MODE, + ACTION_BERSERK +}; + +struct SummonLocation +{ + Position pos; + uint32 entry; +}; + +SummonLocation const PreAddLocations[] = +{ + { { 2149.68f, -263.477f, 419.679f, 3.120f }, NPC_JORMUNGAR_BEHEMOTH }, + { { 2131.31f, -271.640f, 419.840f, 2.188f }, NPC_MERCENARY_CAPTAIN_A }, + { { 2127.24f, -259.182f, 419.974f, 5.917f }, NPC_MERCENARY_SOLDIER_A }, + { { 2123.32f, -254.770f, 419.840f, 6.170f }, NPC_MERCENARY_SOLDIER_A }, + { { 2120.10f, -258.990f, 419.840f, 6.250f }, NPC_MERCENARY_SOLDIER_A }, + { { 2129.09f, -277.142f, 419.756f, 1.222f }, NPC_DARK_RUNE_ACOLYTE_PRE } +}; + +SummonLocation const ColossusAddLocations[] = +{ + { { 2218.38f, -297.50f, 412.18f, 1.030f }, NPC_IRON_RING_GUARD }, + { { 2235.07f, -297.98f, 412.18f, 1.613f }, NPC_IRON_RING_GUARD }, + { { 2235.26f, -338.34f, 412.18f, 1.589f }, NPC_IRON_RING_GUARD }, + { { 2217.69f, -337.39f, 412.18f, 1.241f }, NPC_IRON_RING_GUARD }, + { { 2227.58f, -308.30f, 412.18f, 1.591f }, NPC_DARK_RUNE_ACOLYTE }, + { { 2227.47f, -345.37f, 412.18f, 1.566f }, NPC_DARK_RUNE_ACOLYTE } +}; + +SummonLocation const GiantAddLocations[] = +{ + { { 2198.05f, -428.77f, 419.95f, 6.056f }, NPC_IRON_HONOR_GUARD }, + { { 2220.31f, -436.22f, 412.26f, 1.064f }, NPC_IRON_HONOR_GUARD }, + { { 2158.88f, -441.73f, 438.25f, 0.127f }, NPC_IRON_HONOR_GUARD }, + { { 2198.29f, -436.92f, 419.95f, 0.261f }, NPC_DARK_RUNE_ACOLYTE }, + { { 2230.93f, -434.27f, 412.26f, 1.931f }, NPC_DARK_RUNE_ACOLYTE } +}; + +Position const SifSpawnPosition = { 2148.301f, -297.8453f, 438.3308f, 2.687807f }; + +enum Data +{ + DATA_CHARGED_PILLAR = 1 +}; + +enum DisplayIds +{ + THORIM_WEAPON_DISPLAY_ID = 45900 +}; + +uint32 const LightningOrbPathSize = 8; +G3D::Vector3 const LightningOrbPath[LightningOrbPathSize] = +{ + { 2134.889893f, -298.632996f, 438.247467f }, + { 2134.570068f, -440.317993f, 438.247467f }, + { 2167.820312f, -440.330261f, 438.247589f }, + { 2213.394287f, -433.318298f, 412.665863f }, + { 2227.766113f, -433.275818f, 412.177032f }, + { 2227.551270f, -263.081085f, 412.176880f }, + { 2202.208008f, -262.939270f, 412.168976f }, + { 2182.310059f, -263.233093f, 414.739410f } +}; + +// used for trash jump calculation +Position const ArenaCenter = { 2134.77f, -262.307f }; + +// used for lightning field calculation +Position const LightningFieldCenter = { 2135.178f, -321.122f }; + +CircleBoundary const ArenaFloorCircle(ArenaCenter, 45.4); +CircleBoundary const InvertedBalconyCircle(LightningFieldCenter, 32.0, true); + +CreatureBoundary const ArenaBoundaries = +{ + &ArenaFloorCircle, + &InvertedBalconyCircle +}; + +class HeightPositionCheck +{ + public: + HeightPositionCheck(bool ret) : _ret(ret) { } + + bool operator()(Position const* pos) const + { + return pos->GetPositionZ() > THORIM_BALCONY_Z_CHECK == _ret; + } + + private: + bool _ret; + + static float const THORIM_BALCONY_Z_CHECK; +}; +float const HeightPositionCheck::THORIM_BALCONY_Z_CHECK = 428.0f; + +class RunicSmashExplosionEvent : public BasicEvent +{ + public: + RunicSmashExplosionEvent(Creature* owner) : _owner(owner) { } + + bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override + { + _owner->CastSpell((Unit*)nullptr, SPELL_RUNIC_SMASH); + return true; + } + + private: + Creature* _owner; +}; + +class TrashJumpEvent : public BasicEvent +{ + public: + TrashJumpEvent(Creature* owner) : _owner(owner), _stage(0) { } + + bool Execute(uint64 eventTime, uint32 /*updateTime*/) override + { + switch (_stage) + { + case 0: + _owner->CastSpell((Unit*)nullptr, SPELL_LEAP); + ++_stage; + _owner->m_Events.AddEvent(this, eventTime + 2000); + return false; + case 1: + _owner->SetReactState(REACT_AGGRESSIVE); + _owner->AI()->DoZoneInCombat(_owner); + _owner->AI()->SetBoundary(&ArenaBoundaries); + return true; + default: + break; + } + + return true; + } + + private: + Creature* _owner; + uint8 _stage; +}; + +class LightningFieldEvent : public BasicEvent +{ + public: + LightningFieldEvent(Creature* owner) : _owner(owner) { } + + bool Execute(uint64 eventTime, uint32 /*updateTime*/) override + { + if (InstanceScript* instance = _owner->GetInstanceScript()) + { + if (instance->GetBossState(BOSS_THORIM) == IN_PROGRESS) + { + _owner->CastSpell((Unit*)nullptr, SPELL_LIGHTNING_FIELD); + _owner->m_Events.AddEvent(this, eventTime + 1000); + return false; + } + } + + _owner->InterruptNonMeleeSpells(false); + _owner->AI()->EnterEvadeMode(); + return true; + } + + private: + Creature* _owner; }; class boss_thorim : public CreatureScript @@ -47,17 +447,76 @@ class boss_thorim : public CreatureScript { boss_thorimAI(Creature* creature) : BossAI(creature, BOSS_THORIM) { + _encounterFinished = false; + Initialize(); + } + + void Initialize() + { + _killedCount = 0; + _waveType = 0; + _hardMode = true; + _orbSummoned = false; + _dontStandInTheLightning = true; } void Reset() override { + if (_encounterFinished) + return; + + SetBoundary(nullptr); _Reset(); + Initialize(); + + me->SetReactState(REACT_PASSIVE); + me->SetDisableGravity(true); + me->SetControlled(true, UNIT_STATE_ROOT); + me->AddUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); + + events.SetPhase(PHASE_NULL); + + // Respawn Mini Bosses + for (uint8 i = DATA_RUNIC_COLOSSUS; i <= DATA_RUNE_GIANT; ++i) + if (Creature* miniBoss = ObjectAccessor::GetCreature(*me, instance->GetGuidData(i))) + miniBoss->Respawn(true); + + // Spawn Pre Phase Adds + for (SummonLocation const& s : PreAddLocations) + me->SummonCreature(s.entry, s.pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000); + + if (GameObject* lever = instance->GetGameObject(DATA_THORIM_LEVER)) + lever->AddFlag(GO_FLAG_NOT_SELECTABLE); + + // Remove trigger auras + if (Creature* pillar = ObjectAccessor::GetCreature(*me, _activePillarGUID)) + pillar->RemoveAllAuras(); + + if (Creature* controller = instance->GetCreature(DATA_THORIM_CONTROLLER)) + controller->RemoveAllAuras(); + + _activePillarGUID.Clear(); } - void EnterEvadeMode(EvadeReason why) override + void EnterEvadeMode(EvadeReason /*why*/) override { - Talk(SAY_WIPE); - _EnterEvadeMode(why); + summons.DespawnAll(); + _DespawnAtEvade(); + } + + void SetGUID(ObjectGuid guid, int32 type) override + { + if (type == DATA_CHARGED_PILLAR) + { + _activePillarGUID = guid; + + if (Creature* pillar = ObjectAccessor::GetCreature(*me, _activePillarGUID)) + { + pillar->CastSpell(pillar, SPELL_LIGHTNING_ORB_CHARGED, true); + pillar->CastSpell((Unit*)nullptr, SPELL_LIGHTNING_PILLAR_2); + events.ScheduleEvent(EVENT_LIGHTNING_CHARGE, 8000, 0, PHASE_2); + } + } } void KilledUnit(Unit* who) override @@ -66,27 +525,410 @@ class boss_thorim : public CreatureScript Talk(SAY_SLAY); } - void JustDied(Unit* /*killer*/) override + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override { - Talk(SAY_DEATH); + if (spellInfo->Id == SPELL_TOUCH_OF_DOMINION_TRIGGERED) + { + if (Creature* sif = instance->GetCreature(DATA_SIF)) + { + sif->AI()->Talk(SAY_SIF_DESPAWN); + sif->DespawnOrUnsummon(6000); + _hardMode = false; + } + } + } + + void SpellHitTarget(Unit* who, SpellInfo const* spellInfo) override + { + if (who->GetTypeId() == TYPEID_PLAYER && spellInfo->Id == SPELL_LIGHTNING_RELEASE) + _dontStandInTheLightning = false; + } + + void FinishEncounter() + { + if (_encounterFinished) + return; + + _encounterFinished = true; + + DoCastAOE(SPELL_CREDIT_KILL, true); // before change faction + + me->SetReactState(REACT_PASSIVE); + me->InterruptNonMeleeSpells(true); + me->RemoveAllAttackers(); + me->AttackStop(); + me->SetFaction(FACTION_FRIENDLY); + me->AddUnitFlag(UNIT_FLAG_RENAME); + + if (Creature* controller = instance->GetCreature(DATA_THORIM_CONTROLLER)) + controller->RemoveAllAuras(); + if (Creature* pillar = ObjectAccessor::GetCreature(*me, _activePillarGUID)) + pillar->RemoveAllAuras(); + + if (_hardMode) + { + if (Creature* sif = instance->GetCreature(DATA_SIF)) + { + summons.Despawn(sif); + sif->DespawnOrUnsummon(10000); + } + } + _JustDied(); + + Talk(SAY_DEATH); + events.ScheduleEvent(EVENT_OUTRO_1, 4000); + events.ScheduleEvent(EVENT_OUTRO_2, _hardMode ? 8000 : 11000); + events.ScheduleEvent(EVENT_OUTRO_3, _hardMode ? 19000 : 21000); + + me->m_Events.AddEvent(new KeeperDespawnEvent(me), me->m_Events.CalculateTime(35000)); + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type != EFFECT_MOTION_TYPE || id != EVENT_JUMP) + return; + + me->getThreatManager().resetAllAggro(); + SetBoundary(&ArenaBoundaries); } void EnterCombat(Unit* /*who*/) override { - Talk(SAY_AGGRO); _EnterCombat(); + Talk(SAY_AGGRO_1); + + events.SetPhase(PHASE_1); + + events.ScheduleEvent(EVENT_SAY_AGGRO_2, 9000, 0, PHASE_1); + events.ScheduleEvent(EVENT_SAY_SIF_START, 16500, 0, PHASE_1); + events.ScheduleEvent(EVENT_START_SIF_CHANNEL, 22500, 0, PHASE_1); + + events.ScheduleEvent(EVENT_STORMHAMMER, 40000, 0, PHASE_1); + events.ScheduleEvent(EVENT_CHARGE_ORB, 30000, 0, PHASE_1); + events.ScheduleEvent(EVENT_SUMMON_ADDS, 15000, 0, PHASE_1); + events.ScheduleEvent(EVENT_BERSERK, 369000); + + DoCast(me, SPELL_SHEATH_OF_LIGHTNING); + + if (Creature* runicColossus = instance->GetCreature(DATA_RUNIC_COLOSSUS)) + { + runicColossus->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); + runicColossus->AI()->DoAction(ACTION_ACTIVATE_ADDS); + } + + if (GameObject* lever = instance->GetGameObject(DATA_THORIM_LEVER)) + lever->RemoveFlag(GO_FLAG_NOT_SELECTABLE); + + // Summon Sif + me->SummonCreature(NPC_SIF, SifSpawnPosition); + } + + void JustSummoned(Creature* summon) override + { + switch (summon->GetEntry()) + { + case NPC_LIGHTNING_ORB: + { + summon->SetReactState(REACT_PASSIVE); + summon->CastSpell(summon, SPELL_LIGHTNING_DESTRUCTION, true); + + summon->GetMotionMaster()->MovePoint(EVENT_CHARGE_PREPATH, LightningOrbPath[LightningOrbPathSize - 1].x, LightningOrbPath[LightningOrbPathSize - 1].y, LightningOrbPath[LightningOrbPathSize - 1].z, false); + + Movement::PointsArray path(LightningOrbPath, LightningOrbPath + LightningOrbPathSize); + + Movement::MoveSplineInit init(summon); + init.MovebyPath(path); + init.Launch(); + break; + } + case NPC_DARK_RUNE_CHAMPION: + case NPC_DARK_RUNE_WARBRINGER: + case NPC_DARK_RUNE_EVOKER: + case NPC_DARK_RUNE_COMMONER: + summon->SetReactState(REACT_PASSIVE); + summon->m_Events.AddEvent(new TrashJumpEvent(summon), summon->m_Events.CalculateTime(3000)); + break; + case NPC_SIF: + summon->SetReactState(REACT_PASSIVE); + break; + default: + break; + } + + BossAI::JustSummoned(summon); } - void UpdateAI(uint32 /*diff*/) override + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; - //SPELLS @todo - // + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SAY_AGGRO_2: + Talk(SAY_AGGRO_2); + break; + case EVENT_SAY_SIF_START: + if (Creature* sif = instance->GetCreature(DATA_SIF)) + sif->AI()->Talk(SAY_SIF_START); + break; + case EVENT_START_SIF_CHANNEL: + if (Creature* sif = instance->GetCreature(DATA_SIF)) + sif->CastSpell(me, SPELL_TOUCH_OF_DOMINION); + break; + case EVENT_STORMHAMMER: + DoCast(SPELL_STORMHAMMER); + events.Repeat(15000, 20000); + break; + case EVENT_CHARGE_ORB: + DoCastAOE(SPELL_CHARGE_ORB); + events.Repeat(15000, 20000); + break; + case EVENT_SUMMON_ADDS: + SummonWave(); + events.Repeat(_orbSummoned ? 3000 : 10000); + break; + case EVENT_JUMPDOWN: + if (_hardMode) + if (Creature* sif = instance->GetCreature(DATA_SIF)) + sif->AI()->DoAction(ACTION_START_HARD_MODE); + me->RemoveAurasDueToSpell(SPELL_SHEATH_OF_LIGHTNING); + me->SetReactState(REACT_AGGRESSIVE); + me->SetDisableGravity(false); + me->SetControlled(false, UNIT_STATE_ROOT); + me->GetMotionMaster()->MoveJump(2134.8f, -263.056f, 419.983f, me->GetOrientation(), 30.0f, 20.0f); + events.ScheduleEvent(EVENT_START_PERIODIC_CHARGE, 2000, 0, PHASE_2); + events.ScheduleEvent(EVENT_UNBALANCING_STRIKE, 15000, 0, PHASE_2); + events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 20000, 0, PHASE_2); + break; + case EVENT_UNBALANCING_STRIKE: + DoCastVictim(SPELL_UNBALANCING_STRIKE); + events.Repeat(15000, 20000); + break; + case EVENT_CHAIN_LIGHTNING: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_CHAIN_LIGHTNING); + events.Repeat(7000, 15000); + break; + case EVENT_START_PERIODIC_CHARGE: + if (Creature* controller = instance->GetCreature(DATA_THORIM_CONTROLLER)) + controller->CastSpell(controller, SPELL_ACTIVATE_LIGHTNING_ORB_PERIODIC, true); + break; + case EVENT_LIGHTNING_CHARGE: + if (Creature* pillar = ObjectAccessor::GetCreature(*me, _activePillarGUID)) + DoCast(pillar, SPELL_LIGHTNING_RELEASE); + break; + case EVENT_BERSERK: + if (events.IsInPhase(PHASE_1)) + { + Talk(SAY_WIPE); + DoCastAOE(SPELL_BERSERK_PHASE_1, true); + DoCast(me, SPELL_SUMMON_LIGHTNING_ORB, true); + } + else + { + Talk(SAY_BERSERK); + DoCast(me, SPELL_BERSERK_PHASE_2, true); + } + break; + case EVENT_ACTIVATE_LIGHTNING_FIELD: + { + std::list<Creature*> triggers; + me->GetCreatureListWithEntryInGrid(triggers, NPC_THORIM_EVENT_BUNNY, 100.0f); + triggers.remove_if([](Creature* bunny) + { + if (HeightPositionCheck(false)(bunny)) + return true; + return LightningFieldCenter.GetExactDist2dSq(bunny) > 1296.0f; + }); + + uint64 timer = 1000; + for (Creature* bunny : triggers) + bunny->m_Events.AddEvent(new LightningFieldEvent(bunny), bunny->m_Events.CalculateTime(timer += 100)); + + triggers.remove_if([](Creature* bunny) + { + return LightningFieldCenter.GetExactDist2dSq(bunny) < 576.0f; + }); + + triggers.sort([](Creature* a, Creature* b) + { + return a->GetPositionX() < b->GetPositionX(); + }); + + for (auto itr = triggers.cbegin(); itr != triggers.cend();) + { + auto prev = itr++; + if (itr != triggers.end()) + (*prev)->CastSpell(*itr, SPELL_LIGHTNING_BEAM_CHANNEL); + } + break; + } + case EVENT_OUTRO_1: + Talk(_hardMode ? SAY_END_HARD_1 : SAY_END_NORMAL_1); + if (_hardMode) + DoCast(me, SPELL_STORMHAMMER_SIF); + break; + case EVENT_OUTRO_2: + Talk(_hardMode ? SAY_END_HARD_2 : SAY_END_NORMAL_2); + if (_hardMode) + if (Creature* sif = instance->GetCreature(DATA_SIF)) + sif->SetStandState(UNIT_STAND_STATE_DEAD); + break; + case EVENT_OUTRO_3: + Talk(_hardMode ? SAY_END_HARD_3 : SAY_END_NORMAL_3); + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + DoMeleeAttackIfReady(); } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_BERSERK: + if (events.IsInPhase(PHASE_2)) + return; + + if (!_orbSummoned) + { + _orbSummoned = true; + events.RescheduleEvent(EVENT_BERSERK, 1000); + } + return; + case ACTION_INCREASE_PREADDS_COUNT: + if (++_killedCount >= 6) + { + // Event starts + me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); + DoZoneInCombat(me); + } + break; + default: + break; + } + } + + void GetTrashSpawnTriggers(std::list<Creature*>& triggerList, uint32 count = 1) + { + me->GetCreatureListWithEntryInGrid(triggerList, NPC_THORIM_EVENT_BUNNY, 100.0f); + triggerList.remove_if([](Creature* bunny) + { + if (HeightPositionCheck(false)(bunny)) + return true; + return ArenaCenter.GetExactDist2dSq(bunny) < 3025.0f; + }); + + if (triggerList.empty()) + return; + + if (count == 1) + { + Creature* bunny = Trinity::Containers::SelectRandomContainerElement(triggerList); + triggerList.clear(); + triggerList.push_back(bunny); + } + else + Trinity::Containers::RandomResize(triggerList, count); + } + + void SummonWave() + { + switch (_waveType) + { + case 0: + { + // Dark Rune Commoner + std::list<Creature*> triggers; + GetTrashSpawnTriggers(triggers, urand(5, 6)); + + for (Creature* bunny : triggers) + me->SummonCreature(StaticThorimTrashInfo[6 + 3].Entry, *bunny, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000); + + ++_waveType; + break; + } + case 1: + if (urand(0, 1)) + { + // Dark Rune Champion or Dark Rune Evoker + std::list<Creature*> triggers; + GetTrashSpawnTriggers(triggers, urand(2, 4)); + + for (Creature* bunny : triggers) + me->SummonCreature(StaticThorimTrashInfo[6 + RAND(0, 2)].Entry, *bunny, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000); + } + else + { + // Dark Rune Warbringer + std::list<Creature*> triggers; + GetTrashSpawnTriggers(triggers); + + for (Creature* bunny : triggers) + me->SummonCreature(StaticThorimTrashInfo[6 + 1].Entry, *bunny, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000); + } + --_waveType; + break; + } + } + + bool CanStartPhase2(Unit* actor) const + { + if (actor->GetTypeId() != TYPEID_PLAYER || !me->IsWithinDistInMap(actor, 10.0f)) + return false; + + Creature* runicColossus = instance->GetCreature(DATA_RUNIC_COLOSSUS); + Creature* runeGiant = instance->GetCreature(DATA_RUNE_GIANT); + return runicColossus && !runicColossus->IsAlive() && runeGiant && !runeGiant->IsAlive(); + } + + void DamageTaken(Unit* attacker, uint32& damage) override + { + if (events.IsInPhase(PHASE_1) && CanStartPhase2(attacker)) + { + Talk(SAY_JUMPDOWN); + events.SetPhase(PHASE_2); + events.ScheduleEvent(EVENT_JUMPDOWN, 8000); + events.ScheduleEvent(EVENT_ACTIVATE_LIGHTNING_FIELD, 15000); + events.RescheduleEvent(EVENT_BERSERK, 300000, 0, PHASE_2); + + if (Creature* sif = instance->GetCreature(DATA_SIF)) + sif->InterruptNonMeleeSpells(false); + + // Hard Mode + if (_hardMode) + DoCastAOE(SPELL_CREDIT_SIFFED, true); + } + else if (me->HealthBelowPctDamaged(1, damage)) + { + damage = 0; + FinishEncounter(); + } + } + + private: + ObjectGuid _activePillarGUID; + uint8 _killedCount; + uint8 _waveType; + bool _hardMode; + bool _encounterFinished; + bool _orbSummoned; + bool _dontStandInTheLightning; }; CreatureAI* GetAI(Creature* creature) const override @@ -95,7 +937,1234 @@ class boss_thorim : public CreatureScript } }; +struct npc_thorim_trashAI : public ScriptedAI +{ + npc_thorim_trashAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + for (uint8 i = 0; i < ThorimTrashCount; ++i) + if (me->GetEntry() == StaticThorimTrashInfo[i].Entry) + _info = &StaticThorimTrashInfo[i]; + + ASSERT(_info); + } + + struct AIHelper + { + /// returns heal amount of the given spell including hots + static uint32 GetTotalHeal(SpellInfo const* spellInfo, Unit const* caster) + { + uint32 heal = 0; + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) + { + if (effect->IsEffect(SPELL_EFFECT_HEAL)) + heal += effect->CalcValue(caster); + + if (effect->IsEffect(SPELL_EFFECT_APPLY_AURA) && effect->IsAura(SPELL_AURA_PERIODIC_HEAL)) + heal += spellInfo->GetMaxTicks() * effect->CalcValue(caster); + } + return heal; + } + + /// returns remaining heal amount on given target + static uint32 GetRemainingHealOn(Unit* target) + { + uint32 heal = 0; + Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL); + for (AuraEffect const* aurEff : auras) + heal += aurEff->GetAmount() * (aurEff->GetTotalTicks() - aurEff->GetTickNumber()); + + return heal; + } + + class MostHPMissingInRange + { + public: + MostHPMissingInRange(Unit const* referer, float range, uint32 hp, uint32 exclAura = 0, bool exclSelf = false) + : _referer(referer), _range(range), _hp(hp), _exclAura(exclAura), _exclSelf(exclSelf) { } + + bool operator()(Unit* u) + { + if (_exclSelf && u == _referer) + return false; + + if (_exclAura && u->HasAura(_exclAura)) + return false; + + if ((u->GetHealth() + GetRemainingHealOn(u) + _hp) > u->GetMaxHealth()) + return false; + + uint32 missingHP = u->GetMaxHealth() - u->GetHealth(); + if (u->IsAlive() && _referer->IsFriendlyTo(u) && _referer->IsWithinDistInMap(u, _range) && missingHP > _hp) + { + _hp = missingHP; + return true; + } + + return false; + } + + private: + Unit const* _referer; + float _range; + uint32 _hp; + uint32 _exclAura; + bool _exclSelf; + }; + + static Unit* GetUnitWithMostMissingHp(SpellInfo const* spellInfo, Unit* caster) + { + // use positive range, it's a healing spell + float const range = spellInfo->GetMaxRange(true); + uint32 const heal = GetTotalHeal(spellInfo, caster); + + Unit* target = nullptr; + Trinity::MostHPMissingInRange checker(caster, range, heal); + Trinity::UnitLastSearcher<Trinity::MostHPMissingInRange> searcher(caster, target, checker); + Cell::VisitGridObjects(caster, searcher, 60.0f); + + return target; + } + + static Unit* GetHealTarget(SpellInfo const* spellInfo, Unit* caster) + { + Unit* healTarget = nullptr; + if (!spellInfo->HasAttribute(SPELL_ATTR1_CANT_TARGET_SELF) && !roll_chance_f(caster->GetHealthPct()) && ((caster->GetHealth() + GetRemainingHealOn(caster) + GetTotalHeal(spellInfo, caster)) <= caster->GetMaxHealth())) + healTarget = caster; + else + healTarget = GetUnitWithMostMissingHp(spellInfo, caster); + + return healTarget; + } + }; + + bool UseAbility(uint32 spellId) + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetDifficulty()); + if (!spellInfo) + return false; + + Unit* target = nullptr; + if (AIHelper::GetTotalHeal(spellInfo, me)) + target = AIHelper::GetHealTarget(spellInfo, me); + else + target = me->GetVictim(); + + if (!target) + return false; + + if (_info->Type == MERCENARY_SOLDIER) + { + bool allowMove = true; + if (me->IsInRange(target, spellInfo->GetMinRange(), spellInfo->GetMaxRange())) + allowMove = false; + + if (IsCombatMovementAllowed() != allowMove) + { + SetCombatMovement(allowMove); + + // need relaunch movement + ScriptedAI::AttackStart(target); + + // give some time to allow reposition, try again in a second + if (allowMove) + return false; + } + } + + DoCast(target, spellId); + return true; + } + + void UpdateAI(uint32 diff) final override + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + ExecuteEvent(eventId); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + + if (_info->Type == DARK_RUNE_ACOLYTE) + DoSpellAttackIfReady(SPELL_HOLY_SMITE); + else + DoMeleeAttackIfReady(); + } + + virtual void ExecuteEvent(uint32 eventId) = 0; + +protected: + InstanceScript* _instance; + EventMap _events; + + ThorimTrashInfo const* _info = nullptr; +}; + +class npc_thorim_pre_phase : public CreatureScript +{ + public: + npc_thorim_pre_phase() : CreatureScript("npc_thorim_pre_phase") { } + + struct npc_thorim_pre_phaseAI : public npc_thorim_trashAI + { + npc_thorim_pre_phaseAI(Creature* creature) : npc_thorim_trashAI(creature) + { + me->setActive(true); // prevent grid unload + } + + void Reset() override + { + _events.Reset(); + if (_info->PrimaryAbility) + _events.ScheduleEvent(EVENT_PRIMARY_ABILITY, urand(3000, 6000)); + if (_info->SecondaryAbility) + _events.ScheduleEvent(EVENT_SECONDARY_ABILITY, _info->SecondaryAbility == SPELL_SHOOT ? 2000 : urand(12000, 15000)); + if (_info->ThirdAbility) + _events.ScheduleEvent(EVENT_THIRD_ABILITY, urand(6000, 8000)); + if (_info->Type == MERCENARY_SOLDIER) + SetCombatMovement(false); + } + + void JustDied(Unit* /*victim*/) override + { + if (Creature* thorim = _instance->GetCreature(BOSS_THORIM)) + thorim->AI()->DoAction(ACTION_INCREASE_PREADDS_COUNT); + } + + bool ShouldSparWith(Unit const* target) const override + { + return !target->GetAffectingPlayer(); + } + + void DamageTaken(Unit* attacker, uint32& damage) override + { + // nullify spell damage + if (!attacker->GetAffectingPlayer()) + damage = 0; + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case EVENT_PRIMARY_ABILITY: + if (UseAbility(_info->PrimaryAbility)) + _events.ScheduleEvent(eventId, urand(15000, 20000)); + else + _events.ScheduleEvent(eventId, 1000); + break; + case EVENT_SECONDARY_ABILITY: + if (UseAbility(_info->SecondaryAbility)) + _events.ScheduleEvent(eventId, _info->SecondaryAbility == SPELL_SHOOT ? 2000 : urand(4000, 8000)); + else + _events.ScheduleEvent(eventId, 1000); + break; + case EVENT_THIRD_ABILITY: + if (UseAbility(_info->ThirdAbility)) + _events.ScheduleEvent(eventId, urand(6000, 8000)); + else + _events.ScheduleEvent(eventId, 1000); + break; + default: + break; + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_thorim_pre_phaseAI>(creature); + } +}; + +class npc_thorim_arena_phase : public CreatureScript +{ + public: + npc_thorim_arena_phase() : CreatureScript("npc_thorim_arena_phase") { } + + struct npc_thorim_arena_phaseAI : public npc_thorim_trashAI + { + npc_thorim_arena_phaseAI(Creature* creature) : npc_thorim_trashAI(creature) + { + switch (_info->Type) + { + case DARK_RUNE_CHAMPION: + case DARK_RUNE_WARBRINGER: + case DARK_RUNE_COMMONER: + case DARK_RUNE_EVOKER: + _isInArena = true; + break; + case DARK_RUNE_ACOLYTE: + { + _isInArena = (_info->Entry == NPC_DARK_RUNE_ACOLYTE_PRE); + SetBoundary(&ArenaBoundaries, !_isInArena); + break; + } + default: + _isInArena = false; + break; + } + } + + bool CanAIAttack(Unit const* who) const override + { + // don't try to attack players in balcony + if (_isInArena && HeightPositionCheck(true)(who)) + return false; + + return CheckBoundary(who); + } + + void Reset() override + { + _events.Reset(); + if (_info->PrimaryAbility) + _events.ScheduleEvent(EVENT_PRIMARY_ABILITY, urand(3000, 6000)); + if (_info->SecondaryAbility) + _events.ScheduleEvent(EVENT_SECONDARY_ABILITY, urand(7000, 9000)); + if (_info->ThirdAbility) + _events.ScheduleEvent(EVENT_THIRD_ABILITY, urand(6000, 8000)); + if (_info->Type == DARK_RUNE_CHAMPION) + _events.ScheduleEvent(EVENT_ABILITY_CHARGE, 8000); + } + + void EnterCombat(Unit* /*who*/) override + { + if (_info->Type == DARK_RUNE_WARBRINGER) + DoCast(me, SPELL_AURA_OF_CELERITY); + + if (!_isInArena) + if (Creature* colossus = _instance->GetCreature(DATA_RUNIC_COLOSSUS)) + colossus->AI()->DoAction(ACTION_ACTIVATE_RUNIC_SMASH); + } + + void EnterEvadeMode(EvadeReason why) override + { + if (why != EVADE_REASON_NO_HOSTILES && why != EVADE_REASON_BOUNDARY) + return; + + // this should only happen if theres no alive player in the arena -> summon orb + if (Creature* thorim = _instance->GetCreature(BOSS_THORIM)) + thorim->AI()->DoAction(ACTION_BERSERK); + ScriptedAI::EnterEvadeMode(why); + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case EVENT_PRIMARY_ABILITY: + if (UseAbility(_info->PrimaryAbility)) + _events.Repeat(3000, 6000); + else + _events.Repeat(1000); + break; + case EVENT_SECONDARY_ABILITY: + if (UseAbility(_info->SecondaryAbility)) + _events.Repeat(12000, 16000); + else + _events.Repeat(1000); + break; + case EVENT_THIRD_ABILITY: + if (UseAbility(_info->ThirdAbility)) + _events.Repeat(6000, 8000); + else + _events.Repeat(1000); + break; + case EVENT_ABILITY_CHARGE: + { + Unit* referer = me; + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, [referer](Unit* unit){ return unit->GetTypeId() == TYPEID_PLAYER && unit->IsInRange(referer, 8.0f, 25.0f); })) + DoCast(target, SPELL_CHARGE); + _events.ScheduleEvent(eventId, 12000); + break; + } + default: + break; + } + } + + private: + bool _isInArena; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_thorim_arena_phaseAI>(creature); + } +}; + +struct npc_thorim_minibossAI : public ScriptedAI +{ + npc_thorim_minibossAI(Creature* creature) : ScriptedAI(creature), _summons(me) + { + _instance = creature->GetInstanceScript(); + + SetBoundary(&ArenaBoundaries, true); + } + + bool CanAIAttack(Unit const* who) const final override + { + return CheckBoundary(who); + } + + void JustSummoned(Creature* summon) final override + { + _summons.Summon(summon); + } + + void SummonedCreatureDespawn(Creature* summon) final override + { + _summons.Despawn(summon); + } + + void DoAction(int32 action) override + { + if (action == ACTION_ACTIVATE_ADDS) + { + for (ObjectGuid const& guid : _summons) + if (Creature* summon = ObjectAccessor::GetCreature(*me, guid)) + summon->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); + } + } + +protected: + InstanceScript* _instance; + EventMap _events; + SummonList _summons; +}; + +class npc_runic_colossus : public CreatureScript +{ + public: + npc_runic_colossus() : CreatureScript("npc_runic_colossus") { } + + struct npc_runic_colossusAI : public npc_thorim_minibossAI + { + npc_runic_colossusAI(Creature* creature) : npc_thorim_minibossAI(creature) + { + Initialize(); + } + + void Initialize() + { + _runicActive = false; + } + + void Reset() override + { + Initialize(); + _events.Reset(); + + // close the Runic Door + _instance->HandleGameObject(_instance->GetGuidData(DATA_RUNIC_DOOR), false); + + // Spawn trashes + _summons.DespawnAll(); + for (SummonLocation const& s : ColossusAddLocations) + me->SummonCreature(s.entry, s.pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000); + } + + void MoveInLineOfSight(Unit* /*who*/) override + { + // don't enter combat + } + + void DoAction(int32 action) override + { + npc_thorim_minibossAI::DoAction(action); + + if (_runicActive) + return; + + if (action == ACTION_ACTIVATE_RUNIC_SMASH) + { + _runicActive = true; + _events.ScheduleEvent(EVENT_RUNIC_SMASH, 7000); + } + } + + void JustDied(Unit* /*victim*/) override + { + // open the Runic Door + _instance->HandleGameObject(_instance->GetGuidData(DATA_RUNIC_DOOR), true); + + if (Creature* thorim = _instance->GetCreature(BOSS_THORIM)) + thorim->AI()->Talk(SAY_SPECIAL); + + if (Creature* giant = _instance->GetCreature(DATA_RUNE_GIANT)) + { + giant->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); + giant->AI()->DoAction(ACTION_ACTIVATE_ADDS); + } + } + + void EnterCombat(Unit* /*who*/) override + { + DoZoneInCombat(); + _events.Reset(); + _events.ScheduleEvent(EVENT_RUNIC_BARRIER, urand(12000, 15000)); + _events.ScheduleEvent(EVENT_SMASH, urand(15000, 18000)); + _events.ScheduleEvent(EVENT_RUNIC_CHARGE, urand(20000, 24000)); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_RUNIC_BARRIER: + Talk(EMOTE_RUNIC_BARRIER); + DoCastAOE(SPELL_RUNIC_BARRIER); + _events.Repeat(35000, 45000); + break; + case EVENT_SMASH: + DoCastAOE(SPELL_SMASH); + _events.Repeat(15000, 18000); + break; + case EVENT_RUNIC_CHARGE: + { + Unit* referer = me; + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, [referer](Unit* unit){ return unit->GetTypeId() == TYPEID_PLAYER && unit->IsInRange(referer, 8.0f, 40.0f); })) + DoCast(target, SPELL_RUNIC_CHARGE); + _events.Repeat(20000); + break; + } + case EVENT_RUNIC_SMASH: + DoCast(me, RAND(SPELL_RUNIC_SMASH_LEFT, SPELL_RUNIC_SMASH_RIGHT)); + _events.Repeat(6000); + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + + private: + bool _runicActive; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_runic_colossusAI>(creature); + } +}; + +class npc_ancient_rune_giant : public CreatureScript +{ + public: + npc_ancient_rune_giant() : CreatureScript("npc_ancient_rune_giant") { } + + struct npc_ancient_rune_giantAI : public npc_thorim_minibossAI + { + npc_ancient_rune_giantAI(Creature* creature) : npc_thorim_minibossAI(creature) { } + + void Reset() override + { + _events.Reset(); + + // close the Stone Door + _instance->HandleGameObject(_instance->GetGuidData(DATA_STONE_DOOR), false); + + // Spawn trashes + _summons.DespawnAll(); + for (SummonLocation const& s : GiantAddLocations) + me->SummonCreature(s.entry, s.pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000); + } + + void EnterCombat(Unit* /*who*/) override + { + DoZoneInCombat(); + _events.Reset(); + _events.ScheduleEvent(EVENT_RUNIC_FORTIFICATION, 1); + _events.ScheduleEvent(EVENT_STOMP, urand(10000, 12000)); + _events.ScheduleEvent(EVENT_RUNE_DETONATION, 25000); + } + + void JustDied(Unit* /*victim*/) override + { + // opem the Stone Door + _instance->HandleGameObject(_instance->GetGuidData(DATA_STONE_DOOR), true); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_RUNIC_FORTIFICATION: + Talk(EMOTE_RUNIC_MIGHT); + DoCastAOE(SPELL_RUNIC_FORTIFICATION); + break; + case EVENT_STOMP: + DoCastAOE(SPELL_STOMP); + _events.Repeat(10000, 12000); + break; + case EVENT_RUNE_DETONATION: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 60.0f, true)) + DoCast(target, SPELL_RUNE_DETONATION); + _events.Repeat(10000, 12000); + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_ancient_rune_giantAI>(creature); + } +}; + +class npc_sif : public CreatureScript +{ + public: + npc_sif() : CreatureScript("npc_sif") { } + + struct npc_sifAI : public ScriptedAI + { + npc_sifAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + _instance = creature->GetInstanceScript(); + } + + void Reset() override + { + _events.Reset(); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_STORMHAMMER_SIF) + { + me->InterruptSpell(CURRENT_GENERIC_SPELL); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + } + } + + void DoAction(int32 action) override + { + if (action == ACTION_START_HARD_MODE) + { + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(me, 250.0f); + Talk(SAY_SIF_EVENT); + _events.Reset(); + _events.ScheduleEvent(EVENT_FROSTBOLT, 2000); + _events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 15000); + _events.ScheduleEvent(EVENT_BLINK, urand(20000, 25000)); + _events.ScheduleEvent(EVENT_BLIZZARD, 30000); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BLINK: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_BLINK); + _events.ScheduleEvent(EVENT_FROST_NOVA, 0); + _events.Repeat(20000, 25000); + return; + case EVENT_FROST_NOVA: + DoCastAOE(SPELL_FROSTNOVA); + return; + case EVENT_FROSTBOLT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_FROSTBOLT); + _events.Repeat(2000); + return; + case EVENT_FROSTBOLT_VOLLEY: + DoCastAOE(SPELL_FROSTBOLT_VOLLEY); + _events.Repeat(15000, 20000); + return; + case EVENT_BLIZZARD: + DoCastAOE(SPELL_BLIZZARD); + _events.Repeat(35000, 45000); + return; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + + // no melee attack + } + + private: + EventMap _events; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_sifAI>(creature); + } +}; + +// 62576 - Blizzard +// 62602 - Blizzard +class spell_thorim_blizzard_effect : public SpellScriptLoader +{ + public: + spell_thorim_blizzard_effect() : SpellScriptLoader("spell_thorim_blizzard_effect") { } + + class spell_thorim_blizzard_effect_AuraScript : public AuraScript + { + PrepareAuraScript(spell_thorim_blizzard_effect_AuraScript); + + bool CheckAreaTarget(Unit* target) + { + /// @todo: fix this for all dynobj auras + if (target != GetOwner()) + { + // check if not stacking aura already on target + // this one prevents overriding auras periodically by 2 near area aura owners + Unit::AuraApplicationMap const& auraMap = target->GetAppliedAuras(); + for (Unit::AuraApplicationMap::const_iterator iter = auraMap.begin(); iter != auraMap.end(); ++iter) + { + Aura const* aura = iter->second->GetBase(); + if (GetId() == aura->GetId() && GetOwner() != aura->GetOwner() /*!GetAura()->CanStackWith(aura)*/) + return false; + } + } + + return true; + } + + void Register() override + { + DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_thorim_blizzard_effect_AuraScript::CheckAreaTarget); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_thorim_blizzard_effect_AuraScript(); + } +}; + +// 62580, 62604 - Frostbolt Volley +class spell_thorim_frostbolt_volley : public SpellScriptLoader +{ + public: + spell_thorim_frostbolt_volley() : SpellScriptLoader("spell_thorim_frostbolt_volley") { } + + class spell_thorim_frostbolt_volley_SpellScript : public SpellScript + { + PrepareSpellScript(spell_thorim_frostbolt_volley_SpellScript); + + void FilterTargets(std::list<WorldObject*>& unitList) + { + unitList.remove_if([](WorldObject* target) + { + return target->GetTypeId() != TYPEID_PLAYER && (target->GetTypeId() != TYPEID_UNIT || !target->ToUnit()->IsPet()); + }); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thorim_frostbolt_volley_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_thorim_frostbolt_volley_SpellScript(); + } +}; + +// 62016 - Charge Orb +class spell_thorim_charge_orb : public SpellScriptLoader +{ + public: + spell_thorim_charge_orb() : SpellScriptLoader("spell_thorim_charge_orb") { } + + class spell_thorim_charge_orb_SpellScript : public SpellScript + { + PrepareSpellScript(spell_thorim_charge_orb_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_LIGHTNING_PILLAR_1 }); + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove_if(HeightPositionCheck(false)); + + if (targets.empty()) + return; + + WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); + targets.clear(); + targets.push_back(target); + } + + void HandleScript() + { + if (Unit* target = GetHitUnit()) + target->CastSpell((Unit*)nullptr, SPELL_LIGHTNING_PILLAR_1, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thorim_charge_orb_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + AfterHit += SpellHitFn(spell_thorim_charge_orb_SpellScript::HandleScript); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_thorim_charge_orb_SpellScript(); + } +}; + +// 62466 - Lightning Charge +class spell_thorim_lightning_charge : public SpellScriptLoader +{ + public: + spell_thorim_lightning_charge() : SpellScriptLoader("spell_thorim_lightning_charge") { } + + class spell_thorim_lightning_charge_SpellScript : public SpellScript + { + PrepareSpellScript(spell_thorim_lightning_charge_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_LIGHTNING_CHARGE }); + } + + void HandleFocus() + { + /// @workaround: focus target is not working because spell is triggered and instant + if (Creature* creature = GetCaster()->ToCreature()) + creature->FocusTarget(GetSpell(), GetExplTargetWorldObject()); + } + + void HandleCharge() + { + GetCaster()->CastSpell(GetCaster(), SPELL_LIGHTNING_CHARGE); + } + + void Register() override + { + BeforeCast += SpellCastFn(spell_thorim_lightning_charge_SpellScript::HandleFocus); + AfterCast += SpellCastFn(spell_thorim_lightning_charge_SpellScript::HandleCharge); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_thorim_lightning_charge_SpellScript(); + } +}; + +// 61934 - Leap +class spell_thorim_arena_leap : public SpellScriptLoader +{ + public: + spell_thorim_arena_leap() : SpellScriptLoader("spell_thorim_arena_leap") { } + + class spell_thorim_arena_leap_SpellScript : public SpellScript + { + PrepareSpellScript(spell_thorim_arena_leap_SpellScript); + + bool Load() override + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Position const* pos = GetHitDest()) + GetCaster()->ToCreature()->SetHomePosition(*pos); + } + + void Register() override + { + OnEffectLaunch += SpellEffectFn(spell_thorim_arena_leap_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_JUMP_DEST); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_thorim_arena_leap_SpellScript(); + } +}; + +struct OutOfArenaCheck +{ + bool operator()(Position const* who) const + { + return !CreatureAI::IsInBounds(ArenaBoundaries, who); + } +}; + +// 62042 - Stormhammer +class spell_thorim_stormhammer : public SpellScriptLoader +{ + public: + spell_thorim_stormhammer() : SpellScriptLoader("spell_thorim_stormhammer") { } + + class spell_thorim_stormhammer_SpellScript : public SpellScript + { + PrepareSpellScript(spell_thorim_stormhammer_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_STORMHAMMER_BOOMERANG, + SPELL_DEAFENING_THUNDER + }); + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove_if([](WorldObject* target) -> bool { return HeightPositionCheck(true)(target) || OutOfArenaCheck()(target); }); + + if (targets.empty()) + { + FinishCast(SPELL_FAILED_NO_VALID_TARGETS); + return; + } + + WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); + targets.clear(); + targets.push_back(target); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + { + target->CastSpell(target, SPELL_DEAFENING_THUNDER, true); + target->CastSpell(GetCaster(), SPELL_STORMHAMMER_BOOMERANG, true); + } + } + + void LoseHammer() + { + GetCaster()->SetVirtualItem(0, 0); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thorim_stormhammer_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); + AfterCast += SpellCastFn(spell_thorim_stormhammer_SpellScript::LoseHammer); + OnEffectHitTarget += SpellEffectFn(spell_thorim_stormhammer_SpellScript::HandleScript, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_thorim_stormhammer_SpellScript(); + } +}; + +// 64767 - Stormhammer +class spell_thorim_stormhammer_sif : public SpellScriptLoader +{ + public: + spell_thorim_stormhammer_sif() : SpellScriptLoader("spell_thorim_stormhammer_sif") { } + + class spell_thorim_stormhammer_sif_SpellScript : public SpellScript + { + PrepareSpellScript(spell_thorim_stormhammer_sif_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_STORMHAMMER_BOOMERANG, + SPELL_SIF_TRANSFORM + }); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + { + target->CastSpell(GetCaster(), SPELL_STORMHAMMER_BOOMERANG, true); + target->CastSpell(target, SPELL_SIF_TRANSFORM, true); + } + } + + void LoseHammer() + { + GetCaster()->SetVirtualItem(0, 0); + } + + void Register() override + { + AfterCast += SpellCastFn(spell_thorim_stormhammer_sif_SpellScript::LoseHammer); + OnEffectHitTarget += SpellEffectFn(spell_thorim_stormhammer_sif_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_thorim_stormhammer_sif_SpellScript(); + } +}; + +// 64909 - Stormhammer +class spell_thorim_stormhammer_boomerang : public SpellScriptLoader +{ + public: + spell_thorim_stormhammer_boomerang() : SpellScriptLoader("spell_thorim_stormhammer_boomerang") { } + + class spell_thorim_stormhammer_boomerang_SpellScript : public SpellScript + { + PrepareSpellScript(spell_thorim_stormhammer_boomerang_SpellScript); + + void RecoverHammer(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + target->SetVirtualItem(0, THORIM_WEAPON_DISPLAY_ID); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_thorim_stormhammer_boomerang_SpellScript::RecoverHammer, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_thorim_stormhammer_boomerang_SpellScript(); + } +}; + +// 62057, 62058 - Runic Smash +class spell_thorim_runic_smash : public SpellScriptLoader +{ + public: + spell_thorim_runic_smash() : SpellScriptLoader("spell_thorim_runic_smash") { } + + class spell_thorim_runic_smash_SpellScript : public SpellScript + { + PrepareSpellScript(spell_thorim_runic_smash_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_RUNIC_SMASH }); + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + + std::vector<Creature*> triggers; + GetCaster()->GetCreatureListWithEntryInGrid(triggers, GetSpellInfo()->Id == SPELL_RUNIC_SMASH_LEFT ? NPC_GOLEM_LEFT_HAND_BUNNY : NPC_GOLEM_RIGHT_HAND_BUNNY, 150.0f); + for (Creature* trigger : triggers) + { + float dist = GetCaster()->GetExactDist(trigger); + trigger->m_Events.AddEvent(new RunicSmashExplosionEvent(trigger), trigger->m_Events.CalculateTime(uint64(dist * 30.f))); + }; + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_thorim_runic_smash_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_TRIGGER_SPELL); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_thorim_runic_smash_SpellScript(); + } +}; + +class UpperOrbCheck +{ + public: + UpperOrbCheck() : _check(true) { } + + bool operator() (Creature* target) const + { + return target->GetEntry() == NPC_THUNDER_ORB && _check(target); + } + + private: + HeightPositionCheck const _check; +}; + +// 62184 - Activate Lightning Orb Periodic +class spell_thorim_activate_lightning_orb_periodic : public SpellScriptLoader +{ + public: + spell_thorim_activate_lightning_orb_periodic() : SpellScriptLoader("spell_thorim_activate_lightning_orb_periodic") { } + + class spell_thorim_activate_lightning_orb_periodic_AuraScript : public AuraScript + { + PrepareAuraScript(spell_thorim_activate_lightning_orb_periodic_AuraScript); + + InstanceScript* instance = nullptr; + + void PeriodicTick(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + + Unit* caster = GetCaster(); + std::vector<Creature*> triggers; + + UpperOrbCheck check; + Trinity::CreatureListSearcher<UpperOrbCheck> searcher(caster, triggers, check); + Cell::VisitGridObjects(caster, searcher, 100.f); + + if (!triggers.empty()) + { + Creature* target = Trinity::Containers::SelectRandomContainerElement(triggers); + if (Creature* thorim = instance->GetCreature(BOSS_THORIM)) + thorim->AI()->SetGUID(target->GetGUID(), DATA_CHARGED_PILLAR); + } + } + + bool Load() override + { + if (Unit* caster = GetCaster()) + instance = caster->GetInstanceScript(); + + return instance != nullptr; + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_thorim_activate_lightning_orb_periodic_AuraScript::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_thorim_activate_lightning_orb_periodic_AuraScript(); + } +}; + +// 62331, 62418 - Impale +class spell_iron_ring_guard_impale : public SpellScriptLoader +{ + public: + spell_iron_ring_guard_impale() : SpellScriptLoader("spell_iron_ring_guard_impale") { } + + class spell_iron_ring_guard_impale_AuraScript : public AuraScript + { + PrepareAuraScript(spell_iron_ring_guard_impale_AuraScript); + + void PeriodicTick(AuraEffect const* /*aurEff*/) + { + if (GetTarget()->HealthAbovePct(GetSpellInfo()->GetEffect(EFFECT_1)->CalcValue())) + { + Remove(AURA_REMOVE_BY_ENEMY_SPELL); + PreventDefaultAction(); + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_iron_ring_guard_impale_AuraScript::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_iron_ring_guard_impale_AuraScript(); + } +}; + +class condition_thorim_arena_leap : public ConditionScript +{ + public: + condition_thorim_arena_leap() : ConditionScript("condition_thorim_arena_leap"), _check(false) { } + + bool OnConditionCheck(Condition const* condition, ConditionSourceInfo& sourceInfo) override + { + WorldObject* target = sourceInfo.mConditionTargets[condition->ConditionTarget]; + InstanceScript* instance = target->GetInstanceScript(); + + if (!instance) + return false; + + return _check(target); + } + + private: + HeightPositionCheck _check; +}; + void AddSC_boss_thorim() { new boss_thorim(); + new npc_thorim_pre_phase(); + new npc_thorim_arena_phase(); + new npc_runic_colossus(); + new npc_ancient_rune_giant(); + new npc_sif(); + new spell_thorim_blizzard_effect(); + new spell_thorim_frostbolt_volley(); + new spell_thorim_charge_orb(); + new spell_thorim_lightning_charge(); + new spell_thorim_stormhammer(); + new spell_thorim_stormhammer_sif(); + new spell_thorim_stormhammer_boomerang(); + new spell_thorim_arena_leap(); + new spell_thorim_runic_smash(); + new spell_thorim_activate_lightning_orb_periodic(); + new spell_iron_ring_guard_impale(); + new condition_thorim_arena_leap(); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp index 2eb507db98c..be43dc8c6cb 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp @@ -774,7 +774,7 @@ class boss_sara : public CreatureScript { me->RemoveAllAuras(); me->SetReactState(REACT_PASSIVE); - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); _events.Reset(); _events.SetPhase(PHASE_ONE); } @@ -817,7 +817,7 @@ class boss_sara : public CreatureScript case EVENT_TRANSFORM_3: Talk(SAY_SARA_TRANSFORM_4); DoCast(me, SPELL_FULL_HEAL); - me->SetFaction(16); + me->SetFaction(FACTION_MONSTER_2); if (Creature* voice = _instance->GetCreature(DATA_VOICE_OF_YOGG_SARON)) voice->AI()->DoAction(ACTION_PHASE_TWO); if (Creature* mimiron = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_MIMIRON_YS))) diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index d34a7ac516c..a90efe7bfd8 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -38,9 +38,9 @@ static BossBoundaryData const boundaries = { BOSS_XT002, new RectangleBoundary(755.0f, 940.0f, -125.0f, 95.0f) }, { BOSS_ASSEMBLY_OF_IRON, new CircleBoundary(Position(1587.2f, 121.0f), 90.0) }, { BOSS_ALGALON, new CircleBoundary(Position(1632.668f, -307.7656f), 45.0) }, - { BOSS_ALGALON, new ZRangeBoundary(410.0f, 440.0f) }, + { BOSS_ALGALON, new ZRangeBoundary(410.0f, 470.0f) }, { BOSS_HODIR, new EllipseBoundary(Position(2001.5f, -240.0f), 50.0, 75.0) }, - { BOSS_THORIM, new CircleBoundary(Position(2134.73f, -263.2f), 50.0) }, + // Thorim sets boundaries dynamically { BOSS_FREYA, new RectangleBoundary(2094.6f, 2520.0f, -250.0f, 200.0f) }, { BOSS_MIMIRON, new CircleBoundary(Position(2744.0f, 2569.0f), 70.0) }, { BOSS_VEZAX, new RectangleBoundary(1740.0f, 1930.0f, 31.0f, 228.0f) }, @@ -59,6 +59,11 @@ static DoorData const doorData[] = { GO_MIMIRON_DOOR_1, BOSS_MIMIRON, DOOR_TYPE_ROOM }, { GO_MIMIRON_DOOR_2, BOSS_MIMIRON, DOOR_TYPE_ROOM }, { GO_MIMIRON_DOOR_3, BOSS_MIMIRON, DOOR_TYPE_ROOM }, + { GO_THORIM_ENCOUNTER_DOOR, BOSS_THORIM, DOOR_TYPE_ROOM }, + { GO_ANCIENT_GATE_OF_THE_KEEPERS, BOSS_HODIR, DOOR_TYPE_PASSAGE }, + { GO_ANCIENT_GATE_OF_THE_KEEPERS, BOSS_MIMIRON, DOOR_TYPE_PASSAGE }, + { GO_ANCIENT_GATE_OF_THE_KEEPERS, BOSS_THORIM, DOOR_TYPE_PASSAGE }, + { GO_ANCIENT_GATE_OF_THE_KEEPERS, BOSS_FREYA, DOOR_TYPE_PASSAGE }, { GO_VEZAX_DOOR, BOSS_VEZAX, DOOR_TYPE_PASSAGE }, { GO_YOGG_SARON_DOOR, BOSS_YOGG_SARON, DOOR_TYPE_ROOM }, { GO_DOODAD_UL_SIGILDOOR_03, BOSS_ALGALON, DOOR_TYPE_ROOM }, @@ -95,6 +100,10 @@ ObjectData const creatureData[] = { NPC_EXPEDITION_COMMANDER, DATA_EXPEDITION_COMMANDER }, { NPC_RAZORSCALE_CONTROLLER, DATA_RAZORSCALE_CONTROL }, + { NPC_SIF, DATA_SIF }, + { NPC_RUNIC_COLOSSUS, DATA_RUNIC_COLOSSUS }, + { NPC_RUNE_GIANT, DATA_RUNE_GIANT }, + { NPC_THORIM_CONTROLLER, DATA_THORIM_CONTROLLER }, { NPC_COMPUTER, DATA_COMPUTER }, { NPC_WORLD_TRIGGER_MIMIRON, DATA_MIMIRON_WORLD_TRIGGER }, { NPC_VOICE_OF_YOGG_SARON, DATA_VOICE_OF_YOGG_SARON }, @@ -118,6 +127,9 @@ ObjectData const objectData[] = { GO_RAZOR_HARPOON_2, GO_RAZOR_HARPOON_2 }, { GO_RAZOR_HARPOON_3, GO_RAZOR_HARPOON_3 }, { GO_RAZOR_HARPOON_4, GO_RAZOR_HARPOON_4 }, + { GO_THORIM_LEVER, DATA_THORIM_LEVER }, + { GO_THORIM_STONE_DOOR, DATA_STONE_DOOR }, + { GO_THORIM_RUNIC_DOOR, DATA_RUNIC_DOOR }, { 0, 0 } }; @@ -173,7 +185,9 @@ class instance_ulduar : public InstanceMapScript ObjectGuid LeviathanGateGUID; ObjectGuid KologarnChestGUID; ObjectGuid KologarnBridgeGUID; - ObjectGuid ThorimChestGUID; + ObjectGuid ThorimDarkIronPortcullisGUID; + ObjectGuid CacheOfStormsGUID; + ObjectGuid CacheOfStormsHardmodeGUID; ObjectGuid HodirRareCacheGUID; ObjectGuid HodirChestGUID; ObjectGuid MimironTramGUID; @@ -330,6 +344,16 @@ class instance_ulduar : public InstanceMapScript creature->UpdateEntry(NPC_BATTLE_PRIEST_GINA); break; + // Thorim + case NPC_MERCENARY_CAPTAIN_H: + if (TeamInInstance == HORDE) + creature->UpdateEntry(NPC_MERCENARY_CAPTAIN_A); + break; + case NPC_MERCENARY_SOLDIER_H: + if (TeamInInstance == HORDE) + creature->UpdateEntry(NPC_MERCENARY_SOLDIER_A); + break; + // Freya case NPC_IRONBRANCH: ElderGUIDs[0] = creature->GetGUID(); @@ -447,9 +471,16 @@ class instance_ulduar : public InstanceMapScript if (GetBossState(BOSS_KOLOGARN) == DONE) HandleGameObject(ObjectGuid::Empty, false, gameObject); break; - case GO_THORIM_CHEST_HERO: - case GO_THORIM_CHEST: - ThorimChestGUID = gameObject->GetGUID(); + case GO_THORIM_DARK_IRON_PORTCULLIS: + ThorimDarkIronPortcullisGUID = gameObject->GetGUID(); + break; + case GO_CACHE_OF_STORMS_10: + case GO_CACHE_OF_STORMS_25: + CacheOfStormsGUID = gameObject->GetGUID(); + break; + case GO_CACHE_OF_STORMS_HARDMODE_10: + case GO_CACHE_OF_STORMS_HARDMODE_25: + CacheOfStormsHardmodeGUID = gameObject->GetGUID(); break; case GO_HODIR_RARE_CACHE_OF_WINTER_HERO: case GO_HODIR_RARE_CACHE_OF_WINTER: @@ -656,11 +687,25 @@ class instance_ulduar : public InstanceMapScript case BOSS_THORIM: if (state == DONE) { - if (GameObject* gameObject = instance->GetGameObject(ThorimChestGUID)) - gameObject->SetRespawnTime(gameObject->GetRespawnDelay()); + if (Creature* thorim = GetCreature(BOSS_THORIM)) + { + if (GameObject* cache = instance->GetGameObject(thorim->AI()->GetData(DATA_THORIM_HARDMODE) ? CacheOfStormsHardmodeGUID : CacheOfStormsGUID)) + { + cache->SetLootRecipient(thorim->GetLootRecipient()); + cache->SetRespawnTime(cache->GetRespawnDelay()); + cache->RemoveFlag(GO_FLAG_LOCKED); + cache->RemoveFlag(GO_FLAG_NOT_SELECTABLE); + cache->RemoveFlag(GO_FLAG_NODESPAWN); + } + } instance->SummonCreature(NPC_THORIM_OBSERVATION_RING, ObservationRingKeepersPos[2]); } + else + { + DoCloseDoorOrButton(GetGuidData(DATA_THORIM_LEVER)); + DoCloseDoorOrButton(ThorimDarkIronPortcullisGUID); + } break; case BOSS_ALGALON: if (state == DONE) diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h index a26b699b396..885686e6fc6 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -157,6 +157,31 @@ enum UlduarNPCs // Freya Achievement Trigger NPC_FREYA_ACHIEVE_TRIGGER = 33406, + // Thorim + NPC_THORIM_INVISIBLE_STALKER = 32780, + NPC_JORMUNGAR_BEHEMOTH = 32882, + NPC_MERCENARY_CAPTAIN_A = 32908, + NPC_MERCENARY_CAPTAIN_H = 32907, + NPC_MERCENARY_SOLDIER_A = 32885, + NPC_MERCENARY_SOLDIER_H = 32883, + NPC_DARK_RUNE_ACOLYTE_PRE = 32886, + NPC_RUNIC_COLOSSUS = 32872, + NPC_RUNE_GIANT = 32873, + NPC_IRON_RING_GUARD = 32874, + NPC_IRON_HONOR_GUARD = 32875, + NPC_DARK_RUNE_CHAMPION = 32876, + NPC_DARK_RUNE_WARBRINGER = 32877, + NPC_DARK_RUNE_EVOKER = 32878, + NPC_DARK_RUNE_COMMONER = 32904, + NPC_DARK_RUNE_ACOLYTE = 33110, + NPC_THORIM_EVENT_BUNNY = 32892, + NPC_LIGHTNING_ORB = 33138, + NPC_GOLEM_RIGHT_HAND_BUNNY = 33140, + NPC_GOLEM_LEFT_HAND_BUNNY = 33141, + NPC_SIF = 33196, + NPC_THUNDER_ORB = 33378, + NPC_THORIM_CONTROLLER = 32879, + // Yogg-Saron NPC_SARA = 33134, NPC_GUARDIAN_OF_YOGG_SARON = 33136, @@ -231,6 +256,8 @@ enum UlduarGameObjects GO_KOLOGARN_BRIDGE = 194232, GO_KOLOGARN_DOOR = 194553, + GO_ANCIENT_GATE_OF_THE_KEEPERS = 194255, + // Hodir GO_HODIR_ENTRANCE = 194442, GO_HODIR_DOOR = 194634, @@ -241,8 +268,15 @@ enum UlduarGameObjects GO_HODIR_CHEST = 194307, // Thorim - GO_THORIM_CHEST_HERO = 194315, - GO_THORIM_CHEST = 194314, + GO_CACHE_OF_STORMS_10 = 194312, + GO_CACHE_OF_STORMS_HARDMODE_10 = 194313, + GO_CACHE_OF_STORMS_25 = 194315, + GO_CACHE_OF_STORMS_HARDMODE_25 = 194314, + GO_THORIM_RUNIC_DOOR = 194557, + GO_THORIM_STONE_DOOR = 194558, + GO_THORIM_ENCOUNTER_DOOR = 194559, + GO_THORIM_LEVER = 194264, + GO_THORIM_DARK_IRON_PORTCULLIS = 194560, // Mimiron GO_MIMIRON_TRAM = 194675, @@ -407,6 +441,16 @@ enum UlduarData DATA_ALGALON_TRAPDOOR, DATA_BRANN_BRONZEBEARD_ALG, + // Thorim + DATA_SIF, + DATA_THORIM_LEVER, + DATA_RUNIC_COLOSSUS, + DATA_RUNE_GIANT, + DATA_RUNIC_DOOR, + DATA_STONE_DOOR, + DATA_THORIM_HARDMODE, + DATA_THORIM_CONTROLLER, + // Misc DATA_BRANN_BRONZEBEARD_INTRO, DATA_LORE_KEEPER_OF_NORGANNON, @@ -423,10 +467,15 @@ enum UlduarWorldStates enum UlduarAchievementData { // FL Achievement boolean - DATA_UNBROKEN = 29052906, // 2905, 2906 are achievement IDs, + DATA_UNBROKEN = 29052906, // 2905, 2906 are achievement IDs, MAX_HERALD_ARMOR_ITEMLEVEL = 226, - MAX_HERALD_WEAPON_ITEMLEVEL = 232, - SPELL_LUMBERJACKED_CREDIT = 65296 + MAX_HERALD_WEAPON_ITEMLEVEL = 232 +}; + +enum UlduarSharedSpells +{ + SPELL_LUMBERJACKED_CREDIT = 65296, + SPELL_TELEPORT_KEEPER_VISUAL = 62940 // used by keepers }; enum UlduarEvents @@ -445,6 +494,23 @@ enum YoggSaronIllusions STORMWIND_ILLUSION = 2, }; +class KeeperDespawnEvent : public BasicEvent +{ +public: + KeeperDespawnEvent(Creature* owner, uint32 despawnTimerOffset = 500) : _owner(owner), _despawnTimer(despawnTimerOffset) { } + + bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override + { + _owner->CastSpell(_owner, SPELL_TELEPORT_KEEPER_VISUAL); + _owner->DespawnOrUnsummon(1000 + _despawnTimer); + return true; + } + +private: + Creature* _owner; + uint32 _despawnTimer; +}; + template<typename AI, typename T> inline AI* GetUlduarAI(T* obj) { diff --git a/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp b/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp index 5b9ab19fb86..ae9d06e9e5d 100644 --- a/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp +++ b/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp @@ -277,7 +277,7 @@ class npc_frozen_orb_stalker : public CreatureScript { Position pos; me->GetNearPoint(toravon, pos.m_positionX, pos.m_positionY, pos.m_positionZ, 0.0f, 10.0f, 0.0f); - me->SetPosition(pos); + me->UpdatePosition(pos); DoCast(me, SPELL_FROZEN_ORB_SUMMON); } } diff --git a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp index 042b8dad906..8d7231d2ea3 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp @@ -243,7 +243,7 @@ class npc_ichor_globule : public CreatureScript struct npc_ichor_globuleAI : public ScriptedAI { - npc_ichor_globuleAI(Creature* creature) : ScriptedAI(creature) + npc_ichor_globuleAI(Creature* creature) : ScriptedAI(creature), _splashTriggered(false) { _instance = creature->GetInstanceScript(); creature->SetReactState(REACT_PASSIVE); @@ -275,14 +275,21 @@ class npc_ichor_globule : public CreatureScript // this feature should be still implemented void DamageTaken(Unit* /*attacker*/, uint32& damage) override { + if (_splashTriggered) + return; + if (damage >= me->GetHealth()) + { + _splashTriggered = true; DoCastAOE(SPELL_SPLASH); + } } void UpdateAI(uint32 /*diff*/) override { } private: InstanceScript* _instance; + bool _splashTriggered; }; CreatureAI* GetAI(Creature* creature) const override diff --git a/src/server/scripts/Northrend/northrend_script_loader.cpp b/src/server/scripts/Northrend/northrend_script_loader.cpp index 934d29e61b6..57bd641591c 100644 --- a/src/server/scripts/Northrend/northrend_script_loader.cpp +++ b/src/server/scripts/Northrend/northrend_script_loader.cpp @@ -110,6 +110,7 @@ void AddSC_boss_general_vezax(); void AddSC_boss_mimiron(); void AddSC_boss_hodir(); void AddSC_boss_freya(); +void AddSC_boss_thorim(); void AddSC_boss_yogg_saron(); void AddSC_boss_algalon_the_observer(); void AddSC_instance_ulduar(); @@ -291,6 +292,7 @@ void AddNorthrendScripts() AddSC_boss_mimiron(); AddSC_boss_hodir(); AddSC_boss_freya(); + AddSC_boss_thorim(); AddSC_boss_yogg_saron(); AddSC_boss_algalon_the_observer(); AddSC_instance_ulduar(); diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp index b14038431ad..b487d7fc6e1 100644 --- a/src/server/scripts/Northrend/zone_borean_tundra.cpp +++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp @@ -119,7 +119,7 @@ public: DoCast(me, SPELL_EXPLODE_CART, true); DoCast(me, SPELL_SUMMON_CART, true); if (GameObject* cart = me->FindNearestGameObject(GO_EXPLOSIVES_CART, 3.0f)) - cart->SetFaction(14); + cart->SetFaction(FACTION_MONSTER); phaseTimer = 3000; phase = 2; break; @@ -557,9 +557,6 @@ enum Lurgglbr GO_CAGE = 187369, - FACTION_ESCORTEE_A = 774, - FACTION_ESCORTEE_H = 775, - SAY_START_1 = 0, SAY_START_2 = 1, SAY_END_1 = 2, @@ -681,11 +678,11 @@ public: switch (player->GetTeam()) { case ALLIANCE: - me->SetFaction(FACTION_ESCORTEE_A); + me->SetFaction(FACTION_ESCORTEE_A_PASSIVE); break; default: case HORDE: - me->SetFaction(FACTION_ESCORTEE_H); + me->SetFaction(FACTION_ESCORTEE_H_PASSIVE); break; } } @@ -1690,10 +1687,10 @@ public: switch (player->GetTeam()) { case ALLIANCE: - me->SetFaction(FACTION_ESCORTEE_A); + me->SetFaction(FACTION_ESCORTEE_A_PASSIVE); break; case HORDE: - me->SetFaction(FACTION_ESCORTEE_H); + me->SetFaction(FACTION_ESCORTEE_H_PASSIVE); break; } me->SetStandState(UNIT_STAND_STATE_STAND); diff --git a/src/server/scripts/Northrend/zone_dragonblight.cpp b/src/server/scripts/Northrend/zone_dragonblight.cpp index 5c7df86b6a4..9c3f455bc41 100644 --- a/src/server/scripts/Northrend/zone_dragonblight.cpp +++ b/src/server/scripts/Northrend/zone_dragonblight.cpp @@ -379,9 +379,7 @@ enum StrengthenAncientsMisc SPELL_CREATE_ITEM_BARK = 47550, SPELL_CONFUSED = 47044, - NPC_LOTHALOR = 26321, - - FACTION_WALKER_ENEMY = 14, + NPC_LOTHALOR = 26321 }; class spell_q12096_q12092_dummy : public SpellScriptLoader // Strengthen the Ancients: On Interact Dummy to Woodlands Walker @@ -414,7 +412,7 @@ public: else if (roll == 0) // enemy version { tree->AI()->Talk(SAY_WALKER_ENEMY, player); - tree->SetFaction(FACTION_WALKER_ENEMY); + tree->SetFaction(FACTION_MONSTER); tree->Attack(player, true); } } diff --git a/src/server/scripts/Northrend/zone_grizzly_hills.cpp b/src/server/scripts/Northrend/zone_grizzly_hills.cpp index d5c06855cff..bfb90373474 100644 --- a/src/server/scripts/Northrend/zone_grizzly_hills.cpp +++ b/src/server/scripts/Northrend/zone_grizzly_hills.cpp @@ -103,7 +103,7 @@ public: Talk(SAY_WORGRAGGRO3); if (Creature* RWORG = me->SummonCreature(NPC_RAVENOUS_WORG, me->GetPositionX()+10, me->GetPositionY()+8, me->GetPositionZ()+2, 3.229f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000)) { - RWORG->SetFaction(35); + RWORG->SetFaction(FACTION_FRIENDLY); _RavenousworgGUID = RWORG->GetGUID(); } break; @@ -136,7 +136,7 @@ public: { RWORG->Kill(Mrfloppy); Mrfloppy->ExitVehicle(); - RWORG->SetFaction(14); + RWORG->SetFaction(FACTION_MONSTER); RWORG->GetMotionMaster()->MovePoint(0, RWORG->GetPositionX()+10, RWORG->GetPositionY()+80, RWORG->GetPositionZ()); Talk(SAY_VICTORY2); } diff --git a/src/server/scripts/Northrend/zone_howling_fjord.cpp b/src/server/scripts/Northrend/zone_howling_fjord.cpp index cab2d03b29c..1989b424679 100644 --- a/src/server/scripts/Northrend/zone_howling_fjord.cpp +++ b/src/server/scripts/Northrend/zone_howling_fjord.cpp @@ -43,7 +43,6 @@ EndContentData */ enum Entries { NPC_APOTHECARY_HANES = 23784, - FACTION_ESCORTEE_H = 775, QUEST_TRAIL_OF_FIRE = 11241, SPELL_HEALING_POTION = 17534, @@ -155,7 +154,7 @@ public: break; case EVENT_START_ESCORT: events.Reset(); - me->SetFaction(FACTION_ESCORTEE_H); + me->SetFaction(FACTION_ESCORTEE_H_PASSIVE); me->SetReactState(REACT_AGGRESSIVE); ENSURE_AI(npc_escortAI, (me->AI()))->Start(true, true, _player); break; diff --git a/src/server/scripts/Northrend/zone_icecrown.cpp b/src/server/scripts/Northrend/zone_icecrown.cpp index 8adbd37d884..bf4caf3128f 100644 --- a/src/server/scripts/Northrend/zone_icecrown.cpp +++ b/src/server/scripts/Northrend/zone_icecrown.cpp @@ -47,7 +47,7 @@ public: { Initialize(); creature->GetMotionMaster()->MovePoint(0, 8599.258f, 963.951f, 547.553f); - creature->SetFaction(35); //wrong faction in db? + creature->SetFaction(FACTION_FRIENDLY); //wrong faction in db? } void Initialize() @@ -69,7 +69,7 @@ public: if (uiType != POINT_MOTION_TYPE) return; - me->SetFaction(14); + me->SetFaction(FACTION_MONSTER); } void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override @@ -78,7 +78,7 @@ public: { uiDamage = 0; pDoneBy->CastSpell(pDoneBy, SPELL_KILL_CREDIT, true); - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); me->DespawnOrUnsummon(5000); me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); EnterEvadeMode(); diff --git a/src/server/scripts/Northrend/zone_sholazar_basin.cpp b/src/server/scripts/Northrend/zone_sholazar_basin.cpp index 01285e18a61..5ace31b5cdd 100644 --- a/src/server/scripts/Northrend/zone_sholazar_basin.cpp +++ b/src/server/scripts/Northrend/zone_sholazar_basin.cpp @@ -340,7 +340,7 @@ public: if (quest->GetQuestId() == QUEST_DISASTER) { me->GetMotionMaster()->MoveJumpTo(0, 0.4f, 0.4f); - me->SetFaction(113); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE); Start(false, false, player->GetGUID()); Talk(SAY_WP_1); diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp index 8fbf23d4a44..5a0e6c5aa99 100644 --- a/src/server/scripts/Northrend/zone_storm_peaks.cpp +++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp @@ -93,7 +93,7 @@ public: if (menuId == GOSSIP_ID && gossipListId == GOSSIP_OPTION_ID) { CloseGossipMenuFor(player); - me->SetFaction(113); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE); Start(true, true, player->GetGUID()); } return false; diff --git a/src/server/scripts/Northrend/zone_zuldrak.cpp b/src/server/scripts/Northrend/zone_zuldrak.cpp index 48dc7a1d7e4..4e1079eccc7 100644 --- a/src/server/scripts/Northrend/zone_zuldrak.cpp +++ b/src/server/scripts/Northrend/zone_zuldrak.cpp @@ -139,7 +139,7 @@ public: void Reset() override { - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); DoCast(me, SPELL_KNEEL, true); // Little Hack for kneel - Thanks Illy :P } diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp index 56b21a7465f..416eec05c45 100644 --- a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp +++ b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp @@ -192,7 +192,7 @@ class boss_grandmaster_vorpil : public CreatureScript if (i_pl->IsAlive() && !i_pl->HasAura(SPELL_BANISH)) i_pl->TeleportTo(me->GetMapId(), VorpilPosition.GetPositionX(), VorpilPosition.GetPositionY(), VorpilPosition.GetPositionZ(), VorpilPosition.GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT); - me->SetPosition(VorpilPosition); + me->UpdatePosition(VorpilPosition); DoCast(me, SPELL_DRAW_SHADOWS, true); DoCast(me, SPELL_RAIN_OF_FIRE); events.ScheduleEvent(EVENT_SHADOWBOLT_VOLLEY, 6000); diff --git a/src/server/scripts/Outland/BlackTemple/black_temple.h b/src/server/scripts/Outland/BlackTemple/black_temple.h index 2213c65373d..42a6c0457d8 100644 --- a/src/server/scripts/Outland/BlackTemple/black_temple.h +++ b/src/server/scripts/Outland/BlackTemple/black_temple.h @@ -133,7 +133,6 @@ enum BTGameObjectIds enum BlackTempleMisc { - ASHTONGUE_FACTION_FRIEND = 1820, AKAMA_FACTION_COMBAT = 1868, AKAMA_INTRO = 1, AKAMA_FIGHT = 2, diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp index 44f9f9069ee..1080e6c1ca9 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp @@ -439,7 +439,7 @@ public: bool operator()(Unit* unit) const { - return _me->GetDistance2d(unit) > 25.0f; + return unit->GetTypeId() == TYPEID_PLAYER && _me->GetDistance2d(unit) > 25.0f; } private: @@ -2074,7 +2074,8 @@ class spell_illidan_flame_blast : public SpellScriptLoader void HandleBlaze(SpellEffIndex /*effIndex*/) { Unit* target = GetHitUnit(); - target->CastSpell(target, SPELL_BLAZE_SUMMON, true); + if (target->GetTypeId() == TYPEID_PLAYER) + target->CastSpell(target, SPELL_BLAZE_SUMMON, true); } void Register() override diff --git a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp index 279749dfd9f..3d5b3c3f4a4 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp @@ -384,7 +384,7 @@ public: void Reset() override { Initialize(); - me->SetFaction(ASHTONGUE_FACTION_FRIEND); + me->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); DoCastSelf(SPELL_STEALTH); if (_instance->GetBossState(DATA_SHADE_OF_AKAMA) != DONE) @@ -430,7 +430,7 @@ public: { _isInCombat = false; me->CombatStop(true); - me->SetFaction(ASHTONGUE_FACTION_FRIEND); + me->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); me->SetWalk(true); _events.Reset(); me->GetMotionMaster()->MovePoint(AKAMA_INTRO_WAYPOINT, AkamaWP[1]); @@ -484,7 +484,7 @@ public: case EVENT_SHADE_CHANNEL: me->SetFacingTo(FACE_THE_PLATFORM); DoCastSelf(SPELL_AKAMA_SOUL_CHANNEL); - me->SetFaction(AKAMA_FACTION_COMBAT); + me->SetFaction(FACTION_MONSTER_SPAR_BUDDY); _events.ScheduleEvent(EVENT_FIXATE, Seconds(5)); break; case EVENT_FIXATE: @@ -532,7 +532,7 @@ public: } } - if (me->GetFaction() == AKAMA_FACTION_COMBAT) + if (me->GetFaction() == FACTION_MONSTER_SPAR_BUDDY) { if (!UpdateVictim()) return; @@ -1171,7 +1171,7 @@ public: Talk(SAY_BROKEN_SPECIAL); break; case ACTION_BROKEN_HAIL: - me->SetFaction(ASHTONGUE_FACTION_FRIEND); + me->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); Talk(SAY_BROKEN_HAIL); break; case ACTION_BROKEN_EMOTE: diff --git a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp index 21197f01c81..bc2c071f7c3 100644 --- a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp +++ b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp @@ -128,7 +128,7 @@ class instance_black_temple : public InstanceMapScript case NPC_STORM_FURY: AshtongueGUIDs.emplace_back(creature->GetGUID()); if (GetBossState(DATA_SHADE_OF_AKAMA) == DONE) - creature->SetFaction(ASHTONGUE_FACTION_FRIEND); + creature->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); break; default: break; @@ -175,8 +175,8 @@ class instance_black_temple : public InstanceMapScript if (state == DONE) for (ObjectGuid ashtongueGuid : AshtongueGUIDs) if (Creature* ashtongue = instance->GetCreature(ashtongueGuid)) - ashtongue->SetFaction(ASHTONGUE_FACTION_FRIEND); - /* fallthrough */ + ashtongue->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); + // no break case DATA_TERON_GOREFIEND: case DATA_GURTOGG_BLOODBOIL: case DATA_RELIQUARY_OF_SOULS: diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp index a454599bbf7..ba563eb252f 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp @@ -753,7 +753,7 @@ public: void Reset() override { me->SetDisableGravity(true); - me->SetFaction(14); + me->SetFaction(FACTION_MONSTER); Initialize(); } @@ -788,7 +788,7 @@ public: { if (Creature* trig = me->SummonCreature(TOXIC_SPORES_TRIGGER, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) { - trig->SetFaction(14); + trig->SetFaction(FACTION_MONSTER); trig->CastSpell(trig, SPELL_TOXIC_SPORES, true); } } @@ -804,7 +804,7 @@ public: if (!Vashj || !Vashj->IsAlive() || ENSURE_AI(boss_lady_vashj::boss_lady_vashjAI, Vashj->ToCreature()->AI())->Phase != 3) { // remove - me->SetFaction(35); + me->SetFaction(FACTION_FRIENDLY); me->DespawnOrUnsummon(); return; } diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp index eca80aec5e6..8d2d134d80c 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp @@ -321,7 +321,7 @@ public: me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetFaction(14); + me->SetFaction(FACTION_MONSTER); } void EnterCombat(Unit* /*who*/) override { } diff --git a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_ahune.cpp b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_ahune.cpp index 2379950f294..00a911cc53b 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_ahune.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_ahune.cpp @@ -662,7 +662,7 @@ public: InstanceScript* instance; - bool OnGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) + bool GossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override { ClearGossipMenuFor(player); diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp index 765a7d5a7de..7a04ba358ac 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp @@ -207,7 +207,7 @@ class boss_grand_warlock_nethekurse : public CreatureScript void JustSummoned(Creature* summoned) override { - summoned->SetFaction(16); + summoned->SetFaction(FACTION_MONSTER_2); summoned->AddUnitFlag(UNIT_FLAG_NON_ATTACKABLE); summoned->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp index 6fba85f3580..59e48cb078b 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp @@ -289,7 +289,7 @@ class boss_alar : public CreatureScript if (me->IsWithinDist3d(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 5.0f)) dist = 5.0f; WaitTimer = 1000 + uint32(floor(dist / 80 * 1000.0f)); - me->SetPosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f); + me->UpdatePosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f); me->StopMoving(); WaitEvent = WE_LAND; return; diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp index ee7c9396764..f1a4e6e2d8f 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp @@ -291,7 +291,7 @@ class boss_high_astromancer_solarian : public CreatureScript Phase1_Timer = 50000; //After these 50 seconds she portals to the middle of the room and disappears, leaving 3 light portals behind. me->GetMotionMaster()->Clear(); - me->SetPosition(CENTER_X, CENTER_Y, CENTER_Z, CENTER_O); + me->UpdatePosition(CENTER_X, CENTER_Y, CENTER_Z, CENTER_O); for (uint8 i=0; i <= 2; ++i) { if (!i) @@ -357,7 +357,7 @@ class boss_high_astromancer_solarian : public CreatureScript //15 seconds later Solarian reappears out of one of the 3 portals. Simultaneously, 2 healers appear in the two other portals. int i = rand32() % 3; me->GetMotionMaster()->Clear(); - me->SetPosition(Portals[i][0], Portals[i][1], Portals[i][2], CENTER_O); + me->UpdatePosition(Portals[i][0], Portals[i][1], Portals[i][2], CENTER_O); for (int j=0; j <= 2; j++) if (j != i) diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp index ee44f0c0f46..ab5480e8b5f 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp @@ -1278,7 +1278,7 @@ class npc_kael_flamestrike : public CreatureScript Initialize(); me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetFaction(14); + me->SetFaction(FACTION_MONSTER); } void MoveInLineOfSight(Unit* /*who*/) override { } diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp index 70b1da72d93..3b4f22bc23c 100644 --- a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp @@ -539,7 +539,7 @@ class npc_zerekethvoidzone : public CreatureScript void Reset() override { me->SetNpcFlags(UNIT_NPC_FLAG_NONE); - me->SetFaction(16); + me->SetFaction(FACTION_MONSTER_2); me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); DoCast(me, SPELL_VOID_ZONE_DAMAGE); diff --git a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp index 72001b3a07e..ab8b16468ae 100644 --- a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp +++ b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp @@ -46,8 +46,6 @@ enum Aeranas { SAY_SUMMON = 0, SAY_FREE = 1, - FACTION_HOSTILE = 16, - FACTION_FRIENDLY = 35, SPELL_ENVELOPING_WINDS = 15535, SPELL_SHOCK = 12553 }; @@ -87,7 +85,7 @@ public: { if (faction_Timer <= diff) { - me->SetFaction(FACTION_HOSTILE); + me->SetFaction(FACTION_MONSTER_2); faction_Timer = 0; } else faction_Timer -= diff; } @@ -252,7 +250,7 @@ enum WoundedBloodElf QUEST_ROAD_TO_FALCON_WATCH = 9375, NPC_HAALESHI_WINDWALKER = 16966, NPC_HAALESHI_TALONGUARD = 16967, - FACTION_FALCON_WATCH_QUEST = 775 + }; class npc_wounded_blood_elf : public CreatureScript @@ -281,7 +279,7 @@ public: { if (quest->GetQuestId() == QUEST_ROAD_TO_FALCON_WATCH) { - me->SetFaction(FACTION_FALCON_WATCH_QUEST); + me->SetFaction(FACTION_ESCORTEE_H_PASSIVE); npc_escortAI::Start(true, false, player->GetGUID()); } } @@ -997,7 +995,7 @@ public: break; case EVENT_ATTACK: me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); - me->SetFaction(FACTION_HOSTILE); + me->SetFaction(FACTION_MONSTER_2); if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID)) me->CombatStart(player); _events.ScheduleEvent(EVENT_FIREBALL, 1); diff --git a/src/server/scripts/Outland/zone_nagrand.cpp b/src/server/scripts/Outland/zone_nagrand.cpp index c51dfa286ad..55e129504e6 100644 --- a/src/server/scripts/Outland/zone_nagrand.cpp +++ b/src/server/scripts/Outland/zone_nagrand.cpp @@ -200,7 +200,7 @@ public: if (quest->GetQuestId() == QUEST_TOTEM_KARDASH_H) { me->SetStandState(UNIT_STAND_STATE_STAND); - me->SetFaction(232); + me->SetFaction(FACTION_ESCORTEE_H_NEUTRAL_ACTIVE); Start(true, false, player->GetGUID(), quest); Talk(SAY_MAG_START); @@ -575,7 +575,7 @@ public: if (quest->GetQuestId() == QUEST_TOTEM_KARDASH_A) { me->SetStandState(UNIT_STAND_STATE_STAND); - me->SetFaction(231); + me->SetFaction(FACTION_ESCORTEE_A_NEUTRAL_ACTIVE); Start(true, false, player->GetGUID(), quest); Talk(SAY_KUR_START); diff --git a/src/server/scripts/Outland/zone_netherstorm.cpp b/src/server/scripts/Outland/zone_netherstorm.cpp index c4560a9d633..9ef66707d03 100644 --- a/src/server/scripts/Outland/zone_netherstorm.cpp +++ b/src/server/scripts/Outland/zone_netherstorm.cpp @@ -548,7 +548,7 @@ public: { if (quest->GetQuestId() == Q_ALMABTRIEB) { - me->SetFaction(113); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE); me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); Start(true, false, player->GetGUID()); } @@ -656,7 +656,7 @@ public: { if (quest->GetQuestId() == QUEST_MARK_V_IS_ALIVE) { - me->SetFaction(113); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE); Start(false, false, player->GetGUID()); } } diff --git a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp index 19b79b6ee4c..a44dedb56ca 100644 --- a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp +++ b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp @@ -341,10 +341,6 @@ public: enum EnshlavedNetherwingDrake { - // Factions - FACTION_DEFAULT = 62, - FACTION_FRIENDLY = 1840, // Not sure if this is correct, it was taken off of Mordenai. - // Spells SPELL_HIT_FORCE_OF_NELTHARAKU = 38762, SPELL_FORCE_OF_NELTHARAKU = 38775, @@ -380,7 +376,7 @@ public: void Reset() override { if (!Tapped) - me->SetFaction(FACTION_DEFAULT); + me->SetFaction(FACTION_ORC_DRAGONMAW); FlyTimer = 10000; me->SetDisableGravity(false); @@ -396,7 +392,7 @@ public: Tapped = true; PlayerGUID = caster->GetGUID(); - me->SetFaction(FACTION_FRIENDLY); + me->SetFaction(FACTION_FLAYER_HUNTER); DoCast(caster, SPELL_FORCE_OF_NELTHARAKU, true); Unit* Dragonmaw = me->FindNearestCreature(NPC_DRAGONMAW_SUBJUGATOR, 50); @@ -589,8 +585,7 @@ enum Earthmender SPELL_HEALING_WAVE = 12491, QUEST_ESCAPE_COILSCAR = 10451, - NPC_COILSKAR_ASSASSIN = 21044, - FACTION_EARTHEN = 1726 //guessed + NPC_COILSKAR_ASSASSIN = 21044 }; class npc_earthmender_wilda : public CreatureScript @@ -733,7 +728,7 @@ public: if (quest->GetQuestId() == QUEST_ESCAPE_COILSCAR) { Talk(SAY_WIL_START, player); - me->SetFaction(FACTION_EARTHEN); + me->SetFaction(FACTION_EARTHEN_RING); Start(false, false, player->GetGUID(), quest); } @@ -1415,11 +1410,7 @@ enum Enraged_Dpirits NPC_CREDIT_EARTH = 21092, // Captured Spell / Buff - SPELL_SOUL_CAPTURED = 36115, - - // Factions - FACTION_ENRAGED_SOUL_FRIENDLY = 35, - FACTION_ENRAGED_SOUL_HOSTILE = 14 + SPELL_SOUL_CAPTURED = 36115 }; class npc_enraged_spirit : public CreatureScript @@ -1487,7 +1478,7 @@ public: totemOspirits = me->FindNearestCreature(ENTRY_TOTEM_OF_SPIRITS, RADIUS_TOTEM_OF_SPIRITS); if (totemOspirits) { - Summoned->SetFaction(FACTION_ENRAGED_SOUL_FRIENDLY); + Summoned->SetFaction(FACTION_FRIENDLY); Summoned->GetMotionMaster()->MovePoint(0, totemOspirits->GetPositionX(), totemOspirits->GetPositionY(), Summoned->GetPositionZ()); if (Unit* owner = totemOspirits->GetOwner()) diff --git a/src/server/scripts/Outland/zone_shattrath_city.cpp b/src/server/scripts/Outland/zone_shattrath_city.cpp index 5334f567a89..60037276c25 100644 --- a/src/server/scripts/Outland/zone_shattrath_city.cpp +++ b/src/server/scripts/Outland/zone_shattrath_city.cpp @@ -44,7 +44,6 @@ enum RaliqTheDrunk { SAY_RALIQ_ATTACK = 0, OPTION_ID_COLLECT_A_DEBT = 0, - FACTION_OGRE_HOSTILE = 45, MENU_ID_COLLECT_A_DEBT = 7729, NPC_TEXT_WUT_YOU_WANT = 9440, CRACKIN_SOME_SKULLS = 10009, @@ -97,7 +96,7 @@ public: if (action == GOSSIP_ACTION_INFO_DEF + 1) { CloseGossipMenuFor(player); - me->SetFaction(FACTION_OGRE_HOSTILE); + me->SetFaction(FACTION_OGRE); Talk(SAY_RALIQ_ATTACK, player); AttackStart(player); } @@ -134,8 +133,6 @@ enum Salsalabim { SAY_DEMONIC_AGGRO = 0, OPTION_ID_ALTRUIS_SENT_ME = 0, - FACTION_FRIENDLY = 35, - FACTION_DEMON_HOSTILE = 90, MENU_ID_ALTRUIS_SENT_ME = 7725, NPC_TEXT_SAL_GROWLS_AT_YOU = 9435, PATIENCE_AND_UNDERSTANDING = 10004, @@ -198,7 +195,7 @@ public: if (action == GOSSIP_ACTION_INFO_DEF + 1) { CloseGossipMenuFor(player); - me->SetFaction(FACTION_DEMON_HOSTILE); + me->SetFaction(FACTION_DEMON); Talk(SAY_DEMONIC_AGGRO, player); AttackStart(player); } diff --git a/src/server/scripts/Outland/zone_terokkar_forest.cpp b/src/server/scripts/Outland/zone_terokkar_forest.cpp index 50ee9cf0039..7d519c434a4 100644 --- a/src/server/scripts/Outland/zone_terokkar_forest.cpp +++ b/src/server/scripts/Outland/zone_terokkar_forest.cpp @@ -48,8 +48,6 @@ enum UnkorTheRuthless { SAY_SUBMIT = 0, REQUIRED_KILL_COUNT = 10, - FACTION_FRIENDLY = 35, - FACTION_HOSTILE = 45, SPELL_PULVERIZE = 2676, QUEST_DONTKILLTHEFATONE = 9889, NPC_BOULDERFIST_INVADER = 18260 @@ -87,7 +85,7 @@ public: { Initialize(); me->SetStandState(UNIT_STAND_STATE_STAND); - me->SetFaction(FACTION_HOSTILE); + me->SetFaction(FACTION_OGRE); } void EnterCombat(Unit* /*who*/) override { } @@ -310,7 +308,6 @@ enum Floon SAY_FLOON_ATTACK = 0, OPTION_ID_PAY_UP_OR_DIE = 0, OPTION_ID_COLLECT_A_DEBT = 0, - FACTION_HOSTILE_FLOON = 1738, MENU_ID_PAY_UP_OR_DIE = 7731, MENU_ID_COLLECT_A_DEBT = 7732, GOSSIP_FLOON_STRANGE_SOUNDS = 9442, @@ -395,7 +392,7 @@ public: if (action == GOSSIP_ACTION_INFO_DEF + 1) { CloseGossipMenuFor(player); - me->SetFaction(FACTION_HOSTILE_FLOON); + me->SetFaction(FACTION_ARAKKOA); Talk(SAY_FLOON_ATTACK, player); AttackStart(player); } @@ -428,7 +425,6 @@ enum IslaStarmaneData SAY_PROGRESS_3 = 2, SAY_PROGRESS_4 = 3, GO_DISTANCE = 10, - FACTION_ESCORTEE = 113, ESCAPE_FROM_FIREWING_POINT_A = 10051, ESCAPE_FROM_FIREWING_POINT_H = 10052, SPELL_TRAVEL_FORM_CAT = 32447, @@ -504,7 +500,7 @@ public: if (quest->GetQuestId() == ESCAPE_FROM_FIREWING_POINT_H || quest->GetQuestId() == ESCAPE_FROM_FIREWING_POINT_A) { Start(true, false, player->GetGUID()); - me->SetFaction(FACTION_ESCORTEE); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE); } } }; @@ -694,9 +690,9 @@ public: Start(false, false, player->GetGUID()); if (player->GetTeamId() == TEAM_ALLIANCE) - me->SetFaction(FACTION_ESCORT_A_NEUTRAL_PASSIVE); + me->SetFaction(FACTION_ESCORTEE_A_NEUTRAL_PASSIVE); else - me->SetFaction(FACTION_ESCORT_H_NEUTRAL_PASSIVE); + me->SetFaction(FACTION_ESCORTEE_H_NEUTRAL_PASSIVE); } } }; diff --git a/src/server/scripts/Outland/zone_zangarmarsh.cpp b/src/server/scripts/Outland/zone_zangarmarsh.cpp index ced7d46107f..3ff618f4b2d 100644 --- a/src/server/scripts/Outland/zone_zangarmarsh.cpp +++ b/src/server/scripts/Outland/zone_zangarmarsh.cpp @@ -162,8 +162,7 @@ public: enum Cooshhooosh { SPELL_LIGHTNING_BOLT = 9532, - QUEST_CRACK_SKULLS = 10009, - FACTION_HOSTILE_CO = 45 + QUEST_CRACK_SKULLS = 10009 }; class npc_cooshcoosh : public CreatureScript @@ -226,7 +225,7 @@ public: if (action == GOSSIP_ACTION_INFO_DEF) { CloseGossipMenuFor(player); - me->SetFaction(FACTION_HOSTILE_CO); + me->SetFaction(FACTION_OGRE); AttackStart(player); } return true; diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index 48d63353a34..b0e52234c13 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -66,6 +66,7 @@ enum DruidSpells SPELL_DRUID_REJUVENATION_T10_PROC = 70691, SPELL_DRUID_BALANCE_T10_BONUS = 70718, SPELL_DRUID_BALANCE_T10_BONUS_PROC = 70721, + SPELL_DRUID_RESTORATION_T10_2P_BONUS = 70658, SPELL_DRUID_SUNFIRE_DAMAGE = 164815, SPELL_DRUID_SURVIVAL_INSTINCTS = 50322 }; @@ -1434,14 +1435,52 @@ public: OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_dru_wild_growth_SpellScript::SetTargets, EFFECT_1, TARGET_UNIT_DEST_AREA_ALLY); } - private: std::list<WorldObject*> _targets; }; + class spell_dru_wild_growth_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dru_wild_growth_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DRUID_RESTORATION_T10_2P_BONUS }); + } + + void HandleTickUpdate(AuraEffect* aurEff) + { + Unit* caster = GetCaster(); + if (!caster) + return; + + // calculate from base damage, not from aurEff->GetAmount() (already modified) + float damage = caster->CalculateSpellDamage(GetUnitOwner(), GetSpellInfo(), aurEff->GetEffIndex()); + + // Wild Growth = first tick gains a 6% bonus, reduced by 2% each tick + float reduction = 2.f; + if (AuraEffect* bonus = caster->GetAuraEffect(SPELL_DRUID_RESTORATION_T10_2P_BONUS, EFFECT_0)) + reduction -= CalculatePct(reduction, bonus->GetAmount()); + reduction *= (aurEff->GetTickNumber() - 1); + + AddPct(damage, 6.f - reduction); + aurEff->SetAmount(int32(damage)); + } + + void Register() override + { + OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_dru_wild_growth_AuraScript::HandleTickUpdate, EFFECT_0, SPELL_AURA_PERIODIC_HEAL); + } + }; + SpellScript* GetSpellScript() const override { return new spell_dru_wild_growth_SpellScript(); } + + AuraScript* GetAuraScript() const override + { + return new spell_dru_wild_growth_AuraScript(); + } }; void AddSC_druid_spell_scripts() diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 2824a5e637b..de38535a865 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -3704,7 +3704,7 @@ class spell_gen_gm_freeze : public SpellScriptLoader if (Player* player = GetTarget()->ToPlayer()) { // stop combat + make player unattackable + duel stop + stop some spells - player->SetFaction(35); + player->SetFaction(FACTION_FRIENDLY); player->CombatStop(); if (player->IsNonMeleeSpellCast(true)) player->InterruptNonMeleeSpells(true); diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 095933d4c03..60db94dbf63 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -259,8 +259,6 @@ enum ChickenCluck EMOTE_CLUCK_TEXT = 2, QUEST_CLUCK = 3861, - FACTION_FRIENDLY = 35, - FACTION_CHICKEN = 31 }; class npc_chicken_cluck : public CreatureScript @@ -285,7 +283,7 @@ public: void Reset() override { Initialize(); - me->SetFaction(FACTION_CHICKEN); + me->SetFaction(FACTION_PREY); me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); } diff --git a/src/server/shared/Dynamic/FactoryHolder.h b/src/server/shared/Dynamic/FactoryHolder.h index ce6622daea4..317d50ea9fc 100644 --- a/src/server/shared/Dynamic/FactoryHolder.h +++ b/src/server/shared/Dynamic/FactoryHolder.h @@ -24,23 +24,21 @@ /** FactoryHolder holds a factory object of a specific type */ -template<class T, class Key = std::string> +template<class T, class O, class Key = std::string> class FactoryHolder { public: - typedef ObjectRegistry<FactoryHolder<T, Key >, Key > FactoryHolderRegistry; + typedef ObjectRegistry<FactoryHolder<T, O, Key>, Key> FactoryHolderRegistry; - FactoryHolder(Key k) : i_key(k) { } + explicit FactoryHolder(Key const& k) : _key(k) { } virtual ~FactoryHolder() { } - inline Key key() const { return i_key; } - void RegisterSelf(void) { FactoryHolderRegistry::instance()->InsertItem(this, i_key); } - void DeregisterSelf(void) { FactoryHolderRegistry::instance()->RemoveItem(this, false); } + void RegisterSelf() { FactoryHolderRegistry::instance()->InsertItem(this, _key); } /// Abstract Factory create method - virtual T* Create(void *data = NULL) const = 0; + virtual T* Create(O* object = nullptr) const = 0; private: - Key i_key; + Key const _key; }; /** Permissible is a classic way of letting the object decide @@ -52,6 +50,6 @@ class Permissible { public: virtual ~Permissible() { } - virtual int Permit(const T *) const = 0; + virtual int32 Permit(T const*) const = 0; }; #endif diff --git a/src/server/shared/Dynamic/ObjectRegistry.h b/src/server/shared/Dynamic/ObjectRegistry.h index 45380d699d3..973c34fda24 100644 --- a/src/server/shared/Dynamic/ObjectRegistry.h +++ b/src/server/shared/Dynamic/ObjectRegistry.h @@ -23,14 +23,15 @@ #include <string> #include <map> #include <vector> +#include <memory> /** ObjectRegistry holds all registry item of the same type */ template<class T, class Key = std::string> -class ObjectRegistry +class ObjectRegistry final { public: - typedef std::map<Key, T*> RegistryMapType; + typedef std::map<Key, std::unique_ptr<T>> RegistryMapType; static ObjectRegistry<T, Key>* instance() { @@ -39,71 +40,47 @@ class ObjectRegistry } /// Returns a registry item - const T* GetRegistryItem(Key key) const + T const* GetRegistryItem(Key const& key) const { - typename RegistryMapType::const_iterator iter = i_registeredObjects.find(key); - return( iter == i_registeredObjects.end() ? NULL : iter->second ); + auto itr = _registeredObjects.find(key); + if (itr == _registeredObjects.end()) + return nullptr; + return itr->second.get(); } /// Inserts a registry item - bool InsertItem(T *obj, Key key, bool _override = false) + bool InsertItem(T* obj, Key const& key, bool force = false) { - typename RegistryMapType::iterator iter = i_registeredObjects.find(key); - if ( iter != i_registeredObjects.end() ) + auto itr = _registeredObjects.find(key); + if (itr != _registeredObjects.end()) { - if ( !_override ) + if (!force) return false; - delete iter->second; - i_registeredObjects.erase(iter); + _registeredObjects.erase(itr); } - i_registeredObjects[key] = obj; + _registeredObjects.emplace(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(obj)); return true; } - /// Removes a registry item - void RemoveItem(Key key, bool delete_object = true) - { - typename RegistryMapType::iterator iter = i_registeredObjects.find(key); - if ( iter != i_registeredObjects.end() ) - { - if ( delete_object ) - delete iter->second; - i_registeredObjects.erase(iter); - } - } - /// Returns true if registry contains an item - bool HasItem(Key key) const + bool HasItem(Key const& key) const { - return (i_registeredObjects.find(key) != i_registeredObjects.end()); - } - - /// Inefficiently return a vector of registered items - unsigned int GetRegisteredItems(std::vector<Key> &l) const - { - unsigned int sz = l.size(); - l.resize(sz + i_registeredObjects.size()); - for (typename RegistryMapType::const_iterator iter = i_registeredObjects.begin(); iter != i_registeredObjects.end(); ++iter) - l[sz++] = iter->first; - return i_registeredObjects.size(); + return (_registeredObjects.count(key) > 0); } /// Return the map of registered items - RegistryMapType const &GetRegisteredItems() const + RegistryMapType const& GetRegisteredItems() const { - return i_registeredObjects; + return _registeredObjects; } - ObjectRegistry() { } - ~ObjectRegistry() - { - for (typename RegistryMapType::iterator iter=i_registeredObjects.begin(); iter != i_registeredObjects.end(); ++iter) - delete iter->second; - i_registeredObjects.clear(); - } private: - RegistryMapType i_registeredObjects; + RegistryMapType _registeredObjects; + + // non instanceable, only static + ObjectRegistry() { } + ~ObjectRegistry() { } }; #endif |