aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/authserver/Server/AuthSession.h2
-rw-r--r--src/server/authserver/authserver.conf.dist1
-rw-r--r--src/server/database/Database/DatabaseWorkerPool.h6
-rw-r--r--src/server/database/Database/QueryCallback.h209
-rw-r--r--src/server/game/AI/CoreAI/CombatAI.cpp2
-rw-r--r--src/server/game/AI/CoreAI/PassiveAI.cpp6
-rw-r--r--src/server/game/AI/CoreAI/PassiveAI.h2
-rw-r--r--src/server/game/AI/CoreAI/PetAI.cpp6
-rw-r--r--src/server/game/AI/CoreAI/PetAI.h2
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.h1
-rw-r--r--src/server/game/AI/CreatureAI.cpp33
-rw-r--r--src/server/game/AI/CreatureAI.h5
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.cpp60
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.h4
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp11
-rw-r--r--src/server/game/Accounts/RBAC.h4
-rw-r--r--src/server/game/Achievements/AchievementMgr.cpp11
-rw-r--r--src/server/game/DataStores/DBCEnums.h16
-rw-r--r--src/server/game/DataStores/DBCStores.cpp245
-rw-r--r--src/server/game/DataStores/DBCStores.h4
-rw-r--r--src/server/game/DataStores/DBCStructure.h12
-rw-r--r--src/server/game/DataStores/M2Stores.cpp266
-rw-r--r--src/server/game/DataStores/M2Stores.h36
-rw-r--r--src/server/game/DataStores/M2Structure.h133
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp57
-rw-r--r--src/server/game/Entities/Creature/Creature.h27
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp42
-rw-r--r--src/server/game/Entities/Item/ItemEnchantmentMgr.cpp6
-rw-r--r--src/server/game/Entities/Object/Object.cpp4
-rw-r--r--src/server/game/Entities/Object/Object.h12
-rw-r--r--src/server/game/Entities/Player/CinematicMgr.cpp171
-rw-r--r--src/server/game/Entities/Player/CinematicMgr.h60
-rw-r--r--src/server/game/Entities/Player/Player.cpp197
-rw-r--r--src/server/game/Entities/Player/Player.h47
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp26
-rw-r--r--src/server/game/Entities/Unit/Unit.h1
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp6
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.h4
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp18
-rw-r--r--src/server/game/Handlers/QueryHandler.cpp4
-rw-r--r--src/server/game/Miscellaneous/Language.h6
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp5
-rw-r--r--src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp4
-rw-r--r--src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp11
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp2
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h2
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp2
-rw-r--r--src/server/game/Server/Protocol/PacketLog.cpp4
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp5
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp14
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h2
-rw-r--r--src/server/game/Spells/Spell.cpp29
-rw-r--r--src/server/game/Spells/Spell.h8
-rw-r--r--src/server/game/Spells/SpellEffects.cpp15
-rw-r--r--src/server/game/Spells/SpellHistory.cpp2
-rw-r--r--src/server/game/Spells/SpellMgr.cpp130
-rw-r--r--src/server/game/Spells/SpellMgr.h26
-rw-r--r--src/server/game/World/World.cpp7
-rw-r--r--src/server/game/World/World.h7
-rw-r--r--src/server/scripts/Commands/cs_character.cpp2
-rw-r--r--src/server/scripts/Commands/cs_debug.cpp3
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp2
-rw-r--r--src/server/scripts/Commands/cs_modify.cpp456
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp117
-rw-r--r--src/server/scripts/Commands/cs_pet.cpp59
-rw-r--r--src/server/scripts/Commands/cs_server.cpp78
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp12
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp833
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h3
-rw-r--r--src/server/scripts/Kalimdor/BlackfathomDeeps/instance_blackfathom_deeps.cpp2
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp12
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp46
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_temporus.cpp52
-rw-r--r--src/server/scripts/Kalimdor/zone_the_barrens.cpp43
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp49
-rw-r--r--src/server/scripts/Northrend/IsleOfConquest/boss_ioc_horde_alliance.cpp132
-rw-r--r--src/server/scripts/Northrend/IsleOfConquest/isle_of_conquest.cpp (renamed from src/server/scripts/Northrend/isle_of_conquest.cpp)0
-rw-r--r--src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp4
-rw-r--r--src/server/scripts/Northrend/northrend_script_loader.cpp6
-rw-r--r--src/server/scripts/Northrend/zone_grizzly_hills.cpp254
-rw-r--r--src/server/scripts/Outland/BlackTemple/boss_illidan.cpp32
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp19
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp151
-rw-r--r--src/server/scripts/World/go_scripts.cpp2
-rw-r--r--src/server/scripts/World/item_scripts.cpp14
-rw-r--r--src/server/shared/DataStores/DBCStore.h115
-rw-r--r--src/server/worldserver/worldserver.conf.dist15
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
+
+#
###################################################################################################
###################################################################################################