diff options
Diffstat (limited to 'src/server')
88 files changed, 2720 insertions, 1837 deletions
| diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h index 1babb7407a9..027011629eb 100644 --- a/src/server/authserver/Server/AuthSession.h +++ b/src/server/authserver/Server/AuthSession.h @@ -23,7 +23,7 @@  #include "ByteBuffer.h"  #include "Socket.h"  #include "BigNumber.h" -#include "Callback.h" +#include "QueryCallback.h"  #include <memory>  #include <boost/asio/ip/tcp.hpp> diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist index db60e3b3ece..1d3b48839a8 100644 --- a/src/server/authserver/authserver.conf.dist +++ b/src/server/authserver/authserver.conf.dist @@ -179,6 +179,7 @@ LoginDatabaseInfo = "127.0.0.1;3306;trinity;trinity;auth"  #    LoginDatabase.WorkerThreads  #        Description: The amount of worker threads spawned to handle asynchronous (delayed) MySQL  #                     statements. Each worker thread is mirrored with its own connection to the +#                     MySQL server and their own thread on the MySQL server.  #        Default:     1  LoginDatabase.WorkerThreads = 1 diff --git a/src/server/database/Database/DatabaseWorkerPool.h b/src/server/database/Database/DatabaseWorkerPool.h index d883366237f..ffdde91c0a6 100644 --- a/src/server/database/Database/DatabaseWorkerPool.h +++ b/src/server/database/Database/DatabaseWorkerPool.h @@ -19,7 +19,7 @@  #define _DATABASEWORKERPOOL_H  #include "Common.h" -#include "Callback.h" +#include "QueryCallback.h"  #include "MySQLConnection.h"  #include "Transaction.h"  #include "DatabaseWorker.h" @@ -120,7 +120,7 @@ class DatabaseWorkerPool          //! This method should only be used for queries that are only executed once, e.g during startup.          void DirectExecute(const char* sql)          { -            if (!sql) +            if (Trinity::IsFormatEmptyOrNull(sql))                  return;              T* connection = GetFreeConnection(); @@ -175,7 +175,7 @@ class DatabaseWorkerPool          template<typename Format, typename... Args>          QueryResult PQuery(Format&& sql, Args&&... args)          { -            if (!sql) +            if (Trinity::IsFormatEmptyOrNull(sql))                  return QueryResult(nullptr);              return Query(Trinity::StringFormat(std::forward<Format>(sql), std::forward<Args>(args)...).c_str()); diff --git a/src/server/database/Database/QueryCallback.h b/src/server/database/Database/QueryCallback.h new file mode 100644 index 00000000000..5f6ae74da4f --- /dev/null +++ b/src/server/database/Database/QueryCallback.h @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * 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 _QUERY_CALLBACK_H +#define _QUERY_CALLBACK_H + +#include <future> +#include "QueryResult.h" + +typedef std::future<QueryResult> QueryResultFuture; +typedef std::promise<QueryResult> QueryResultPromise; +typedef std::future<PreparedQueryResult> PreparedQueryResultFuture; +typedef std::promise<PreparedQueryResult> PreparedQueryResultPromise; + +#define CALLBACK_STAGE_INVALID uint8(-1) + +template <typename Result, typename ParamType, bool chain = false> +class QueryCallback +{ +    public: +        QueryCallback() : _param(), _stage(chain ? 0 : CALLBACK_STAGE_INVALID)  { } + +        //! The parameter of this function should be a resultset returned from either .AsyncQuery or .AsyncPQuery +        void SetFutureResult(std::future<Result> value) +        { +            _result = std::move(value); +        } + +        std::future<Result>& GetFutureResult() +        { +            return _result; +        } + +        int IsReady() +        { +            return _result.valid() && _result.wait_for(std::chrono::seconds(0)) == std::future_status::ready; +        } + +        void GetResult(Result& res) +        { +            res = _result.get(); +        } + +        void FreeResult() +        { +            // Nothing to do here, the constructor of std::future will take care of the cleanup +        } + +        void SetParam(ParamType value) +        { +            _param = value; +        } + +        ParamType GetParam() +        { +            return _param; +        } + +        //! Resets the stage of the callback chain +        void ResetStage() +        { +            if (!chain) +                return; + +            _stage = 0; +        } + +        //! Advances the callback chain to the next stage, so upper level code can act on its results accordingly +        void NextStage() +        { +            if (!chain) +                return; + +            ++_stage; +        } + +        //! Returns the callback stage (or CALLBACK_STAGE_INVALID if invalid) +        uint8 GetStage() +        { +            return _stage; +        } + +        //! Resets all underlying variables (param, result and stage) +        void Reset() +        { +            SetParam(ParamType()); +            FreeResult(); +            ResetStage(); +        } + +    private: +        std::future<Result> _result; +        ParamType _param; +        uint8 _stage; + +        QueryCallback(QueryCallback const& right) = delete; +        QueryCallback& operator=(QueryCallback const& right) = delete; +}; + +template <typename Result, typename ParamType1, typename ParamType2, bool chain = false> +class QueryCallback_2 +{ +    public: +        QueryCallback_2() : _stage(chain ? 0 : CALLBACK_STAGE_INVALID) { } + +        //! The parameter of this function should be a resultset returned from either .AsyncQuery or .AsyncPQuery +        void SetFutureResult(std::future<Result> value) +        { +            _result = std::move(value); +        } + +        std::future<Result>& GetFutureResult() +        { +            return _result; +        } + +        int IsReady() +        { +            return _result.valid() && _result.wait_for(std::chrono::seconds(0)) == std::future_status::ready; +        } + +        void GetResult(Result& res) +        { +            res = _result.get(); +        } + +        void FreeResult() +        { +            // Nothing to do here, the constructor of std::future will take care of the cleanup +        } + +        void SetFirstParam(ParamType1 value) +        { +            _param_1 = value; +        } + +        void SetSecondParam(ParamType2 value) +        { +            _param_2 = value; +        } + +        ParamType1 GetFirstParam() +        { +            return _param_1; +        } + +        ParamType2 GetSecondParam() +        { +            return _param_2; +        } + +        //! Resets the stage of the callback chain +        void ResetStage() +        { +            if (!chain) +                return; + +            _stage = 0; +        } + +        //! Advances the callback chain to the next stage, so upper level code can act on its results accordingly +        void NextStage() +        { +            if (!chain) +                return; + +            ++_stage; +        } + +        //! Returns the callback stage (or CALLBACK_STAGE_INVALID if invalid) +        uint8 GetStage() +        { +            return _stage; +        } + +        //! Resets all underlying variables (param, result and stage) +        void Reset() +        { +            SetFirstParam(NULL); +            SetSecondParam(NULL); +            FreeResult(); +            ResetStage(); +        } + +    private: +        std::future<Result> _result; +        ParamType1 _param_1; +        ParamType2 _param_2; +        uint8 _stage; + +        QueryCallback_2(QueryCallback_2 const& right) = delete; +        QueryCallback_2& operator=(QueryCallback_2 const& right) = delete; +}; + +#endif // _QUERY_CALLBACK_H diff --git a/src/server/game/AI/CoreAI/CombatAI.cpp b/src/server/game/AI/CoreAI/CombatAI.cpp index 716ac13c666..4d0247d9fb5 100644 --- a/src/server/game/AI/CoreAI/CombatAI.cpp +++ b/src/server/game/AI/CoreAI/CombatAI.cpp @@ -50,7 +50,7 @@ void AggressorAI::UpdateAI(uint32 /*diff*/)  void CombatAI::InitializeAI()  { -    for (uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) +    for (uint32 i = 0; i < MAX_CREATURE_SPELLS; ++i)          if (me->m_spells[i] && sSpellMgr->GetSpellInfo(me->m_spells[i]))              spells.push_back(me->m_spells[i]); diff --git a/src/server/game/AI/CoreAI/PassiveAI.cpp b/src/server/game/AI/CoreAI/PassiveAI.cpp index aafde3c1d9a..3ed2f927645 100644 --- a/src/server/game/AI/CoreAI/PassiveAI.cpp +++ b/src/server/game/AI/CoreAI/PassiveAI.cpp @@ -58,6 +58,12 @@ void PossessedAI::KilledUnit(Unit* victim)          victim->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);  } +void PossessedAI::OnCharmed(bool /*apply*/) +{ +    me->NeedChangeAI = true; +    me->IsAIEnabled = false; +} +  void CritterAI::DamageTaken(Unit* /*done_by*/, uint32&)  {      if (!me->HasUnitState(UNIT_STATE_FLEEING)) diff --git a/src/server/game/AI/CoreAI/PassiveAI.h b/src/server/game/AI/CoreAI/PassiveAI.h index 5a6dba7046d..9ca9e75bd9f 100644 --- a/src/server/game/AI/CoreAI/PassiveAI.h +++ b/src/server/game/AI/CoreAI/PassiveAI.h @@ -46,6 +46,8 @@ class TC_GAME_API PossessedAI : public CreatureAI          void JustDied(Unit*) override;          void KilledUnit(Unit* victim) override; +        void OnCharmed(bool /*apply*/) override; +          static int Permissible(const Creature*) { return PERMIT_BASE_IDLE;  }  }; diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index 68554722db6..2abe20f0ae6 100644 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -588,6 +588,12 @@ void PetAI::ReceiveEmote(Player* player, uint32 emote)          }  } +void PetAI::OnCharmed(bool /*apply*/) +{ +    me->NeedChangeAI = true; +    me->IsAIEnabled = false; +} +  void PetAI::ClearCharmInfoFlags()  {      // Quick access to set all flags to FALSE diff --git a/src/server/game/AI/CoreAI/PetAI.h b/src/server/game/AI/CoreAI/PetAI.h index 3ad34047b01..93ee6c41ece 100644 --- a/src/server/game/AI/CoreAI/PetAI.h +++ b/src/server/game/AI/CoreAI/PetAI.h @@ -49,6 +49,8 @@ class TC_GAME_API PetAI : public CreatureAI          void MoveInLineOfSight_Safe(Unit* /*who*/) { } // CreatureAI interferes with returning pets          void EnterEvadeMode(EvadeReason /*why*/) override { } // For fleeing, pets don't use this type of Evade mechanic +        void OnCharmed(bool /*apply*/) override; +      private:          bool _isVisible(Unit*) const;          bool _needToStop(void); diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index 344ccc06249..20a986c0483 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -242,6 +242,7 @@ class TC_GAME_API UnitAI          void DoAddAuraToAllHostilePlayers(uint32 spellid);          void DoCast(uint32 spellId);          void DoCast(Unit* victim, uint32 spellId, bool triggered = false); +        void DoCastSelf(uint32 spellId, bool triggered = false) { DoCast(me, spellId, triggered); }          void DoCastToAllHostilePlayers(uint32 spellid, bool triggered = false);          void DoCastVictim(uint32 spellId, bool triggered = false);          void DoCastAOE(uint32 spellId, bool triggered = false); diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp index 6ceb4f01c48..15bbff2793f 100644 --- a/src/server/game/AI/CreatureAI.cpp +++ b/src/server/game/AI/CreatureAI.cpp @@ -29,11 +29,13 @@  #include "Language.h"  //Disable CreatureAI when charmed -void CreatureAI::OnCharmed(bool /*apply*/) +void CreatureAI::OnCharmed(bool apply)  { -    //me->IsAIEnabled = !apply;*/ -    me->NeedChangeAI = true; -    me->IsAIEnabled = false; +    if (apply) +    { +        me->NeedChangeAI = true; +        me->IsAIEnabled = false; +    }  }  AISpellInfoType* UnitAI::AISpellInfo; @@ -44,7 +46,7 @@ void CreatureAI::Talk(uint8 id, WorldObject const* whisperTarget /*= nullptr*/)      sCreatureTextMgr->SendChat(me, id, whisperTarget);  } -void CreatureAI::DoZoneInCombat(Creature* creature /*= NULL*/, float maxRangeToNearestTarget /* = 50.0f*/) +void CreatureAI::DoZoneInCombat(Creature* creature /*= nullptr*/, float maxRangeToNearestTarget /* = 250.0f*/)  {      if (!creature)          creature = me; @@ -263,9 +265,10 @@ bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/)      me->DeleteThreatList();      me->CombatStop(true);      me->LoadCreaturesAddon(); -    me->SetLootRecipient(NULL); +    me->SetLootRecipient(nullptr);      me->ResetPlayerDamageReq();      me->SetLastDamagedTime(0); +    me->SetCannotReachTarget(false);      if (me->IsInEvadeMode())          return false; @@ -273,11 +276,11 @@ bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/)      return true;  } -#define BOUNDARY_VISUALIZE_CREATURE 15425 -#define BOUNDARY_VISUALIZE_CREATURE_SCALE 0.25f -#define BOUNDARY_VISUALIZE_STEP_SIZE 1 -#define BOUNDARY_VISUALIZE_FAILSAFE_LIMIT 750 -#define BOUNDARY_VISUALIZE_SPAWN_HEIGHT 5 +static const uint32 BOUNDARY_VISUALIZE_CREATURE = 15425; +static const float BOUNDARY_VISUALIZE_CREATURE_SCALE = 0.25f; +static const int8 BOUNDARY_VISUALIZE_STEP_SIZE = 1; +static const int32 BOUNDARY_VISUALIZE_FAILSAFE_LIMIT = 750; +static const float BOUNDARY_VISUALIZE_SPAWN_HEIGHT = 5.0f;  int32 CreatureAI::VisualizeBoundary(uint32 duration, Unit* owner, bool fill) const  {      typedef std::pair<int32, int32> coordinate; @@ -293,13 +296,13 @@ int32 CreatureAI::VisualizeBoundary(uint32 duration, Unit* owner, bool fill) con      std::unordered_set<coordinate> outOfBounds;      Position startPosition = owner->GetPosition(); -    if (!CheckBoundary(&startPosition)) // fall back to creature position -    { +    if (!CheckBoundary(&startPosition)) +    { // fall back to creature position          startPosition = me->GetPosition();          if (!CheckBoundary(&startPosition)) -        { +        { // fall back to creature home position              startPosition = me->GetHomePosition(); -            if (!CheckBoundary(&startPosition)) // fall back to creature home position +            if (!CheckBoundary(&startPosition))                  return LANG_CREATURE_NO_INTERIOR_POINT_FOUND;          }      } diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index f175050e107..f8fa6ba532b 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -87,6 +87,7 @@ class TC_GAME_API CreatureAI : public UnitAI          {              EVADE_REASON_NO_HOSTILES,       // the creature's threat list is empty              EVADE_REASON_BOUNDARY,          // the creature has moved outside its evade boundary +            EVADE_REASON_NO_PATH,           // the creature was unable to reach its target for over 5 seconds              EVADE_REASON_SEQUENCE_BREAK,    // this is a boss and the pre-requisite encounters for engaging it are not defeated yet              EVADE_REASON_OTHER          }; @@ -111,7 +112,7 @@ class TC_GAME_API CreatureAI : public UnitAI          // Called for reaction at stopping attack at no attackers or targets          virtual void EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER); -        // Called for reaction at enter to combat if not in combat yet (enemy can be NULL) +        // Called for reaction at enter to combat if not in combat yet (enemy can be nullptr)          virtual void EnterCombat(Unit* /*victim*/) { }          // Called when the creature is killed @@ -148,7 +149,7 @@ class TC_GAME_API CreatureAI : public UnitAI          // Called at reaching home after evade          virtual void JustReachedHome() { } -        void DoZoneInCombat(Creature* creature = NULL, float maxRangeToNearestTarget = 50.0f); +        void DoZoneInCombat(Creature* creature = nullptr, float maxRangeToNearestTarget = 250.0f);          // Called at text emote receive from player          virtual void ReceiveEmote(Player* /*player*/, uint32 /*emoteId*/) { } diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 6f04a852b61..6475cc8117e 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -32,7 +32,7 @@ struct TSpellSummary      uint8 Effects;                                          // set of enum SelectEffect  } extern* SpellSummary; -void SummonList::DoZoneInCombat(uint32 entry) +void SummonList::DoZoneInCombat(uint32 entry, float maxRangeToNearestTarget)  {      for (StorageType::iterator i = storage_.begin(); i != storage_.end();)      { @@ -41,7 +41,7 @@ void SummonList::DoZoneInCombat(uint32 entry)          if (summon && summon->IsAIEnabled                  && (!entry || summon->GetEntry() == entry))          { -            summon->AI()->DoZoneInCombat(); +            summon->AI()->DoZoneInCombat(nullptr, maxRangeToNearestTarget);          }      }  } @@ -183,22 +183,22 @@ SpellInfo const* ScriptedAI::SelectSpell(Unit* target, uint32 school, uint32 mec  {      //No target so we can't cast      if (!target) -        return NULL; +        return nullptr;      //Silenced so we can't cast      if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) -        return NULL; +        return nullptr;      //Using the extended script system we first create a list of viable spells -    SpellInfo const* apSpell[CREATURE_MAX_SPELLS]; -    memset(apSpell, 0, CREATURE_MAX_SPELLS * sizeof(SpellInfo*)); +    SpellInfo const* apSpell[MAX_CREATURE_SPELLS]; +    memset(apSpell, 0, MAX_CREATURE_SPELLS * sizeof(SpellInfo*));      uint32 spellCount = 0; -    SpellInfo const* tempSpell = NULL; +    SpellInfo const* tempSpell = nullptr;      //Check if each spell is viable(set it to null if not) -    for (uint32 i = 0; i < CREATURE_MAX_SPELLS; i++) +    for (uint32 i = 0; i < MAX_CREATURE_SPELLS; i++)      {          tempSpell = sSpellMgr->GetSpellInfo(me->m_spells[i]); @@ -251,7 +251,7 @@ SpellInfo const* ScriptedAI::SelectSpell(Unit* target, uint32 school, uint32 mec      //We got our usable spells so now lets randomly pick one      if (!spellCount) -        return NULL; +        return nullptr;      return apSpell[urand(0, spellCount - 1)];  } @@ -327,7 +327,7 @@ void ScriptedAI::DoTeleportAll(float x, float y, float z, float o)  Unit* ScriptedAI::DoSelectLowestHpFriendly(float range, uint32 minHPDiff)  { -    Unit* unit = NULL; +    Unit* unit = nullptr;      Trinity::MostHPMissingInRange u_check(me, range, minHPDiff);      Trinity::UnitLastSearcher<Trinity::MostHPMissingInRange> searcher(me, unit, u_check);      me->VisitNearbyObject(range, searcher); @@ -357,7 +357,7 @@ std::list<Creature*> ScriptedAI::DoFindFriendlyMissingBuff(float range, uint32 u  Player* ScriptedAI::GetPlayerAtMinimumRange(float minimumRange)  { -    Player* player = NULL; +    Player* player = nullptr;      CellCoord pair(Trinity::ComputeCellCoord(me->GetPositionX(), me->GetPositionY()));      Cell cell(pair); @@ -547,7 +547,7 @@ void BossAI::UpdateAI(uint32 diff)      DoMeleeAttackIfReady();  } -void BossAI::_DespawnAtEvade(uint32 delayToRespawn) +void BossAI::_DespawnAtEvade(uint32 delayToRespawn, Creature* who)  {      if (delayToRespawn < 2)      { @@ -555,18 +555,28 @@ void BossAI::_DespawnAtEvade(uint32 delayToRespawn)          delayToRespawn = 2;      } -    uint32 corpseDelay = me->GetCorpseDelay(); -    uint32 respawnDelay = me->GetRespawnDelay(); +    if (!who) +        who = me; -    me->SetCorpseDelay(1); -    me->SetRespawnDelay(delayToRespawn - 1); +    if (TempSummon* whoSummon = who->ToTempSummon()) +    { +        TC_LOG_WARN("scripts", "_DespawnAtEvade called on a temporary summon."); +        whoSummon->UnSummon(); +        return; +    } -    me->DespawnOrUnsummon(); +    uint32 corpseDelay = who->GetCorpseDelay(); +    uint32 respawnDelay = who->GetRespawnDelay(); -    me->SetCorpseDelay(corpseDelay); -    me->SetRespawnDelay(respawnDelay); +    who->SetCorpseDelay(1); +    who->SetRespawnDelay(delayToRespawn - 1); -    if (instance) +    who->DespawnOrUnsummon(); + +    who->SetCorpseDelay(corpseDelay); +    who->SetRespawnDelay(respawnDelay); + +    if (instance && who == me)          instance->SetBossState(_bossId, FAIL);  } @@ -628,27 +638,27 @@ void WorldBossAI::UpdateAI(uint32 diff)  }  // SD2 grid searchers. -TC_GAME_API Creature* GetClosestCreatureWithEntry(WorldObject* source, uint32 entry, float maxSearchRange, bool alive /*= true*/) +Creature* GetClosestCreatureWithEntry(WorldObject* source, uint32 entry, float maxSearchRange, bool alive /*= true*/)  {      return source->FindNearestCreature(entry, maxSearchRange, alive);  } -TC_GAME_API GameObject* GetClosestGameObjectWithEntry(WorldObject* source, uint32 entry, float maxSearchRange) +GameObject* GetClosestGameObjectWithEntry(WorldObject* source, uint32 entry, float maxSearchRange)  {      return source->FindNearestGameObject(entry, maxSearchRange);  } -TC_GAME_API void GetCreatureListWithEntryInGrid(std::list<Creature*>& list, WorldObject* source, uint32 entry, float maxSearchRange) +void GetCreatureListWithEntryInGrid(std::list<Creature*>& list, WorldObject* source, uint32 entry, float maxSearchRange)  {      source->GetCreatureListWithEntryInGrid(list, entry, maxSearchRange);  } -TC_GAME_API void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& list, WorldObject* source, uint32 entry, float maxSearchRange) +void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& list, WorldObject* source, uint32 entry, float maxSearchRange)  {      source->GetGameObjectListWithEntryInGrid(list, entry, maxSearchRange);  } -TC_GAME_API void GetPlayerListInGrid(std::list<Player*>& list, WorldObject* source, float maxSearchRange) +void GetPlayerListInGrid(std::list<Player*>& list, WorldObject* source, float maxSearchRange)  {      source->GetPlayerListInGrid(list, maxSearchRange);  } diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index 42befa26a23..6144a4e5203 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -114,7 +114,7 @@ public:          }      } -    void DoZoneInCombat(uint32 entry = 0); +    void DoZoneInCombat(uint32 entry = 0, float maxRangeToNearestTarget = 250.0f);      void RemoveNotExisting();      bool HasEntry(uint32 entry) const; @@ -367,7 +367,7 @@ class TC_GAME_API BossAI : public ScriptedAI          void _EnterCombat();          void _JustDied();          void _JustReachedHome() { me->setActive(false); } -        void _DespawnAtEvade(uint32 delayToRespawn = 30); +        void _DespawnAtEvade(uint32 delayToRespawn = 30,  Creature* who = nullptr);          void TeleportCheaters(); diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 8e9bd7cdff7..60df4fe6d5a 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -416,12 +416,7 @@ void SmartAI::EnterEvadeMode(EvadeReason /*why*/)      me->RemoveAurasOnEvade();      me->AddUnitState(UNIT_STATE_EVADE); -    me->DeleteThreatList(); -    me->CombatStop(true); -    me->LoadCreaturesAddon(); -    me->SetLootRecipient(NULL); -    me->ResetPlayerDamageReq(); -    me->SetLastDamagedTime(0); +    _EnterEvadeMode();      GetScript()->ProcessEventsFor(SMART_EVENT_EVADE);//must be after aura clear so we can cast spells from db @@ -653,8 +648,8 @@ void SmartAI::OnCharmed(bool apply)  {      GetScript()->ProcessEventsFor(SMART_EVENT_CHARMED, NULL, 0, 0, apply); -    if (!apply && !me->IsInEvadeMode() && me->GetCharmerGUID()) -        if (Unit* charmer = ObjectAccessor::GetUnit(*me, me->GetCharmerGUID())) +    if (!apply && !me->IsInEvadeMode()) +        if (Unit* charmer = me->GetCharmer())              AttackStart(charmer);  } diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 5f883175157..9dd56ec8180 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -697,6 +697,10 @@ enum RBACPermissions      // 799 - 834 6.x only      RBAC_PERM_COMMAND_DEBUG_LOADCELLS                        = 835,      RBAC_PERM_COMMAND_DEBUG_BOUNDARY                         = 836, +    RBAC_PERM_COMMAND_NPC_EVADE                              = 837, +    RBAC_PERM_COMMAND_PET_LEVEL                              = 838, +    RBAC_PERM_COMMAND_SERVER_SHUTDOWN_FORCE                  = 839, +    RBAC_PERM_COMMAND_SERVER_RESTART_FORCE                   = 840,      // custom permissions 1000+      RBAC_PERM_MAX diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 87f5ff6ce5c..11c2635da33 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -646,13 +646,20 @@ void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement)      if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_KILL | ACHIEVEMENT_FLAG_REALM_FIRST_REACH))      { +        uint32 team = GetPlayer()->GetTeam(); +          // broadcast realm first reached          WorldPacket data(SMSG_SERVER_FIRST_ACHIEVEMENT, GetPlayer()->GetName().size() + 1 + 8 + 4 + 4);          data << GetPlayer()->GetName();          data << uint64(GetPlayer()->GetGUID());          data << uint32(achievement->ID); -        data << uint32(0);                                  // 1=link supplied string as player name, 0=display plain string -        sWorld->SendGlobalMessage(&data); + +        std::size_t linkTypePos = data.wpos(); +        data << uint32(1);                                  // display name as clickable link in chat +        sWorld->SendGlobalMessage(&data, nullptr, team); + +        data.put<uint32>(linkTypePos, 0);                   // display name as plain string in chat +        sWorld->SendGlobalMessage(&data, nullptr, team == ALLIANCE ? HORDE : ALLIANCE);      }      // if player is in world he can tell his friends about new achievement      else if (GetPlayer()->IsInWorld()) diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index f0ea5b4a5f1..cb2f26e567f 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -19,6 +19,22 @@  #ifndef DBCENUMS_H  #define DBCENUMS_H +#pragma pack(push, 1) + +struct DBCPosition2D +{ +    float X; +    float Y; +}; + +struct DBCPosition3D +{ +    float X; +    float Y; +    float Z; +}; + +#pragma pack(pop)  enum LevelLimit  {      // Client expected level limitation, like as used in DBC item max levels for "until max player level" diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 5ede70da2a3..36ec418ed56 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -27,9 +27,6 @@  #include <boost/regex.hpp>  #include <map> -#include <fstream> -#include <iostream> -#include <iomanip>  typedef std::map<uint16, uint32> AreaFlagByAreaID;  typedef std::map<uint32, uint32> AreaFlagByMapID; @@ -221,8 +218,6 @@ DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreaEntryfmt);  DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore(WorldMapOverlayEntryfmt);  DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore(WorldSafeLocsEntryfmt); -std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore; -  typedef std::list<std::string> StoreProblemList;  uint32 DBCFileCount = 0; @@ -724,250 +719,10 @@ void LoadDBCStores(const std::string& dataPath)          exit(1);      } -    LoadM2Cameras(dataPath); -      TC_LOG_INFO("server.loading", ">> Initialized %d data stores in %u ms", DBCFileCount, GetMSTimeDiffToNow(oldMSTime));  } -// Convert the geomoetry from a spline value, to an actual WoW XYZ -G3D::Vector3 TranslateLocation(G3D::Vector4 const* DBCPosition, G3D::Vector3 const* basePosition, G3D::Vector3 const* splineVector) -{ -    G3D::Vector3 work; -    float x = basePosition->x + splineVector->x; -    float y = basePosition->y + splineVector->y; -    float z = basePosition->z + splineVector->z; -    float const distance = sqrt((x * x) + (y * y)); -    float angle = std::atan2(x, y) - DBCPosition->w; - -    if (angle < 0) -        angle += 2 * float(M_PI); - -    work.x = DBCPosition->x + (distance * sin(angle)); -    work.y = DBCPosition->y + (distance * cos(angle)); -    work.z = DBCPosition->z + z; -    return work; -} - -// Number of cameras not used. Multiple cameras never used in 3.3.5 -bool readCamera(M2Camera const* cam, uint32 buffSize, M2Header const* header, CinematicCameraEntry const* dbcentry) -{ -    char const* buffer = reinterpret_cast<char const*>(header); - -    FlyByCameraCollection cameras; -    FlyByCameraCollection targetcam; - -    G3D::Vector4 DBCData; -    DBCData.x = dbcentry->base_x; -    DBCData.y = dbcentry->base_y; -    DBCData.z = dbcentry->base_z; -    DBCData.w = dbcentry->base_o; - -    // Read target locations, only so that we can calculate orientation -    for (uint32 k = 0; k < cam->target_positions.timestamps.number; ++k) -    { -        // Extract Target positions -        if (cam->target_positions.timestamps.offset_elements + sizeof(M2Array) > buffSize) -            return false; -        M2Array const* targTsArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.timestamps.offset_elements); -        if (targTsArray->offset_elements + sizeof(uint32) > buffSize || cam->target_positions.values.offset_elements + sizeof(M2Array) > buffSize) -            return false; -        uint32 const* targTimestamps = reinterpret_cast<uint32 const*>(buffer + targTsArray->offset_elements); -        M2Array const* targArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.values.offset_elements); - -        if (targArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize) -            return false; -        M2SplineKey<G3D::Vector3> const* targPositions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + targArray->offset_elements); - -        // Read the data for this set -        uint32 currPos = targArray->offset_elements; -        for (uint32 i = 0; i < targTsArray->number; ++i) -        { -            if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize) -                return false; -            // Translate co-ordinates -            G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->target_position_base, &targPositions->p0); - -            // Add to vector -            FlyByCamera thisCam; -            thisCam.timeStamp = targTimestamps[i]; -            thisCam.locations.x = newPos.x; -            thisCam.locations.y = newPos.y; -            thisCam.locations.z = newPos.z; -            thisCam.locations.w = 0.0f; -            targetcam.push_back(thisCam); -            targPositions++; -            currPos += sizeof(M2SplineKey<G3D::Vector3>); -        } -    } - -    // Read camera positions and timestamps (translating first position of 3 only, we don't need to translate the whole spline) -    for (uint32 k = 0; k < cam->positions.timestamps.number; ++k) -    { -        // Extract Camera positions for this set -        if (cam->positions.timestamps.offset_elements + sizeof(M2Array) > buffSize) -            return false; -        M2Array const* posTsArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.timestamps.offset_elements); -        if (posTsArray->offset_elements + sizeof(uint32) > buffSize || cam->positions.values.offset_elements + sizeof(M2Array) > buffSize) -            return false; -        uint32 const* posTimestamps = reinterpret_cast<uint32 const*>(buffer + posTsArray->offset_elements); -        M2Array const* posArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.values.offset_elements); -        if (posArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize) -            return false; -        M2SplineKey<G3D::Vector3> const* positions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + posArray->offset_elements); - -        // Read the data for this set -        uint32 currPos = posArray->offset_elements; -        for (uint32 i = 0; i < posTsArray->number; ++i) -        { -            if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize) -                return false; -            // Translate co-ordinates -            G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->position_base, &positions->p0); - -            // Add to vector -            FlyByCamera thisCam; -            thisCam.timeStamp = posTimestamps[i]; -            thisCam.locations.x = newPos.x; -            thisCam.locations.y = newPos.y; -            thisCam.locations.z = newPos.z; - -            if (targetcam.size() > 0) -            { -                // Find the target camera before and after this camera -                FlyByCamera lastTarget; -                FlyByCamera nextTarget; - -                // Pre-load first item -                lastTarget = targetcam[0]; -                nextTarget = targetcam[0]; -                for (uint32 j = 0; j < targetcam.size(); ++j) -                { -                    nextTarget = targetcam[j]; -                    if (targetcam[j].timeStamp > posTimestamps[i]) -                        break; - -                    lastTarget = targetcam[j]; -                } - -                float x = lastTarget.locations.x; -                float y = lastTarget.locations.y; -                float z = lastTarget.locations.z; - -                // Now, the timestamps for target cam and position can be different. So, if they differ we interpolate -                if (lastTarget.timeStamp != posTimestamps[i]) -                { -                    uint32 timeDiffTarget = nextTarget.timeStamp - lastTarget.timeStamp; -                    uint32 timeDiffThis = posTimestamps[i] - lastTarget.timeStamp; -                    float xDiff = nextTarget.locations.x - lastTarget.locations.x; -                    float yDiff = nextTarget.locations.y - lastTarget.locations.y; -                    float zDiff = nextTarget.locations.z - lastTarget.locations.z; -                    x = lastTarget.locations.x + (xDiff * (float(timeDiffThis) / float(timeDiffTarget))); -                    y = lastTarget.locations.y + (yDiff * (float(timeDiffThis) / float(timeDiffTarget))); -                    z = lastTarget.locations.z + (zDiff * (float(timeDiffThis) / float(timeDiffTarget))); -                } -                float xDiff = x - thisCam.locations.x; -                float yDiff = y - thisCam.locations.y; -                thisCam.locations.w = std::atan2(yDiff, xDiff); - -                if (thisCam.locations.w < 0) -                    thisCam.locations.w += 2 * float(M_PI); -            } - -            cameras.push_back(thisCam); -            positions++; -            currPos += sizeof(M2SplineKey<G3D::Vector3>); -        } -    } - -    sFlyByCameraStore[dbcentry->id] = cameras; -    return true; -} - -void LoadM2Cameras(const std::string& dataPath) -{ -    sFlyByCameraStore.clear(); -    TC_LOG_INFO("server.loading", ">> Loading Cinematic Camera files"); - -    uint32 oldMSTime = getMSTime(); -    for (uint32 i = 0; i < sCinematicCameraStore.GetNumRows(); ++i) -    { -        if (CinematicCameraEntry const* dbcentry = sCinematicCameraStore.LookupEntry(i)) -        { -            std::string filename = dataPath.c_str(); -            filename.append(dbcentry->filename); - -            // Replace slashes -            size_t loc = filename.find("\\"); -            while (loc != std::string::npos) -            { -                filename.replace(loc, 1, "/"); -                loc = filename.find("\\"); -            } - -            // Replace mdx to .m2 -            loc = filename.find(".mdx"); -            if (loc != std::string::npos) -                filename.replace(loc, 4, ".m2"); - -            std::ifstream m2file(filename.c_str(), std::ios::in | std::ios::binary); -            if (!m2file.is_open()) -                continue; - -            // Get file size -            m2file.seekg(0, std::ios::end); -            std::streamoff const fileSize = m2file.tellg(); - -            // Reject if not at least the size of the header -            if (static_cast<uint32 const>(fileSize) < sizeof(M2Header)) -            { -                TC_LOG_ERROR("server.loading", "Camera file %s is damaged. File is smaller than header size", filename.c_str()); -                m2file.close(); -                continue; -            } - -            // Read 4 bytes (signature) -            m2file.seekg(0, std::ios::beg); -            char fileCheck[5]; -            m2file.read(fileCheck, 4); -            fileCheck[4] = 0; - -            // Check file has correct magic (MD20) -            if (strcmp(fileCheck, "MD20")) -            { -                TC_LOG_ERROR("server.loading", "Camera file %s is damaged. File identifier not found", filename.c_str()); -                m2file.close(); -                continue; -            } - -            // Now we have a good file, read it all into a vector of char's, then close the file. -            std::vector<char> buffer(fileSize); -            m2file.seekg(0, std::ios::beg); -            if (!m2file.read(buffer.data(), fileSize)) -            { -                m2file.close(); -                continue; -            } -            m2file.close(); - -            // Read header -            M2Header const* header = reinterpret_cast<M2Header const*>(buffer.data()); - -            if (header->ofsCameras + sizeof(M2Camera) > static_cast<uint32 const>(fileSize)) -            { -                TC_LOG_ERROR("server.loading", "Camera file %s is damaged. Camera references position beyond file end", filename.c_str()); -                continue; -            } - -            // Get camera(s) - Main header, then dump them. -            M2Camera const* cam = reinterpret_cast<M2Camera const*>(buffer.data() + header->ofsCameras); -            if (!readCamera(cam, fileSize, header, dbcentry)) -                TC_LOG_ERROR("server.loading", "Camera file %s is damaged. Camera references position beyond file end", filename.c_str()); -        } -    } -    TC_LOG_INFO("server.loading", ">> Loaded %u cinematic waypoint sets in %u ms", (uint32)sFlyByCameraStore.size(), GetMSTimeDiffToNow(oldMSTime)); -} -  SimpleFactionsList const* GetFactionTeamList(uint32 faction)  {      FactionTeamMap::const_iterator itr = sFactionTeamMap.find(faction); diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index 6cad13fdf9a..00b4141555f 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -27,8 +27,6 @@  #include <list>  typedef std::list<uint32> SimpleFactionsList; -typedef std::vector<FlyByCamera> FlyByCameraCollection; -  TC_GAME_API SimpleFactionsList const* GetFactionTeamList(uint32 faction);  TC_GAME_API char* GetPetName(uint32 petfamily, uint32 dbclang); @@ -196,9 +194,7 @@ TC_GAME_API extern DBCStorage <WMOAreaTableEntry>            sWMOAreaTableStore;  //TC_GAME_API extern DBCStorage <WorldMapAreaEntry>           sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates  TC_GAME_API extern DBCStorage <WorldMapOverlayEntry>         sWorldMapOverlayStore;  TC_GAME_API extern DBCStorage <WorldSafeLocsEntry>           sWorldSafeLocsStore; -TC_GAME_API extern std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore;  TC_GAME_API void LoadDBCStores(const std::string& dataPath); -TC_GAME_API void LoadM2Cameras(const std::string& dataPath);  #endif diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 51b3dcbd38b..13f0198a5e7 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -727,13 +727,11 @@ struct ChrRacesEntry  struct CinematicCameraEntry  { -    uint32      id;                                         // 0 index -    char*       filename;                                   // 1 -    uint32      soundid;                                    // 2 in SoundEntries.dbc or 0 -    float       base_x;                                     // 3 -    float       base_y;                                     // 4 -    float       base_z;                                     // 5 -    float       base_o;                                     // 6 +    uint32 ID;                                              // 0 +    char const* Model;                                      // 1    Model filename (translate .mdx to .m2) +    uint32 SoundID;                                         // 2    Sound ID       (voiceover for cinematic) +    DBCPosition3D Origin;                                   // 3-5  Position in map used for basis for M2 co-ordinates +    float OriginFacing;                                     // 6    Orientation in map used for basis for M2 co-ordinates  };  struct CinematicSequencesEntry diff --git a/src/server/game/DataStores/M2Stores.cpp b/src/server/game/DataStores/M2Stores.cpp new file mode 100644 index 00000000000..5cff66e6107 --- /dev/null +++ b/src/server/game/DataStores/M2Stores.cpp @@ -0,0 +1,266 @@ +/* +* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* 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/>. +*/ + +#include "DBCStores.h" +#include "M2Structure.h" +#include "M2Stores.h" +#include "Common.h" +#include "Containers.h" +#include "Log.h" +#include "World.h" +#include <fstream> +#include <iostream> +#include <iomanip> +#include <boost/filesystem/path.hpp> + +std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore; + +// Convert the geomoetry from a spline value, to an actual WoW XYZ +G3D::Vector3 TranslateLocation(G3D::Vector4 const* DBCPosition, G3D::Vector3 const* basePosition, G3D::Vector3 const* splineVector) +{ +    G3D::Vector3 work; +    float x = basePosition->x + splineVector->x; +    float y = basePosition->y + splineVector->y; +    float z = basePosition->z + splineVector->z; +    float const distance = sqrt((x * x) + (y * y)); +    float angle = std::atan2(x, y) - DBCPosition->w; + +    if (angle < 0) +        angle += 2 * float(M_PI); + +    work.x = DBCPosition->x + (distance * sin(angle)); +    work.y = DBCPosition->y + (distance * cos(angle)); +    work.z = DBCPosition->z + z; +    return work; +} + +// Number of cameras not used. Multiple cameras never used in 3.3.5 +bool readCamera(M2Camera const* cam, uint32 buffSize, M2Header const* header, CinematicCameraEntry const* dbcentry) +{ +    char const* buffer = reinterpret_cast<char const*>(header); + +    FlyByCameraCollection cameras; +    FlyByCameraCollection targetcam; + +    G3D::Vector4 DBCData; +    DBCData.x = dbcentry->Origin.X; +    DBCData.y = dbcentry->Origin.Y; +    DBCData.z = dbcentry->Origin.Z; +    DBCData.w = dbcentry->OriginFacing; + +    // Read target locations, only so that we can calculate orientation +    for (uint32 k = 0; k < cam->target_positions.timestamps.number; ++k) +    { +        // Extract Target positions +        if (cam->target_positions.timestamps.offset_elements + sizeof(M2Array) > buffSize) +            return false; +        M2Array const* targTsArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.timestamps.offset_elements); +        if (targTsArray->offset_elements + sizeof(uint32) > buffSize || cam->target_positions.values.offset_elements + sizeof(M2Array) > buffSize) +            return false; +        uint32 const* targTimestamps = reinterpret_cast<uint32 const*>(buffer + targTsArray->offset_elements); +        M2Array const* targArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.values.offset_elements); + +        if (targArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize) +            return false; +        M2SplineKey<G3D::Vector3> const* targPositions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + targArray->offset_elements); + +        // Read the data for this set +        uint32 currPos = targArray->offset_elements; +        for (uint32 i = 0; i < targTsArray->number; ++i) +        { +            if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize) +                return false; +            // Translate co-ordinates +            G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->target_position_base, &targPositions->p0); + +            // Add to vector +            FlyByCamera thisCam; +            thisCam.timeStamp = targTimestamps[i]; +            thisCam.locations.x = newPos.x; +            thisCam.locations.y = newPos.y; +            thisCam.locations.z = newPos.z; +            thisCam.locations.w = 0.0f; +            targetcam.push_back(thisCam); +            targPositions++; +            currPos += sizeof(M2SplineKey<G3D::Vector3>); +        } +    } + +    // Read camera positions and timestamps (translating first position of 3 only, we don't need to translate the whole spline) +    for (uint32 k = 0; k < cam->positions.timestamps.number; ++k) +    { +        // Extract Camera positions for this set +        if (cam->positions.timestamps.offset_elements + sizeof(M2Array) > buffSize) +            return false; +        M2Array const* posTsArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.timestamps.offset_elements); +        if (posTsArray->offset_elements + sizeof(uint32) > buffSize || cam->positions.values.offset_elements + sizeof(M2Array) > buffSize) +            return false; +        uint32 const* posTimestamps = reinterpret_cast<uint32 const*>(buffer + posTsArray->offset_elements); +        M2Array const* posArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.values.offset_elements); +        if (posArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize) +            return false; +        M2SplineKey<G3D::Vector3> const* positions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + posArray->offset_elements); + +        // Read the data for this set +        uint32 currPos = posArray->offset_elements; +        for (uint32 i = 0; i < posTsArray->number; ++i) +        { +            if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize) +                return false; +            // Translate co-ordinates +            G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->position_base, &positions->p0); + +            // Add to vector +            FlyByCamera thisCam; +            thisCam.timeStamp = posTimestamps[i]; +            thisCam.locations.x = newPos.x; +            thisCam.locations.y = newPos.y; +            thisCam.locations.z = newPos.z; + +            if (targetcam.size() > 0) +            { +                // Find the target camera before and after this camera +                FlyByCamera lastTarget; +                FlyByCamera nextTarget; + +                // Pre-load first item +                lastTarget = targetcam[0]; +                nextTarget = targetcam[0]; +                for (uint32 j = 0; j < targetcam.size(); ++j) +                { +                    nextTarget = targetcam[j]; +                    if (targetcam[j].timeStamp > posTimestamps[i]) +                        break; + +                    lastTarget = targetcam[j]; +                } + +                float x = lastTarget.locations.x; +                float y = lastTarget.locations.y; +                float z = lastTarget.locations.z; + +                // Now, the timestamps for target cam and position can be different. So, if they differ we interpolate +                if (lastTarget.timeStamp != posTimestamps[i]) +                { +                    uint32 timeDiffTarget = nextTarget.timeStamp - lastTarget.timeStamp; +                    uint32 timeDiffThis = posTimestamps[i] - lastTarget.timeStamp; +                    float xDiff = nextTarget.locations.x - lastTarget.locations.x; +                    float yDiff = nextTarget.locations.y - lastTarget.locations.y; +                    float zDiff = nextTarget.locations.z - lastTarget.locations.z; +                    x = lastTarget.locations.x + (xDiff * (float(timeDiffThis) / float(timeDiffTarget))); +                    y = lastTarget.locations.y + (yDiff * (float(timeDiffThis) / float(timeDiffTarget))); +                    z = lastTarget.locations.z + (zDiff * (float(timeDiffThis) / float(timeDiffTarget))); +                } +                float xDiff = x - thisCam.locations.x; +                float yDiff = y - thisCam.locations.y; +                thisCam.locations.w = std::atan2(yDiff, xDiff); + +                if (thisCam.locations.w < 0) +                    thisCam.locations.w += 2 * float(M_PI); +            } + +            cameras.push_back(thisCam); +            positions++; +            currPos += sizeof(M2SplineKey<G3D::Vector3>); +        } +    } + +    sFlyByCameraStore[dbcentry->ID] = cameras; +    return true; +} + +void LoadM2Cameras(std::string const& dataPath) +{ +    sFlyByCameraStore.clear(); +    TC_LOG_INFO("server.loading", ">> Loading Cinematic Camera files"); + +    uint32 oldMSTime = getMSTime(); +    for (uint32 i = 0; i < sCinematicCameraStore.GetNumRows(); ++i) +    { +        if (CinematicCameraEntry const* dbcentry = sCinematicCameraStore.LookupEntry(i)) +        { +            std::string filenameWork = dataPath.c_str(); +            filenameWork.append(dbcentry->Model); + +            // Replace slashes (always to forward slash, because boost!) +            std::replace(filenameWork.begin(), filenameWork.end(), '\\', '/'); + +            boost::filesystem::path filename = filenameWork; + +            // Convert to native format +            filename.make_preferred(); + +            // Replace mdx to .m2 +            filename.replace_extension("m2"); + +            std::ifstream m2file(filename.string().c_str(), std::ios::in | std::ios::binary); +            if (!m2file.is_open()) +                continue; + +            // Get file size +            m2file.seekg(0, std::ios::end); +            std::streamoff const fileSize = m2file.tellg(); + +            // Reject if not at least the size of the header +            if (static_cast<uint32 const>(fileSize) < sizeof(M2Header)) +            { +                TC_LOG_ERROR("server.loading", "Camera file %s is damaged. File is smaller than header size", filename.string().c_str()); +                m2file.close(); +                continue; +            } + +            // Read 4 bytes (signature) +            m2file.seekg(0, std::ios::beg); +            char fileCheck[5]; +            m2file.read(fileCheck, 4); +            fileCheck[4] = 0; + +            // Check file has correct magic (MD20) +            if (strcmp(fileCheck, "MD20")) +            { +                TC_LOG_ERROR("server.loading", "Camera file %s is damaged. File identifier not found", filename.string().c_str()); +                m2file.close(); +                continue; +            } + +            // Now we have a good file, read it all into a vector of char's, then close the file. +            std::vector<char> buffer(fileSize); +            m2file.seekg(0, std::ios::beg); +            if (!m2file.read(buffer.data(), fileSize)) +            { +                m2file.close(); +                continue; +            } +            m2file.close(); + +            // Read header +            M2Header const* header = reinterpret_cast<M2Header const*>(buffer.data()); + +            if (header->ofsCameras + sizeof(M2Camera) > static_cast<uint32 const>(fileSize)) +            { +                TC_LOG_ERROR("server.loading", "Camera file %s is damaged. Camera references position beyond file end", filename.string().c_str()); +                continue; +            } + +            // Get camera(s) - Main header, then dump them. +            M2Camera const* cam = reinterpret_cast<M2Camera const*>(buffer.data() + header->ofsCameras); +            if (!readCamera(cam, fileSize, header, dbcentry)) +                TC_LOG_ERROR("server.loading", "Camera file %s is damaged. Camera references position beyond file end", filename.string().c_str()); +        } +    } +    TC_LOG_INFO("server.loading", ">> Loaded %u cinematic waypoint sets in %u ms", (uint32)sFlyByCameraStore.size(), GetMSTimeDiffToNow(oldMSTime)); +} diff --git a/src/server/game/DataStores/M2Stores.h b/src/server/game/DataStores/M2Stores.h new file mode 100644 index 00000000000..97224475e5d --- /dev/null +++ b/src/server/game/DataStores/M2Stores.h @@ -0,0 +1,36 @@ +/* +* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* 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_M2STORES_H +#define TRINITY_M2STORES_H + +#include "SharedDefines.h" +#include "Common.h" + +struct FlyByCamera +{ +    uint32 timeStamp; +    G3D::Vector4 locations; +}; + +typedef std::vector<FlyByCamera> FlyByCameraCollection; + +TC_GAME_API extern std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore; + +TC_GAME_API void LoadM2Cameras(std::string const& dataPath); + +#endif
\ No newline at end of file diff --git a/src/server/game/DataStores/M2Structure.h b/src/server/game/DataStores/M2Structure.h new file mode 100644 index 00000000000..43e8d008b9f --- /dev/null +++ b/src/server/game/DataStores/M2Structure.h @@ -0,0 +1,133 @@ +/* +* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* 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_M2STRUCTURE_H +#define TRINITY_M2STRUCTURE_H + +#include <G3D/Vector3.h> +#include <G3D/AABox.h> + +// Structures for M2 file. Source: https://wowdev.wiki +#pragma pack(push, 1) +template<typename T> +struct M2SplineKey +{ +    T p0; +    T p1; +    T p2; +}; + +struct M2Header +{ +    char   Magic[4];               // "MD20" +    uint32 Version;                // The version of the format. +    uint32 lName;                  // Length of the model's name including the trailing \0 +    uint32 ofsName;                // Offset to the name, it seems like models can get reloaded by this name.should be unique, i guess. +    uint32 GlobalModelFlags;       // 0x0001: tilt x, 0x0002: tilt y, 0x0008: add 2 fields in header, 0x0020: load .phys data (MoP+), 0x0080: has _lod .skin files (MoP?+), 0x0100: is camera related. +    uint32 nGlobalSequences; +    uint32 ofsGlobalSequences;     // A list of timestamps. +    uint32 nAnimations; +    uint32 ofsAnimations;          // Information about the animations in the model. +    uint32 nAnimationLookup; +    uint32 ofsAnimationLookup;     // Mapping of global IDs to the entries in the Animation sequences block. +    uint32 nBones;                 // MAX_BONES = 0x100 +    uint32 ofsBones;               // Information about the bones in this model. +    uint32 nKeyBoneLookup; +    uint32 ofsKeyBoneLookup;       // Lookup table for key skeletal bones. +    uint32 nVertices; +    uint32 ofsVertices;            // Vertices of the model. +    uint32 nViews;                 // Views (LOD) are now in .skins. +    uint32 nSubmeshAnimations; +    uint32 ofsSubmeshAnimations;   // Submesh color and alpha animations definitions. +    uint32 nTextures; +    uint32 ofsTextures;            // Textures of this model. +    uint32 nTransparency; +    uint32 ofsTransparency;        // Transparency of textures. +    uint32 nUVAnimation; +    uint32 ofsUVAnimation; +    uint32 nTexReplace; +    uint32 ofsTexReplace;          // Replaceable Textures. +    uint32 nRenderFlags; +    uint32 ofsRenderFlags;         // Blending modes / render flags. +    uint32 nBoneLookupTable; +    uint32 ofsBoneLookupTable;     // A bone lookup table. +    uint32 nTexLookup; +    uint32 ofsTexLookup;           // The same for textures. +    uint32 nTexUnits;              // possibly removed with cata?! +    uint32 ofsTexUnits;            // And texture units. Somewhere they have to be too. +    uint32 nTransLookup; +    uint32 ofsTransLookup;         // Everything needs its lookup. Here are the transparencies. +    uint32 nUVAnimLookup; +    uint32 ofsUVAnimLookup; +    G3D::AABox BoundingBox;            // min/max( [1].z, 2.0277779f ) - 0.16f seems to be the maximum camera height +    float  BoundingSphereRadius; +    G3D::AABox CollisionBox; +    float  CollisionSphereRadius; +    uint32 nBoundingTriangles; +    uint32 ofsBoundingTriangles;   // Our bounding volumes. Similar structure like in the old ofsViews. +    uint32 nBoundingVertices; +    uint32 ofsBoundingVertices; +    uint32 nBoundingNormals; +    uint32 ofsBoundingNormals; +    uint32 nAttachments; +    uint32 ofsAttachments;         // Attachments are for weapons etc. +    uint32 nAttachLookup; +    uint32 ofsAttachLookup;        // Of course with a lookup. +    uint32 nEvents; +    uint32 ofsEvents;              // Used for playing sounds when dying and a lot else. +    uint32 nLights; +    uint32 ofsLights;              // Lights are mainly used in loginscreens but in wands and some doodads too. +    uint32 nCameras;               // Format of Cameras changed with version 271! +    uint32 ofsCameras;             // The cameras are present in most models for having a model in the Character-Tab. +    uint32 nCameraLookup; +    uint32 ofsCameraLookup;        // And lookup-time again. +    uint32 nRibbonEmitters; +    uint32 ofsRibbonEmitters;      // Things swirling around. See the CoT-entrance for light-trails. +    uint32 nParticleEmitters; +    uint32 ofsParticleEmitters;    // Spells and weapons, doodads and loginscreens use them. Blood dripping of a blade? Particles. +    uint32 nBlendMaps;             // This has to deal with blending. Exists IFF (flags & 0x8) != 0. When set, textures blending is overriden by the associated array. See M2/WotLK#Blend_mode_overrides +    uint32 ofsBlendMaps;           // Same as above. Points to an array of uint16 of nBlendMaps entries -- From WoD information.}; +}; + +struct M2Array +{ +    uint32_t number; +    uint32 offset_elements; +}; +struct M2Track +{ +    uint16_t interpolation_type; +    uint16_t global_sequence; +    M2Array timestamps; +    M2Array values; +}; + +struct M2Camera +{ +    uint32_t type; // 0: portrait, 1: characterinfo; -1: else (flyby etc.); referenced backwards in the lookup table. +    float fov; // No radians, no degrees. Multiply by 35 to get degrees. +    float far_clip; +    float near_clip; +    M2Track positions; // How the camera's position moves. Should be 3*3 floats. +    G3D::Vector3 position_base; +    M2Track target_positions; // How the target moves. Should be 3*3 floats. +    G3D::Vector3 target_position_base; +    M2Track rolldata; // The camera can have some roll-effect. Its 0 to 2*Pi. +}; +#pragma pack(pop) + +#endif
\ No newline at end of file diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index d3843c86aa4..450cf2396a8 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -182,13 +182,13 @@ m_groupLootTimer(0), lootingGroupLowGUID(0), m_PlayerDamageReq(0),  m_lootRecipient(), m_lootRecipientGroup(0), _skinner(), _pickpocketLootRestore(0), m_corpseRemoveTime(0), m_respawnTime(0),  m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_boundaryCheckTime(2500), m_combatPulseTime(0), m_combatPulseDelay(0), m_reactState(REACT_AGGRESSIVE),  m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), -m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), +m_AlreadySearchedAssistance(false), m_regenHealth(true), m_cannotReachTarget(false), m_cannotReachTimer(0), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),  m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_waypointID(0), m_path_id(0), m_formation(nullptr), m_focusSpell(nullptr), m_focusDelay(0)  {      m_regenTimer = CREATURE_REGEN_INTERVAL;      m_valuesCount = UNIT_END; -    for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i) +    for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)          m_spells[i] = 0;      DisableReputationGain = false; @@ -394,7 +394,7 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/)      if (!m_respawnradius && m_defaultMovementType == RANDOM_MOTION_TYPE)          m_defaultMovementType = IDLE_MOTION_TYPE; -    for (uint8 i=0; i < CREATURE_MAX_SPELLS; ++i) +    for (uint8 i=0; i < MAX_CREATURE_SPELLS; ++i)          m_spells[i] = GetCreatureTemplate()->spells[i];      return true; @@ -648,33 +648,32 @@ void Creature::Update(uint32 diff)                      m_regenTimer -= diff;              } -            if (m_regenTimer != 0) -               break; - -            bool bInCombat = IsInCombat() && (!GetVictim() ||                                        // if IsInCombat() is true and this has no victim -                             !EnsureVictim()->GetCharmerOrOwnerPlayerOrPlayerItself() ||                // or the victim/owner/charmer is not a player -                             !EnsureVictim()->GetCharmerOrOwnerPlayerOrPlayerItself()->IsGameMaster()); // or the victim/owner/charmer is not a GameMaster +            if (m_regenTimer == 0) +            { +                bool bInCombat = IsInCombat() && (!GetVictim() ||                                        // if IsInCombat() is true and this has no victim +                                                  !EnsureVictim()->GetCharmerOrOwnerPlayerOrPlayerItself() ||                // or the victim/owner/charmer is not a player +                                                  !EnsureVictim()->GetCharmerOrOwnerPlayerOrPlayerItself()->IsGameMaster()); // or the victim/owner/charmer is not a GameMaster -            /*if (m_regenTimer <= diff) -            {*/ -            if (!IsInEvadeMode() && (!bInCombat || IsPolymorphed())) // regenerate health if not in combat or if polymorphed -                RegenerateHealth(); +                if (!IsInEvadeMode() && (!bInCombat || IsPolymorphed() || CanNotReachTarget())) // regenerate health if not in combat or if polymorphed +                    RegenerateHealth(); -            if (HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER)) -            { -                if (getPowerType() == POWER_ENERGY) -                    Regenerate(POWER_ENERGY); -                else -                    RegenerateMana(); +                if (HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER)) +                { +                    if (getPowerType() == POWER_ENERGY) +                        Regenerate(POWER_ENERGY); +                    else +                        RegenerateMana(); +                } +                m_regenTimer = CREATURE_REGEN_INTERVAL;              } -            /*if (!bIsPolymorphed) // only increase the timer if not polymorphed -                    m_regenTimer += CREATURE_REGEN_INTERVAL - diff; +            if (CanNotReachTarget() && !IsInEvadeMode() && !GetMap()->IsRaid()) +            { +                m_cannotReachTimer += diff; +                if (m_cannotReachTimer >= CREATURE_NOPATH_EVADE_TIME) +                    if (IsAIEnabled) +                        AI()->EnterEvadeMode(CreatureAI::EVADE_REASON_NO_PATH);              } -            else -                if (!bIsPolymorphed) // if polymorphed, skip the timer -                    m_regenTimer -= diff;*/ -            m_regenTimer = CREATURE_REGEN_INTERVAL;              break;          }          default: @@ -1832,7 +1831,7 @@ SpellInfo const* Creature::reachWithSpellAttack(Unit* victim)      if (!victim)          return nullptr; -    for (uint32 i=0; i < CREATURE_MAX_SPELLS; ++i) +    for (uint32 i=0; i < MAX_CREATURE_SPELLS; ++i)      {          if (!m_spells[i])              continue; @@ -1880,7 +1879,7 @@ SpellInfo const* Creature::reachWithSpellCure(Unit* victim)      if (!victim)          return nullptr; -    for (uint32 i=0; i < CREATURE_MAX_SPELLS; ++i) +    for (uint32 i=0; i < MAX_CREATURE_SPELLS; ++i)      {          if (!m_spells[i])              continue; @@ -2325,10 +2324,10 @@ uint32 Creature::GetShieldBlockValue() const                  //dunno mob block  bool Creature::HasSpell(uint32 spellID) const  {      uint8 i; -    for (i = 0; i < CREATURE_MAX_SPELLS; ++i) +    for (i = 0; i < MAX_CREATURE_SPELLS; ++i)          if (spellID == m_spells[i])              break; -    return i < CREATURE_MAX_SPELLS;                         //broke before end of iteration of known spells +    return i < MAX_CREATURE_SPELLS;                         //broke before end of iteration of known spells  }  time_t Creature::GetRespawnTimeEx() const diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 8466dad9e95..bb43bcb5ff1 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -67,12 +67,13 @@ enum CreatureFlagsExtra      CREATURE_FLAG_EXTRA_NO_SKILLGAIN | CREATURE_FLAG_EXTRA_TAUNT_DIMINISH | CREATURE_FLAG_EXTRA_ALL_DIMINISH | \      CREATURE_FLAG_EXTRA_GUARD | CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING | CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ | CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK) -#define CREATURE_REGEN_INTERVAL 2 * IN_MILLISECONDS +static const uint32 CREATURE_REGEN_INTERVAL = 2 * IN_MILLISECONDS; +static const uint32 CREATURE_NOPATH_EVADE_TIME = 5 * IN_MILLISECONDS; -#define MAX_KILL_CREDIT 2 -#define MAX_CREATURE_MODELS 4 -#define MAX_CREATURE_QUEST_ITEMS 6 -#define CREATURE_MAX_SPELLS 8 +static const uint8 MAX_KILL_CREDIT = 2; +static const uint32 MAX_CREATURE_MODELS = 4; +static const uint32 MAX_CREATURE_QUEST_ITEMS = 6; +static const uint32 MAX_CREATURE_SPELLS = 8;  // from `creature_template` table  struct TC_GAME_API CreatureTemplate @@ -117,7 +118,7 @@ struct TC_GAME_API CreatureTemplate      uint32  pickpocketLootId;      uint32  SkinLootId;      int32   resistance[MAX_SPELL_SCHOOL]; -    uint32  spells[CREATURE_MAX_SPELLS]; +    uint32  spells[MAX_CREATURE_SPELLS];      uint32  PetSpellDataId;      uint32  VehicleId;      uint32  mingold; @@ -475,6 +476,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma          uint8 getLevelForTarget(WorldObject const* target) const override; // overwrite Unit::getLevelForTarget for boss level support          bool IsInEvadeMode() const { return HasUnitState(UNIT_STATE_EVADE); } +        bool IsEvadingAttacks() const { return IsInEvadeMode() || CanNotReachTarget(); }          bool AIM_Destroy();          bool AIM_Initialize(CreatureAI* ai = NULL); @@ -567,7 +569,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma          SpellInfo const* reachWithSpellAttack(Unit* victim);          SpellInfo const* reachWithSpellCure(Unit* victim); -        uint32 m_spells[CREATURE_MAX_SPELLS]; +        uint32 m_spells[MAX_CREATURE_SPELLS];          bool CanStartAttack(Unit const* u, bool force) const;          float GetAttackDistance(Unit const* player) const; @@ -632,6 +634,15 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma          virtual uint8 GetPetAutoSpellSize() const { return MAX_SPELL_CHARM; }          virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const; +        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()); } @@ -719,6 +730,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma          bool m_AlreadyCallAssistance;          bool m_AlreadySearchedAssistance;          bool m_regenHealth; +        bool m_cannotReachTarget; +        uint32 m_cannotReachTimer;          bool m_AI_locked;          SpellSchoolMask m_meleeDamageSchoolMask; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 7f922f89572..d7e478bb4e5 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -34,7 +34,7 @@  #include "Transport.h"  GameObject::GameObject() : WorldObject(false), MapObject(), -    m_model(NULL), m_goValue(), m_AI(NULL) +    m_model(nullptr), m_goValue(), m_AI(nullptr)  {      m_objectType |= TYPEMASK_GAMEOBJECT;      m_objectTypeId = TYPEID_GAMEOBJECT; @@ -49,8 +49,8 @@ GameObject::GameObject() : WorldObject(false), MapObject(),      m_usetimes = 0;      m_spellId = 0;      m_cooldownTime = 0; -    m_goInfo = NULL; -    m_goData = NULL; +    m_goInfo = nullptr; +    m_goData = nullptr;      m_spawnId = 0;      m_rotation = 0; @@ -496,7 +496,7 @@ void GameObject::Update(uint32 diff)                          radius = goInfo->trap.diameter / 2.f;                      // Pointer to appropriate target if found any -                    Unit* target = NULL; +                    Unit* target = nullptr;                      /// @todo this hack with search required until GO casting not implemented                      if (Unit* owner = GetOwner()) @@ -511,7 +511,7 @@ void GameObject::Update(uint32 diff)                      else                      {                          // Environmental trap: Any player -                        Player* player = NULL; +                        Player* player = nullptr;                          Trinity::AnyPlayerInObjectRangeCheck checker(this, radius);                          Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(this, player, checker);                          VisitNearbyWorldObject(radius, searcher); @@ -571,8 +571,8 @@ void GameObject::Update(uint32 diff)                      GameObjectTemplate const* goInfo = GetGOInfo();                      if (goInfo->trap.type == 2 && goInfo->trap.spellId)                      { -                        /// @todo NULL target won't work for target type 1 -                        CastSpell(NULL, goInfo->trap.spellId); +                        /// @todo nullptr target won't work for target type 1 +                        CastSpell(nullptr, goInfo->trap.spellId);                          SetLootState(GO_JUST_DEACTIVATED);                      }                      else if (Unit* target = ObjectAccessor::GetUnit(*this, m_lootStateUnitGUID)) @@ -1093,7 +1093,7 @@ void GameObject::TriggeringLinkedGameObject(uint32 trapEntry, Unit* target)      float range = float(target->GetSpellMaxRangeForTarget(GetOwner(), trapSpell));      // search nearest linked GO -    GameObject* trapGO = NULL; +    GameObject* trapGO = nullptr;      {          // using original GO distance          CellCoord p(Trinity::ComputeCellCoord(GetPositionX(), GetPositionY())); @@ -1113,7 +1113,7 @@ void GameObject::TriggeringLinkedGameObject(uint32 trapEntry, Unit* target)  GameObject* GameObject::LookupFishingHoleAround(float range)  { -    GameObject* ok = NULL; +    GameObject* ok = nullptr;      CellCoord p(Trinity::ComputeCellCoord(GetPositionX(), GetPositionY()));      Cell cell(p); @@ -1136,7 +1136,7 @@ void GameObject::ResetDoorOrButton()      m_cooldownTime = 0;  } -void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = false */, Unit* user /*=NULL*/) +void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = false */, Unit* user /*=nullptr*/)  {      if (m_lootState != GO_READY)          return; @@ -1160,7 +1160,7 @@ void GameObject::SetGoArtKit(uint8 kit)  void GameObject::SetGoArtKit(uint8 artkit, GameObject* go, ObjectGuid::LowType lowguid)  { -    const GameObjectData* data = NULL; +    const GameObjectData* data = nullptr;      if (go)      {          go->SetGoArtKit(artkit); @@ -1386,7 +1386,7 @@ void GameObject::Use(Unit* user)              // cast this spell later if provided              spellId = info->goober.spellId; -            spellCaster = NULL; +            spellCaster = nullptr;              break;          } @@ -1505,7 +1505,7 @@ void GameObject::Use(Unit* user)              GameObjectTemplate const* info = GetGOInfo(); -            Player* m_ritualOwner = NULL; +            Player* m_ritualOwner = nullptr;              if (m_ritualOwnerGUID)                  m_ritualOwner = ObjectAccessor::FindPlayer(m_ritualOwnerGUID); @@ -1869,7 +1869,7 @@ bool GameObject::IsInRange(float x, float y, float z, float radius) const          && dz < info->maxZ + radius && dz > info->minZ - radius;  } -void GameObject::EventInform(uint32 eventId, WorldObject* invoker /*= NULL*/) +void GameObject::EventInform(uint32 eventId, WorldObject* invoker /*= nullptr*/)  {      if (!eventId)          return; @@ -1929,7 +1929,7 @@ void GameObject::UpdateRotationFields(float rotation2 /*=0.0f*/, float rotation3      SetFloatValue(GAMEOBJECT_PARENTROTATION+3, rotation3);  } -void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= NULL*/, uint32 spellId /*= 0*/) +void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= nullptr*/, uint32 spellId /*= 0*/)  {      if (!m_goValue.Building.MaxHealth || !change)          return; @@ -1948,7 +1948,7 @@ void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= NULL*/, u      // Set the health bar, value = 255 * healthPct;      SetGoAnimProgress(m_goValue.Building.Health * 255 / m_goValue.Building.MaxHealth); -    Player* player = attackerOrHealer ? attackerOrHealer->GetCharmerOrOwnerPlayerOrPlayerItself() : NULL; +    Player* player = attackerOrHealer ? attackerOrHealer->GetCharmerOrOwnerPlayerOrPlayerItself() : nullptr;      // dealing damage, send packet      if (player) @@ -1979,7 +1979,7 @@ void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= NULL*/, u      SetDestructibleState(newState, player, false);  } -void GameObject::SetDestructibleState(GameObjectDestructibleState state, Player* eventInvoker /*= NULL*/, bool setHealth /*= false*/) +void GameObject::SetDestructibleState(GameObjectDestructibleState state, Player* eventInvoker /*= nullptr*/, bool setHealth /*= false*/)  {      // the user calling this must know he is already operating on destructible gameobject      ASSERT(GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING); @@ -2161,14 +2161,14 @@ void GameObject::UpdateModel()  Player* GameObject::GetLootRecipient() const  {      if (!m_lootRecipient) -        return NULL; +        return nullptr;      return ObjectAccessor::FindConnectedPlayer(m_lootRecipient);  }  Group* GameObject::GetLootRecipientGroup() const  {      if (!m_lootRecipientGroup) -        return NULL; +        return nullptr;      return sGroupMgr->GetGroupByGUID(m_lootRecipientGroup);  } @@ -2176,7 +2176,7 @@ void GameObject::SetLootRecipient(Unit* unit)  {      // set the player whose group should receive the right      // to loot the creature after it dies -    // should be set to NULL after the loot disappears +    // should be set to nullptr after the loot disappears      if (!unit)      { @@ -2295,7 +2295,7 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t      data->append(fieldBuffer);  } -void GameObject::GetRespawnPosition(float &x, float &y, float &z, float* ori /* = NULL*/) const +void GameObject::GetRespawnPosition(float &x, float &y, float &z, float* ori /* = nullptr*/) const  {      if (m_spawnId)      { diff --git a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp index b44a3e7ad7b..a7b410bc04b 100644 --- a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp +++ b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp @@ -44,7 +44,7 @@ typedef std::unordered_map<uint32, EnchStoreList> EnchantmentStore;  static EnchantmentStore RandomItemEnch; -TC_GAME_API void LoadRandomEnchantmentsTable() +void LoadRandomEnchantmentsTable()  {      uint32 oldMSTime = getMSTime(); @@ -77,7 +77,7 @@ TC_GAME_API void LoadRandomEnchantmentsTable()          TC_LOG_ERROR("server.loading", ">> Loaded 0 Item Enchantment definitions. DB table `item_enchantment_template` is empty.");  } -TC_GAME_API uint32 GetItemEnchantMod(int32 entry) +uint32 GetItemEnchantMod(int32 entry)  {      if (!entry)          return 0; @@ -118,7 +118,7 @@ TC_GAME_API uint32 GetItemEnchantMod(int32 entry)      return 0;  } -TC_GAME_API uint32 GenerateEnchSuffixFactor(uint32 item_id) +uint32 GenerateEnchSuffixFactor(uint32 item_id)  {      ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(item_id); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 45952ba51ac..a2f519a681c 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1471,7 +1471,7 @@ float WorldObject::GetGridActivationRange() const  {      if (ToPlayer())      { -        if (ToPlayer()->IsOnCinematic()) +        if (ToPlayer()->GetCinematicMgr()->IsOnCinematic())              return DEFAULT_VISIBILITY_INSTANCE;          return GetMap()->GetVisibilityRange();      } @@ -1504,7 +1504,7 @@ float WorldObject::GetSightRange(const WorldObject* target) const          {              if (target && target->isActiveObject() && !target->ToPlayer())                  return MAX_VISIBILITY_DISTANCE; -            else if (ToPlayer()->IsOnCinematic()) +            else if (ToPlayer()->GetCinematicMgr()->IsOnCinematic())                  return DEFAULT_VISIBILITY_INSTANCE;              else                  return GetMap()->GetVisibilityRange(); diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index d4c8fc35451..5c8a84453c3 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -550,8 +550,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation          GameObject* FindNearestGameObject(uint32 entry, float range) const;          GameObject* FindNearestGameObjectOfType(GameobjectTypes type, float range) const; -        void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& lList, uint32 uiEntry, float fMaxSearchRange) const; -        void GetCreatureListWithEntryInGrid(std::list<Creature*>& lList, uint32 uiEntry, float fMaxSearchRange) const; +        void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& lList, uint32 uiEntry = 0, float fMaxSearchRange = 250.0f) const; +        void GetCreatureListWithEntryInGrid(std::list<Creature*>& lList, uint32 uiEntry = 0, float fMaxSearchRange = 250.0f) const;          void GetPlayerListInGrid(std::list<Player*>& lList, float fMaxSearchRange) const;          void DestroyForNearbyPlayers(); @@ -584,14 +584,6 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation          template<class NOTIFIER> void VisitNearbyGridObject(float const& radius, NOTIFIER& notifier) const { if (IsInWorld()) GetMap()->VisitGrid(GetPositionX(), GetPositionY(), radius, notifier); }          template<class NOTIFIER> void VisitNearbyWorldObject(float const& radius, NOTIFIER& notifier) const { if (IsInWorld()) GetMap()->VisitWorld(GetPositionX(), GetPositionY(), radius, notifier); } -#ifdef MAP_BASED_RAND_GEN -        int32 irand(int32 min, int32 max) const     { return int32 (GetMap()->mtRand.randInt(max - min)) + min; } -        uint32 urand(uint32 min, uint32 max) const  { return GetMap()->mtRand.randInt(max - min) + min;} -        int32 rand32() const                        { return GetMap()->mtRand.randInt();} -        double rand_norm() const                    { return GetMap()->mtRand.randExc();} -        double rand_chance() const                  { return GetMap()->mtRand.randExc(100.0);} -#endif -          uint32  LastUsedScriptID;          // Transports diff --git a/src/server/game/Entities/Player/CinematicMgr.cpp b/src/server/game/Entities/Player/CinematicMgr.cpp new file mode 100644 index 00000000000..07bf733c9ff --- /dev/null +++ b/src/server/game/Entities/Player/CinematicMgr.cpp @@ -0,0 +1,171 @@ +/* +* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> +* +* 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/>. +*/ + +#include "CinematicMgr.h" +#include "Creature.h" +#include "Player.h" +#include "TemporarySummon.h" + +CinematicMgr::CinematicMgr(Player* playerref) +{ +    player = playerref; +    m_cinematicDiff = 0; +    m_lastCinematicCheck = 0; +    m_activeCinematicCameraId = 0; +    m_cinematicCamera = nullptr; +    m_remoteSightPosition = Position(0.0f, 0.0f, 0.0f); +    m_CinematicObject = nullptr; +} + +CinematicMgr::~CinematicMgr() +{ +    if (m_cinematicCamera && m_activeCinematicCameraId) +        EndCinematic(); +} + +void CinematicMgr::BeginCinematic() +{ +    // Sanity check for active camera set +    if (m_activeCinematicCameraId == 0) +        return; + +    auto itr = sFlyByCameraStore.find(m_activeCinematicCameraId); +    if (itr != sFlyByCameraStore.end()) +    { +        // Initialize diff, and set camera +        m_cinematicDiff = 0; +        m_cinematicCamera = &itr->second; + +        auto camitr = m_cinematicCamera->begin(); +        if (camitr != m_cinematicCamera->end()) +        { +            Position pos(camitr->locations.x, camitr->locations.y, camitr->locations.z, camitr->locations.w); +            if (!pos.IsPositionValid()) +                return; + +            player->GetMap()->LoadGrid(camitr->locations.x, camitr->locations.y); +            m_CinematicObject = player->SummonCreature(VISUAL_WAYPOINT, pos.m_positionX, pos.m_positionY, pos.m_positionZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 5 * MINUTE * IN_MILLISECONDS); +            if (m_CinematicObject) +            { +                m_CinematicObject->setActive(true); +                player->SetViewpoint(m_CinematicObject, true); +            } + +            // Get cinematic length +            FlyByCameraCollection::const_reverse_iterator camrevitr = m_cinematicCamera->rbegin(); +            if (camrevitr != m_cinematicCamera->rend()) +                m_cinematicLength = camrevitr->timeStamp; +        } +    } +} + +void CinematicMgr::EndCinematic() +{ +    if (m_activeCinematicCameraId == 0) +        return; + +    m_cinematicDiff = 0; +    m_cinematicCamera = nullptr; +    m_activeCinematicCameraId = 0; +    if (m_CinematicObject) +    { +        if (WorldObject* vpObject = player->GetViewpoint()) +            if (vpObject == m_CinematicObject) +                player->SetViewpoint(m_CinematicObject, false); + +        m_CinematicObject->AddObjectToRemoveList(); +    } +} + +void CinematicMgr::UpdateCinematicLocation(uint32 /*diff*/) +{ +    if (m_activeCinematicCameraId == 0 || !m_cinematicCamera || m_cinematicCamera->size() == 0) +        return; + +    Position lastPosition; +    uint32 lastTimestamp = 0; +    Position nextPosition; +    uint32 nextTimestamp = 0; + +    // Obtain direction of travel +    for (FlyByCamera cam : *m_cinematicCamera) +    { +        if (cam.timeStamp > m_cinematicDiff) +        { +            nextPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w); +            nextTimestamp = cam.timeStamp; +            break; +        } +        lastPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w); +        lastTimestamp = cam.timeStamp; +    } +    float angle = lastPosition.GetAngle(&nextPosition); +    angle -= lastPosition.GetOrientation(); +    if (angle < 0) +        angle += 2 * float(M_PI); + +    // Look for position around 2 second ahead of us. +    int32 workDiff = m_cinematicDiff; + +    // Modify result based on camera direction (Humans for example, have the camera point behind) +    workDiff += static_cast<int32>(float(CINEMATIC_LOOKAHEAD) * cos(angle)); + +    // Get an iterator to the last entry in the cameras, to make sure we don't go beyond the end +    FlyByCameraCollection::const_reverse_iterator endItr = m_cinematicCamera->rbegin(); +    if (endItr != m_cinematicCamera->rend() && workDiff > static_cast<int32>(endItr->timeStamp)) +        workDiff = endItr->timeStamp; + +    // Never try to go back in time before the start of cinematic! +    if (workDiff < 0) +        workDiff = m_cinematicDiff; + +    // Obtain the previous and next waypoint based on timestamp +    for (FlyByCamera cam : *m_cinematicCamera) +    { +        if (static_cast<int32>(cam.timeStamp) >= workDiff) +        { +            nextPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w); +            nextTimestamp = cam.timeStamp; +            break; +        } +        lastPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w); +        lastTimestamp = cam.timeStamp; +    } + +    // Never try to go beyond the end of the cinematic +    if (workDiff > static_cast<int32>(nextTimestamp)) +        workDiff = static_cast<int32>(nextTimestamp); + +    // Interpolate the position for this moment in time (or the adjusted moment in time) +    uint32 timeDiff = nextTimestamp - lastTimestamp; +    uint32 interDiff = workDiff - lastTimestamp; +    float xDiff = nextPosition.m_positionX - lastPosition.m_positionX; +    float yDiff = nextPosition.m_positionY - lastPosition.m_positionY; +    float zDiff = nextPosition.m_positionZ - lastPosition.m_positionZ; +    Position interPosition(lastPosition.m_positionX + (xDiff * (float(interDiff) / float(timeDiff))), lastPosition.m_positionY + +        (yDiff * (float(interDiff) / float(timeDiff))), lastPosition.m_positionZ + (zDiff * (float(interDiff) / float(timeDiff)))); + +    // Advance (at speed) to this position. The remote sight object is used  +    // to send update information to player in cinematic +    if (m_CinematicObject && interPosition.IsPositionValid()) +        m_CinematicObject->MonsterMoveWithSpeed(interPosition.m_positionX, interPosition.m_positionY, interPosition.m_positionZ, 500.0f, false, true); + +    // If we never received an end packet 10 seconds after the final timestamp then force an end +    if (m_cinematicDiff > m_cinematicLength + 10 * IN_MILLISECONDS) +        EndCinematic(); +} diff --git a/src/server/game/Entities/Player/CinematicMgr.h b/src/server/game/Entities/Player/CinematicMgr.h new file mode 100644 index 00000000000..ab067afa042 --- /dev/null +++ b/src/server/game/Entities/Player/CinematicMgr.h @@ -0,0 +1,60 @@ +/* +* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> +* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> +* +* 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 CinematicMgr_h__ +#define CinematicMgr_h__ + +#include "Define.h" +#include "Object.h" +#include "M2Stores.h" + +#define CINEMATIC_LOOKAHEAD (2 * IN_MILLISECONDS) +#define CINEMATIC_UPDATEDIFF 500 + +class Player; + +class TC_GAME_API CinematicMgr +{ +    friend class Player; +public: +    explicit CinematicMgr(Player* playerref); +    ~CinematicMgr(); + +    // Cinematic camera data and remote sight functions +    uint32 GetActiveCinematicCamera() const { return m_activeCinematicCameraId; } +    void SetActiveCinematicCamera(uint32 cinematicCameraId = 0) { m_activeCinematicCameraId = cinematicCameraId; } +    bool IsOnCinematic() const { return (m_cinematicCamera != nullptr); } +    void BeginCinematic(); +    void EndCinematic(); +    void UpdateCinematicLocation(uint32 diff); + +private: +    // Remote location information +    Player*     player; + +protected: +    uint32      m_cinematicDiff; +    uint32      m_lastCinematicCheck; +    uint32      m_activeCinematicCameraId; +    uint32      m_cinematicLength; +    FlyByCameraCollection* m_cinematicCamera; +    Position    m_remoteSightPosition; +    TempSummon*   m_CinematicObject; +}; + +#endif
\ No newline at end of file diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 503b6277963..9ed101bf52e 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -96,9 +96,6 @@  #define SKILL_PERM_BONUS(x)    int16(PAIR32_HIPART(x))  #define MAKE_SKILL_BONUS(t, p) MAKE_PAIR32(t, p) -#define CINEMATIC_LOOKAHEAD (2 * IN_MILLISECONDS) -#define CINEMATIC_UPDATEDIFF 500 -  enum CharacterFlags  {      CHARACTER_FLAG_NONE                 = 0x00000000, @@ -477,21 +474,11 @@ Player::Player(WorldSession* session): Unit(true)      // Player summoning      m_summon_expire = 0; -    m_summon_mapid = 0; -    m_summon_x = 0.0f; -    m_summon_y = 0.0f; -    m_summon_z = 0.0f;      m_mover = this;      m_movedPlayer = this;      m_seer = this; -    m_recallMap = 0; -    m_recallX = 0; -    m_recallY = 0; -    m_recallZ = 0; -    m_recallO = 0; -      m_homebindMapId = 0;      m_homebindAreaId = 0;      m_homebindX = 0; @@ -539,12 +526,7 @@ Player::Player(WorldSession* session): Unit(true)      healthBeforeDuel = 0;      manaBeforeDuel = 0; -    m_cinematicDiff = 0; -    m_lastCinematicCheck = 0; -    m_activeCinematicCameraId = 0; -    m_cinematicCamera = nullptr; -    m_remoteSightPosition = Position(0.0f, 0.0f, 0.0f); -    m_CinematicObject = nullptr; +    _cinematicMgr = new CinematicMgr(this);      m_achievementMgr = new AchievementMgr(this);      m_reputationMgr = new ReputationMgr(this); @@ -1236,11 +1218,11 @@ void Player::Update(uint32 p_time)      }      // Update cinematic location, if 500ms have passed and we're doing a cinematic now. -    m_cinematicDiff += p_time; -    if (m_cinematicCamera && m_activeCinematicCameraId && GetMSTimeDiffToNow(m_lastCinematicCheck) > CINEMATIC_UPDATEDIFF) +    _cinematicMgr->m_cinematicDiff += p_time; +    if (_cinematicMgr->m_cinematicCamera && _cinematicMgr->m_activeCinematicCameraId && GetMSTimeDiffToNow(_cinematicMgr->m_lastCinematicCheck) > CINEMATIC_UPDATEDIFF)      { -        m_lastCinematicCheck = getMSTime(); -        UpdateCinematicLocation(p_time); +        _cinematicMgr->m_lastCinematicCheck = getMSTime(); +        _cinematicMgr->UpdateCinematicLocation(p_time);      }      //used to implement delayed far teleports @@ -6374,15 +6356,6 @@ bool Player::UpdatePosition(float x, float y, float z, float orientation, bool t      return true;  } -void Player::SaveRecallPosition() -{ -    m_recallMap = GetMapId(); -    m_recallX = GetPositionX(); -    m_recallY = GetPositionY(); -    m_recallZ = GetPositionZ(); -    m_recallO = GetOrientation(); -} -  void Player::SendMessageToSetInRange(WorldPacket* data, float dist, bool self)  {      if (self) @@ -6417,13 +6390,13 @@ void Player::SendDirectMessage(WorldPacket const* data) const      m_session->SendPacket(data);  } -void Player::SendCinematicStart(uint32 CinematicSequenceId) +void Player::SendCinematicStart(uint32 CinematicSequenceId) const  {      WorldPacket data(SMSG_TRIGGER_CINEMATIC, 4);      data << uint32(CinematicSequenceId);      SendDirectMessage(&data); -    if (const CinematicSequencesEntry* sequence = sCinematicSequencesStore.LookupEntry(CinematicSequenceId)) -        SetActiveCinematicCamera(sequence->cinematicCamera); +    if (CinematicSequencesEntry const* sequence = sCinematicSequencesStore.LookupEntry(CinematicSequenceId)) +        _cinematicMgr->SetActiveCinematicCamera(sequence->cinematicCamera);  }  void Player::SendMovieStart(uint32 MovieId) const @@ -20535,7 +20508,7 @@ void Player::VehicleSpellInitialize()      data << uint8(0);                                       // Command State      data << uint16(0x800);                                  // DisableActions (set for all vehicles) -    for (uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) +    for (uint32 i = 0; i < MAX_CREATURE_SPELLS; ++i)      {          uint32 spellId = vehicle->m_spells[i];          SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); @@ -20559,7 +20532,7 @@ void Player::VehicleSpellInitialize()          data << uint32(MAKE_UNIT_ACTION_BUTTON(spellId, i+8));      } -    for (uint32 i = CREATURE_MAX_SPELLS; i < MAX_SPELL_CONTROL_BAR; ++i) +    for (uint32 i = MAX_CREATURE_SPELLS; i < MAX_SPELL_CONTROL_BAR; ++i)          data << uint32(0);      data << uint8(0); // Auras? @@ -23209,13 +23182,32 @@ void Player::UpdateForQuestWorldObjects()      GetSession()->SendPacket(&packet);  } -void Player::SetSummonPoint(uint32 mapid, float x, float y, float z) +bool Player::HasSummonPending() const +{ +    return m_summon_expire >= time(nullptr); +} + +void Player::SendSummonRequestFrom(Unit* summoner)  { +    if (!summoner) +        return; + +    // Player already has active summon request +    if (HasSummonPending()) +        return; + +    // Evil Twin (ignore player summon, but hide this for summoner) +    if (HasAura(23445)) +        return; +      m_summon_expire = time(nullptr) + MAX_PLAYER_SUMMON_DELAY; -    m_summon_mapid = mapid; -    m_summon_x = x; -    m_summon_y = y; -    m_summon_z = z; +    m_summon_location.WorldRelocate(*summoner); + +    WorldPacket data(SMSG_SUMMON_REQUEST, 8 + 4 + 4); +    data << uint64(summoner->GetGUID());                     // summoner guid +    data << uint32(summoner->GetZoneId());                   // summoner zone +    data << uint32(MAX_PLAYER_SUMMON_DELAY*IN_MILLISECONDS); // auto decline after msecs +    GetSession()->SendPacket(&data);  }  void Player::SummonIfPossible(bool agree) @@ -23246,7 +23238,7 @@ void Player::SummonIfPossible(bool agree)      UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS, 1); -    TeleportTo(m_summon_mapid, m_summon_x, m_summon_y, m_summon_z, GetOrientation()); +    TeleportTo(m_summon_location);  }  void Player::RemoveItemDurations(Item* item) @@ -26243,125 +26235,6 @@ float Player::GetCollisionHeight(bool mounted) const      }  } -void Player::BeginCinematic() -{ -    // Sanity check for active camera set -    if (m_activeCinematicCameraId == 0) -        return; - -    auto itr = sFlyByCameraStore.find(m_activeCinematicCameraId); -    if (itr != sFlyByCameraStore.end()) -    { -        // Initialize diff, and set camera -        m_cinematicDiff = 0; -        m_cinematicCamera = &itr->second; - -        auto camitr = m_cinematicCamera->begin(); -        if (camitr != m_cinematicCamera->end()) -        { -            Position pos(camitr->locations.x, camitr->locations.y, camitr->locations.z, camitr->locations.w); -            if (!pos.IsPositionValid()) -                return; - -            m_mapRef->LoadGrid(camitr->locations.x, camitr->locations.y); -            m_CinematicObject = SummonCreature(VISUAL_WAYPOINT, pos.m_positionX, pos.m_positionY, pos.m_positionZ, 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 120000); -            if (m_CinematicObject) -            { -                m_CinematicObject->setActive(true); -                SetViewpoint(m_CinematicObject, true); -            } -        } -    } -} - -void Player::EndCinematic() -{ -    m_cinematicDiff = 0; -    m_cinematicCamera = nullptr; -    m_activeCinematicCameraId = 0; -    if (m_CinematicObject) -    { -        if (m_seer && m_seer == m_CinematicObject) -            SetViewpoint(m_CinematicObject, false); -        m_CinematicObject->AddObjectToRemoveList(); -    } -} - -void Player::UpdateCinematicLocation(uint32 /*diff*/) -{ -    Position lastPosition; -    uint32 lastTimestamp = 0; -    Position nextPosition; -    uint32 nextTimestamp = 0; - -    if (m_cinematicCamera->size() == 0) -        return; - -    // Obtain direction of travel -    for (FlyByCamera cam : *m_cinematicCamera) -    { -        if (cam.timeStamp > m_cinematicDiff) -        { -            nextPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w); -            nextTimestamp = cam.timeStamp; -            break; -        } -        lastPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w); -        lastTimestamp = cam.timeStamp; -    } -    float angle = lastPosition.GetAngle(&nextPosition); -    angle -= lastPosition.GetOrientation(); -    if (angle < 0) -        angle += 2 * float(M_PI); - -    // Look for position around 2 second ahead of us. -    int32 workDiff = m_cinematicDiff; - -    // Modify result based on camera direction (Humans for example, have the camera point behind) -    workDiff += static_cast<int32>(float(CINEMATIC_LOOKAHEAD) * cos(angle)); - -    // Get an iterator to the last entry in the cameras, to make sure we don't go beyond the end -    FlyByCameraCollection::const_reverse_iterator endItr = m_cinematicCamera->rbegin(); -    if (endItr != m_cinematicCamera->rend() && workDiff > static_cast<int32>(endItr->timeStamp)) -        workDiff = endItr->timeStamp; - -    // Never try to go back in time before the start of cinematic! -    if (workDiff < 0) -        workDiff = m_cinematicDiff; - -    // Obtain the previous and next waypoint based on timestamp -    for (FlyByCamera cam : *m_cinematicCamera) -    { -        if (static_cast<int32>(cam.timeStamp) >= workDiff) -        { -            nextPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w); -            nextTimestamp = cam.timeStamp; -            break; -        } -        lastPosition = Position(cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w); -        lastTimestamp = cam.timeStamp; -    } - -    // Never try to go beyond the end of the cinematic -    if (workDiff > static_cast<int32>(nextTimestamp)) -        workDiff = static_cast<int32>(nextTimestamp); - -    // Interpolate the position for this moment in time (or the adjusted moment in time) -    uint32 timeDiff = nextTimestamp - lastTimestamp; -    uint32 interDiff = workDiff - lastTimestamp; -    float xDiff = nextPosition.m_positionX - lastPosition.m_positionX; -    float yDiff = nextPosition.m_positionY - lastPosition.m_positionY; -    float zDiff = nextPosition.m_positionZ - lastPosition.m_positionZ; -    Position interPosition(lastPosition.m_positionX + (xDiff * (float(interDiff)/float(timeDiff))), lastPosition.m_positionY +  -                                                      (yDiff * (float(interDiff) / float(timeDiff))), lastPosition.m_positionZ + (zDiff * (float(interDiff) / float(timeDiff)))); -     -    // Advance (at speed) to this position. The remote sight object is used  -    // to send update information to player in cinematic -    if (m_CinematicObject && interPosition.IsPositionValid()) -        m_CinematicObject->MonsterMoveWithSpeed(interPosition.m_positionX, interPosition.m_positionY, interPosition.m_positionZ, 200.0f, false, true); -} - -  std::string Player::GetMapAreaAndZoneString() const  {      uint32 areaId = GetAreaId(); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 51443ce8939..372a49b4f9d 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -30,6 +30,7 @@  #include "SpellHistory.h"  #include "Unit.h"  #include "TradeData.h" +#include "CinematicMgr.h"  #include <limits>  #include <string> @@ -1026,6 +1027,7 @@ struct ResurrectionData  class TC_GAME_API Player : public Unit, public GridObject<Player>  {      friend class WorldSession; +    friend class CinematicMgr;      friend void Item::AddToUpdateQueueOf(Player* player);      friend void Item::RemoveFromUpdateQueueOf(Player* player);      public: @@ -1050,7 +1052,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          bool TeleportTo(WorldLocation const &loc, uint32 options = 0);          bool TeleportToBGEntryPoint(); -        void SetSummonPoint(uint32 mapid, float x, float y, float z); +        bool HasSummonPending() const; +        void SendSummonRequestFrom(Unit* summoner);          void SummonIfPossible(bool agree);          bool Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo); @@ -1273,6 +1276,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          TradeData* GetTradeData() const { return m_trade; }          void TradeCancel(bool sendback); +        CinematicMgr* GetCinematicMgr() const { return _cinematicMgr; } +          void UpdateEnchantTime(uint32 time);          void UpdateSoulboundTradeItems();          void AddTradeableItem(Item* item); @@ -2077,13 +2082,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          uint32 GetSaveTimer() const { return m_nextSave; }          void   SetSaveTimer(uint32 timer) { m_nextSave = timer; } -        // Recall position -        uint32 m_recallMap; -        float  m_recallX; -        float  m_recallY; -        float  m_recallZ; -        float  m_recallO; -        void   SaveRecallPosition(); +        void SaveRecallPosition() { m_recall_location.WorldRelocate(*this); } +        void Recall() { TeleportTo(m_recall_location); }          void SetHomebind(WorldLocation const& loc, uint32 areaId); @@ -2133,7 +2133,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          void ResummonPetTemporaryUnSummonedIfAny();          bool IsPetNeedBeTemporaryUnsummoned() const; -        void SendCinematicStart(uint32 CinematicSequenceId); +        void SendCinematicStart(uint32 CinematicSequenceId) const;          void SendMovieStart(uint32 MovieId) const;          uint32 DoRandomRoll(uint32 minimum, uint32 maximum); @@ -2271,17 +2271,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          std::string GetMapAreaAndZoneString() const;          std::string GetCoordsMapAreaAndZoneString() const; -        // Cinematic camera data and remote sight functions -        uint32 GetActiveCinematicCamera() const { return m_activeCinematicCameraId; } -        void SetActiveCinematicCamera(uint32 cinematicCameraId = 0) { m_activeCinematicCameraId = cinematicCameraId; } -        bool IsOnCinematic() const { return (m_cinematicCamera != nullptr); } -        void BeginCinematic(); -        void EndCinematic(); -        void UpdateCinematicLocation(uint32 diff); - -        std::string GetMapAreaAndZoneString(); -        std::string GetCoordsMapAreaAndZoneString(); -      protected:          // Gamemaster whisper whitelist          GuidList WhisperList; @@ -2516,10 +2505,10 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          // Player summoning          time_t m_summon_expire; -        uint32 m_summon_mapid; -        float  m_summon_x; -        float  m_summon_y; -        float  m_summon_z; +        WorldLocation m_summon_location; + +        // Recall position +        WorldLocation m_recall_location;          DeclinedName *m_declinedname;          Runes *m_runes; @@ -2541,6 +2530,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          Item* _StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool update);          Item* _LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, Field* fields); +        CinematicMgr* _cinematicMgr; +          GuidSet m_refundableItems;          void SendRefundInfo(Item* item);          void RefundItem(Item* item); @@ -2607,14 +2598,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          uint32 manaBeforeDuel;          WorldLocation _corpseLocation; - -        // Remote location information -        uint32 m_cinematicDiff; -        uint32 m_lastCinematicCheck; -        uint32 m_activeCinematicCameraId; -        FlyByCameraCollection* m_cinematicCamera; -        Position m_remoteSightPosition; -        Creature* m_CinematicObject;  };  TC_GAME_API void AddItemsSetItem(Player* player, Item* item); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 9ec55343e7d..0e9aa4395a3 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -578,7 +578,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons  void Unit::DealDamageMods(Unit* victim, uint32 &damage, uint32* absorb)  { -    if (!victim || !victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode())) +    if (!victim || !victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))      {          if (absorb)              *absorb += damage; @@ -1120,7 +1120,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss)      if (!victim)          return; -    if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode())) +    if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))          return;      SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(damageInfo->SpellID); @@ -1346,7 +1346,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)  {      Unit* victim = damageInfo->target; -    if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode())) +    if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))          return;      // Hmmmm dont like this emotes client must by self do all animations @@ -2044,7 +2044,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* victim, WeaponAttackTy  MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const  { -    if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()) +    if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks())          return MELEE_HIT_EVADE;      int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(victim); @@ -2656,7 +2656,7 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, boo          return SPELL_MISS_NONE;      // Return evade for units in evade mode -    if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()) +    if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks())          return SPELL_MISS_EVADE;      // Try victim reflect spell @@ -7868,6 +7868,10 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg                              RemoveAurasDueToSpell(50240);                          break;                      } +                    // Battle Experience +                    // already handled in gunship battle script +                    case 71201: +                        return false;                  }                  break;              case SPELLFAMILY_MAGE: @@ -9009,7 +9013,7 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)      }      else      { -        if (victim->ToCreature()->IsInEvadeMode()) +        if (victim->ToCreature()->IsEvadingAttacks())              return false;      } @@ -11944,6 +11948,7 @@ void Unit::ClearInCombat()          ToPlayer()->UpdatePotionCooldown();      RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT); +    RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_LEAVE_COMBAT);  }  bool Unit::isTargetableForAttack(bool checkFakeDeath) const @@ -12521,7 +12526,7 @@ void Unit::SetSpeedRate(UnitMoveType mtype, float rate)          WorldPacket self;          self.Initialize(moveTypeToOpcode[mtype][1], mtype != MOVE_RUN ? 8 + 4 + 4 : 8 + 4 + 1 + 4);          self << GetPackGUID(); -        self << (uint32)0;                                  // Movement counter. Unimplemented at the moment! NUM_PMOVE_EVTS = 0x39Z.  +        self << (uint32)0;                                  // Movement counter. Unimplemented at the moment! NUM_PMOVE_EVTS = 0x39Z.          if (mtype == MOVE_RUN)              self << uint8(1);                               // unknown byte added in 2.1.0          self << float(GetSpeed(mtype)); @@ -13721,6 +13726,9 @@ void Unit::UpdateCharmAI()                      delete i_AI;                      i_AI = i_disabledAI;                      i_disabledAI = nullptr; + +                    if (GetTypeId() == TYPEID_UNIT) +                        ToCreature()->AI()->OnCharmed(false);                  }              }              else @@ -13868,7 +13876,7 @@ void CharmInfo::InitPossessCreateSpells()                  break;          } -        for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i) +        for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)          {              uint32 spellId = _unit->ToCreature()->m_spells[i];              SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); @@ -17666,7 +17674,7 @@ void Unit::SetFacingToObject(WorldObject const* object)      /// @todo figure out under what conditions creature will move towards object instead of facing it where it currently is.      Movement::MoveSplineInit init(this); -    init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset()); +    init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset(), false);      init.SetFacing(GetAngle(object));   // when on transport, GetAngle will still return global coordinates (and angle) that needs transforming      init.Launch();  } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 47193cd0c45..b1571e4379f 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -76,6 +76,7 @@ enum SpellAuraInterruptFlags      AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT    = 0x00800000,   // 23   removed by entering pvp combat      AURA_INTERRUPT_FLAG_DIRECT_DAMAGE       = 0x01000000,   // 24   removed by any direct damage      AURA_INTERRUPT_FLAG_LANDING             = 0x02000000,   // 25   removed by hitting the ground +    AURA_INTERRUPT_FLAG_LEAVE_COMBAT        = 0x80000000,   // 31   removed by leaving combat      AURA_INTERRUPT_FLAG_NOT_VICTIM = (AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE | AURA_INTERRUPT_FLAG_DIRECT_DAMAGE)  }; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 3efeb1ca273..fc0abf5a8c7 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -487,7 +487,7 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields)      for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)          creatureTemplate.resistance[i] = fields[42 + i - 1].GetInt16(); -    for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i) +    for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)          creatureTemplate.spells[i] = fields[48 + i].GetUInt32();      creatureTemplate.PetSpellDataId = fields[56].GetUInt32(); @@ -833,7 +833,7 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)      if (!displayScaleEntry)          TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) does not have any existing display id in Modelid1/Modelid2/Modelid3/Modelid4.", cInfo->Entry); -    for (int k = 0; k < MAX_KILL_CREDIT; ++k) +    for (uint8 k = 0; k < MAX_KILL_CREDIT; ++k)      {          if (cInfo->KillCredit[k])          { @@ -920,7 +920,7 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)              TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has non-existing PetSpellDataId (%u).", cInfo->Entry, cInfo->PetSpellDataId);      } -    for (uint8 j = 0; j < CREATURE_MAX_SPELLS; ++j) +    for (uint8 j = 0; j < MAX_CREATURE_SPELLS; ++j)      {          if (cInfo->spells[j] && !sSpellMgr->GetSpellInfo(cInfo->spells[j]))          { diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 84aa29f96b7..1d2b0bd33cf 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -1237,7 +1237,7 @@ namespace Trinity          AllGameObjectsWithEntryInRange(const WorldObject* object, uint32 entry, float maxRange) : m_pObject(object), m_uiEntry(entry), m_fRange(maxRange) { }          bool operator() (GameObject* go)          { -            if (go->GetEntry() == m_uiEntry && m_pObject->IsWithinDist(go, m_fRange, false)) +            if ((!m_uiEntry || go->GetEntry() == m_uiEntry) && m_pObject->IsWithinDist(go, m_fRange, false))                  return true;              return false; @@ -1254,7 +1254,7 @@ namespace Trinity              AllCreaturesOfEntryInRange(const WorldObject* object, uint32 entry, float maxRange) : m_pObject(object), m_uiEntry(entry), m_fRange(maxRange) { }              bool operator() (Unit* unit)              { -                if (unit->GetEntry() == m_uiEntry && m_pObject->IsWithinDist(unit, m_fRange, false)) +                if ((!m_uiEntry || unit->GetEntry() == m_uiEntry) && m_pObject->IsWithinDist(unit, m_fRange, false))                      return true;                  return false; diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 467d3730ab2..52b36d80202 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -884,15 +884,15 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recvData)                          player->SendTransferAborted(entry->MapID, TRANSFER_ABORT_DIFFICULTY, player->GetDifficulty(entry->IsRaid()));                      break;                  case Map::CANNOT_ENTER_NOT_IN_RAID: -                    if (MapEntry const* entry = sMapStore.LookupEntry(at->target_mapId)) -                    { -                        char const* mapName = entry->name[player->GetSession()->GetSessionDbcLocale()]; -                        TC_LOG_DEBUG("maps", "MAP: Player '%s' must be in a raid group to enter instance '%s'", player->GetName().c_str(), mapName); -                        // probably there must be special opcode, because client has this string constant in GlobalStrings.lua -                        player->GetSession()->SendAreaTriggerMessage(player->GetSession()->GetTrinityString(LANG_INSTANCE_RAID_GROUP_ONLY), mapName); -                    } +                { +                    WorldPacket data(SMSG_RAID_GROUP_ONLY, 4 + 4); +                    data << uint32(0); +                    data << uint32(2); // You must be in a raid group to enter this instance. +                    player->GetSession()->SendPacket(&data); +                    TC_LOG_DEBUG("maps", "MAP: Player '%s' must be in a raid group to enter instance map %d", player->GetName().c_str(), at->target_mapId);                      reviveAtTrigger = true;                      break; +                }                  case Map::CANNOT_ENTER_CORPSE_IN_DIFFERENT_INSTANCE:                  {                      WorldPacket data(SMSG_CORPSE_NOT_IN_INSTANCE); @@ -1057,13 +1057,13 @@ void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recvData)  void WorldSession::HandleCompleteCinematic(WorldPacket& /*recvData*/)  {      // If player has sight bound to visual waypoint NPC we should remove it -    GetPlayer()->EndCinematic(); +    GetPlayer()->GetCinematicMgr()->EndCinematic();  }  void WorldSession::HandleNextCinematicCamera(WorldPacket& /*recvData*/)  {      // Sent by client when cinematic actually begun. So we begin the server side process -    GetPlayer()->BeginCinematic(); +    GetPlayer()->GetCinematicMgr()->BeginCinematic();  }  void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket& recvData) diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp index ebc9ebde994..1eee9e0d9fe 100644 --- a/src/server/game/Handlers/QueryHandler.cpp +++ b/src/server/game/Handlers/QueryHandler.cpp @@ -133,10 +133,10 @@ void WorldSession::HandleCreatureQueryOpcode(WorldPacket& recvData)          CreatureQuestItemList const* items = sObjectMgr->GetCreatureQuestItemList(entry);          if (items) -            for (size_t i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i) +            for (uint32 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i)                  data << (i < items->size() ? uint32((*items)[i]) : uint32(0));          else -            for (size_t i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i) +            for (uint32 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i)                  data << uint32(0);          data << uint32(ci->movementId);                     // CreatureMovementInfo.dbc diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index ca63137ac93..d6af5d81432 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1063,7 +1063,7 @@ enum TrinityStrings      LANG_COMMAND_NO_FROZEN_PLAYERS      = 5004,      LANG_COMMAND_LIST_FREEZE            = 5005,      LANG_COMMAND_PERMA_FROZEN_PLAYER    = 5006, -    LANG_INSTANCE_RAID_GROUP_ONLY       = 5007, +    //                                  = 5007, unused      LANG_INSTANCE_CLOSED                = 5008,      LANG_COMMAND_PLAYED_TO_ALL          = 5009,      LANG_NPCINFO_LINKGUID               = 5010, @@ -1212,6 +1212,8 @@ enum TrinityStrings      LANG_CREATURE_NO_INTERIOR_POINT_FOUND         = 11011,      LANG_CREATURE_MOVEMENT_NOT_BOUNDED            = 11012,      LANG_CREATURE_MOVEMENT_MAYBE_UNBOUNDED        = 11013, -    LANG_INSTANCE_BIND_MISMATCH                   = 11014 +    LANG_INSTANCE_BIND_MISMATCH                   = 11014, +    LANG_CREATURE_NOT_AI_ENABLED                  = 11015, +    LANG_SELECT_PLAYER_OR_PET                     = 11016,  };  #endif diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp index 108276c951a..6f6a8037d47 100755 --- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp @@ -23,11 +23,6 @@  #include "MoveSpline.h"  #include "Player.h" -#ifdef MAP_BASED_RAND_GEN -#define rand_norm() unit.rand_norm() -#define urand(a, b) unit.urand(a, b) -#endif -  template<class T>  void ConfusedMovementGenerator<T>::DoInitialize(T* unit)  { diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp index 2e013c44ae8..421678ded17 100644 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp @@ -26,10 +26,6 @@  #define RUNNING_CHANCE_RANDOMMV 20                                  //will be "1 / RUNNING_CHANCE_RANDOMMV" -#ifdef MAP_BASED_RAND_GEN -#define rand_norm() creature.rand_norm() -#endif -  template<>  void RandomMovementGenerator<Creature>::_setRandomLocation(Creature* creature)  { diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index 533b087c7a1..3fd3b702ba5 100644 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -40,7 +40,10 @@ void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T* owner, bool up          return;      if (owner->GetTypeId() == TYPEID_UNIT && !i_target->isInAccessiblePlaceFor(owner->ToCreature())) +    { +        owner->ToCreature()->SetCannotReachTarget(true);          return; +    }      if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsFocusing(nullptr, true))          return; @@ -105,8 +108,10 @@ void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T* owner, bool up      bool result = i_path->CalculatePath(x, y, z, forceDest);      if (!result || (i_path->GetPathType() & PATHFIND_NOPATH))      { -        // Cant reach target +        // can't reach target          i_recalculateTravel = true; +        if (owner->GetTypeId() == TYPEID_UNIT) +            owner->ToCreature()->SetCannotReachTarget(true);          return;      } @@ -114,6 +119,8 @@ void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T* owner, bool up      i_targetReached = false;      i_recalculateTravel = false;      owner->AddUnitState(UNIT_STATE_CHASE); +    if (owner->GetTypeId() == TYPEID_UNIT) +        owner->ToCreature()->SetCannotReachTarget(false);      Movement::MoveSplineInit init(owner);      init.MovebyPath(i_path->GetPath()); @@ -204,6 +211,8 @@ void ChaseMovementGenerator<T>::_reachTarget(T* owner)  {      if (owner->IsWithinMeleeRange(this->i_target.getTarget()))          owner->Attack(this->i_target.getTarget(), true); +    if (owner->GetTypeId() == TYPEID_UNIT) +        owner->ToCreature()->SetCannotReachTarget(false);  }  template<> diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index 48d29b3259b..dd1cf494325 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -213,7 +213,7 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 di              creature->SetHomePosition(creature->GetPosition());          if (creature->IsStopped()) -            Stop(STOP_TIME_FOR_PLAYER); +            Stop(sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER));          else if (creature->movespline->Finalized())          {              OnArrived(creature); diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h index 1dd4611d53b..72309822dab 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h @@ -28,9 +28,9 @@  #include "MovementGenerator.h"  #include "WaypointManager.h"  #include "Player.h" +#include "World.h"  #define FLIGHT_TRAVEL_UPDATE  100 -#define STOP_TIME_FOR_PLAYER  3 * MINUTE * IN_MILLISECONDS           // 3 Minutes  #define TIMEDIFF_NEXT_WP      250  template<class T, class P> diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index ca1cd71363e..ac440da3f24 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -368,6 +368,8 @@ class CreatureGameObjectScriptRegistrySwapHooks      // Hook which is called before a creature is swapped      static void UnloadStage1(Creature* creature)      { +        creature->m_Events.KillAllEvents(true); +          if (creature->IsCharmed())              creature->RemoveCharmedBy(nullptr); diff --git a/src/server/game/Server/Protocol/PacketLog.cpp b/src/server/game/Server/Protocol/PacketLog.cpp index 11a02828998..114b2ae0ecc 100644 --- a/src/server/game/Server/Protocol/PacketLog.cpp +++ b/src/server/game/Server/Protocol/PacketLog.cpp @@ -45,7 +45,7 @@ struct PacketHeader          uint32 SocketPort;      }; -    char Direction[4]; +    uint32 Direction;      uint32 ConnectionId;      uint32 ArrivalTicks;      uint32 OptionalDataSize; @@ -109,7 +109,7 @@ void PacketLog::LogPacket(WorldPacket const& packet, Direction direction, boost:      std::lock_guard<std::mutex> lock(_logPacketLock);      PacketHeader header; -    *reinterpret_cast<uint32*>(header.Direction) = direction == CLIENT_TO_SERVER ? 0x47534d43 : 0x47534d53; +    header.Direction = direction == CLIENT_TO_SERVER ? 0x47534d43 : 0x47534d53;      header.ConnectionId = 0;      header.ArrivalTicks = getMSTime(); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index a8adda3ad58..ffe79293430 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -4686,7 +4686,7 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool                  case 71563:                      if (Aura* newAura = target->AddAura(71564, target))                          newAura->SetStackAmount(newAura->GetSpellInfo()->StackAmount); -                        break; +                    break;              }          }          // AT REMOVE @@ -5979,9 +5979,6 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c      caster->SendSpellNonMeleeDamageLog(target, GetId(), damage, GetSpellInfo()->GetSchoolMask(), absorb, resist, false, 0, crit); -    if (target->GetHealth() < damage) -        damage = uint32(target->GetHealth()); -      // Set trigger flag      uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;      uint32 procVictim   = PROC_FLAG_TAKEN_PERIODIC; diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 1ca5df6b327..74a94a63594 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -789,7 +789,7 @@ uint8 Aura::CalcMaxCharges(Unit* caster) const  {      uint32 maxProcCharges = m_spellInfo->ProcCharges;      if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId())) -        maxProcCharges = procEntry->charges; +        maxProcCharges = procEntry->Charges;      if (caster)          if (Player* modOwner = caster->GetSpellModOwner()) @@ -1861,9 +1861,9 @@ bool Aura::IsProcOnCooldown() const      return false;  } -void Aura::AddProcCooldown(uint32 /*msec*/) +void Aura::AddProcCooldown(Milliseconds /*msec*/)  { -    //m_procCooldown = time(NULL) + msec; +    //m_procCooldown = std::chrono::steady_clock::now() + msec;  }  void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo) @@ -1884,7 +1884,7 @@ void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInf      ASSERT(procEntry);      // cooldowns should be added to the whole aura (see 51698 area aura) -    AddProcCooldown(procEntry->cooldown); +    AddProcCooldown(procEntry->Cooldown);  }  bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const @@ -1963,16 +1963,16 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI  float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const  { -    float chance = procEntry.chance; +    float chance = procEntry.Chance;      // calculate chances depending on unit with caster's data      // so talents modifying chances and judgements will have properly calculated proc chance      if (Unit* caster = GetCaster())      {          // calculate ppm chance if present and we're using weapon -        if (eventInfo.GetDamageInfo() && procEntry.ratePerMinute != 0) +        if (eventInfo.GetDamageInfo() && procEntry.ProcsPerMinute != 0)          {              uint32 WeaponSpeed = caster->GetAttackTime(eventInfo.GetDamageInfo()->GetAttackType()); -            chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ratePerMinute, GetSpellInfo()); +            chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ProcsPerMinute, GetSpellInfo());          }          // apply chance modifer aura, applies also to ppm chance (see improved judgement of light spell)          if (Player* modOwner = caster->GetSpellModOwner()) diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 750110dc146..f792581c86d 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -204,7 +204,7 @@ class TC_GAME_API Aura          // and some dependant problems fixed before it can replace old proc system (for example cooldown handling)          // currently proc system functionality is implemented in Unit::ProcDamageAndSpell          bool IsProcOnCooldown() const; -        void AddProcCooldown(uint32 msec); +        void AddProcCooldown(Milliseconds msec);          bool IsUsingCharges() const { return m_isUsingCharges; }          void SetUsingCharges(bool val) { m_isUsingCharges = val; }          void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 8329e0f3ca1..4176e8fb20e 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1302,18 +1302,30 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici          }          default:          { -            float dist; +            float dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster);              float angle = targetType.CalcDirectionAngle();              float objSize = m_caster->GetObjectSize(); -            if (targetType.GetTarget() == TARGET_DEST_CASTER_SUMMON) -                dist = PET_FOLLOW_DIST; -            else -                dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster);              if (dist < objSize)                  dist = objSize; -            else if (targetType.GetTarget() == TARGET_DEST_CASTER_RANDOM) -                dist = objSize + (dist - objSize) * float(rand_norm()); + +            switch (targetType.GetTarget()) +            { +                case TARGET_DEST_CASTER_SUMMON: +                    dist = PET_FOLLOW_DIST; +                    break; +                case TARGET_DEST_CASTER_RANDOM: +                    dist = objSize + (dist - objSize) * float(rand_norm()); +                    break; +                case TARGET_DEST_CASTER_FRONT_LEFT: +                case TARGET_DEST_CASTER_BACK_LEFT: +                case TARGET_DEST_CASTER_FRONT_RIGHT: +                case TARGET_DEST_CASTER_BACK_RIGHT: +                    dist = dist + objSize; +                    break; +                default: +                    break; +            }              Position pos = dest._position;              m_caster->MovePositionToFirstCollision(pos, dist, angle); @@ -5329,6 +5341,9 @@ SpellCastResult Spell::CheckCast(bool strict)                  if (!target || m_caster->ToPlayer() == target || (!target->IsInSameRaidWith(m_caster->ToPlayer()) && m_spellInfo->Id != 48955)) // refer-a-friend spell                      return SPELL_FAILED_BAD_TARGETS; +                if (target->HasSummonPending()) +                    return SPELL_FAILED_SUMMON_PENDING; +                  // check if our map is dungeon                  MapEntry const* map = sMapStore.LookupEntry(m_caster->GetMapId());                  if (map->IsDungeon()) diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index e634aa62a1c..b7134283ccb 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -694,14 +694,6 @@ class TC_GAME_API Spell          ByteBuffer * m_effectExecuteData[MAX_SPELL_EFFECTS]; -#ifdef MAP_BASED_RAND_GEN -        int32 irand(int32 min, int32 max)       { return int32 (m_caster->GetMap()->mtRand.randInt(max - min)) + min; } -        uint32 urand(uint32 min, uint32 max)    { return m_caster->GetMap()->mtRand.randInt(max - min) + min; } -        int32 rand32()                          { return m_caster->GetMap()->mtRand.randInt(); } -        double rand_norm()                      { return m_caster->GetMap()->mtRand.randExc(); } -        double rand_chance()                    { return m_caster->GetMap()->mtRand.randExc(100.0); } -#endif -          Spell(Spell const& right) = delete;          Spell& operator=(Spell const& right) = delete;  }; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 1c2b2743a6d..51b6db197db 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4212,20 +4212,7 @@ void Spell::EffectSummonPlayer(SpellEffIndex /*effIndex*/)      if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)          return; -    // Evil Twin (ignore player summon, but hide this for summoner) -    if (unitTarget->HasAura(23445)) -        return; - -    float x, y, z; -    m_caster->GetPosition(x, y, z); - -    unitTarget->ToPlayer()->SetSummonPoint(m_caster->GetMapId(), x, y, z); - -    WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4); -    data << uint64(m_caster->GetGUID());                    // summoner guid -    data << uint32(m_caster->GetZoneId());                  // summoner zone -    data << uint32(MAX_PLAYER_SUMMON_DELAY*IN_MILLISECONDS); // auto decline after msecs -    unitTarget->ToPlayer()->GetSession()->SendPacket(&data); +    unitTarget->ToPlayer()->SendSummonRequestFrom(m_caster);  }  void Spell::EffectActivateObject(SpellEffIndex /*effIndex*/) diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp index 4f74197fed2..31490bea29b 100644 --- a/src/server/game/Spells/SpellHistory.cpp +++ b/src/server/game/Spells/SpellHistory.cpp @@ -533,7 +533,7 @@ void SpellHistory::LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTim      else      {          Creature* creatureOwner = _owner->ToCreature(); -        for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i) +        for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)              if (creatureOwner->m_spells[i])                  knownSpells.insert(creatureOwner->m_spells[i]);      } diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 50f750f2ca5..56042e05257 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -955,11 +955,11 @@ SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const  bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const  {      // proc type doesn't match -    if (!(eventInfo.GetTypeMask() & procEntry.typeMask)) +    if (!(eventInfo.GetTypeMask() & procEntry.ProcFlags))          return false;      // check XP or honor target requirement -    if (procEntry.attributesMask & PROC_ATTR_REQ_EXP_OR_HONOR) +    if (procEntry.AttributesMask & PROC_ATTR_REQ_EXP_OR_HONOR)          if (Player* actor = eventInfo.GetActor()->ToPlayer())              if (eventInfo.GetActionTarget() && !actor->isHonorOrXPTarget(eventInfo.GetActionTarget()))                  return false; @@ -969,7 +969,7 @@ bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcE          return true;      // check school mask (if set) for other trigger types -    if (procEntry.schoolMask && !(eventInfo.GetSchoolMask() & procEntry.schoolMask)) +    if (procEntry.SchoolMask && !(eventInfo.GetSchoolMask() & procEntry.SchoolMask))          return false;      // check spell family name/flags (if set) for spells @@ -977,31 +977,31 @@ bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcE      {          SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo(); -        if (procEntry.spellFamilyName && eventSpellInfo && (procEntry.spellFamilyName != eventSpellInfo->SpellFamilyName)) +        if (procEntry.SpellFamilyName && eventSpellInfo && (procEntry.SpellFamilyName != eventSpellInfo->SpellFamilyName))              return false; -        if (procEntry.spellFamilyMask && eventSpellInfo && !(procEntry.spellFamilyMask & eventSpellInfo->SpellFamilyFlags)) +        if (procEntry.SpellFamilyMask && eventSpellInfo && !(procEntry.SpellFamilyMask & eventSpellInfo->SpellFamilyFlags))              return false;      }      // check spell type mask (if set)      if (eventInfo.GetTypeMask() & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))      { -        if (procEntry.spellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.spellTypeMask)) +        if (procEntry.SpellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.SpellTypeMask))              return false;      }      // check spell phase mask      if (eventInfo.GetTypeMask() & REQ_SPELL_PHASE_PROC_FLAG_MASK)      { -        if (!(eventInfo.GetSpellPhaseMask() & procEntry.spellPhaseMask)) +        if (!(eventInfo.GetSpellPhaseMask() & procEntry.SpellPhaseMask))              return false;      }      // check hit mask (on taken hit or on done hit, but not on spell cast phase)      if ((eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) || ((eventInfo.GetTypeMask() & DONE_HIT_PROC_FLAG_MASK) && !(eventInfo.GetSpellPhaseMask() & PROC_SPELL_PHASE_CAST)))      { -        uint32 hitMask = procEntry.hitMask; +        uint32 hitMask = procEntry.HitMask;          // get default values if hit mask not set          if (!hitMask)          { @@ -1929,8 +1929,11 @@ void SpellMgr::LoadSpellProcs()      mSpellProcMap.clear();                             // need for reload case -    //                                                 0        1           2                3                 4                 5                 6         7              8               9        10              11             12      13        14 -    QueryResult result = WorldDatabase.Query("SELECT spellId, schoolMask, spellFamilyName, spellFamilyMask0, spellFamilyMask1, spellFamilyMask2, typeMask, spellTypeMask, spellPhaseMask, hitMask, attributesMask, ratePerMinute, chance, cooldown, charges FROM spell_proc"); +    //                                                     0           1                2                 3                 4                 5 +    QueryResult result = WorldDatabase.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, " +    //           6              7               8        9              10              11      12        13      14 +        "ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc"); +      if (!result)      {          TC_LOG_INFO("server.loading", ">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty."); @@ -1972,21 +1975,20 @@ void SpellMgr::LoadSpellProcs()          SpellProcEntry baseProcEntry; -        baseProcEntry.schoolMask      = fields[1].GetInt8(); -        baseProcEntry.spellFamilyName = fields[2].GetUInt16(); -        baseProcEntry.spellFamilyMask[0] = fields[3].GetUInt32(); -        baseProcEntry.spellFamilyMask[1] = fields[4].GetUInt32(); -        baseProcEntry.spellFamilyMask[2] = fields[5].GetUInt32(); -        baseProcEntry.typeMask        = fields[6].GetUInt32(); -        baseProcEntry.spellTypeMask   = fields[7].GetUInt32(); -        baseProcEntry.spellPhaseMask  = fields[8].GetUInt32(); -        baseProcEntry.hitMask         = fields[9].GetUInt32(); -        baseProcEntry.attributesMask  = fields[10].GetUInt32(); -        baseProcEntry.ratePerMinute   = fields[11].GetFloat(); -        baseProcEntry.chance          = fields[12].GetFloat(); -        float cooldown                = fields[13].GetFloat(); -        baseProcEntry.cooldown        = uint32(cooldown); -        baseProcEntry.charges         = fields[14].GetUInt32(); +        baseProcEntry.SchoolMask         = fields[1].GetInt8(); +        baseProcEntry.SpellFamilyName    = fields[2].GetUInt16(); +        baseProcEntry.SpellFamilyMask[0] = fields[3].GetUInt32(); +        baseProcEntry.SpellFamilyMask[1] = fields[4].GetUInt32(); +        baseProcEntry.SpellFamilyMask[2] = fields[5].GetUInt32(); +        baseProcEntry.ProcFlags          = fields[6].GetUInt32(); +        baseProcEntry.SpellTypeMask      = fields[7].GetUInt32(); +        baseProcEntry.SpellPhaseMask     = fields[8].GetUInt32(); +        baseProcEntry.HitMask            = fields[9].GetUInt32(); +        baseProcEntry.AttributesMask     = fields[10].GetUInt32(); +        baseProcEntry.ProcsPerMinute     = fields[11].GetFloat(); +        baseProcEntry.Chance             = fields[12].GetFloat(); +        baseProcEntry.Cooldown           = Milliseconds(fields[13].GetUInt32()); +        baseProcEntry.Charges            = fields[14].GetUInt8();          while (spellInfo)          { @@ -1999,56 +2001,46 @@ void SpellMgr::LoadSpellProcs()              SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);              // take defaults from dbcs -            if (!procEntry.typeMask) -                procEntry.typeMask = spellInfo->ProcFlags; -            if (!procEntry.charges) -                procEntry.charges = spellInfo->ProcCharges; -            if (!procEntry.chance && !procEntry.ratePerMinute) -                procEntry.chance = float(spellInfo->ProcChance); +            if (!procEntry.ProcFlags) +                procEntry.ProcFlags = spellInfo->ProcFlags; +            if (!procEntry.Charges) +                procEntry.Charges = spellInfo->ProcCharges; +            if (!procEntry.Chance && !procEntry.ProcsPerMinute) +                procEntry.Chance = float(spellInfo->ProcChance);              // validate data -            if (procEntry.schoolMask & ~SPELL_SCHOOL_MASK_ALL) -                TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `schoolMask` set: %u", spellInfo->Id, procEntry.schoolMask); -            if (procEntry.spellFamilyName && (procEntry.spellFamilyName < 3 || procEntry.spellFamilyName > 17 || procEntry.spellFamilyName == 14 || procEntry.spellFamilyName == 16)) -                TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `spellFamilyName` set: %u", spellInfo->Id, procEntry.spellFamilyName); -            if (procEntry.chance < 0) -            { -                TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `chance` field", spellInfo->Id); -                procEntry.chance = 0; -            } -            if (procEntry.ratePerMinute < 0) -            { -                TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `ratePerMinute` field", spellInfo->Id); -                procEntry.ratePerMinute = 0; -            } -            if (cooldown < 0) +            if (procEntry.SchoolMask & ~SPELL_SCHOOL_MASK_ALL) +                TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SchoolMask` set: %u", spellInfo->Id, procEntry.SchoolMask); +            if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName < 3 || procEntry.SpellFamilyName > 17 || procEntry.SpellFamilyName == 14 || procEntry.SpellFamilyName == 16)) +                TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SpellFamilyName` set: %u", spellInfo->Id, procEntry.SpellFamilyName); +            if (procEntry.Chance < 0)              { -                TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `cooldown` field", spellInfo->Id); -                procEntry.cooldown = 0; +                TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `Chance` field", spellInfo->Id); +                procEntry.Chance = 0;              } -            if (procEntry.chance == 0 && procEntry.ratePerMinute == 0) -                TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u doesn't have any `chance` and `ratePerMinute` values defined, proc will not be triggered", spellInfo->Id); -            if (procEntry.charges > 99) +            if (procEntry.ProcsPerMinute < 0)              { -                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has a too big `charges` field value.", spellInfo->Id); -                procEntry.charges = 99; +                TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `ProcsPerMinute` field", spellInfo->Id); +                procEntry.ProcsPerMinute = 0;              } -            if (!procEntry.typeMask) -                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `typeMask` value defined, proc will not be triggered.", spellInfo->Id); -            if (procEntry.spellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL) -                TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `spellTypeMask` set: %u", spellInfo->Id, procEntry.spellTypeMask); -            if (procEntry.spellTypeMask && !(procEntry.typeMask & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))) -                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `spellTypeMask` value defined, but it will not be used for the defined `typeMask` value.", spellInfo->Id); -            if (!procEntry.spellPhaseMask && procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK) -                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `spellPhaseMask` value defined, but it is required for the defined `typeMask` value. Proc will not be triggered.", spellInfo->Id); -            if (procEntry.spellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL) -                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `spellPhaseMask` set: %u", spellInfo->Id, procEntry.spellPhaseMask); -            if (procEntry.spellPhaseMask && !(procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK)) -                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has a `spellPhaseMask` value defined, but it will not be used for the defined `typeMask` value.", spellInfo->Id); -            if (procEntry.hitMask & ~PROC_HIT_MASK_ALL) -                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `hitMask` set: %u", spellInfo->Id, procEntry.hitMask); -            if (procEntry.hitMask && !(procEntry.typeMask & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.typeMask & DONE_HIT_PROC_FLAG_MASK && (!procEntry.spellPhaseMask || procEntry.spellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH))))) -                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `hitMask` value defined, but it will not be used for defined `typeMask` and `spellPhaseMask` values.", spellInfo->Id); +            if (procEntry.Chance == 0 && procEntry.ProcsPerMinute == 0) +                TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u doesn't have any `Chance` and `ProcsPerMinute` values defined, proc will not be triggered", spellInfo->Id); +            if (!procEntry.ProcFlags) +                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `ProcFlags` value defined, proc will not be triggered.", spellInfo->Id); +            if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL) +                TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SpellTypeMask` set: %u", spellInfo->Id, procEntry.SpellTypeMask); +            if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))) +                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `SpellTypeMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id); +            if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK) +                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `SpellPhaseMask` value defined, but it is required for the defined `ProcFlags` value. Proc will not be triggered.", spellInfo->Id); +            if (procEntry.SpellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL) +                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `SpellPhaseMask` set: %u", spellInfo->Id, procEntry.SpellPhaseMask); +            if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)) +                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has a `SpellPhaseMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id); +            if (procEntry.HitMask & ~PROC_HIT_MASK_ALL) +                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `HitMask` set: %u", spellInfo->Id, procEntry.HitMask); +            if (procEntry.HitMask && !(procEntry.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.ProcFlags & DONE_HIT_PROC_FLAG_MASK && (!procEntry.SpellPhaseMask || procEntry.SpellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH))))) +                TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `HitMask` value defined, but it will not be used for defined `ProcFlags` and `SpellPhaseMask` values.", spellInfo->Id);              mSpellProcMap[spellInfo->Id] = procEntry; diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index fea7513b092..75da933636c 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -266,7 +266,7 @@ enum ProcFlagsHit      PROC_HIT_REFLECT             = 0x0000800,      PROC_HIT_INTERRUPT           = 0x0001000, // (not used atm)      PROC_HIT_FULL_BLOCK          = 0x0002000, -    PROC_HIT_MASK_ALL            = 0x2FFF +    PROC_HIT_MASK_ALL            = 0x0002FFF  };  enum ProcAttributes @@ -290,18 +290,18 @@ typedef std::unordered_map<uint32, SpellProcEventEntry> SpellProcEventMap;  struct SpellProcEntry  { -    uint32      schoolMask;                                 // if nonzero - bitmask for matching proc condition based on spell's school -    uint32      spellFamilyName;                            // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName -    flag96      spellFamilyMask;                            // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags -    uint32      typeMask;                                   // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags -    uint32      spellTypeMask;                              // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType -    uint32      spellPhaseMask;                             // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase -    uint32      hitMask;                                    // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit -    uint32      attributesMask;                             // bitmask, see ProcAttributes -    float       ratePerMinute;                              // if nonzero - chance to proc is equal to value * aura caster's weapon speed / 60 -    float       chance;                                     // if nonzero - owerwrite procChance field for given Spell.dbc entry, defines chance of proc to occur, not used if perMinuteRate set -    uint32      cooldown;                                   // if nonzero - cooldown in secs for aura proc, applied to aura -    uint32      charges;                                    // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite +    uint32 SchoolMask;      // if nonzero - bitmask for matching proc condition based on spell's school +    uint32 SpellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName +    flag96 SpellFamilyMask; // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags +    uint32 ProcFlags;       // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags +    uint32 SpellTypeMask;   // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType +    uint32 SpellPhaseMask;  // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase +    uint32 HitMask;         // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit +    uint32 AttributesMask;  // bitmask, see ProcAttributes +    float ProcsPerMinute;   // if nonzero - chance to proc is equal to value * aura caster's weapon speed / 60 +    float Chance;           // if nonzero - owerwrite procChance field for given Spell.dbc entry, defines chance of proc to occur, not used if ProcsPerMinute set +    Milliseconds Cooldown;  // if nonzero - cooldown in secs for aura proc, applied to aura +    uint32 Charges;         // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite  };  typedef std::unordered_map<uint32, SpellProcEntry> SpellProcMap; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 4b64ef0bbd8..d84fe11383f 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -66,7 +66,7 @@  #include "WaypointMovementGenerator.h"  #include "WeatherMgr.h"  #include "WorldSession.h" - +#include "M2Stores.h"  TC_GAME_API std::atomic<bool> World::m_stopEvent(false);  TC_GAME_API uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE; @@ -900,6 +900,7 @@ void World::LoadConfigSettings(bool reload)      m_bool_configs[CONFIG_ALLOW_GM_GROUP]       = sConfigMgr->GetBoolDefault("GM.AllowInvite", false);      m_bool_configs[CONFIG_GM_LOWER_SECURITY] = sConfigMgr->GetBoolDefault("GM.LowerSecurity", false);      m_float_configs[CONFIG_CHANCE_OF_GM_SURVEY] = sConfigMgr->GetFloatDefault("GM.TicketSystem.ChanceOfGMSurvey", 50.0f); +    m_int_configs[CONFIG_FORCE_SHUTDOWN_THRESHOLD] = sConfigMgr->GetIntDefault("GM.ForceShutdownThreshold", 30);      m_int_configs[CONFIG_GROUP_VISIBILITY] = sConfigMgr->GetIntDefault("Visibility.GroupMode", 1); @@ -1082,6 +1083,7 @@ void World::LoadConfigSettings(bool reload)      m_bool_configs[CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN]            = sConfigMgr->GetBoolDefault("OffhandCheckAtSpellUnlearn", true);      m_int_configs[CONFIG_CREATURE_PICKPOCKET_REFILL] = sConfigMgr->GetIntDefault("Creature.PickPocketRefillDelay", 10 * MINUTE); +    m_int_configs[CONFIG_CREATURE_STOP_FOR_PLAYER] = sConfigMgr->GetIntDefault("Creature.MovingStopTimeForPlayer", 3 * MINUTE * IN_MILLISECONDS);      if (int32 clientCacheId = sConfigMgr->GetIntDefault("ClientCacheVersion", 0))      { @@ -1402,6 +1404,9 @@ void World::SetInitialWorldSettings()      LoadDBCStores(m_dataPath);      DetectDBCLang(); +    // Load cinematic cameras +    LoadM2Cameras(m_dataPath); +      std::vector<uint32> mapIds;      for (uint32 mapId = 0; mapId < sMapStore.GetNumRows(); mapId++)          if (sMapStore.LookupEntry(mapId)) diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index abc0ea452ac..330e78cf510 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -28,7 +28,7 @@  #include "Timer.h"  #include "SharedDefines.h"  #include "QueryResult.h" -#include "Callback.h" +#include "QueryCallback.h"  #include "Realm/Realm.h"  #include <atomic> @@ -56,7 +56,8 @@ enum ServerMessageType  enum ShutdownMask  {      SHUTDOWN_MASK_RESTART = 1, -    SHUTDOWN_MASK_IDLE    = 2 +    SHUTDOWN_MASK_IDLE    = 2, +    SHUTDOWN_MASK_FORCE   = 4  };  enum ShutdownExitCode @@ -252,6 +253,7 @@ enum WorldIntConfigs      CONFIG_GM_LEVEL_IN_GM_LIST,      CONFIG_GM_LEVEL_IN_WHO_LIST,      CONFIG_START_GM_LEVEL, +    CONFIG_FORCE_SHUTDOWN_THRESHOLD,      CONFIG_GROUP_VISIBILITY,      CONFIG_MAIL_DELIVERY_DELAY,      CONFIG_UPTIME_UPDATE, @@ -357,6 +359,7 @@ enum WorldIntConfigs      CONFIG_BG_REWARD_LOSER_HONOR_LAST,      CONFIG_BIRTHDAY_TIME,      CONFIG_CREATURE_PICKPOCKET_REFILL, +    CONFIG_CREATURE_STOP_FOR_PLAYER,      CONFIG_AHBOT_UPDATE_INTERVAL,      CONFIG_CHARTER_COST_GUILD,      CONFIG_CHARTER_COST_ARENA_2v2, diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp index 9557d182df1..01602e2f24c 100644 --- a/src/server/scripts/Commands/cs_character.cpp +++ b/src/server/scripts/Commands/cs_character.cpp @@ -436,7 +436,7 @@ public:          if (isalpha(levelStr[0]))          {              nameStr = levelStr; -            levelStr = NULL;                                    // current level will used +            levelStr = nullptr;                                    // current level will used          }          Player* target; diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 1d8094885d4..ca4dd814e01 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -34,6 +34,7 @@ EndScriptData */  #include "Transport.h"  #include "Language.h"  #include "MapManager.h" +#include "M2Stores.h"  #include <fstream> @@ -847,7 +848,7 @@ public:              if (Unit* unit = ref->GetSource()->GetOwner())              {                  ++count; -                handler->PSendSysMessage("   %u.   %s   (guid %u)  - threat %f", count, unit->GetName().c_str(), unit->GetGUID().GetCounter(), ref->getThreat()); +                handler->PSendSysMessage("   %u.   %s   (current guid %u, DB guid %u)  - threat %f", count, unit->GetName().c_str(), unit->GetGUID().GetCounter(), unit->GetTypeId() == TYPEID_UNIT ? unit->ToCreature()->GetSpawnId() : 0, ref->getThreat());              }              ref = ref->next();          } diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 3e35a721162..a98f9f4bf9c 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -796,7 +796,7 @@ public:              target->CleanupAfterTaxiFlight();          } -        target->TeleportTo(target->m_recallMap, target->m_recallX, target->m_recallY, target->m_recallZ, target->m_recallO); +        target->Recall();          return true;      } diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index f1ddb448b35..e25018cf1bd 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -80,23 +80,32 @@ public:          return commandTable;      } -    //Edit Player HP -    static bool HandleModifyHPCommand(ChatHandler* handler, const char* args) +    template<typename... Args> +    static void NotifyModification(ChatHandler* handler, Unit* target, TrinityStrings resourceMessage, TrinityStrings resourceReportMessage, Args&&... args) +    { +        if (Player* player = target->ToPlayer()) +        { +            handler->PSendSysMessage(resourceMessage, handler->GetNameLink(player).c_str(), args...); +            if (handler->needReportToTarget(player)) +                ChatHandler(player->GetSession()).PSendSysMessage(resourceReportMessage, handler->GetNameLink().c_str(), std::forward<Args>(args)...); +        } +    } + +    static bool CheckModifyResources(ChatHandler* handler, const char* args, Player* target, int32& res, int32& resmax, int8 const multiplier = 1)      {          if (!*args)              return false; -        int32 hp = atoi((char*)args); -        int32 hpm = atoi((char*)args); +        res = atoi((char*)args) * multiplier; +        resmax = atoi((char*)args) * multiplier; -        if (hp < 1 || hpm < 1 || hpm < hp) +        if (res < 1 || resmax < 1 || resmax < res)          {              handler->SendSysMessage(LANG_BAD_VALUE);              handler->SetSentErrorMessage(true);              return false;          } -        Player* target = handler->getSelectedPlayerOrSelf();          if (!target)          {              handler->SendSysMessage(LANG_NO_CHAR_SELECTED); @@ -107,164 +116,87 @@ public:          if (handler->HasLowerSecurity(target, ObjectGuid::Empty))              return false; -        handler->PSendSysMessage(LANG_YOU_CHANGE_HP, handler->GetNameLink(target).c_str(), hp, hpm); -        if (handler->needReportToTarget(target)) -            ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_HP_CHANGED, handler->GetNameLink().c_str(), hp, hpm); - -        target->SetMaxHealth(hpm); -        target->SetHealth(hp); -          return true;      } -    //Edit Player Mana -    static bool HandleModifyManaCommand(ChatHandler* handler, const char* args) +    //Edit Player HP +    static bool HandleModifyHPCommand(ChatHandler* handler, const char* args)      { -        if (!*args) -            return false; - -        int32 mana = atoi((char*)args); -        int32 manam = atoi((char*)args); - -        if (mana <= 0 || manam <= 0 || manam < mana) +        int32 hp, hpmax; +        Player* target = handler->getSelectedPlayerOrSelf(); +        if (CheckModifyResources(handler, args, target, hp, hpmax))          { -            handler->SendSysMessage(LANG_BAD_VALUE); -            handler->SetSentErrorMessage(true); -            return false; +            NotifyModification(handler, target, LANG_YOU_CHANGE_HP, LANG_YOURS_HP_CHANGED, hp, hpmax); +            target->SetMaxHealth(hpmax); +            target->SetHealth(hp); +            return true;          } +        return false; +    } +    //Edit Player Mana +    static bool HandleModifyManaCommand(ChatHandler* handler, const char* args) +    { +        int32 mana, manamax;          Player* target = handler->getSelectedPlayerOrSelf(); -        if (!target) + +        if (CheckModifyResources(handler, args, target, mana, manamax))          { -            handler->SendSysMessage(LANG_NO_CHAR_SELECTED); -            handler->SetSentErrorMessage(true); -            return false; +            NotifyModification(handler, target, LANG_YOU_CHANGE_MANA, LANG_YOURS_MANA_CHANGED, mana, manamax); +            target->SetMaxPower(POWER_MANA, manamax); +            target->SetPower(POWER_MANA, mana); +            return true;          } - -        // check online security -        if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) -            return false; - -        handler->PSendSysMessage(LANG_YOU_CHANGE_MANA, handler->GetNameLink(target).c_str(), mana, manam); -        if (handler->needReportToTarget(target)) -            ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_MANA_CHANGED, handler->GetNameLink().c_str(), mana, manam); - -        target->SetMaxPower(POWER_MANA, manam); -        target->SetPower(POWER_MANA, mana); - -        return true; +        return false;      }      //Edit Player Energy      static bool HandleModifyEnergyCommand(ChatHandler* handler, const char* args)      { -        if (!*args) -            return false; - -        int32 energy = atoi((char*)args)*10; -        int32 energym = atoi((char*)args)*10; - -        if (energy <= 0 || energym <= 0 || energym < energy) -        { -            handler->SendSysMessage(LANG_BAD_VALUE); -            handler->SetSentErrorMessage(true); -            return false; -        } - +        int32 energy, energymax;          Player* target = handler->getSelectedPlayerOrSelf(); -        if (!target) +        int8 const energyMultiplier = 10; +        if (CheckModifyResources(handler, args, target, energy, energymax, energyMultiplier))          { -            handler->SendSysMessage(LANG_NO_CHAR_SELECTED); -            handler->SetSentErrorMessage(true); -            return false; +            NotifyModification(handler, target, LANG_YOU_CHANGE_ENERGY, LANG_YOURS_ENERGY_CHANGED, energy / energyMultiplier, energymax / energyMultiplier); +            target->SetMaxPower(POWER_ENERGY, energymax); +            target->SetPower(POWER_ENERGY, energy); +            TC_LOG_DEBUG("misc", handler->GetTrinityString(LANG_CURRENT_ENERGY), target->GetMaxPower(POWER_ENERGY)); +            return true;          } - -        // check online security -        if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) -            return false; - -        handler->PSendSysMessage(LANG_YOU_CHANGE_ENERGY, handler->GetNameLink(target).c_str(), energy/10, energym/10); -        if (handler->needReportToTarget(target)) -            ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_ENERGY_CHANGED, handler->GetNameLink().c_str(), energy/10, energym/10); - -        target->SetMaxPower(POWER_ENERGY, energym); -        target->SetPower(POWER_ENERGY, energy); - -        TC_LOG_DEBUG("misc", handler->GetTrinityString(LANG_CURRENT_ENERGY), target->GetMaxPower(POWER_ENERGY)); - -        return true; +        return false;      }      //Edit Player Rage      static bool HandleModifyRageCommand(ChatHandler* handler, const char* args)      { -        if (!*args) -            return false; - -        int32 rage = atoi((char*)args)*10; -        int32 ragem = atoi((char*)args)*10; - -        if (rage <= 0 || ragem <= 0 || ragem < rage) -        { -            handler->SendSysMessage(LANG_BAD_VALUE); -            handler->SetSentErrorMessage(true); -            return false; -        } - +        int32 rage, ragemax;          Player* target = handler->getSelectedPlayerOrSelf(); -        if (!target) +        int8 const rageMultiplier = 10; +        if (CheckModifyResources(handler, args, target, rage, ragemax, rageMultiplier))          { -            handler->SendSysMessage(LANG_NO_CHAR_SELECTED); -            handler->SetSentErrorMessage(true); -            return false; +            NotifyModification(handler, target, LANG_YOU_CHANGE_RAGE, LANG_YOURS_RAGE_CHANGED, rage / rageMultiplier, ragemax / rageMultiplier); +            target->SetMaxPower(POWER_RAGE, ragemax); +            target->SetPower(POWER_RAGE, rage); +            return true;          } - -        // check online security -        if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) -            return false; - -        handler->PSendSysMessage(LANG_YOU_CHANGE_RAGE, handler->GetNameLink(target).c_str(), rage/10, ragem/10); -        if (handler->needReportToTarget(target)) -            ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_RAGE_CHANGED, handler->GetNameLink().c_str(), rage/10, ragem/10); - -        target->SetMaxPower(POWER_RAGE, ragem); -        target->SetPower(POWER_RAGE, rage); - -        return true; +        return false;      }      // Edit Player Runic Power      static bool HandleModifyRunicPowerCommand(ChatHandler* handler, const char* args)      { -        if (!*args) -            return false; - -        int32 rune = atoi((char*)args)*10; -        int32 runem = atoi((char*)args)*10; - -        if (rune <= 0 || runem <= 0 || runem < rune) -        { -            handler->SendSysMessage(LANG_BAD_VALUE); -            handler->SetSentErrorMessage(true); -            return false; -        } - +        int32 rune, runemax;          Player* target = handler->getSelectedPlayerOrSelf(); -        if (!target) +        int8 const runeMultiplier = 10; +        if (CheckModifyResources(handler, args, target, rune, runemax, runeMultiplier))          { -            handler->SendSysMessage(LANG_NO_CHAR_SELECTED); -            handler->SetSentErrorMessage(true); -            return false; +            NotifyModification(handler, target, LANG_YOU_CHANGE_RUNIC_POWER, LANG_YOURS_RUNIC_POWER_CHANGED, rune / runeMultiplier, runemax / runeMultiplier); +            target->SetMaxPower(POWER_RUNIC_POWER, runemax); +            target->SetPower(POWER_RUNIC_POWER, rune); +            return true;          } - -        handler->PSendSysMessage(LANG_YOU_CHANGE_RUNIC_POWER, handler->GetNameLink(target).c_str(), rune/10, runem/10); -        if (handler->needReportToTarget(target)) -            ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_RUNIC_POWER_CHANGED, handler->GetNameLink().c_str(), rune/10, runem/10); - -        target->SetMaxPower(POWER_RUNIC_POWER, runem); -        target->SetPower(POWER_RUNIC_POWER, rune); - -        return true; +        return false;      }      //Edit Player Faction @@ -437,22 +369,20 @@ public:          return false;      } -    //Edit Player Aspeed -    static bool HandleModifyASpeedCommand(ChatHandler* handler, const char* args) +    static bool CheckModifySpeed(ChatHandler* handler, const char* args, Unit* target, float& speed, float minimumBound, float maximumBound, bool checkInFlight = true)      {          if (!*args)              return false; -        float ASpeed = (float)atof((char*)args); +        speed = (float)atof((char*)args); -        if (ASpeed > 50.0f || ASpeed < 0.1f) +        if (speed > maximumBound || speed < minimumBound)          {              handler->SendSysMessage(LANG_BAD_VALUE);              handler->SetSentErrorMessage(true);              return false;          } -        Player* target = handler->getSelectedPlayerOrSelf();          if (!target)          {              handler->SendSysMessage(LANG_NO_CHAR_SELECTED); @@ -460,238 +390,107 @@ public:              return false;          } -        // check online security -        if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) -            return false; - -        std::string targetNameLink = handler->GetNameLink(target); - -        if (target->IsInFlight()) +        if (Player* player = target->ToPlayer())          { -            handler->PSendSysMessage(LANG_CHAR_IN_FLIGHT, targetNameLink.c_str()); -            handler->SetSentErrorMessage(true); -            return false; -        } - -        handler->PSendSysMessage(LANG_YOU_CHANGE_ASPEED, targetNameLink.c_str(), ASpeed); -        if (handler->needReportToTarget(target)) -            ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_ASPEED_CHANGED, handler->GetNameLink().c_str(), ASpeed); +            // check online security +            if (handler->HasLowerSecurity(player, ObjectGuid::Empty)) +                return false; -        target->SetSpeedRate(MOVE_WALK,    ASpeed); -        target->SetSpeedRate(MOVE_RUN,     ASpeed); -        target->SetSpeedRate(MOVE_SWIM,    ASpeed); -        //target->SetSpeedRate(MOVE_TURN,    ASpeed); -        target->SetSpeedRate(MOVE_FLIGHT,     ASpeed); +            if (player->IsInFlight() && checkInFlight) +            { +                handler->PSendSysMessage(LANG_CHAR_IN_FLIGHT, handler->GetNameLink(player).c_str()); +                handler->SetSentErrorMessage(true); +                return false; +            } +        }          return true;      } -    //Edit Player Speed -    static bool HandleModifySpeedCommand(ChatHandler* handler, const char* args) +    //Edit Player Aspeed +    static bool HandleModifyASpeedCommand(ChatHandler* handler, const char* args)      { -        if (!*args) -            return false; - -        float Speed = (float)atof((char*)args); - -        if (Speed > 50.0f || Speed < 0.1f) -        { -            handler->SendSysMessage(LANG_BAD_VALUE); -            handler->SetSentErrorMessage(true); -            return false; -        } - +        float allSpeed;          Player* target = handler->getSelectedPlayerOrSelf(); -        if (!target) +        if (CheckModifySpeed(handler, args, target, allSpeed, 0.1f, 50.0f))          { -            handler->SendSysMessage(LANG_NO_CHAR_SELECTED); -            handler->SetSentErrorMessage(true); -            return false; +            NotifyModification(handler, target, LANG_YOU_CHANGE_ASPEED, LANG_YOURS_ASPEED_CHANGED, allSpeed); +            target->SetSpeedRate(MOVE_WALK, allSpeed); +            target->SetSpeedRate(MOVE_RUN, allSpeed); +            target->SetSpeedRate(MOVE_SWIM, allSpeed); +            target->SetSpeedRate(MOVE_FLIGHT, allSpeed); +            return true;          } +        return false; +    } -        // check online security -        if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) -            return false; - -        std::string targetNameLink = handler->GetNameLink(target); - -        if (target->IsInFlight()) +    //Edit Player Speed +    static bool HandleModifySpeedCommand(ChatHandler* handler, const char* args) +    { +        float Speed; +        Player* target = handler->getSelectedPlayerOrSelf(); +        if (CheckModifySpeed(handler, args, target, Speed, 0.1f, 50.0f))          { -            handler->PSendSysMessage(LANG_CHAR_IN_FLIGHT, targetNameLink.c_str()); -            handler->SetSentErrorMessage(true); -            return false; +            NotifyModification(handler, target, LANG_YOU_CHANGE_SPEED, LANG_YOURS_SPEED_CHANGED, Speed); +            target->SetSpeedRate(MOVE_RUN, Speed); +            return true;          } - -        handler->PSendSysMessage(LANG_YOU_CHANGE_SPEED, targetNameLink.c_str(), Speed); -        if (handler->needReportToTarget(target)) -            ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_SPEED_CHANGED, handler->GetNameLink().c_str(), Speed); - -        target->SetSpeedRate(MOVE_RUN, Speed); - -        return true; +        return false;      }      //Edit Player Swim Speed      static bool HandleModifySwimCommand(ChatHandler* handler, const char* args)      { -        if (!*args) -            return false; - -        float Swim = (float)atof((char*)args); - -        if (Swim > 50.0f || Swim < 0.1f) -        { -            handler->SendSysMessage(LANG_BAD_VALUE); -            handler->SetSentErrorMessage(true); -            return false; -        } - +        float swimSpeed;          Player* target = handler->getSelectedPlayerOrSelf(); -        if (!target) +        if (CheckModifySpeed(handler, args, target, swimSpeed, 0.1f, 50.0f))          { -            handler->SendSysMessage(LANG_NO_CHAR_SELECTED); -            handler->SetSentErrorMessage(true); -            return false; -        } - -        // check online security -        if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) -            return false; - -        std::string targetNameLink = handler->GetNameLink(target); - -        if (target->IsInFlight()) -        { -            handler->PSendSysMessage(LANG_CHAR_IN_FLIGHT, targetNameLink.c_str()); -            handler->SetSentErrorMessage(true); -            return false; +            NotifyModification(handler, target, LANG_YOU_CHANGE_SWIM_SPEED, LANG_YOURS_SWIM_SPEED_CHANGED, swimSpeed); +            target->SetSpeedRate(MOVE_SWIM, swimSpeed); +            return true;          } - -        handler->PSendSysMessage(LANG_YOU_CHANGE_SWIM_SPEED, targetNameLink.c_str(), Swim); -        if (handler->needReportToTarget(target)) -            ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_SWIM_SPEED_CHANGED, handler->GetNameLink().c_str(), Swim); - -        target->SetSpeedRate(MOVE_SWIM, Swim); - -        return true; +        return false;      } -    //Edit Player Walk Speed +    //Edit Player Backwards Walk Speed      static bool HandleModifyBWalkCommand(ChatHandler* handler, const char* args)      { -        if (!*args) -            return false; - -        float BSpeed = (float)atof((char*)args); - -        if (BSpeed > 50.0f || BSpeed < 0.1f) -        { -            handler->SendSysMessage(LANG_BAD_VALUE); -            handler->SetSentErrorMessage(true); -            return false; -        } - +        float backSpeed;          Player* target = handler->getSelectedPlayerOrSelf(); -        if (!target) +        if (CheckModifySpeed(handler, args, target, backSpeed, 0.1f, 50.0f))          { -            handler->SendSysMessage(LANG_NO_CHAR_SELECTED); -            handler->SetSentErrorMessage(true); -            return false; -        } - -        // check online security -        if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) -            return false; - -        std::string targetNameLink = handler->GetNameLink(target); - -        if (target->IsInFlight()) -        { -            handler->PSendSysMessage(LANG_CHAR_IN_FLIGHT, targetNameLink.c_str()); -            handler->SetSentErrorMessage(true); -            return false; +            NotifyModification(handler, target, LANG_YOU_CHANGE_BACK_SPEED, LANG_YOURS_BACK_SPEED_CHANGED, backSpeed); +            target->SetSpeedRate(MOVE_RUN_BACK, backSpeed); +            return true;          } - -        handler->PSendSysMessage(LANG_YOU_CHANGE_BACK_SPEED, targetNameLink.c_str(), BSpeed); -        if (handler->needReportToTarget(target)) -            ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_BACK_SPEED_CHANGED, handler->GetNameLink().c_str(), BSpeed); - -        target->SetSpeedRate(MOVE_RUN_BACK, BSpeed); - -        return true; +        return false;      }      //Edit Player Fly      static bool HandleModifyFlyCommand(ChatHandler* handler, const char* args)      { -        if (!*args) -            return false; - -        float FSpeed = (float)atof((char*)args); - -        if (FSpeed > 50.0f || FSpeed < 0.1f) -        { -            handler->SendSysMessage(LANG_BAD_VALUE); -            handler->SetSentErrorMessage(true); -            return false; -        } - +        float flySpeed;          Player* target = handler->getSelectedPlayerOrSelf(); -        if (!target) +        if (CheckModifySpeed(handler, args, target, flySpeed, 0.1f, 50.0f, false))          { -            handler->SendSysMessage(LANG_NO_CHAR_SELECTED); -            handler->SetSentErrorMessage(true); -            return false; +            NotifyModification(handler, target, LANG_YOU_CHANGE_FLY_SPEED, LANG_YOURS_FLY_SPEED_CHANGED, flySpeed); +            target->SetSpeedRate(MOVE_FLIGHT, flySpeed); +            return true;          } - -        // check online security -        if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) -            return false; - -        handler->PSendSysMessage(LANG_YOU_CHANGE_FLY_SPEED, handler->GetNameLink(target).c_str(), FSpeed); -        if (handler->needReportToTarget(target)) -            ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_FLY_SPEED_CHANGED, handler->GetNameLink().c_str(), FSpeed); - -        target->SetSpeedRate(MOVE_FLIGHT, FSpeed); - -        return true; +        return false;      }      //Edit Player or Creature Scale      static bool HandleModifyScaleCommand(ChatHandler* handler, const char* args)      { -        if (!*args) -            return false; - -        float Scale = (float)atof((char*)args); -        if (Scale > 10.0f || Scale < 0.1f) -        { -            handler->SendSysMessage(LANG_BAD_VALUE); -            handler->SetSentErrorMessage(true); -            return false; -        } - +        float Scale;          Unit* target = handler->getSelectedUnit(); -        if (!target) +        if (CheckModifySpeed(handler, args, target, Scale, 0.1f, 10.0f, false))          { -            handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); -            handler->SetSentErrorMessage(true); -            return false; -        } - -        if (Player* player = target->ToPlayer()) -        { -            // check online security -            if (handler->HasLowerSecurity(player, ObjectGuid::Empty)) -                return false; - -            handler->PSendSysMessage(LANG_YOU_CHANGE_SIZE, handler->GetNameLink(player).c_str(), Scale); -            if (handler->needReportToTarget(player)) -                ChatHandler(player->GetSession()).PSendSysMessage(LANG_YOURS_SIZE_CHANGED, handler->GetNameLink().c_str(), Scale); +            NotifyModification(handler, target, LANG_YOU_CHANGE_SIZE, LANG_YOURS_SIZE_CHANGED, Scale); +            target->SetObjectScale(Scale); +            return true;          } - -        target->SetObjectScale(Scale); - -        return true; +        return false;      }      //Enable Player mount @@ -932,9 +731,7 @@ public:          if (handler->HasLowerSecurity(target, ObjectGuid::Empty))              return false; -        handler->PSendSysMessage(LANG_YOU_GIVE_MOUNT, handler->GetNameLink(target).c_str()); -        if (handler->needReportToTarget(target)) -            ChatHandler(target->GetSession()).PSendSysMessage(LANG_MOUNT_GIVED, handler->GetNameLink().c_str()); +        NotifyModification(handler, target, LANG_YOU_GIVE_MOUNT, LANG_MOUNT_GIVED);          target->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP);          target->Mount(mId); @@ -988,10 +785,7 @@ public:              TC_LOG_DEBUG("misc", handler->GetTrinityString(LANG_CURRENT_MONEY), targetMoney, moneyToAdd, newmoney);              if (newmoney <= 0)              { -                handler->PSendSysMessage(LANG_YOU_TAKE_ALL_MONEY, handler->GetNameLink(target).c_str()); -                if (handler->needReportToTarget(target)) -                    ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_ALL_MONEY_GONE, handler->GetNameLink().c_str()); - +                NotifyModification(handler, target, LANG_YOU_TAKE_ALL_MONEY, LANG_YOURS_ALL_MONEY_GONE);                  target->SetMoney(0);              }              else diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index fbd199b99db..438d05c5687 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -220,14 +220,15 @@ public:              { "whisper",   rbac::RBAC_PERM_COMMAND_NPC_WHISPER,   false, &HandleNpcWhisperCommand,           ""       },              { "yell",      rbac::RBAC_PERM_COMMAND_NPC_YELL,      false, &HandleNpcYellCommand,              ""       },              { "tame",      rbac::RBAC_PERM_COMMAND_NPC_TAME,      false, &HandleNpcTameCommand,              ""       }, -            { "add",       rbac::RBAC_PERM_COMMAND_NPC_ADD,       false, NULL,                 "", npcAddCommandTable }, -            { "delete",    rbac::RBAC_PERM_COMMAND_NPC_DELETE,    false, NULL,              "", npcDeleteCommandTable }, -            { "follow",    rbac::RBAC_PERM_COMMAND_NPC_FOLLOW,    false, NULL,              "", npcFollowCommandTable }, -            { "set",       rbac::RBAC_PERM_COMMAND_NPC_SET,       false, NULL,                 "", npcSetCommandTable }, +            { "add",       rbac::RBAC_PERM_COMMAND_NPC_ADD,       false, nullptr,              "", npcAddCommandTable }, +            { "delete",    rbac::RBAC_PERM_COMMAND_NPC_DELETE,    false, nullptr,           "", npcDeleteCommandTable }, +            { "follow",    rbac::RBAC_PERM_COMMAND_NPC_FOLLOW,    false, nullptr,           "", npcFollowCommandTable }, +            { "set",       rbac::RBAC_PERM_COMMAND_NPC_SET,       false, nullptr,              "", npcSetCommandTable }, +            { "evade",     rbac::RBAC_PERM_COMMAND_NPC_EVADE,     false, &HandleNpcEvadeCommand,             ""       },          };          static std::vector<ChatCommand> commandTable =          { -            { "npc", rbac::RBAC_PERM_COMMAND_NPC, false, NULL, "", npcCommandTable }, +            { "npc", rbac::RBAC_PERM_COMMAND_NPC, false, nullptr, "", npcCommandTable },          };          return commandTable;      } @@ -318,17 +319,17 @@ public:          uint32 itemId = item_int; -        char* fmaxcount = strtok(NULL, " ");                    //add maxcount, default: 0 +        char* fmaxcount = strtok(nullptr, " ");                    //add maxcount, default: 0          uint32 maxcount = 0;          if (fmaxcount)              maxcount = atoul(fmaxcount); -        char* fincrtime = strtok(NULL, " ");                    //add incrtime, default: 0 +        char* fincrtime = strtok(nullptr, " ");                    //add incrtime, default: 0          uint32 incrtime = 0;          if (fincrtime)              incrtime = atoul(fincrtime); -        char* fextendedcost = strtok(NULL, " ");                //add ExtendedCost, default: 0 +        char* fextendedcost = strtok(nullptr, " ");                //add ExtendedCost, default: 0          uint32 extendedcost = fextendedcost ? atoul(fextendedcost) : 0;          Creature* vendor = handler->getSelectedCreature();          if (!vendor) @@ -361,7 +362,7 @@ public:              return false;          char* guidStr = strtok((char*)args, " "); -        char* waitStr = strtok((char*)NULL, " "); +        char* waitStr = strtok((char*)nullptr, " ");          ObjectGuid::LowType lowGuid = atoi((char*)guidStr); @@ -446,36 +447,24 @@ public:          }          Creature* creature = handler->getSelectedCreature(); -        if (!creature) +        if (!creature || creature->IsPet())          {              handler->SendSysMessage(LANG_SELECT_CREATURE);              handler->SetSentErrorMessage(true);              return false;          } -        if (creature->IsPet()) -        { -            if (((Pet*)creature)->getPetType() == HUNTER_PET) -            { -                creature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr->GetXPForLevel(lvl)/4); -                creature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0); -            } -            ((Pet*)creature)->GivePetLevel(lvl); -        } -        else -        { -            creature->SetMaxHealth(100 + 30*lvl); -            creature->SetHealth(100 + 30*lvl); -            creature->SetLevel(lvl); -            creature->SaveToDB(); -        } +        creature->SetMaxHealth(100 + 30*lvl); +        creature->SetHealth(100 + 30*lvl); +        creature->SetLevel(lvl); +        creature->SaveToDB();          return true;      }      static bool HandleNpcDeleteCommand(ChatHandler* handler, char const* args)      { -        Creature* unit = NULL; +        Creature* unit = nullptr;          if (*args)          { @@ -628,7 +617,7 @@ public:              return false;          char* arg1 = strtok((char*)args, " "); -        char* arg2 = strtok((char*)NULL, ""); +        char* arg2 = strtok((char*)nullptr, "");          if (!arg1 || !arg2)              return false; @@ -926,8 +915,8 @@ public:          //        later switched on/off according to special events (like escort          //        quests, etc)          char* guid_str = strtok((char*)args, " "); -        char* type_str = strtok((char*)NULL, " "); -        char* dontdel_str = strtok((char*)NULL, " "); +        char* type_str = strtok((char*)nullptr, " "); +        char* dontdel_str = strtok((char*)nullptr, " ");          bool doNotDelete = false; @@ -935,7 +924,7 @@ public:              return false;          ObjectGuid::LowType lowguid = 0; -        Creature* creature = NULL; +        Creature* creature = nullptr;          if (dontdel_str)          { @@ -961,7 +950,7 @@ public:                  {                      //TC_LOG_ERROR("misc", "DEBUG: type_str, NODEL ");                      doNotDelete = true; -                    type_str = NULL; +                    type_str = nullptr;                  }              }          } @@ -1001,7 +990,7 @@ public:          }          // now lowguid is low guid really existed creature -        // and creature point (maybe) to this creature or NULL +        // and creature point (maybe) to this creature or nullptr          MovementGeneratorType move_type; @@ -1260,7 +1249,7 @@ public:          }          char* receiver_str = strtok((char*)args, " "); -        char* text = strtok(NULL, ""); +        char* text = strtok(nullptr, "");          if (!receiver_str || !text)          { @@ -1319,7 +1308,16 @@ public:          if (!*args)              return false; -        char* charID = handler->extractKeyFromLink((char*)args, "Hcreature_entry"); +        bool loot = false; +        char const* spawntype_str = strtok((char*)args, " "); +        char const* entry_str = strtok(nullptr, ""); +        if (stricmp(spawntype_str, "LOOT") == 0) +            loot = true; +        else if (stricmp(spawntype_str, "NOLOOT") == 0) +            loot = false; +        else +            entry_str = args; +        char* charID = handler->extractKeyFromLink((char*)entry_str, "Hcreature_entry");          if (!charID)              return false; @@ -1332,7 +1330,7 @@ public:          if (!sObjectMgr->GetCreatureTemplate(id))              return false; -        chr->SummonCreature(id, *chr, TEMPSUMMON_CORPSE_DESPAWN, 120); +        chr->SummonCreature(id, *chr, loot ? TEMPSUMMON_CORPSE_TIMED_DESPAWN : TEMPSUMMON_CORPSE_DESPAWN, 30 * IN_MILLISECONDS);          return true;      } @@ -1404,6 +1402,51 @@ public:          return true;      } +    static bool HandleNpcEvadeCommand(ChatHandler* handler, char const* args) +    { +        Creature* creatureTarget = handler->getSelectedCreature(); +        if (!creatureTarget || creatureTarget->IsPet()) +        { +            handler->PSendSysMessage(LANG_SELECT_CREATURE); +            handler->SetSentErrorMessage(true); +            return false; +        } + +        if (!creatureTarget->IsAIEnabled) +        { +            handler->PSendSysMessage(LANG_CREATURE_NOT_AI_ENABLED); +            handler->SetSentErrorMessage(true); +            return false; +        } + +        char* type_str = args ? strtok((char*)args, " ") : nullptr; +        char* force_str = args ? strtok(nullptr, " ") : nullptr; + +        CreatureAI::EvadeReason why = CreatureAI::EVADE_REASON_OTHER; +        bool force = false; +        if (type_str) +        { +            if (stricmp(type_str, "NO_HOSTILES") == 0 || stricmp(type_str, "EVADE_REASON_NO_HOSTILES") == 0) +                why = CreatureAI::EVADE_REASON_NO_HOSTILES; +            else if (stricmp(type_str, "BOUNDARY") == 0 || stricmp(type_str, "EVADE_REASON_BOUNDARY") == 0) +                why = CreatureAI::EVADE_REASON_BOUNDARY; +            else if (stricmp(type_str, "SEQUENCE_BREAK") == 0 || stricmp(type_str, "EVADE_REASON_SEQUENCE_BREAK") == 0) +                why = CreatureAI::EVADE_REASON_SEQUENCE_BREAK; +            else if (stricmp(type_str, "FORCE") == 0) +                force = true; +             +            if (!force && force_str) +                if (stricmp(force_str, "FORCE") == 0) +                    force = true; +        } + +        if (force) +            creatureTarget->ClearUnitState(UNIT_STATE_EVADE); +        creatureTarget->AI()->EnterEvadeMode(why); + +        return true; +    } +      static bool HandleNpcAddFormationCommand(ChatHandler* handler, char const* args)      {          if (!*args) @@ -1515,7 +1558,7 @@ public:          if (!pSlotID)              return false; -        char* pItemID = strtok(NULL, " "); +        char* pItemID = strtok(nullptr, " ");          if (!pItemID)              return false; diff --git a/src/server/scripts/Commands/cs_pet.cpp b/src/server/scripts/Commands/cs_pet.cpp index 4f0a179142d..787265cc19b 100644 --- a/src/server/scripts/Commands/cs_pet.cpp +++ b/src/server/scripts/Commands/cs_pet.cpp @@ -22,6 +22,19 @@  #include "ObjectMgr.h"  #include "ScriptMgr.h" +static inline Pet* GetSelectedPlayerPetOrOwn(ChatHandler* handler) +{ +    if (Unit* target = handler->getSelectedUnit()) +    { +        if (target->GetTypeId() == TYPEID_PLAYER) +            return target->ToPlayer()->GetPet(); +        if (target->IsPet()) +            return target->ToPet(); +        return nullptr; +    } +    Player* player = handler->GetSession()->GetPlayer(); +    return player ? player->GetPet() : nullptr; +}  class pet_commandscript : public CommandScript  {  public: @@ -34,6 +47,7 @@ public:              { "create",  rbac::RBAC_PERM_COMMAND_PET_CREATE,  false, &HandlePetCreateCommand,  "" },              { "learn",   rbac::RBAC_PERM_COMMAND_PET_LEARN,   false, &HandlePetLearnCommand,   "" },              { "unlearn", rbac::RBAC_PERM_COMMAND_PET_UNLEARN, false, &HandlePetUnlearnCommand, "" }, +            { "level",   rbac::RBAC_PERM_COMMAND_PET_LEVEL,   false, &HandlePetLevelCommand,   "" },          };          static std::vector<ChatCommand> commandTable = @@ -54,9 +68,9 @@ public:              return false;          } -        CreatureTemplate const* creatrueTemplate = creatureTarget->GetCreatureTemplate(); +        CreatureTemplate const* creatureTemplate = creatureTarget->GetCreatureTemplate();          // Creatures with family 0 crashes the server -        if (!creatrueTemplate->family) +        if (!creatureTemplate->family)          {              handler->PSendSysMessage("This creature cannot be tamed. (family id: 0).");              handler->SetSentErrorMessage(true); @@ -119,12 +133,11 @@ public:          if (!*args)              return false; -        Player* player = handler->GetSession()->GetPlayer(); -        Pet* pet = player->GetPet(); +        Pet* pet = GetSelectedPlayerPetOrOwn(handler);          if (!pet)          { -            handler->PSendSysMessage("You have no pet"); +            handler->SendSysMessage(LANG_SELECT_PLAYER_OR_PET);              handler->SetSentErrorMessage(true);              return false;          } @@ -162,11 +175,10 @@ public:          if (!*args)              return false; -        Player* player = handler->GetSession()->GetPlayer(); -        Pet* pet = player->GetPet(); +        Pet* pet = GetSelectedPlayerPetOrOwn(handler);          if (!pet)          { -            handler->PSendSysMessage("You have no pet"); +            handler->SendSysMessage(LANG_SELECT_PLAYER_OR_PET);              handler->SetSentErrorMessage(true);              return false;          } @@ -180,6 +192,37 @@ public:          return true;      } + +    static bool HandlePetLevelCommand(ChatHandler* handler, char const* args) +    { +        Pet* pet = GetSelectedPlayerPetOrOwn(handler); +        Player* owner = pet ? pet->GetOwner() : nullptr; +        if (!pet || !owner) +        { +            handler->SendSysMessage(LANG_SELECT_PLAYER_OR_PET); +            handler->SetSentErrorMessage(true); +            return false; +        } + +        int32 level = args ? atoi(args) : 0; +        if (level == 0) +            level = owner->getLevel() - pet->getLevel(); +        if (level == 0 || level < -STRONG_MAX_LEVEL || level > STRONG_MAX_LEVEL) +        { +            handler->SendSysMessage(LANG_BAD_VALUE); +            handler->SetSentErrorMessage(true); +            return false; +        } + +        int32 newLevel = pet->getLevel() + level; +        if (newLevel < 1) +            newLevel = 1; +        else if (newLevel > owner->getLevel()) +            newLevel = owner->getLevel(); + +        pet->GivePetLevel(newLevel); +        return true; +    }  };  void AddSC_pet_commandscript() diff --git a/src/server/scripts/Commands/cs_server.cpp b/src/server/scripts/Commands/cs_server.cpp index 83bc2e47674..e0e52d4e1f5 100644 --- a/src/server/scripts/Commands/cs_server.cpp +++ b/src/server/scripts/Commands/cs_server.cpp @@ -29,6 +29,7 @@ EndScriptData */  #include "Player.h"  #include "ScriptMgr.h"  #include "GitRevision.h" +#include "Util.h"  class server_commandscript : public CommandScript  { @@ -52,12 +53,14 @@ public:          static std::vector<ChatCommand> serverRestartCommandTable =          {              { "cancel", rbac::RBAC_PERM_COMMAND_SERVER_RESTART_CANCEL, true, &HandleServerShutDownCancelCommand, "" }, +            { "force",  rbac::RBAC_PERM_COMMAND_SERVER_RESTART_FORCE,  true, &HandleServerForceRestartCommand,   "" },              { ""   ,    rbac::RBAC_PERM_COMMAND_SERVER_RESTART,        true, &HandleServerRestartCommand,        "" },          };          static std::vector<ChatCommand> serverShutdownCommandTable =          {              { "cancel", rbac::RBAC_PERM_COMMAND_SERVER_SHUTDOWN_CANCEL, true, &HandleServerShutDownCancelCommand, "" }, +            { "force",  rbac::RBAC_PERM_COMMAND_SERVER_SHUTDOWN_FORCE,  true, &HandleServerForceShutDownCommand,  "" },              { ""   ,    rbac::RBAC_PERM_COMMAND_SERVER_SHUTDOWN,        true, &HandleServerShutDownCommand,       "" },          }; @@ -73,19 +76,19 @@ public:          {              { "corpses",      rbac::RBAC_PERM_COMMAND_SERVER_CORPSES,      true, &HandleServerCorpsesCommand, "" },              { "exit",         rbac::RBAC_PERM_COMMAND_SERVER_EXIT,         true, &HandleServerExitCommand,    "" }, -            { "idlerestart",  rbac::RBAC_PERM_COMMAND_SERVER_IDLERESTART,  true, NULL,                        "", serverIdleRestartCommandTable }, -            { "idleshutdown", rbac::RBAC_PERM_COMMAND_SERVER_IDLESHUTDOWN, true, NULL,                        "", serverIdleShutdownCommandTable }, +            { "idlerestart",  rbac::RBAC_PERM_COMMAND_SERVER_IDLERESTART,  true, nullptr,                     "", serverIdleRestartCommandTable }, +            { "idleshutdown", rbac::RBAC_PERM_COMMAND_SERVER_IDLESHUTDOWN, true, nullptr,                     "", serverIdleShutdownCommandTable },              { "info",         rbac::RBAC_PERM_COMMAND_SERVER_INFO,         true, &HandleServerInfoCommand,    "" },              { "motd",         rbac::RBAC_PERM_COMMAND_SERVER_MOTD,         true, &HandleServerMotdCommand,    "" },              { "plimit",       rbac::RBAC_PERM_COMMAND_SERVER_PLIMIT,       true, &HandleServerPLimitCommand,  "" }, -            { "restart",      rbac::RBAC_PERM_COMMAND_SERVER_RESTART,      true, NULL,                        "", serverRestartCommandTable }, -            { "shutdown",     rbac::RBAC_PERM_COMMAND_SERVER_SHUTDOWN,     true, NULL,                        "", serverShutdownCommandTable }, -            { "set",          rbac::RBAC_PERM_COMMAND_SERVER_SET,          true, NULL,                        "", serverSetCommandTable }, +            { "restart",      rbac::RBAC_PERM_COMMAND_SERVER_RESTART,      true, nullptr,                     "", serverRestartCommandTable }, +            { "shutdown",     rbac::RBAC_PERM_COMMAND_SERVER_SHUTDOWN,     true, nullptr,                     "", serverShutdownCommandTable }, +            { "set",          rbac::RBAC_PERM_COMMAND_SERVER_SET,          true, nullptr,                     "", serverSetCommandTable },          };          static std::vector<ChatCommand> commandTable =          { -            { "server", rbac::RBAC_PERM_COMMAND_SERVER, true, NULL, "", serverCommandTable }, +            { "server", rbac::RBAC_PERM_COMMAND_SERVER, true, nullptr, "", serverCommandTable },          };          return commandTable;      } @@ -192,19 +195,34 @@ public:          return true;      } -    static bool HandleServerShutDownCommand(ChatHandler* /*handler*/, char const* args) +    static inline bool IsOnlyUser(WorldSession* mySession)      { -        return ShutdownServer(args, 0, SHUTDOWN_EXIT_CODE); +        // check if there is any session connected from a different address +        std::string myAddr = mySession ? mySession->GetRemoteAddress() : ""; +        SessionMap const& sessions = sWorld->GetAllSessions(); +        for (SessionMap::value_type const& session : sessions) +            if (session.second && myAddr != session.second->GetRemoteAddress()) +                return false; +        return true; +    } +    static bool HandleServerShutDownCommand(ChatHandler* handler, char const* args) +    { +        return ShutdownServer(args, IsOnlyUser(handler->GetSession()) ? SHUTDOWN_MASK_FORCE : 0, SHUTDOWN_EXIT_CODE);      } -    static bool HandleServerRestartCommand(ChatHandler* /*handler*/, char const* args) +    static bool HandleServerRestartCommand(ChatHandler* handler, char const* args)      { -        return ShutdownServer(args, SHUTDOWN_MASK_RESTART, RESTART_EXIT_CODE); +        return ShutdownServer(args, IsOnlyUser(handler->GetSession()) ? (SHUTDOWN_MASK_FORCE | SHUTDOWN_MASK_RESTART) : SHUTDOWN_MASK_RESTART, RESTART_EXIT_CODE);      } -    static bool HandleServerIdleRestartCommand(ChatHandler* /*handler*/, char const* args) +    static bool HandleServerForceShutDownCommand(ChatHandler* /*handler*/, char const* args)      { -        return ShutdownServer(args, SHUTDOWN_MASK_RESTART | SHUTDOWN_MASK_IDLE, RESTART_EXIT_CODE); +        return ShutdownServer(args, SHUTDOWN_MASK_FORCE, SHUTDOWN_EXIT_CODE); +    } + +    static bool HandleServerForceRestartCommand(ChatHandler* /*handler*/, char const* args) +    { +        return ShutdownServer(args, SHUTDOWN_MASK_FORCE | SHUTDOWN_MASK_RESTART, RESTART_EXIT_CODE);      }      static bool HandleServerIdleShutDownCommand(ChatHandler* /*handler*/, char const* args) @@ -212,6 +230,11 @@ public:          return ShutdownServer(args, SHUTDOWN_MASK_IDLE, SHUTDOWN_EXIT_CODE);      } +    static bool HandleServerIdleRestartCommand(ChatHandler* /*handler*/, char const* args) +    { +        return ShutdownServer(args, SHUTDOWN_MASK_RESTART | SHUTDOWN_MASK_IDLE, RESTART_EXIT_CODE); +    } +      // Exit the realm      static bool HandleServerExitCommand(ChatHandler* handler, char const* /*args*/)      { @@ -256,8 +279,8 @@ public:              return false;          char* type = strtok((char*)args, " "); -        char* name = strtok(NULL, " "); -        char* level = strtok(NULL, " "); +        char* name = strtok(nullptr, " "); +        char* level = strtok(nullptr, " ");          if (!type || !name || !level || *name == '\0' || *level == '\0' || (*type != 'a' && *type != 'l'))              return false; @@ -313,10 +336,26 @@ private:              return false;          // #delay [#exit_code] [reason] +        int32 delay = 0;          char* delayStr = strtok((char*)args, " "); -        if (!delayStr || !isNumeric(delayStr)) +        if (!delayStr)              return false; +        if (isNumeric(delayStr)) +        { +            delay = atoi(delayStr); +            // Prevent interpret wrong arg value as 0 secs shutdown time +            if ((delay == 0 && (delayStr[0] != '0' || delayStr[1] != '\0')) || delay < 0) +                return false; +        } +        else +        { +            delay = TimeStringToSecs(std::string(delayStr)); + +            if (delay == 0) +                return false; +        } +          char* exitCodeStr = nullptr;          char reason[256] = { 0 }; @@ -337,17 +376,14 @@ private:              }          } -        int32 delay = atoi(delayStr); - -        // Prevent interpret wrong arg value as 0 secs shutdown time -        if ((delay == 0 && (delayStr[0] != '0' || delayStr[1] != '\0')) || delay < 0) -            return false; -          int32 exitCode = defaultExitCode;          if (exitCodeStr)              if (!ParseExitCode(exitCodeStr, exitCode))                  return false; +        if (delay < (int32)sWorld->getIntConfig(CONFIG_FORCE_SHUTDOWN_THRESHOLD) && !(shutdownMask & SHUTDOWN_MASK_FORCE)) +            return false; +          sWorld->ShutdownServ(delay, shutdownMask, static_cast<uint8>(exitCode), std::string(reason));          return true; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp index f7a1c18c234..734b70933aa 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp @@ -894,12 +894,12 @@ public:              if (instance->GetBossState(DATA_HORSEMAN_EVENT) == IN_PROGRESS)                  return false; -            player->AreaExploredOrEventHappens(11405); -            if (Creature* horseman = go->SummonCreature(HH_MOUNTED, FlightPoint[20].x, FlightPoint[20].y, FlightPoint[20].z, 0, TEMPSUMMON_MANUAL_DESPAWN, 0)) -            { -                ENSURE_AI(boss_headless_horseman::boss_headless_horsemanAI, horseman->AI())->PlayerGUID = player->GetGUID(); -                ENSURE_AI(boss_headless_horseman::boss_headless_horsemanAI, horseman->AI())->FlyMode(); -            } +        player->AreaExploredOrEventHappens(11405); +        if (Creature* horseman = go->SummonCreature(HH_MOUNTED, FlightPoint[20].x, FlightPoint[20].y, FlightPoint[20].z, 0, TEMPSUMMON_MANUAL_DESPAWN, 0)) +        { +            ENSURE_AI(boss_headless_horseman::boss_headless_horsemanAI, horseman->AI())->PlayerGUID = player->GetGUID(); +            ENSURE_AI(boss_headless_horseman::boss_headless_horsemanAI, horseman->AI())->FlyMode(); +        }          return true;      }  }; diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp index d86b3707606..7563a880f0a 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp @@ -143,11 +143,7 @@ enum Spells      SPELL_RING_OF_BLUE_FLAMES                   = 45825  //Cast this spell when the go is activated  }; -/*** Error messages ***/ -#define ERROR_KJ_NOT_SUMMONED "TSCR ERROR: Unable to summon Kil'Jaeden for some reason" -  /*** Others ***/ -#define FLOOR_Z         28.050388f  #define SHIELD_ORB_Z    45.000f  enum Phase diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp index 04d23cd7d4e..6c84677708e 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp @@ -15,88 +15,119 @@   * with this program. If not, see <http://www.gnu.org/licenses/>.   */ -/* ScriptData -SDName: Boss_Muru -SD%Complete: 80 -SDComment: all sounds, black hole effect triggers to often (46228) -*/ -  #include "ScriptMgr.h"  #include "ScriptedCreature.h"  #include "sunwell_plateau.h" -#include "Player.h" -#include "SpellInfo.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" -// Muru & Entropius's spells  enum Spells  { -    SPELL_ENRAGE                 = 26662, -      // Muru's spells -    SPELL_NEGATIVE_ENERGY        = 46009, //(this trigger 46008) -    SPELL_DARKNESS               = 45999, -    SPELL_OPEN_ALL_PORTALS       = 46177, -    SPELL_OPEN_PORTAL            = 45977, -    SPELL_OPEN_PORTAL_2          = 45976, -    SPELL_SUMMON_BERSERKER       = 46037, -    SPELL_SUMNON_FURY_MAGE       = 46038, -    SPELL_SUMMON_VOID_SENTINEL   = 45988, -    SPELL_SUMMON_ENTROPIUS       = 46217, +    SPELL_OPEN_PORTAL_PERIODIC                  = 45994, +    SPELL_DARKNESS_PERIODIC                     = 45998, +    SPELL_NEGATIVE_ENERGY_PERIODIC              = 46009, +    SPELL_SUMMON_VOID_SPAWN                     = 46071, +    SPELL_SUMMON_BLOOD_ELVES_SCRIPT             = 46050, +    SPELL_SUMMON_BLOOD_ELVES_PERIODIC           = 46041, +    SPELL_OPEN_ALL_PORTALS                      = 46177, +    SPELL_SUMMON_ENTROPIUS                      = 46217, +    SPELL_ENRAGE                                = 26662, +    SPELL_SUMMON_DARK_FIEND_0                   = 46000, +    SPELL_SUMMON_DARK_FIEND_1                   = 46001, +    SPELL_SUMMON_DARK_FIEND_2                   = 46002, +    SPELL_SUMMON_DARK_FIEND_3                   = 46003, +    SPELL_SUMMON_DARK_FIEND_4                   = 46004, +    SPELL_SUMMON_DARK_FIEND_5                   = 46005, +    SPELL_SUMMON_DARK_FIEND_6                   = 46006, +    SPELL_SUMMON_DARK_FIEND_7                   = 46007, +    SPELL_SUMMON_BERSERKER                      = 46037, +    SPELL_SUMMON_BERSERKER_2                    = 46040, +    SPELL_SUMMON_FURY_MAGE                      = 46038, +    SPELL_SUMMON_FURY_MAGE_2                    = 46039,      // Entropius's spells -    SPELL_DARKNESS_E             = 46269, -    SPELL_BLACKHOLE              = 46282, -    SPELL_NEGATIVE_ENERGY_E      = 46284, -    SPELL_ENTROPIUS_SPAWN        = 46223, - -    // Shadowsword Berserker's spells -    SPELL_FLURRY                 = 46160, -    SPELL_DUAL_WIELD             = 29651, +    SPELL_ENTROPIUS_COSMETIC_SPAWN              = 46223, +    SPELL_DARKNESS_E                            = 46269, +    SPELL_NEGATIVE_ENERGY_PERIODIC_E            = 46284, +    SPELL_BLACKHOLE                             = 46282, +    SPELL_SUMMON_DARKFIEND_E                    = 46263, + +    // Myruu's Portal Target +    SPELL_SUMMON_VOID_SENTINEL_SUMMONER         = 45978, +    SPELL_SUMMON_VOID_SENTINEL_SUMMONER_VISUAL  = 45989, +    SPELL_SUMMON_VOID_SENTINEL                  = 45988, +    SPELL_TRANSFORM_VISUAL_MISSILE              = 46205, +    TRANSFORM_VISUAL_MISSILE_1                  = 46208, +    TRANSFORM_VISUAL_MISSILE_2                  = 46178, +    SPELL_OPEN_PORTAL                           = 45977, +    SPELL_OPEN_PORTAL_2                         = 45976, -    // Shadowsword Fury Mage's spells -    SPELL_FEL_FIREBALL           = 46101, -    SPELL_SPELL_FURY             = 46102, +    //Dark Fiend Spells +    SPELL_DARKFIEND_DAMAGE                      = 45944, +    SPELL_DARKFIEND_VISUAL                      = 45936, +    SPELL_DARKFIEND_SKIN                        = 45934,      // Void Sentinel's spells -    SPELL_SHADOW_PULSE           = 46087, -    SPELL_VOID_BLAST             = 46161, +    SPELL_SHADOW_PULSE_PERIODIC                 = 46086, +    SPELL_VOID_BLAST                            = 46161, -    // Void Spawn's spells -    SPELL_SHADOW_BOLT_VOLLEY     = 46082, +    //Black Hole Spells +    SPELL_BLACKHOLE_SUMMON_VISUAL               = 46242, +    SPELL_BLACKHOLE_SUMMON_VISUAL_2             = 46247, +    SPELL_BLACKHOLE_PASSIVE                     = 46228, +    SPELL_BLACK_HOLE_VISUAL_2                   = 46235 +}; -    //Dark Fiend Spells -    SPELL_DARKFIEND_AOE          = 45944, -    SPELL_DARKFIEND_VISUAL       = 45936, -    SPELL_DARKFIEND_SKIN         = 45934, +enum Phases +{ +    PHASE_ONE                                   = 1, +    PHASE_TWO                                   = 2 +}; -    //Black Hole Spells -    SPELL_BLACKHOLE_SPAWN        = 46242, -    SPELL_BLACKHOLE_GROW         = 46228 +enum Misc +{ +    MAX_VOID_SPAWNS                             = 6, +    MAX_SUMMON_BLOOD_ELVES                      = 4, +    MAX_SUMMON_DARK_FIEND                       = 8  }; -enum Events +uint32 const SummonDarkFiendSpells[MAX_SUMMON_DARK_FIEND] =  { -    // M'uru -    EVENT_DARKNESS = 1, -    EVENT_SUMMON_HUMANOIDS, -    EVENT_SUMMON_SENTINEL, -    EVENT_PHASE_TRANSITION, // Delayed phase transition. -    EVENT_ENRAGE, - -    // Entropius -    EVENT_SUMMON_BLACK_HOLE +    SPELL_SUMMON_DARK_FIEND_0, +    SPELL_SUMMON_DARK_FIEND_1, +    SPELL_SUMMON_DARK_FIEND_2, +    SPELL_SUMMON_DARK_FIEND_3, +    SPELL_SUMMON_DARK_FIEND_4, +    SPELL_SUMMON_DARK_FIEND_5, +    SPELL_SUMMON_DARK_FIEND_6, +    SPELL_SUMMON_DARK_FIEND_7  }; -enum Phases +uint32 const SummonBloodElvesSpells[MAX_SUMMON_BLOOD_ELVES] =  { -    PHASE_ONE = 1, -    PHASE_TWO, +    SPELL_SUMMON_BERSERKER, +    SPELL_SUMMON_BERSERKER_2, +    SPELL_SUMMON_FURY_MAGE, +    SPELL_SUMMON_FURY_MAGE_2  }; -enum CreatureGroups +class VoidSpawnSummon : public BasicEvent  { -    CREATURE_GROUP_HUMANOIDS, -    CREATURE_GROUP_DARKFIENDS +    public: +        explicit VoidSpawnSummon(Creature* owner) +            : _owner(owner) +        { +        } + +        bool Execute(uint64 /*time*/, uint32 /*diff*/) +        { +            _owner->CastSpell((Unit*)nullptr, SPELL_SUMMON_VOID_SENTINEL, true); +            return true; +        } + +    private: +        Creature* _owner;  };  class boss_entropius : public CreatureScript @@ -110,53 +141,78 @@ public:          void Reset() override          { -            DoCastAOE(SPELL_NEGATIVE_ENERGY_E); +            _Reset(); +            DoCast(me, SPELL_ENTROPIUS_COSMETIC_SPAWN, true);          } -        void EnterCombat(Unit* /*who*/) override +        void ScheduleTasks() override          { -            _EnterCombat(); -            DoCastAOE(SPELL_NEGATIVE_ENERGY_E, true); -            DoCast(me, SPELL_ENTROPIUS_SPAWN); -            events.ScheduleEvent(EVENT_SUMMON_BLACK_HOLE, 15000); +            scheduler.Schedule(Milliseconds(2000), [this](TaskContext /*context*/) +            { +                DoResetPortals(); +                DoCastAOE(SPELL_NEGATIVE_ENERGY_PERIODIC_E, true); +            }); + +            scheduler.Schedule(Seconds(15), [this](TaskContext context) +            { +                DoCastAOE(SPELL_DARKNESS_E, true); +                DoCastAOE(SPELL_BLACKHOLE, true); + +                context.Repeat(); +            });          } -        void JustSummoned(Creature* summoned) override +        void JustSummoned(Creature* summon) override          { -            switch (summoned->GetEntry()) +            switch (summon->GetEntry())              {                  case NPC_DARK_FIENDS: -                    summoned->CastSpell(summoned, SPELL_DARKFIEND_VISUAL); +                    summon->CastSpell(summon, SPELL_DARKFIEND_VISUAL);                      break;                  case NPC_DARKNESS: -                    summoned->AddUnitState(UNIT_STATE_STUNNED); -                    float x, y, z, o; -                    summoned->GetHomePosition(x, y, z, o); -                    me->SummonCreature(NPC_DARK_FIENDS, x, y, z, o, TEMPSUMMON_CORPSE_DESPAWN, 0); +                    summon->SetReactState(REACT_PASSIVE); +                    summon->CastSpell(summon, SPELL_BLACKHOLE); +                    summon->CastSpell(summon, SPELL_SUMMON_DARKFIEND_E, true);                      break;              } -            summoned->AI()->AttackStart(SelectTarget(SELECT_TARGET_RANDOM, 0, 50, true)); -            summons.Summon(summoned); +            summons.Summon(summon);          } -        void ExecuteEvent(uint32 eventId) override +        void EnterEvadeMode(EvadeReason /*why*/) override          { -            if (eventId == EVENT_SUMMON_BLACK_HOLE) -            { -                if (Unit* random = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) -                    DoCast(random, SPELL_DARKNESS_E); -                if (Unit* random = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) -                    random->CastSpell(random, SPELL_BLACKHOLE); -                events.ScheduleEvent(EVENT_SUMMON_BLACK_HOLE, 15000); -            } +            if (Creature* muru = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MURU))) +                muru->AI()->EnterEvadeMode(); + +            DoResetPortals(); +            summons.DespawnAll(); +            me->DespawnOrUnsummon();          } -        void EnterEvadeMode(EvadeReason /*why*/) override +        void JustDied(Unit* /*killer*/) override          { +            _JustDied(); +              if (Creature* muru = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MURU))) -                muru->AI()->Reset(); // Reset encounter. -            me->DisappearAndDie(); -            summons.DespawnAll(); +                muru->DisappearAndDie(); +        } + +        void UpdateAI(uint32 diff) override +        { +            if (!UpdateVictim()) +                return; + +            scheduler.Update(diff, [this] +            { +                DoMeleeAttackIfReady(); +            }); +        } + +        void DoResetPortals() +        { +            std::list<Creature*> portals; +            me->GetCreatureListWithEntryInGrid(portals, NPC_MURU_PORTAL_TARGET, 100.0f); +            for (Creature* portal : portals) +                portal->RemoveAllAuras();          }      }; @@ -181,101 +237,96 @@ public:          void Initialize()          { -            DarkFiend = false; -            HasEnraged = false; -            EntropiusGUID.Clear(); +            _hasEnraged = false; +            _phase = PHASE_ONE; +            _entropiusGUID.Clear();          }          void Reset() override          { -            Initialize();              _Reset(); +            Initialize();              me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);              me->SetVisible(true);          } +        void EnterEvadeMode(EvadeReason /*why*/) override +        { +            BossAI::EnterEvadeMode(); +            if (Creature* entropius = ObjectAccessor::GetCreature(*me, _entropiusGUID)) +                entropius->AI()->EnterEvadeMode(); +        } + +        void ScheduleTasks() override +        { +            scheduler.Schedule(Minutes(10), [this](TaskContext /*context*/) +            { +                if (Creature* entropius = ObjectAccessor::GetCreature(*me, _entropiusGUID)) +                    entropius->CastSpell(entropius, SPELL_ENRAGE); +                DoCast(me, SPELL_ENRAGE); +                _hasEnraged = true; +            }); + +            scheduler.Schedule(Seconds(10), [this](TaskContext /*context*/) +            { +                DoCast(me, SPELL_SUMMON_BLOOD_ELVES_SCRIPT, true); +                DoCast(me, SPELL_SUMMON_BLOOD_ELVES_PERIODIC, true); +            }); +        } +          void EnterCombat(Unit* /*who*/) override          {              _EnterCombat(); -            events.SetPhase(PHASE_ONE); -            events.ScheduleEvent(EVENT_ENRAGE, 600000); -            events.ScheduleEvent(EVENT_DARKNESS, 45000, 0, PHASE_ONE); -            events.ScheduleEvent(EVENT_SUMMON_HUMANOIDS, 10000, 0, PHASE_ONE); -            events.ScheduleEvent(EVENT_SUMMON_SENTINEL, 31500, 0, PHASE_ONE); -            DoCastAOE(SPELL_NEGATIVE_ENERGY); +            DoCast(me, SPELL_OPEN_PORTAL_PERIODIC, true); +            DoCast(me, SPELL_DARKNESS_PERIODIC, true); +            DoCast(me, SPELL_NEGATIVE_ENERGY_PERIODIC, true);          }          void DamageTaken(Unit* /*done_by*/, uint32 &damage) override          { -            if (damage >= me->GetHealth() && events.IsInPhase(PHASE_ONE)) +            if (damage >= me->GetHealth())              { -                damage = 0; +                damage = me->GetHealth() - 1; +                if (_phase != PHASE_ONE) +                    return; + +                _phase = PHASE_TWO;                  me->RemoveAllAuras(); -                DoCast(me, SPELL_OPEN_ALL_PORTALS); +                DoCast(me, SPELL_OPEN_ALL_PORTALS, true);                  me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                events.SetPhase(PHASE_TWO); -                events.ScheduleEvent(EVENT_PHASE_TRANSITION, 2000); + +                scheduler.Schedule(Seconds(6), [this](TaskContext /*context*/) +                { +                    DoCast(me, SPELL_SUMMON_ENTROPIUS, true); +                });              }          } -        void JustSummoned(Creature* summoned) override +        void JustSummoned(Creature* summon) override          { -            switch (summoned->GetEntry()) +            if (summon->GetEntry() == NPC_ENTROPIUS)              { -                case NPC_ENTROPIUS: -                    me->SetVisible(false); -                    EntropiusGUID = summoned->GetGUID(); -                    if (HasEnraged) // If we hit phase transition while enraged, enrage Entropius as well. -                        summoned->CastSpell(summoned, SPELL_ENRAGE); -                    break; -                case NPC_DARK_FIENDS: -                    summoned->CastSpell(summoned, SPELL_DARKFIEND_VISUAL); -                    break; +                me->SetVisible(false); +                _entropiusGUID = summon->GetGUID(); +                if (_hasEnraged) +                    summon->CastSpell(summon, SPELL_ENRAGE, true); +                return;              } -            summoned->AI()->AttackStart(SelectTarget(SELECT_TARGET_RANDOM, 0, 50, true)); -            summons.Summon(summoned); +            BossAI::JustSummoned(summon);          } -        void ExecuteEvent(uint32 eventId) override +        void UpdateAI(uint32 diff) override          { -            switch (eventId) -            { -                case EVENT_DARKNESS: -                    if (!DarkFiend) -                    { -                        DarkFiend = true; -                        DoCastAOE(SPELL_DARKNESS); -                    } -                    else -                        me->SummonCreatureGroup(CREATURE_GROUP_DARKFIENDS); -                    events.ScheduleEvent(EVENT_DARKNESS, DarkFiend ? 3000 : 42000, 0, PHASE_ONE); -                    break; -                case EVENT_SUMMON_HUMANOIDS: -                    me->SummonCreatureGroup(CREATURE_GROUP_HUMANOIDS); -                    events.ScheduleEvent(EVENT_SUMMON_HUMANOIDS, 60000, 0, PHASE_ONE); -                    break; -                case EVENT_SUMMON_SENTINEL: -                    DoCastAOE(SPELL_OPEN_PORTAL_2); -                    events.ScheduleEvent(EVENT_SUMMON_SENTINEL, 30000, 0, PHASE_ONE); -                    break; -                case EVENT_PHASE_TRANSITION: -                    DoCast(me, SPELL_SUMMON_ENTROPIUS); -                    break; -                case EVENT_ENRAGE: -                    if (Creature* entropius = ObjectAccessor::GetCreature(*me, EntropiusGUID)) -                        entropius->CastSpell(entropius, SPELL_ENRAGE); -                    DoCast(me, SPELL_ENRAGE); -                    HasEnraged = true; -                    break; -                default: -                    break; -            } +            if (!UpdateVictim()) +                return; + +            scheduler.Update(diff);          }      private: -        bool DarkFiend; -        bool HasEnraged; -        ObjectGuid EntropiusGUID; +        ObjectGuid _entropiusGUID; +        bool _hasEnraged; +        uint8 _phase;      };      CreatureAI* GetAI(Creature* creature) const override @@ -289,89 +340,50 @@ class npc_muru_portal : public CreatureScript  public:      npc_muru_portal() : CreatureScript("npc_muru_portal") { } -    CreatureAI* GetAI(Creature* creature) const override -    { -        return GetInstanceAI<npc_muru_portalAI>(creature); -    } -      struct npc_muru_portalAI : public ScriptedAI      { -        npc_muru_portalAI(Creature* creature) : ScriptedAI(creature), Summons(creature) -        { -            Initialize(); -            SetCombatMovement(false); -            instance = creature->GetInstanceScript(); -        } - -        void Initialize() -        { -            SummonTimer = 5000; - -            InAction = false; -            SummonSentinel = false; -        } - -        InstanceScript* instance; - -        SummonList Summons; - -        bool SummonSentinel; -        bool InAction; - -        uint32 SummonTimer; - -        void Reset() override -        { -            Initialize(); +        npc_muru_portalAI(Creature* creature) : ScriptedAI(creature) { } -            me->AddUnitState(UNIT_STATE_STUNNED); - -            Summons.DespawnAll(); -        } - -        void JustSummoned(Creature* summoned) override +        void JustSummoned(Creature* summon) override          { -            if (Player* target = ObjectAccessor::GetPlayer(*me, instance->GetGuidData(DATA_PLAYER_GUID))) -                summoned->AI()->AttackStart(target); +            DoCast(summon, SPELL_SUMMON_VOID_SENTINEL_SUMMONER_VISUAL, true); -            Summons.Summon(summoned); +            summon->m_Events.AddEvent(new VoidSpawnSummon(summon), summon->m_Events.CalculateTime(1500));          } -        void SpellHit(Unit* /*caster*/, const SpellInfo* Spell) override +        void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override          { -            float x, y, z, o; -            me->GetHomePosition(x, y, z, o); -            me->NearTeleportTo(x, y, z, o); -            InAction = true; -            switch (Spell->Id) +            switch (spell->Id)              {                  case SPELL_OPEN_ALL_PORTALS: -                    DoCastAOE(SPELL_OPEN_PORTAL); +                    DoCastAOE(SPELL_OPEN_PORTAL, true); +                    DoCastAOE(SPELL_TRANSFORM_VISUAL_MISSILE, true);                      break;                  case SPELL_OPEN_PORTAL_2: -                    DoCastAOE(SPELL_OPEN_PORTAL); -                    SummonSentinel = true; +                    DoCastAOE(SPELL_OPEN_PORTAL, true); +                    _scheduler.Schedule(Seconds(6), [this](TaskContext /*context*/) +                    { +                        DoCastAOE(SPELL_SUMMON_VOID_SENTINEL_SUMMONER, true); +                    }); +                    break; +                default:                      break;              }          }          void UpdateAI(uint32 diff) override          { -            if (!SummonSentinel) -            { -                if (InAction && instance->GetBossState(DATA_MURU) == NOT_STARTED) -                    Reset(); -                return; -            } - -            if (SummonTimer <= diff) -            { -                DoCastAOE(SPELL_SUMMON_VOID_SENTINEL, false); -                SummonTimer = 5000; -                SummonSentinel = false; -            } else SummonTimer -= diff; +            _scheduler.Update(diff);          } + +    private: +        TaskScheduler _scheduler;      }; + +    CreatureAI* GetAI(Creature* creature) const override +    { +        return GetSunwellPlateauAI<npc_muru_portalAI>(creature); +    }  };  class npc_dark_fiend : public CreatureScript @@ -379,11 +391,6 @@ class npc_dark_fiend : public CreatureScript  public:      npc_dark_fiend() : CreatureScript("npc_dark_fiend") { } -    CreatureAI* GetAI(Creature* creature) const override -    { -        return new npc_dark_fiendAI(creature); -    } -      struct npc_dark_fiendAI : public ScriptedAI      {          npc_dark_fiendAI(Creature* creature) : ScriptedAI(creature) @@ -393,54 +400,56 @@ public:          void Initialize()          { -            WaitTimer = 2000; -            InAction = false; -        } +            me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); +            me->SetReactState(REACT_PASSIVE); +            DoCast(me, SPELL_DARKFIEND_SKIN, true); -        uint32 WaitTimer; -        bool InAction; +            _scheduler.Schedule(Seconds(2), [this](TaskContext /*context*/) +            { +                me->SetReactState(REACT_AGGRESSIVE); +                me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -        void Reset() override -        { -            Initialize(); +                if (Creature* _summoner = ObjectAccessor::GetCreature(*me, _summonerGUID)) +                    if (Unit* target = _summoner->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0)) +                        AttackStart(target); +            }); -            me->AddUnitState(UNIT_STATE_STUNNED); +            _scheduler.Schedule(Seconds(3), [this](TaskContext context) +            { +                if (me->IsWithinDist(me->GetVictim(), 5.0f) && me->HasAura(SPELL_DARKFIEND_SKIN)) +                { +                    DoCastAOE(SPELL_DARKFIEND_DAMAGE, false); +                    me->DisappearAndDie(); +                } + +                context.Repeat(Milliseconds(500)); +            });          } -        void SpellHit(Unit* /*caster*/, const SpellInfo* Spell) override +        void IsSummonedBy(Unit* summoner) override          { -            for (uint8 i = 0; i < 3; ++i) -                if (Spell->Effects[i].Effect == 38) -                    me->DisappearAndDie(); +            _summonerGUID = summoner->GetGUID();          } -        void UpdateAI(uint32 diff) override +        bool CanAIAttack(Unit const* /*target*/) const override          { -            if (!UpdateVictim()) -                return; +            return me->HasAura(SPELL_DARKFIEND_SKIN); +        } -            if (WaitTimer <= diff) -            { -                if (!InAction) -                { -                    me->ClearUnitState(UNIT_STATE_STUNNED); -                    DoCastAOE(SPELL_DARKFIEND_SKIN, false); -                    AttackStart(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)); -                    InAction = true; -                    WaitTimer = 500; -                } -                else -                { -                    if (me->IsWithinDist(me->GetVictim(), 5)) -                    { -                        DoCastAOE(SPELL_DARKFIEND_AOE, false); -                        me->DisappearAndDie(); -                    } -                    WaitTimer = 500; -                } -            } else WaitTimer -= diff; +        void UpdateAI(uint32 diff) override +        { +            _scheduler.Update(diff);          } + +    private: +        TaskScheduler _scheduler; +        ObjectGuid _summonerGUID;      }; + +    CreatureAI* GetAI(Creature* creature) const override +    { +        return GetSunwellPlateauAI<npc_dark_fiendAI>(creature); +    }  };  class npc_void_sentinel : public CreatureScript @@ -448,63 +457,54 @@ class npc_void_sentinel : public CreatureScript  public:      npc_void_sentinel() : CreatureScript("npc_void_sentinel") { } -    CreatureAI* GetAI(Creature* creature) const override -    { -        return new npc_void_sentinelAI(creature); -    } -      struct npc_void_sentinelAI : public ScriptedAI      {          npc_void_sentinelAI(Creature* creature) : ScriptedAI(creature)          { -            Initialize(); +            _instance = me->GetInstanceScript();          } -        void Initialize() +        void IsSummonedBy(Unit* /*summoner*/) override          { -            PulseTimer = 3000; -            VoidBlastTimer = 45000; //is this a correct timer? +            if (Creature* muru = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_MURU))) +                muru->AI()->JustSummoned(me);          } -        uint32 PulseTimer; -        uint32 VoidBlastTimer; - -        void Reset() override +        void EnterCombat(Unit* /*who*/) override          { -            Initialize(); +            DoCast(me, SPELL_SHADOW_PULSE_PERIODIC, true); -            float x, y, z, o; -            me->GetHomePosition(x, y, z, o); -            me->NearTeleportTo(x, y, 71, o); +            _scheduler.Schedule(Seconds(45), [this](TaskContext context) +            { +                DoCastVictim(SPELL_VOID_BLAST, false); + +                context.Repeat(); +            });          } -        void JustDied(Unit* killer) override +        void JustDied(Unit* /*killer*/) override          { -            for (uint8 i = 0; i < 8; ++i) -                if (Creature* temp = me->SummonCreature(NPC_VOID_SPAWN, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), float(rand32() % 6), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 180000)) -                    temp->AI()->AttackStart(killer); +            for (uint8 i = 0; i < MAX_VOID_SPAWNS; ++i) +                DoCastAOE(SPELL_SUMMON_VOID_SPAWN, true);          }          void UpdateAI(uint32 diff) override          { -            if (!UpdateVictim()) -                return; - -            if (PulseTimer <= diff) -            { -                DoCastAOE(SPELL_SHADOW_PULSE, true); -                PulseTimer = 3000; -            } else PulseTimer -= diff; - -            if (VoidBlastTimer <= diff) +            _scheduler.Update(diff, [this]              { -                DoCastVictim(SPELL_VOID_BLAST, false); -                VoidBlastTimer = 45000; -            } else VoidBlastTimer -= diff; - -            DoMeleeAttackIfReady(); +                DoMeleeAttackIfReady(); +            });          } + +    private: +        TaskScheduler _scheduler; +        InstanceScript* _instance;      }; + +    CreatureAI* GetAI(Creature* creature) const override +    { +        return GetSunwellPlateauAI<npc_void_sentinelAI>(creature); +    }  };  class npc_blackhole : public CreatureScript @@ -512,84 +512,220 @@ class npc_blackhole : public CreatureScript  public:      npc_blackhole() : CreatureScript("npc_blackhole") { } -    CreatureAI* GetAI(Creature* creature) const override -    { -        return GetInstanceAI<npc_blackholeAI>(creature); -    } -      struct npc_blackholeAI : public ScriptedAI      {          npc_blackholeAI(Creature* creature) : ScriptedAI(creature)          { -            Initialize(); -            instance = creature->GetInstanceScript(); +            _instance = creature->GetInstanceScript();          } -        void Initialize() -        { -            DespawnTimer = 15000; -            SpellTimer = 5000; -            Phase = 0; -            NeedForAHack = 0; -        } - -        InstanceScript* instance; - -        uint32 DespawnTimer; -        uint32 SpellTimer; -        uint8 Phase; -        uint8 NeedForAHack; -          void Reset() override          { -            Initialize(); +            me->SetReactState(REACT_PASSIVE); +            DoCast(SPELL_BLACKHOLE_SUMMON_VISUAL); -            me->AddUnitState(UNIT_STATE_STUNNED); -            DoCastAOE(SPELL_BLACKHOLE_SPAWN, true); -        } +            _scheduler.Schedule(Seconds(15), [this](TaskContext /*context*/) +            { +                me->DisappearAndDie(); +            }); -        void UpdateAI(uint32 diff) override -        { -            if (SpellTimer <= diff) +            _scheduler.Schedule(Seconds(1), [this](TaskContext context)              { -                Unit* Victim = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_PLAYER_GUID)); -                switch (NeedForAHack) +                switch (context.GetRepeatCounter())                  {                      case 0: -                        me->ClearUnitState(UNIT_STATE_STUNNED); -                        DoCastAOE(SPELL_BLACKHOLE_GROW, false); -                        if (Victim) -                            AttackStart(Victim); -                        SpellTimer = 700; -                        NeedForAHack = 2; +                        me->SetReactState(REACT_AGGRESSIVE); +                        DoCast(SPELL_BLACKHOLE_SUMMON_VISUAL_2); +                        if (Unit* victim = ObjectAccessor::GetUnit(*me, _instance->GetGuidData(DATA_PLAYER_GUID))) +                            AttackStart(victim); +                        context.Repeat(Milliseconds(1200));                          break;                      case 1: -                        me->AddAura(SPELL_BLACKHOLE_GROW, me); -                        NeedForAHack = 2; -                        SpellTimer = 600; +                        DoCast(SPELL_BLACKHOLE_SUMMON_VISUAL); +                        context.Repeat(Seconds(2));                          break;                      case 2: -                        SpellTimer = 400; -                        NeedForAHack = 3; -                        me->RemoveAura(SPELL_BLACKHOLE_GROW); +                        DoCast(SPELL_BLACKHOLE_PASSIVE); +                        DoCast(SPELL_BLACK_HOLE_VISUAL_2); +                        break; +                    default:                          break; -                    case 3: -                        SpellTimer = urand(400, 900); -                        NeedForAHack = 1; -                        if (Unit* Temp = me->GetVictim()) -                        { -                            if (Temp->GetPositionZ() > 73 && Victim) -                                AttackStart(Victim); -                        } else -                            return;                  } -            } else SpellTimer -= diff; +            }); +        } -            if (DespawnTimer <= diff) -                me->DisappearAndDie(); -            else DespawnTimer -= diff; +        void UpdateAI(uint32 diff) override +        { +            _scheduler.Update(diff);          } + +    private: +        TaskScheduler _scheduler; +        InstanceScript* _instance;      }; + +    CreatureAI* GetAI(Creature* creature) const override +    { +        return GetSunwellPlateauAI<npc_blackholeAI>(creature); +    } +}; + +class spell_summon_blood_elves_script : SpellScriptLoader +{ +    public: +        spell_summon_blood_elves_script() : SpellScriptLoader("spell_summon_blood_elves_script") { } + +        class spell_summon_blood_elves_script_SpellScript : public SpellScript +        { +            PrepareSpellScript(spell_summon_blood_elves_script_SpellScript); + +            bool Validate(SpellInfo const* /*spell*/) override +            { +                for (uint8 i = 0; i < MAX_SUMMON_BLOOD_ELVES; ++i) +                    if (!sSpellMgr->GetSpellInfo(SummonBloodElvesSpells[i])) +                        return false; +                return true; +            } + +            void HandleScript(SpellEffIndex /*effIndex*/) +            { +                for (uint8 i = 0; i < MAX_SUMMON_BLOOD_ELVES; ++i) +                    GetCaster()->CastSpell((Unit*)nullptr, SummonBloodElvesSpells[urand(0,3)], true); +            } + +            void Register() override +            { +                OnEffectHitTarget += SpellEffectFn(spell_summon_blood_elves_script_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); +            } +        }; + +        SpellScript* GetSpellScript() const override +        { +            return new spell_summon_blood_elves_script_SpellScript(); +        } +}; + +class spell_muru_darkness : SpellScriptLoader +{ +    public: +        spell_muru_darkness() : SpellScriptLoader("spell_muru_darkness") { } + +        class spell_muru_darkness_SpellScript : public SpellScript +        { +            PrepareSpellScript(spell_muru_darkness_SpellScript); + +            bool Validate(SpellInfo const* /*spell*/) override +            { +                for (uint8 i = 0; i < MAX_SUMMON_DARK_FIEND; ++i) +                    if (!sSpellMgr->GetSpellInfo(SummonDarkFiendSpells[i])) +                        return false; +                return true; +            } + +            void HandleAfterCast() +            { +                for (uint8 i = 0; i < MAX_SUMMON_DARK_FIEND; ++i) +                    GetCaster()->CastSpell((Unit*)nullptr, SummonDarkFiendSpells[i], true); +            } + +            void Register() override +            { +                AfterCast += SpellCastFn(spell_muru_darkness_SpellScript::HandleAfterCast); +            } +        }; + +        SpellScript* GetSpellScript() const override +        { +            return new spell_muru_darkness_SpellScript(); +        } +}; + +class spell_dark_fiend_skin : public SpellScriptLoader +{ +    public: +        spell_dark_fiend_skin() : SpellScriptLoader("spell_dark_fiend_skin") { } + +        class spell_dark_fiend_skin_AuraScript : public AuraScript +        { +            PrepareAuraScript(spell_dark_fiend_skin_AuraScript); + +            void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) +            { +                if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_ENEMY_SPELL) +                    return; + +                if (Creature* target = GetTarget()->ToCreature()) +                { +                    target->SetReactState(REACT_PASSIVE); +                    target->AttackStop(); +                    target->StopMoving(); +                    target->CastSpell(target, SPELL_DARKFIEND_VISUAL, true); +                    target->DespawnOrUnsummon(3000); +                } +            } + +            void Register() override +            { +                AfterEffectRemove += AuraEffectRemoveFn(spell_dark_fiend_skin_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); +            } +        }; + +        AuraScript* GetAuraScript() const override +        { +            return new spell_dark_fiend_skin_AuraScript(); +        } +}; + +class spell_transform_visual_missile_periodic : public SpellScriptLoader +{ +    public: +        spell_transform_visual_missile_periodic() : SpellScriptLoader("spell_transform_visual_missile_periodic") { } + +        class spell_transform_visual_missile_periodic_AuraScript : public AuraScript +        { +            PrepareAuraScript(spell_transform_visual_missile_periodic_AuraScript); + +            void OnPeriodic(AuraEffect const* /*aurEff*/) +            { +                GetTarget()->CastSpell((Unit*)nullptr, RAND(TRANSFORM_VISUAL_MISSILE_1, TRANSFORM_VISUAL_MISSILE_2), true); +            } + +            void Register() override +            { +                OnEffectPeriodic += AuraEffectPeriodicFn(spell_transform_visual_missile_periodic_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); +            } +        }; + +        AuraScript* GetAuraScript() const override +        { +            return new spell_transform_visual_missile_periodic_AuraScript(); +        } +}; + +class spell_summon_blood_elves_periodic : public SpellScriptLoader +{ +    public: +        spell_summon_blood_elves_periodic() : SpellScriptLoader("spell_summon_blood_elves_periodic") { } + +        class spell_summon_blood_elves_periodic_AuraScript : public AuraScript +        { +            PrepareAuraScript(spell_summon_blood_elves_periodic_AuraScript); + +            void OnPeriodic(AuraEffect const* /*aurEff*/) +            { +                GetTarget()->CastSpell((Unit*)nullptr, SPELL_SUMMON_BLOOD_ELVES_SCRIPT, true); +            } + +            void Register() override +            { +                OnEffectPeriodic += AuraEffectPeriodicFn(spell_summon_blood_elves_periodic_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); +            } +        }; + +        AuraScript* GetAuraScript() const override +        { +            return new spell_summon_blood_elves_periodic_AuraScript(); +        }  };  void AddSC_boss_muru() @@ -600,4 +736,9 @@ void AddSC_boss_muru()      new npc_dark_fiend();      new npc_void_sentinel();      new npc_blackhole(); +    new spell_summon_blood_elves_script(); +    new spell_muru_darkness(); +    new spell_dark_fiend_skin(); +    new spell_transform_visual_missile_periodic(); +    new spell_summon_blood_elves_periodic();  } diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h b/src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h index c6b4ae753a5..7ea0fc4bc7d 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h @@ -97,7 +97,8 @@ enum CreatureIds      NPC_FURY_MAGE                            = 25799,      NPC_VOID_SENTINEL                        = 25772,      NPC_VOID_SPAWN                           = 25824, -    NPC_BLACK_HOLE                           = 25855 +    NPC_BLACK_HOLE                           = 25855, +    NPC_MURU_PORTAL_TARGET                   = 25770  };  enum GameObjectIds diff --git a/src/server/scripts/Kalimdor/BlackfathomDeeps/instance_blackfathom_deeps.cpp b/src/server/scripts/Kalimdor/BlackfathomDeeps/instance_blackfathom_deeps.cpp index b0d6e782052..03c957fa221 100644 --- a/src/server/scripts/Kalimdor/BlackfathomDeeps/instance_blackfathom_deeps.cpp +++ b/src/server/scripts/Kalimdor/BlackfathomDeeps/instance_blackfathom_deeps.cpp @@ -174,7 +174,7 @@ public:                      if (state == DONE)                          if (GameObject* go = instance->GetGameObject(shrineOfGelihastGUID))                              go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); -                        break; +                    break;                  case DATA_AKU_MAI:                      if (state == DONE)                          if (GameObject* go = instance->GetGameObject(altarOfTheDeepsGUID)) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp index 0526dcfa630..8e53ab06ca5 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp @@ -535,12 +535,12 @@ public:              if (!UpdateVictim())                  return; -                 /// @todo add his abilities'n-crap here -                if (!LowHp && HealthBelowPct(20)) -                { -                    Talk(SAY_TH_RANDOM_LOW_HP); -                    LowHp = true; -                } +            /// @todo add his abilities'n-crap here +            if (!LowHp && HealthBelowPct(20)) +            { +                Talk(SAY_TH_RANDOM_LOW_HP); +                LowHp = true; +            }          }      }; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp index 8715f3ca0f6..4d0f80d502d 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp @@ -106,33 +106,33 @@ public:              if (!UpdateVictim())                  return; -                events.Update(diff); +            events.Update(diff); -                if (me->HasUnitState(UNIT_STATE_CASTING)) -                    return; +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; -                while (uint32 eventId = events.ExecuteEvent()) +            while (uint32 eventId = events.ExecuteEvent()) +            { +                switch (eventId)                  { -                    switch (eventId) -                    { -                        case EVENT_SANDBREATH: -                            DoCastVictim(SPELL_SAND_BREATH); -                            events.ScheduleEvent(EVENT_SANDBREATH, urand(15000, 25000)); -                            break; -                        case EVENT_TIMESTOP: -                            DoCastVictim(SPELL_TIME_STOP); -                            events.ScheduleEvent(EVENT_TIMESTOP, urand(20000, 35000)); -                            break; -                        case EVENT_FRENZY: -                             Talk(EMOTE_FRENZY); -                             DoCast(me, SPELL_ENRAGE); -                            events.ScheduleEvent(EVENT_FRENZY, urand(20000, 35000)); -                            break; -                        default: -                            break; -                    } +                    case EVENT_SANDBREATH: +                        DoCastVictim(SPELL_SAND_BREATH); +                        events.ScheduleEvent(EVENT_SANDBREATH, urand(15000, 25000)); +                        break; +                    case EVENT_TIMESTOP: +                        DoCastVictim(SPELL_TIME_STOP); +                        events.ScheduleEvent(EVENT_TIMESTOP, urand(20000, 35000)); +                        break; +                    case EVENT_FRENZY: +                         Talk(EMOTE_FRENZY); +                         DoCast(me, SPELL_ENRAGE); +                        events.ScheduleEvent(EVENT_FRENZY, urand(20000, 35000)); +                        break; +                    default: +                        break;                  } -                DoMeleeAttackIfReady(); +            } +            DoMeleeAttackIfReady();          }      }; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_temporus.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_temporus.cpp index 2befdabe550..844ce239bdf 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_temporus.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_temporus.cpp @@ -107,36 +107,36 @@ public:              if (!UpdateVictim())                  return; -                events.Update(diff); +            events.Update(diff); -                if (me->HasUnitState(UNIT_STATE_CASTING)) -                    return; +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; -                while (uint32 eventId = events.ExecuteEvent()) +            while (uint32 eventId = events.ExecuteEvent()) +            { +                switch (eventId)                  { -                    switch (eventId) -                    { -                        case EVENT_HASTE: -                            DoCast(me, SPELL_HASTE); -                            events.ScheduleEvent(EVENT_HASTE, urand(20000, 25000)); -                            break; -                        case EVENT_MORTAL_WOUND: -                            DoCast(me, SPELL_MORTAL_WOUND); -                            events.ScheduleEvent(EVENT_MORTAL_WOUND, urand(10000, 20000)); -                            break; -                        case EVENT_WING_BUFFET: -                             DoCast(me, SPELL_WING_BUFFET); -                            events.ScheduleEvent(EVENT_WING_BUFFET, urand(20000, 30000)); -                            break; -                        case EVENT_SPELL_REFLECTION: // Only in Heroic -                            DoCast(me, SPELL_REFLECT); -                            events.ScheduleEvent(EVENT_SPELL_REFLECTION, urand(25000, 35000)); -                            break; -                        default: -                            break; -                    } +                    case EVENT_HASTE: +                        DoCast(me, SPELL_HASTE); +                        events.ScheduleEvent(EVENT_HASTE, urand(20000, 25000)); +                        break; +                    case EVENT_MORTAL_WOUND: +                        DoCast(me, SPELL_MORTAL_WOUND); +                        events.ScheduleEvent(EVENT_MORTAL_WOUND, urand(10000, 20000)); +                        break; +                    case EVENT_WING_BUFFET: +                         DoCast(me, SPELL_WING_BUFFET); +                        events.ScheduleEvent(EVENT_WING_BUFFET, urand(20000, 30000)); +                        break; +                    case EVENT_SPELL_REFLECTION: // Only in Heroic +                        DoCast(me, SPELL_REFLECT); +                        events.ScheduleEvent(EVENT_SPELL_REFLECTION, urand(25000, 35000)); +                        break; +                    default: +                        break;                  } -                DoMeleeAttackIfReady(); +            } +            DoMeleeAttackIfReady();          }      }; diff --git a/src/server/scripts/Kalimdor/zone_the_barrens.cpp b/src/server/scripts/Kalimdor/zone_the_barrens.cpp index b113615ca50..7a963d066b6 100644 --- a/src/server/scripts/Kalimdor/zone_the_barrens.cpp +++ b/src/server/scripts/Kalimdor/zone_the_barrens.cpp @@ -43,38 +43,37 @@ EndContentData */  ## npc_beaten_corpse  ######*/ -#define GOSSIP_CORPSE "Examine corpse in detail..." -  enum BeatenCorpse  { -    QUEST_LOST_IN_BATTLE    = 4921 +    GOSSIP_OPTION_ID_BEATEN_CORPSE  = 0, +    GOSSIP_MENU_OPTION_INSPECT_BODY = 2871  };  class npc_beaten_corpse : public CreatureScript  { -public: -    npc_beaten_corpse() : CreatureScript("npc_beaten_corpse") { } +    public: +        npc_beaten_corpse() : CreatureScript("npc_beaten_corpse") { } -    bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override -    { -        player->PlayerTalkClass->ClearMenus(); -        if (action == GOSSIP_ACTION_INFO_DEF +1) +        struct npc_beaten_corpseAI : public ScriptedAI          { -            player->SEND_GOSSIP_MENU(3558, creature->GetGUID()); -            player->TalkedToCreature(creature->GetEntry(), creature->GetGUID()); -        } -        return true; -    } - -    bool OnGossipHello(Player* player, Creature* creature) override -    { -        if (player->GetQuestStatus(QUEST_LOST_IN_BATTLE) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(QUEST_LOST_IN_BATTLE) == QUEST_STATUS_COMPLETE) -            player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_CORPSE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); +            npc_beaten_corpseAI(Creature* creature) : ScriptedAI(creature) +            { +            } -        player->SEND_GOSSIP_MENU(3557, creature->GetGUID()); -        return true; -    } +            void sGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override +            { +                if (menuId == GOSSIP_MENU_OPTION_INSPECT_BODY && gossipListId == GOSSIP_OPTION_ID_BEATEN_CORPSE) +                { +                    player->CLOSE_GOSSIP_MENU(); +                    player->TalkedToCreature(me->GetEntry(), me->GetGUID()); +                } +            } +        }; +        CreatureAI* GetAI(Creature* creature) const override +        { +            return new npc_beaten_corpseAI(creature); +        }  };  /*###### diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index caa37465165..1a37d5238d2 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -604,6 +604,7 @@ class npc_ice_tomb : public CreatureScript                      _trappedPlayerGUID.Clear();                      player->RemoveAurasDueToSpell(SPELL_ICE_TOMB_DAMAGE);                      player->RemoveAurasDueToSpell(SPELL_ASPHYXIATION); +                    player->RemoveAurasDueToSpell(SPELL_ICE_TOMB_UNTARGETABLE);                  }              } @@ -1284,9 +1285,9 @@ class spell_sindragosa_ice_tomb : public SpellScriptLoader      public:          spell_sindragosa_ice_tomb() : SpellScriptLoader("spell_sindragosa_ice_tomb_trap") { } -        class spell_sindragosa_ice_tomb_SpellScript : public SpellScript +        class spell_sindragosa_ice_tomb_AuraScript : public AuraScript          { -            PrepareSpellScript(spell_sindragosa_ice_tomb_SpellScript); +            PrepareAuraScript(spell_sindragosa_ice_tomb_AuraScript);              bool Validate(SpellInfo const* /*spell*/) override              { @@ -1297,46 +1298,42 @@ class spell_sindragosa_ice_tomb : public SpellScriptLoader                  return true;              } -            void SummonTomb() +            void PeriodicTick(AuraEffect const* aurEff)              { -                Position pos = GetHitUnit()->GetPosition(); -                if (TempSummon* summon = GetCaster()->SummonCreature(NPC_ICE_TOMB, pos)) +                PreventDefaultAction(); + +                if (aurEff->GetTickNumber() == 1)                  { -                    summon->AI()->SetGUID(GetHitUnit()->GetGUID(), DATA_TRAPPED_PLAYER); -                    if (GameObject* go = summon->SummonGameObject(GO_ICE_BLOCK, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0)) +                    if (Unit* caster = GetCaster())                      { -                        go->SetSpellId(SPELL_ICE_TOMB_DAMAGE); -                        summon->AddGameObject(go); +                        Position pos = GetTarget()->GetPosition(); + +                        if (TempSummon* summon = caster->SummonCreature(NPC_ICE_TOMB, pos)) +                        { +                            summon->AI()->SetGUID(GetTarget()->GetGUID(), DATA_TRAPPED_PLAYER); +                            GetTarget()->CastSpell(GetTarget(), SPELL_ICE_TOMB_UNTARGETABLE); +                            if (GameObject* go = summon->SummonGameObject(GO_ICE_BLOCK, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0)) +                            { +                                go->SetSpellId(SPELL_ICE_TOMB_DAMAGE); +                                summon->AddGameObject(go); +                            } +                        }                      }                  }              } -            void Register() override -            { -                AfterHit += SpellHitFn(spell_sindragosa_ice_tomb_SpellScript::SummonTomb); -            } -        }; - -        class spell_sindragosa_ice_tomb_AuraScript : public AuraScript -        { -            PrepareAuraScript(spell_sindragosa_ice_tomb_AuraScript); - -            void PeriodicTick(AuraEffect const* /*aurEff*/) +            void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)              { -                PreventDefaultAction(); +                GetTarget()->RemoveAurasDueToSpell(SPELL_ICE_TOMB_UNTARGETABLE);              }              void Register() override              {                  OnEffectPeriodic += AuraEffectPeriodicFn(spell_sindragosa_ice_tomb_AuraScript::PeriodicTick, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL); +                AfterEffectRemove += AuraEffectRemoveFn(spell_sindragosa_ice_tomb_AuraScript::HandleRemove, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);              }          }; -        SpellScript* GetSpellScript() const override -        { -            return new spell_sindragosa_ice_tomb_SpellScript(); -        } -          AuraScript* GetAuraScript() const override          {              return new spell_sindragosa_ice_tomb_AuraScript(); diff --git a/src/server/scripts/Northrend/IsleOfConquest/boss_ioc_horde_alliance.cpp b/src/server/scripts/Northrend/IsleOfConquest/boss_ioc_horde_alliance.cpp new file mode 100644 index 00000000000..71d90da21a1 --- /dev/null +++ b/src/server/scripts/Northrend/IsleOfConquest/boss_ioc_horde_alliance.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * 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/>. + */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "BattlegroundIC.h" + +enum BossSpells +{ +    SPELL_BRUTAL_STRIKE       = 58460, +    SPELL_DAGGER_THROW        = 67280, +    SPELL_CRUSHING_LEAP       = 68506, +    SPELL_RAGE                = 66776 +}; + +enum BossEvents +{ +    EVENT_BRUTAL_STRIKE       = 1, +    EVENT_DAGGER_THROW        = 2, +    EVENT_CRUSHING_LEAP       = 3, +    EVENT_CHECK_RANGE         = 4 +}; + +class boss_ioc_horde_alliance : public CreatureScript +{ +public: +    boss_ioc_horde_alliance() : CreatureScript("boss_ioc_horde_alliance") { } + +    struct boss_ioc_horde_allianceAI : public ScriptedAI +    { +        boss_ioc_horde_allianceAI(Creature* creature) : ScriptedAI(creature) { } + +        void Reset() override +        { +            _events.Reset(); + +            uint32 _npcGuard; +            if (me->GetEntry() == NPC_HIGH_COMMANDER_HALFORD_WYRMBANE) +                _npcGuard = NPC_SEVEN_TH_LEGION_INFANTRY; +            else +                _npcGuard = NPC_KOR_KRON_GUARD; + +            std::list<Creature*> guardsList; +            me->GetCreatureListWithEntryInGrid(guardsList, _npcGuard, 100.0f); +            for (std::list<Creature*>::const_iterator itr = guardsList.begin(); itr != guardsList.end(); ++itr) +                (*itr)->Respawn(); +        }; + +        void EnterCombat(Unit* /*who*/) override +        { +            _events.ScheduleEvent(EVENT_BRUTAL_STRIKE, 5 * IN_MILLISECONDS); +            _events.ScheduleEvent(EVENT_DAGGER_THROW,  7 * IN_MILLISECONDS); +            _events.ScheduleEvent(EVENT_CHECK_RANGE,   1 * IN_MILLISECONDS); +            _events.ScheduleEvent(EVENT_CRUSHING_LEAP, 15 * IN_MILLISECONDS); +        } + +        void SpellHit(Unit* caster, SpellInfo const* /*spell*/) override +        { +            if (caster->IsVehicle()) +                me->Kill(caster); +        } + +        void UpdateAI(uint32 diff) override +        { +            if (!UpdateVictim()) +                return; + +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; + +            _events.Update(diff); + +            while (uint32 eventId = _events.ExecuteEvent()) +            { +                switch (eventId) +                { +                    case EVENT_BRUTAL_STRIKE: +                        DoCastVictim(SPELL_BRUTAL_STRIKE); +                        _events.ScheduleEvent(EVENT_BRUTAL_STRIKE, 5 * IN_MILLISECONDS); +                        break; +                    case EVENT_DAGGER_THROW: +                        if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1)) +                            DoCast(target, SPELL_DAGGER_THROW); +                        _events.ScheduleEvent(EVENT_DAGGER_THROW, 7 * IN_MILLISECONDS); +                        break; +                    case EVENT_CRUSHING_LEAP: +                        DoCastVictim(SPELL_CRUSHING_LEAP); +                        _events.ScheduleEvent(EVENT_CRUSHING_LEAP, 25 * IN_MILLISECONDS); +                        break; +                    case EVENT_CHECK_RANGE: +                        if (me->GetDistance(me->GetHomePosition()) > 25.0f) +                            DoCast(me, SPELL_RAGE); +                        else +                            me->RemoveAurasDueToSpell(SPELL_RAGE); +                        _events.ScheduleEvent(EVENT_CHECK_RANGE, 1 * IN_MILLISECONDS); +                        break; +                    default: +                        break; +                } +            } + +            DoMeleeAttackIfReady(); +        } + +    private: +        EventMap _events; +    }; + +    CreatureAI* GetAI(Creature* creature) const +    { +        return new boss_ioc_horde_allianceAI(creature); +    } +}; + +void AddSC_boss_ioc_horde_alliance() +{ +    new boss_ioc_horde_alliance(); +} diff --git a/src/server/scripts/Northrend/isle_of_conquest.cpp b/src/server/scripts/Northrend/IsleOfConquest/isle_of_conquest.cpp index 11cc645f0cb..11cc645f0cb 100644 --- a/src/server/scripts/Northrend/isle_of_conquest.cpp +++ b/src/server/scripts/Northrend/IsleOfConquest/isle_of_conquest.cpp diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index f000d7a3ef7..3d5a6ee8dfb 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -1224,13 +1224,15 @@ public:          void DoAction(int32 /*action*/) override          {              if (Vehicle* vehicleTemp = me->GetVehicleKit()) +            {                  if (vehicleTemp->GetPassenger(0) && vehicleTemp->GetPassenger(0)->GetTypeId() == TYPEID_PLAYER)                  {                      vehicleTemp->RemoveAllPassengers();                      me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);                  } +            } -                me->DespawnOrUnsummon(3*IN_MILLISECONDS); +            me->DespawnOrUnsummon(3*IN_MILLISECONDS);          }          void MovementInform(uint32 type, uint32 id) override diff --git a/src/server/scripts/Northrend/northrend_script_loader.cpp b/src/server/scripts/Northrend/northrend_script_loader.cpp index 7d104b85f6d..d84bb1c4072 100644 --- a/src/server/scripts/Northrend/northrend_script_loader.cpp +++ b/src/server/scripts/Northrend/northrend_script_loader.cpp @@ -178,6 +178,8 @@ void AddSC_boss_baltharus_the_warborn();  void AddSC_boss_saviana_ragefire();  void AddSC_boss_general_zarithrian();  void AddSC_boss_halion(); +void AddSC_isle_of_conquest();           // Isle of Conquest +void AddSC_boss_ioc_horde_alliance();  void AddSC_dalaran();  void AddSC_borean_tundra(); @@ -190,7 +192,6 @@ void AddSC_storm_peaks();  void AddSC_wintergrasp();  void AddSC_zuldrak();  void AddSC_crystalsong_forest(); -void AddSC_isle_of_conquest();  // The name of this function should match:  // void Add${NameOfDirectory}Scripts() @@ -358,6 +359,8 @@ void AddNorthrendScripts()      AddSC_boss_saviana_ragefire();      AddSC_boss_general_zarithrian();      AddSC_boss_halion(); +    AddSC_isle_of_conquest();          // Isle of Conquest +    AddSC_boss_ioc_horde_alliance();      AddSC_dalaran();      AddSC_borean_tundra(); @@ -370,5 +373,4 @@ void AddNorthrendScripts()      AddSC_wintergrasp();      AddSC_zuldrak();      AddSC_crystalsong_forest(); -    AddSC_isle_of_conquest();  } diff --git a/src/server/scripts/Northrend/zone_grizzly_hills.cpp b/src/server/scripts/Northrend/zone_grizzly_hills.cpp index 59802165a94..4eafc1cd94e 100644 --- a/src/server/scripts/Northrend/zone_grizzly_hills.cpp +++ b/src/server/scripts/Northrend/zone_grizzly_hills.cpp @@ -22,6 +22,7 @@  #include "Player.h"  #include "SpellScript.h"  #include "CreatureTextMgr.h" +#include "CombatAI.h"  /*######  ## Quest 12027: Mr. Floppy's Perilous Adventure @@ -854,6 +855,254 @@ class spell_infected_worgen_bite : public SpellScriptLoader          }  }; +/*###### +## Quest: Riding the Red Rocket +######*/ + +enum RedRocket +{ +    SPELL_VEHICLE_WARHEAD_FUSE            = 49107, +    SPELL_ALLIANCE_KILL_CREDIT_TORPEDO    = 49510, +    SPELL_HORDE_KILL_CREDIT_TORPEDO       = 49340, +    NPC_HORDE_LUMBERBOAT                  = 27702, +    NPC_ALLIANCE_LUMBERBOAT               = 27688, +    SPELL_DETONATE                        = 49250 +}; + +class npc_rocket_propelled_warhead : public CreatureScript +{ +public: +    npc_rocket_propelled_warhead() : CreatureScript("npc_rocket_propelled_warhead") { } + +    struct npc_rocket_propelled_warheadAI : public VehicleAI +    { +        npc_rocket_propelled_warheadAI(Creature* creature) : VehicleAI(creature) +        { +            _finished = false; +            _faction = ALLIANCE; +        } + +        void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override +        { +            if (apply && who->ToPlayer()) +            { +                DoCast(me, SPELL_VEHICLE_WARHEAD_FUSE); +                _faction = who->ToPlayer()->GetTeam(); +            } +        } + +        void JustReachedHome() override +        { +            _finished = false; +            me->SetVisible(true); +            me->GetMotionMaster()->Clear(true); +        } + +        void DoAction(int32 /*action*/) override +        { +            FinishQuest(false, _faction); +        } + +        void SpellHit(Unit* caster, SpellInfo const* /*spellInfo*/) override +        { +            if (caster->GetEntry() == NPC_HORDE_LUMBERBOAT || caster->GetEntry() == NPC_ALLIANCE_LUMBERBOAT) +                FinishQuest(true, _faction); +        } + +        void FinishQuest(bool success, uint32 faction) +        { +            if (_finished) +                return; + +            _finished = true; + +            if (success) +                DoCast(me, faction == ALLIANCE ? SPELL_ALLIANCE_KILL_CREDIT_TORPEDO : SPELL_HORDE_KILL_CREDIT_TORPEDO); + +            DoCast(me, SPELL_DETONATE); +            me->RemoveAllAuras(); +            me->SetVisible(false); +            me->GetMotionMaster()->MoveTargetedHome(); +        } + +    private: +        uint32 _faction; +        bool _finished; +    }; + +    CreatureAI* GetAI(Creature* creature) const override +    { +        return new npc_rocket_propelled_warheadAI(creature); +    } +}; + +enum WarheadSpells +{ +    SPELL_WARHEAD_Z_CHECK               = 61678, +    SPELL_WARHEAD_SEEKING_LUMBERSHIP    = 49331, +    SPELL_WARHEAD_FUSE                  = 49181 +}; +// 49107 - Vehicle: Warhead Fuse +class spell_vehicle_warhead_fuse : public SpellScriptLoader +{ +public: +    spell_vehicle_warhead_fuse() : SpellScriptLoader("spell_vehicle_warhead_fuse") { } + +    class spell_vehicle_warhead_fuse_SpellScript : public SpellScript +    { +        PrepareSpellScript(spell_vehicle_warhead_fuse_SpellScript); + +        bool Validate(SpellInfo const* /*spellInfo*/) override +        { +            if (!sSpellMgr->GetSpellInfo(SPELL_WARHEAD_Z_CHECK) || !sSpellMgr->GetSpellInfo(SPELL_WARHEAD_SEEKING_LUMBERSHIP) || !sSpellMgr->GetSpellInfo(SPELL_WARHEAD_FUSE)) +                return false; +            return true; +        } + +        void HandleDummy(SpellEffIndex /*effIndex*/) +        { +            Unit* caster = GetCaster(); + +            caster->CastSpell(caster, SPELL_WARHEAD_Z_CHECK, true); +            caster->CastSpell(caster, SPELL_WARHEAD_SEEKING_LUMBERSHIP, true); +            caster->CastSpell(caster, SPELL_WARHEAD_FUSE, true); +        } + +        void Register() override +        { +            OnEffectHitTarget += SpellEffectFn(spell_vehicle_warhead_fuse_SpellScript::HandleDummy, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); +        } +    }; + +    SpellScript* GetSpellScript() const override +    { +        return new spell_vehicle_warhead_fuse_SpellScript(); +    } +}; + +enum WarheadDenonate +{ +    SPELL_PARACHUTE                     = 66154, +    SPELL_TORPEDO_EXPLOSION             = 49290, +    NPC_ALLIANCE_LUMBERBOAT_EXPLOSIONS  = 27689 +}; +// 49250 - Detonate +class spell_warhead_detonate : public SpellScriptLoader +{ +public: +    spell_warhead_detonate() : SpellScriptLoader("spell_warhead_detonate") { } + +    class spell_warhead_detonate_SpellScript : public SpellScript +    { +        PrepareSpellScript(spell_warhead_detonate_SpellScript); + +        bool Validate(SpellInfo const* /*spellInfo*/) override +        { +            if (!sSpellMgr->GetSpellInfo(SPELL_PARACHUTE) || !sSpellMgr->GetSpellInfo(SPELL_TORPEDO_EXPLOSION)) +                return false; +            return true; +        } + +        void HandleDummy(SpellEffIndex /*effIndex*/) +        { +            Unit* caster = GetCaster(); +            Player* player = GetHitPlayer(); +            if (!player) +                return; + +            player->ExitVehicle(); +            float horizontalSpeed = 3.0f; +            float verticalSpeed = 40.0f; +            player->KnockbackFrom(caster->GetPositionX(), caster->GetPositionY(), horizontalSpeed, verticalSpeed); +            caster->CastSpell(player, SPELL_PARACHUTE, true); + +            std::list<Creature*> explosionBunnys; +            caster->GetCreatureListWithEntryInGrid(explosionBunnys, NPC_ALLIANCE_LUMBERBOAT_EXPLOSIONS, 90.0f); +            for (std::list<Creature*>::const_iterator itr = explosionBunnys.begin(); itr != explosionBunnys.end(); ++itr) +                (*itr)->CastSpell((*itr), SPELL_TORPEDO_EXPLOSION, true); +        } + +        void Register() override +        { +            OnEffectHitTarget += SpellEffectFn(spell_warhead_detonate_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); +        } +    }; + +    SpellScript* GetSpellScript() const override +    { +        return new spell_warhead_detonate_SpellScript(); +    } +}; + +// 61678 - Z Check +class spell_z_check : public SpellScriptLoader +{ +public: +    spell_z_check() : SpellScriptLoader("spell_z_check") { } + +    class spell_z_check_AuraScript : public AuraScript +    { +        PrepareAuraScript(spell_z_check_AuraScript); + +        void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) +        { +            _posZ = GetTarget()->GetPositionZ(); +        } + +        void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) +        { +            PreventDefaultAction(); + +            if (_posZ != GetTarget()->GetPositionZ()) +                if (Creature* target = GetTarget()->ToCreature()) +                    target->AI()->DoAction(0); +        } + +    private: +        float _posZ; + +        void Register() override +        { +            OnEffectApply += AuraEffectApplyFn(spell_z_check_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); +            OnEffectPeriodic += AuraEffectPeriodicFn(spell_z_check_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); +        } +    }; + +    AuraScript* GetAuraScript() const override +    { +        return new spell_z_check_AuraScript(); +    } +}; + +// 49181 - Warhead Fuse +class spell_warhead_fuse : public SpellScriptLoader +{ +public: +    spell_warhead_fuse() : SpellScriptLoader("spell_warhead_fuse") { } + +    class spell_warhead_fuse_AuraScript : public AuraScript +    { +        PrepareAuraScript(spell_warhead_fuse_AuraScript); + +        void HandleOnEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) +        { +            if (Unit* rocketUnit = GetTarget()->GetVehicleBase()) +                if (Creature* rocketCrea = rocketUnit->ToCreature()) +                    rocketCrea->AI()->DoAction(0); +        } + +        void Register() override +        { +            OnEffectRemove += AuraEffectRemoveFn(spell_warhead_fuse_AuraScript::HandleOnEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); +        } +    }; + +    AuraScript* GetAuraScript() const override +    { +        return new spell_warhead_fuse_AuraScript(); +    } +}; +  void AddSC_grizzly_hills()  {      new npc_emily(); @@ -866,4 +1115,9 @@ void AddSC_grizzly_hills()      new npc_lake_frog();      new spell_shredder_delivery();      new spell_infected_worgen_bite(); +    new npc_rocket_propelled_warhead(); +    new spell_z_check(); +    new spell_warhead_detonate(); +    new spell_vehicle_warhead_fuse(); +    new spell_warhead_fuse();  } diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp index 3c651e10a1e..14aeda04a7e 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp @@ -1301,15 +1301,17 @@ public:              EventMaiev Event = EVENT_MAIEV_NULL;              for (uint8 i = 1; i <= MaxTimer; ++i) +            {                  if (Timer[i])                  {                      if (Timer[i] <= diff)                          Event = (EventMaiev)i;                      else Timer[i] -= diff;                  } +            } -                switch (Event) -                { +            switch (Event) +            {                  case EVENT_MAIEV_STEALTH:                      {                          me->SetFullHealth(); @@ -1345,21 +1347,21 @@ public:                      break;                  default:                      break; -                } +            } -                if (HealthBelowPct(50)) -                { -                    me->SetVisible(false); -                    me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); -                    if (Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID)) -                        ENSURE_AI(boss_illidan_stormrage::boss_illidan_stormrageAI, illidan->AI())->DeleteFromThreatList(me->GetGUID()); -                    me->AttackStop(); -                    Timer[EVENT_MAIEV_STEALTH] = 60000; // reappear after 1 minute -                    MaxTimer = 1; -                } +            if (HealthBelowPct(50)) +            { +                me->SetVisible(false); +                me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); +                if (Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID)) +                    ENSURE_AI(boss_illidan_stormrage::boss_illidan_stormrageAI, illidan->AI())->DeleteFromThreatList(me->GetGUID()); +                me->AttackStop(); +                Timer[EVENT_MAIEV_STEALTH] = 60000; // reappear after 1 minute +                MaxTimer = 1; +            } -                if (Phase == PHASE_NORMAL_MAIEV) -                    DoMeleeAttackIfReady(); +            if (Phase == PHASE_NORMAL_MAIEV) +                DoMeleeAttackIfReady();          }      private: diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp index 499550945c6..2592ed3b262 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp @@ -180,24 +180,23 @@ class boss_grand_warlock_nethekurse : public CreatureScript              }              void MoveInLineOfSight(Unit* who) override -              {                  if (!IntroOnce && me->IsWithinDistInMap(who, 30.0f)) -                    { +                {                      if (who->GetTypeId() != TYPEID_PLAYER)                          return; -                        Talk(SAY_INTRO); -                        IntroOnce = true; -                        IsIntroEvent = true; +                    Talk(SAY_INTRO); +                    IntroOnce = true; +                    IsIntroEvent = true; -                        instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS); -                    } +                    instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS); +                } -                    if (IsIntroEvent || !IsMainEvent) -                        return; +                if (IsIntroEvent || !IsMainEvent) +                    return; -                    ScriptedAI::MoveInLineOfSight(who); +                ScriptedAI::MoveInLineOfSight(who);              }              void EnterCombat(Unit* /*who*/) override diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp index 9fd1c5c7388..30b3fd67687 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp @@ -325,86 +325,85 @@ class boss_high_astromancer_solarian : public CreatureScript                      else                          Phase1_Timer-=diff;                  } -                else -                    if (Phase == 2) +                else if (Phase == 2) +                { +                    //10 seconds after Solarian disappears, 12 mobs spawn out of the three portals. +                    me->AttackStop(); +                    me->StopMoving(); +                    if (Phase2_Timer <= diff)                      { -                        //10 seconds after Solarian disappears, 12 mobs spawn out of the three portals. -                        me->AttackStop(); -                        me->StopMoving(); -                        if (Phase2_Timer <= diff) -                        { -                            Phase = 3; -                            for (int i=0; i <= 2; ++i) -                                for (int j=1; j <= 4; j++) -                                    SummonMinion(NPC_SOLARIUM_AGENT, Portals[i][0], Portals[i][1], Portals[i][2]); +                        Phase = 3; +                        for (int i=0; i <= 2; ++i) +                            for (int j=1; j <= 4; j++) +                                SummonMinion(NPC_SOLARIUM_AGENT, Portals[i][0], Portals[i][1], Portals[i][2]); -                            Talk(SAY_SUMMON1); -                            Phase2_Timer = 10000; -                        } -                        else -                            Phase2_Timer -= diff; +                        Talk(SAY_SUMMON1); +                        Phase2_Timer = 10000;                      }                      else -                        if (Phase == 3) -                        { -                            me->AttackStop(); -                            me->StopMoving(); -                            //Check Phase3_Timer -                            if (Phase3_Timer <= diff) -                            { -                                Phase = 1; -                                //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); - -                                for (int j=0; j <= 2; j++) -                                    if (j != i) -                                        SummonMinion(NPC_SOLARIUM_PRIEST, Portals[j][0], Portals[j][1], Portals[j][2]); - -                                me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                                me->SetVisible(true); - -                                Talk(SAY_SUMMON2); -                                AppearDelay = true; -                                Phase3_Timer = 15000; -                            } -                            else -                                Phase3_Timer -= diff; -                        } -                        else -                            if (Phase == 4) -                            { -                                //Fear_Timer -                                if (Fear_Timer <= diff) -                                { -                                    DoCast(me, SPELL_FEAR); -                                    Fear_Timer = 20000; -                                } -                                else -                                    Fear_Timer -= diff; -                                //VoidBolt_Timer -                                if (VoidBolt_Timer <= diff) -                                { -                                    DoCastVictim(SPELL_VOID_BOLT); -                                    VoidBolt_Timer = 10000; -                                } -                                else -                                    VoidBolt_Timer -= diff; -                            } -                            //When Solarian reaches 20% she will transform into a huge void walker. -                            if (Phase != 4 && me->HealthBelowPct(20)) -                            { -                                Phase = 4; -                                //To make sure she wont be invisible or not selecatble -                                me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                                me->SetVisible(true); -                                Talk(SAY_VOIDA); -                                Talk(SAY_VOIDB); -                                me->SetArmor(WV_ARMOR); -                                me->SetDisplayId(MODEL_VOIDWALKER); -                                me->SetObjectScale(defaultsize*2.5f); -                            } +                        Phase2_Timer -= diff; +                } +                else if (Phase == 3) +                { +                    me->AttackStop(); +                    me->StopMoving(); +                    //Check Phase3_Timer +                    if (Phase3_Timer <= diff) +                    { +                        Phase = 1; +                        //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); + +                        for (int j=0; j <= 2; j++) +                            if (j != i) +                                SummonMinion(NPC_SOLARIUM_PRIEST, Portals[j][0], Portals[j][1], Portals[j][2]); + +                        me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +                        me->SetVisible(true); + +                        Talk(SAY_SUMMON2); +                        AppearDelay = true; +                        Phase3_Timer = 15000; +                    } +                    else +                        Phase3_Timer -= diff; +                } +                else if (Phase == 4) +                { +                    //Fear_Timer +                    if (Fear_Timer <= diff) +                    { +                        DoCast(me, SPELL_FEAR); +                        Fear_Timer = 20000; +                    } +                    else +                        Fear_Timer -= diff; +                    //VoidBolt_Timer +                    if (VoidBolt_Timer <= diff) +                    { +                        DoCastVictim(SPELL_VOID_BOLT); +                        VoidBolt_Timer = 10000; +                    } +                    else +                        VoidBolt_Timer -= diff; +                } +                 +                //When Solarian reaches 20% she will transform into a huge void walker. +                if (Phase != 4 && me->HealthBelowPct(20)) +                { +                    Phase = 4; +                    //To make sure she wont be invisible or not selecatble +                    me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +                    me->SetVisible(true); +                    Talk(SAY_VOIDA); +                    Talk(SAY_VOIDB); +                    me->SetArmor(WV_ARMOR); +                    me->SetDisplayId(MODEL_VOIDWALKER); +                    me->SetObjectScale(defaultsize*2.5f); +                } +                                  DoMeleeAttackIfReady();              }          }; diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp index 3094ecd660a..8f2ea5887d2 100644 --- a/src/server/scripts/World/go_scripts.cpp +++ b/src/server/scripts/World/go_scripts.cpp @@ -1171,7 +1171,7 @@ public:                  player->CastSpell(player, SPELL_CLEANSING_SOUL);                  player->SetStandState(UNIT_STAND_STATE_SIT);              } -            return true; +        return true;      }  }; diff --git a/src/server/scripts/World/item_scripts.cpp b/src/server/scripts/World/item_scripts.cpp index f4241ba0819..52174e1b012 100644 --- a/src/server/scripts/World/item_scripts.cpp +++ b/src/server/scripts/World/item_scripts.cpp @@ -57,18 +57,18 @@ public:          //for special scripts          switch (itemId)          { -           case 24538: +            case 24538:                  if (player->GetAreaId() != 3628)                      disabled = true; -                    break; -           case 34489: +                break; +            case 34489:                  if (player->GetZoneId() != 4080)                      disabled = true; -                    break; -           case 34475: -                if (const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(SPELL_ARCANE_CHARGES)) +                break; +            case 34475: +                if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_ARCANE_CHARGES))                      Spell::SendCastResult(player, spellInfo, 1, SPELL_FAILED_NOT_ON_GROUND); -                    break; +                break;          }          // allow use in flight only diff --git a/src/server/shared/DataStores/DBCStore.h b/src/server/shared/DataStores/DBCStore.h index 7c2cab1e36a..b93bbdaea12 100644 --- a/src/server/shared/DataStores/DBCStore.h +++ b/src/server/shared/DataStores/DBCStore.h @@ -25,121 +25,6 @@  #include "DatabaseWorkerPool.h"  #include "Implementation/WorldDatabase.h"  #include "DatabaseEnv.h" -#include <G3D/Vector3.h> -#include <G3D/AABox.h> - - // Structures for M4 file. Source: https://wowdev.wiki -template<typename T> -struct M2SplineKey -{ -    T p0; -    T p1; -    T p2; -}; - -struct M2Header -{ -    char   Magic[4];               // "MD20" -    uint32 Version;                // The version of the format. -    uint32 lName;                  // Length of the model's name including the trailing \0 -    uint32 ofsName;                // Offset to the name, it seems like models can get reloaded by this name.should be unique, i guess. -    uint32 GlobalModelFlags;       // 0x0001: tilt x, 0x0002: tilt y, 0x0008: add 2 fields in header, 0x0020: load .phys data (MoP+), 0x0080: has _lod .skin files (MoP?+), 0x0100: is camera related. -    uint32 nGlobalSequences; -    uint32 ofsGlobalSequences;     // A list of timestamps. -    uint32 nAnimations; -    uint32 ofsAnimations;          // Information about the animations in the model. -    uint32 nAnimationLookup; -    uint32 ofsAnimationLookup;     // Mapping of global IDs to the entries in the Animation sequences block. -    uint32 nBones;                 // MAX_BONES = 0x100 -    uint32 ofsBones;               // Information about the bones in this model. -    uint32 nKeyBoneLookup; -    uint32 ofsKeyBoneLookup;       // Lookup table for key skeletal bones. -    uint32 nVertices; -    uint32 ofsVertices;            // Vertices of the model. -    uint32 nViews;                 // Views (LOD) are now in .skins. -    uint32 nSubmeshAnimations; -    uint32 ofsSubmeshAnimations;   // Submesh color and alpha animations definitions. -    uint32 nTextures; -    uint32 ofsTextures;            // Textures of this model. -    uint32 nTransparency; -    uint32 ofsTransparency;        // Transparency of textures. -    uint32 nUVAnimation; -    uint32 ofsUVAnimation; -    uint32 nTexReplace; -    uint32 ofsTexReplace;          // Replaceable Textures. -    uint32 nRenderFlags; -    uint32 ofsRenderFlags;         // Blending modes / render flags. -    uint32 nBoneLookupTable; -    uint32 ofsBoneLookupTable;     // A bone lookup table. -    uint32 nTexLookup; -    uint32 ofsTexLookup;           // The same for textures. -    uint32 nTexUnits;              // possibly removed with cata?! -    uint32 ofsTexUnits;            // And texture units. Somewhere they have to be too. -    uint32 nTransLookup; -    uint32 ofsTransLookup;         // Everything needs its lookup. Here are the transparencies. -    uint32 nUVAnimLookup; -    uint32 ofsUVAnimLookup; -    G3D::AABox BoundingBox;            // min/max( [1].z, 2.0277779f ) - 0.16f seems to be the maximum camera height -    float  BoundingSphereRadius; -    G3D::AABox CollisionBox; -    float  CollisionSphereRadius; -    uint32 nBoundingTriangles; -    uint32 ofsBoundingTriangles;   // Our bounding volumes. Similar structure like in the old ofsViews. -    uint32 nBoundingVertices; -    uint32 ofsBoundingVertices; -    uint32 nBoundingNormals; -    uint32 ofsBoundingNormals; -    uint32 nAttachments; -    uint32 ofsAttachments;         // Attachments are for weapons etc. -    uint32 nAttachLookup; -    uint32 ofsAttachLookup;        // Of course with a lookup. -    uint32 nEvents; -    uint32 ofsEvents;              // Used for playing sounds when dying and a lot else. -    uint32 nLights; -    uint32 ofsLights;              // Lights are mainly used in loginscreens but in wands and some doodads too. -    uint32 nCameras;               // Format of Cameras changed with version 271! -    uint32 ofsCameras;             // The cameras are present in most models for having a model in the Character-Tab. -    uint32 nCameraLookup; -    uint32 ofsCameraLookup;        // And lookup-time again. -    uint32 nRibbonEmitters; -    uint32 ofsRibbonEmitters;      // Things swirling around. See the CoT-entrance for light-trails. -    uint32 nParticleEmitters; -    uint32 ofsParticleEmitters;    // Spells and weapons, doodads and loginscreens use them. Blood dripping of a blade? Particles. -    uint32 nBlendMaps;             // This has to deal with blending. Exists IFF (flags & 0x8) != 0. When set, textures blending is overriden by the associated array. See M2/WotLK#Blend_mode_overrides -    uint32 ofsBlendMaps;           // Same as above. Points to an array of uint16 of nBlendMaps entries -- From WoD information.}; -}; - -struct M2Array -{ -    uint32_t number; -    uint32 offset_elements; -}; -struct M2Track -{ -    uint16_t interpolation_type; -    uint16_t global_sequence; -    M2Array timestamps; -    M2Array values; -}; - -struct M2Camera -{ -    uint32_t type; // 0: portrait, 1: characterinfo; -1: else (flyby etc.); referenced backwards in the lookup table. -    float fov; // No radians, no degrees. Multiply by 35 to get degrees. -    float far_clip; -    float near_clip; -    M2Track positions; // How the camera's position moves. Should be 3*3 floats. -    G3D::Vector3 position_base; -    M2Track target_positions; // How the target moves. Should be 3*3 floats. -    G3D::Vector3 target_position_base; -    M2Track rolldata; // The camera can have some roll-effect. Its 0 to 2*Pi. -}; - -struct FlyByCamera -{ -    uint32 timeStamp; -    G3D::Vector4 locations; -};  struct SqlDbc  { diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 9e0e1cbada5..ccb784f8c2b 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -1658,6 +1658,14 @@ ListenRange.TextEmote = 40  ListenRange.Yell = 300  # +#    Creature.MovingStopTimeForPlayer +#        Description: Time (in milliseconds) during which creature will not move after +#                     interaction with player. +#        Default: 180000 + +Creature.MovingStopTimeForPlayer = 180000 + +#  ###################################################################################################  ################################################################################################### @@ -1869,6 +1877,13 @@ GM.LowerSecurity = 0  GM.TicketSystem.ChanceOfGMSurvey = 50  # +#    GM.ForceShutdownThreshold +#        Description: Minimum shutdown time in seconds before 'force' is required if other players are connected. +#        Default:     30 + +GM.ForceShutdownThreshold = 30 + +#  ###################################################################################################  ################################################################################################### | 
