aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/authserver/Main.cpp112
-rw-r--r--src/server/game/AI/CoreAI/PetAI.cpp7
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.h2
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp4
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp26
-rw-r--r--src/server/game/Accounts/RBAC.h6
-rw-r--r--src/server/game/Battlegrounds/BattlegroundQueue.cpp7
-rw-r--r--src/server/game/Battlegrounds/BattlegroundQueue.h2
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp122
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundSA.h6
-rw-r--r--src/server/game/Chat/Channels/Channel.h2
-rw-r--r--src/server/game/DataStores/DBCStores.cpp6
-rw-r--r--src/server/game/DataStores/DBCStructure.h33
-rw-r--r--src/server/game/DungeonFinding/LFGMgr.cpp6
-rw-r--r--src/server/game/Entities/Corpse/Corpse.cpp1
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp110
-rw-r--r--src/server/game/Entities/Creature/Creature.h34
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp34
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h10
-rw-r--r--src/server/game/Entities/Item/Item.h2
-rw-r--r--src/server/game/Entities/Object/Object.cpp146
-rw-r--r--src/server/game/Entities/Object/Object.h136
-rw-r--r--src/server/game/Entities/Object/ObjectGuid.h12
-rw-r--r--src/server/game/Entities/Object/Position.cpp184
-rw-r--r--src/server/game/Entities/Object/Position.h225
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp107
-rw-r--r--src/server/game/Entities/Pet/Pet.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp557
-rw-r--r--src/server/game/Entities/Player/Player.h44
-rw-r--r--src/server/game/Entities/Totem/Totem.cpp3
-rw-r--r--src/server/game/Entities/Transport/Transport.cpp98
-rw-r--r--src/server/game/Entities/Transport/Transport.h5
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp222
-rw-r--r--src/server/game/Entities/Unit/Unit.h67
-rw-r--r--src/server/game/Events/GameEventMgr.h2
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp70
-rw-r--r--src/server/game/Globals/ObjectMgr.h13
-rw-r--r--src/server/game/Groups/Group.cpp3
-rw-r--r--src/server/game/Groups/Group.h2
-rw-r--r--src/server/game/Handlers/BattleGroundHandler.cpp8
-rw-r--r--src/server/game/Handlers/PetHandler.cpp20
-rw-r--r--src/server/game/Handlers/SpellHandler.cpp2
-rw-r--r--src/server/game/Handlers/TaxiHandler.cpp2
-rw-r--r--src/server/game/Instances/InstanceScript.cpp21
-rw-r--r--src/server/game/Instances/InstanceScript.h1
-rw-r--r--src/server/game/Maps/Map.cpp11
-rw-r--r--src/server/game/Maps/Map.h9
-rw-r--r--src/server/game/Maps/TransportMgr.cpp24
-rw-r--r--src/server/game/Maps/TransportMgr.h2
-rw-r--r--src/server/game/Maps/ZoneScript.h4
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h8
-rw-r--r--src/server/game/Movement/MotionMaster.h2
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp22
-rw-r--r--src/server/game/Movement/Spline/MoveSplineFlag.h8
-rw-r--r--src/server/game/Scripting/ScriptLoader.cpp2
-rw-r--r--src/server/game/Server/Protocol/Opcodes.h8
-rw-r--r--src/server/game/Server/WorldSession.cpp1
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp42
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp28
-rw-r--r--src/server/game/Spells/Spell.cpp89
-rw-r--r--src/server/game/Spells/Spell.h1
-rw-r--r--src/server/game/Spells/SpellEffects.cpp13
-rw-r--r--src/server/game/Spells/SpellHistory.cpp643
-rw-r--r--src/server/game/Spells/SpellHistory.h137
-rw-r--r--src/server/game/Spells/SpellInfo.cpp2
-rw-r--r--src/server/game/Spells/SpellInfo.h1
-rw-r--r--src/server/game/Spells/SpellMgr.cpp5
-rw-r--r--src/server/game/Texts/CreatureTextMgr.cpp26
-rw-r--r--src/server/game/Texts/CreatureTextMgr.h6
-rw-r--r--src/server/game/Warden/Warden.h8
-rw-r--r--src/server/game/Warden/WardenWin.h8
-rw-r--r--src/server/game/World/World.cpp3
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp12
-rw-r--r--src/server/scripts/Commands/cs_modify.cpp46
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp71
-rw-r--r--src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp2
-rw-r--r--src/server/scripts/Kalimdor/zone_moonglade.cpp2
-rw-r--r--src/server/scripts/Kalimdor/zone_winterspring.cpp6
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp2
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp11
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp6
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h12
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp4
-rw-r--r--src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp1
-rw-r--r--src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h3
-rw-r--r--src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp6
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp39
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp20
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp43
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_erekem.cpp45
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp70
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp56
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_moragg.cpp34
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp75
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp40
-rw-r--r--src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp471
-rw-r--r--src/server/scripts/Northrend/VioletHold/violet_hold.cpp190
-rw-r--r--src/server/scripts/Northrend/VioletHold/violet_hold.h71
-rw-r--r--src/server/scripts/Northrend/zone_dragonblight.cpp2
-rw-r--r--src/server/scripts/Northrend/zone_icecrown.cpp48
-rw-r--r--src/server/scripts/Northrend/zone_storm_peaks.cpp1
-rw-r--r--src/server/scripts/OutdoorPvP/OutdoorPvPNA.h8
-rw-r--r--src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp2
-rw-r--r--src/server/scripts/Outland/CMakeLists.txt1
-rw-r--r--src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp4
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp6
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp255
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp255
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h22
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp21
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp35
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp75
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp22
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp123
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/the_eye.h30
-rw-r--r--src/server/scripts/Outland/zone_hellfire_peninsula.cpp472
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp7
-rw-r--r--src/server/scripts/Spells/spell_hunter.cpp19
-rw-r--r--src/server/scripts/Spells/spell_item.cpp17
-rw-r--r--src/server/scripts/Spells/spell_mage.cpp19
-rw-r--r--src/server/scripts/Spells/spell_paladin.cpp5
-rw-r--r--src/server/scripts/Spells/spell_quest.cpp23
-rw-r--r--src/server/scripts/Spells/spell_rogue.cpp45
-rw-r--r--src/server/scripts/Spells/spell_shaman.cpp7
-rw-r--r--src/server/scripts/Spells/spell_warrior.cpp3
-rw-r--r--src/server/scripts/World/npcs_special.cpp57
-rw-r--r--src/server/shared/Cryptography/SHA1.h4
-rw-r--r--src/server/shared/Database/Field.h8
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp7
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.h3
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.cpp213
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.h5
-rw-r--r--src/server/shared/Networking/MessageBuffer.h4
-rw-r--r--src/server/shared/Networking/Socket.h21
-rw-r--r--src/server/shared/PrecompiledHeaders/sharedPCH.h1
-rw-r--r--src/server/shared/Threading/ProducerConsumerQueue.h4
-rw-r--r--src/server/shared/Updater/DBUpdater.cpp19
-rw-r--r--src/server/shared/Utilities/TaskScheduler.cpp208
-rw-r--r--src/server/shared/Utilities/TaskScheduler.h627
-rw-r--r--src/server/worldserver/worldserver.conf.dist2
-rw-r--r--src/tools/map_extractor/mpq_libmpq.cpp2
-rw-r--r--src/tools/map_extractor/mpq_libmpq04.h2
-rw-r--r--src/tools/vmap4_extractor/mpq_libmpq.cpp2
-rw-r--r--src/tools/vmap4_extractor/mpq_libmpq04.h2
147 files changed, 4534 insertions, 3125 deletions
diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp
index c748e9d28a8..15ab1c38925 100644
--- a/src/server/authserver/Main.cpp
+++ b/src/server/authserver/Main.cpp
@@ -46,25 +46,52 @@ using namespace boost::program_options;
# define _TRINITY_REALM_CONFIG "authserver.conf"
#endif
+#if PLATFORM == PLATFORM_WINDOWS
+#include "ServiceWin32.h"
+char serviceName[] = "authserver";
+char serviceLongName[] = "TrinityCore auth service";
+char serviceDescription[] = "TrinityCore World of Warcraft emulator auth service";
+/*
+* -1 - not in service mode
+* 0 - stopped
+* 1 - running
+* 2 - paused
+*/
+int m_ServiceStatus = -1;
+
+boost::asio::deadline_timer* _serviceStatusWatchTimer;
+void ServiceStatusWatcher(boost::system::error_code const& error);
+#endif
+
bool StartDB();
void StopDB();
void SignalHandler(const boost::system::error_code& error, int signalNumber);
void KeepDatabaseAliveHandler(const boost::system::error_code& error);
-variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile);
+variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile, std::string& configService);
-boost::asio::io_service _ioService;
-boost::asio::deadline_timer _dbPingTimer(_ioService);
+boost::asio::io_service* _ioService;
+boost::asio::deadline_timer* _dbPingTimer;
uint32 _dbPingInterval;
LoginDatabaseWorkerPool LoginDatabase;
int main(int argc, char** argv)
{
std::string configFile = _TRINITY_REALM_CONFIG;
- auto vm = GetConsoleArguments(argc, argv, configFile);
+ std::string configService;
+ auto vm = GetConsoleArguments(argc, argv, configFile, configService);
// exit if help is enabled
if (vm.count("help"))
return 0;
+#if PLATFORM == PLATFORM_WINDOWS
+ if (configService.compare("install") == 0)
+ return WinServiceInstall() == true ? 0 : 1;
+ else if (configService.compare("uninstall") == 0)
+ return WinServiceUninstall() == true ? 0 : 1;
+ else if (configService.compare("run") == 0)
+ return WinServiceRun() ? 0 : 1;
+#endif
+
std::string configError;
if (!sConfigMgr->LoadInitial(configFile, configError))
{
@@ -95,13 +122,16 @@ int main(int argc, char** argv)
if (!StartDB())
return 1;
+ _ioService = new boost::asio::io_service();
+
// Get the list of realms for the server
- sRealmList->Initialize(_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20));
+ sRealmList->Initialize(*_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20));
if (sRealmList->size() == 0)
{
TC_LOG_ERROR("server.authserver", "No valid realms specified.");
StopDB();
+ delete _ioService;
return 1;
}
@@ -111,15 +141,16 @@ int main(int argc, char** argv)
{
TC_LOG_ERROR("server.authserver", "Specified port out of allowed range (1-65535)");
StopDB();
+ delete _ioService;
return 1;
}
std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
- sAuthSocketMgr.StartNetwork(_ioService, bindIp, port);
+ sAuthSocketMgr.StartNetwork(*_ioService, bindIp, port);
// Set signal handlers
- boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM);
+ boost::asio::signal_set signals(*_ioService, SIGINT, SIGTERM);
#if PLATFORM == PLATFORM_WINDOWS
signals.add(SIGBREAK);
#endif
@@ -130,20 +161,38 @@ int main(int argc, char** argv)
// Enabled a timed callback for handling the database keep alive ping
_dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30);
- _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval));
- _dbPingTimer.async_wait(KeepDatabaseAliveHandler);
+ _dbPingTimer = new boost::asio::deadline_timer(*_ioService);
+ _dbPingTimer->expires_from_now(boost::posix_time::minutes(_dbPingInterval));
+ _dbPingTimer->async_wait(KeepDatabaseAliveHandler);
+
+#if PLATFORM == PLATFORM_WINDOWS
+ if (m_ServiceStatus != -1)
+ {
+ _serviceStatusWatchTimer = new boost::asio::deadline_timer(*_ioService);
+ _serviceStatusWatchTimer->expires_from_now(boost::posix_time::seconds(1));
+ _serviceStatusWatchTimer->async_wait(ServiceStatusWatcher);
+ }
+#endif
// Start the io service worker loop
- _ioService.run();
+ _ioService->run();
+
+ _dbPingTimer->cancel();
+
+ sAuthSocketMgr.StopNetwork();
// Close the Database Pool and library
StopDB();
TC_LOG_INFO("server.authserver", "Halting process...");
+
+ signals.cancel();
+
+ delete _dbPingTimer;
+ delete _ioService;
return 0;
}
-
/// Initialize connection to the database
bool StartDB()
{
@@ -174,7 +223,7 @@ void StopDB()
void SignalHandler(const boost::system::error_code& error, int /*signalNumber*/)
{
if (!error)
- _ioService.stop();
+ _ioService->stop();
}
void KeepDatabaseAliveHandler(const boost::system::error_code& error)
@@ -184,31 +233,58 @@ void KeepDatabaseAliveHandler(const boost::system::error_code& error)
TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive");
LoginDatabase.KeepAlive();
- _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval));
- _dbPingTimer.async_wait(KeepDatabaseAliveHandler);
+ _dbPingTimer->expires_from_now(boost::posix_time::minutes(_dbPingInterval));
+ _dbPingTimer->async_wait(KeepDatabaseAliveHandler);
}
}
-variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile)
+#if PLATFORM == PLATFORM_WINDOWS
+void ServiceStatusWatcher(boost::system::error_code const& error)
+{
+ if (!error)
+ {
+ if (m_ServiceStatus == 0)
+ {
+ _ioService->stop();
+ delete _serviceStatusWatchTimer;
+ }
+ else
+ {
+ _serviceStatusWatchTimer->expires_from_now(boost::posix_time::seconds(1));
+ _serviceStatusWatchTimer->async_wait(ServiceStatusWatcher);
+ }
+ }
+}
+#endif
+
+variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile, std::string& configService)
{
options_description all("Allowed options");
all.add_options()
("help,h", "print usage message")
("config,c", value<std::string>(&configFile)->default_value(_TRINITY_REALM_CONFIG), "use <arg> as configuration file")
;
+#if PLATFORM == PLATFORM_WINDOWS
+ options_description win("Windows platform specific options");
+ win.add_options()
+ ("service,s", value<std::string>(&configService)->default_value(""), "Windows service options: [install | uninstall]")
+ ;
+
+ all.add(win);
+#endif
variables_map variablesMap;
try
{
store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), variablesMap);
notify(variablesMap);
}
- catch (std::exception& e) {
+ catch (std::exception& e)
+ {
std::cerr << e.what() << "\n";
}
- if (variablesMap.count("help")) {
+ if (variablesMap.count("help"))
std::cout << all << "\n";
- }
return variablesMap;
}
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp
index abb6126ca2c..2522c97de25 100644
--- a/src/server/game/AI/CoreAI/PetAI.cpp
+++ b/src/server/game/AI/CoreAI/PetAI.cpp
@@ -22,6 +22,7 @@
#include "Player.h"
#include "Spell.h"
#include "ObjectAccessor.h"
+#include "SpellHistory.h"
#include "SpellMgr.h"
#include "Creature.h"
#include "Util.h"
@@ -146,15 +147,15 @@ void PetAI::UpdateAI(uint32 diff)
if (!spellInfo)
continue;
- if (me->GetCharmInfo() && me->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo))
+ if (me->GetCharmInfo() && me->GetSpellHistory()->HasGlobalCooldown(spellInfo))
continue;
if (spellInfo->IsPositive())
{
if (spellInfo->CanBeUsedInCombat())
{
- // check spell cooldown
- if (me->HasSpellCooldown(spellInfo->Id))
+ // check spell cooldown & school lock
+ if (!me->GetSpellHistory()->IsReady(spellInfo))
continue;
// Check if we're in combat or commanded to attack
diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h
index 9eafcc30c81..efe55830b1b 100644
--- a/src/server/game/AI/CoreAI/UnitAI.h
+++ b/src/server/game/AI/CoreAI/UnitAI.h
@@ -128,7 +128,7 @@ class UnitAI
virtual void InitializeAI() { if (!me->isDead()) Reset(); }
- virtual void Reset() { };
+ virtual void Reset() { }
// Called when unit is charmed
virtual void OnCharmed(bool apply) = 0;
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index 20a7ca05d93..21a15fa4f99 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -581,7 +581,11 @@ void SmartAI::JustDied(Unit* killer)
{
GetScript()->ProcessEventsFor(SMART_EVENT_DEATH, killer);
if (HasEscortState(SMART_ESCORT_ESCORTING))
+ {
EndPath(true);
+ me->StopMoving();//force stop
+ me->GetMotionMaster()->MoveIdle();
+ }
}
void SmartAI::KilledUnit(Unit* victim)
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index a5698092d69..267c038faaf 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -1321,7 +1321,31 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
case SMART_ACTION_SET_COUNTER:
{
- StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset);
+ if (ObjectList* targets = GetTargets(e, unit))
+ {
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ {
+ if (IsCreature(*itr))
+ {
+ if (SmartAI* ai = CAST_AI(SmartAI, (*itr)->ToCreature()->AI()))
+ ai->GetScript()->StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset);
+ else
+ TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartAI, skipping");
+ }
+ else if (IsGameObject(*itr))
+ {
+ if (SmartGameObjectAI* ai = CAST_AI(SmartGameObjectAI, (*itr)->ToGameObject()->AI()))
+ ai->GetScript()->StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset);
+ else
+ TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartGameObjectAI, skipping");
+ }
+ }
+
+ delete targets;
+ }
+ else
+ StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset);
+
break;
}
case SMART_ACTION_WP_START:
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index 8f9db8d5a27..339788dee01 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -802,6 +802,7 @@ class RBACData
* @return Success or failure (with reason) to grant the permission
*
* Example Usage:
+ * @code
* // previously defined "RBACData* rbac" with proper initialization
* uint32 permissionId = 2;
* if (rbac->GrantRole(permissionId) == RBAC_IN_DENIED_LIST)
@@ -825,6 +826,7 @@ class RBACData
* @return Success or failure (with reason) to deny the permission
*
* Example Usage:
+ * @code
* // previously defined "RBACData* rbac" with proper initialization
* uint32 permissionId = 2;
* if (rbac->DenyRole(permissionId) == RBAC_ID_DOES_NOT_EXISTS)
@@ -849,6 +851,7 @@ class RBACData
* @return Success or failure (with reason) to remove the permission
*
* Example Usage:
+ * @code
* // previously defined "RBACData* rbac" with proper initialization
* uint32 permissionId = 2;
* if (rbac->RevokeRole(permissionId) == RBAC_OK)
@@ -939,9 +942,6 @@ class RBACData
*
* Given a list of permissions, gets all the inherited permissions
* @param permissions The list of permissions to expand
- *
- * @return new list of permissions containing original permissions and
- * all other pemissions that are linked to the original ones
*/
void ExpandPermissions(RBACPermissionContainer& permissions);
diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.cpp b/src/server/game/Battlegrounds/BattlegroundQueue.cpp
index d9db2a9b5d1..43b7acde925 100644
--- a/src/server/game/Battlegrounds/BattlegroundQueue.cpp
+++ b/src/server/game/Battlegrounds/BattlegroundQueue.cpp
@@ -889,7 +889,8 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 /*diff*/, BattlegroundTyp
// (after what time the ratings aren't taken into account when making teams) then
// the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
// else leave the discard time on 0, this way all ratings will be discarded
- uint32 discardTime = getMSTime() - sBattlegroundMgr->GetRatingDiscardTimer();
+ // this has to be signed value - when the server starts, this value would be negative and thus overflow
+ int32 discardTime = getMSTime() - sBattlegroundMgr->GetRatingDiscardTimer();
// we need to find 2 teams which will play next game
GroupsQueueType::iterator itr_teams[BG_TEAMS_COUNT];
@@ -905,7 +906,7 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 /*diff*/, BattlegroundTyp
// if group match conditions, then add it to pool
if (!(*itr2)->IsInvitedToBGInstanceGUID
&& (((*itr2)->ArenaMatchmakerRating >= arenaMinRating && (*itr2)->ArenaMatchmakerRating <= arenaMaxRating)
- || (*itr2)->JoinTime < discardTime))
+ || (int32)(*itr2)->JoinTime < discardTime))
{
itr_teams[found++] = itr2;
team = i;
@@ -923,7 +924,7 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 /*diff*/, BattlegroundTyp
{
if (!(*itr3)->IsInvitedToBGInstanceGUID
&& (((*itr3)->ArenaMatchmakerRating >= arenaMinRating && (*itr3)->ArenaMatchmakerRating <= arenaMaxRating)
- || (*itr3)->JoinTime < discardTime)
+ || (int32)(*itr3)->JoinTime < discardTime)
&& (*itr_teams[0])->ArenaTeamId != (*itr3)->ArenaTeamId)
{
itr_teams[found++] = itr3;
diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.h b/src/server/game/Battlegrounds/BattlegroundQueue.h
index b0adaa4078d..7e8debfd24d 100644
--- a/src/server/game/Battlegrounds/BattlegroundQueue.h
+++ b/src/server/game/Battlegrounds/BattlegroundQueue.h
@@ -106,7 +106,7 @@ class BattlegroundQueue
class SelectionPool
{
public:
- SelectionPool(): PlayerCount(0) { };
+ SelectionPool(): PlayerCount(0) { }
void Init();
bool AddGroup(GroupQueueInfo* ginfo, uint32 desiredCount);
bool KickGroup(uint32 size);
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
index e14e9fadafc..f267bf7c6c6 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
@@ -99,7 +99,7 @@ bool BattlegroundSA::ResetObjs()
for (uint8 i = BG_SA_MAXNPC; i < BG_SA_MAXNPC + BG_SA_MAX_GY; i++)
DelCreature(i);
- for (uint8 i = 0; i < 6; i++)
+ for (uint8 i = 0; i < MAX_GATES; ++i)
GateStatus[i] = BG_SA_GATE_OK;
if (!AddCreature(BG_SA_NpcEntries[BG_SA_NPC_KANRETHAD], BG_SA_NPC_KANRETHAD, BG_SA_NpcSpawnlocs[BG_SA_NPC_KANRETHAD]))
@@ -179,9 +179,6 @@ bool BattlegroundSA::ResetObjs()
GetBGObject(BG_SA_TITAN_RELIC)->SetFaction(atF);
GetBGObject(BG_SA_TITAN_RELIC)->Refresh();
- for (uint8 i = 0; i <= 5; i++)
- GateStatus[i] = BG_SA_GATE_OK;
-
TotalTime = 0;
ShipsStarted = false;
@@ -221,6 +218,8 @@ bool BattlegroundSA::ResetObjs()
GetBGObject(i)->SetFaction(atF);
}
+ UpdateObjectInteractionFlags();
+
for (uint8 i = BG_SA_BOMB; i < BG_SA_MAXOBJ; i++)
{
if (!AddObject(i, BG_SA_ObjEntries[BG_SA_BOMB], BG_SA_ObjSpawnlocs[i], 0, 0, 0, 0, RESPAWN_ONE_DAY))
@@ -481,28 +480,7 @@ void BattlegroundSA::AddPlayer(Player* player)
SendTransportInit(player);
- if (!ShipsStarted)
- {
- if (player->GetTeamId() == Attackers)
- {
- player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
-
- if (urand(0, 1))
- player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f, 0);
- else
- player->TeleportTo(607, 2577.003f, 980.261f, 15.0f, 0.807f, 0);
-
- }
- else
- player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0);
- }
- else
- {
- if (player->GetTeamId() == Attackers)
- player->TeleportTo(607, 1600.381f, -106.263f, 8.8745f, 3.78f, 0);
- else
- player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0);
- }
+ TeleportToEntrancePosition(player);
}
void BattlegroundSA::RemovePlayer(Player* /*player*/, ObjectGuid /*guid*/, uint32 /*team*/) { }
@@ -533,23 +511,31 @@ void BattlegroundSA::TeleportPlayers()
player->ResetAllPowers();
player->CombatStopWithPets(true);
- for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
- if (Player* p = ObjectAccessor::FindPlayer(itr->first))
- p->CastSpell(p, SPELL_PREPARATION, true);
+ player->CastSpell(player, SPELL_PREPARATION, true);
- if (player->GetTeamId() == Attackers)
- {
- player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ TeleportToEntrancePosition(player);
+ }
+ }
+}
- if (urand(0, 1))
- player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f, 0);
- else
- player->TeleportTo(607, 2577.003f, 980.261f, 15.0f, 0.807f, 0);
- }
+void BattlegroundSA::TeleportToEntrancePosition(Player* player)
+{
+ if (player->GetTeamId() == Attackers)
+ {
+ if (!ShipsStarted)
+ {
+ player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+
+ if (urand(0, 1))
+ player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f, 0);
else
- player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0);
+ player->TeleportTo(607, 2577.003f, 980.261f, 15.0f, 0.807f, 0);
}
+ else
+ player->TeleportTo(607, 1600.381f, -106.263f, 8.8745f, 3.78f, 0);
}
+ else
+ player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0);
}
void BattlegroundSA::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker /*= NULL*/)
@@ -628,6 +614,8 @@ void BattlegroundSA::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject*
}
}
}
+
+ UpdateObjectInteractionFlags();
}
else
break;
@@ -711,7 +699,7 @@ WorldSafeLocsEntry const* BattlegroundSA::GetClosestGraveYard(Player* player)
safeloc = BG_SA_GYEntries[BG_SA_DEFENDER_LAST_GY];
closest = sWorldSafeLocsStore.LookupEntry(safeloc);
- nearest = std::sqrt((closest->x - x)*(closest->x - x) + (closest->y - y)*(closest->y - y) + (closest->z - z)*(closest->z - z));
+ nearest = player->GetExactDistSq(closest->x, closest->y, closest->z);
for (uint8 i = BG_SA_RIGHT_CAPTURABLE_GY; i < BG_SA_MAX_GY; i++)
{
@@ -719,7 +707,7 @@ WorldSafeLocsEntry const* BattlegroundSA::GetClosestGraveYard(Player* player)
continue;
ret = sWorldSafeLocsStore.LookupEntry(BG_SA_GYEntries[i]);
- dist = std::sqrt((ret->x - x)*(ret->x - x) + (ret->y - y)*(ret->y - y) + (ret->z - z)*(ret->z - z));
+ dist = player->GetExactDistSq(ret->x, ret->y, ret->z);
if (dist < nearest)
{
closest = ret;
@@ -738,23 +726,66 @@ void BattlegroundSA::SendTime()
UpdateWorldState(BG_SA_TIMER_SEC_DECS, ((end_of_round%60000)%10000)/1000);
}
+bool BattlegroundSA::CanInteractWithObject(uint32 objectId)
+{
+ switch (objectId)
+ {
+ case BG_SA_TITAN_RELIC:
+ if (GateStatus[BG_SA_ANCIENT_GATE] != BG_SA_GATE_DESTROYED || GateStatus[BG_SA_YELLOW_GATE] != BG_SA_GATE_DESTROYED)
+ return false;
+ // no break
+ case BG_SA_CENTRAL_FLAG:
+ if (GateStatus[BG_SA_RED_GATE] != BG_SA_GATE_DESTROYED && GateStatus[BG_SA_PURPLE_GATE] != BG_SA_GATE_DESTROYED)
+ return false;
+ // no break
+ case BG_SA_LEFT_FLAG:
+ case BG_SA_RIGHT_FLAG:
+ if (GateStatus[BG_SA_GREEN_GATE] != BG_SA_GATE_DESTROYED && GateStatus[BG_SA_BLUE_GATE] != BG_SA_GATE_DESTROYED)
+ return false;
+ break;
+ default:
+ ASSERT(false);
+ break;
+ }
+
+ return true;
+}
+
+void BattlegroundSA::UpdateObjectInteractionFlags(uint32 objectId)
+{
+ if (GameObject* go = GetBGObject(objectId))
+ {
+ if (CanInteractWithObject(objectId))
+ go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
+ else
+ go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
+ }
+}
+
+void BattlegroundSA::UpdateObjectInteractionFlags()
+{
+ for (uint8 i = BG_SA_CENTRAL_FLAG; i <= BG_SA_LEFT_FLAG; ++i)
+ UpdateObjectInteractionFlags(i);
+ UpdateObjectInteractionFlags(BG_SA_TITAN_RELIC);
+}
+
void BattlegroundSA::EventPlayerClickedOnFlag(Player* source, GameObject* go)
{
switch (go->GetEntry())
{
case 191307:
case 191308:
- if (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED)
+ if (CanInteractWithObject(BG_SA_LEFT_FLAG))
CaptureGraveyard(BG_SA_LEFT_CAPTURABLE_GY, source);
break;
case 191305:
case 191306:
- if (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED)
+ if (CanInteractWithObject(BG_SA_RIGHT_FLAG))
CaptureGraveyard(BG_SA_RIGHT_CAPTURABLE_GY, source);
break;
case 191310:
case 191309:
- if ((GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED) && (GateStatus[BG_SA_RED_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_PURPLE_GATE] == BG_SA_GATE_DESTROYED))
+ if (CanInteractWithObject(BG_SA_CENTRAL_FLAG))
CaptureGraveyard(BG_SA_CENTRAL_CAPTURABLE_GY, source);
break;
default:
@@ -856,10 +887,7 @@ void BattlegroundSA::TitanRelicActivated(Player* clicker)
if (!clicker)
return;
- if (GateStatus[BG_SA_ANCIENT_GATE] == BG_SA_GATE_DESTROYED &&
- GateStatus[BG_SA_YELLOW_GATE] == BG_SA_GATE_DESTROYED &&
- (GateStatus[BG_SA_PURPLE_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_RED_GATE] == BG_SA_GATE_DESTROYED) &&
- (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED))
+ if (CanInteractWithObject(BG_SA_TITAN_RELIC))
{
if (clicker->GetTeamId() == Attackers)
{
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h
index 7f9a656c979..118cea41a7b 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h
@@ -620,6 +620,7 @@ class BattlegroundSA : public Battleground
* -Teleport all players to good location
*/
void TeleportPlayers();
+ void TeleportToEntrancePosition(Player* player);
/**
* \brief Called on start and between the two round
* -Update faction of all vehicle
@@ -627,6 +628,11 @@ class BattlegroundSA : public Battleground
void OverrideGunFaction();
/// Set selectable or not demolisher, called on battle start, when boats arrive to dock
void DemolisherStartState(bool start);
+ /// Checks if a player can interact with the given object
+ bool CanInteractWithObject(uint32 objectId);
+ /// Updates interaction flags of specific objects
+ void UpdateObjectInteractionFlags(uint32 objectId);
+ void UpdateObjectInteractionFlags();
/**
* \brief Called when a gate is destroy
* -Give honor to player witch destroy it
diff --git a/src/server/game/Chat/Channels/Channel.h b/src/server/game/Chat/Channels/Channel.h
index 9b9c2f1e514..0f2a940e3b4 100644
--- a/src/server/game/Chat/Channels/Channel.h
+++ b/src/server/game/Chat/Channels/Channel.h
@@ -184,7 +184,7 @@ class Channel
void DeVoice(ObjectGuid guid1, ObjectGuid guid2);
void JoinNotify(ObjectGuid guid); // invisible notify
void LeaveNotify(ObjectGuid guid); // invisible notify
- void SetOwnership(bool ownership) { _ownership = ownership; };
+ void SetOwnership(bool ownership) { _ownership = ownership; }
static void CleanOldChannelsInDB();
private:
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index 6586c5035ec..5cd9b363ae0 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -560,8 +560,8 @@ void LoadDBCStores(const std::string& dataPath)
for (uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i)
if (TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i))
{
- if (pathLength[entry->path] < entry->index + 1)
- pathLength[entry->path] = entry->index + 1;
+ if (pathLength[entry->PathID] < entry->NodeIndex + 1)
+ pathLength[entry->PathID] = entry->NodeIndex + 1;
}
// Set path length
sTaxiPathNodesByPath.resize(pathCount); // 0 and some other indexes not used
@@ -570,7 +570,7 @@ void LoadDBCStores(const std::string& dataPath)
// fill data
for (uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i)
if (TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i))
- sTaxiPathNodesByPath[entry->path].set(entry->index, entry);
+ sTaxiPathNodesByPath[entry->PathID].set(entry->NodeIndex, entry);
// Initialize global taxinodes mask
// include existed nodes that have at least single not spell base (scripted) path
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index 5c784f3fe69..5ccd5d2b7e5 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -30,13 +30,7 @@
#include <vector>
// Structures using to access raw DBC data and required packing to portability
-
-// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
-#if defined(__GNUC__)
-#pragma pack(1)
-#else
#pragma pack(push, 1)
-#endif
struct AchievementEntry
{
@@ -1939,17 +1933,17 @@ struct TaxiPathEntry
struct TaxiPathNodeEntry
{
- // 0 m_ID
- uint32 path; // 1 m_PathID
- uint32 index; // 2 m_NodeIndex
- uint32 mapid; // 3 m_ContinentID
- float x; // 4 m_LocX
- float y; // 5 m_LocY
- float z; // 6 m_LocZ
- uint32 actionFlag; // 7 m_flags
- uint32 delay; // 8 m_delay
- uint32 arrivalEventID; // 9 m_arrivalEventID
- uint32 departureEventID; // 10 m_departureEventID
+ // 0 ID
+ uint32 PathID; // 1
+ uint32 NodeIndex; // 2
+ uint32 MapID; // 3
+ float LocX; // 4
+ float LocY; // 5
+ float LocZ; // 6
+ uint32 Flags; // 7
+ uint32 Delay; // 8
+ uint32 ArrivalEventID; // 9
+ uint32 DepartureEventID; // 10
};
struct TeamContributionPointsEntry
@@ -2177,12 +2171,7 @@ struct WorldStateUI
};
*/
-// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
-#if defined(__GNUC__)
-#pragma pack()
-#else
#pragma pack(pop)
-#endif
// Structures not used for casting to loaded DBC data and not required then packing
struct MapDifficulty
diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp
index f07e4e7113f..5ad94948cd0 100644
--- a/src/server/game/DungeonFinding/LFGMgr.cpp
+++ b/src/server/game/DungeonFinding/LFGMgr.cpp
@@ -410,6 +410,8 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const
joinData.result = LFG_JOIN_RANDOM_COOLDOWN;
else if (dungeons.empty())
joinData.result = LFG_JOIN_NOT_MEET_REQS;
+ else if (player->HasAura(9454)) // check Freeze debuff
+ joinData.result = LFG_JOIN_NOT_MEET_REQS;
else if (grp)
{
if (grp->GetMembersCount() > MAXGROUPSIZE)
@@ -429,6 +431,8 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const
joinData.result = LFG_JOIN_PARTY_RANDOM_COOLDOWN;
else if (plrg->InBattleground() || plrg->InArena() || plrg->InBattlegroundQueue())
joinData.result = LFG_JOIN_USING_BG_SYSTEM;
+ else if (plrg->HasAura(9454)) // check Freeze debuff
+ joinData.result = LFG_JOIN_PARTY_NOT_MEET_REQS;
++memberCount;
players.insert(plrg->GetGUID());
}
@@ -1281,6 +1285,8 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
error = LFG_TELEPORTERROR_IN_VEHICLE;
else if (player->GetCharmGUID())
error = LFG_TELEPORTERROR_CHARMING;
+ else if (player->HasAura(9454)) // check Freeze debuff
+ error = LFG_TELEPORTERROR_INVALID_LOCATION;
else if (player->GetMapId() != uint32(dungeon->map)) // Do not teleport players in dungeon to the entrance
{
uint32 mapid = dungeon->map;
diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp
index bf69b4e7443..192a897238a 100644
--- a/src/server/game/Entities/Corpse/Corpse.cpp
+++ b/src/server/game/Entities/Corpse/Corpse.cpp
@@ -169,6 +169,7 @@ bool Corpse::LoadCorpseFromDB(uint32 guid, Field* fields)
Object::_Create(guid, 0, HIGHGUID_CORPSE);
+ SetObjectScale(1.0f);
SetUInt32Value(CORPSE_FIELD_DISPLAY_ID, fields[5].GetUInt32());
_LoadIntoDataField(fields[6].GetCString(), CORPSE_FIELD_ITEM, EQUIPMENT_SLOT_END);
SetUInt32Value(CORPSE_FIELD_BYTES_1, fields[7].GetUInt32());
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 05de671830e..809c76c260a 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -150,8 +150,6 @@ m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(
for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i)
m_spells[i] = 0;
- m_CreatureSpellCooldowns.clear();
- m_CreatureCategoryCooldowns.clear();
DisableReputationGain = false;
m_SightDistance = sWorld->getFloatConfig(CONFIG_SIGHT_MONSTER);
@@ -1372,9 +1370,6 @@ bool Creature::CanStartAttack(Unit const* who, bool force) const
if (IsCivilian())
return false;
- if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC))
- return false;
-
// Do not attack non-combat pets
if (who->GetTypeId() == TYPEID_UNIT && who->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET)
return false;
@@ -2156,83 +2151,6 @@ uint32 Creature::GetShieldBlockValue() const //dunno mob block
return (getLevel()/2 + uint32(GetStat(STAT_STRENGTH)/20));
}
-void Creature::_AddCreatureSpellCooldown(uint32 spell_id, time_t end_time)
-{
- m_CreatureSpellCooldowns[spell_id] = end_time;
-}
-
-void Creature::_AddCreatureCategoryCooldown(uint32 category, time_t apply_time)
-{
- m_CreatureCategoryCooldowns[category] = apply_time;
-}
-
-void Creature::AddCreatureSpellCooldown(uint32 spellid)
-{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid);
- if (!spellInfo)
- return;
-
- uint32 cooldown = spellInfo->GetRecoveryTime();
- if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellid, SPELLMOD_COOLDOWN, cooldown);
-
- if (cooldown)
- _AddCreatureSpellCooldown(spellid, time(NULL) + cooldown/IN_MILLISECONDS);
-
- if (spellInfo->GetCategory())
- _AddCreatureCategoryCooldown(spellInfo->GetCategory(), time(NULL));
-}
-
-bool Creature::HasCategoryCooldown(uint32 spell_id) const
-{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id);
- if (!spellInfo)
- return false;
-
- CreatureSpellCooldowns::const_iterator itr = m_CreatureCategoryCooldowns.find(spellInfo->GetCategory());
- return(itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / IN_MILLISECONDS)) > time(NULL));
-}
-
-uint32 Creature::GetCreatureSpellCooldownDelay(uint32 spellId) const
-{
- CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spellId);
- time_t t = time(NULL);
- return uint32(itr != m_CreatureSpellCooldowns.end() && itr->second > t ? itr->second - t : 0);
-}
-
-bool Creature::HasSpellCooldown(uint32 spell_id) const
-{
- CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spell_id);
- return (itr != m_CreatureSpellCooldowns.end() && itr->second > time(NULL)) || HasCategoryCooldown(spell_id);
-}
-
-void Creature::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs)
-{
- time_t curTime = time(NULL);
- for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i)
- {
- if (m_spells[i] == 0)
- continue;
-
- uint32 unSpellId = m_spells[i];
- SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(unSpellId);
-
- // Not send cooldown for this spells
- if (spellInfo->IsCooldownStartedOnEvent())
- continue;
-
- if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE)
- continue;
-
- if ((idSchoolMask & spellInfo->GetSchoolMask()) && GetCreatureSpellCooldownDelay(unSpellId) < unTimeMs)
- {
- _AddCreatureSpellCooldown(unSpellId, curTime + unTimeMs/IN_MILLISECONDS);
- if (UnitAI* ai = GetAI())
- ai->SpellInterrupted(unSpellId, unTimeMs);
- }
- }
-}
-
bool Creature::HasSpell(uint32 spellID) const
{
uint8 i;
@@ -2494,7 +2412,7 @@ bool Creature::SetSwim(bool enable)
return true;
}
-bool Creature::SetCanFly(bool enable)
+bool Creature::SetCanFly(bool enable, bool /*packetOnly = false */)
{
if (!Unit::SetCanFly(enable))
return false;
@@ -2717,3 +2635,29 @@ void Creature::StartPickPocketRefillTimer()
_pickpocketLootRestore = time(NULL) + sWorld->getIntConfig(CONFIG_CREATURE_PICKPOCKET_REFILL);
}
+void Creature::SetTextRepeatId(uint8 textGroup, uint8 id)
+{
+ CreatureTextRepeatIds& repeats = m_textRepeat[textGroup];
+ if (std::find(repeats.begin(), repeats.end(), id) == repeats.end())
+ repeats.push_back(id);
+ else
+ TC_LOG_ERROR("sql.sql", "CreatureTextMgr: TextGroup %u for Creature(%s) GuidLow %u Entry %u, id %u already added", uint32(textGroup), GetName().c_str(), GetGUIDLow(), GetEntry(), uint32(id));
+}
+
+CreatureTextRepeatIds Creature::GetTextRepeatGroup(uint8 textGroup)
+{
+ CreatureTextRepeatIds ids;
+
+ CreatureTextRepeatGroup::const_iterator groupItr = m_textRepeat.find(textGroup);
+ if (groupItr != m_textRepeat.end())
+ ids = groupItr->second;
+
+ return ids;
+}
+
+void Creature::ClearTextRepeatGroup(uint8 textGroup)
+{
+ CreatureTextRepeatGroup::iterator groupItr = m_textRepeat.find(textGroup);
+ if (groupItr != m_textRepeat.end())
+ groupItr->second.clear();
+}
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index ec06bf90595..585bc137e0b 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -170,12 +170,7 @@ struct CreatureTemplate
// Benchmarked: Faster than std::map (insert/find)
typedef std::unordered_map<uint32, CreatureTemplate> CreatureTemplateContainer;
-// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
-#if defined(__GNUC__)
-#pragma pack(1)
-#else
#pragma pack(push, 1)
-#endif
// Defines base stats for creatures (used to calculate HP/mana/armor/attackpower/rangedattackpower/all damage).
struct CreatureBaseStats
@@ -307,12 +302,7 @@ enum ChatType
CHAT_TYPE_END = 255
};
-// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
-#if defined(__GNUC__)
-#pragma pack()
-#else
#pragma pack(pop)
-#endif
// `creature_addon` table
struct CreatureAddon
@@ -414,13 +404,15 @@ struct TrainerSpellData
TrainerSpell const* Find(uint32 spell_id) const;
};
-typedef std::map<uint32, time_t> CreatureSpellCooldowns;
-
// max different by z coordinate for creature aggro reaction
#define CREATURE_Z_ATTACK_RANGE 3
#define MAX_VENDOR_ITEMS 150 // Limitation in 3.x.x item count in SMSG_LIST_INVENTORY
+//used for handling non-repeatable random texts
+typedef std::vector<uint8> CreatureTextRepeatIds;
+typedef std::unordered_map<uint8, CreatureTextRepeatIds> CreatureTextRepeatGroup;
+
class Creature : public Unit, public GridObject<Creature>, public MapObject
{
public:
@@ -484,7 +476,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
bool SetWalk(bool enable) override;
bool SetDisableGravity(bool disable, bool packetOnly = false) override;
bool SetSwim(bool enable) override;
- bool SetCanFly(bool enable) override;
+ bool SetCanFly(bool enable, bool packetOnly = false) override;
bool SetWaterWalking(bool enable, bool packetOnly = false) override;
bool SetFeatherFall(bool enable, bool packetOnly = false) override;
bool SetHover(bool enable, bool packetOnly = false) override;
@@ -494,14 +486,6 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
SpellSchoolMask GetMeleeDamageSchoolMask() const override { return m_meleeDamageSchoolMask; }
void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); }
- void _AddCreatureSpellCooldown(uint32 spell_id, time_t end_time);
- void _AddCreatureCategoryCooldown(uint32 category, time_t apply_time);
- void AddCreatureSpellCooldown(uint32 spellid);
- bool HasSpellCooldown(uint32 spell_id) const;
- bool HasCategoryCooldown(uint32 spell_id) const;
- uint32 GetCreatureSpellCooldownDelay(uint32 spellId) const;
- virtual void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) override;
-
bool HasSpell(uint32 spellID) const override;
bool UpdateEntry(uint32 entry, CreatureData const* data = nullptr);
@@ -575,8 +559,6 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
SpellInfo const* reachWithSpellCure(Unit* victim);
uint32 m_spells[CREATURE_MAX_SPELLS];
- CreatureSpellCooldowns m_CreatureSpellCooldowns;
- CreatureSpellCooldowns m_CreatureCategoryCooldowns;
bool CanStartAttack(Unit const* u, bool force) const;
float GetAttackDistance(Unit const* player) const;
@@ -678,6 +660,10 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
void FocusTarget(Spell const* focusSpell, WorldObject const* target);
void ReleaseFocus(Spell const* focusSpell);
+ CreatureTextRepeatIds GetTextRepeatGroup(uint8 textGroup);
+ void SetTextRepeatId(uint8 textGroup, uint8 id);
+ void ClearTextRepeatGroup(uint8 textGroup);
+
protected:
bool CreateFromProto(uint32 guidlow, uint32 entry, CreatureData const* data = nullptr, uint32 vehId = 0);
bool InitEntry(uint32 entry, CreatureData const* data = nullptr);
@@ -742,6 +728,8 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
bool TriggerJustRespawned;
Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing
+
+ CreatureTextRepeatGroup m_textRepeat;
};
class AssistDelayEvent : public BasicEvent
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index a73cbfa3e5c..a4b140b9878 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -190,6 +190,12 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa
return false;
}
+ if (goinfo->type == GAMEOBJECT_TYPE_MO_TRANSPORT)
+ {
+ TC_LOG_ERROR("sql.sql", "Gameobject (GUID: %u Entry: %u) not created: gameobject type GAMEOBJECT_TYPE_MO_TRANSPORT cannot be manually created.", guidlow, name_id);
+ return false;
+ }
+
if (goinfo->type == GAMEOBJECT_TYPE_TRANSPORT)
m_updateFlag = (m_updateFlag | UPDATEFLAG_TRANSPORT) & ~UPDATEFLAG_POSITION;
@@ -265,6 +271,16 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa
SetGoAnimProgress(animprogress);
break;
}
+
+ if (GameObjectAddon const* addon = sObjectMgr->GetGameObjectAddon(guidlow))
+ {
+ if (addon->InvisibilityValue)
+ {
+ m_invisibility.AddFlag(addon->invisibilityType);
+ m_invisibility.AddValue(addon->invisibilityType, addon->InvisibilityValue);
+ }
+ }
+
LastUsedScriptID = GetGOInfo()->ScriptId;
AIM_Initialize();
@@ -2068,6 +2084,15 @@ void GameObject::SetGoState(GOState state)
}
}
+uint32 GameObject::GetTransportPeriod() const
+{
+ ASSERT(GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT);
+ if (m_goValue.Transport.AnimationInfo)
+ return m_goValue.Transport.AnimationInfo->TotalTime;
+
+ return 0;
+}
+
void GameObject::SetDisplayId(uint32 displayid)
{
SetUInt32Value(GAMEOBJECT_DISPLAYID, displayid);
@@ -2206,9 +2231,16 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
if (ActivateToQuest(target))
dynFlags |= GO_DYNFLAG_LO_SPARKLE;
break;
+ case GAMEOBJECT_TYPE_TRANSPORT:
case GAMEOBJECT_TYPE_MO_TRANSPORT:
- pathProgress = int16(float(m_goValue.Transport.PathProgress) / float(GetUInt32Value(GAMEOBJECT_LEVEL)) * 65535.0f);
+ {
+ if (uint32 transportPeriod = GetTransportPeriod())
+ {
+ float timer = float(m_goValue.Transport.PathProgress % transportPeriod);
+ pathProgress = int16(timer / float(transportPeriod) * 65535.0f);
+ }
break;
+ }
default:
break;
}
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index 844674b2210..5f1d2c793e6 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -576,6 +576,15 @@ struct GameObjectLocale
StringVector CastBarCaption;
};
+// `gameobject_addon` table
+struct GameObjectAddon
+{
+ InvisibilityType invisibilityType;
+ uint32 InvisibilityValue;
+};
+
+typedef std::unordered_map<ObjectGuid::LowType, GameObjectAddon> GameObjectAddonContainer;
+
// client side GO show states
enum GOState
{
@@ -717,6 +726,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map
void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); }
GOState GetGoState() const { return GOState(GetByteValue(GAMEOBJECT_BYTES_1, 0)); }
void SetGoState(GOState state);
+ virtual uint32 GetTransportPeriod() const;
uint8 GetGoArtKit() const { return GetByteValue(GAMEOBJECT_BYTES_1, 2); }
void SetGoArtKit(uint8 artkit);
uint8 GetGoAnimProgress() const { return GetByteValue(GAMEOBJECT_BYTES_1, 3); }
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index c82ae723f4c..b832aeb5614 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -201,8 +201,6 @@ enum ItemUpdateState
ITEM_REMOVED = 3
};
-#define MAX_ITEM_SPELLS 5
-
bool ItemCanGoIntoBag(ItemTemplate const* proto, ItemTemplate const* pBagProto);
class Item : public Object
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 4be3a03040d..6392c3ee51b 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1008,61 +1008,6 @@ bool Object::PrintIndexError(uint32 index, bool set) const
return false;
}
-bool Position::operator==(Position const &a)
-{
- return (G3D::fuzzyEq(a.m_positionX, m_positionX) &&
- G3D::fuzzyEq(a.m_positionY, m_positionY) &&
- G3D::fuzzyEq(a.m_positionZ, m_positionZ) &&
- G3D::fuzzyEq(a.m_orientation, m_orientation));
-}
-
-bool Position::HasInLine(WorldObject const* target, float width) const
-{
- if (!HasInArc(float(M_PI), target))
- return false;
- width += target->GetObjectSize();
- float angle = GetRelativeAngle(target);
- return std::fabs(std::sin(angle)) * GetExactDist2d(target->GetPositionX(), target->GetPositionY()) < width;
-}
-
-std::string Position::ToString() const
-{
- std::stringstream sstr;
- sstr << "X: " << m_positionX << " Y: " << m_positionY << " Z: " << m_positionZ << " O: " << m_orientation;
- return sstr.str();
-}
-
-ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer)
-{
- float x, y, z, o;
- buf >> x >> y >> z >> o;
- streamer.m_pos->Relocate(x, y, z, o);
- return buf;
-}
-ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer)
-{
- float x, y, z;
- streamer.m_pos->GetPosition(x, y, z);
- buf << x << y << z;
- return buf;
-}
-
-ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer)
-{
- float x, y, z;
- buf >> x >> y >> z;
- streamer.m_pos->Relocate(x, y, z);
- return buf;
-}
-
-ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer)
-{
- float x, y, z, o;
- streamer.m_pos->GetPosition(x, y, z, o);
- buf << x << y << z << o;
- return buf;
-}
-
void MovementInfo::OutDebug()
{
TC_LOG_DEBUG("misc", "MOVEMENT INFO");
@@ -1423,92 +1368,6 @@ bool WorldObject::IsInRange3d(float x, float y, float z, float minRange, float m
return distsq < maxdist * maxdist;
}
-void Position::RelocateOffset(const Position & offset)
-{
- m_positionX = GetPositionX() + (offset.GetPositionX() * std::cos(GetOrientation()) + offset.GetPositionY() * std::sin(GetOrientation() + float(M_PI)));
- m_positionY = GetPositionY() + (offset.GetPositionY() * std::cos(GetOrientation()) + offset.GetPositionX() * std::sin(GetOrientation()));
- m_positionZ = GetPositionZ() + offset.GetPositionZ();
- SetOrientation(GetOrientation() + offset.GetOrientation());
-}
-
-void Position::GetPositionOffsetTo(const Position & endPos, Position & retOffset) const
-{
- float dx = endPos.GetPositionX() - GetPositionX();
- float dy = endPos.GetPositionY() - GetPositionY();
-
- retOffset.m_positionX = dx * std::cos(GetOrientation()) + dy * std::sin(GetOrientation());
- retOffset.m_positionY = dy * std::cos(GetOrientation()) - dx * std::sin(GetOrientation());
- retOffset.m_positionZ = endPos.GetPositionZ() - GetPositionZ();
- retOffset.SetOrientation(endPos.GetOrientation() - GetOrientation());
-}
-
-Position Position::GetPositionWithOffset(Position const& offset) const
-{
- Position ret(*this);
- ret.RelocateOffset(offset);
- return ret;
-}
-
-float Position::GetAngle(const Position* obj) const
-{
- if (!obj)
- return 0;
-
- return GetAngle(obj->GetPositionX(), obj->GetPositionY());
-}
-
-// Return angle in range 0..2*pi
-float Position::GetAngle(const float x, const float y) const
-{
- float dx = x - GetPositionX();
- float dy = y - GetPositionY();
-
- float ang = std::atan2(dy, dx);
- ang = (ang >= 0) ? ang : 2 * float(M_PI) + ang;
- return ang;
-}
-
-void Position::GetSinCos(const float x, const float y, float &vsin, float &vcos) const
-{
- float dx = GetPositionX() - x;
- float dy = GetPositionY() - y;
-
- if (std::fabs(dx) < 0.001f && std::fabs(dy) < 0.001f)
- {
- float angle = (float)rand_norm()*static_cast<float>(2*M_PI);
- vcos = std::cos(angle);
- vsin = std::sin(angle);
- }
- else
- {
- float dist = std::sqrt((dx*dx) + (dy*dy));
- vcos = dx / dist;
- vsin = dy / dist;
- }
-}
-
-bool Position::HasInArc(float arc, const Position* obj, float border) const
-{
- // always have self in arc
- if (obj == this)
- return true;
-
- // move arc to range 0.. 2*pi
- arc = NormalizeOrientation(arc);
-
- float angle = GetAngle(obj);
- angle -= m_orientation;
-
- // move angle to range -pi ... +pi
- angle = NormalizeOrientation(angle);
- if (angle > float(M_PI))
- angle -= 2.0f * float(M_PI);
-
- float lborder = -1 * (arc/border); // in range -pi..0
- float rborder = (arc/border); // in range 0..pi
- return ((angle >= lborder) && (angle <= rborder));
-}
-
bool WorldObject::IsInBetween(const WorldObject* obj1, const WorldObject* obj2, float size) const
{
if (!obj1 || !obj2)
@@ -1642,11 +1501,6 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const
}
}
-bool Position::IsPositionValid() const
-{
- return Trinity::IsValidMapCoord(m_positionX, m_positionY, m_positionZ, m_orientation);
-}
-
float WorldObject::GetGridActivationRange() const
{
if (ToPlayer())
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index c48d8ff4d18..a560afa7f1b 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -20,6 +20,7 @@
#define _OBJECT_H
#include "Common.h"
+#include "Position.h"
#include "UpdateMask.h"
#include "GridReference.h"
#include "ObjectDefines.h"
@@ -246,141 +247,6 @@ class Object
Object& operator=(Object const& right) = delete;
};
-struct Position
-{
- Position(float x = 0, float y = 0, float z = 0, float o = 0)
- : m_positionX(x), m_positionY(y), m_positionZ(z), m_orientation(NormalizeOrientation(o)) { }
-
- Position(const Position &loc) { Relocate(loc); }
-
- struct PositionXYZStreamer
- {
- explicit PositionXYZStreamer(Position& pos) : m_pos(&pos) { }
- Position* m_pos;
- };
-
- struct PositionXYZOStreamer
- {
- explicit PositionXYZOStreamer(Position& pos) : m_pos(&pos) { }
- Position* m_pos;
- };
-
- float m_positionX;
- float m_positionY;
- float m_positionZ;
-// Better to limit access to m_orientation field, but this will be hard to achieve with many scripts using array initialization for this structure
-//private:
- float m_orientation;
-//public:
-
- bool operator==(Position const &a);
-
- inline bool operator!=(Position const &a)
- {
- return !(operator==(a));
- }
-
- void Relocate(float x, float y)
- { m_positionX = x; m_positionY = y;}
- void Relocate(float x, float y, float z)
- { m_positionX = x; m_positionY = y; m_positionZ = z; }
- void Relocate(float x, float y, float z, float orientation)
- { m_positionX = x; m_positionY = y; m_positionZ = z; SetOrientation(orientation); }
- void Relocate(Position const &pos)
- { m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; SetOrientation(pos.m_orientation); }
- void Relocate(Position const* pos)
- { m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; SetOrientation(pos->m_orientation); }
- void RelocateOffset(Position const &offset);
- void SetOrientation(float orientation)
- { m_orientation = NormalizeOrientation(orientation); }
-
- float GetPositionX() const { return m_positionX; }
- float GetPositionY() const { return m_positionY; }
- float GetPositionZ() const { return m_positionZ; }
- float GetOrientation() const { return m_orientation; }
-
- void GetPosition(float &x, float &y) const
- { x = m_positionX; y = m_positionY; }
- void GetPosition(float &x, float &y, float &z) const
- { x = m_positionX; y = m_positionY; z = m_positionZ; }
- void GetPosition(float &x, float &y, float &z, float &o) const
- { x = m_positionX; y = m_positionY; z = m_positionZ; o = m_orientation; }
-
- Position GetPosition() const
- {
- return *this;
- }
-
- Position::PositionXYZStreamer PositionXYZStream()
- {
- return PositionXYZStreamer(*this);
- }
- Position::PositionXYZOStreamer PositionXYZOStream()
- {
- return PositionXYZOStreamer(*this);
- }
-
- bool IsPositionValid() const;
-
- float GetExactDist2dSq(float x, float y) const
- { float dx = m_positionX - x; float dy = m_positionY - y; return dx*dx + dy*dy; }
- float GetExactDist2d(const float x, const float y) const
- { return std::sqrt(GetExactDist2dSq(x, y)); }
- float GetExactDist2dSq(Position const* pos) const
- { float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy; }
- float GetExactDist2d(Position const* pos) const
- { return std::sqrt(GetExactDist2dSq(pos)); }
- float GetExactDistSq(float x, float y, float z) const
- { float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz; }
- float GetExactDist(float x, float y, float z) const
- { return std::sqrt(GetExactDistSq(x, y, z)); }
- float GetExactDistSq(Position const* pos) const
- { float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; float dz = m_positionZ - pos->m_positionZ; return dx*dx + dy*dy + dz*dz; }
- float GetExactDist(Position const* pos) const
- { return std::sqrt(GetExactDistSq(pos)); }
-
- void GetPositionOffsetTo(Position const & endPos, Position & retOffset) const;
- Position GetPositionWithOffset(Position const& offset) const;
-
- float GetAngle(Position const* pos) const;
- float GetAngle(float x, float y) const;
- float GetRelativeAngle(Position const* pos) const
- { return GetAngle(pos) - m_orientation; }
- float GetRelativeAngle(float x, float y) const { return GetAngle(x, y) - m_orientation; }
- void GetSinCos(float x, float y, float &vsin, float &vcos) const;
-
- bool IsInDist2d(float x, float y, float dist) const
- { return GetExactDist2dSq(x, y) < dist * dist; }
- bool IsInDist2d(Position const* pos, float dist) const
- { return GetExactDist2dSq(pos) < dist * dist; }
- bool IsInDist(float x, float y, float z, float dist) const
- { return GetExactDistSq(x, y, z) < dist * dist; }
- bool IsInDist(Position const* pos, float dist) const
- { return GetExactDistSq(pos) < dist * dist; }
- bool HasInArc(float arcangle, Position const* pos, float border = 2.0f) const;
- bool HasInLine(WorldObject const* target, float width) const;
- std::string ToString() const;
-
- // modulos a radian orientation to the range of 0..2PI
- static float NormalizeOrientation(float o)
- {
- // fmod only supports positive numbers. Thus we have
- // to emulate negative numbers
- if (o < 0)
- {
- float mod = o *-1;
- mod = std::fmod(mod, 2.0f * static_cast<float>(M_PI));
- mod = -mod + 2.0f * static_cast<float>(M_PI);
- return mod;
- }
- return std::fmod(o, 2.0f * static_cast<float>(M_PI));
- }
-};
-ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
-ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer);
-ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer);
-ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
-
struct MovementInfo
{
// common
diff --git a/src/server/game/Entities/Object/ObjectGuid.h b/src/server/game/Entities/Object/ObjectGuid.h
index 36dbdd72069..45881ddab6d 100644
--- a/src/server/game/Entities/Object/ObjectGuid.h
+++ b/src/server/game/Entities/Object/ObjectGuid.h
@@ -83,10 +83,12 @@ class ObjectGuid
public:
static ObjectGuid const Empty;
+ typedef uint32 LowType;
+
ObjectGuid() : _guid(0) { }
explicit ObjectGuid(uint64 guid) : _guid(guid) { }
- ObjectGuid(HighGuid hi, uint32 entry, uint32 counter) : _guid(counter ? uint64(counter) | (uint64(entry) << 24) | (uint64(hi) << 48) : 0) { }
- ObjectGuid(HighGuid hi, uint32 counter) : _guid(counter ? uint64(counter) | (uint64(hi) << 48) : 0) { }
+ ObjectGuid(HighGuid hi, uint32 entry, LowType counter) : _guid(counter ? uint64(counter) | (uint64(entry) << 24) | (uint64(hi) << 48) : 0) { }
+ ObjectGuid(HighGuid hi, LowType counter) : _guid(counter ? uint64(counter) | (uint64(hi) << 48) : 0) { }
operator uint64() const { return _guid; }
PackedGuidReader ReadAsPacked() { return PackedGuidReader(*this); }
@@ -99,11 +101,11 @@ class ObjectGuid
uint64 GetRawValue() const { return _guid; }
HighGuid GetHigh() const { return HighGuid((_guid >> 48) & 0x0000FFFF); }
uint32 GetEntry() const { return HasEntry() ? uint32((_guid >> 24) & UI64LIT(0x0000000000FFFFFF)) : 0; }
- uint32 GetCounter() const
+ LowType GetCounter() const
{
return HasEntry()
- ? uint32(_guid & UI64LIT(0x0000000000FFFFFF))
- : uint32(_guid & UI64LIT(0x00000000FFFFFFFF));
+ ? LowType(_guid & UI64LIT(0x0000000000FFFFFF))
+ : LowType(_guid & UI64LIT(0x00000000FFFFFFFF));
}
static uint32 GetMaxCounter(HighGuid high)
diff --git a/src/server/game/Entities/Object/Position.cpp b/src/server/game/Entities/Object/Position.cpp
new file mode 100644
index 00000000000..530e51cd8f5
--- /dev/null
+++ b/src/server/game/Entities/Object/Position.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2008-2015 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 "Position.h"
+#include "ByteBuffer.h"
+#include "G3D/g3dmath.h"
+#include "GridDefines.h"
+
+bool Position::operator==(Position const &a)
+{
+ return (G3D::fuzzyEq(a.m_positionX, m_positionX) &&
+ G3D::fuzzyEq(a.m_positionY, m_positionY) &&
+ G3D::fuzzyEq(a.m_positionZ, m_positionZ) &&
+ G3D::fuzzyEq(a.m_orientation, m_orientation));
+}
+
+void Position::RelocateOffset(const Position & offset)
+{
+ m_positionX = GetPositionX() + (offset.GetPositionX() * std::cos(GetOrientation()) + offset.GetPositionY() * std::sin(GetOrientation() + float(M_PI)));
+ m_positionY = GetPositionY() + (offset.GetPositionY() * std::cos(GetOrientation()) + offset.GetPositionX() * std::sin(GetOrientation()));
+ m_positionZ = GetPositionZ() + offset.GetPositionZ();
+ SetOrientation(GetOrientation() + offset.GetOrientation());
+}
+
+bool Position::IsPositionValid() const
+{
+ return Trinity::IsValidMapCoord(m_positionX, m_positionY, m_positionZ, m_orientation);
+}
+
+void Position::GetPositionOffsetTo(const Position & endPos, Position & retOffset) const
+{
+ float dx = endPos.GetPositionX() - GetPositionX();
+ float dy = endPos.GetPositionY() - GetPositionY();
+
+ retOffset.m_positionX = dx * std::cos(GetOrientation()) + dy * std::sin(GetOrientation());
+ retOffset.m_positionY = dy * std::cos(GetOrientation()) - dx * std::sin(GetOrientation());
+ retOffset.m_positionZ = endPos.GetPositionZ() - GetPositionZ();
+ retOffset.SetOrientation(endPos.GetOrientation() - GetOrientation());
+}
+
+Position Position::GetPositionWithOffset(Position const& offset) const
+{
+ Position ret(*this);
+ ret.RelocateOffset(offset);
+ return ret;
+}
+
+float Position::GetAngle(const Position* obj) const
+{
+ if (!obj)
+ return 0;
+
+ return GetAngle(obj->GetPositionX(), obj->GetPositionY());
+}
+
+// Return angle in range 0..2*pi
+float Position::GetAngle(float x, float y) const
+{
+ float dx = x - GetPositionX();
+ float dy = y - GetPositionY();
+
+ float ang = std::atan2(dy, dx);
+ ang = (ang >= 0) ? ang : 2 * float(M_PI) + ang;
+ return ang;
+}
+
+void Position::GetSinCos(const float x, const float y, float &vsin, float &vcos) const
+{
+ float dx = GetPositionX() - x;
+ float dy = GetPositionY() - y;
+
+ if (std::fabs(dx) < 0.001f && std::fabs(dy) < 0.001f)
+ {
+ float angle = (float)rand_norm()*static_cast<float>(2 * M_PI);
+ vcos = std::cos(angle);
+ vsin = std::sin(angle);
+ }
+ else
+ {
+ float dist = std::sqrt((dx*dx) + (dy*dy));
+ vcos = dx / dist;
+ vsin = dy / dist;
+ }
+}
+
+bool Position::HasInArc(float arc, const Position* obj, float border) const
+{
+ // always have self in arc
+ if (obj == this)
+ return true;
+
+ // move arc to range 0.. 2*pi
+ arc = NormalizeOrientation(arc);
+
+ float angle = GetAngle(obj);
+ angle -= m_orientation;
+
+ // move angle to range -pi ... +pi
+ angle = NormalizeOrientation(angle);
+ if (angle > float(M_PI))
+ angle -= 2.0f * float(M_PI);
+
+ float lborder = -1 * (arc / border); // in range -pi..0
+ float rborder = (arc / border); // in range 0..pi
+ return ((angle >= lborder) && (angle <= rborder));
+}
+
+bool Position::HasInLine(Position const* pos, float width) const
+{
+ if (!HasInArc(float(M_PI), pos))
+ return false;
+
+ float angle = GetRelativeAngle(pos);
+ return std::fabs(std::sin(angle)) * GetExactDist2d(pos->GetPositionX(), pos->GetPositionY()) < width;
+}
+
+std::string Position::ToString() const
+{
+ std::stringstream sstr;
+ sstr << "X: " << m_positionX << " Y: " << m_positionY << " Z: " << m_positionZ << " O: " << m_orientation;
+ return sstr.str();
+}
+
+ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer)
+{
+ buf << streamer.Pos->GetPositionX();
+ buf << streamer.Pos->GetPositionY();
+ return buf;
+}
+
+ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYStreamer const& streamer)
+{
+ float x, y;
+ buf >> x >> y;
+ streamer.Pos->Relocate(x, y);
+ return buf;
+}
+
+ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer)
+{
+ buf << streamer.Pos->GetPositionX();
+ buf << streamer.Pos->GetPositionY();
+ buf << streamer.Pos->GetPositionZ();
+ return buf;
+}
+
+ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer)
+{
+ float x, y, z;
+ buf >> x >> y >> z;
+ streamer.Pos->Relocate(x, y, z);
+ return buf;
+}
+
+ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer)
+{
+ buf << streamer.Pos->GetPositionX();
+ buf << streamer.Pos->GetPositionY();
+ buf << streamer.Pos->GetPositionZ();
+ buf << streamer.Pos->GetOrientation();
+ return buf;
+}
+
+ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer)
+{
+ float x, y, z, o;
+ buf >> x >> y >> z >> o;
+ streamer.Pos->Relocate(x, y, z, o);
+ return buf;
+}
diff --git a/src/server/game/Entities/Object/Position.h b/src/server/game/Entities/Object/Position.h
new file mode 100644
index 00000000000..5bd37567811
--- /dev/null
+++ b/src/server/game/Entities/Object/Position.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2008-2015 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_game_Position_h__
+#define Trinity_game_Position_h__
+
+#include "Common.h"
+
+class ByteBuffer;
+
+struct Position
+{
+ Position(float x = 0, float y = 0, float z = 0, float o = 0)
+ : m_positionX(x), m_positionY(y), m_positionZ(z), m_orientation(NormalizeOrientation(o)) { }
+
+ Position(Position const& loc) { Relocate(loc); }
+
+ struct PositionXYStreamer
+ {
+ explicit PositionXYStreamer(Position& pos) : Pos(&pos) { }
+ Position* Pos;
+ };
+
+ struct PositionXYZStreamer
+ {
+ explicit PositionXYZStreamer(Position& pos) : Pos(&pos) { }
+ Position* Pos;
+ };
+
+ struct PositionXYZOStreamer
+ {
+ explicit PositionXYZOStreamer(Position& pos) : Pos(&pos) { }
+ Position* Pos;
+ };
+
+ float m_positionX;
+ float m_positionY;
+ float m_positionZ;
+ // Better to limit access to _orientation field, to guarantee the value is normalized
+private:
+ float m_orientation;
+
+public:
+ bool operator==(Position const &a);
+
+ inline bool operator!=(Position const &a)
+ {
+ return !(operator==(a));
+ }
+
+ void Relocate(float x, float y)
+ {
+ m_positionX = x; m_positionY = y;
+ }
+
+ void Relocate(float x, float y, float z)
+ {
+ m_positionX = x; m_positionY = y; m_positionZ = z;
+ }
+
+ void Relocate(float x, float y, float z, float orientation)
+ {
+ m_positionX = x; m_positionY = y; m_positionZ = z; SetOrientation(orientation);
+ }
+
+ void Relocate(Position const &pos)
+ {
+ m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; SetOrientation(pos.m_orientation);
+ }
+
+ void Relocate(Position const* pos)
+ {
+ m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; SetOrientation(pos->m_orientation);
+ }
+
+ void RelocateOffset(Position const &offset);
+
+ void SetOrientation(float orientation)
+ {
+ m_orientation = NormalizeOrientation(orientation);
+ }
+
+ float GetPositionX() const { return m_positionX; }
+ float GetPositionY() const { return m_positionY; }
+ float GetPositionZ() const { return m_positionZ; }
+ float GetOrientation() const { return m_orientation; }
+
+ void GetPosition(float &x, float &y) const
+ {
+ x = m_positionX; y = m_positionY;
+ }
+
+ void GetPosition(float &x, float &y, float &z) const
+ {
+ x = m_positionX; y = m_positionY; z = m_positionZ;
+ }
+
+ void GetPosition(float &x, float &y, float &z, float &o) const
+ {
+ x = m_positionX; y = m_positionY; z = m_positionZ; o = m_orientation;
+ }
+
+ Position GetPosition() const { return *this; }
+
+ Position::PositionXYStreamer PositionXYStream() { return PositionXYStreamer(*this); }
+ Position::PositionXYZStreamer PositionXYZStream() { return PositionXYZStreamer(*this); }
+ Position::PositionXYZOStreamer PositionXYZOStream() { return PositionXYZOStreamer(*this); }
+
+ bool IsPositionValid() const;
+
+ float GetExactDist2dSq(float x, float y) const
+ {
+ float dx = m_positionX - x; float dy = m_positionY - y; return dx*dx + dy*dy;
+ }
+
+ float GetExactDist2d(const float x, const float y) const
+ {
+ return std::sqrt(GetExactDist2dSq(x, y));
+ }
+
+ float GetExactDist2dSq(Position const* pos) const
+ {
+ float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy;
+ }
+
+ float GetExactDist2d(Position const* pos) const
+ {
+ return std::sqrt(GetExactDist2dSq(pos));
+ }
+
+ float GetExactDistSq(float x, float y, float z) const
+ {
+ float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz;
+ }
+
+ float GetExactDist(float x, float y, float z) const
+ {
+ return std::sqrt(GetExactDistSq(x, y, z));
+ }
+
+ float GetExactDistSq(Position const* pos) const
+ {
+ float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; float dz = m_positionZ - pos->m_positionZ; return dx*dx + dy*dy + dz*dz;
+ }
+
+ float GetExactDist(Position const* pos) const
+ {
+ return std::sqrt(GetExactDistSq(pos));
+ }
+
+ void GetPositionOffsetTo(Position const & endPos, Position & retOffset) const;
+ Position GetPositionWithOffset(Position const& offset) const;
+
+ float GetAngle(Position const* pos) const;
+ float GetAngle(float x, float y) const;
+ float GetRelativeAngle(Position const* pos) const
+ {
+ return GetAngle(pos) - m_orientation;
+ }
+
+ float GetRelativeAngle(float x, float y) const { return GetAngle(x, y) - m_orientation; }
+ void GetSinCos(float x, float y, float &vsin, float &vcos) const;
+
+ bool IsInDist2d(float x, float y, float dist) const
+ {
+ return GetExactDist2dSq(x, y) < dist * dist;
+ }
+
+ bool IsInDist2d(Position const* pos, float dist) const
+ {
+ return GetExactDist2dSq(pos) < dist * dist;
+ }
+
+ bool IsInDist(float x, float y, float z, float dist) const
+ {
+ return GetExactDistSq(x, y, z) < dist * dist;
+ }
+
+ bool IsInDist(Position const* pos, float dist) const
+ {
+ return GetExactDistSq(pos) < dist * dist;
+ }
+
+ bool HasInArc(float arcangle, Position const* pos, float border = 2.0f) const;
+ bool HasInLine(Position const* pos, float width) const;
+ std::string ToString() const;
+
+ // modulos a radian orientation to the range of 0..2PI
+ static float NormalizeOrientation(float o)
+ {
+ // fmod only supports positive numbers. Thus we have
+ // to emulate negative numbers
+ if (o < 0)
+ {
+ float mod = o *-1;
+ mod = std::fmod(mod, 2.0f * static_cast<float>(M_PI));
+ mod = -mod + 2.0f * static_cast<float>(M_PI);
+ return mod;
+ }
+ return std::fmod(o, 2.0f * static_cast<float>(M_PI));
+ }
+};
+
+ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer);
+ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYStreamer const& streamer);
+ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer);
+ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer);
+ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
+ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
+
+#endif // Trinity_game_Position_h__
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index d5d6bdf9831..97cdb0cf1df 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -24,6 +24,7 @@
#include "SpellMgr.h"
#include "Pet.h"
#include "Formulas.h"
+#include "SpellHistory.h"
#include "SpellAuras.h"
#include "SpellAuraEffects.h"
#include "Unit.h"
@@ -407,7 +408,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
RemoveAllAuras();
_SaveSpells(trans);
- _SaveSpellCooldowns(trans);
+ GetSpellHistory()->SaveToDB<Pet>(trans);
CharacterDatabase.CommitTransaction(trans);
// current/stable/not_in_slot
@@ -1106,77 +1107,11 @@ uint32 Pet::GetCurrentFoodBenefitLevel(uint32 itemlevel) const
void Pet::_LoadSpellCooldowns()
{
- m_CreatureSpellCooldowns.clear();
- m_CreatureCategoryCooldowns.clear();
-
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL_COOLDOWN);
stmt->setUInt32(0, m_charmInfo->GetPetNumber());
- PreparedQueryResult result = CharacterDatabase.Query(stmt);
-
- if (result)
- {
- time_t curTime = time(NULL);
-
- PacketCooldowns cooldowns;
- WorldPacket data;
-
- do
- {
- Field* fields = result->Fetch();
-
- uint32 spell_id = fields[0].GetUInt32();
- time_t db_time = time_t(fields[1].GetUInt32());
-
- if (!sSpellMgr->GetSpellInfo(spell_id))
- {
- TC_LOG_ERROR("entities.pet", "Pet %u have unknown spell %u in `pet_spell_cooldown`, skipping.", m_charmInfo->GetPetNumber(), spell_id);
- continue;
- }
+ PreparedQueryResult cooldownsResult = CharacterDatabase.Query(stmt);
- // skip outdated cooldown
- if (db_time <= curTime)
- continue;
-
- cooldowns[spell_id] = uint32(db_time - curTime)*IN_MILLISECONDS;
-
- _AddCreatureSpellCooldown(spell_id, db_time);
-
- TC_LOG_DEBUG("entities.pet", "Pet (Number: %u) spell %u cooldown loaded (%u secs).", m_charmInfo->GetPetNumber(), spell_id, uint32(db_time-curTime));
- }
- while (result->NextRow());
-
- if (!cooldowns.empty())
- {
- BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, cooldowns);
- GetOwner()->GetSession()->SendPacket(&data);
- }
- }
-}
-
-void Pet::_SaveSpellCooldowns(SQLTransaction& trans)
-{
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PET_SPELL_COOLDOWNS);
- stmt->setUInt32(0, m_charmInfo->GetPetNumber());
- trans->Append(stmt);
-
- time_t curTime = time(NULL);
-
- // remove oudated and save active
- for (CreatureSpellCooldowns::iterator itr = m_CreatureSpellCooldowns.begin(); itr != m_CreatureSpellCooldowns.end();)
- {
- if (itr->second <= curTime)
- m_CreatureSpellCooldowns.erase(itr++);
- else
- {
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET_SPELL_COOLDOWN);
- stmt->setUInt32(0, m_charmInfo->GetPetNumber());
- stmt->setUInt32(1, itr->first);
- stmt->setUInt32(2, uint32(itr->second));
- trans->Append(stmt);
-
- ++itr;
- }
- }
+ GetSpellHistory()->LoadFromDB<Pet>(cooldownsResult);
}
void Pet::_LoadSpells()
@@ -2025,40 +1960,6 @@ void Pet::SynchronizeLevelWithOwner()
}
}
-void Pet::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs)
-{
- PacketCooldowns cooldowns;
- WorldPacket data;
- time_t curTime = time(NULL);
- for (PetSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
- {
- if (itr->second.state == PETSPELL_REMOVED)
- continue;
-
- uint32 unSpellId = itr->first;
- SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(unSpellId);
-
- // Not send cooldown for this spells
- if (spellInfo->IsCooldownStartedOnEvent())
- continue;
-
- if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE)
- continue;
-
- if ((idSchoolMask & spellInfo->GetSchoolMask()) && GetCreatureSpellCooldownDelay(unSpellId) < unTimeMs)
- {
- cooldowns[unSpellId] = unTimeMs;
- _AddCreatureSpellCooldown(unSpellId, curTime + unTimeMs/IN_MILLISECONDS);
- }
- }
-
- if (!cooldowns.empty())
- {
- BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, cooldowns);
- GetOwner()->GetSession()->SendPacket(&data);
- }
-}
-
Player* Pet::GetOwner() const
{
return Minion::GetOwner()->ToPlayer();
diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h
index 62d82aaab1b..1cc86ea2a20 100644
--- a/src/server/game/Entities/Pet/Pet.h
+++ b/src/server/game/Entities/Pet/Pet.h
@@ -108,7 +108,6 @@ class Pet : public Guardian
bool IsPetAura(Aura const* aura);
void _LoadSpellCooldowns();
- void _SaveSpellCooldowns(SQLTransaction& trans);
void _LoadAuras(uint32 timediff);
void _SaveAuras(SQLTransaction& trans);
void _LoadSpells();
@@ -121,7 +120,6 @@ class Pet : public Guardian
bool unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true);
bool removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true);
void CleanupActionBar();
- virtual void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) override;
PetSpellMap m_spells;
AutoSpellList m_autospells;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 32fd5c53803..275dbf92dca 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -67,6 +67,7 @@
#include "SpellAuraEffects.h"
#include "SpellAuras.h"
#include "SpellMgr.h"
+#include "SpellHistory.h"
#include "Transport.h"
#include "UpdateData.h"
#include "UpdateFieldFlags.h"
@@ -3345,12 +3346,10 @@ void Player::InitStatsForLevel(bool reapplyMods)
void Player::SendInitialSpells()
{
- time_t curTime = time(NULL);
- time_t infTime = curTime + infinityCooldownDelayCheck;
-
+ uint16 spellCooldowns = GetSpellHistory()->GetCooldownsSizeForPacket();
uint16 spellCount = 0;
- WorldPacket data(SMSG_INITIAL_SPELLS, (1+2+4*m_spells.size()+2+m_spellCooldowns.size()*(2+2+2+4+4)));
+ WorldPacket data(SMSG_INITIAL_SPELLS, (1 + 2 + 4 * m_spells.size() + 2 + spellCooldowns * (2 + 2 + 2 + 4 + 4)));
data << uint8(0);
size_t countPos = data.wpos();
@@ -3372,40 +3371,7 @@ void Player::SendInitialSpells()
data.put<uint16>(countPos, spellCount); // write real count value
- uint16 spellCooldowns = m_spellCooldowns.size();
- data << uint16(spellCooldowns);
- for (SpellCooldowns::const_iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); ++itr)
- {
- SpellInfo const* sEntry = sSpellMgr->GetSpellInfo(itr->first);
- if (!sEntry)
- continue;
-
- data << uint32(itr->first);
-
- data << uint16(itr->second.itemid); // cast item id
- data << uint16(sEntry->GetCategory()); // spell category
-
- // send infinity cooldown in special format
- if (itr->second.end >= infTime)
- {
- data << uint32(1); // cooldown
- data << uint32(0x80000000); // category cooldown
- continue;
- }
-
- time_t cooldown = itr->second.end > curTime ? (itr->second.end-curTime)*IN_MILLISECONDS : 0;
-
- if (sEntry->GetCategory()) // may be wrong, but anyway better than nothing...
- {
- data << uint32(0); // cooldown
- data << uint32(cooldown); // category cooldown
- }
- else
- {
- data << uint32(cooldown); // cooldown
- data << uint32(0); // category cooldown
- }
- }
+ GetSpellHistory()->WritePacket<Player>(data);
GetSession()->SendPacket(&data);
@@ -4202,154 +4168,19 @@ bool Player::Has310Flyer(bool checkAllSpells, uint32 excludeSpellId)
return false;
}
-void Player::RemoveSpellCooldown(uint32 spell_id, bool update /* = false */)
-{
- m_spellCooldowns.erase(spell_id);
-
- if (update)
- SendClearCooldown(spell_id, this);
-}
-
-// I am not sure which one is more efficient
-void Player::RemoveCategoryCooldown(uint32 cat)
-{
- SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(cat);
- if (i_scstore != sSpellsByCategoryStore.end())
- for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
- RemoveSpellCooldown(*i_scset, true);
-}
-
-void Player::RemoveSpellCategoryCooldown(uint32 cat, bool update /* = false */)
-{
- SpellCategoryStore::const_iterator ct = sSpellsByCategoryStore.find(cat);
- if (ct == sSpellsByCategoryStore.end())
- return;
-
- const SpellCategorySet& ct_set = ct->second;
- for (SpellCooldowns::const_iterator i = m_spellCooldowns.begin(); i != m_spellCooldowns.end();)
- {
- if (ct_set.find(i->first) != ct_set.end())
- RemoveSpellCooldown((i++)->first, update);
- else
- ++i;
- }
-}
-
void Player::RemoveArenaSpellCooldowns(bool removeActivePetCooldowns)
{
// remove cooldowns on spells that have < 10 min CD
-
- SpellCooldowns::iterator itr, next;
- for (itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); itr = next)
+ GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
{
- next = itr;
- ++next;
- SpellInfo const* entry = sSpellMgr->GetSpellInfo(itr->first);
- // check if spellentry is present and if the cooldown is less than 10 min
- if (entry &&
- entry->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS &&
- entry->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS)
- {
- // remove & notify
- RemoveSpellCooldown(itr->first, true);
- }
- }
+ SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
+ return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS;
+ }, true);
// pet cooldowns
if (removeActivePetCooldowns)
if (Pet* pet = GetPet())
- {
- // notify player
- for (CreatureSpellCooldowns::const_iterator itr2 = pet->m_CreatureSpellCooldowns.begin(); itr2 != pet->m_CreatureSpellCooldowns.end(); ++itr2)
- SendClearCooldown(itr2->first, pet);
-
- // actually clear cooldowns
- pet->m_CreatureSpellCooldowns.clear();
- }
-}
-
-void Player::RemoveAllSpellCooldown()
-{
- if (!m_spellCooldowns.empty())
- {
- for (SpellCooldowns::const_iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); ++itr)
- SendClearCooldown(itr->first, this);
-
- m_spellCooldowns.clear();
- }
-}
-
-void Player::_LoadSpellCooldowns(PreparedQueryResult result)
-{
- // some cooldowns can be already set at aura loading...
-
- //QueryResult* result = CharacterDatabase.PQuery("SELECT spell, item, time FROM character_spell_cooldown WHERE guid = '%u'", GetGUIDLow());
-
- if (result)
- {
- time_t curTime = time(NULL);
-
- do
- {
- Field* fields = result->Fetch();
- uint32 spell_id = fields[0].GetUInt32();
- uint32 item_id = fields[1].GetUInt32();
- time_t db_time = time_t(fields[2].GetUInt32());
-
- if (!sSpellMgr->GetSpellInfo(spell_id))
- {
- TC_LOG_ERROR("entities.player.loading", "Player %u has unknown spell %u in `character_spell_cooldown`, skipping.", GetGUIDLow(), spell_id);
- continue;
- }
-
- // skip outdated cooldown
- if (db_time <= curTime)
- continue;
-
- AddSpellCooldown(spell_id, item_id, db_time);
-
- TC_LOG_DEBUG("entities.player.loading", "Player (GUID: %u) spell %u, item %u cooldown loaded (%u secs).", GetGUIDLow(), spell_id, item_id, uint32(db_time-curTime));
- }
- while (result->NextRow());
- }
-}
-
-void Player::_SaveSpellCooldowns(SQLTransaction& trans)
-{
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN);
- stmt->setUInt32(0, GetGUIDLow());
- trans->Append(stmt);
-
- time_t curTime = time(NULL);
- time_t infTime = curTime + infinityCooldownDelayCheck;
-
- bool first_round = true;
- std::ostringstream ss;
-
- // remove outdated and save active
- for (SpellCooldowns::iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end();)
- {
- if (itr->second.end <= curTime)
- m_spellCooldowns.erase(itr++);
- else if (itr->second.end <= infTime) // not save locked cooldowns, it will be reset or set at reload
- {
- if (first_round)
- {
- ss << "INSERT INTO character_spell_cooldown (guid, spell, item, time) VALUES ";
- first_round = false;
- }
- // next new/changed record prefix
- else
- ss << ',';
- ss << '(' << GetGUIDLow() << ',' << itr->first << ',' << itr->second.itemid << ',' << uint64(itr->second.end) << ')';
- ++itr;
- }
- else
- ++itr;
- }
- // if something changed execute
- if (!first_round)
- trans->Append(ss.str().c_str());
+ pet->GetSpellHistory()->ResetAllCooldowns();
}
uint32 Player::ResetTalentsCost() const
@@ -4897,7 +4728,7 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt32(0, guid);
trans->Append(stmt);
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWNS);
stmt->setUInt32(0, guid);
trans->Append(stmt);
@@ -8382,7 +8213,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
if (procVictim & PROC_FLAG_TAKEN_DAMAGE)
//if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
{
- for (uint8 i = 0; i < MAX_ITEM_SPELLS; ++i)
+ for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
_Spell const& spellData = proto->Spells[i];
@@ -12425,10 +12256,9 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
{
m_weaponChangeTimer = spellProto->StartRecoveryTime;
- GetGlobalCooldownMgr().AddGlobalCooldown(spellProto, m_weaponChangeTimer);
-
+ GetSpellHistory()->AddGlobalCooldown(spellProto, m_weaponChangeTimer);
WorldPacket data;
- BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_INCLUDE_GCD, cooldownSpell, 0);
+ GetSpellHistory()->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_INCLUDE_GCD, cooldownSpell, 0);
GetSession()->SendPacket(&data);
}
}
@@ -17811,7 +17641,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
// has to be called after last Relocate() in Player::LoadFromDB
SetFallInformation(0, GetPositionZ());
- _LoadSpellCooldowns(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS));
+ GetSpellHistory()->LoadFromDB<Player>(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS));
// Spell code allow apply any auras to dead character in load time in aura/spell/item loading
// Do now before stats re-calculation cleanup for ghost state unexpected auras
@@ -19517,7 +19347,7 @@ void Player::SaveToDB(bool create /*=false*/)
_SaveMonthlyQuestStatus(trans);
_SaveTalents(trans);
_SaveSpells(trans);
- _SaveSpellCooldowns(trans);
+ GetSpellHistory()->SaveToDB<Player>(trans);
_SaveActions(trans);
_SaveAuras(trans);
_SaveSkills(trans);
@@ -20754,41 +20584,8 @@ void Player::PetSpellInitialize()
data.put<uint8>(spellsCountPos, addlist);
- uint8 cooldownsCount = pet->m_CreatureSpellCooldowns.size() + pet->m_CreatureCategoryCooldowns.size();
- data << uint8(cooldownsCount);
-
- time_t curTime = time(NULL);
-
- for (CreatureSpellCooldowns::const_iterator itr = pet->m_CreatureSpellCooldowns.begin(); itr != pet->m_CreatureSpellCooldowns.end(); ++itr)
- {
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
- if (!spellInfo)
- {
- data << uint32(0);
- data << uint16(0);
- data << uint32(0);
- data << uint32(0);
- continue;
- }
-
- time_t cooldown = (itr->second > curTime) ? (itr->second - curTime) * IN_MILLISECONDS : 0;
- data << uint32(itr->first); // spell ID
-
- CreatureSpellCooldowns::const_iterator categoryitr = pet->m_CreatureCategoryCooldowns.find(spellInfo->GetCategory());
- if (categoryitr != pet->m_CreatureCategoryCooldowns.end())
- {
- time_t categoryCooldown = (categoryitr->second > curTime) ? (categoryitr->second - curTime) * IN_MILLISECONDS : 0;
- data << uint16(spellInfo->GetCategory()); // spell category
- data << uint32(cooldown); // spell cooldown
- data << uint32(categoryCooldown); // category cooldown
- }
- else
- {
- data << uint16(0);
- data << uint32(cooldown);
- data << uint32(0);
- }
- }
+ //Cooldowns
+ pet->GetSpellHistory()->WritePacket<Pet>(data);
GetSession()->SendPacket(&data);
}
@@ -20827,7 +20624,7 @@ void Player::VehicleSpellInitialize()
if (!vehicle)
return;
- uint8 cooldownCount = vehicle->m_CreatureSpellCooldowns.size();
+ uint8 cooldownCount = vehicle->GetSpellHistory()->GetCooldownsSizeForPacket();
WorldPacket data(SMSG_PET_SPELLS, 8 + 2 + 4 + 4 + 4 * 10 + 1 + 1 + cooldownCount * (4 + 2 + 4 + 4));
data << uint64(vehicle->GetGUID()); // Guid
@@ -20868,41 +20665,7 @@ void Player::VehicleSpellInitialize()
data << uint8(0); // Auras?
// Cooldowns
- data << uint8(cooldownCount);
-
- time_t now = sWorld->GetGameTime();
-
- for (CreatureSpellCooldowns::const_iterator itr = vehicle->m_CreatureSpellCooldowns.begin(); itr != vehicle->m_CreatureSpellCooldowns.end(); ++itr)
- {
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
- if (!spellInfo)
- {
- data << uint32(0);
- data << uint16(0);
- data << uint32(0);
- data << uint32(0);
- continue;
- }
-
- time_t cooldown = (itr->second > now) ? (itr->second - now) * IN_MILLISECONDS : 0;
- data << uint32(itr->first); // spell ID
-
- CreatureSpellCooldowns::const_iterator categoryitr = vehicle->m_CreatureCategoryCooldowns.find(spellInfo->GetCategory());
- if (categoryitr != vehicle->m_CreatureCategoryCooldowns.end())
- {
- time_t categoryCooldown = (categoryitr->second > now) ? (categoryitr->second - now) * IN_MILLISECONDS : 0;
- data << uint16(spellInfo->GetCategory()); // spell category
- data << uint32(cooldown); // spell cooldown
- data << uint32(categoryCooldown); // category cooldown
- }
- else
- {
- data << uint16(0);
- data << uint32(cooldown);
- data << uint32(0);
- }
- }
-
+ vehicle->GetSpellHistory()->WritePacket<Pet>(data);
GetSession()->SendPacket(&data);
}
@@ -21522,9 +21285,9 @@ void Player::ContinueTaxiFlight()
float distPrev = MAP_SIZE*MAP_SIZE;
float distNext =
- (nodeList[0].x-GetPositionX())*(nodeList[0].x-GetPositionX())+
- (nodeList[0].y-GetPositionY())*(nodeList[0].y-GetPositionY())+
- (nodeList[0].z-GetPositionZ())*(nodeList[0].z-GetPositionZ());
+ (nodeList[0].LocX-GetPositionX())*(nodeList[0].LocX-GetPositionX())+
+ (nodeList[0].LocY-GetPositionY())*(nodeList[0].LocY-GetPositionY())+
+ (nodeList[0].LocZ-GetPositionZ())*(nodeList[0].LocZ-GetPositionZ());
for (uint32 i = 1; i < nodeList.size(); ++i)
{
@@ -21532,20 +21295,20 @@ void Player::ContinueTaxiFlight()
TaxiPathNodeEntry const& prevNode = nodeList[i-1];
// skip nodes at another map
- if (node.mapid != GetMapId())
+ if (node.MapID != GetMapId())
continue;
distPrev = distNext;
distNext =
- (node.x-GetPositionX())*(node.x-GetPositionX())+
- (node.y-GetPositionY())*(node.y-GetPositionY())+
- (node.z-GetPositionZ())*(node.z-GetPositionZ());
+ (node.LocX-GetPositionX())*(node.LocX-GetPositionX())+
+ (node.LocY-GetPositionY())*(node.LocY-GetPositionY())+
+ (node.LocZ-GetPositionZ())*(node.LocZ-GetPositionZ());
float distNodes =
- (node.x-prevNode.x)*(node.x-prevNode.x)+
- (node.y-prevNode.y)*(node.y-prevNode.y)+
- (node.z-prevNode.z)*(node.z-prevNode.z);
+ (node.LocX-prevNode.LocX)*(node.LocX-prevNode.LocX)+
+ (node.LocY-prevNode.LocY)*(node.LocY-prevNode.LocY)+
+ (node.LocZ-prevNode.LocZ)*(node.LocZ-prevNode.LocZ);
if (distNext + distPrev < distNodes)
{
@@ -21557,39 +21320,6 @@ void Player::ContinueTaxiFlight()
GetSession()->SendDoFlight(mountDisplayId, path, startNode);
}
-void Player::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs)
-{
- PacketCooldowns cooldowns;
- WorldPacket data;
- time_t curTime = time(NULL);
- for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
- {
- if (itr->second->state == PLAYERSPELL_REMOVED)
- continue;
- uint32 unSpellId = itr->first;
- SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(unSpellId);
-
- // Not send cooldown for this spells
- if (spellInfo->IsCooldownStartedOnEvent())
- continue;
-
- if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE)
- continue;
-
- if ((idSchoolMask & spellInfo->GetSchoolMask()) && GetSpellCooldownDelay(unSpellId) < unTimeMs)
- {
- cooldowns[unSpellId] = unTimeMs;
- AddSpellCooldown(unSpellId, 0, curTime + unTimeMs/IN_MILLISECONDS);
- }
- }
-
- if (!cooldowns.empty())
- {
- BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, cooldowns);
- GetSession()->SendPacket(&data);
- }
-}
-
void Player::InitDataForForm(bool reapplyMods)
{
ShapeshiftForm form = GetShapeshiftForm();
@@ -22011,206 +21741,6 @@ void Player::UpdatePvP(bool state, bool _override)
}
}
-bool Player::HasSpellCooldown(uint32 spell_id) const
-{
- SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id);
- return itr != m_spellCooldowns.end() && itr->second.end > time(NULL);
-}
-
-uint32 Player::GetSpellCooldownDelay(uint32 spell_id) const
-{
- SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id);
- time_t t = time(NULL);
- return uint32(itr != m_spellCooldowns.end() && itr->second.end > t ? itr->second.end - t : 0);
-}
-
-void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 itemId, Spell* spell, bool infinityCooldown)
-{
- // init cooldown values
- uint32 cat = 0;
- int32 rec = -1;
- int32 catrec = -1;
-
- // some special item spells without correct cooldown in SpellInfo
- // cooldown information stored in item prototype
- // This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client.
-
- if (itemId)
- {
- if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId))
- {
- for (uint8 idx = 0; idx < MAX_ITEM_SPELLS; ++idx)
- {
- if (uint32(proto->Spells[idx].SpellId) == spellInfo->Id)
- {
- cat = proto->Spells[idx].SpellCategory;
- rec = proto->Spells[idx].SpellCooldown;
- catrec = proto->Spells[idx].SpellCategoryCooldown;
- break;
- }
- }
- }
- }
-
- // if no cooldown found above then base at DBC data
- if (rec < 0 && catrec < 0)
- {
- cat = spellInfo->GetCategory();
- rec = spellInfo->RecoveryTime;
- catrec = spellInfo->CategoryRecoveryTime;
- }
-
- time_t curTime = time(NULL);
-
- time_t catrecTime;
- time_t recTime;
-
- bool needsCooldownPacket = false;
-
- // overwrite time for selected category
- if (infinityCooldown)
- {
- // use +MONTH as infinity mark for spell cooldown (will checked as MONTH/2 at save ans skipped)
- // but not allow ignore until reset or re-login
- catrecTime = catrec > 0 ? curTime+infinityCooldownDelay : 0;
- recTime = rec > 0 ? curTime+infinityCooldownDelay : catrecTime;
- }
- else
- {
- // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
- // prevent 0 cooldowns set by another way
- if (rec <= 0 && catrec <= 0 && (cat == 76 || (spellInfo->IsAutoRepeatRangedSpell() && spellInfo->Id != 75)))
- rec = GetAttackTime(RANGED_ATTACK);
-
- // Now we have cooldown data (if found any), time to apply mods
- if (rec > 0)
- ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, rec, spell);
-
- if (catrec > 0 && !spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS))
- ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, catrec, spell);
-
- if (int32 cooldownMod = GetTotalAuraModifier(SPELL_AURA_MOD_COOLDOWN))
- {
- // Apply SPELL_AURA_MOD_COOLDOWN only to own spells
- if (HasSpell(spellInfo->Id))
- {
- needsCooldownPacket = true;
- rec += cooldownMod * IN_MILLISECONDS; // SPELL_AURA_MOD_COOLDOWN does not affect category cooldows, verified with shaman shocks
- }
- }
-
- // replace negative cooldowns by 0
- if (rec < 0) rec = 0;
- if (catrec < 0) catrec = 0;
-
- // no cooldown after applying spell mods
- if (rec == 0 && catrec == 0)
- return;
-
- catrecTime = catrec ? curTime+catrec/IN_MILLISECONDS : 0;
- recTime = rec ? curTime+rec/IN_MILLISECONDS : catrecTime;
- }
-
- // self spell cooldown
- if (recTime > 0)
- {
- AddSpellCooldown(spellInfo->Id, itemId, recTime);
-
- if (needsCooldownPacket)
- {
- WorldPacket data;
- BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, rec);
- SendDirectMessage(&data);
- }
- }
-
- // category spells
- if (cat && catrec > 0)
- {
- SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(cat);
- if (i_scstore != sSpellsByCategoryStore.end())
- {
- for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
- {
- if (*i_scset == spellInfo->Id) // skip main spell, already handled above
- continue;
-
- AddSpellCooldown(*i_scset, itemId, catrecTime);
- }
- }
- }
-}
-
-void Player::AddSpellCooldown(uint32 spellid, uint32 itemid, time_t end_time)
-{
- SpellCooldown sc;
- sc.end = end_time;
- sc.itemid = itemid;
- m_spellCooldowns[spellid] = sc;
-}
-
-void Player::ModifySpellCooldown(uint32 spellId, int32 cooldown)
-{
- SpellCooldowns::iterator itr = m_spellCooldowns.find(spellId);
- if (itr == m_spellCooldowns.end())
- return;
-
- time_t now = time(NULL);
- if (itr->second.end + (cooldown / IN_MILLISECONDS) > now)
- itr->second.end += (cooldown / IN_MILLISECONDS);
- else
- m_spellCooldowns.erase(itr);
-
- WorldPacket data(SMSG_MODIFY_COOLDOWN, 4 + 8 + 4);
- data << uint32(spellId); // Spell ID
- data << uint64(GetGUID()); // Player GUID
- data << int32(cooldown); // Cooldown mod in milliseconds
- GetSession()->SendPacket(&data);
-
- TC_LOG_DEBUG("misc", "ModifySpellCooldown:: Player: %s (GUID: %u) Spell: %u cooldown: %u", GetName().c_str(), GetGUIDLow(), spellId, GetSpellCooldownDelay(spellId));
-}
-
-void Player::SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId /*= 0*/, Spell* spell /*= NULL*/, bool setCooldown /*= true*/)
-{
- // start cooldowns at server side, if any
- if (setCooldown)
- AddSpellAndCategoryCooldowns(spellInfo, itemId, spell);
-
- // Send activate cooldown timer (possible 0) at client side
- WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8);
- data << uint32(spellInfo->Id);
- data << uint64(GetGUID());
- SendDirectMessage(&data);
-
- uint32 cat = spellInfo->GetCategory();
- if (cat && spellInfo->CategoryRecoveryTime)
- {
- SpellCategoryStore::const_iterator ct = sSpellsByCategoryStore.find(cat);
- if (ct != sSpellsByCategoryStore.end())
- {
- SpellCategorySet const& catSet = ct->second;
- for (SpellCooldowns::const_iterator i = m_spellCooldowns.begin(); i != m_spellCooldowns.end(); ++i)
- {
- if (i->first == spellInfo->Id) // skip main spell, already handled above
- continue;
-
- SpellInfo const* spellInfo2 = sSpellMgr->GetSpellInfo(i->first);
- if (!spellInfo2 || !spellInfo2->IsCooldownStartedOnEvent())
- continue;
-
- if (catSet.find(i->first) != catSet.end())
- {
- // Send activate cooldown timer (possible 0) at client side
- WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8);
- data << uint32(i->first);
- data << uint64(GetGUID());
- SendDirectMessage(&data);
- }
- }
- }
- }
-}
-
void Player::UpdatePotionCooldown(Spell* spell)
{
// no potion used i combat or still in combat
@@ -22222,14 +21752,14 @@ void Player::UpdatePotionCooldown(Spell* spell)
{
// spell/item pair let set proper cooldown (except not existed charged spell cooldown spellmods for potions)
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(m_lastPotionId))
- for (uint8 idx = 0; idx < MAX_ITEM_SPELLS; ++idx)
+ for (uint8 idx = 0; idx < MAX_ITEM_PROTO_SPELLS; ++idx)
if (proto->Spells[idx].SpellId && proto->Spells[idx].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Spells[idx].SpellId))
- SendCooldownEvent(spellInfo, m_lastPotionId);
+ GetSpellHistory()->SendCooldownEvent(spellInfo, m_lastPotionId);
}
// from spell cases (m_lastPotionId set in Spell::SendSpellCooldown)
else
- SendCooldownEvent(spell->m_spellInfo, m_lastPotionId, spell);
+ GetSpellHistory()->SendCooldownEvent(spell->m_spellInfo, m_lastPotionId, spell);
m_lastPotionId = 0;
}
@@ -23139,14 +22669,13 @@ void Player::ApplyEquipCooldown(Item* pItem)
continue;
// Don't replace longer cooldowns by equip cooldown if we have any.
- SpellCooldowns::iterator itr = m_spellCooldowns.find(spellData.SpellId);
- if (itr != m_spellCooldowns.end() && itr->second.itemid == pItem->GetEntry() && itr->second.end > time(NULL) + 30)
+ if (GetSpellHistory()->GetRemainingCooldown(spellData.SpellId) > 30 * IN_MILLISECONDS)
continue;
- AddSpellCooldown(spellData.SpellId, pItem->GetEntry(), time(NULL) + 30);
+ GetSpellHistory()->AddCooldown(spellData.SpellId, pItem->GetEntry(), std::chrono::seconds(30));
- WorldPacket data(SMSG_ITEM_COOLDOWN, 12);
- data << pItem->GetGUID();
+ WorldPacket data(SMSG_ITEM_COOLDOWN, 8 + 4);
+ data << uint64(pItem->GetGUID());
data << uint32(spellData.SpellId);
GetSession()->SendPacket(&data);
}
@@ -24017,7 +23546,7 @@ uint32 Player::GetResurrectionSpellId()
}
// Reincarnation (passive spell) // prio: 1 // Glyph of Renewed Life
- if (prio < 1 && HasSpell(20608) && !HasSpellCooldown(21169) && (HasAura(58059) || HasItemCount(17030)))
+ if (prio < 1 && HasSpell(20608) && !GetSpellHistory()->HasCooldown(21169) && (HasAura(58059) || HasItemCount(17030)))
spell_id = 21169;
return spell_id;
@@ -26072,14 +25601,6 @@ void Player::RemoveAtLoginFlag(AtLoginFlags flags, bool persist /*= false*/)
}
}
-void Player::SendClearCooldown(uint32 spell_id, Unit* target)
-{
- WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8);
- data << uint32(spell_id);
- data << uint64(target->GetGUID());
- SendDirectMessage(&data);
-}
-
void Player::ResetMap()
{
// this may be called during Map::Update
@@ -26730,9 +26251,9 @@ bool Player::SetDisableGravity(bool disable, bool packetOnly /*= false*/)
return true;
}
-bool Player::SetCanFly(bool apply)
+bool Player::SetCanFly(bool apply, bool packetOnly /*= false*/)
{
- if (!Unit::SetCanFly(apply))
+ if (!packetOnly && !Unit::SetCanFly(apply))
return false;
WorldPacket data(apply ? SMSG_MOVE_SET_CAN_FLY : SMSG_MOVE_UNSET_CAN_FLY, 12);
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index e3a7f39b2ba..98b9d8a3d07 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -128,13 +128,6 @@ typedef std::unordered_map<uint32, PlayerTalent*> PlayerTalentMap;
typedef std::unordered_map<uint32, PlayerSpell*> PlayerSpellMap;
typedef std::list<SpellModifier*> SpellModList;
-struct SpellCooldown
-{
- time_t end;
- uint16 itemid;
-};
-
-typedef std::map<uint32, SpellCooldown> SpellCooldowns;
typedef std::unordered_map<uint32 /*instanceId*/, time_t/*releaseTime*/> InstanceTimeMap;
enum TrainerSpellState
@@ -353,9 +346,9 @@ struct Runes
struct EnchantDuration
{
- EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) { };
+ EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) { }
EnchantDuration(Item* _item, EnchantmentSlot _slot, uint32 _leftduration) : item(_item), slot(_slot),
- leftduration(_leftduration){ ASSERT(item); };
+ leftduration(_leftduration){ ASSERT(item); }
Item* item;
EnchantmentSlot slot;
@@ -1655,8 +1648,6 @@ class Player : public Unit, public GridObject<Player>
PlayerSpellMap const& GetSpellMap() const { return m_spells; }
PlayerSpellMap & GetSpellMap() { return m_spells; }
- SpellCooldowns const& GetSpellCooldownMap() const { return m_spellCooldowns; }
-
void AddSpellMod(SpellModifier* mod, bool apply);
bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = NULL);
template <class T> T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell* spell = NULL);
@@ -1666,33 +1657,14 @@ class Player : public Unit, public GridObject<Player>
void DropModCharge(SpellModifier* mod, Spell* spell);
void SetSpellModTakingSpell(Spell* spell, bool apply);
- static uint32 const infinityCooldownDelay = MONTH; // used for set "infinity cooldowns" for spells and check
- static uint32 const infinityCooldownDelayCheck = MONTH/2;
- bool HasSpellCooldown(uint32 spell_id) const;
- uint32 GetSpellCooldownDelay(uint32 spell_id) const;
- void AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 itemId, Spell* spell = NULL, bool infinityCooldown = false);
- void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time);
- void ModifySpellCooldown(uint32 spellId, int32 cooldown);
- void SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId = 0, Spell* spell = NULL, bool setCooldown = true);
- void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) override;
- void RemoveSpellCooldown(uint32 spell_id, bool update = false);
- void RemoveSpellCategoryCooldown(uint32 cat, bool update = false);
- void SendClearCooldown(uint32 spell_id, Unit* target);
-
- GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; }
-
- void RemoveCategoryCooldown(uint32 cat);
void RemoveArenaSpellCooldowns(bool removeActivePetCooldowns = false);
- void RemoveAllSpellCooldown();
- void _LoadSpellCooldowns(PreparedQueryResult result);
- void _SaveSpellCooldowns(SQLTransaction& trans);
uint32 GetLastPotionId() { return m_lastPotionId; }
void SetLastPotionId(uint32 item_id) { m_lastPotionId = item_id; }
void UpdatePotionCooldown(Spell* spell = NULL);
void setResurrectRequestData(ObjectGuid guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana);
void clearResurrectRequestData() { setResurrectRequestData(ObjectGuid::Empty, 0, 0.0f, 0.0f, 0.0f, 0, 0); }
- bool isResurrectRequestedBy(ObjectGuid guid) const { return m_resurrectGUID == guid; }
+ bool isResurrectRequestedBy(ObjectGuid guid) const { return !m_resurrectGUID.IsEmpty() && m_resurrectGUID == guid; }
bool isResurrectRequested() const { return !m_resurrectGUID.IsEmpty(); }
void ResurrectUsingRequestData();
@@ -1867,7 +1839,7 @@ class Player : public Unit, public GridObject<Player>
bool UpdatePosition(const Position &pos, bool teleport = false) { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); }
void UpdateUnderwaterState(Map* m, float x, float y, float z) override;
- void SendMessageToSet(WorldPacket* data, bool self) override {SendMessageToSetInRange(data, GetVisibilityRange(), self); };// overwrite Object::SendMessageToSet
+ void SendMessageToSet(WorldPacket* data, bool self) override {SendMessageToSetInRange(data, GetVisibilityRange(), self); }// overwrite Object::SendMessageToSet
void SendMessageToSetInRange(WorldPacket* data, float fist, bool self) override;// overwrite Object::SendMessageToSetInRange
void SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool own_team_only);
void SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr) override;
@@ -1975,8 +1947,6 @@ class Player : public Unit, public GridObject<Player>
//End of PvP System
- inline SpellCooldowns GetSpellCooldowns() const { return m_spellCooldowns; }
-
void SetDrunkValue(uint8 newDrunkValue, uint32 itemId = 0);
uint8 GetDrunkValue() const { return GetByteValue(PLAYER_BYTES_3, 1); }
static DrunkenState GetDrunkenstateByValue(uint8 value);
@@ -2331,7 +2301,7 @@ class Player : public Unit, public GridObject<Player>
void RemoveFromWhisperWhiteList(ObjectGuid guid) { WhisperList.remove(guid); }
bool SetDisableGravity(bool disable, bool packetOnly /* = false */) override;
- bool SetCanFly(bool apply) override;
+ bool SetCanFly(bool apply, bool packetOnly = false) override;
bool SetWaterWalking(bool apply, bool packetOnly = false) override;
bool SetFeatherFall(bool apply, bool packetOnly = false) override;
bool SetHover(bool enable, bool packetOnly = false) override;
@@ -2493,8 +2463,6 @@ class Player : public Unit, public GridObject<Player>
PlayerTalentMap* m_talents[MAX_TALENT_SPECS];
uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use
- GlobalCooldownMgr m_GlobalCooldownMgr;
-
uint8 m_activeSpec;
uint8 m_specsCount;
@@ -2662,8 +2630,6 @@ class Player : public Unit, public GridObject<Player>
AchievementMgr* m_achievementMgr;
ReputationMgr* m_reputationMgr;
- SpellCooldowns m_spellCooldowns;
-
uint32 m_ChampioningFaction;
uint32 m_timeSyncCounter;
diff --git a/src/server/game/Entities/Totem/Totem.cpp b/src/server/game/Entities/Totem/Totem.cpp
index 39a078a907f..85ee51aebf5 100644
--- a/src/server/game/Entities/Totem/Totem.cpp
+++ b/src/server/game/Entities/Totem/Totem.cpp
@@ -20,6 +20,7 @@
#include "Group.h"
#include "Opcodes.h"
#include "Player.h"
+#include "SpellHistory.h"
#include "SpellMgr.h"
#include "SpellInfo.h"
#include "WorldPacket.h"
@@ -128,7 +129,7 @@ void Totem::UnSummon(uint32 msTime)
owner->SendAutoRepeatCancel(this);
if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(GetUInt32Value(UNIT_CREATED_BY_SPELL)))
- owner->SendCooldownEvent(spell, 0, NULL, false);
+ GetSpellHistory()->SendCooldownEvent(spell, 0, nullptr, false);
if (Group* group = owner->GetGroup())
{
diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp
index 7b219e4dc15..6d98a4c78b2 100644
--- a/src/server/game/Entities/Transport/Transport.cpp
+++ b/src/server/game/Entities/Transport/Transport.cpp
@@ -32,7 +32,7 @@
Transport::Transport() : GameObject(),
_transportInfo(NULL), _isMoving(true), _pendingStop(false),
_triggeredArrivalEvent(false), _triggeredDepartureEvent(false),
- _passengerTeleportItr(_passengers.begin()), _delayedAddModel(false)
+ _passengerTeleportItr(_passengers.begin()), _delayedAddModel(false), _delayedTeleport(false)
{
m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION;
}
@@ -125,7 +125,7 @@ void Transport::Update(uint32 diff)
if (IsMoving() || !_pendingStop)
m_goValue.Transport.PathProgress += diff;
- uint32 timer = m_goValue.Transport.PathProgress % GetPeriod();
+ uint32 timer = m_goValue.Transport.PathProgress % GetTransportPeriod();
// Set current waypoint
// Desired outcome: _currentFrame->DepartureTime < timer < _nextFrame->ArriveTime
@@ -147,8 +147,8 @@ void Transport::Update(uint32 diff)
if (_pendingStop && GetGoState() != GO_STATE_READY)
{
SetGoState(GO_STATE_READY);
- m_goValue.Transport.PathProgress = (m_goValue.Transport.PathProgress / GetPeriod());
- m_goValue.Transport.PathProgress *= GetPeriod();
+ m_goValue.Transport.PathProgress = (m_goValue.Transport.PathProgress / GetTransportPeriod());
+ m_goValue.Transport.PathProgress *= GetTransportPeriod();
m_goValue.Transport.PathProgress += _currentFrame->ArriveTime;
}
break; // its a stop frame and we are waiting
@@ -173,13 +173,13 @@ void Transport::Update(uint32 diff)
MoveToNextWaypoint();
- sScriptMgr->OnRelocate(this, _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z);
+ sScriptMgr->OnRelocate(this, _currentFrame->Node->NodeIndex, _currentFrame->Node->MapID, _currentFrame->Node->LocX, _currentFrame->Node->LocY, _currentFrame->Node->LocZ);
- TC_LOG_DEBUG("entities.transport", "Transport %u (%s) moved to node %u %u %f %f %f", GetEntry(), GetName().c_str(), _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z);
+ TC_LOG_DEBUG("entities.transport", "Transport %u (%s) moved to node %u %u %f %f %f", GetEntry(), GetName().c_str(), _currentFrame->Node->NodeIndex, _currentFrame->Node->MapID, _currentFrame->Node->LocX, _currentFrame->Node->LocY, _currentFrame->Node->LocZ);
// Departure event
if (_currentFrame->IsTeleportFrame())
- if (TeleportTransport(_nextFrame->Node->mapid, _nextFrame->Node->x, _nextFrame->Node->y, _nextFrame->Node->z, _nextFrame->InitialOrientation))
+ if (TeleportTransport(_nextFrame->Node->MapID, _nextFrame->Node->LocX, _nextFrame->Node->LocY, _nextFrame->Node->LocZ, _nextFrame->InitialOrientation))
return; // Update more in new map thread
}
@@ -226,6 +226,14 @@ void Transport::Update(uint32 diff)
sScriptMgr->OnTransportUpdate(this, diff);
}
+void Transport::DelayedUpdate(uint32 /*diff*/)
+{
+ if (GetKeyFrames().size() <= 1)
+ return;
+
+ DelayedTeleportTransport();
+}
+
void Transport::AddPassenger(WorldObject* passenger)
{
if (!IsInWorld())
@@ -591,36 +599,8 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
if (oldMap->GetId() != newMapid)
{
- Map* newMap = sMapMgr->CreateBaseMap(newMapid);
+ _delayedTeleport = true;
UnloadStaticPassengers();
- GetMap()->RemoveFromMap<Transport>(this, false);
- SetMap(newMap);
-
- for (_passengerTeleportItr = _passengers.begin(); _passengerTeleportItr != _passengers.end();)
- {
- WorldObject* obj = (*_passengerTeleportItr++);
-
- float destX, destY, destZ, destO;
- obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO);
- TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, o);
-
- switch (obj->GetTypeId())
- {
- case TYPEID_PLAYER:
- if (!obj->ToPlayer()->TeleportTo(newMapid, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT))
- RemovePassenger(obj);
- break;
- case TYPEID_DYNAMICOBJECT:
- obj->AddObjectToRemoveList();
- break;
- default:
- RemovePassenger(obj);
- break;
- }
- }
-
- Relocate(x, y, z, o);
- GetMap()->AddToMap<Transport>(this);
return true;
}
else
@@ -643,6 +623,48 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
}
}
+void Transport::DelayedTeleportTransport()
+{
+ if (!_delayedTeleport)
+ return;
+
+ _delayedTeleport = false;
+ Map* newMap = sMapMgr->CreateBaseMap(_nextFrame->Node->MapID);
+ GetMap()->RemoveFromMap<Transport>(this, false);
+ SetMap(newMap);
+
+ float x = _nextFrame->Node->LocX,
+ y = _nextFrame->Node->LocY,
+ z = _nextFrame->Node->LocZ,
+ o =_nextFrame->InitialOrientation;
+
+ for (_passengerTeleportItr = _passengers.begin(); _passengerTeleportItr != _passengers.end();)
+ {
+ WorldObject* obj = (*_passengerTeleportItr++);
+
+ float destX, destY, destZ, destO;
+ obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO);
+ TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, o);
+
+ switch (obj->GetTypeId())
+ {
+ case TYPEID_PLAYER:
+ if (!obj->ToPlayer()->TeleportTo(_nextFrame->Node->MapID, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT))
+ RemovePassenger(obj);
+ break;
+ case TYPEID_DYNAMICOBJECT:
+ obj->AddObjectToRemoveList();
+ break;
+ default:
+ RemovePassenger(obj);
+ break;
+ }
+ }
+
+ Relocate(x, y, z, o);
+ GetMap()->AddToMap<Transport>(this);
+}
+
void Transport::UpdatePassengerPositions(PassengerSet& passengers)
{
for (PassengerSet::iterator itr = passengers.begin(); itr != passengers.end(); ++itr)
@@ -697,9 +719,9 @@ void Transport::UpdatePassengerPositions(PassengerSet& passengers)
void Transport::DoEventIfAny(KeyFrame const& node, bool departure)
{
- if (uint32 eventid = departure ? node.Node->departureEventID : node.Node->arrivalEventID)
+ if (uint32 eventid = departure ? node.Node->DepartureEventID : node.Node->ArrivalEventID)
{
- TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of %s path", departure ? "departure" : "arrival", eventid, node.Node->index, GetName().c_str());
+ TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of %s path", departure ? "departure" : "arrival", eventid, node.Node->NodeIndex, GetName().c_str());
GetMap()->ScriptsStart(sEventScripts, eventid, this, this);
EventInform(eventid);
}
diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h
index 4e3d7c3c50e..c56ceb1696d 100644
--- a/src/server/game/Entities/Transport/Transport.h
+++ b/src/server/game/Entities/Transport/Transport.h
@@ -39,6 +39,7 @@ class Transport : public GameObject, public TransportBase
void CleanupsBeforeDelete(bool finalCleanup = true) override;
void Update(uint32 diff) override;
+ void DelayedUpdate(uint32 diff);
void BuildUpdate(UpdateDataMapType& data_map) override;
@@ -79,7 +80,7 @@ class Transport : public GameObject, public TransportBase
TransportBase::CalculatePassengerOffset(x, y, z, o, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
}
- uint32 GetPeriod() const { return GetUInt32Value(GAMEOBJECT_LEVEL); }
+ uint32 GetTransportPeriod() const override { return GetUInt32Value(GAMEOBJECT_LEVEL); }
void SetPeriod(uint32 period) { SetUInt32Value(GAMEOBJECT_LEVEL, period); }
uint32 GetTimer() const { return GetGOValue()->Transport.PathProgress; }
@@ -103,6 +104,7 @@ class Transport : public GameObject, public TransportBase
void MoveToNextWaypoint();
float CalculateSegmentPos(float perc);
bool TeleportTransport(uint32 newMapid, float x, float y, float z, float o);
+ void DelayedTeleportTransport();
void UpdatePassengerPositions(PassengerSet& passengers);
void DoEventIfAny(KeyFrame const& node, bool departure);
@@ -127,6 +129,7 @@ class Transport : public GameObject, public TransportBase
PassengerSet _staticPassengers;
bool _delayedAddModel;
+ bool _delayedTeleport;
};
#endif
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 7c2272c0d08..9b0da57fa31 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -51,6 +51,7 @@
#include "SpellAuras.h"
#include "Spell.h"
#include "SpellInfo.h"
+#include "SpellHistory.h"
#include "SpellMgr.h"
#include "TemporarySummon.h"
#include "Totem.h"
@@ -163,7 +164,7 @@ Unit::Unit(bool isWorldObject) :
i_AI(NULL), i_disabledAI(NULL), m_AutoRepeatFirstCast(false), m_procDeep(0),
m_removedAurasCount(0), i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_ThreatManager(this),
m_vehicle(NULL), m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE),
- m_HostileRefManager(this), _lastDamagedTime(0)
+ m_HostileRefManager(this), _lastDamagedTime(0), m_spellHistory(new SpellHistory(this))
{
m_objectType |= TYPEMASK_UNIT;
m_objectTypeId = TYPEID_UNIT;
@@ -257,24 +258,6 @@ Unit::Unit(bool isWorldObject) :
}
////////////////////////////////////////////////////////////
-// Methods of class GlobalCooldownMgr
-bool GlobalCooldownMgr::HasGlobalCooldown(SpellInfo const* spellInfo) const
-{
- GlobalCooldownList::const_iterator itr = m_GlobalCooldowns.find(spellInfo->StartRecoveryCategory);
- return itr != m_GlobalCooldowns.end() && itr->second.duration && getMSTimeDiff(itr->second.cast_time, getMSTime()) < itr->second.duration;
-}
-
-void GlobalCooldownMgr::AddGlobalCooldown(SpellInfo const* spellInfo, uint32 gcd)
-{
- m_GlobalCooldowns[spellInfo->StartRecoveryCategory] = GlobalCooldown(gcd, getMSTime());
-}
-
-void GlobalCooldownMgr::CancelGlobalCooldown(SpellInfo const* spellInfo)
-{
- m_GlobalCooldowns[spellInfo->StartRecoveryCategory].duration = 0;
-}
-
-////////////////////////////////////////////////////////////
// Methods of class Unit
Unit::~Unit()
{
@@ -291,6 +274,7 @@ Unit::~Unit()
delete i_motionMaster;
delete m_charmInfo;
delete movespline;
+ delete m_spellHistory;
ASSERT(!m_duringRemoveFromWorld);
ASSERT(!m_attacking);
@@ -406,7 +390,7 @@ void Unit::UpdateSplinePosition()
pos.m_positionX = loc.x;
pos.m_positionY = loc.y;
pos.m_positionZ = loc.z;
- pos.m_orientation = loc.orientation;
+ pos.SetOrientation(loc.orientation);
if (TransportBase* transport = GetDirectTransport())
transport->CalculatePassengerPosition(loc.x, loc.y, loc.z, &loc.orientation);
@@ -2925,6 +2909,8 @@ void Unit::_UpdateSpells(uint32 time)
++itr;
}
}
+
+ m_spellHistory->Update();
}
void Unit::_UpdateAutoRepeatSpell()
@@ -4860,13 +4846,13 @@ void Unit::AddGameObject(GameObject* gameObj)
m_gameObj.push_back(gameObj);
gameObj->SetOwnerGUID(GetGUID());
- if (GetTypeId() == TYPEID_PLAYER && gameObj->GetSpellId())
+ if (gameObj->GetSpellId())
{
SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(gameObj->GetSpellId());
// Need disable spell use for owner
if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
// note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
- ToPlayer()->AddSpellAndCategoryCooldowns(createBySpell, 0, NULL, true);
+ GetSpellHistory()->StartCooldown(createBySpell, 0, nullptr, true);
}
}
@@ -4891,14 +4877,11 @@ void Unit::RemoveGameObject(GameObject* gameObj, bool del)
{
RemoveAurasDueToSpell(spellid);
- if (GetTypeId() == TYPEID_PLAYER)
- {
- SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid);
- // Need activate spell use for owner
- if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
- // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
- ToPlayer()->SendCooldownEvent(createBySpell);
- }
+ SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid);
+ // Need activate spell use for owner
+ if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
+ // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
+ GetSpellHistory()->SendCooldownEvent(createBySpell);
}
m_gameObj.remove(gameObj);
@@ -5488,8 +5471,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster);
for (std::vector<uint32>::iterator itr = RandomSpells.begin(); itr != RandomSpells.end(); ++itr)
{
- if (!ToPlayer()->HasSpellCooldown(*itr))
- ToPlayer()->AddSpellCooldown(*itr, 0, time(NULL) + cooldown);
+ if (!GetSpellHistory()->HasCooldown(*itr))
+ GetSpellHistory()->AddCooldown(*itr, 0, std::chrono::seconds(cooldown));
}
break;
}
@@ -5534,8 +5517,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster);
for (std::vector<uint32>::iterator itr = RandomSpells.begin(); itr != RandomSpells.end(); ++itr)
{
- if (!ToPlayer()->HasSpellCooldown(*itr))
- ToPlayer()->AddSpellCooldown(*itr, 0, time(NULL) + cooldown);
+ if (!GetSpellHistory()->HasCooldown(*itr))
+ GetSpellHistory()->AddCooldown(*itr, 0, std::chrono::seconds(cooldown));
}
break;
}
@@ -5639,20 +5622,17 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
// Glyph of Ice Block
case 56372:
{
- Player* player = ToPlayer();
- if (!player)
+ if (GetTypeId() != TYPEID_PLAYER)
return false;
- SpellCooldowns const cooldowns = player->GetSpellCooldowns();
- // remove cooldowns on all ranks of Frost Nova
- for (SpellCooldowns::const_iterator itr = cooldowns.begin(); itr != cooldowns.end(); ++itr)
+ GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
{
SpellInfo const* cdSpell = sSpellMgr->GetSpellInfo(itr->first);
- // Frost Nova
- if (cdSpell && cdSpell->SpellFamilyName == SPELLFAMILY_MAGE
- && cdSpell->SpellFamilyFlags[0] & 0x00000040)
- player->RemoveSpellCooldown(cdSpell->Id, true);
- }
+ if (!cdSpell || cdSpell->SpellFamilyName != SPELLFAMILY_MAGE
+ || !(cdSpell->SpellFamilyFlags[0] & 0x00000040))
+ return false;
+ return true;
+ }, true);
break;
}
case 47020: // Enter vehicle XT-002 (Scrapbot)
@@ -6061,7 +6041,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
int32 basepoints1 = CalculatePct(GetMaxPower(Powers(POWER_MANA)), triggerAmount * 2);
// Improved Leader of the Pack
// Check cooldown of heal spell cooldown
- if (GetTypeId() == TYPEID_PLAYER && !ToPlayer()->HasSpellCooldown(34299))
+ if (!GetSpellHistory()->HasCooldown(34299))
CastCustomSpell(this, 68285, &basepoints1, 0, 0, true, 0, triggeredByAura);
break;
}
@@ -6732,7 +6712,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
return false;
// custom cooldown processing case
- if (cooldown && player->HasSpellCooldown(dummySpell->Id))
+ if (cooldown && GetSpellHistory()->HasCooldown(dummySpell->Id))
return false;
if (triggeredByAura->GetBase() && castItem->GetGUID() != triggeredByAura->GetBase()->GetCastItemGUID())
@@ -6798,7 +6778,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
// apply cooldown before cast to prevent processing itself
if (cooldown)
- player->AddSpellCooldown(dummySpell->Id, 0, time(NULL) + cooldown);
+ player->GetSpellHistory()->AddCooldown(dummySpell->Id, 0, std::chrono::seconds(cooldown));
// Attack Twice
for (uint32 i = 0; i < 2; ++i)
@@ -7040,7 +7020,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
return false;
// custom cooldown processing case
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(dummySpell->Id))
+ if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(dummySpell->Id))
return false;
uint32 spellId = 0;
@@ -7087,13 +7067,13 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
return false;
// Remove cooldown (Chain Lightning - has Category Recovery time)
- ToPlayer()->RemoveSpellCooldown(spellId);
+ GetSpellHistory()->ResetCooldown(spellId);
}
CastSpell(victim, spellId, true, castItem, triggeredByAura);
if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(dummySpell->Id, 0, time(NULL) + cooldown);
+ GetSpellHistory()->AddCooldown(dummySpell->Id, 0, std::chrono::seconds(cooldown));
return true;
}
@@ -7106,8 +7086,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
uint32 spell = sSpellMgr->GetSpellWithRank(26364, aurEff->GetSpellInfo()->GetRank());
// custom cooldown processing case
- if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(spell))
- ToPlayer()->RemoveSpellCooldown(spell);
+ if (GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(spell))
+ GetSpellHistory()->ResetCooldown(spell);
CastSpell(target, spell, true, castItem, triggeredByAura);
aurEff->GetBase()->DropCharge();
@@ -7399,7 +7379,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
if (cooldown_spell_id == 0)
cooldown_spell_id = triggered_spell_id;
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(cooldown_spell_id))
+ if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(cooldown_spell_id))
return false;
if (basepoints0)
@@ -7408,7 +7388,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura, originalCaster);
if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(cooldown_spell_id, 0, time(NULL) + cooldown);
+ GetSpellHistory()->AddCooldown(cooldown_spell_id, 0, std::chrono::seconds(cooldown));
return true;
}
@@ -7629,9 +7609,9 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp
*handled = true;
if (cooldown && GetTypeId() == TYPEID_PLAYER)
{
- if (ToPlayer()->HasSpellCooldown(100000))
+ if (GetSpellHistory()->HasCooldown(100000))
return false;
- ToPlayer()->AddSpellCooldown(100000, 0, time(NULL) + cooldown);
+ GetSpellHistory()->AddCooldown(100000, 0, std::chrono::seconds(cooldown));
}
return true;
}
@@ -8300,7 +8280,11 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
return false;
// Howling Blast
- ToPlayer()->RemoveSpellCategoryCooldown(1248, true);
+ GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
+ {
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
+ return spellInfo && spellInfo->GetCategory() == 1248;
+ }, true);
}
// Custom basepoints/target for exist spell
@@ -8319,13 +8303,13 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
if (!target)
return false;
- if (cooldown && target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->HasSpellCooldown(trigger_spell_id))
+ if (cooldown && target->GetTypeId() == TYPEID_PLAYER && target->GetSpellHistory()->HasCooldown(trigger_spell_id))
return false;
target->CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura);
if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown);
+ GetSpellHistory()->AddCooldown(trigger_spell_id, 0, std::chrono::seconds(cooldown));
return true;
}
// Cast positive spell on enemy target
@@ -8408,8 +8392,11 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
case 50227:
{
// Remove cooldown on Shield Slam
- if (GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->RemoveSpellCategoryCooldown(1209, true);
+ GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
+ {
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
+ return spellInfo && spellInfo->GetCategory() == 1209;
+ }, true);
break;
}
// Maelstrom Weapon
@@ -8469,8 +8456,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
case 58628:
{
// remove cooldown of Death Grip
- if (GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->RemoveSpellCooldown(49576, true);
+ GetSpellHistory()->ResetCooldown(49576, true);
return true;
}
// Savage Defense
@@ -8501,7 +8487,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
}
}
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(trigger_spell_id))
+ if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(trigger_spell_id))
return false;
// extra attack should hit same target
@@ -8518,7 +8504,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura);
if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown);
+ GetSpellHistory()->AddCooldown(trigger_spell_id, 0, std::chrono::seconds(cooldown));
return true;
}
@@ -8614,13 +8600,13 @@ bool Unit::HandleOverrideClassScriptAuraProc(Unit* victim, uint32 /*damage*/, Au
return false;
}
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
+ if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(triggered_spell_id))
return false;
CastSpell(victim, triggered_spell_id, true, castItem, triggeredByAura);
if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
+ GetSpellHistory()->AddCooldown(triggered_spell_id, 0, std::chrono::seconds(cooldown));
return true;
}
@@ -9355,14 +9341,11 @@ void Unit::SetMinion(Minion *minion, bool apply)
if (minion->IsPetGhoul())
minion->setPowerType(POWER_ENERGY);
- if (GetTypeId() == TYPEID_PLAYER)
- {
- // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
+ // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
- if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
- ToPlayer()->AddSpellAndCategoryCooldowns(spellInfo, 0, NULL, true);
- }
+ if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
+ GetSpellHistory()->StartCooldown(spellInfo, 0, nullptr, true);
}
else
{
@@ -9396,13 +9379,10 @@ void Unit::SetMinion(Minion *minion, bool apply)
}
}
- if (GetTypeId() == TYPEID_PLAYER)
- {
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
- // Remove infinity cooldown
- if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
- ToPlayer()->SendCooldownEvent(spellInfo);
- }
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
+ // Remove infinity cooldown
+ if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
+ GetSpellHistory()->SendCooldownEvent(spellInfo);
//if (minion->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
{
@@ -9969,11 +9949,15 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod);
}
- // Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods.
- float tmpDamage = (int32(pdamage) + DoneTotal) * (damagetype == DOT ? 1.0f : SpellDamagePctDone(victim, spellProto, damagetype));
- // apply spellmod to Done damage (flat and pct)
- if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage);
+ float tmpDamage = float(int32(pdamage) + DoneTotal);
+ // SPELLMOD_DOT will be applied in AuraEffect::HandlePeriodicDamageAurasTick.
+ if (damagetype != DOT)
+ {
+ tmpDamage *= SpellDamagePctDone(victim, spellProto, damagetype);
+ // apply spellmod to Done damage (flat and pct)
+ if (Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage);
+ }
return uint32(std::max(tmpDamage, 0.0f));
}
@@ -10813,11 +10797,15 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
DoneTotal = 0;
}
- // Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods.
- float heal = float(int32(healamount) + DoneTotal) * (damagetype == DOT ? 1.0f : SpellHealingPctDone(victim, spellProto));
- // apply spellmod to Done amount
- if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal);
+ float heal = float(int32(healamount) + DoneTotal);
+ // SPELLMOD_DOT will be applied in AuraEffect::HandlePeriodicHealAurasTick.
+ if (damagetype != DOT)
+ {
+ heal *= SpellHealingPctDone(victim, spellProto);
+ // apply spellmod to Done amount
+ if (Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, heal);
+ }
return uint32(std::max(heal, 0.0f));
}
@@ -12306,6 +12294,13 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
/// @todo possible affect only on MOVE_RUN
if (int32 normalization = GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED))
{
+ if (Creature* creature = ToCreature())
+ {
+ uint32 immuneMask = creature->GetCreatureTemplate()->MechanicImmuneMask;
+ if (immuneMask & (1 << MECHANIC_SNARE) || immuneMask & (1 << MECHANIC_DAZE))
+ break;
+ }
+
// Use speed from aura
float max_speed = normalization / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
if (speed > max_speed)
@@ -12932,7 +12927,7 @@ void Unit::ModSpellCastTime(SpellInfo const* spellInfo, int32 & castTime, Spell*
if (Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell);
- if (!(spellInfo->HasAttribute(SPELL_ATTR0_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR0_TRADESPELL) || spellInfo->HasAttribute(SPELL_ATTR0_TRADESPELL) || spellInfo->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS)) &&
+ if (!(spellInfo->HasAttribute(SPELL_ATTR0_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR0_TRADESPELL) || spellInfo->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS)) &&
((GetTypeId() == TYPEID_PLAYER && spellInfo->SpellFamilyName) || GetTypeId() == TYPEID_UNIT))
castTime = int32(float(castTime) * GetFloatValue(UNIT_MOD_CAST_SPEED));
else if (spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) && !spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG))
@@ -15532,18 +15527,11 @@ void Unit::SetControlled(bool apply, UnitState state)
{
case UNIT_STATE_STUNNED:
SetStunned(true);
- // i need to stop fear on stun and root or i will get teleport to destination issue as MVMGEN for fear keeps going on
- if (HasUnitState(UNIT_STATE_FLEEING))
- SetFeared(false);
CastStop();
break;
case UNIT_STATE_ROOT:
if (!HasUnitState(UNIT_STATE_STUNNED))
- {
SetRooted(true);
- if (HasUnitState(UNIT_STATE_FLEEING))
- SetFeared(false);
- }
break;
case UNIT_STATE_CONFUSED:
if (!HasUnitState(UNIT_STATE_STUNNED))
@@ -15631,11 +15619,9 @@ void Unit::SetStunned(bool apply)
// setting MOVEMENTFLAG_ROOT
RemoveUnitMovementFlag(MOVEMENTFLAG_MASK_MOVING);
AddUnitMovementFlag(MOVEMENTFLAG_ROOT);
+ StopMoving();
- // Creature specific
- if (GetTypeId() != TYPEID_PLAYER)
- StopMoving();
- else
+ if (GetTypeId() == TYPEID_PLAYER)
SetStandState(UNIT_STAND_STATE_STAND);
WorldPacket data(SMSG_FORCE_MOVE_ROOT, 8);
@@ -15679,6 +15665,7 @@ void Unit::SetRooted(bool apply)
// setting MOVEMENTFLAG_ROOT
RemoveUnitMovementFlag(MOVEMENTFLAG_MASK_MOVING);
AddUnitMovementFlag(MOVEMENTFLAG_ROOT);
+ StopMoving();
if (GetTypeId() == TYPEID_PLAYER)
{
@@ -15692,7 +15679,6 @@ void Unit::SetRooted(bool apply)
WorldPacket data(SMSG_SPLINE_MOVE_ROOT, 8);
data << GetPackGUID();
SendMessageToSet(&data, true);
- StopMoving();
}
}
else
@@ -16469,7 +16455,7 @@ void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ)
float vcos, vsin;
GetSinCos(x, y, vsin, vcos);
- WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
+ WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8 + 4 + 4 + 4 + 4 + 4));
data << GetPackGUID();
data << uint32(0); // counter
data << float(vcos); // x direction
@@ -16478,6 +16464,9 @@ void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ)
data << float(-speedZ); // Z Movement speed (vertical)
player->GetSession()->SendPacket(&data);
+
+ if (player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || player->HasAuraType(SPELL_AURA_FLY))
+ player->SetCanFly(true, true);
}
}
@@ -17536,7 +17525,7 @@ bool Unit::SetSwim(bool enable)
return true;
}
-bool Unit::SetCanFly(bool enable)
+bool Unit::SetCanFly(bool enable, bool /*packetOnly = false */)
{
if (enable == HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY))
return false;
@@ -17787,27 +17776,6 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target)
data->append(fieldBuffer);
}
-void Unit::BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown)
-{
- data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + 4 + 4);
- data << uint64(GetGUID());
- data << uint8(flags);
- data << uint32(spellId);
- data << uint32(cooldown);
-}
-
-void Unit::BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns)
-{
- data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + (4 + 4) * cooldowns.size());
- data << uint64(GetGUID());
- data << uint8(flags);
- for (std::unordered_map<uint32, uint32>::const_iterator itr = cooldowns.begin(); itr != cooldowns.end(); ++itr)
- {
- data << uint32(itr->first);
- data << uint32(itr->second);
- }
-}
-
int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const
{
int32 val = 0;
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index ddf43f30971..2593ca2c728 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -273,13 +273,6 @@ enum UnitRename
#define MAX_AGGRO_RESET_TIME 10 // in seconds
#define MAX_AGGRO_RADIUS 45.0f // yards
-enum Swing
-{
- NOSWING = 0,
- SINGLEHANDEDSWING = 1,
- TWOHANDEDSWING = 2
-};
-
enum VictimState
{
VICTIMSTATE_INTACT = 0, // set when attacker misses
@@ -339,6 +332,7 @@ class AuraEffect;
class Creature;
class Spell;
class SpellInfo;
+class SpellHistory;
class DynamicObject;
class GameObject;
class Item;
@@ -355,7 +349,7 @@ class TransportBase;
class SpellCastTargets;
typedef std::list<Unit*> UnitList;
-typedef std::list< std::pair<Aura*, uint8> > DispelChargesList;
+typedef std::list<std::pair<Aura*, uint8>> DispelChargesList;
struct SpellImmune
{
@@ -380,13 +374,6 @@ enum WeaponDamageRange
MAXDAMAGE
};
-enum DamageTypeToSchool
-{
- RESISTANCE,
- DAMAGE_DEALT,
- DAMAGE_TAKEN
-};
-
enum AuraRemoveMode
{
AURA_REMOVE_NONE = 0,
@@ -1031,30 +1018,6 @@ enum CurrentSpellTypes
#define CURRENT_FIRST_NON_MELEE_SPELL 1
#define CURRENT_MAX_SPELL 4
-struct GlobalCooldown
-{
- explicit GlobalCooldown(uint32 _dur = 0, uint32 _time = 0) : duration(_dur), cast_time(_time) { }
-
- uint32 duration;
- uint32 cast_time;
-};
-
-typedef std::unordered_map<uint32 /*category*/, GlobalCooldown> GlobalCooldownList;
-
-class GlobalCooldownMgr // Shared by Player and CharmInfo
-{
-public:
- GlobalCooldownMgr() { }
-
-public:
- bool HasGlobalCooldown(SpellInfo const* spellInfo) const;
- void AddGlobalCooldown(SpellInfo const* spellInfo, uint32 gcd);
- void CancelGlobalCooldown(SpellInfo const* spellInfo);
-
-private:
- GlobalCooldownList m_GlobalCooldowns;
-};
-
enum ActiveStates
{
ACT_PASSIVE = 0x01, // 0x01 - passive
@@ -1171,8 +1134,6 @@ struct CharmInfo
CharmSpellInfo* GetCharmSpell(uint8 index) { return &(_charmspells[index]); }
- GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; }
-
void SetIsCommandAttack(bool val);
bool IsCommandAttack();
void SetIsCommandFollow(bool val);
@@ -1205,8 +1166,6 @@ struct CharmInfo
float _stayX;
float _stayY;
float _stayZ;
-
- GlobalCooldownMgr m_GlobalCooldownMgr;
};
// for clearing special attacks
@@ -1237,16 +1196,6 @@ enum PlayerTotemType
SUMMON_TYPE_TOTEM_AIR = 83
};
-/// Spell cooldown flags sent in SMSG_SPELL_COOLDOWN
-enum SpellCooldownFlags
-{
- SPELL_COOLDOWN_FLAG_NONE = 0x0,
- SPELL_COOLDOWN_FLAG_INCLUDE_GCD = 0x1, ///< Starts GCD in addition to normal cooldown specified in the packet
- SPELL_COOLDOWN_FLAG_INCLUDE_EVENT_COOLDOWNS = 0x2 ///< Starts GCD for spells that should start their cooldown on events, requires SPELL_COOLDOWN_FLAG_INCLUDE_GCD set
-};
-
-typedef std::unordered_map<uint32, uint32> PacketCooldowns;
-
// delay time next attack to prevent client attack animation problems
#define ATTACK_DISPLAY_DELAY 200
#define MAX_PLAYER_STEALTH_DETECT_RANGE 30.0f // max distance for detection targets by player
@@ -1585,8 +1534,6 @@ class Unit : public WorldObject
void SetAuraStack(uint32 spellId, Unit* target, uint32 stack);
void SendPlaySpellVisual(uint32 id);
void SendPlaySpellImpact(ObjectGuid guid, uint32 id);
- void BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown);
- void BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns);
void DeMorph();
@@ -1622,7 +1569,7 @@ class Unit : public WorldObject
virtual bool SetWalk(bool enable);
virtual bool SetDisableGravity(bool disable, bool packetOnly = false);
virtual bool SetSwim(bool enable);
- virtual bool SetCanFly(bool enable);
+ virtual bool SetCanFly(bool enable, bool packetOnly = false);
virtual bool SetWaterWalking(bool enable, bool packetOnly = false);
virtual bool SetFeatherFall(bool enable, bool packetOnly = false);
virtual bool SetHover(bool enable, bool packetOnly = false);
@@ -1845,7 +1792,6 @@ class Unit : public WorldObject
void SetChannelObjectGuid(ObjectGuid guid) { SetGuidValue(UNIT_FIELD_CHANNEL_OBJECT, guid); }
void SetCurrentCastSpell(Spell* pSpell);
- virtual void ProhibitSpellSchool(SpellSchoolMask /*idSchoolMask*/, uint32 /*unTimeMs*/) { }
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed = true, bool withInstant = true);
void FinishSpell(CurrentSpellTypes spellType, bool ok = true);
@@ -1863,6 +1809,9 @@ class Unit : public WorldObject
Spell* FindCurrentSpellBySpellId(uint32 spell_id) const;
int32 GetCurrentSpellCastTime(uint32 spell_id) const;
+ SpellHistory* GetSpellHistory() { return m_spellHistory; }
+ SpellHistory const* GetSpellHistory() const { return m_spellHistory; }
+
ObjectGuid m_SummonSlot[MAX_SUMMON_SLOT];
ObjectGuid m_ObjectSlot[MAX_GAMEOBJECT_SLOT];
@@ -1933,7 +1882,7 @@ class Unit : public WorldObject
void TauntApply(Unit* victim);
void TauntFadeOut(Unit* taunter);
ThreatManager& getThreatManager() { return m_ThreatManager; }
- void addHatedBy(HostileReference* pHostileReference) { m_HostileRefManager.insertFirst(pHostileReference); };
+ void addHatedBy(HostileReference* pHostileReference) { m_HostileRefManager.insertFirst(pHostileReference); }
void removeHatedBy(HostileReference* /*pHostileReference*/) { /* nothing to do yet */ }
HostileRefManager& getHostileRefManager() { return m_HostileRefManager; }
@@ -2293,6 +2242,8 @@ class Unit : public WorldObject
bool _isWalkingBeforeCharm; ///< Are we walking before we were charmed?
time_t _lastDamagedTime; // Part of Evade mechanics
+
+ SpellHistory* m_spellHistory;
};
namespace Trinity
diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h
index a47b6f29e80..eb29e463a4d 100644
--- a/src/server/game/Events/GameEventMgr.h
+++ b/src/server/game/Events/GameEventMgr.h
@@ -96,7 +96,7 @@ class GameEventMgr
{
private:
GameEventMgr();
- ~GameEventMgr() { };
+ ~GameEventMgr() { }
public:
static GameEventMgr* instance()
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index f74201fee60..e540824e71c 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -1039,6 +1039,66 @@ void ObjectMgr::LoadCreatureAddons()
TC_LOG_INFO("server.loading", ">> Loaded %u creature addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
+void ObjectMgr::LoadGameObjectAddons()
+{
+ uint32 oldMSTime = getMSTime();
+
+ // 0 1 2
+ QueryResult result = WorldDatabase.Query("SELECT guid, invisibilityType, invisibilityValue FROM gameobject_addon");
+
+ if (!result)
+ {
+ TC_LOG_INFO("server.loading", ">> Loaded 0 gameobject addon definitions. DB table `gameobject_addon` is empty.");
+ return;
+ }
+
+ uint32 count = 0;
+ do
+ {
+ Field* fields = result->Fetch();
+
+ ObjectGuid::LowType guid = fields[0].GetUInt32();
+
+ const GameObjectData* goData = GetGOData(guid);
+ if (!goData)
+ {
+ TC_LOG_ERROR("sql.sql", "GameObject (GUID: %u) does not exist but has a record in `gameobject_addon`", guid);
+ continue;
+ }
+
+ GameObjectAddon& gameObjectAddon = _gameObjectAddonStore[guid];
+ gameObjectAddon.invisibilityType = InvisibilityType(fields[1].GetUInt8());
+ gameObjectAddon.InvisibilityValue = fields[2].GetUInt32();
+
+ if (gameObjectAddon.invisibilityType >= TOTAL_INVISIBILITY_TYPES)
+ {
+ TC_LOG_ERROR("sql.sql", "GameObject (GUID: %u) has invalid InvisibilityType in `gameobject_addon`", guid);
+ gameObjectAddon.invisibilityType = INVISIBILITY_GENERAL;
+ gameObjectAddon.InvisibilityValue = 0;
+ }
+
+ if (gameObjectAddon.invisibilityType && !gameObjectAddon.InvisibilityValue)
+ {
+ TC_LOG_ERROR("sql.sql", "GameObject (GUID: %u) has InvisibilityType set but has no InvisibilityValue in `gameobject_addon`, set to 1", guid);
+ gameObjectAddon.InvisibilityValue = 1;
+ }
+
+ ++count;
+ }
+ while (result->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded %u gameobject addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
+GameObjectAddon const* ObjectMgr::GetGameObjectAddon(ObjectGuid::LowType lowguid)
+{
+ GameObjectAddonContainer::const_iterator itr = _gameObjectAddonStore.find(lowguid);
+ if (itr != _gameObjectAddonStore.end())
+ return &(itr->second);
+
+ return NULL;
+}
+
CreatureAddon const* ObjectMgr::GetCreatureAddon(uint32 lowguid)
{
CreatureAddonContainer::const_iterator itr = _creatureAddonStore.find(lowguid);
@@ -4941,11 +5001,11 @@ void ObjectMgr::LoadEventScripts()
{
TaxiPathNodeEntry const& node = sTaxiPathNodesByPath[path_idx][node_idx];
- if (node.arrivalEventID)
- evt_scripts.insert(node.arrivalEventID);
+ if (node.ArrivalEventID)
+ evt_scripts.insert(node.ArrivalEventID);
- if (node.departureEventID)
- evt_scripts.insert(node.departureEventID);
+ if (node.DepartureEventID)
+ evt_scripts.insert(node.DepartureEventID);
}
}
@@ -6674,7 +6734,7 @@ void ObjectMgr::LoadGameObjectTemplate()
{
if (got.moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[got.moTransport.taxiPathId].empty())
TC_LOG_ERROR("sql.sql", "GameObject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.",
- entry, got.type, got.moTransport.taxiPathId, got.moTransport.taxiPathId);
+ entry, got.type, got.moTransport.taxiPathId, got.moTransport.taxiPathId);
}
if (uint32 transportMap = got.moTransport.mapID)
_transportMaps.insert(transportMap);
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index f9562a12335..f18e39077f3 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -49,12 +49,7 @@ struct PlayerClassLevelInfo;
struct PlayerInfo;
struct PlayerLevelInfo;
-// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
-#if defined(__GNUC__)
-#pragma pack(1)
-#else
#pragma pack(push, 1)
-#endif
struct PageText
{
@@ -82,12 +77,7 @@ private:
uint8 _summonGroup; ///< Summon's group id
};
-// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
-#if defined(__GNUC__)
-#pragma pack()
-#else
#pragma pack(pop)
-#endif
// DB scripting commands
enum ScriptCommands
@@ -732,6 +722,7 @@ class ObjectMgr
static void ChooseCreatureFlags(CreatureTemplate const* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, CreatureData const* data = NULL);
EquipmentInfo const* GetEquipmentInfo(uint32 entry, int8& id);
CreatureAddon const* GetCreatureAddon(uint32 lowguid);
+ GameObjectAddon const* GetGameObjectAddon(ObjectGuid::LowType lowguid);
CreatureAddon const* GetCreatureTemplateAddon(uint32 entry);
ItemTemplate const* GetItemTemplate(uint32 entry);
ItemTemplateContainer const* GetItemTemplateStore() const { return &_itemTemplateStore; }
@@ -974,6 +965,7 @@ class ObjectMgr
void LoadLinkedRespawn();
bool SetCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid);
void LoadCreatureAddons();
+ void LoadGameObjectAddons();
void LoadCreatureModelInfo();
void LoadEquipmentTemplates();
void LoadGameObjectLocales();
@@ -1419,6 +1411,7 @@ class ObjectMgr
CreatureModelContainer _creatureModelStore;
CreatureAddonContainer _creatureAddonStore;
CreatureAddonContainer _creatureTemplateAddonStore;
+ GameObjectAddonContainer _gameObjectAddonStore;
EquipmentInfoContainer _equipmentInfoStore;
LinkedRespawnContainer _linkedRespawnStore;
CreatureLocaleContainer _creatureLocaleStore;
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index ae8712510c9..2e81bdd1af8 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -1857,6 +1857,9 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const*
// check if someone in party is using dungeon system
if (member->isUsingLfg())
return ERR_LFG_CANT_USE_BATTLEGROUND;
+ // check Freeze debuff
+ if (member->HasAura(9454))
+ return ERR_BATTLEGROUND_JOIN_FAILED;
}
// only check for MinPlayerCount since MinPlayerCount == MaxPlayerCount for arenas...
diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h
index 28e933bd08c..732afce9517 100644
--- a/src/server/game/Groups/Group.h
+++ b/src/server/game/Groups/Group.h
@@ -218,7 +218,7 @@ class Group
ObjectGuid GetMasterLooterGuid() const;
ItemQualities GetLootThreshold() const;
- uint32 GetDbStoreId() const { return m_dbStoreId; };
+ uint32 GetDbStoreId() const { return m_dbStoreId; }
// member manipulation methods
bool IsMember(ObjectGuid guid) const;
diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp
index de23626eb25..2ec89ac2a26 100644
--- a/src/server/game/Handlers/BattleGroundHandler.cpp
+++ b/src/server/game/Handlers/BattleGroundHandler.cpp
@@ -178,6 +178,10 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
return;
}
+ // check Freeze debuff
+ if (_player->HasAura(9454))
+ return;
+
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
@@ -434,6 +438,10 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData)
WorldPacket data;
if (action)
{
+ // check Freeze debuff
+ if (_player->HasAura(9454))
+ return;
+
if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId))
return; // cheating?
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 9ff2041ee92..0bf33eee234 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -30,6 +30,7 @@
#include "Pet.h"
#include "World.h"
#include "Group.h"
+#include "SpellHistory.h"
#include "SpellInfo.h"
#include "Player.h"
@@ -344,8 +345,6 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
if (result == SPELL_CAST_OK)
{
- pet->ToCreature()->AddCreatureSpellCooldown(spellid);
-
unit_target = spell->m_targets.GetUnitTarget();
//10% chance to play special pet attack talk, else growl
@@ -379,8 +378,8 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
else
spell->SendPetCastResult(result);
- if (!pet->ToCreature()->HasSpellCooldown(spellid))
- GetPlayer()->SendClearCooldown(spellid, pet);
+ if (!pet->GetSpellHistory()->HasCooldown(spellid))
+ pet->GetSpellHistory()->ResetCooldown(spellid, true);
spell->finish(false);
delete spell;
@@ -794,7 +793,6 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
{
if (Creature* creature = caster->ToCreature())
{
- creature->AddCreatureSpellCooldown(spellId);
if (Pet* pet = creature->ToPet())
{
// 10% chance to play special pet attack talk, else growl
@@ -812,16 +810,8 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
{
spell->SendPetCastResult(result);
- if (caster->GetTypeId() == TYPEID_PLAYER)
- {
- if (!caster->ToPlayer()->HasSpellCooldown(spellId))
- GetPlayer()->SendClearCooldown(spellId, caster);
- }
- else
- {
- if (!caster->ToCreature()->HasSpellCooldown(spellId))
- GetPlayer()->SendClearCooldown(spellId, caster);
- }
+ if (!caster->GetSpellHistory()->HasCooldown(spellId))
+ caster->GetSpellHistory()->ResetCooldown(spellId, true);
spell->finish(false);
delete spell;
diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
index 5f641bf713f..a6108b36c13 100644
--- a/src/server/game/Handlers/SpellHandler.cpp
+++ b/src/server/game/Handlers/SpellHandler.cpp
@@ -491,8 +491,6 @@ void WorldSession::HandlePetCancelAuraOpcode(WorldPacket& recvPacket)
}
pet->RemoveOwnedAura(spellId, ObjectGuid::Empty, 0, AURA_REMOVE_BY_CANCEL);
-
- pet->AddCreatureSpellCooldown(spellId);
}
void WorldSession::HandleCancelGrowthAuraOpcode(WorldPacket& /*recvPacket*/) { }
diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp
index a9dc7f26b8e..af0f5b0fc75 100644
--- a/src/server/game/Handlers/TaxiHandler.cpp
+++ b/src/server/game/Handlers/TaxiHandler.cpp
@@ -237,7 +237,7 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData)
TaxiPathNodeEntry const& node = flight->GetPath()[flight->GetCurrentNode()];
flight->SkipCurrentNode();
- GetPlayer()->TeleportTo(curDestNode->map_id, node.x, node.y, node.z, GetPlayer()->GetOrientation());
+ GetPlayer()->TeleportTo(curDestNode->map_id, node.LocX, node.LocY, node.LocZ, GetPlayer()->GetOrientation());
}
return;
}
diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp
index 42bf61b6e38..da806e5b038 100644
--- a/src/server/game/Instances/InstanceScript.cpp
+++ b/src/server/game/Instances/InstanceScript.cpp
@@ -426,7 +426,26 @@ void InstanceScript::DoUseDoorOrButton(ObjectGuid guid, uint32 withRestoreTime /
TC_LOG_ERROR("scripts", "InstanceScript: DoUseDoorOrButton can't use gameobject entry %u, because type is %u.", go->GetEntry(), go->GetGoType());
}
else
- TC_LOG_DEBUG("scripts", "InstanceScript: HandleGameObject failed");
+ TC_LOG_DEBUG("scripts", "InstanceScript: DoUseDoorOrButton failed");
+}
+
+void InstanceScript::DoCloseDoorOrButton(ObjectGuid guid)
+{
+ if (!guid)
+ return;
+
+ if (GameObject* go = instance->GetGameObject(guid))
+ {
+ if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR || go->GetGoType() == GAMEOBJECT_TYPE_BUTTON)
+ {
+ if (go->getLootState() == GO_ACTIVATED)
+ go->ResetDoorOrButton();
+ }
+ else
+ TC_LOG_ERROR("scripts", "InstanceScript: DoCloseDoorOrButton can't use gameobject entry %u, because type is %u.", go->GetEntry(), go->GetGoType());
+ }
+ else
+ TC_LOG_DEBUG("scripts", "InstanceScript: DoCloseDoorOrButton failed");
}
void InstanceScript::DoRespawnGameObject(ObjectGuid guid, uint32 timeToDespawn /*= MINUTE*/)
diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h
index 41a9e9d0be1..be05a9f4495 100644
--- a/src/server/game/Instances/InstanceScript.h
+++ b/src/server/game/Instances/InstanceScript.h
@@ -191,6 +191,7 @@ class InstanceScript : public ZoneScript
// Change active state of doors or buttons
void DoUseDoorOrButton(ObjectGuid guid, uint32 withRestoreTime = 0, bool useAlternativeState = false);
+ void DoCloseDoorOrButton(ObjectGuid guid);
// Respawns a GO having negative spawntimesecs in gameobject-table
void DoRespawnGameObject(ObjectGuid guid, uint32 timeToDespawn = MINUTE);
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index dad24de7288..c1a462497cd 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -2562,6 +2562,17 @@ inline void Map::setNGrid(NGridType *grid, uint32 x, uint32 y)
void Map::DelayedUpdate(const uint32 t_diff)
{
+ for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();)
+ {
+ Transport* transport = *_transportsUpdateIter;
+ ++_transportsUpdateIter;
+
+ if (!transport->IsInWorld())
+ continue;
+
+ transport->DelayedUpdate(t_diff);
+ }
+
RemoveAllObjectsInRemoveList();
// Don't unload grids if it's battleground, since we may have manually added GOs, creatures, those doesn't load from DB at grid re-load !
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 3bbd6068e4e..43fcbaba31c 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -210,12 +210,7 @@ public:
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0);
};
-// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
-#if defined(__GNUC__)
-#pragma pack(1)
-#else
#pragma pack(push, 1)
-#endif
struct InstanceTemplate
{
@@ -241,11 +236,7 @@ struct ZoneDynamicInfo
uint32 LightFadeInTime;
};
-#if defined(__GNUC__)
-#pragma pack()
-#else
#pragma pack(pop)
-#endif
#define MAX_HEIGHT 100000.0f // can be use for find ground height at surface
#define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE
diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp
index b2e30473632..dadc2eeeac3 100644
--- a/src/server/game/Maps/TransportMgr.cpp
+++ b/src/server/game/Maps/TransportMgr.cpp
@@ -112,7 +112,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
Movement::PointsArray splinePath, allPoints;
bool mapChange = false;
for (size_t i = 0; i < path.size(); ++i)
- allPoints.push_back(G3D::Vector3(path[i].x, path[i].y, path[i].z));
+ allPoints.push_back(G3D::Vector3(path[i].LocX, path[i].LocY, path[i].LocZ));
// Add extra points to allow derivative calculations for all path nodes
allPoints.insert(allPoints.begin(), allPoints.front().lerp(allPoints[1], -0.2f));
@@ -129,7 +129,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
if (!mapChange)
{
TaxiPathNodeEntry const& node_i = path[i];
- if (i != path.size() - 1 && (node_i.actionFlag & 1 || node_i.mapid != path[i + 1].mapid))
+ if (i != path.size() - 1 && (node_i.Flags & 1 || node_i.MapID != path[i + 1].MapID))
{
keyFrames.back().Teleport = true;
mapChange = true;
@@ -142,8 +142,8 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
k.InitialOrientation = Position::NormalizeOrientation(std::atan2(h.y, h.x) + float(M_PI));
keyFrames.push_back(k);
- splinePath.push_back(G3D::Vector3(node_i.x, node_i.y, node_i.z));
- transport->mapsUsed.insert(k.Node->mapid);
+ splinePath.push_back(G3D::Vector3(node_i.LocX, node_i.LocY, node_i.LocZ));
+ transport->mapsUsed.insert(k.Node->MapID);
}
}
else
@@ -153,12 +153,12 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
if (splinePath.size() >= 2)
{
// Remove special catmull-rom spline points
- if (!keyFrames.front().IsStopFrame() && !keyFrames.front().Node->arrivalEventID && !keyFrames.front().Node->departureEventID)
+ if (!keyFrames.front().IsStopFrame() && !keyFrames.front().Node->ArrivalEventID && !keyFrames.front().Node->DepartureEventID)
{
splinePath.erase(splinePath.begin());
keyFrames.erase(keyFrames.begin());
}
- if (!keyFrames.back().IsStopFrame() && !keyFrames.back().Node->arrivalEventID && !keyFrames.back().Node->departureEventID)
+ if (!keyFrames.back().IsStopFrame() && !keyFrames.back().Node->ArrivalEventID && !keyFrames.back().Node->DepartureEventID)
{
splinePath.pop_back();
keyFrames.pop_back();
@@ -311,7 +311,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
float curPathTime = 0.0f;
if (keyFrames[0].IsStopFrame())
{
- curPathTime = float(keyFrames[0].Node->delay);
+ curPathTime = float(keyFrames[0].Node->Delay);
keyFrames[0].DepartureTime = uint32(curPathTime * IN_MILLISECONDS);
}
@@ -322,7 +322,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
{
keyFrames[i].ArriveTime = uint32(curPathTime * IN_MILLISECONDS);
keyFrames[i - 1].NextArriveTime = keyFrames[i].ArriveTime;
- curPathTime += float(keyFrames[i].Node->delay);
+ curPathTime += float(keyFrames[i].Node->Delay);
keyFrames[i].DepartureTime = uint32(curPathTime * IN_MILLISECONDS);
}
else
@@ -374,10 +374,10 @@ Transport* TransportMgr::CreateTransport(uint32 entry, uint32 guid /*= 0*/, Map*
// ...at first waypoint
TaxiPathNodeEntry const* startNode = tInfo->keyFrames.begin()->Node;
- uint32 mapId = startNode->mapid;
- float x = startNode->x;
- float y = startNode->y;
- float z = startNode->z;
+ uint32 mapId = startNode->MapID;
+ float x = startNode->LocX;
+ float y = startNode->LocY;
+ float z = startNode->LocZ;
float o = tInfo->keyFrames.begin()->InitialOrientation;
// initialize the gameobject base
diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h
index dbd99bd163a..fff7b9d8afa 100644
--- a/src/server/game/Maps/TransportMgr.h
+++ b/src/server/game/Maps/TransportMgr.h
@@ -61,7 +61,7 @@ struct KeyFrame
uint32 NextArriveTime;
bool IsTeleportFrame() const { return Teleport; }
- bool IsStopFrame() const { return Node->actionFlag == 2; }
+ bool IsStopFrame() const { return Node->Flags == 2; }
};
struct TransportTemplate
diff --git a/src/server/game/Maps/ZoneScript.h b/src/server/game/Maps/ZoneScript.h
index d8dba57d438..fd52bdd4c14 100644
--- a/src/server/game/Maps/ZoneScript.h
+++ b/src/server/game/Maps/ZoneScript.h
@@ -29,8 +29,8 @@ class ZoneScript
ZoneScript() { }
virtual ~ZoneScript() { }
- virtual uint32 GetCreatureEntry(uint32 /*guidlow*/, CreatureData const* data) { return data->id; }
- virtual uint32 GetGameObjectEntry(uint32 /*guidlow*/, uint32 entry) { return entry; }
+ virtual uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) { return data->id; }
+ virtual uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) { return entry; }
virtual void OnCreatureCreate(Creature* ) { }
virtual void OnCreatureRemove(Creature* ) { }
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 685bcd338a9..06c58a408da 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -3599,4 +3599,12 @@ enum DiminishingLevels
DIMINISHING_LEVEL_TAUNT_IMMUNE = 4
};
+/// Spell cooldown flags sent in SMSG_SPELL_COOLDOWN
+enum SpellCooldownFlags
+{
+ SPELL_COOLDOWN_FLAG_NONE = 0x0,
+ SPELL_COOLDOWN_FLAG_INCLUDE_GCD = 0x1, ///< Starts GCD in addition to normal cooldown specified in the packet
+ SPELL_COOLDOWN_FLAG_INCLUDE_EVENT_COOLDOWNS = 0x2 ///< Starts GCD for spells that should start their cooldown on events, requires SPELL_COOLDOWN_FLAG_INCLUDE_GCD set
+};
+
#endif
diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h
index 0b547d96e7f..c8da50364ba 100644
--- a/src/server/game/Movement/MotionMaster.h
+++ b/src/server/game/Movement/MotionMaster.h
@@ -182,7 +182,7 @@ class MotionMaster //: private std::stack<MovementGenerator *>
void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ);
void MoveJumpTo(float angle, float speedXY, float speedZ);
void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = EVENT_JUMP)
- { MoveJump(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speedXY, speedZ, id); };
+ { MoveJump(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speedXY, speedZ, id); }
void MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id = EVENT_JUMP);
void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount);
void MoveFall(uint32 id = 0);
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index a4c3831cf82..f91fc1985d5 100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -248,10 +248,10 @@ uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const
if (i_currentNode >= i_path->size())
return i_path->size();
- uint32 curMapId = (*i_path)[i_currentNode].mapid;
+ uint32 curMapId = (*i_path)[i_currentNode].MapID;
for (uint32 i = i_currentNode; i < i_path->size(); ++i)
{
- if ((*i_path)[i].mapid != curMapId)
+ if ((*i_path)[i].MapID != curMapId)
return i;
}
@@ -296,7 +296,7 @@ void FlightPathMovementGenerator::DoReset(Player* player)
uint32 end = GetPathAtMapEnd();
for (uint32 i = GetCurrentNode(); i != end; ++i)
{
- G3D::Vector3 vertice((*i_path)[i].x, (*i_path)[i].y, (*i_path)[i].z);
+ G3D::Vector3 vertice((*i_path)[i].LocX, (*i_path)[i].LocY, (*i_path)[i].LocZ);
init.Path().push_back(vertice);
}
init.SetFirstPointId(GetCurrentNode());
@@ -332,10 +332,10 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
if (i_path->empty())
return;
- uint32 map0 = (*i_path)[0].mapid;
+ uint32 map0 = (*i_path)[0].MapID;
for (size_t i = 1; i < i_path->size(); ++i)
{
- if ((*i_path)[i].mapid != map0)
+ if ((*i_path)[i].MapID != map0)
{
i_currentNode = i;
return;
@@ -345,9 +345,9 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry const& node, bool departure)
{
- if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID)
+ if (uint32 eventid = departure ? node.DepartureEventID : node.ArrivalEventID)
{
- TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.index, node.path, player->GetName().c_str());
+ TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.NodeIndex, node.PathID, player->GetName().c_str());
player->GetMap()->ScriptsStart(sEventScripts, eventid, player, player);
}
}
@@ -355,7 +355,7 @@ void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry
bool FlightPathMovementGenerator::GetResetPos(Player*, float& x, float& y, float& z)
{
const TaxiPathNodeEntry& node = (*i_path)[i_currentNode];
- x = node.x; y = node.y; z = node.z;
+ x = node.LocX; y = node.LocY; z = node.LocZ;
return true;
}
@@ -364,10 +364,10 @@ void FlightPathMovementGenerator::InitEndGridInfo()
/*! Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will
be reinitialized for each flightmaster at the end of each spline (or stop) in the flight. */
uint32 nodeCount = (*i_path).size(); //! Number of nodes in path.
- _endMapId = (*i_path)[nodeCount - 1].mapid; //! MapId of last node
+ _endMapId = (*i_path)[nodeCount - 1].MapID; //! MapId of last node
_preloadTargetNode = nodeCount - 3;
- _endGridX = (*i_path)[nodeCount - 1].x;
- _endGridY = (*i_path)[nodeCount - 1].y;
+ _endGridX = (*i_path)[nodeCount - 1].LocX;
+ _endGridY = (*i_path)[nodeCount - 1].LocY;
}
void FlightPathMovementGenerator::PreloadEndGrid()
diff --git a/src/server/game/Movement/Spline/MoveSplineFlag.h b/src/server/game/Movement/Spline/MoveSplineFlag.h
index 62fe808b6f5..0a3b41d412a 100644
--- a/src/server/game/Movement/Spline/MoveSplineFlag.h
+++ b/src/server/game/Movement/Spline/MoveSplineFlag.h
@@ -24,11 +24,7 @@
namespace Movement
{
-#if defined( __GNUC__ )
-#pragma pack(1)
-#else
#pragma pack(push, 1)
-#endif
class MoveSplineFlag
{
@@ -136,11 +132,7 @@ namespace Movement
bool unknown12 : 1;
bool unknown13 : 1;
};
-#if defined( __GNUC__ )
-#pragma pack()
-#else
#pragma pack(pop)
-#endif
}
#endif // TRINITYSERVER_MOVESPLINEFLAG_H
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index 8be5da91c32..f0ee013bcc2 100644
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -622,6 +622,7 @@ void AddSC_instance_magtheridons_lair();
void AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls
void AddSC_boss_warbringer_omrogg();
void AddSC_boss_warchief_kargath_bladefist();
+void AddSC_shattered_halls();
void AddSC_instance_shattered_halls();
void AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts
void AddSC_boss_omor_the_unscarred();
@@ -1152,6 +1153,7 @@ void AddOutlandScripts()
AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls
AddSC_boss_warbringer_omrogg();
AddSC_boss_warchief_kargath_bladefist();
+ AddSC_shattered_halls();
AddSC_instance_shattered_halls();
AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts
AddSC_boss_omor_the_unscarred();
diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h
index 68abadccf75..4b47e51fde6 100644
--- a/src/server/game/Server/Protocol/Opcodes.h
+++ b/src/server/game/Server/Protocol/Opcodes.h
@@ -1363,11 +1363,7 @@ enum PacketProcessing
class WorldSession;
class WorldPacket;
-#if defined(__GNUC__)
-#pragma pack(1)
-#else
#pragma pack(push, 1)
-#endif
struct OpcodeHandler
{
@@ -1379,11 +1375,7 @@ struct OpcodeHandler
extern OpcodeHandler opcodeTable[NUM_MSG_TYPES];
-#if defined(__GNUC__)
-#pragma pack()
-#else
#pragma pack(pop)
-#endif
/// Lookup opcode name for human understandable logging
inline const char* LookupOpcodeName(uint16 id)
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index d79392177e4..d6055e9733b 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -1370,6 +1370,7 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co
case MSG_RANDOM_ROLL: // not profiled
case CMSG_TIME_SYNC_RESP: // not profiled
case CMSG_TRAINER_BUY_SPELL: // not profiled
+ case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: // not profiled
{
// "0" is a magic number meaning there's no limit for the opcode.
// All the opcodes above must cause little CPU usage and no sync/async database queries at all
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index de2dc26b643..918b000a557 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -27,6 +27,7 @@
#include "ObjectAccessor.h"
#include "Util.h"
#include "Spell.h"
+#include "SpellHistory.h"
#include "SpellAuraEffects.h"
#include "Battleground.h"
#include "OutdoorPvPMgr.h"
@@ -1108,15 +1109,13 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
// Remove cooldown of spells triggered on stance change - they may share cooldown with stance spell
if (spellId)
{
- if (target->GetTypeId() == TYPEID_PLAYER)
- target->ToPlayer()->RemoveSpellCooldown(spellId);
+ target->GetSpellHistory()->ResetCooldown(spellId);
target->CastSpell(target, spellId, true, NULL, this);
}
if (spellId2)
{
- if (target->GetTypeId() == TYPEID_PLAYER)
- target->ToPlayer()->RemoveSpellCooldown(spellId2);
+ target->GetSpellHistory()->ResetCooldown(spellId2);
target->CastSpell(target, spellId2, true, NULL, this);
}
@@ -3852,10 +3851,11 @@ void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint
}
else
{
- if (int32(target->GetHealth()) > GetAmount())
- target->ModifyHealth(-GetAmount());
- else
- target->SetHealth(1);
+ if (target->GetHealth() > 0)
+ {
+ int32 value = std::min<int32>(target->GetHealth() - 1, GetAmount());
+ target->ModifyHealth(-value);
+ }
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
}
}
@@ -3867,19 +3867,15 @@ void AuraEffect::HandleAuraModIncreaseMaxHealth(AuraApplication const* aurApp, u
Unit* target = aurApp->GetTarget();
- uint32 oldhealth = target->GetHealth();
- double healthPercentage = (double)oldhealth / (double)target->GetMaxHealth();
+ float percent = target->GetHealthPct();
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
// refresh percentage
- if (oldhealth > 0)
+ if (target->GetHealth() > 0)
{
- uint32 newhealth = uint32(ceil((double)target->GetMaxHealth() * healthPercentage));
- if (newhealth == 0)
- newhealth = 1;
-
- target->SetHealth(newhealth);
+ uint32 newHealth = std::max<uint32>(target->CountPctFromMaxHealth(int32(percent)), 1);
+ target->SetHealth(newHealth);
}
}
@@ -3943,8 +3939,12 @@ void AuraEffect::HandleAuraModIncreaseHealthPercent(AuraApplication const* aurAp
// Unit will keep hp% after MaxHealth being modified if unit is alive.
float percent = target->GetHealthPct();
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount()), apply);
- if (target->IsAlive())
- target->SetHealth(target->CountPctFromMaxHealth(int32(percent)));
+
+ if (target->GetHealth() > 0)
+ {
+ uint32 newHealth = std::max<uint32>(target->CountPctFromMaxHealth(int32(percent)), 1);
+ target->SetHealth(newHealth);
+ }
}
void AuraEffect::HandleAuraIncreaseBaseHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -5845,6 +5845,9 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
else
damage = std::max(int32(damage * GetDonePct()), 0);
+ if (Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage);
+
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
// Calculate armor mitigation
@@ -6148,6 +6151,9 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
else
damage = std::max(int32(damage * GetDonePct()), 0);
+ if (Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage);
+
damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
}
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 0ba059b1952..5479dcdbf00 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -25,6 +25,7 @@
#include "Player.h"
#include "Unit.h"
#include "Spell.h"
+#include "SpellHistory.h"
#include "SpellAuraEffects.h"
#include "DynamicObject.h"
#include "ObjectAccessor.h"
@@ -418,7 +419,7 @@ void Aura::_ApplyForTarget(Unit* target, Unit* caster, AuraApplication * auraApp
if (m_spellInfo->IsCooldownStartedOnEvent())
{
Item* castItem = m_castItemGuid ? caster->ToPlayer()->GetItemByGuid(m_castItemGuid) : NULL;
- caster->ToPlayer()->AddSpellAndCategoryCooldowns(m_spellInfo, castItem ? castItem->GetEntry() : 0, NULL, true);
+ caster->GetSpellHistory()->StartCooldown(m_spellInfo, castItem ? castItem->GetEntry() : 0, nullptr, true);
}
}
}
@@ -446,12 +447,9 @@ void Aura::_UnapplyForTarget(Unit* target, Unit* caster, AuraApplication * auraA
m_removedApplications.push_back(auraApp);
// reset cooldown state for spells
- if (caster && caster->GetTypeId() == TYPEID_PLAYER)
- {
- if (GetSpellInfo()->IsCooldownStartedOnEvent())
- // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
- caster->ToPlayer()->SendCooldownEvent(GetSpellInfo());
- }
+ if (caster && GetSpellInfo()->IsCooldownStartedOnEvent())
+ // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
+ caster->GetSpellHistory()->SendCooldownEvent(GetSpellInfo());
}
// removes aura from all targets
@@ -1215,7 +1213,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
break;
case 60970: // Heroic Fury (remove Intercept cooldown)
if (target->GetTypeId() == TYPEID_PLAYER)
- target->ToPlayer()->RemoveSpellCooldown(20252, true);
+ target->GetSpellHistory()->ResetCooldown(20252, true);
break;
}
break;
@@ -1497,15 +1495,15 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
// check cooldown
if (caster->GetTypeId() == TYPEID_PLAYER)
{
- if (caster->ToPlayer()->HasSpellCooldown(aura->GetId()))
+ if (caster->GetSpellHistory()->HasCooldown(aura->GetId()))
{
// This additional check is needed to add a minimal delay before cooldown in in effect
// to allow all bubbles broken by a single damage source proc mana return
- if (caster->ToPlayer()->GetSpellCooldownDelay(aura->GetId()) <= 11)
+ if (caster->GetSpellHistory()->GetRemainingCooldown(aura->GetId()) <= 11)
break;
}
else // and add if needed
- caster->ToPlayer()->AddSpellCooldown(aura->GetId(), 0, uint32(time(NULL) + 12));
+ caster->GetSpellHistory()->AddCooldown(aura->GetId(), 0, std::chrono::seconds(12));
}
// effect on caster
@@ -1558,14 +1556,14 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
// Glyph of Guardian Spirit
if (AuraEffect* aurEff = player->GetAuraEffect(63231, 0))
{
- if (!player->HasSpellCooldown(47788))
+ if (!player->GetSpellHistory()->HasCooldown(47788))
break;
- player->RemoveSpellCooldown(GetSpellInfo()->Id, true);
- player->AddSpellCooldown(GetSpellInfo()->Id, 0, uint32(time(NULL) + aurEff->GetAmount()));
+ player->GetSpellHistory()->ResetCooldown(GetSpellInfo()->Id, true);
+ player->GetSpellHistory()->AddCooldown(GetSpellInfo()->Id, 0, std::chrono::seconds(aurEff->GetAmount()));
WorldPacket data;
- player->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, GetSpellInfo()->Id, aurEff->GetAmount()*IN_MILLISECONDS);
+ player->GetSpellHistory()->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, GetSpellInfo()->Id, aurEff->GetAmount() * IN_MILLISECONDS);
player->SendDirectMessage(&data);
}
break;
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index dbe87daa1a1..94bb90487bc 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -50,6 +50,7 @@
#include "SpellScript.h"
#include "InstanceScript.h"
#include "SpellInfo.h"
+#include "SpellHistory.h"
#include "Battlefield.h"
#include "BattlefieldMgr.h"
@@ -3226,7 +3227,7 @@ void Spell::cast(bool skipCheck)
//Clear spell cooldowns after every spell is cast if .cheat cooldown is enabled.
if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_COOLDOWN))
- m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id, true);
+ m_caster->GetSpellHistory()->ResetCooldown(m_spellInfo->Id, true);
}
SetExecutedCurrently(false);
@@ -3430,30 +3431,7 @@ void Spell::_handle_finish_phase()
void Spell::SendSpellCooldown()
{
- Player* _player = m_caster->ToPlayer();
- if (!_player)
- {
- // Handle pet cooldowns here if needed instead of in PetAI to avoid hidden cooldown restarts
- Creature* _creature = m_caster->ToCreature();
- if (_creature && (_creature->IsPet() || _creature->IsGuardian()))
- _creature->AddCreatureSpellCooldown(m_spellInfo->Id);
-
- return;
- }
-
- // mana/health/etc potions, disabled by client (until combat out as declarate)
- if (m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent()))
- {
- // need in some way provided data for Spell::finish SendCooldownEvent
- _player->SetLastPotionId(m_CastItem->GetEntry());
- return;
- }
-
- // have infinity cooldown but set at aura apply // do not set cooldown for triggered spells (needed by reincarnation)
- if (m_spellInfo->IsCooldownStartedOnEvent() || m_spellInfo->IsPassive() || (_triggeredCastFlags & TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD))
- return;
-
- _player->AddSpellAndCategoryCooldowns(m_spellInfo, m_CastItem ? m_CastItem->GetEntry() : 0, this);
+ m_caster->GetSpellHistory()->HandleCooldowns(m_spellInfo, m_CastItem, this);
}
void Spell::update(uint32 difftime)
@@ -4635,23 +4613,26 @@ SpellCastResult Spell::CheckCast(bool strict)
return SPELL_FAILED_CASTER_DEAD;
// check cooldowns to prevent cheating
- if (m_caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE))
+ if (!m_spellInfo->IsPassive())
{
- //can cast triggered (by aura only?) spells while have this flag
- if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE) && m_caster->ToPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY))
- return SPELL_FAILED_SPELL_IN_PROGRESS;
+ if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ //can cast triggered (by aura only?) spells while have this flag
+ if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE) && m_caster->ToPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY))
+ return SPELL_FAILED_SPELL_IN_PROGRESS;
- if (m_caster->ToPlayer()->HasSpellCooldown(m_spellInfo->Id))
+ // check if we are using a potion in combat for the 2nd+ time. Cooldown is added only after caster gets out of combat
+ if (m_caster->ToPlayer()->GetLastPotionId() && m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent()))
+ return SPELL_FAILED_NOT_READY;
+ }
+
+ if (!m_caster->GetSpellHistory()->IsReady(m_spellInfo))
{
if (m_triggeredByAuraSpell)
return SPELL_FAILED_DONT_REPORT;
else
return SPELL_FAILED_NOT_READY;
}
-
- // check if we are using a potion in combat for the 2nd+ time. Cooldown is added only after caster gets out of combat
- if (m_caster->ToPlayer()->GetLastPotionId() && m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent()))
- return SPELL_FAILED_NOT_READY;
}
if (m_spellInfo->HasAttribute(SPELL_ATTR7_IS_CHEAT_SPELL) && !m_caster->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS))
@@ -5504,13 +5485,13 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
}
// cooldown
- if (Creature const* creatureCaster = m_caster->ToCreature())
- if (creatureCaster->HasSpellCooldown(m_spellInfo->Id))
+ if (Creature* creatureCaster = m_caster->ToCreature())
+ if (!creatureCaster->GetSpellHistory()->IsReady(m_spellInfo))
return SPELL_FAILED_NOT_READY;
// Check if spell is affected by GCD
if (m_spellInfo->StartRecoveryCategory > 0)
- if (m_caster->GetCharmInfo() && m_caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo))
+ if (m_caster->GetCharmInfo() && m_caster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo))
return SPELL_FAILED_NOT_READY;
return CheckCast(true);
@@ -5801,7 +5782,7 @@ SpellCastResult Spell::CheckItems()
if (!proto)
return SPELL_FAILED_ITEM_NOT_READY;
- for (uint8 i = 0; i < MAX_ITEM_SPELLS; ++i)
+ for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
if (proto->Spells[i].SpellCharges)
if (m_CastItem->GetSpellCharges(i) == 0)
return SPELL_FAILED_NO_CHARGES_REMAIN;
@@ -7230,13 +7211,11 @@ enum GCDLimits
bool Spell::HasGlobalCooldown() const
{
- // Only player or controlled units have global cooldown
- if (m_caster->GetCharmInfo())
- return m_caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo);
- else if (m_caster->GetTypeId() == TYPEID_PLAYER)
- return m_caster->ToPlayer()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo);
- else
+ // Only players or controlled units have global cooldown
+ if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo())
return false;
+
+ return m_caster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo);
}
void Spell::TriggerGlobalCooldown()
@@ -7245,6 +7224,10 @@ void Spell::TriggerGlobalCooldown()
if (!gcd)
return;
+ // Only players or controlled units have global cooldown
+ if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo())
+ return;
+
if (m_caster->GetTypeId() == TYPEID_PLAYER)
if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_COOLDOWN))
return;
@@ -7266,11 +7249,7 @@ void Spell::TriggerGlobalCooldown()
gcd = MAX_GCD;
}
- // Only players or controlled units have global cooldown
- if (m_caster->GetCharmInfo())
- m_caster->GetCharmInfo()->GetGlobalCooldownMgr().AddGlobalCooldown(m_spellInfo, gcd);
- else if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->GetGlobalCooldownMgr().AddGlobalCooldown(m_spellInfo, gcd);
+ m_caster->GetSpellHistory()->AddGlobalCooldown(m_spellInfo, gcd);
}
void Spell::CancelGlobalCooldown()
@@ -7283,10 +7262,10 @@ void Spell::CancelGlobalCooldown()
return;
// Only players or controlled units have global cooldown
- if (m_caster->GetCharmInfo())
- m_caster->GetCharmInfo()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo);
- else if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo);
+ if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo())
+ return;
+
+ m_caster->GetSpellHistory()->CancelGlobalCooldown(m_spellInfo);
}
namespace Trinity
@@ -7405,7 +7384,7 @@ bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target)
}
else if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_LINE))
{
- if (!_caster->HasInLine(target, _caster->GetObjectSize()))
+ if (!_caster->HasInLine(target, _caster->GetObjectSize() + target->GetObjectSize()))
return false;
}
else
@@ -7422,7 +7401,7 @@ WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Po
bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target)
{
// return all targets on missile trajectory (0 - size of a missile)
- if (!_caster->HasInLine(target, 0))
+ if (!_caster->HasInLine(target, target->GetObjectSize()))
return false;
return WorldObjectSpellAreaTargetCheck::operator ()(target);
}
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 2ae2930aeb0..1aac88ac602 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -473,6 +473,7 @@ class Spell
void ReSetTimer() { m_timer = m_casttime > 0 ? m_casttime : 0; }
bool IsNextMeleeSwingSpell() const;
bool IsTriggered() const { return (_triggeredCastFlags & TRIGGERED_FULL_MASK) != 0; }
+ bool IsIgnoringCooldowns() const { return (_triggeredCastFlags & TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD) != 0; }
bool IsChannelActive() const { return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0; }
bool IsAutoActionResetSpell() const;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index cb518ee6099..3829e12b790 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -48,6 +48,7 @@
#include "GridNotifiers.h"
#include "Formulas.h"
#include "ScriptMgr.h"
+#include "SpellHistory.h"
#include "GameObjectAI.h"
#include "AccountMgr.h"
#include "InstanceScript.h"
@@ -769,8 +770,8 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex)
return;
// Reset cooldown on stealth if needed
- if (unitTarget->ToPlayer()->HasSpellCooldown(1784))
- unitTarget->ToPlayer()->RemoveSpellCooldown(1784);
+ if (unitTarget->GetSpellHistory()->HasCooldown(1784))
+ unitTarget->GetSpellHistory()->ResetCooldown(1784);
unitTarget->CastSpell(unitTarget, 1784, true);
return;
@@ -879,7 +880,7 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex)
// Remove spell cooldown (not category) if spell triggering spell with cooldown and same category
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime
&& m_spellInfo->GetCategory() == spellInfo->GetCategory())
- m_caster->ToPlayer()->RemoveSpellCooldown(spellInfo->Id);
+ m_caster->GetSpellHistory()->ResetCooldown(spellInfo->Id);
// original caster guid only for GO cast
m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID);
@@ -932,7 +933,7 @@ void Spell::EffectTriggerMissileSpell(SpellEffIndex effIndex)
// Remove spell cooldown (not category) if spell triggering spell with cooldown and same category
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime
&& m_spellInfo->GetCategory() == spellInfo->GetCategory())
- m_caster->ToPlayer()->RemoveSpellCooldown(spellInfo->Id);
+ m_caster->GetSpellHistory()->ResetCooldown(spellInfo->Id);
// original caster guid only for GO cast
m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID);
@@ -3472,7 +3473,7 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex)
if (m_originalCaster)
{
int32 duration = m_spellInfo->GetDuration();
- unitTarget->ProhibitSpellSchool(curSpellInfo->GetSchoolMask(), unitTarget->ModSpellDuration(m_spellInfo, unitTarget, duration, false, 1 << effIndex));
+ unitTarget->GetSpellHistory()->LockSpellSchool(curSpellInfo->GetSchoolMask(), unitTarget->ModSpellDuration(m_spellInfo, unitTarget, duration, false, 1 << effIndex));
}
ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo->Id);
unitTarget->InterruptSpell(CurrentSpellTypes(i), false);
@@ -5839,7 +5840,7 @@ void Spell::EffectCastButtons(SpellEffIndex effIndex)
if (!spellInfo)
continue;
- if (!p_caster->HasSpell(spell_id) || p_caster->HasSpellCooldown(spell_id))
+ if (!p_caster->HasSpell(spell_id) || p_caster->GetSpellHistory()->HasCooldown(spell_id))
continue;
if (!spellInfo->HasAttribute(SPELL_ATTR7_SUMMON_PLAYER_TOTEM))
diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp
new file mode 100644
index 00000000000..09e3be690b1
--- /dev/null
+++ b/src/server/game/Spells/SpellHistory.cpp
@@ -0,0 +1,643 @@
+/*
+ * Copyright (C) 2008-2015 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 "WorldPacket.h"
+#include "SpellHistory.h"
+#include "Pet.h"
+#include "Player.h"
+#include "SpellInfo.h"
+#include "Spell.h"
+#include "World.h"
+#include "Opcodes.h"
+
+SpellHistory::Clock::duration const SpellHistory::InfinityCooldownDelay = std::chrono::duration_cast<SpellHistory::Clock::duration>(std::chrono::seconds(MONTH));
+SpellHistory::Clock::duration const SpellHistory::InfinityCooldownDelayCheck = std::chrono::duration_cast<SpellHistory::Clock::duration>(std::chrono::seconds(MONTH / 2));
+
+template<>
+struct SpellHistory::PersistenceHelper<Player>
+{
+ static CharacterDatabaseStatements const CooldownsDeleteStatement = CHAR_DEL_CHAR_SPELL_COOLDOWNS;
+ static CharacterDatabaseStatements const CooldownsInsertStatement = CHAR_INS_CHAR_SPELL_COOLDOWN;
+
+ static void SetIdentifier(PreparedStatement* stmt, uint8 index, Unit* owner) { stmt->setUInt32(index, owner->GetGUID().GetCounter()); }
+
+ static bool ReadCooldown(Field* fields, uint32* spellId, CooldownEntry* cooldownEntry)
+ {
+ *spellId = fields[0].GetUInt32();
+ if (!sSpellMgr->GetSpellInfo(*spellId))
+ return false;
+
+ cooldownEntry->CooldownEnd = Clock::from_time_t(time_t(fields[2].GetUInt32()));
+ cooldownEntry->ItemId = fields[1].GetUInt32();
+ return true;
+ }
+
+ static void WriteCooldown(PreparedStatement* stmt, uint8& index, CooldownStorageType::value_type const& cooldown)
+ {
+ stmt->setUInt32(index++, cooldown.first);
+ stmt->setUInt32(index++, cooldown.second.ItemId);
+ stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CooldownEnd)));
+ }
+};
+
+template<>
+struct SpellHistory::PersistenceHelper<Pet>
+{
+ static CharacterDatabaseStatements const CooldownsDeleteStatement = CHAR_DEL_PET_SPELL_COOLDOWNS;
+ static CharacterDatabaseStatements const CooldownsInsertStatement = CHAR_INS_PET_SPELL_COOLDOWN;
+
+ static void SetIdentifier(PreparedStatement* stmt, uint8 index, Unit* owner) { stmt->setUInt32(index, owner->GetCharmInfo()->GetPetNumber()); }
+
+ static bool ReadCooldown(Field* fields, uint32* spellId, CooldownEntry* cooldownEntry)
+ {
+ *spellId = fields[0].GetUInt32();
+ if (!sSpellMgr->GetSpellInfo(*spellId))
+ return false;
+
+ cooldownEntry->CooldownEnd = Clock::from_time_t(time_t(fields[1].GetUInt32()));
+ cooldownEntry->ItemId = 0;
+ return true;
+ }
+
+ static void WriteCooldown(PreparedStatement* stmt, uint8& index, CooldownStorageType::value_type const& cooldown)
+ {
+ stmt->setUInt32(index++, cooldown.first);
+ stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CooldownEnd)));
+ }
+};
+
+template<class OwnerType>
+void SpellHistory::LoadFromDB(PreparedQueryResult cooldownsResult)
+{
+ typedef PersistenceHelper<OwnerType> StatementInfo;
+
+ if (cooldownsResult)
+ {
+ do
+ {
+ uint32 spellId;
+ CooldownEntry cooldown;
+ if (StatementInfo::ReadCooldown(cooldownsResult->Fetch(), &spellId, &cooldown))
+ _spellCooldowns[spellId] = cooldown;
+
+ } while (cooldownsResult->NextRow());
+ }
+}
+
+template<class OwnerType>
+void SpellHistory::SaveToDB(SQLTransaction& trans)
+{
+ typedef PersistenceHelper<OwnerType> StatementInfo;
+
+ uint8 index = 0;
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(StatementInfo::CooldownsDeleteStatement);
+ StatementInfo::SetIdentifier(stmt, index++, _owner);
+ trans->Append(stmt);
+
+ for (auto const& p : _spellCooldowns)
+ {
+ if (!p.second.OnHold)
+ {
+ index = 0;
+ stmt = CharacterDatabase.GetPreparedStatement(StatementInfo::CooldownsInsertStatement);
+ StatementInfo::SetIdentifier(stmt, index++, _owner);
+ StatementInfo::WriteCooldown(stmt, index, p);
+ trans->Append(stmt);
+ }
+ }
+}
+
+void SpellHistory::Update()
+{
+ SQLTransaction t;
+ Clock::time_point now = Clock::now();
+ for (auto itr = _spellCooldowns.begin(); itr != _spellCooldowns.end();)
+ {
+ if (itr->second.CooldownEnd < now)
+ itr = _spellCooldowns.erase(itr);
+ else
+ ++itr;
+ }
+}
+
+void SpellHistory::HandleCooldowns(SpellInfo const* spellInfo, Item const* item, Spell* spell /*= nullptr*/)
+{
+ if (Player* player = _owner->ToPlayer())
+ {
+ // potions start cooldown until exiting combat
+ if (item && (item->IsPotion() || spellInfo->IsCooldownStartedOnEvent()))
+ {
+ player->SetLastPotionId(item->GetEntry());
+ return;
+ }
+ }
+
+ if (spellInfo->IsCooldownStartedOnEvent() || spellInfo->IsPassive() || (spell && spell->IsIgnoringCooldowns()))
+ return;
+
+ StartCooldown(spellInfo, item ? item->GetEntry() : 0, spell);
+}
+
+bool SpellHistory::IsReady(SpellInfo const* spellInfo) const
+{
+ if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
+ if (IsSchoolLocked(spellInfo->GetSchoolMask()))
+ return false;
+
+ if (HasCooldown(spellInfo->Id))
+ return false;
+
+ return true;
+}
+
+template<>
+void SpellHistory::WritePacket<Pet>(WorldPacket& packet) const
+{
+ Clock::time_point now = Clock::now();
+
+ uint8 cooldownsCount = _spellCooldowns.size();
+ packet << uint8(cooldownsCount);
+
+ for (auto const& spellCooldown : _spellCooldowns)
+ {
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellCooldown.first);
+ if (!spellInfo)
+ {
+ packet << uint32(0);
+ packet << uint16(0);
+ packet << uint32(0);
+ packet << uint32(0);
+ continue;
+ }
+
+ packet << uint32(spellCooldown.first); // spell ID
+ packet << uint16(spellInfo->GetCategory()); // spell category
+ if (!spellCooldown.second.OnHold)
+ {
+ uint32 cooldownDuration = spellCooldown.second.CooldownEnd > now ? std::chrono::duration_cast<std::chrono::milliseconds>(spellCooldown.second.CooldownEnd - now).count() : 0;
+ if (cooldownDuration <= 0)
+ {
+ packet << uint32(0);
+ packet << uint32(0);
+ continue;
+ }
+
+ if (spellInfo->GetCategory())
+ {
+ packet << uint32(0);
+ packet << uint32(cooldownDuration);
+ }
+ else
+ {
+ packet << uint32(cooldownDuration);
+ packet << uint32(0);
+ }
+ }
+ }
+}
+
+template<>
+void SpellHistory::WritePacket<Player>(WorldPacket& packet) const
+{
+ Clock::time_point now = Clock::now();
+ Clock::time_point infTime = now + InfinityCooldownDelayCheck;
+
+ uint16 cooldownsCount = _spellCooldowns.size();
+ size_t dataPos = packet.wpos();
+ packet << uint16(cooldownsCount);
+
+ for (auto const& spellCooldown : _spellCooldowns)
+ {
+ SpellInfo const* sEntry = sSpellMgr->GetSpellInfo(spellCooldown.first);
+ if (!sEntry)
+ {
+ --cooldownsCount;
+ continue;
+ }
+
+ packet << uint32(spellCooldown.first);
+
+ packet << uint16(spellCooldown.second.ItemId); // cast item id
+ packet << uint16(sEntry->GetCategory()); // spell category
+
+ // send infinity cooldown in special format
+ if (spellCooldown.second.CooldownEnd >= infTime)
+ {
+ packet << uint32(1); // cooldown
+ packet << uint32(0x80000000); // category cooldown
+ continue;
+ }
+
+ uint32 cooldownDuration = spellCooldown.second.CooldownEnd > now ? std::chrono::duration_cast<std::chrono::milliseconds>(spellCooldown.second.CooldownEnd - now).count() : 0;
+
+ if (sEntry->GetCategory()) // may be wrong, but anyway better than nothing...
+ {
+ packet << uint32(0); // cooldown
+ packet << uint32(cooldownDuration); // category cooldown
+ }
+ else
+ {
+ packet << uint32(cooldownDuration); // cooldown
+ packet << uint32(0); // category cooldown
+ }
+ }
+
+ packet.put<uint16>(dataPos, cooldownsCount);
+}
+
+void SpellHistory::StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spell* spell /*= nullptr*/, bool onHold /*= false*/)
+{
+ // init cooldown values
+ uint32 categoryId = 0;
+ int32 cooldown = -1;
+ int32 categoryCooldown = -1;
+
+ // some special item spells without correct cooldown in SpellInfo
+ // cooldown information stored in item prototype
+ if (itemId)
+ {
+ if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId))
+ {
+ for (uint8 idx = 0; idx < MAX_ITEM_PROTO_SPELLS; ++idx)
+ {
+ if (uint32(proto->Spells[idx].SpellId) == spellInfo->Id)
+ {
+ categoryId = proto->Spells[idx].SpellCategory;
+ cooldown = proto->Spells[idx].SpellCooldown;
+ categoryCooldown = proto->Spells[idx].SpellCategoryCooldown;
+ break;
+ }
+ }
+ }
+ }
+
+ // if no cooldown found above then base at DBC data
+ if (cooldown < 0 && categoryCooldown < 0)
+ {
+ categoryId = spellInfo->GetCategory();
+ cooldown = spellInfo->RecoveryTime;
+ categoryCooldown = spellInfo->CategoryRecoveryTime;
+ }
+
+ Clock::time_point curTime = Clock::now();
+ Clock::time_point catrecTime;
+ Clock::time_point recTime;
+ bool needsCooldownPacket = false;
+
+ // overwrite time for selected category
+ if (onHold)
+ {
+ // use +MONTH as infinite cooldown marker
+ catrecTime = categoryCooldown > 0 ? (curTime + InfinityCooldownDelay) : curTime;
+ recTime = cooldown > 0 ? (curTime + InfinityCooldownDelay) : catrecTime;
+ }
+ else
+ {
+ // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
+ // prevent 0 cooldowns set by another way
+ if (cooldown <= 0 && categoryCooldown <= 0 && (categoryId == 76 || (spellInfo->IsAutoRepeatRangedSpell() && spellInfo->Id != 75)))
+ cooldown = _owner->GetAttackTime(RANGED_ATTACK);
+
+ // Now we have cooldown data (if found any), time to apply mods
+ if (Player* modOwner = _owner->GetSpellModOwner())
+ {
+ if (cooldown > 0)
+ modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, cooldown, spell);
+
+ if (categoryCooldown > 0 && !spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS))
+ modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, categoryCooldown, spell);
+ }
+
+ if (int32 cooldownMod = _owner->GetTotalAuraModifier(SPELL_AURA_MOD_COOLDOWN))
+ {
+ // Apply SPELL_AURA_MOD_COOLDOWN only to own spells
+ Player* playerOwner = GetPlayerOwner();
+ if (!playerOwner || playerOwner->HasSpell(spellInfo->Id))
+ {
+ needsCooldownPacket = true;
+ cooldown += cooldownMod * IN_MILLISECONDS; // SPELL_AURA_MOD_COOLDOWN does not affect category cooldows, verified with shaman shocks
+ }
+ }
+
+ // replace negative cooldowns by 0
+ if (cooldown < 0)
+ cooldown = 0;
+
+ if (categoryCooldown < 0)
+ categoryCooldown = 0;
+
+ // no cooldown after applying spell mods
+ if (cooldown == 0 && categoryCooldown == 0)
+ return;
+
+ catrecTime = categoryCooldown ? curTime + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(categoryCooldown)) : curTime;
+ recTime = cooldown ? curTime + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(cooldown)) : catrecTime;
+ }
+
+ // self spell cooldown
+ if (recTime != curTime)
+ {
+ AddCooldown(spellInfo->Id, itemId, recTime, onHold);
+
+ if (needsCooldownPacket)
+ {
+ if (Player* playerOwner = GetPlayerOwner())
+ {
+ WorldPacket spellCooldown;
+ BuildCooldownPacket(spellCooldown, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, cooldown);
+ playerOwner->SendDirectMessage(&spellCooldown);
+ }
+ }
+ }
+
+ // category spells
+ if (categoryId && catrecTime != curTime)
+ {
+ SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(categoryId);
+ if (i_scstore != sSpellsByCategoryStore.end())
+ {
+ for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
+ {
+ if (*i_scset == spellInfo->Id) // skip main spell, already handled above
+ continue;
+
+ AddCooldown(*i_scset, itemId, catrecTime, onHold);
+ }
+ }
+ }
+}
+
+void SpellHistory::SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId /*= 0*/, Spell* spell /*= nullptr*/, bool startCooldown /*= true*/)
+{
+ // start cooldowns at server side, if any
+ if (startCooldown)
+ StartCooldown(spellInfo, itemId, spell);
+
+ if (Player* player = GetPlayerOwner())
+ {
+ // Send activate cooldown timer (possible 0) at client side
+ WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8);
+ data << uint32(spellInfo->Id);
+ data << uint64(_owner->GetGUID());
+ player->SendDirectMessage(&data);
+
+ uint32 category = spellInfo->GetCategory();
+ if (category && spellInfo->CategoryRecoveryTime)
+ {
+ SpellCategoryStore::const_iterator ct = sSpellsByCategoryStore.find(category);
+ if (ct != sSpellsByCategoryStore.end())
+ {
+ for (auto const& cooldownPair : _spellCooldowns)
+ {
+ uint32 categorySpell = cooldownPair.first;
+ if (!ct->second.count(categorySpell))
+ continue;
+
+ if (categorySpell == spellInfo->Id) // skip main spell, already handled above
+ continue;
+
+ SpellInfo const* spellInfo2 = sSpellMgr->EnsureSpellInfo(categorySpell);
+ if (!spellInfo2->IsCooldownStartedOnEvent())
+ continue;
+
+ data.Initialize(SMSG_COOLDOWN_EVENT, 4 + 8);
+ data << uint32(categorySpell);
+ data << uint64(_owner->GetGUID());
+ player->SendDirectMessage(&data);
+ }
+ }
+ }
+ }
+}
+
+void SpellHistory::AddCooldown(uint32 spellId, uint32 itemId, Clock::time_point cooldownEnd, bool onHold /*= false*/)
+{
+ CooldownEntry& cooldownEntry = _spellCooldowns[spellId];
+ cooldownEntry.CooldownEnd = cooldownEnd;
+ cooldownEntry.ItemId = itemId;
+ cooldownEntry.OnHold = onHold;
+}
+
+void SpellHistory::ModifyCooldown(uint32 spellId, int32 cooldownModMs)
+{
+ auto itr = _spellCooldowns.find(spellId);
+ if (!cooldownModMs || itr == _spellCooldowns.end())
+ return;
+
+ Clock::time_point now = Clock::now();
+ Clock::duration offset = std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(cooldownModMs));
+ if (itr->second.CooldownEnd + offset > now)
+ itr->second.CooldownEnd += offset;
+ else
+ _spellCooldowns.erase(itr);
+
+ if (Player* playerOwner = GetPlayerOwner())
+ {
+ WorldPacket modifyCooldown(SMSG_MODIFY_COOLDOWN, 4 + 8 + 4);
+ modifyCooldown << uint32(spellId);
+ modifyCooldown << uint64(_owner->GetGUID());
+ modifyCooldown << int32(cooldownModMs);
+ playerOwner->SendDirectMessage(&modifyCooldown);
+ }
+}
+
+void SpellHistory::ResetCooldown(uint32 spellId, bool update /*= false*/)
+{
+ auto itr = _spellCooldowns.find(spellId);
+ if (itr == _spellCooldowns.end())
+ return;
+
+ ResetCooldown(itr, update);
+}
+
+void SpellHistory::ResetCooldown(CooldownStorageType::iterator& itr, bool update /*= false*/)
+{
+ if (update)
+ {
+ if (Player* playerOwner = GetPlayerOwner())
+ {
+ WorldPacket data(SMSG_CLEAR_COOLDOWN, 4 + 8);
+ data << uint32(itr->first);
+ data << uint64(_owner->GetGUID());
+ playerOwner->SendDirectMessage(&data);
+ }
+ }
+
+ itr = _spellCooldowns.erase(itr);
+}
+
+void SpellHistory::ResetAllCooldowns()
+{
+ if (GetPlayerOwner())
+ {
+ std::vector<int32> cooldowns;
+ cooldowns.reserve(_spellCooldowns.size());
+ for (auto const& p : _spellCooldowns)
+ cooldowns.push_back(p.first);
+
+ SendClearCooldowns(cooldowns);
+ }
+
+ _spellCooldowns.clear();
+}
+
+bool SpellHistory::HasCooldown(uint32 spellId) const
+{
+ return _spellCooldowns.count(spellId) != 0;
+}
+
+uint32 SpellHistory::GetRemainingCooldown(uint32 spellId) const
+{
+ auto itr = _spellCooldowns.find(spellId);
+ if (itr == _spellCooldowns.end())
+ return 0;
+
+ Clock::time_point now = Clock::now();
+ if (itr->second.CooldownEnd < now)
+ return 0;
+
+ Clock::duration remaining = itr->second.CooldownEnd - now;
+ return uint32(std::chrono::duration_cast<std::chrono::milliseconds>(remaining).count());
+}
+
+void SpellHistory::LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTime)
+{
+ Clock::time_point lockoutEnd = Clock::now() + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(lockoutTime));
+ for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
+ if (SpellSchoolMask(1 << i) & schoolMask)
+ _schoolLockouts[i] = lockoutEnd;
+
+ std::set<uint32> knownSpells;
+ if (Player* plrOwner = _owner->ToPlayer())
+ {
+ for (auto const& p : plrOwner->GetSpellMap())
+ if (p.second->state != PLAYERSPELL_REMOVED)
+ knownSpells.insert(p.first);
+ }
+ else if (Pet* petOwner = _owner->ToPet())
+ {
+ for (auto const& p : petOwner->m_spells)
+ if (p.second.state != PETSPELL_REMOVED)
+ knownSpells.insert(p.first);
+ }
+ else
+ {
+ Creature* creatureOwner = _owner->ToCreature();
+ for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i)
+ if (creatureOwner->m_spells[i])
+ knownSpells.insert(creatureOwner->m_spells[i]);
+ }
+
+ PacketCooldowns cooldowns;
+ WorldPacket spellCooldowns;
+ for (uint32 spellId : knownSpells)
+ {
+ SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(spellId);
+ if (spellInfo->IsCooldownStartedOnEvent())
+ continue;
+
+ if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE)
+ continue;
+
+ if ((schoolMask & spellInfo->GetSchoolMask()) && GetRemainingCooldown(spellId) < lockoutTime)
+ {
+ cooldowns[spellId] = lockoutTime;
+ AddCooldown(spellId, 0, lockoutEnd);
+ }
+ }
+
+ if (Player* player = GetPlayerOwner())
+ {
+ if (!cooldowns.empty())
+ {
+ BuildCooldownPacket(spellCooldowns, SPELL_COOLDOWN_FLAG_NONE, cooldowns);
+ player->SendDirectMessage(&spellCooldowns);
+ }
+ }
+}
+
+bool SpellHistory::IsSchoolLocked(SpellSchoolMask schoolMask) const
+{
+ Clock::time_point now = Clock::now();
+ for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
+ if (SpellSchoolMask(1 << i) & schoolMask)
+ if (_schoolLockouts[i] > now)
+ return true;
+
+ return false;
+}
+
+bool SpellHistory::HasGlobalCooldown(SpellInfo const* spellInfo) const
+{
+ auto itr = _globalCooldowns.find(spellInfo->StartRecoveryCategory);
+ return itr != _globalCooldowns.end() && itr->second > Clock::now();
+}
+
+void SpellHistory::AddGlobalCooldown(SpellInfo const* spellInfo, uint32 duration)
+{
+ _globalCooldowns[spellInfo->StartRecoveryCategory] = Clock::now() + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(duration));
+}
+
+void SpellHistory::CancelGlobalCooldown(SpellInfo const* spellInfo)
+{
+ _globalCooldowns[spellInfo->StartRecoveryCategory] = Clock::time_point(Clock::duration(0));
+}
+
+Player* SpellHistory::GetPlayerOwner() const
+{
+ return _owner->GetCharmerOrOwnerPlayerOrPlayerItself();
+}
+
+void SpellHistory::SendClearCooldowns(std::vector<int32> const& cooldowns) const
+{
+ if (Player* playerOwner = GetPlayerOwner())
+ {
+ for (int32 spell : cooldowns)
+ {
+ WorldPacket data(SMSG_CLEAR_COOLDOWN, 4 + 8);
+ data << uint32(spell);
+ data << uint64(_owner->GetGUID());
+ playerOwner->SendDirectMessage(&data);
+ }
+ }
+}
+
+void SpellHistory::BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown) const
+{
+ data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + 4 + 4);
+ data << uint64(_owner->GetGUID());
+ data << uint8(flags);
+ data << uint32(spellId);
+ data << uint32(cooldown);
+}
+
+void SpellHistory::BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns) const
+{
+ data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + (4 + 4) * cooldowns.size());
+ data << uint64(_owner->GetGUID());
+ data << uint8(flags);
+ for (auto const& cooldown : cooldowns)
+ {
+ data << cooldown.first;
+ data << cooldown.second;
+ }
+}
+
+template void SpellHistory::LoadFromDB<Player>(PreparedQueryResult cooldownsResult);
+template void SpellHistory::LoadFromDB<Pet>(PreparedQueryResult cooldownsResult);
+template void SpellHistory::SaveToDB<Player>(SQLTransaction& trans);
+template void SpellHistory::SaveToDB<Pet>(SQLTransaction& trans);
diff --git a/src/server/game/Spells/SpellHistory.h b/src/server/game/Spells/SpellHistory.h
new file mode 100644
index 00000000000..f1533d57aef
--- /dev/null
+++ b/src/server/game/Spells/SpellHistory.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2008-2015 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 SpellHistory_h__
+#define SpellHistory_h__
+
+#include "SharedDefines.h"
+#include "QueryResult.h"
+#include "Transaction.h"
+#include <chrono>
+#include <deque>
+
+class Item;
+class Player;
+class Spell;
+class SpellInfo;
+class Unit;
+struct SpellCategoryEntry;
+
+class SpellHistory
+{
+public:
+ typedef std::chrono::system_clock Clock;
+
+ struct CooldownEntry
+ {
+ CooldownEntry() : ItemId(0), OnHold(false) { }
+ CooldownEntry(Clock::time_point endTime, uint32 itemId) : CooldownEnd(endTime), ItemId(itemId), OnHold(false) { }
+
+ Clock::time_point CooldownEnd;
+ uint32 ItemId;
+ bool OnHold;
+ };
+
+ typedef std::unordered_map<uint32 /*spellId*/, CooldownEntry> CooldownStorageType;
+ typedef std::unordered_map<uint32 /*categoryId*/, Clock::time_point> GlobalCooldownStorageType;
+
+ explicit SpellHistory(Unit* owner) : _owner(owner), _schoolLockouts() { }
+
+ template<class OwnerType>
+ void LoadFromDB(PreparedQueryResult cooldownsResult);
+
+ template<class OwnerType>
+ void SaveToDB(SQLTransaction& trans);
+
+ void Update();
+
+ void HandleCooldowns(SpellInfo const* spellInfo, Item const* item, Spell* spell = nullptr);
+ bool IsReady(SpellInfo const* spellInfo) const;
+ template<class OwnerType>
+ void WritePacket(WorldPacket& packet) const;
+
+ // Cooldowns
+ static Clock::duration const InfinityCooldownDelay; // used for set "infinity cooldowns" for spells and check
+ static Clock::duration const InfinityCooldownDelayCheck;
+
+ void StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spell* spell = nullptr, bool onHold = false);
+ void SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId = 0, Spell* spell = nullptr, bool startCooldown = true);
+
+ template<class Type, class Period>
+ void AddCooldown(uint32 spellId, uint32 itemId, std::chrono::duration<Type, Period> cooldownDuration)
+ {
+ AddCooldown(spellId, itemId, Clock::now() + std::chrono::duration_cast<Clock::duration>(cooldownDuration));
+ }
+
+ void AddCooldown(uint32 spellId, uint32 itemId, Clock::time_point cooldownEnd, bool onHold = false);
+ void ModifyCooldown(uint32 spellId, int32 cooldownModMs);
+ void ResetCooldown(uint32 spellId, bool update = false);
+ void ResetCooldown(CooldownStorageType::iterator& itr, bool update = false);
+ template<typename Predicate>
+ void ResetCooldowns(Predicate predicate, bool update = false)
+ {
+ std::vector<int32> resetCooldowns;
+ resetCooldowns.reserve(_spellCooldowns.size());
+ for (auto itr = _spellCooldowns.begin(); itr != _spellCooldowns.end();)
+ {
+ if (predicate(itr))
+ {
+ resetCooldowns.push_back(itr->first);
+ ResetCooldown(itr, false);
+ }
+ else
+ ++itr;
+ }
+
+ if (update && !resetCooldowns.empty())
+ SendClearCooldowns(resetCooldowns);
+ }
+
+ void ResetAllCooldowns();
+ bool HasCooldown(uint32 spellId) const;
+ uint32 GetRemainingCooldown(uint32 spellId) const;
+
+ // School lockouts
+ void LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTime);
+ bool IsSchoolLocked(SpellSchoolMask schoolMask) const;
+
+ // Global cooldown
+ bool HasGlobalCooldown(SpellInfo const* spellInfo) const;
+ void AddGlobalCooldown(SpellInfo const* spellInfo, uint32 duration);
+ void CancelGlobalCooldown(SpellInfo const* spellInfo);
+
+ void BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown) const;
+
+ CooldownStorageType::size_type GetCooldownsSizeForPacket() const { return _spellCooldowns.size(); }
+
+private:
+ Player* GetPlayerOwner() const;
+ void SendClearCooldowns(std::vector<int32> const& cooldowns) const;
+
+ typedef std::unordered_map<uint32, uint32> PacketCooldowns;
+ void BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns) const;
+
+ Unit* _owner;
+ CooldownStorageType _spellCooldowns;
+ Clock::time_point _schoolLockouts[MAX_SPELL_SCHOOL];
+ GlobalCooldownStorageType _globalCooldowns;
+
+ template<class T>
+ struct PersistenceHelper { };
+};
+
+#endif // SpellHistory_h__
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 75a48e36ded..789b95e3e14 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -1614,7 +1614,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
}
// not allow casting on flying player
- if (unitTarget->HasUnitState(UNIT_STATE_IN_FLIGHT))
+ if (unitTarget->HasUnitState(UNIT_STATE_IN_FLIGHT) && !(AttributesCu & SPELL_ATTR0_CU_ALLOW_INFLIGHT_TARGET))
return SPELL_FAILED_BAD_TARGETS;
/* TARGET_UNIT_MASTER gets blocked here for passengers, because the whole idea of this check is to
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index f2808a089e1..cfa9877405d 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -186,6 +186,7 @@ enum SpellCustomAttributes
SPELL_ATTR0_CU_IGNORE_ARMOR = 0x00008000,
SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER = 0x00010000,
SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET = 0x00020000,
+ SPELL_ATTR0_CU_ALLOW_INFLIGHT_TARGET = 0x00040000,
SPELL_ATTR0_CU_NEGATIVE = SPELL_ATTR0_CU_NEGATIVE_EFF0 | SPELL_ATTR0_CU_NEGATIVE_EFF1 | SPELL_ATTR0_CU_NEGATIVE_EFF2
};
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index be1384588fb..13290320084 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -2954,6 +2954,10 @@ void SpellMgr::LoadSpellInfoCorrections()
switch (spellInfo->Id)
{
+ case 63026: // Force Cast (HACK: Target shouldn't be changed)
+ case 63137: // Force Cast (HACK: Target shouldn't be changed; summon position should be untied from spell destination)
+ spellInfo->Effects[0].TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB);
+ break;
case 53096: // Quetz'lun's Judgment
case 70743: // AoD Special
case 70614: // AoD Special - Vegard
@@ -3130,6 +3134,7 @@ void SpellMgr::LoadSpellInfoCorrections()
case 64823: // Item - Druid T8 Balance 4P Bonus
case 34477: // Misdirection
case 44401: // Missile Barrage
+ case 18820: // Insight
spellInfo->ProcCharges = 1;
break;
case 44544: // Fingers of Frost
diff --git a/src/server/game/Texts/CreatureTextMgr.cpp b/src/server/game/Texts/CreatureTextMgr.cpp
index 5fbc4b8ae1e..f9ccd2efd16 100644
--- a/src/server/game/Texts/CreatureTextMgr.cpp
+++ b/src/server/game/Texts/CreatureTextMgr.cpp
@@ -77,7 +77,7 @@ void CreatureTextMgr::LoadCreatureTexts()
uint32 oldMSTime = getMSTime();
mTextMap.clear(); // for reload case
- mTextRepeatMap.clear(); //reset all currently used temp texts
+ //all currently used temp texts are NOT reset
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_TEXT);
PreparedQueryResult result = WorldDatabase.Query(stmt);
@@ -224,13 +224,7 @@ uint32 CreatureTextMgr::SendChat(Creature* source, uint8 textGroup, WorldObject
if (tempGroup.empty())
{
- CreatureTextRepeatMap::iterator mapItr = mTextRepeatMap.find(source->GetGUID());
- if (mapItr != mTextRepeatMap.end())
- {
- CreatureTextRepeatGroup::iterator groupItr = mapItr->second.find(textGroup);
- groupItr->second.clear();
- }
-
+ source->ClearTextRepeatGroup(textGroup);
tempGroup = textGroupContainer;
}
@@ -426,26 +420,14 @@ void CreatureTextMgr::SetRepeatId(Creature* source, uint8 textGroup, uint8 id)
if (!source)
return;
- CreatureTextRepeatIds& repeats = mTextRepeatMap[source->GetGUID()][textGroup];
- if (std::find(repeats.begin(), repeats.end(), id) == repeats.end())
- repeats.push_back(id);
- else
- TC_LOG_ERROR("sql.sql", "CreatureTextMgr: TextGroup %u for Creature(%s) GuidLow %u Entry %u, id %u already added", uint32(textGroup), source->GetName().c_str(), source->GetGUIDLow(), source->GetEntry(), uint32(id));
+ source->SetTextRepeatId(textGroup, id);
}
CreatureTextRepeatIds CreatureTextMgr::GetRepeatGroup(Creature* source, uint8 textGroup)
{
ASSERT(source);//should never happen
- CreatureTextRepeatIds ids;
- CreatureTextRepeatMap::const_iterator mapItr = mTextRepeatMap.find(source->GetGUID());
- if (mapItr != mTextRepeatMap.end())
- {
- CreatureTextRepeatGroup::const_iterator groupItr = (*mapItr).second.find(textGroup);
- if (groupItr != mapItr->second.end())
- ids = groupItr->second;
- }
- return ids;
+ return source->GetTextRepeatGroup(textGroup);
}
bool CreatureTextMgr::TextExist(uint32 sourceEntry, uint8 textGroup)
diff --git a/src/server/game/Texts/CreatureTextMgr.h b/src/server/game/Texts/CreatureTextMgr.h
index 6ee1e82ce66..237aedd49d0 100644
--- a/src/server/game/Texts/CreatureTextMgr.h
+++ b/src/server/game/Texts/CreatureTextMgr.h
@@ -75,11 +75,6 @@ typedef std::unordered_map<uint32, CreatureTextHolder> CreatureTextMap; // a
typedef std::map<CreatureTextId, CreatureTextLocale> LocaleCreatureTextMap;
-//used for handling non-repeatable random texts
-typedef std::vector<uint8> CreatureTextRepeatIds;
-typedef std::unordered_map<uint8, CreatureTextRepeatIds> CreatureTextRepeatGroup;
-typedef std::unordered_map<ObjectGuid, CreatureTextRepeatGroup> CreatureTextRepeatMap;//guid based
-
class CreatureTextMgr
{
private:
@@ -115,7 +110,6 @@ class CreatureTextMgr
float GetRangeForChatType(ChatMsg msgType) const;
CreatureTextMap mTextMap;
- CreatureTextRepeatMap mTextRepeatMap;
LocaleCreatureTextMap mLocaleTextMap;
};
diff --git a/src/server/game/Warden/Warden.h b/src/server/game/Warden/Warden.h
index 4d46773adcd..695c6730b27 100644
--- a/src/server/game/Warden/Warden.h
+++ b/src/server/game/Warden/Warden.h
@@ -57,11 +57,7 @@ enum WardenCheckType
MODULE_CHECK = 0xD9 // 217: uint Seed + byte[20] SHA1 (check to ensure module isn't injected)
};
-#if defined(__GNUC__)
-#pragma pack(1)
-#else
#pragma pack(push, 1)
-#endif
struct WardenModuleUse
{
@@ -84,11 +80,7 @@ struct WardenHashRequest
uint8 Seed[16];
};
-#if defined(__GNUC__)
-#pragma pack()
-#else
#pragma pack(pop)
-#endif
struct ClientWardenModule
{
diff --git a/src/server/game/Warden/WardenWin.h b/src/server/game/Warden/WardenWin.h
index 31d28b22e23..ab6ef7c8c65 100644
--- a/src/server/game/Warden/WardenWin.h
+++ b/src/server/game/Warden/WardenWin.h
@@ -25,11 +25,7 @@
#include "ByteBuffer.h"
#include "Warden.h"
-#if defined(__GNUC__)
-#pragma pack(1)
-#else
#pragma pack(push, 1)
-#endif
struct WardenInitModuleRequest
{
@@ -61,11 +57,7 @@ struct WardenInitModuleRequest
uint8 Function3_set;
};
-#if defined(__GNUC__)
-#pragma pack()
-#else
#pragma pack(pop)
-#endif
class WorldSession;
class Warden;
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 9a84fa1670d..5f54154fab1 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1523,6 +1523,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Gameobject Data...");
sObjectMgr->LoadGameobjects();
+
+ TC_LOG_INFO("server.loading", "Loading GameObject Addon Data...");
+ sObjectMgr->LoadGameObjectAddons(); // must be after LoadGameObjectTemplate() and LoadGameobjects()
TC_LOG_INFO("server.loading", "Loading Creature Linked Respawn...");
sObjectMgr->LoadLinkedRespawn(); // must be after LoadCreatures(), LoadGameObjects()
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 0b74eb6bee7..c8a908f6930 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -35,6 +35,7 @@
#include "GroupMgr.h"
#include "MMapFactory.h"
#include "DisableMgr.h"
+#include "SpellHistory.h"
class misc_commandscript : public CommandScript
{
@@ -708,7 +709,7 @@ public:
if (!*args)
{
- target->RemoveAllSpellCooldown();
+ target->GetSpellHistory()->ResetAllCooldowns();
handler->PSendSysMessage(LANG_REMOVEALL_COOLDOWN, nameLink.c_str());
}
else
@@ -718,14 +719,15 @@ public:
if (!spellIid)
return false;
- if (!sSpellMgr->GetSpellInfo(spellIid))
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellIid);
+ if (!spellInfo)
{
handler->PSendSysMessage(LANG_UNKNOWN_SPELL, target == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str());
handler->SetSentErrorMessage(true);
return false;
}
- target->RemoveSpellCooldown(spellIid, true);
+ target->GetSpellHistory()->ResetCooldown(spellIid, true);
handler->PSendSysMessage(LANG_REMOVE_COOLDOWN, spellIid, target == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str());
}
return true;
@@ -1438,7 +1440,7 @@ public:
* Player %s %s (guid: %u) - I. LANG_PINFO_PLAYER
* ** GM Mode active, Phase: -1 - II. LANG_PINFO_GM_ACTIVE (if GM)
* ** Banned: (Type, Reason, Time, By) - III. LANG_PINFO_BANNED (if banned)
- * ** Muted: (Time, Reason, By) - IV. LANG_PINFO_MUTED (if muted)
+ * ** Muted: (Reason, Time, By) - IV. LANG_PINFO_MUTED (if muted)
* * Account: %s (id: %u), GM Level: %u - V. LANG_PINFO_ACC_ACCOUNT
* * Last Login: %u (Failed Logins: %u) - VI. LANG_PINFO_ACC_LASTLOGIN
* * Uses OS: %s - Latency: %u ms - VII. LANG_PINFO_ACC_OS
@@ -1691,7 +1693,7 @@ public:
// Output IV. LANG_PINFO_MUTED if mute is applied
if (muteTime > 0)
- handler->PSendSysMessage(LANG_PINFO_MUTED, secsToTimeString(muteTime - time(NULL), true).c_str(), muteReason.c_str(), muteBy.c_str());
+ handler->PSendSysMessage(LANG_PINFO_MUTED, muteReason.c_str(), secsToTimeString(muteTime - time(nullptr), true).c_str(), muteBy.c_str());
// Output V. LANG_PINFO_ACC_ACCOUNT
handler->PSendSysMessage(LANG_PINFO_ACC_ACCOUNT, userName.c_str(), accId, security);
diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp
index 4667b7c2767..54d1f314140 100644
--- a/src/server/scripts/Commands/cs_modify.cpp
+++ b/src/server/scripts/Commands/cs_modify.cpp
@@ -136,7 +136,7 @@ public:
return false;
}
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
@@ -164,17 +164,6 @@ public:
if (!*args)
return false;
- // char* pmana = strtok((char*)args, " ");
- // if (!pmana)
- // return false;
-
- // char* pmanaMax = strtok(NULL, " ");
- // if (!pmanaMax)
- // return false;
-
- // int32 manam = atoi(pmanaMax);
- // int32 mana = atoi(pmana);
-
int32 energy = atoi((char*)args)*10;
int32 energym = atoi((char*)args)*10;
@@ -185,7 +174,7 @@ public:
return false;
}
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
@@ -215,17 +204,6 @@ public:
if (!*args)
return false;
- // char* pmana = strtok((char*)args, " ");
- // if (!pmana)
- // return false;
-
- // char* pmanaMax = strtok(NULL, " ");
- // if (!pmanaMax)
- // return false;
-
- // int32 manam = atoi(pmanaMax);
- // int32 mana = atoi(pmana);
-
int32 rage = atoi((char*)args)*10;
int32 ragem = atoi((char*)args)*10;
@@ -236,7 +214,7 @@ public:
return false;
}
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
@@ -274,7 +252,7 @@ public:
return false;
}
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
@@ -390,7 +368,7 @@ public:
else
mark = atoi(pmark);
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (target == NULL)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
@@ -945,7 +923,7 @@ public:
return false;
}
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
@@ -986,7 +964,7 @@ public:
if (!*args)
return false;
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
@@ -1107,7 +1085,7 @@ public:
if (!*args)
return false;
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
@@ -1137,7 +1115,7 @@ public:
if (drunklevel > 100)
drunklevel = 100;
- if (Player* target = handler->getSelectedPlayer())
+ if (Player* target = handler->getSelectedPlayerOrSelf())
target->SetDrunkValue(drunklevel);
return true;
@@ -1148,7 +1126,7 @@ public:
if (!*args)
return false;
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
@@ -1302,7 +1280,7 @@ public:
if (!*args)
return false;
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
@@ -1324,7 +1302,7 @@ public:
if (!*args)
return false;
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index 390be999d9d..09a41fd82b5 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -370,28 +370,13 @@ public:
uint32 lowGuid = atoi((char*)guidStr);
- Creature* creature = NULL;
-
- /* FIXME: impossible without entry
- if (lowguid)
- creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT));
- */
-
// attempt check creature existence by DB data
- if (!creature)
- {
- CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid);
- if (!data)
- {
- handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowGuid);
- handler->SetSentErrorMessage(true);
- return false;
- }
- }
- else
+ CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid);
+ if (!data)
{
- // obtain real GUID for DB operations
- lowGuid = creature->GetDBTableGUIDLow();
+ handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowGuid);
+ handler->SetSentErrorMessage(true);
+ return false;
}
int wait = waitStr ? atoi(waitStr) : 0;
@@ -407,18 +392,6 @@ public:
WorldDatabase.Execute(stmt);
- if (creature && creature->GetWaypointPath())
- {
- creature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
- creature->GetMotionMaster()->Initialize();
- if (creature->IsAlive()) // dead creature will reset movement generator at respawn
- {
- creature->setDeathState(JUST_DIED);
- creature->Respawn(true);
- }
- creature->SaveToDB();
- }
-
handler->SendSysMessage(LANG_WAYPOINT_ADDED);
return true;
@@ -830,34 +803,22 @@ public:
lowguid = atoi(cId);
- /* FIXME: impossible without entry
- if (lowguid)
- creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT));
- */
-
// Attempting creature load from DB data
- if (!creature)
+ CreatureData const* data = sObjectMgr->GetCreatureData(lowguid);
+ if (!data)
{
- CreatureData const* data = sObjectMgr->GetCreatureData(lowguid);
- if (!data)
- {
- handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
- handler->SetSentErrorMessage(true);
- return false;
- }
+ handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
- uint32 map_id = data->mapid;
+ uint32 map_id = data->mapid;
- if (handler->GetSession()->GetPlayer()->GetMapId() != map_id)
- {
- handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
- handler->SetSentErrorMessage(true);
- return false;
- }
- }
- else
+ if (handler->GetSession()->GetPlayer()->GetMapId() != map_id)
{
- lowguid = creature->GetDBTableGUIDLow();
+ handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
+ handler->SetSentErrorMessage(true);
+ return false;
}
}
else
diff --git a/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp b/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp
index 1d7e1594d05..ca944f7037b 100644
--- a/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp
+++ b/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp
@@ -102,7 +102,7 @@ public:
}
}
- virtual void Update(uint32 /*diff*/) // correct order goes form 1-6
+ virtual void Update(uint32 /*diff*/) override // correct order goes form 1-6
{
switch (State)
{
diff --git a/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp b/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp
index cae26735568..29002460b2a 100644
--- a/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp
+++ b/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp
@@ -202,7 +202,7 @@ class boss_archaedas : public CreatureScript
DoMeleeAttackIfReady();
}
- void JustDied (Unit* /*killer*/)
+ void JustDied (Unit* /*killer*/) override
{
instance->SetData(DATA_ANCIENT_DOOR, DONE); // open the vault door
instance->SetData(DATA_MINIONS, SPECIAL); // deactivate his minions
diff --git a/src/server/scripts/Kalimdor/zone_moonglade.cpp b/src/server/scripts/Kalimdor/zone_moonglade.cpp
index 704fefe2678..163620230ef 100644
--- a/src/server/scripts/Kalimdor/zone_moonglade.cpp
+++ b/src/server/scripts/Kalimdor/zone_moonglade.cpp
@@ -384,6 +384,8 @@ public:
}
PlayerGUID = player->GetGUID();
Start(true, false, PlayerGUID);
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid1);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
return;
}
diff --git a/src/server/scripts/Kalimdor/zone_winterspring.cpp b/src/server/scripts/Kalimdor/zone_winterspring.cpp
index ec1291c6d18..5cb6e78b399 100644
--- a/src/server/scripts/Kalimdor/zone_winterspring.cpp
+++ b/src/server/scripts/Kalimdor/zone_winterspring.cpp
@@ -377,12 +377,12 @@ public:
void DoSummonPriestess()
{
// Summon 2 Elune priestess and make each of them move to a different spot
- if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[0].m_positionX, wingThicketLocations[0].m_positionY, wingThicketLocations[0].m_positionZ, wingThicketLocations[0].m_orientation, TEMPSUMMON_CORPSE_DESPAWN, 0))
+ if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[0].m_positionX, wingThicketLocations[0].m_positionY, wingThicketLocations[0].m_positionZ, wingThicketLocations[0].GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0))
{
priestess->GetMotionMaster()->MovePoint(0, wingThicketLocations[3].m_positionX, wingThicketLocations[3].m_positionY, wingThicketLocations[3].m_positionZ);
_firstPriestessGUID = priestess->GetGUID();
}
- if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[1].m_positionX, wingThicketLocations[1].m_positionY, wingThicketLocations[1].m_positionZ, wingThicketLocations[1].m_orientation, TEMPSUMMON_CORPSE_DESPAWN, 0))
+ if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[1].m_positionX, wingThicketLocations[1].m_positionY, wingThicketLocations[1].m_positionZ, wingThicketLocations[1].GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0))
{
// Left priestess should have a distinct move point because she is the one who starts the dialogue at point reach
priestess->GetMotionMaster()->MovePoint(1, wingThicketLocations[4].m_positionX, wingThicketLocations[4].m_positionY, wingThicketLocations[4].m_positionZ);
@@ -480,7 +480,7 @@ public:
break;
case SAY_PRIESTESS_ALTAR_13:
// summon the Guardian of Elune
- if (Creature* guard = me->SummonCreature(NPC_GUARDIAN_ELUNE, wingThicketLocations[2].m_positionX, wingThicketLocations[2].m_positionY, wingThicketLocations[2].m_positionZ, wingThicketLocations[2].m_orientation, TEMPSUMMON_CORPSE_DESPAWN, 0))
+ if (Creature* guard = me->SummonCreature(NPC_GUARDIAN_ELUNE, wingThicketLocations[2].m_positionX, wingThicketLocations[2].m_positionY, wingThicketLocations[2].m_positionZ, wingThicketLocations[2].GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0))
{
guard->GetMotionMaster()->MovePoint(0, wingThicketLocations[5].m_positionX, wingThicketLocations[5].m_positionY, wingThicketLocations[5].m_positionZ);
_guardEluneGUID = guard->GetGUID();
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp
index 39c9fbe37a6..c56a49cb92c 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp
@@ -741,7 +741,7 @@ class boss_dreadscale : public CreatureScript
switch (pointId)
{
case 0:
- instance->DoUseDoorOrButton(instance->GetGuidData(GO_MAIN_GATE_DOOR));
+ instance->DoCloseDoorOrButton(instance->GetGuidData(GO_MAIN_GATE_DOOR));
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
me->SetReactState(REACT_AGGRESSIVE);
me->SetInCombatWithZone();
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
index 660a639487f..fabe54303b8 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
@@ -196,7 +196,7 @@ class instance_halls_of_reflection : public InstanceMapScript
}
}
- uint32 GetGameObjectEntry(uint32 /*guidLow*/, uint32 entry) override
+ uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) override
{
if (!_teamInInstance)
{
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp
index 15bdedc75db..68430f6f0f7 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp
@@ -24,6 +24,7 @@
#include "PassiveAI.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellHistory.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
#include "Transport.h"
@@ -644,10 +645,10 @@ protected:
{
if (Instance->GetBossState(DATA_ICECROWN_GUNSHIP_BATTLE) == IN_PROGRESS &&
!me->HasUnitState(UNIT_STATE_CASTING) && !me->HasReactState(REACT_PASSIVE) &&
- !me->HasSpellCooldown(BurningPitchId))
+ !me->GetSpellHistory()->HasCooldown(BurningPitchId))
{
DoCastAOE(BurningPitchId, true);
- me->_AddCreatureSpellCooldown(BurningPitchId, time(NULL) + urand(3000, 4000) / IN_MILLISECONDS);
+ me->GetSpellHistory()->AddCooldown(BurningPitchId, 0, std::chrono::milliseconds(urand(3000, 4000)));
}
}
@@ -1469,7 +1470,7 @@ struct npc_gunship_boarding_addAI : public gunship_npc_AI
DoCast(me, SPELL_BATTLE_EXPERIENCE, true);
DoCast(me, SPELL_TELEPORT_TO_ENEMY_SHIP, true);
DoCast(me, Instance->GetData(DATA_TEAM_IN_INSTANCE) == HORDE ? SPELL_MELEE_TARGETING_ON_ORGRIMS_HAMMER : SPELL_MELEE_TARGETING_ON_SKYBREAKER, true);
- me->_AddCreatureSpellCooldown(BurningPitchId, time(NULL) + 3);
+ me->GetSpellHistory()->AddCooldown(BurningPitchId, 0, std::chrono::seconds(3));
std::list<Player*> players;
Trinity::UnitAuraCheck check(true, Instance->GetData(DATA_TEAM_IN_INSTANCE) == HORDE ? SPELL_ON_ORGRIMS_HAMMER_DECK : SPELL_ON_SKYBREAKER_DECK);
@@ -1698,11 +1699,11 @@ class npc_gunship_rocketeer : public CreatureScript
return;
uint32 spellId = me->GetEntry() == NPC_SKYBREAKER_MORTAR_SOLDIER ? SPELL_ROCKET_ARTILLERY_A : SPELL_ROCKET_ARTILLERY_H;
- if (me->HasSpellCooldown(spellId))
+ if (me->GetSpellHistory()->HasCooldown(spellId))
return;
DoCastAOE(spellId, true);
- me->_AddCreatureSpellCooldown(spellId, time(NULL) + 9);
+ me->GetSpellHistory()->AddCooldown(spellId, 0, std::chrono::seconds(9));
}
};
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
index 63082808e03..d7a580800bc 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
@@ -1060,8 +1060,8 @@ class spell_putricide_ooze_eruption_searcher : public SpellScriptLoader
uint32 adhesiveId = sSpellMgr->GetSpellIdForDifficulty(SPELL_VOLATILE_OOZE_ADHESIVE, GetCaster());
if (GetHitUnit()->HasAura(adhesiveId))
{
- GetCaster()->CastSpell(GetHitUnit(), SPELL_OOZE_ERUPTION, true);
GetHitUnit()->RemoveAurasDueToSpell(adhesiveId, GetCaster()->GetGUID(), 0, AURA_REMOVE_BY_ENEMY_SPELL);
+ GetCaster()->CastSpell(GetHitUnit(), SPELL_OOZE_ERUPTION, true);
}
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
index 60268fc8d87..e908d088554 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
@@ -348,7 +348,7 @@ class boss_sindragosa : public CreatureScript
events.ScheduleEvent(EVENT_AIR_MOVEMENT, 1);
break;
case POINT_AIR_PHASE:
- me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, RAID_MODE<int32>(2, 5, 2, 6), NULL);
+ me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, RAID_MODE<int32>(2, 5, 2, 6), NULL, TRIGGERED_FULL_MASK);
me->SetFacingTo(float(M_PI));
events.ScheduleEvent(EVENT_AIR_MOVEMENT_FAR, 1);
events.ScheduleEvent(EVENT_FROST_BOMB, 9000);
@@ -491,7 +491,7 @@ class boss_sindragosa : public CreatureScript
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, FrostBeaconSelector(me)))
{
Talk(EMOTE_WARN_FROZEN_ORB, target);
- DoCast(target, SPELL_ICE_TOMB_DUMMY, true);
+ me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, 1, nullptr, TRIGGERED_FULL_MASK);
}
events.ScheduleEvent(EVENT_ICE_TOMB, urand(16000, 23000));
break;
@@ -1631,7 +1631,7 @@ void AddSC_boss_sindragosa()
new spell_rimefang_icy_blast();
new spell_frostwarden_handler_order_whelp();
new spell_frostwarden_handler_focus_fire();
- new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb", SPELL_ICE_TOMB_DUMMY);
+ new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb", SPELL_ICE_TOMB_DUMMY, TRIGGERED_IGNORE_SET_FACING);
new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb_dummy", SPELL_FROST_BEACON);
new at_sindragosa_lair();
new achievement_all_you_can_eat();
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
index 8bf8e5ee6fb..091190b6b4e 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
+++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
@@ -524,14 +524,16 @@ enum AreaIds
class spell_trigger_spell_from_caster : public SpellScriptLoader
{
public:
- spell_trigger_spell_from_caster(char const* scriptName, uint32 triggerId) : SpellScriptLoader(scriptName), _triggerId(triggerId) { }
+ spell_trigger_spell_from_caster(char const* scriptName, uint32 triggerId, TriggerCastFlags triggerFlags = TRIGGERED_FULL_MASK)
+ : SpellScriptLoader(scriptName), _triggerId(triggerId), _triggerFlags(triggerFlags) { }
class spell_trigger_spell_from_caster_SpellScript : public SpellScript
{
PrepareSpellScript(spell_trigger_spell_from_caster_SpellScript);
public:
- spell_trigger_spell_from_caster_SpellScript(uint32 triggerId) : SpellScript(), _triggerId(triggerId) { }
+ spell_trigger_spell_from_caster_SpellScript(uint32 triggerId, TriggerCastFlags triggerFlags)
+ : SpellScript(), _triggerId(triggerId), _triggerFlags(triggerFlags) { }
bool Validate(SpellInfo const* /*spell*/) override
{
@@ -542,7 +544,7 @@ class spell_trigger_spell_from_caster : public SpellScriptLoader
void HandleTrigger()
{
- GetCaster()->CastSpell(GetHitUnit(), _triggerId, true);
+ GetCaster()->CastSpell(GetHitUnit(), _triggerId, _triggerFlags);
}
void Register() override
@@ -551,15 +553,17 @@ class spell_trigger_spell_from_caster : public SpellScriptLoader
}
uint32 _triggerId;
+ TriggerCastFlags _triggerFlags;
};
SpellScript* GetSpellScript() const override
{
- return new spell_trigger_spell_from_caster_SpellScript(_triggerId);
+ return new spell_trigger_spell_from_caster_SpellScript(_triggerId, _triggerFlags);
}
private:
uint32 _triggerId;
+ TriggerCastFlags _triggerFlags;
};
template<class AI>
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
index 61848070170..1b823b4a452 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
@@ -317,7 +317,7 @@ class instance_icecrown_citadel : public InstanceMapScript
}
// Weekly quest spawn prevention
- uint32 GetCreatureEntry(uint32 /*guidLow*/, CreatureData const* data) override
+ uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) override
{
uint32 entry = data->id;
switch (entry)
@@ -372,7 +372,7 @@ class instance_icecrown_citadel : public InstanceMapScript
return entry;
}
- uint32 GetGameObjectEntry(uint32 /*guidLow*/, uint32 entry) override
+ uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) override
{
switch (entry)
{
diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
index 6c3b2187325..9c339e596a4 100644
--- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
+++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
@@ -128,7 +128,6 @@ enum Spells
SPELL_ARCANE_BARRAGE_DAMAGE = 63934, // the actual damage - cast by affected player by script spell
// Transition /II-III/
- SPELL_SUMMOM_RED_DRAGON_BUDYY = 56070,
SPELL_RIDE_RED_DRAGON_BUDDY = 56071,
SPELL_SUMMON_RED_DRAGON_BUDDY_F_CAST = 58846, // After implicitly hit player targets they will force cast 56070 on self
SPELL_DESTROY_PLATFORM_CHANNEL = 58842,
diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h
index b6a0d3f9b62..d9b921b38a1 100644
--- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h
+++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h
@@ -80,7 +80,8 @@ enum InstanceSpells
SPELL_VORTEX_5 = 56263, // damage | used to enter to the vehicle
SPELL_PORTAL_OPENED = 61236,
SPELL_RIDE_RED_DRAGON_TRIGGERED = 56072,
- SPELL_IRIS_OPENED = 61012 // visual when starting encounter
+ SPELL_IRIS_OPENED = 61012, // visual when starting encounter
+ SPELL_SUMMOM_RED_DRAGON_BUDDY = 56070
};
#endif
diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp
index fffdbbc3d1b..7b884f39a41 100644
--- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp
+++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp
@@ -39,6 +39,12 @@ public:
SetBossNumber(MAX_ENCOUNTER);
}
+ void OnPlayerEnter(Player* player) override
+ {
+ if (GetBossState(DATA_MALYGOS_EVENT) == DONE)
+ player->CastSpell(player, SPELL_SUMMOM_RED_DRAGON_BUDDY, true);
+ }
+
bool SetBossState(uint32 type, EncounterState state) override
{
if (!InstanceScript::SetBossState(type, state))
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
index 23b86737f4c..a04c809f893 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
@@ -482,40 +482,47 @@ class boss_flame_leviathan : public CreatureScript
if (action && action <= 4) // Tower destruction, debuff leviathan loot and reduce active tower count
{
if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3 | LOOT_MODE_HARD_MODE_4) && ActiveTowersCount == 4)
- {
me->RemoveLootMode(LOOT_MODE_HARD_MODE_4);
- --ActiveTowersCount;
- }
+
if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3) && ActiveTowersCount == 3)
- {
me->RemoveLootMode(LOOT_MODE_HARD_MODE_3);
- --ActiveTowersCount;
- }
+
if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2) && ActiveTowersCount == 2)
- {
me->RemoveLootMode(LOOT_MODE_HARD_MODE_2);
- --ActiveTowersCount;
- }
+
if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1) && ActiveTowersCount == 1)
- {
me->RemoveLootMode(LOOT_MODE_HARD_MODE_1);
- --ActiveTowersCount;
- }
}
switch (action)
{
case ACTION_TOWER_OF_STORM_DESTROYED:
- towerOfStorms = false;
+ if (towerOfStorms)
+ {
+ towerOfStorms = false;
+ --ActiveTowersCount;
+ }
break;
case ACTION_TOWER_OF_FROST_DESTROYED:
- towerOfFrost = false;
+ if (towerOfFrost)
+ {
+ towerOfFrost = false;
+ --ActiveTowersCount;
+ }
break;
case ACTION_TOWER_OF_FLAMES_DESTROYED:
- towerOfFlames = false;
+ if (towerOfFlames)
+ {
+ towerOfFlames = false;
+ --ActiveTowersCount;
+ }
break;
case ACTION_TOWER_OF_LIFE_DESTROYED:
- towerOfLife = false;
+ if (towerOfLife)
+ {
+ towerOfLife = false;
+ --ActiveTowersCount;
+ }
break;
case ACTION_START_HARD_MODE: // Activate hard-mode enable all towers, apply buffs on leviathan
ActiveTowers = true;
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
index 181fb49ba2e..d0e4b7be63b 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
@@ -903,17 +903,15 @@ class boss_yogg_saron : public CreatureScript
DoCast(me, SPELL_KNOCK_AWAY);
me->ResetLootMode();
- switch (_instance->GetData(DATA_KEEPERS_COUNT))
- {
- case 0:
- me->AddLootMode(LOOT_MODE_HARD_MODE_4);
- case 1:
- me->AddLootMode(LOOT_MODE_HARD_MODE_3);
- case 2:
- me->AddLootMode(LOOT_MODE_HARD_MODE_2);
- case 3:
- me->AddLootMode(LOOT_MODE_HARD_MODE_1);
- }
+ uint32 keepersCount = _instance->GetData(DATA_KEEPERS_COUNT);
+ if (keepersCount == 0)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_4);
+ if (keepersCount <= 1)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_3);
+ if (keepersCount <= 2)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_2);
+ if (keepersCount <= 3)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_1);
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
diff --git a/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp b/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp
index 36d2c5f8ed3..dc923e534b0 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp
@@ -23,12 +23,9 @@ enum Spells
{
SPELL_ARCANE_VACUUM = 58694,
SPELL_BLIZZARD = 58693,
- H_SPELL_BLIZZARD = 59369,
SPELL_MANA_DESTRUCTION = 59374,
SPELL_TAIL_SWEEP = 58690,
- H_SPELL_TAIL_SWEEP = 59283,
SPELL_UNCONTROLLABLE_ENERGY = 58688,
- H_SPELL_UNCONTROLLABLE_ENERGY = 59281,
SPELL_TRANSFORM = 58668
};
@@ -48,17 +45,11 @@ class boss_cyanigosa : public CreatureScript
public:
boss_cyanigosa() : CreatureScript("boss_cyanigosa") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_cyanigosaAI>(creature);
- }
-
- struct boss_cyanigosaAI : public ScriptedAI
+ struct boss_cyanigosaAI : public BossAI
{
- boss_cyanigosaAI(Creature* creature) : ScriptedAI(creature)
+ boss_cyanigosaAI(Creature* creature) : BossAI(creature, DATA_CYANIGOSA)
{
Initialize();
- instance = creature->GetInstanceScript();
}
void Initialize()
@@ -76,24 +67,20 @@ public:
uint32 uiTailSweepTimer;
uint32 uiUncontrollableEnergyTimer;
- InstanceScript* instance;
-
void Reset() override
{
Initialize();
- instance->SetData(DATA_CYANIGOSA_EVENT, NOT_STARTED);
+ BossAI::Reset();
}
- void EnterCombat(Unit* /*who*/) override
+ void EnterCombat(Unit* who) override
{
+ BossAI::EnterCombat(who);
Talk(SAY_AGGRO);
-
- instance->SetData(DATA_CYANIGOSA_EVENT, IN_PROGRESS);
}
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
if (instance->GetData(DATA_REMOVE_NPC) == 1)
@@ -102,13 +89,12 @@ public:
instance->SetData(DATA_REMOVE_NPC, 0);
}
- //Return since we have no target
if (!UpdateVictim())
return;
if (uiArcaneVacuumTimer <= diff)
{
- DoCast(SPELL_ARCANE_VACUUM);
+ DoCastAOE(SPELL_ARCANE_VACUUM);
uiArcaneVacuumTimer = 10000;
} else uiArcaneVacuumTimer -= diff;
@@ -121,7 +107,7 @@ public:
if (uiTailSweepTimer <= diff)
{
- DoCast(SPELL_TAIL_SWEEP);
+ DoCastVictim(SPELL_TAIL_SWEEP);
uiTailSweepTimer = 20000;
} else uiTailSweepTimer -= diff;
@@ -144,22 +130,23 @@ public:
DoMeleeAttackIfReady();
}
- void JustDied(Unit* /*killer*/) override
+ void JustDied(Unit* killer) override
{
+ BossAI::JustDied(killer);
Talk(SAY_DEATH);
-
- instance->SetData(DATA_CYANIGOSA_EVENT, DONE);
}
void KilledUnit(Unit* victim) override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_SLAY);
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_cyanigosaAI>(creature);
+ }
};
class achievement_defenseless : public AchievementCriteriaScript
diff --git a/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp b/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp
index e990b8796de..5c8d4b8691a 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp
@@ -24,9 +24,7 @@ enum Spells
SPELL_BLOODLUST = 54516,
SPELL_BREAK_BONDS = 59463,
SPELL_CHAIN_HEAL = 54481,
- H_SPELL_CHAIN_HEAL = 59473,
SPELL_EARTH_SHIELD = 54479,
- H_SPELL_EARTH_SHIELD = 59471,
SPELL_EARTH_SHOCK = 54511,
SPELL_LIGHTNING_BOLT = 53044,
SPELL_STORMSTRIKE = 51876
@@ -47,11 +45,6 @@ class boss_erekem : public CreatureScript
public:
boss_erekem() : CreatureScript("boss_erekem") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_erekemAI>(creature);
- }
-
struct boss_erekemAI : public ScriptedAI
{
boss_erekemAI(Creature* creature) : ScriptedAI(creature)
@@ -81,9 +74,9 @@ public:
{
Initialize();
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)))
{
@@ -129,25 +122,23 @@ public:
Talk(SAY_AGGRO);
DoCast(me, SPELL_EARTH_SHIELD);
- if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_EREKEM_CELL)))
- if (pDoor->GetGoState() == GO_STATE_READY)
+ if (GameObject* door = instance->GetGameObject(DATA_EREKEM_CELL))
+ if (door->GetGoState() == GO_STATE_READY)
{
EnterEvadeMode();
return;
}
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
}
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
- //Return since we have no target
if (!UpdateVictim())
return;
@@ -212,22 +203,20 @@ public:
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
- instance->SetData(DATA_1ST_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
- instance->SetData(DATA_2ND_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
void KilledUnit(Unit* victim) override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_SLAY);
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
}
ObjectGuid GetChainHealTargetGUID()
@@ -247,6 +236,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_erekemAI>(creature);
+ }
};
enum GuardSpells
@@ -261,11 +254,6 @@ class npc_erekem_guard : public CreatureScript
public:
npc_erekem_guard() : CreatureScript("npc_erekem_guard") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_erekem_guardAI>(creature);
- }
-
struct npc_erekem_guardAI : public ScriptedAI
{
npc_erekem_guardAI(Creature* creature) : ScriptedAI(creature)
@@ -308,7 +296,6 @@ public:
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
@@ -336,6 +323,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_erekem_guardAI>(creature);
+ }
};
void AddSC_boss_erekem()
diff --git a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp
index 48fe8049d19..9be73febd52 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp
@@ -23,19 +23,16 @@ enum Spells
{
SPELL_DRAINED = 59820,
SPELL_FRENZY = 54312,
- SPELL_FRENZY_H = 59522,
SPELL_PROTECTIVE_BUBBLE = 54306,
SPELL_WATER_BLAST = 54237,
- SPELL_WATER_BLAST_H = 59520,
SPELL_WATER_BOLT_VOLLEY = 54241,
- SPELL_WATER_BOLT_VOLLEY_H = 59521,
SPELL_SPLASH = 59516,
SPELL_WATER_GLOBULE = 54268
};
enum IchoronCreatures
{
- NPC_ICHOR_GLOBULE = 29321,
+ NPC_ICHOR_GLOBULE = 29321
};
enum Yells
@@ -52,18 +49,18 @@ enum Yells
enum Actions
{
ACTION_WATER_ELEMENT_HIT = 1,
- ACTION_WATER_ELEMENT_KILLED = 2,
+ ACTION_WATER_ELEMENT_KILLED = 2
};
/// @todo get those positions from spawn of creature 29326
#define MAX_SPAWN_LOC 5
-static Position SpawnLoc[MAX_SPAWN_LOC]=
+static Position const SpawnLoc[MAX_SPAWN_LOC]=
{
{1840.64f, 795.407f, 44.079f, 1.676f},
{1886.24f, 757.733f, 47.750f, 5.201f},
{1877.91f, 845.915f, 43.417f, 3.560f},
{1918.97f, 850.645f, 47.225f, 4.136f},
- {1935.50f, 796.224f, 52.492f, 4.224f},
+ {1935.50f, 796.224f, 52.492f, 4.224f}
};
enum Misc
@@ -76,11 +73,6 @@ class boss_ichoron : public CreatureScript
public:
boss_ichoron() : CreatureScript("boss_ichoron") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_ichoronAI>(creature);
- }
-
struct boss_ichoronAI : public ScriptedAI
{
boss_ichoronAI(Creature* creature) : ScriptedAI(creature), m_waterElements(creature)
@@ -117,9 +109,9 @@ public:
DespawnWaterElements();
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
@@ -128,16 +120,17 @@ public:
DoCast(me, SPELL_PROTECTIVE_BUBBLE);
- if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_ICHORON_CELL)))
- if (pDoor->GetGoState() == GO_STATE_READY)
+ if (GameObject* door = instance->GetGameObject(DATA_ICHORON_CELL))
+ if (door->GetGoState() == GO_STATE_READY)
{
EnterEvadeMode();
return;
}
+
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
}
void AttackStart(Unit* who) override
@@ -208,7 +201,6 @@ public:
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 uiDiff) override
{
if (!UpdateVictim())
@@ -230,7 +222,7 @@ public:
if (!me->HasAura(SPELL_PROTECTIVE_BUBBLE))
{
Talk(SAY_SHATTER);
- DoCast(me, SPELL_WATER_BLAST);
+ DoCast(me, SPELL_WATER_BLAST); // wrong target
DoCast(me, SPELL_DRAINED);
bIsExploded = true;
me->AttackStop();
@@ -291,12 +283,12 @@ public:
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
- instance->SetData(DATA_1ST_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
- instance->SetData(DATA_2ND_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
@@ -323,13 +315,15 @@ public:
void KilledUnit(Unit* victim) override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_SLAY);
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_ichoronAI>(creature);
+ }
};
class npc_ichor_globule : public CreatureScript
@@ -337,11 +331,6 @@ class npc_ichor_globule : public CreatureScript
public:
npc_ichor_globule() : CreatureScript("npc_ichor_globule") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_ichor_globuleAI>(creature);
- }
-
struct npc_ichor_globuleAI : public ScriptedAI
{
npc_ichor_globuleAI(Creature* creature) : ScriptedAI(creature)
@@ -367,19 +356,18 @@ public:
void AttackStart(Unit* /*who*/) override
{
- return;
}
void UpdateAI(uint32 uiDiff) override
{
if (uiRangeCheck_Timer < uiDiff)
{
- if (Creature* pIchoron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ICHORON)))
+ if (Creature* ichoron = instance->GetCreature(DATA_ICHORON))
{
- if (me->IsWithinDist(pIchoron, 2.0f, false))
+ if (me->IsWithinDist(ichoron, 2.0f, false))
{
- if (pIchoron->AI())
- pIchoron->AI()->DoAction(ACTION_WATER_ELEMENT_HIT);
+ if (ichoron->AI())
+ ichoron->AI()->DoAction(ACTION_WATER_ELEMENT_HIT);
me->DespawnOrUnsummon();
}
}
@@ -391,12 +379,16 @@ public:
void JustDied(Unit* /*killer*/) override
{
DoCast(me, SPELL_SPLASH);
- if (Creature* pIchoron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ICHORON)))
- if (pIchoron->AI())
- pIchoron->AI()->DoAction(ACTION_WATER_ELEMENT_KILLED);
+ if (Creature* ichoron = instance->GetCreature(DATA_ICHORON))
+ if (ichoron->AI())
+ ichoron->AI()->DoAction(ACTION_WATER_ELEMENT_KILLED);
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_ichor_globuleAI>(creature);
+ }
};
class achievement_dehydration : public AchievementCriteriaScript
diff --git a/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp b/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp
index c3df7b71b83..5040dccfa36 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp
@@ -21,13 +21,10 @@
enum Spells
{
- SPELL_CAUTERIZING_FLAMES = 59466, //Only in heroic
- SPELL_FIREBOLT = 54235,
- H_SPELL_FIREBOLT = 59468,
- SPELL_FLAME_BREATH = 54282,
- H_SPELL_FLAME_BREATH = 59469,
- SPELL_LAVA_BURN = 54249,
- H_SPELL_LAVA_BURN = 59594
+ SPELL_CAUTERIZING_FLAMES = 59466, // Only in heroic
+ SPELL_FIREBOLT = 54235,
+ SPELL_FLAME_BREATH = 54282,
+ SPELL_LAVA_BURN = 54249
};
class boss_lavanthor : public CreatureScript
@@ -35,11 +32,6 @@ class boss_lavanthor : public CreatureScript
public:
boss_lavanthor() : CreatureScript("boss_lavanthor") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_lavanthorAI>(creature);
- }
-
struct boss_lavanthorAI : public ScriptedAI
{
boss_lavanthorAI(Creature* creature) : ScriptedAI(creature)
@@ -67,23 +59,24 @@ public:
{
Initialize();
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
- if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_LAVANTHOR_CELL)))
- if (pDoor->GetGoState() == GO_STATE_READY)
- {
- EnterEvadeMode();
- return;
- }
- if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
- else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
+ if (GameObject* door = instance->GetGameObject(DATA_LAVANTHOR_CELL))
+ if (door->GetGoState() == GO_STATE_READY)
+ {
+ EnterEvadeMode();
+ return;
+ }
+
+ if (instance->GetData(DATA_WAVE_COUNT) == 6)
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
+ else if (instance->GetData(DATA_WAVE_COUNT) == 12)
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
}
void AttackStart(Unit* who) override
@@ -102,10 +95,8 @@ public:
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
- //Return since we have no target
if (!UpdateVictim())
return;
@@ -123,9 +114,10 @@ public:
if (uiLavaBurnTimer <= diff)
{
- DoCastVictim(SPELL_LAVA_BURN);
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50.0f, true))
+ DoCast(target, SPELL_LAVA_BURN);
uiLavaBurnTimer = urand(15000, 23000);
- }
+ } else uiLavaBurnTimer -= diff;
if (IsHeroic())
{
@@ -143,17 +135,21 @@ public:
{
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
- instance->SetData(DATA_1ST_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
- instance->SetData(DATA_2ND_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_lavanthorAI>(creature);
+ }
};
void AddSC_boss_lavanthor()
diff --git a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp
index 9a6422dec32..1c98806b127 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp
@@ -19,11 +19,12 @@
#include "ScriptedCreature.h"
#include "violet_hold.h"
-//Spells
enum Spells
{
SPELL_CORROSIVE_SALIVA = 54527,
- SPELL_OPTIC_LINK = 54396
+ SPELL_OPTIC_LINK = 54396,
+ SPELL_RAY_OF_PAIN = 54438, // NYI missing spelldifficulty
+ SPELL_RAY_OF_SUFFERING = 54442 // NYI missing spelldifficulty
};
class boss_moragg : public CreatureScript
@@ -31,11 +32,6 @@ class boss_moragg : public CreatureScript
public:
boss_moragg() : CreatureScript("boss_moragg") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_moraggAI>(creature);
- }
-
struct boss_moraggAI : public ScriptedAI
{
boss_moraggAI(Creature* creature) : ScriptedAI(creature)
@@ -60,23 +56,24 @@ public:
Initialize();
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
- if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_MORAGG_CELL)))
- if (pDoor->GetGoState() == GO_STATE_READY)
+ if (GameObject* door = instance->GetGameObject(DATA_MORAGG_CELL))
+ if (door->GetGoState() == GO_STATE_READY)
{
EnterEvadeMode();
return;
}
+
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
}
void AttackStart(Unit* who) override
@@ -95,10 +92,8 @@ public:
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
- //Return since we have no target
if (!UpdateVictim())
return;
@@ -117,21 +112,26 @@ public:
DoMeleeAttackIfReady();
}
+
void JustDied(Unit* /*killer*/) override
{
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
- instance->SetData(DATA_1ST_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
- instance->SetData(DATA_2ND_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_moraggAI>(creature);
+ }
};
void AddSC_boss_moragg()
diff --git a/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp b/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp
index 833b06cfbff..d1efcb8ca7a 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp
@@ -23,9 +23,7 @@
enum Spells
{
SPELL_ARCANE_BARRAGE_VOLLEY = 54202,
- SPELL_ARCANE_BARRAGE_VOLLEY_H = 59483,
SPELL_ARCANE_BUFFET = 54226,
- SPELL_ARCANE_BUFFET_H = 59485,
SPELL_SUMMON_ETHEREAL_SPHERE_1 = 54102,
SPELL_SUMMON_ETHEREAL_SPHERE_2 = 54137,
SPELL_SUMMON_ETHEREAL_SPHERE_3 = 54138
@@ -40,7 +38,6 @@ enum NPCs
enum CreatureSpells
{
SPELL_ARCANE_POWER = 54160,
- H_SPELL_ARCANE_POWER = 59474,
SPELL_SUMMON_PLAYERS = 54164,
SPELL_POWER_BALL_VISUAL = 54141
};
@@ -61,11 +58,6 @@ class boss_xevozz : public CreatureScript
public:
boss_xevozz() : CreatureScript("boss_xevozz") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_xevozzAI>(creature);
- }
-
struct boss_xevozzAI : public ScriptedAI
{
boss_xevozzAI(Creature* creature) : ScriptedAI(creature)
@@ -90,9 +82,9 @@ public:
void Reset() override
{
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
Initialize();
DespawnSphere();
@@ -139,46 +131,46 @@ public:
void EnterCombat(Unit* /*who*/) override
{
- Talk(SAY_AGGRO);
- if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_XEVOZZ_CELL)))
- if (pDoor->GetGoState() == GO_STATE_READY)
+ if (GameObject* door = instance->GetGameObject(DATA_XEVOZZ_CELL))
+ if (door->GetGoState() == GO_STATE_READY)
{
EnterEvadeMode();
return;
}
+
+ Talk(SAY_AGGRO);
+
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
}
void MoveInLineOfSight(Unit* /*who*/) override { }
-
- void UpdateAI(uint32 uiDiff) override
+ void UpdateAI(uint32 diff) override
{
- //Return since we have no target
if (!UpdateVictim())
return;
- if (uiArcaneBarrageVolley_Timer < uiDiff)
+ if (uiArcaneBarrageVolley_Timer < diff)
{
DoCast(me, SPELL_ARCANE_BARRAGE_VOLLEY);
uiArcaneBarrageVolley_Timer = urand(20000, 22000);
}
- else uiArcaneBarrageVolley_Timer -= uiDiff;
+ else uiArcaneBarrageVolley_Timer -= diff;
if (uiArcaneBuffet_Timer)
{
- if (uiArcaneBuffet_Timer < uiDiff)
+ if (uiArcaneBuffet_Timer < diff)
{
DoCastVictim(SPELL_ARCANE_BUFFET);
uiArcaneBuffet_Timer = 0;
}
- else uiArcaneBuffet_Timer -= uiDiff;
+ else uiArcaneBuffet_Timer -= diff;
}
- if (uiSummonEtherealSphere_Timer < uiDiff)
+ if (uiSummonEtherealSphere_Timer < diff)
{
Talk(SAY_SPAWN);
DoCast(me, SPELL_SUMMON_ETHEREAL_SPHERE_1);
@@ -188,7 +180,7 @@ public:
uiSummonEtherealSphere_Timer = urand(45000, 47000);
uiArcaneBuffet_Timer = urand(5000, 6000);
}
- else uiSummonEtherealSphere_Timer -= uiDiff;
+ else uiSummonEtherealSphere_Timer -= diff;
DoMeleeAttackIfReady();
}
@@ -201,24 +193,27 @@ public:
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
- instance->SetData(DATA_1ST_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
- instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
+
void KilledUnit(Unit* victim) override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_SLAY);
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_xevozzAI>(creature);
+ }
};
class npc_ethereal_sphere : public CreatureScript
@@ -226,11 +221,6 @@ class npc_ethereal_sphere : public CreatureScript
public:
npc_ethereal_sphere() : CreatureScript("npc_ethereal_sphere") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_ethereal_sphereAI>(creature);
- }
-
struct npc_ethereal_sphereAI : public ScriptedAI
{
npc_ethereal_sphereAI(Creature* creature) : ScriptedAI(creature)
@@ -255,16 +245,15 @@ public:
Initialize();
}
- void UpdateAI(uint32 uiDiff) override
+ void UpdateAI(uint32 diff) override
{
- //Return since we have no target
if (!UpdateVictim())
return;
if (!me->HasAura(SPELL_POWER_BALL_VISUAL))
DoCast(me, SPELL_POWER_BALL_VISUAL);
- if (uiRangeCheck_Timer < uiDiff)
+ if (uiRangeCheck_Timer < diff)
{
if (Creature* pXevozz = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_XEVOZZ)))
{
@@ -276,9 +265,9 @@ public:
}
uiRangeCheck_Timer = 1000;
}
- else uiRangeCheck_Timer -= uiDiff;
+ else uiRangeCheck_Timer -= diff;
- if (uiSummonPlayers_Timer < uiDiff)
+ if (uiSummonPlayers_Timer < diff)
{
DoCast(me, SPELL_SUMMON_PLAYERS); // not working right
@@ -295,10 +284,14 @@ public:
uiSummonPlayers_Timer = urand(33000, 35000);
}
- else uiSummonPlayers_Timer -= uiDiff;
+ else uiSummonPlayers_Timer -= diff;
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_ethereal_sphereAI>(creature);
+ }
};
void AddSC_boss_xevozz()
diff --git a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp
index 90fd936e853..c29861f08a4 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp
@@ -22,15 +22,13 @@
enum Spells
{
SPELL_SHROUD_OF_DARKNESS = 54524,
- H_SPELL_SHROUD_OF_DARKNESS = 59745,
SPELL_SUMMON_VOID_SENTRY = 54369,
- SPELL_VOID_SHIFT = 54361,
- H_SPELL_VOID_SHIFT = 59743,
+ SPELL_VOID_SHIFT = 54361
};
enum Creatures
{
- NPC_VOID_SENTRY = 29364
+ NPC_VOID_SENTRY = 29364
};
enum Yells
@@ -53,11 +51,6 @@ class boss_zuramat : public CreatureScript
public:
boss_zuramat() : CreatureScript("boss_zuramat") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_zuramatAI>(creature);
- }
-
struct boss_zuramatAI : public ScriptedAI
{
boss_zuramatAI(Creature* creature) : ScriptedAI(creature)
@@ -107,25 +100,25 @@ public:
void EnterCombat(Unit* /*who*/) override
{
- Talk(SAY_AGGRO);
- if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_ZURAMAT_CELL)))
- if (pDoor->GetGoState() == GO_STATE_READY)
+ if (GameObject* door = instance->GetGameObject(DATA_ZURAMAT_CELL))
+ if (door->GetGoState() == GO_STATE_READY)
{
EnterEvadeMode();
return;
}
+
+ Talk(SAY_AGGRO);
+
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
}
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
- //Return since we have no target
if (!UpdateVictim())
return;
@@ -171,26 +164,27 @@ public:
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
- instance->SetData(DATA_1ST_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
- instance->SetData(DATA_2ND_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
void KilledUnit(Unit* victim) override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_SLAY);
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
}
-
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_zuramatAI>(creature);
+ }
};
class achievement_void_dance : public AchievementCriteriaScript
diff --git a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp
index ea50969ecb8..28c56a02255 100644
--- a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp
+++ b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp
@@ -22,8 +22,6 @@
#include "Player.h"
#include "TemporarySummon.h"
-#define MAX_ENCOUNTER 3
-
/* Violet Hold encounters:
0 - First boss
1 - Second boss
@@ -38,21 +36,6 @@
6 - Zuramat
7 - Cyanigosa */
-enum GameObjects
-{
- GO_MAIN_DOOR = 191723,
- GO_XEVOZZ_DOOR = 191556,
- GO_LAVANTHOR_DOOR = 191566,
- GO_ICHORON_DOOR = 191722,
- GO_ZURAMAT_DOOR = 191565,
- GO_EREKEM_DOOR = 191564,
- GO_EREKEM_GUARD_1_DOOR = 191563,
- GO_EREKEM_GUARD_2_DOOR = 191562,
- GO_MORAGG_DOOR = 191606,
- GO_INTRO_ACTIVATION_CRYSTAL = 193615,
- GO_ACTIVATION_CRYSTAL = 193611
-};
-
enum AzureSaboteurSpells
{
SABOTEUR_SHIELD_DISRUPTION = 58291,
@@ -64,7 +47,7 @@ enum CrystalSpells
SPELL_ARCANE_LIGHTNING = 57930
};
-const Position PortalLocation[] =
+Position const PortalLocation[] =
{
{1877.51f, 850.104f, 44.6599f, 4.7822f }, // WP 1
{1918.37f, 853.437f, 47.1624f, 4.12294f}, // WP 2
@@ -74,21 +57,21 @@ const Position PortalLocation[] =
{1908.31f, 809.657f, 38.7037f, 3.08701f} // WP 6
};
-const Position ArcaneSphere = {1887.060059f, 806.151001f, 61.321602f, 0.0f};
-const Position BossStartMove1 = {1894.684448f, 739.390503f, 47.668003f, 0.0f};
-const Position BossStartMove2 = {1875.173950f, 860.832703f, 43.333565f, 0.0f};
-const Position BossStartMove21 = {1858.854614f, 855.071411f, 43.333565f, 0.0f};
-const Position BossStartMove22 = {1891.926636f, 863.388977f, 43.333565f, 0.0f};
-const Position BossStartMove3 = {1916.138062f, 778.152222f, 35.772308f, 0.0f};
-const Position BossStartMove4 = {1853.618286f, 758.557617f, 38.657505f, 0.0f};
-const Position BossStartMove5 = {1906.683960f, 842.348022f, 38.637459f, 0.0f};
-const Position BossStartMove6 = {1928.207031f, 852.864441f, 47.200813f, 0.0f};
-
-const Position CyanigosasSpawnLocation = {1930.281250f, 804.407715f, 52.410946f, 3.139621f};
-const Position MiddleRoomLocation = {1892.291260f, 805.696838f, 38.438862f, 3.139621f};
-const Position MiddleRoomPortalSaboLocation = {1896.622925f, 804.854126f, 38.504772f, 3.139621f};
-
-//Cyanigosa's prefight event data
+Position const ArcaneSphere = {1887.060059f, 806.151001f, 61.321602f, 0.0f};
+Position const BossStartMove1 = {1894.684448f, 739.390503f, 47.668003f, 0.0f};
+Position const BossStartMove2 = {1875.173950f, 860.832703f, 43.333565f, 0.0f};
+Position const BossStartMove21 = {1858.854614f, 855.071411f, 43.333565f, 0.0f};
+Position const BossStartMove22 = {1891.926636f, 863.388977f, 43.333565f, 0.0f};
+Position const BossStartMove3 = {1916.138062f, 778.152222f, 35.772308f, 0.0f};
+Position const BossStartMove4 = {1853.618286f, 758.557617f, 38.657505f, 0.0f};
+Position const BossStartMove5 = {1906.683960f, 842.348022f, 38.637459f, 0.0f};
+Position const BossStartMove6 = {1928.207031f, 852.864441f, 47.200813f, 0.0f};
+
+Position const CyanigosasSpawnLocation = {1930.281250f, 804.407715f, 52.410946f, 3.139621f};
+Position const MiddleRoomLocation = {1892.291260f, 805.696838f, 38.438862f, 3.139621f};
+Position const MiddleRoomPortalSaboLocation = {1896.622925f, 804.854126f, 38.504772f, 3.139621f};
+
+// Cyanigosa's prefight event data
enum Yells
{
CYANIGOSA_SAY_SPAWN = 0
@@ -100,21 +83,45 @@ enum Spells
CYANIGOSA_BLUE_AURA = 47759,
};
+ObjectData const creatureData[] =
+{
+ { NPC_XEVOZZ, DATA_XEVOZZ },
+ { NPC_LAVANTHOR, DATA_LAVANTHOR },
+ { NPC_ICHORON, DATA_ICHORON },
+ { NPC_ZURAMAT, DATA_ZURAMAT },
+ { NPC_EREKEM, DATA_EREKEM },
+ { NPC_MORAGG, DATA_MORAGG },
+ { NPC_CYANIGOSA, DATA_CYANIGOSA },
+ { NPC_SINCLARI, DATA_SINCLARI },
+ { 0, 0 } // END
+};
+
+ObjectData const gameObjectData[] =
+{
+ { GO_EREKEM_GUARD_1_DOOR, DATA_EREKEM_LEFT_GUARD_CELL },
+ { GO_EREKEM_GUARD_2_DOOR, DATA_EREKEM_RIGHT_GUARD_CELL },
+ { GO_EREKEM_DOOR, DATA_EREKEM_CELL },
+ { GO_ZURAMAT_DOOR, DATA_ZURAMAT_CELL },
+ { GO_LAVANTHOR_DOOR, DATA_LAVANTHOR_CELL },
+ { GO_MORAGG_DOOR, DATA_MORAGG_CELL },
+ { GO_ICHORON_DOOR, DATA_ICHORON_CELL },
+ { GO_XEVOZZ_DOOR, DATA_XEVOZZ_CELL },
+ { GO_MAIN_DOOR, DATA_MAIN_DOOR },
+ { 0, 0 } // END
+};
+
class instance_violet_hold : public InstanceMapScript
{
public:
instance_violet_hold() : InstanceMapScript("instance_violet_hold", 608) { }
- InstanceScript* GetInstanceScript(InstanceMap* map) const override
- {
- return new instance_violet_hold_InstanceMapScript(map);
- }
-
struct instance_violet_hold_InstanceMapScript : public InstanceScript
{
instance_violet_hold_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
+ SetBossNumber(EncounterCount);
+ LoadObjectData(creatureData, gameObjectData);
uiRemoveNpc = 0;
@@ -138,29 +145,10 @@ public:
bCrystalActivated = false;
defenseless = true;
uiMainEventPhase = NOT_STARTED;
-
- memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
}
- ObjectGuid uiMoragg;
- ObjectGuid uiErekem;
ObjectGuid uiErekemGuard[2];
- ObjectGuid uiIchoron;
- ObjectGuid uiLavanthor;
- ObjectGuid uiXevozz;
- ObjectGuid uiZuramat;
- ObjectGuid uiCyanigosa;
- ObjectGuid uiSinclari;
-
- ObjectGuid uiMoraggCell;
- ObjectGuid uiErekemCell;
- ObjectGuid uiErekemLeftGuardCell;
- ObjectGuid uiErekemRightGuardCell;
- ObjectGuid uiIchoronCell;
- ObjectGuid uiLavanthorCell;
- ObjectGuid uiXevozzCell;
- ObjectGuid uiZuramatCell;
- ObjectGuid uiMainDoor;
+
ObjectGuid uiTeleportationPortal;
ObjectGuid uiSaboteurPortal;
@@ -180,7 +168,6 @@ public:
uint8 uiDoorIntegrity;
- uint16 m_auiEncounter[MAX_ENCOUNTER];
uint8 uiCountErekemGuards;
uint8 uiCountActivationCrystals;
uint8 uiCyanigosaEventPhase;
@@ -194,52 +181,23 @@ public:
std::list<uint8> NpcAtDoorCastingList;
- std::string str_data;
-
- bool IsEncounterInProgress() const override
- {
- for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- if (m_auiEncounter[i] == IN_PROGRESS)
- return true;
-
- return false;
- }
-
void OnCreatureCreate(Creature* creature) override
{
+ InstanceScript::OnCreatureCreate(creature);
+
switch (creature->GetEntry())
{
- case CREATURE_XEVOZZ:
- uiXevozz = creature->GetGUID();
- break;
- case CREATURE_LAVANTHOR:
- uiLavanthor = creature->GetGUID();
- break;
- case CREATURE_ICHORON:
- uiIchoron = creature->GetGUID();
- break;
- case CREATURE_ZURAMAT:
- uiZuramat = creature->GetGUID();
- break;
- case CREATURE_EREKEM:
- uiErekem = creature->GetGUID();
- break;
- case CREATURE_EREKEM_GUARD:
+ case NPC_EREKEM_GUARD:
if (uiCountErekemGuards < 2)
{
uiErekemGuard[uiCountErekemGuards++] = creature->GetGUID();
- creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE);
}
break;
- case CREATURE_MORAGG:
- uiMoragg = creature->GetGUID();
+ case NPC_CYANIGOSA:
+ creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE);
break;
- case CREATURE_CYANIGOSA:
- uiCyanigosa = creature->GetGUID();
- creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
- break;
- case CREATURE_SINCLARI:
- uiSinclari = creature->GetGUID();
+ default:
break;
}
@@ -255,68 +213,53 @@ public:
void OnGameObjectCreate(GameObject* go) override
{
+ InstanceScript::OnGameObjectCreate(go);
+
switch (go->GetEntry())
{
- case GO_EREKEM_GUARD_1_DOOR:
- uiErekemLeftGuardCell = go->GetGUID();
- break;
- case GO_EREKEM_GUARD_2_DOOR:
- uiErekemRightGuardCell = go->GetGUID();
- break;
- case GO_EREKEM_DOOR:
- uiErekemCell = go->GetGUID();
- break;
- case GO_ZURAMAT_DOOR:
- uiZuramatCell = go->GetGUID();
- break;
- case GO_LAVANTHOR_DOOR:
- uiLavanthorCell = go->GetGUID();
- break;
- case GO_MORAGG_DOOR:
- uiMoraggCell = go->GetGUID();
- break;
- case GO_ICHORON_DOOR:
- uiIchoronCell = go->GetGUID();
- break;
- case GO_XEVOZZ_DOOR:
- uiXevozzCell = go->GetGUID();
- break;
- case GO_MAIN_DOOR:
- uiMainDoor = go->GetGUID();
- break;
case GO_ACTIVATION_CRYSTAL:
if (uiCountActivationCrystals < 4)
uiActivationCrystal[uiCountActivationCrystals++] = go->GetGUID();
break;
+ default:
+ break;
}
}
- void SetData(uint32 type, uint32 data) override
+ bool SetBossState(uint32 type, EncounterState state) override
{
+ if (!InstanceScript::SetBossState(type, state))
+ return false;
+
switch (type)
{
case DATA_1ST_BOSS_EVENT:
- UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, CREATURE_EREKEM, NULL);
- m_auiEncounter[0] = data;
- if (data == DONE)
- SaveToDB();
+ if (state == DONE)
+ UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, NPC_EREKEM, nullptr);
break;
case DATA_2ND_BOSS_EVENT:
- UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, CREATURE_MORAGG, NULL);
- m_auiEncounter[1] = data;
- if (data == DONE)
- SaveToDB();
- break;
- case DATA_CYANIGOSA_EVENT:
- m_auiEncounter[2] = data;
- if (data == DONE)
+ if (state == DONE)
+ UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, NPC_MORAGG, nullptr);
+ break;
+ case DATA_CYANIGOSA:
+ if (state == DONE)
{
- SaveToDB();
uiMainEventPhase = DONE;
- if (GameObject* pMainDoor = instance->GetGameObject(uiMainDoor))
- pMainDoor->SetGoState(GO_STATE_ACTIVE);
+ if (GameObject* mainDoor = GetGameObject(DATA_MAIN_DOOR))
+ mainDoor->SetGoState(GO_STATE_ACTIVE);
}
break;
+ default:
+ break;
+ }
+
+ return true;
+ }
+
+ void SetData(uint32 type, uint32 data) override
+ {
+ switch (type)
+ {
case DATA_WAVE_COUNT:
uiWaveCount = data;
bActive = true;
@@ -340,21 +283,8 @@ public:
NpcAtDoorCastingList.pop_back();
break;
case DATA_MAIN_DOOR:
- if (GameObject* pMainDoor = instance->GetGameObject(uiMainDoor))
- {
- switch (data)
- {
- case GO_STATE_ACTIVE:
- pMainDoor->SetGoState(GO_STATE_ACTIVE);
- break;
- case GO_STATE_READY:
- pMainDoor->SetGoState(GO_STATE_READY);
- break;
- case GO_STATE_ACTIVE_ALTERNATIVE:
- pMainDoor->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE);
- break;
- }
- }
+ if (GameObject* mainDoor = GetGameObject(type))
+ mainDoor->SetGoState(GOState(data));
break;
case DATA_START_BOSS_ENCOUNTER:
switch (uiWaveCount)
@@ -374,7 +304,7 @@ public:
uiMainEventPhase = data;
if (data == IN_PROGRESS) // Start event
{
- if (GameObject* mainDoor = instance->GetGameObject(uiMainDoor))
+ if (GameObject* mainDoor = GetGameObject(DATA_MAIN_DOOR))
mainDoor->SetGoState(GO_STATE_READY);
uiWaveCount = 1;
bActive = true;
@@ -404,9 +334,6 @@ public:
{
switch (type)
{
- case DATA_1ST_BOSS_EVENT: return m_auiEncounter[0];
- case DATA_2ND_BOSS_EVENT: return m_auiEncounter[1];
- case DATA_CYANIGOSA_EVENT: return m_auiEncounter[2];
case DATA_WAVE_COUNT: return uiWaveCount;
case DATA_REMOVE_NPC: return uiRemoveNpc;
case DATA_PORTAL_LOCATION: return uiLocation;
@@ -421,125 +348,107 @@ public:
return 0;
}
- ObjectGuid GetGuidData(uint32 identifier) const override
+ ObjectGuid GetGuidData(uint32 type) const override
{
- switch (identifier)
+ switch (type)
{
- case DATA_MORAGG: return uiMoragg;
- case DATA_EREKEM: return uiErekem;
case DATA_EREKEM_GUARD_1: return uiErekemGuard[0];
case DATA_EREKEM_GUARD_2: return uiErekemGuard[1];
- case DATA_ICHORON: return uiIchoron;
- case DATA_LAVANTHOR: return uiLavanthor;
- case DATA_XEVOZZ: return uiXevozz;
- case DATA_ZURAMAT: return uiZuramat;
- case DATA_CYANIGOSA: return uiCyanigosa;
- case DATA_MORAGG_CELL: return uiMoraggCell;
- case DATA_EREKEM_CELL: return uiErekemCell;
- case DATA_EREKEM_RIGHT_GUARD_CELL: return uiErekemRightGuardCell;
- case DATA_EREKEM_LEFT_GUARD_CELL: return uiErekemLeftGuardCell;
- case DATA_ICHORON_CELL: return uiIchoronCell;
- case DATA_LAVANTHOR_CELL: return uiLavanthorCell;
- case DATA_XEVOZZ_CELL: return uiXevozzCell;
- case DATA_ZURAMAT_CELL: return uiZuramatCell;
- case DATA_MAIN_DOOR: return uiMainDoor;
- case DATA_SINCLARI: return uiSinclari;
case DATA_TELEPORTATION_PORTAL: return uiTeleportationPortal;
case DATA_SABOTEUR_PORTAL: return uiSaboteurPortal;
}
- return ObjectGuid::Empty;
+ return InstanceScript::GetGuidData(type);
}
void SpawnPortal()
{
SetData(DATA_PORTAL_LOCATION, (GetData(DATA_PORTAL_LOCATION) + urand(1, 5))%6);
- if (Creature* pSinclari = instance->GetCreature(uiSinclari))
- if (Creature* portal = pSinclari->SummonCreature(CREATURE_TELEPORTATION_PORTAL, PortalLocation[GetData(DATA_PORTAL_LOCATION)], TEMPSUMMON_CORPSE_DESPAWN))
+ if (Creature* sinclari = GetCreature(DATA_SINCLARI))
+ if (Creature* portal = sinclari->SummonCreature(NPC_TELEPORTATION_PORTAL, PortalLocation[GetData(DATA_PORTAL_LOCATION)], TEMPSUMMON_CORPSE_DESPAWN))
uiTeleportationPortal = portal->GetGUID();
}
void StartBossEncounter(uint8 uiBoss, bool bForceRespawn = true)
{
- Creature* pBoss = NULL;
+ Creature* boss = nullptr;
switch (uiBoss)
{
case BOSS_MORAGG:
- HandleGameObject(uiMoraggCell, bForceRespawn);
- pBoss = instance->GetCreature(uiMoragg);
- if (pBoss)
- pBoss->GetMotionMaster()->MovePoint(0, BossStartMove1);
+ HandleGameObject(GetObjectGuid(DATA_MORAGG_CELL), bForceRespawn);
+ boss = GetCreature(DATA_MORAGG);
+ if (boss)
+ boss->GetMotionMaster()->MovePoint(0, BossStartMove1);
break;
case BOSS_EREKEM:
- HandleGameObject(uiErekemCell, bForceRespawn);
- HandleGameObject(uiErekemRightGuardCell, bForceRespawn);
- HandleGameObject(uiErekemLeftGuardCell, bForceRespawn);
-
- pBoss = instance->GetCreature(uiErekem);
+ HandleGameObject(GetObjectGuid(DATA_EREKEM_CELL), bForceRespawn);
+ HandleGameObject(GetObjectGuid(DATA_EREKEM_LEFT_GUARD_CELL), bForceRespawn);
+ HandleGameObject(GetObjectGuid(DATA_EREKEM_RIGHT_GUARD_CELL), bForceRespawn);
- if (pBoss)
- pBoss->GetMotionMaster()->MovePoint(0, BossStartMove2);
+ boss = GetCreature(DATA_EREKEM);
+ if (boss)
+ boss->GetMotionMaster()->MovePoint(0, BossStartMove2);
if (Creature* pGuard1 = instance->GetCreature(uiErekemGuard[0]))
{
if (bForceRespawn)
- pGuard1->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ pGuard1->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE);
else
- pGuard1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ pGuard1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE);
pGuard1->GetMotionMaster()->MovePoint(0, BossStartMove21);
}
if (Creature* pGuard2 = instance->GetCreature(uiErekemGuard[1]))
{
if (bForceRespawn)
- pGuard2->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ pGuard2->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE);
else
- pGuard2->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ pGuard2->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE);
pGuard2->GetMotionMaster()->MovePoint(0, BossStartMove22);
}
break;
case BOSS_ICHORON:
- HandleGameObject(uiIchoronCell, bForceRespawn);
- pBoss = instance->GetCreature(uiIchoron);
- if (pBoss)
- pBoss->GetMotionMaster()->MovePoint(0, BossStartMove3);
+ HandleGameObject(GetObjectGuid(DATA_ICHORON_CELL), bForceRespawn);
+ boss = GetCreature(DATA_ICHORON);
+ if (boss)
+ boss->GetMotionMaster()->MovePoint(0, BossStartMove3);
break;
case BOSS_LAVANTHOR:
- HandleGameObject(uiLavanthorCell, bForceRespawn);
- pBoss = instance->GetCreature(uiLavanthor);
- if (pBoss)
- pBoss->GetMotionMaster()->MovePoint(0, BossStartMove4);
+ HandleGameObject(GetObjectGuid(DATA_LAVANTHOR_CELL), bForceRespawn);
+ boss = GetCreature(DATA_LAVANTHOR);
+ if (boss)
+ boss->GetMotionMaster()->MovePoint(0, BossStartMove4);
break;
case BOSS_XEVOZZ:
- HandleGameObject(uiXevozzCell, bForceRespawn);
- pBoss = instance->GetCreature(uiXevozz);
- if (pBoss)
- pBoss->GetMotionMaster()->MovePoint(0, BossStartMove5);
+ HandleGameObject(GetObjectGuid(DATA_XEVOZZ_CELL), bForceRespawn);
+ boss = GetCreature(DATA_XEVOZZ);
+ if (boss)
+ boss->GetMotionMaster()->MovePoint(0, BossStartMove5);
break;
case BOSS_ZURAMAT:
- HandleGameObject(uiZuramatCell, bForceRespawn);
- pBoss = instance->GetCreature(uiZuramat);
- if (pBoss)
- pBoss->GetMotionMaster()->MovePoint(0, BossStartMove6);
+ HandleGameObject(GetObjectGuid(DATA_ZURAMAT_CELL), bForceRespawn);
+ boss = GetCreature(DATA_ZURAMAT);
+ if (boss)
+ boss->GetMotionMaster()->MovePoint(0, BossStartMove6);
break;
}
// generic boss state changes
- if (pBoss)
+ if (boss)
{
- pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
- pBoss->SetReactState(REACT_AGGRESSIVE);
+ boss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ boss->SetReactState(REACT_AGGRESSIVE);
if (!bForceRespawn)
{
- if (pBoss->isDead())
+ if (boss->isDead())
{
// respawn but avoid to be looted again
- pBoss->Respawn();
- pBoss->RemoveLootMode(1);
+ boss->Respawn();
+ boss->RemoveLootMode(1);
}
- pBoss->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ boss->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
uiWaveCount = 0;
}
}
@@ -555,12 +464,12 @@ public:
case 6:
if (uiFirstBoss == 0)
uiFirstBoss = urand(1, 6);
- if (Creature* pSinclari = instance->GetCreature(uiSinclari))
+ if (Creature* sinclari = GetCreature(DATA_SINCLARI))
{
- if (Creature* pPortal = pSinclari->SummonCreature(CREATURE_TELEPORTATION_PORTAL, MiddleRoomPortalSaboLocation, TEMPSUMMON_CORPSE_DESPAWN))
- uiSaboteurPortal = pPortal->GetGUID();
- if (Creature* pAzureSaboteur = pSinclari->SummonCreature(CREATURE_SABOTEOUR, MiddleRoomLocation, TEMPSUMMON_DEAD_DESPAWN))
- pAzureSaboteur->CastSpell(pAzureSaboteur, SABOTEUR_SHIELD_EFFECT, false);
+ if (Creature* portal = sinclari->SummonCreature(NPC_TELEPORTATION_PORTAL, MiddleRoomPortalSaboLocation, TEMPSUMMON_CORPSE_DESPAWN))
+ uiSaboteurPortal = portal->GetGUID();
+ if (Creature* azureSaboteur = sinclari->SummonCreature(NPC_SABOTEOUR, MiddleRoomLocation, TEMPSUMMON_DEAD_DESPAWN))
+ azureSaboteur->CastSpell(azureSaboteur, SABOTEUR_SHIELD_EFFECT, false);
}
break;
case 12:
@@ -569,25 +478,22 @@ public:
{
uiSecondBoss = urand(1, 6);
} while (uiSecondBoss == uiFirstBoss);
- if (Creature* pSinclari = instance->GetCreature(uiSinclari))
+ if (Creature* sinclari = GetCreature(DATA_SINCLARI))
{
- if (Creature* pPortal = pSinclari->SummonCreature(CREATURE_TELEPORTATION_PORTAL, MiddleRoomPortalSaboLocation, TEMPSUMMON_CORPSE_DESPAWN))
+ if (Creature* pPortal = sinclari->SummonCreature(NPC_TELEPORTATION_PORTAL, MiddleRoomPortalSaboLocation, TEMPSUMMON_CORPSE_DESPAWN))
uiSaboteurPortal = pPortal->GetGUID();
- if (Creature* pAzureSaboteur = pSinclari->SummonCreature(CREATURE_SABOTEOUR, MiddleRoomLocation, TEMPSUMMON_DEAD_DESPAWN))
+ if (Creature* pAzureSaboteur = sinclari->SummonCreature(NPC_SABOTEOUR, MiddleRoomLocation, TEMPSUMMON_DEAD_DESPAWN))
pAzureSaboteur->CastSpell(pAzureSaboteur, SABOTEUR_SHIELD_EFFECT, false);
}
break;
case 18:
- {
- Creature* pSinclari = instance->GetCreature(uiSinclari);
- if (pSinclari)
- pSinclari->SummonCreature(CREATURE_CYANIGOSA, CyanigosasSpawnLocation, TEMPSUMMON_DEAD_DESPAWN);
+ if (Creature* sinclari = GetCreature(DATA_SINCLARI))
+ sinclari->SummonCreature(NPC_CYANIGOSA, CyanigosasSpawnLocation, TEMPSUMMON_DEAD_DESPAWN);
break;
- }
case 1:
{
- if (GameObject* pMainDoor = instance->GetGameObject(uiMainDoor))
- pMainDoor->SetGoState(GO_STATE_READY);
+ if (GameObject* mainDoor = GetGameObject(DATA_MAIN_DOOR))
+ mainDoor->SetGoState(GO_STATE_READY);
DoUpdateWorldState(WORLD_STATE_VH_PRISON_STATE, 100);
// no break
}
@@ -597,54 +503,15 @@ public:
}
}
- std::string GetSaveData() override
+ void WriteSaveDataMore(std::ostringstream& data) override
{
- OUT_SAVE_INST_DATA;
-
- std::ostringstream saveStream;
- saveStream << "V H " << (uint16)m_auiEncounter[0]
- << ' ' << (uint16)m_auiEncounter[1]
- << ' ' << (uint16)m_auiEncounter[2]
- << ' ' << (uint16)uiFirstBoss
- << ' ' << (uint16)uiSecondBoss;
-
- str_data = saveStream.str();
-
- OUT_SAVE_INST_DATA_COMPLETE;
- return str_data;
+ data << uiFirstBoss << ' ' << uiSecondBoss;
}
- void Load(const char* in) override
+ void ReadSaveDataMore(std::istringstream& data) override
{
- if (!in)
- {
- OUT_LOAD_INST_DATA_FAIL;
- return;
- }
-
- OUT_LOAD_INST_DATA(in);
-
- char dataHead1, dataHead2;
- uint16 data0, data1, data2, data3, data4;
-
- std::istringstream loadStream(in);
- loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3 >> data4;
-
- if (dataHead1 == 'V' && dataHead2 == 'H')
- {
- m_auiEncounter[0] = data0;
- m_auiEncounter[1] = data1;
- m_auiEncounter[2] = data2;
-
- for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- if (m_auiEncounter[i] == IN_PROGRESS)
- m_auiEncounter[i] = NOT_STARTED;
-
- uiFirstBoss = uint8(data3);
- uiSecondBoss = uint8(data4);
- } else OUT_LOAD_INST_DATA_FAIL;
-
- OUT_LOAD_INST_DATA_COMPLETE;
+ data >> uiFirstBoss;
+ data >> uiSecondBoss;
}
bool CheckWipe()
@@ -695,54 +562,51 @@ public:
if (GameObject* crystal = instance->GetGameObject(uiActivationCrystal[i]))
crystal->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
- if (Creature* pSinclari = instance->GetCreature(uiSinclari))
+ if (Creature* sinclari = GetCreature(DATA_SINCLARI))
{
- pSinclari->SetVisible(true);
+ sinclari->SetVisible(true);
std::list<Creature*> GuardList;
- pSinclari->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f);
+ sinclari->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f);
if (!GuardList.empty())
{
- for (std::list<Creature*>::const_iterator itr = GuardList.begin(); itr != GuardList.end(); ++itr)
+ for (Creature* guard : GuardList)
{
- if (Creature* pGuard = *itr)
- {
- pGuard->SetVisible(true);
- pGuard->SetReactState(REACT_AGGRESSIVE);
- pGuard->GetMotionMaster()->MovePoint(1, pGuard->GetHomePosition());
- }
+ guard->SetVisible(true);
+ guard->SetReactState(REACT_AGGRESSIVE);
+ guard->GetMotionMaster()->MovePoint(1, guard->GetHomePosition());
}
}
- pSinclari->GetMotionMaster()->MovePoint(1, pSinclari->GetHomePosition());
- pSinclari->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ sinclari->GetMotionMaster()->MovePoint(1, sinclari->GetHomePosition());
+ sinclari->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
}
// Cyanigosa is spawned but not tranformed, prefight event
- Creature* pCyanigosa = instance->GetCreature(uiCyanigosa);
- if (pCyanigosa && !pCyanigosa->HasAura(CYANIGOSA_SPELL_TRANSFORM))
+ Creature* cyanigosa = GetCreature(DATA_CYANIGOSA);
+ if (cyanigosa && !cyanigosa->HasAura(CYANIGOSA_SPELL_TRANSFORM))
{
if (uiCyanigosaEventTimer <= diff)
{
switch (uiCyanigosaEventPhase)
{
case 1:
- pCyanigosa->CastSpell(pCyanigosa, CYANIGOSA_BLUE_AURA, false);
- pCyanigosa->AI()->Talk(CYANIGOSA_SAY_SPAWN);
+ cyanigosa->CastSpell(cyanigosa, CYANIGOSA_BLUE_AURA, false);
+ cyanigosa->AI()->Talk(CYANIGOSA_SAY_SPAWN);
uiCyanigosaEventTimer = 7*IN_MILLISECONDS;
++uiCyanigosaEventPhase;
break;
case 2:
- pCyanigosa->GetMotionMaster()->MoveJump(MiddleRoomLocation.GetPositionX(), MiddleRoomLocation.GetPositionY(), MiddleRoomLocation.GetPositionZ(), 10.0f, 20.0f);
- pCyanigosa->CastSpell(pCyanigosa, CYANIGOSA_BLUE_AURA, false);
+ cyanigosa->GetMotionMaster()->MoveJump(MiddleRoomLocation.GetPositionX(), MiddleRoomLocation.GetPositionY(), MiddleRoomLocation.GetPositionZ(), 10.0f, 20.0f);
+ cyanigosa->CastSpell(cyanigosa, CYANIGOSA_BLUE_AURA, false);
uiCyanigosaEventTimer = 7*IN_MILLISECONDS;
++uiCyanigosaEventPhase;
break;
case 3:
- pCyanigosa->RemoveAurasDueToSpell(CYANIGOSA_BLUE_AURA);
- pCyanigosa->CastSpell(pCyanigosa, CYANIGOSA_SPELL_TRANSFORM, 0);
- pCyanigosa->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
- pCyanigosa->SetReactState(REACT_AGGRESSIVE);
+ cyanigosa->RemoveAurasDueToSpell(CYANIGOSA_BLUE_AURA);
+ cyanigosa->CastSpell(cyanigosa, CYANIGOSA_SPELL_TRANSFORM, 0);
+ cyanigosa->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ cyanigosa->SetReactState(REACT_AGGRESSIVE);
uiCyanigosaEventTimer = 2*IN_MILLISECONDS;
++uiCyanigosaEventPhase;
break;
@@ -794,9 +658,11 @@ public:
trigger->CastSpell(trigger, spellInfoLightning, true, 0, 0, trigger->GetGUID());
// Kill all mobs registered with SetGuidData(ADD_TRASH_MOB)
- for (GuidSet::const_iterator itr = trashMobs.begin(); itr != trashMobs.end(); ++itr)
+ for (GuidSet::const_iterator itr = trashMobs.begin(); itr != trashMobs.end();)
{
Creature* creature = instance->GetCreature(*itr);
+ // Increment the iterator before killing the creature because the kill will remove itr from trashMobs
+ ++itr;
if (creature && creature->IsAlive())
trigger->Kill(creature);
}
@@ -813,6 +679,11 @@ public:
}
}
};
+
+ InstanceScript* GetInstanceScript(InstanceMap* map) const override
+ {
+ return new instance_violet_hold_InstanceMapScript(map);
+ }
};
void AddSC_instance_violet_hold()
diff --git a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp
index 645a9da4764..8bcc80b5a84 100644
--- a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp
+++ b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp
@@ -32,18 +32,18 @@
enum PortalCreatures
{
- CREATURE_AZURE_INVADER_1 = 30661,
- CREATURE_AZURE_INVADER_2 = 30961,
- CREATURE_AZURE_SPELLBREAKER_1 = 30662,
- CREATURE_AZURE_SPELLBREAKER_2 = 30962,
- CREATURE_AZURE_BINDER_1 = 30663,
- CREATURE_AZURE_BINDER_2 = 30918,
- CREATURE_AZURE_MAGE_SLAYER_1 = 30664,
- CREATURE_AZURE_MAGE_SLAYER_2 = 30963,
- CREATURE_AZURE_CAPTAIN = 30666,
- CREATURE_AZURE_SORCEROR = 30667,
- CREATURE_AZURE_RAIDER = 30668,
- CREATURE_AZURE_STALKER = 32191
+ NPC_AZURE_INVADER_1 = 30661,
+ NPC_AZURE_INVADER_2 = 30961,
+ NPC_AZURE_SPELLBREAKER_1 = 30662,
+ NPC_AZURE_SPELLBREAKER_2 = 30962,
+ NPC_AZURE_BINDER_1 = 30663,
+ NPC_AZURE_BINDER_2 = 30918,
+ NPC_AZURE_MAGE_SLAYER_1 = 30664,
+ NPC_AZURE_MAGE_SLAYER_2 = 30963,
+ NPC_AZURE_CAPTAIN = 30666,
+ NPC_AZURE_SORCEROR = 30667,
+ NPC_AZURE_RAIDER = 30668,
+ NPC_AZURE_STALKER = 32191
};
enum AzureInvaderSpells
@@ -258,7 +258,7 @@ public:
{
case GOSSIP_ACTION_INFO_DEF+1:
player->CLOSE_GOSSIP_MENU();
- ENSURE_AI(npc_sinclari_vh::npc_sinclariAI, (creature->AI()))->uiPhase = 1;
+ ENSURE_AI(npc_sinclari_vh::npc_sinclariAI, creature->AI())->uiPhase = 1;
if (InstanceScript* instance = creature->GetInstanceScript())
instance->SetData(DATA_MAIN_EVENT_PHASE, SPECIAL);
break;
@@ -296,17 +296,12 @@ public:
return true;
}
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_sinclariAI>(creature);
- }
-
struct npc_sinclariAI : public ScriptedAI
{
npc_sinclariAI(Creature* creature) : ScriptedAI(creature)
{
Initialize();
- instance = creature->GetInstanceScript();
+ instance = creature->GetInstanceScript();
}
void Initialize()
@@ -345,8 +340,6 @@ public:
void UpdateAI(uint32 uiDiff) override
{
- ScriptedAI::UpdateAI(uiDiff);
-
if (uiPhase)
{
if (uiTimer <= uiDiff)
@@ -415,6 +408,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_sinclariAI>(creature);
+ }
};
class npc_azure_saboteur : public CreatureScript
@@ -422,14 +419,9 @@ class npc_azure_saboteur : public CreatureScript
public:
npc_azure_saboteur() : CreatureScript("npc_azure_saboteur") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_azure_saboteurAI>(creature);
- }
-
struct npc_azure_saboteurAI : public npc_escortAI
{
- npc_azure_saboteurAI(Creature* creature):npc_escortAI(creature)
+ npc_azure_saboteurAI(Creature* creature) : npc_escortAI(creature)
{
instance = creature->GetInstanceScript();
bHasGotMovingPoints = false;
@@ -532,13 +524,16 @@ public:
{
me->CastSpell(me, SABOTEUR_SHIELD_DISRUPTION, false);
me->DisappearAndDie();
- Creature* pSaboPort = ObjectAccessor::GetCreature((*me), instance->GetGuidData(DATA_SABOTEUR_PORTAL));
- if (pSaboPort)
+ if (Creature* pSaboPort = ObjectAccessor::GetCreature((*me), instance->GetGuidData(DATA_SABOTEUR_PORTAL)))
pSaboPort->DisappearAndDie();
instance->SetData(DATA_START_BOSS_ENCOUNTER, 1);
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_azure_saboteurAI>(creature);
+ }
};
class npc_teleportation_portal_vh : public CreatureScript
@@ -546,11 +541,6 @@ class npc_teleportation_portal_vh : public CreatureScript
public:
npc_teleportation_portal_vh() : CreatureScript("npc_teleportation_portal_vh") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_teleportation_portalAI>(creature);
- }
-
struct npc_teleportation_portalAI : public ScriptedAI
{
npc_teleportation_portalAI(Creature* creature) : ScriptedAI(creature), listOfMobs(me)
@@ -583,7 +573,6 @@ public:
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
if (instance->GetData(DATA_REMOVE_NPC) == 1)
@@ -608,7 +597,7 @@ public:
uint8 k = uiWaveCount < 12 ? 2 : 3;
for (uint8 i = 0; i < k; ++i)
{
- uint32 entry = RAND(CREATURE_AZURE_CAPTAIN, CREATURE_AZURE_RAIDER, CREATURE_AZURE_STALKER, CREATURE_AZURE_SORCEROR);
+ uint32 entry = RAND(NPC_AZURE_CAPTAIN, NPC_AZURE_RAIDER, NPC_AZURE_STALKER, NPC_AZURE_SORCEROR);
DoSummon(entry, me, 2.0f, 20000, TEMPSUMMON_DEAD_DESPAWN);
}
me->SetVisible(false);
@@ -633,14 +622,14 @@ public:
uint8 k = instance->GetData(DATA_WAVE_COUNT) < 12 ? 3 : 4;
for (uint8 i = 0; i < k; ++i)
{
- uint32 entry = RAND(CREATURE_AZURE_INVADER_1, CREATURE_AZURE_INVADER_2, CREATURE_AZURE_SPELLBREAKER_1, CREATURE_AZURE_SPELLBREAKER_2, CREATURE_AZURE_MAGE_SLAYER_1, CREATURE_AZURE_MAGE_SLAYER_2, CREATURE_AZURE_BINDER_1, CREATURE_AZURE_BINDER_2);
+ uint32 entry = RAND(NPC_AZURE_INVADER_1, NPC_AZURE_INVADER_2, NPC_AZURE_SPELLBREAKER_1, NPC_AZURE_SPELLBREAKER_2, NPC_AZURE_MAGE_SLAYER_1, NPC_AZURE_MAGE_SLAYER_2, NPC_AZURE_BINDER_1, NPC_AZURE_BINDER_2);
DoSummon(entry, me, 2.0f, 20000, TEMPSUMMON_DEAD_DESPAWN);
}
}
else
{
bPortalGuardianOrKeeperOrEliteSpawn = true;
- uint32 entry = RAND(CREATURE_PORTAL_GUARDIAN, CREATURE_PORTAL_KEEPER);
+ uint32 entry = RAND(NPC_PORTAL_GUARDIAN, NPC_PORTAL_KEEPER);
if (Creature* pPortalKeeper = DoSummon(entry, me, 2.0f, 0, TEMPSUMMON_DEAD_DESPAWN))
me->CastSpell(pPortalKeeper, SPELL_PORTAL_CHANNEL, false);
}
@@ -674,11 +663,15 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_teleportation_portalAI>(creature);
+ }
};
struct violet_hold_trashAI : public npc_escortAI
{
- violet_hold_trashAI(Creature* creature):npc_escortAI(creature)
+ violet_hold_trashAI(Creature* creature) : npc_escortAI(creature)
{
instance = creature->GetInstanceScript();
bHasGotMovingPoints = false;
@@ -723,7 +716,7 @@ struct violet_hold_trashAI : public npc_escortAI
}
}
- void UpdateAI(uint32) override
+ void UpdateAI(uint32 diff) override
{
if (instance->GetData(DATA_MAIN_EVENT_PHASE) != IN_PROGRESS)
me->CastStop();
@@ -778,6 +771,8 @@ struct violet_hold_trashAI : public npc_escortAI
SetDespawnAtEnd(false);
Start(true, true);
}
+
+ npc_escortAI::UpdateAI(diff);
}
void JustDied(Unit* /*killer*/) override
@@ -791,7 +786,6 @@ struct violet_hold_trashAI : public npc_escortAI
DoCast(SPELL_DESTROY_DOOR_SEAL);
instance->SetData(DATA_NPC_PRESENCE_AT_DOOR_ADD, 1);
}
-
};
class npc_azure_invader : public CreatureScript
@@ -799,11 +793,6 @@ class npc_azure_invader : public CreatureScript
public:
npc_azure_invader() : CreatureScript("npc_azure_invader") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_azure_invaderAI>(creature);
- }
-
struct npc_azure_invaderAI : public violet_hold_trashAI
{
npc_azure_invaderAI(Creature* creature) : violet_hold_trashAI(creature)
@@ -833,12 +822,11 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
- if (me->GetEntry() == CREATURE_AZURE_INVADER_1)
+ if (me->GetEntry() == NPC_AZURE_INVADER_1)
{
if (uiCleaveTimer <= diff)
{
@@ -848,14 +836,13 @@ public:
if (uiImpaleTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_IMPALE);
uiImpaleTimer = 4000;
} else uiImpaleTimer -= diff;
}
- if (me->GetEntry() == CREATURE_AZURE_INVADER_2)
+ if (me->GetEntry() == NPC_AZURE_INVADER_2)
{
if (uiBrutalStrikeTimer <= diff)
{
@@ -876,6 +863,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_azure_invaderAI>(creature);
+ }
};
class npc_azure_binder : public CreatureScript
@@ -883,11 +874,6 @@ class npc_azure_binder : public CreatureScript
public:
npc_azure_binder() : CreatureScript("npc_azure_binder") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_azure_binderAI>(creature);
- }
-
struct npc_azure_binderAI : public violet_hold_trashAI
{
npc_azure_binderAI(Creature* creature) : violet_hold_trashAI(creature)
@@ -917,12 +903,11 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
- if (me->GetEntry() == CREATURE_AZURE_BINDER_1)
+ if (me->GetEntry() == NPC_AZURE_BINDER_1)
{
if (uiArcaneExplosionTimer <= diff)
{
@@ -930,16 +915,15 @@ public:
uiArcaneExplosionTimer = 5000;
} else uiArcaneExplosionTimer -= diff;
- if (uiArcainBarrageTimer <= diff)
+ if (uiArcainBarrageTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
- DoCast(target, SPELL_ARCANE_BARRAGE);
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
+ DoCast(target, SPELL_ARCANE_BARRAGE);
uiArcainBarrageTimer = 6000;
} else uiArcainBarrageTimer -= diff;
}
- if (me->GetEntry() == CREATURE_AZURE_BINDER_2)
+ if (me->GetEntry() == NPC_AZURE_BINDER_2)
{
if (uiFrostNovaTimer <= diff)
{
@@ -949,8 +933,7 @@ public:
if (uiFrostboltTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_FROSTBOLT);
uiFrostboltTimer = 6000;
} else uiFrostboltTimer -= diff;
@@ -960,6 +943,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_azure_binderAI>(creature);
+ }
};
class npc_azure_mage_slayer : public CreatureScript
@@ -967,11 +954,6 @@ class npc_azure_mage_slayer : public CreatureScript
public:
npc_azure_mage_slayer() : CreatureScript("npc_azure_mage_slayer") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_azure_mage_slayerAI>(creature);
- }
-
struct npc_azure_mage_slayerAI : public violet_hold_trashAI
{
npc_azure_mage_slayerAI(Creature* creature) : violet_hold_trashAI(creature)
@@ -997,12 +979,11 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
- if (me->GetEntry() == CREATURE_AZURE_MAGE_SLAYER_1)
+ if (me->GetEntry() == NPC_AZURE_MAGE_SLAYER_1)
{
if (uiArcaneEmpowermentTimer <= diff)
{
@@ -1011,12 +992,11 @@ public:
} else uiArcaneEmpowermentTimer -= diff;
}
- if (me->GetEntry() == CREATURE_AZURE_MAGE_SLAYER_2)
+ if (me->GetEntry() == NPC_AZURE_MAGE_SLAYER_2)
{
if (uiSpellLockTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_SPELL_LOCK);
uiSpellLockTimer = 9000;
} else uiSpellLockTimer -= diff;
@@ -1026,6 +1006,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_azure_mage_slayerAI>(creature);
+ }
};
class npc_azure_raider : public CreatureScript
@@ -1033,11 +1017,6 @@ class npc_azure_raider : public CreatureScript
public:
npc_azure_raider() : CreatureScript("npc_azure_raider") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_azure_raiderAI>(creature);
- }
-
struct npc_azure_raiderAI : public violet_hold_trashAI
{
npc_azure_raiderAI(Creature* creature) : violet_hold_trashAI(creature)
@@ -1063,7 +1042,6 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
@@ -1084,6 +1062,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_azure_raiderAI>(creature);
+ }
};
class npc_azure_stalker : public CreatureScript
@@ -1114,7 +1096,6 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
@@ -1123,8 +1104,7 @@ public:
{
if (_tacticalBlinkTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40, true))
DoCast(target, SPELL_TACTICAL_BLINK);
_tacticalBlinkTimer = 6000;
_tacticalBlinkCast = true;
@@ -1135,8 +1115,8 @@ public:
{
if (_backstabTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_NEAREST, 0, 10, true);
- DoCast(target, SPELL_BACKSTAB);
+ if (Unit* target = SelectTarget(SELECT_TARGET_NEAREST, 0, 10, true))
+ DoCast(target, SPELL_BACKSTAB);
_tacticalBlinkCast = false;
_backstabTimer =1300;
} else _backstabTimer -= diff;
@@ -1191,36 +1171,32 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
- if (me->GetEntry() == CREATURE_AZURE_SPELLBREAKER_1)
+ if (me->GetEntry() == NPC_AZURE_SPELLBREAKER_1)
{
if (uiArcaneBlastTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_ARCANE_BLAST);
uiArcaneBlastTimer = 6000;
} else uiArcaneBlastTimer -= diff;
if (uiSlowTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_SLOW);
uiSlowTimer = 5000;
} else uiSlowTimer -= diff;
}
- if (me->GetEntry() == CREATURE_AZURE_SPELLBREAKER_2)
+ if (me->GetEntry() == NPC_AZURE_SPELLBREAKER_2)
{
if (uiChainsOfIceTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_CHAINS_OF_ICE);
uiChainsOfIceTimer = 7000;
} else uiChainsOfIceTimer -= diff;
@@ -1247,11 +1223,6 @@ class npc_azure_captain : public CreatureScript
public:
npc_azure_captain() : CreatureScript("npc_azure_captain") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_azure_captainAI>(creature);
- }
-
struct npc_azure_captainAI : public violet_hold_trashAI
{
npc_azure_captainAI(Creature* creature) : violet_hold_trashAI(creature)
@@ -1277,7 +1248,6 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
@@ -1298,6 +1268,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_azure_captainAI>(creature);
+ }
};
class npc_azure_sorceror : public CreatureScript
@@ -1305,11 +1279,6 @@ class npc_azure_sorceror : public CreatureScript
public:
npc_azure_sorceror() : CreatureScript("npc_azure_sorceror") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_azure_sorcerorAI>(creature);
- }
-
struct npc_azure_sorcerorAI : public violet_hold_trashAI
{
npc_azure_sorcerorAI(Creature* creature) : violet_hold_trashAI(creature)
@@ -1337,15 +1306,13 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
if (uiArcaneStreamTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_ARCANE_STREAM);
uiArcaneStreamTimer = urand(0, 5000)+5000;
uiArcaneStreamTimerStartingValueHolder = uiArcaneStreamTimer;
@@ -1360,6 +1327,11 @@ public:
DoMeleeAttackIfReady();
}
};
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_azure_sorcerorAI>(creature);
+ }
};
diff --git a/src/server/scripts/Northrend/VioletHold/violet_hold.h b/src/server/scripts/Northrend/VioletHold/violet_hold.h
index 404d1f493e6..275a7467d83 100644
--- a/src/server/scripts/Northrend/VioletHold/violet_hold.h
+++ b/src/server/scripts/Northrend/VioletHold/violet_hold.h
@@ -18,13 +18,18 @@
#ifndef DEF_VIOLET_HOLD_H
#define DEF_VIOLET_HOLD_H
-#define DataHeader "VIO"
+#define DataHeader "VH"
+
+uint32 const EncounterCount = 3;
enum Data
{
+ // Main encounters
DATA_1ST_BOSS_EVENT,
DATA_2ND_BOSS_EVENT,
- DATA_CYANIGOSA_EVENT,
+ DATA_CYANIGOSA,
+
+ // Misc
DATA_WAVE_COUNT,
DATA_REMOVE_NPC,
DATA_PORTAL_LOCATION,
@@ -38,10 +43,8 @@ enum Data
DATA_ACTIVATE_CRYSTAL,
DATA_MAIN_EVENT_PHASE,
DATA_DEFENSELESS,
-};
-enum Data64
-{
+ // Bosses
DATA_MORAGG,
DATA_EREKEM,
DATA_EREKEM_GUARD_1,
@@ -50,7 +53,8 @@ enum Data64
DATA_LAVANTHOR,
DATA_XEVOZZ,
DATA_ZURAMAT,
- DATA_CYANIGOSA,
+
+ // Cells
DATA_MORAGG_CELL,
DATA_EREKEM_CELL,
DATA_EREKEM_LEFT_GUARD_CELL,
@@ -59,6 +63,8 @@ enum Data64
DATA_LAVANTHOR_CELL,
DATA_XEVOZZ_CELL,
DATA_ZURAMAT_CELL,
+
+ // Misc
DATA_MAIN_DOOR,
DATA_SINCLARI,
DATA_TELEPORTATION_PORTAL,
@@ -81,33 +87,48 @@ enum Bosses
enum CreaturesIds
{
- CREATURE_TELEPORTATION_PORTAL = 31011,
- CREATURE_PORTAL_GUARDIAN = 30660,
- CREATURE_PORTAL_KEEPER = 30695,
- CREATURE_XEVOZZ = 29266,
- CREATURE_LAVANTHOR = 29312,
- CREATURE_ICHORON = 29313,
- CREATURE_ZURAMAT = 29314,
- CREATURE_EREKEM = 29315,
- CREATURE_EREKEM_GUARD = 29395,
- CREATURE_MORAGG = 29316,
- CREATURE_CYANIGOSA = 31134,
- CREATURE_SINCLARI = 30658,
- CREATURE_SABOTEOUR = 31079,
- NPC_VIOLET_HOLD_GUARD = 30659,
- NPC_DEFENSE_SYSTEM = 30837
+ NPC_TELEPORTATION_PORTAL = 31011,
+ NPC_PORTAL_GUARDIAN = 30660,
+ NPC_PORTAL_KEEPER = 30695,
+ NPC_XEVOZZ = 29266,
+ NPC_LAVANTHOR = 29312,
+ NPC_ICHORON = 29313,
+ NPC_ZURAMAT = 29314,
+ NPC_EREKEM = 29315,
+ NPC_EREKEM_GUARD = 29395,
+ NPC_MORAGG = 29316,
+ NPC_CYANIGOSA = 31134,
+ NPC_SINCLARI = 30658,
+ NPC_SABOTEOUR = 31079,
+ NPC_VIOLET_HOLD_GUARD = 30659,
+ NPC_DEFENSE_SYSTEM = 30837
+};
+
+enum GameObjectIds
+{
+ GO_MAIN_DOOR = 191723,
+ GO_XEVOZZ_DOOR = 191556,
+ GO_LAVANTHOR_DOOR = 191566,
+ GO_ICHORON_DOOR = 191722,
+ GO_ZURAMAT_DOOR = 191565,
+ GO_EREKEM_DOOR = 191564,
+ GO_EREKEM_GUARD_1_DOOR = 191563,
+ GO_EREKEM_GUARD_2_DOOR = 191562,
+ GO_MORAGG_DOOR = 191606,
+ GO_INTRO_ACTIVATION_CRYSTAL = 193615,
+ GO_ACTIVATION_CRYSTAL = 193611
};
enum WorldStateIds
{
- WORLD_STATE_VH = 3816,
- WORLD_STATE_VH_PRISON_STATE = 3815,
- WORLD_STATE_VH_WAVE_COUNT = 3810,
+ WORLD_STATE_VH = 3816,
+ WORLD_STATE_VH_PRISON_STATE = 3815,
+ WORLD_STATE_VH_WAVE_COUNT = 3810,
};
enum Events
{
- EVENT_ACTIVATE_CRYSTAL = 20001
+ EVENT_ACTIVATE_CRYSTAL = 20001
};
#endif
diff --git a/src/server/scripts/Northrend/zone_dragonblight.cpp b/src/server/scripts/Northrend/zone_dragonblight.cpp
index b7efa7c3d3e..dc5b75d425d 100644
--- a/src/server/scripts/Northrend/zone_dragonblight.cpp
+++ b/src/server/scripts/Northrend/zone_dragonblight.cpp
@@ -174,7 +174,7 @@ class npc_commander_eligor_dawnbringer : public CreatureScript
{
if (id == 1)
{
- me->SetFacingTo(PosTalkLocations[talkWing].m_orientation);
+ me->SetFacingTo(PosTalkLocations[talkWing].GetOrientation());
TurnAudience();
switch (talkWing)
diff --git a/src/server/scripts/Northrend/zone_icecrown.cpp b/src/server/scripts/Northrend/zone_icecrown.cpp
index 7f29a6621bd..2e426fd77cf 100644
--- a/src/server/scripts/Northrend/zone_icecrown.cpp
+++ b/src/server/scripts/Northrend/zone_icecrown.cpp
@@ -25,53 +25,6 @@
#include "CombatAI.h"
/*######
-## npc_squire_david
-######*/
-
-enum SquireDavid
-{
- QUEST_THE_ASPIRANT_S_CHALLENGE_H = 13680,
- QUEST_THE_ASPIRANT_S_CHALLENGE_A = 13679,
-
- NPC_ARGENT_VALIANT = 33448,
-
- GOSSIP_TEXTID_SQUIRE = 14407
-};
-
-#define GOSSIP_SQUIRE_ITEM_1 "I am ready to fight!"
-#define GOSSIP_SQUIRE_ITEM_2 "How do the Argent Crusader raiders fight?"
-
-class npc_squire_david : public CreatureScript
-{
-public:
- npc_squire_david() : CreatureScript("npc_squire_david") { }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (player->GetQuestStatus(QUEST_THE_ASPIRANT_S_CHALLENGE_H) == QUEST_STATUS_INCOMPLETE ||
- player->GetQuestStatus(QUEST_THE_ASPIRANT_S_CHALLENGE_A) == QUEST_STATUS_INCOMPLETE)//We need more info about it.
- {
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SQUIRE_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SQUIRE_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2);
- }
-
- player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_SQUIRE, creature->GetGUID());
- return true;
- }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- if (action == GOSSIP_ACTION_INFO_DEF+1)
- {
- player->CLOSE_GOSSIP_MENU();
- creature->SummonCreature(NPC_ARGENT_VALIANT, 8575.451f, 952.472f, 547.554f, 0.38f);
- }
- return true;
- }
-};
-
-/*######
## npc_argent_valiant
######*/
@@ -837,7 +790,6 @@ class npc_frostbrood_skytalon : public CreatureScript
void AddSC_icecrown()
{
- new npc_squire_david;
new npc_argent_valiant;
new npc_guardian_pavilion;
new npc_tournament_training_dummy;
diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp
index bb1e88ce158..d5d9f8ae77e 100644
--- a/src/server/scripts/Northrend/zone_storm_peaks.cpp
+++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp
@@ -19,6 +19,7 @@
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
#include "ScriptedEscortAI.h"
+#include "SpellHistory.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
#include "Vehicle.h"
diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h
index 80c8041bc6d..fac9d8fa357 100644
--- a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h
+++ b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h
@@ -261,13 +261,13 @@ class OPvPCapturePointNA : public OPvPCapturePoint
public:
OPvPCapturePointNA(OutdoorPvP* pvp);
- bool Update(uint32 diff);
+ bool Update(uint32 diff) override;
- void ChangeState();
+ void ChangeState() override;
- void FillInitialWorldStates(WorldPacket & data);
+ void FillInitialWorldStates(WorldPacket & data) override;
- bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go);
+ bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go) override;
int32 HandleOpenGo(Player* player, ObjectGuid guid) override;
diff --git a/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp b/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp
index 662bad46162..263fd8340b9 100644
--- a/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp
+++ b/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp
@@ -113,7 +113,7 @@ public:
Map::PlayerList const &PlayerList = map->GetPlayers();
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
if (Player* i_pl = i->GetSource())
- if (i_pl->IsAlive() && (dist = i_pl->IsWithinDist(me, 45)))
+ if (i_pl->IsAlive() && (dist = i_pl->GetDistance(me)) < 45)
{
i_pl->RemoveAurasDueToSpell(SPELL_INHIBITMAGIC);
me->AddAura(SPELL_INHIBITMAGIC, i_pl);
diff --git a/src/server/scripts/Outland/CMakeLists.txt b/src/server/scripts/Outland/CMakeLists.txt
index 24658dbc21f..42621b76941 100644
--- a/src/server/scripts/Outland/CMakeLists.txt
+++ b/src/server/scripts/Outland/CMakeLists.txt
@@ -27,6 +27,7 @@ set(scripts_STAT_SRCS
Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp
Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp
+ Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp
Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp
Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp
Outland/CoilfangReservoir/SteamVault/boss_mekgineer_steamrigger.cpp
diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp
index 1657b178327..d7ba0a34939 100644
--- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp
+++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp
@@ -275,8 +275,8 @@ class instance_serpent_shrine : public InstanceMapScript
if (data == DONE)
{
HandleGameObject(BridgePart[0], true);
- HandleGameObject(BridgePart[0], true);
- HandleGameObject(BridgePart[0], true);
+ HandleGameObject(BridgePart[1], true);
+ HandleGameObject(BridgePart[2], true);
}
break;
case DATA_TRASH:
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp
index 21ed710f4d8..7f2e08b39ca 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp
@@ -87,11 +87,11 @@ class boss_warchief_kargath_bladefist : public CreatureScript
resetcheck_timer = 5000;
}
- void SetData(uint32 type, uint32 data) override
+ void DoAction(int32 action) override
{
- if (type == 1)
+ if (action == ACTION_EXECUTIONER_TAUNT)
{
- switch (data)
+ switch (instance->GetData(DATA_TEAM_IN_INSTANCE))
{
case ALLIANCE:
Talk(SAY_CALL_EXECUTIONER_A);
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp
index 325e9456c02..5cfae286f9b 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp
@@ -32,20 +32,11 @@ EndScriptData */
#include "SpellAuras.h"
#include "shattered_halls.h"
-enum Spells
-{
- SPELL_CLEAVE = 15284,
-
- SPELL_EXECUTE_1 = 39288,
- SPELL_EXECUTE_2,
- SPELL_EXECUTE_3
-};
-
DoorData const doorData[] =
{
- {GO_GRAND_WARLOCK_CHAMBER_DOOR_1, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_S },
- {GO_GRAND_WARLOCK_CHAMBER_DOOR_2, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_N },
- {0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE}
+ { GO_GRAND_WARLOCK_CHAMBER_DOOR_1, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
+ { GO_GRAND_WARLOCK_CHAMBER_DOOR_2, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
+ { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE }
};
class instance_shattered_halls : public InstanceMapScript
@@ -77,9 +68,7 @@ class instance_shattered_halls : public InstanceMapScript
if (!_team)
_team = player->GetTeam();
- player->RemoveAurasDueToSpell(SPELL_EXECUTE_1);
- player->RemoveAurasDueToSpell(SPELL_EXECUTE_2);
- player->RemoveAurasDueToSpell(SPELL_EXECUTE_3);
+ player->CastSpell(player, SPELL_REMOVE_KARGATH_EXECUTIONER, true);
if (!executionTimer || executionerGUID.IsEmpty())
return;
@@ -87,13 +76,13 @@ class instance_shattered_halls : public InstanceMapScript
switch (executed)
{
case 0:
- ex = player->AddAura(SPELL_EXECUTE_1, player);
+ ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_1, player);
break;
case 1:
- ex = player->AddAura(SPELL_EXECUTE_2, player);
+ ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_2, player);
break;
case 2:
- ex = player->AddAura(SPELL_EXECUTE_3, player);
+ ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_3, player);
break;
default:
break;
@@ -151,10 +140,22 @@ class instance_shattered_halls : public InstanceMapScript
break;
case NPC_SHATTERED_EXECUTIONER:
executionTimer = 55 * MINUTE * IN_MILLISECONDS;
- DoCastSpellOnPlayers(SPELL_EXECUTE_1);
+ DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_1);
executionerGUID = creature->GetGUID();
SaveToDB();
break;
+ case NPC_CAPTAIN_ALINA:
+ case NPC_CAPTAIN_BONESHATTER:
+ victimsGUID[0] = creature->GetGUID();
+ break;
+ case NPC_ALLIANCE_VICTIM_1:
+ case NPC_HORDE_VICTIM_1:
+ victimsGUID[1] = creature->GetGUID();
+ break;
+ case NPC_ALLIANCE_VICTIM_2:
+ case NPC_HORDE_VICTIM_2:
+ victimsGUID[2] = creature->GetGUID();
+ break;
}
}
@@ -168,16 +169,14 @@ class instance_shattered_halls : public InstanceMapScript
case DATA_SHATTERED_EXECUTIONER:
if (state == DONE)
{
- DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_1);
- DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_2);
- DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_3);
+ DoCastSpellOnPlayers(SPELL_REMOVE_KARGATH_EXECUTIONER);
executionTimer = 0;
SaveToDB();
}
break;
case DATA_KARGATH:
if (Creature* executioner = instance->GetCreature(executionerGUID))
- executioner->AI()->Reset();
+ executioner->AI()->Reset(); // trigger removal of IMMUNE_TO_PC flag
break;
case DATA_OMROGG:
break;
@@ -191,16 +190,16 @@ class instance_shattered_halls : public InstanceMapScript
{
case NPC_GRAND_WARLOCK_NETHEKURSE:
return nethekurseGUID;
- break;
case NPC_KARGATH_BLADEFIST:
return kargathGUID;
- break;
case NPC_SHATTERED_EXECUTIONER:
return executionerGUID;
- break;
+ case DATA_FIRST_PRISONER:
+ case DATA_SECOND_PRISONER:
+ case DATA_THIRD_PRISONER:
+ return victimsGUID[data - DATA_FIRST_PRISONER];
default:
return ObjectGuid::Empty;
- break;
}
}
@@ -253,13 +252,10 @@ class instance_shattered_halls : public InstanceMapScript
{
case DATA_PRISONERS_EXECUTED:
return executed;
- break;
case DATA_TEAM_IN_INSTANCE:
return _team;
- break;
default:
return 0;
- break;
}
}
@@ -269,27 +265,25 @@ class instance_shattered_halls : public InstanceMapScript
return;
if (executionTimer <= diff)
- {
+ {
+ DoCastSpellOnPlayers(SPELL_REMOVE_KARGATH_EXECUTIONER);
switch (++executed)
{
case 1:
- DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_1);
- DoCastSpellOnPlayers(SPELL_EXECUTE_2);
+ DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_2);
executionTimer = 10 * MINUTE * IN_MILLISECONDS;
break;
case 2:
- DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_2);
- DoCastSpellOnPlayers(SPELL_EXECUTE_3);
+ DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_3);
executionTimer = 15 * MINUTE * IN_MILLISECONDS;
break;
default:
- DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_3);
executionTimer = 0;
break;
}
if (Creature* executioner = instance->GetCreature(executionerGUID))
- executioner->AI()->SetData(1, executed);
+ executioner->AI()->SetData(DATA_PRISONERS_EXECUTED, executed);
SaveToDB();
}
@@ -297,10 +291,11 @@ class instance_shattered_halls : public InstanceMapScript
executionTimer -= diff;
}
- protected:
+ private:
ObjectGuid nethekurseGUID;
ObjectGuid kargathGUID;
ObjectGuid executionerGUID;
+ ObjectGuid victimsGUID[3];
uint8 executed;
uint32 executionTimer;
@@ -308,191 +303,7 @@ class instance_shattered_halls : public InstanceMapScript
};
};
-class at_nethekurse_exit : public AreaTriggerScript
-{
- public:
- at_nethekurse_exit() : AreaTriggerScript("at_nethekurse_exit") { };
-
- bool OnTrigger(Player* player, AreaTriggerEntry const*) override
- {
- if (InstanceScript* is = player->GetInstanceScript())
- {
- if (is->instance->IsHeroic())
- {
- Creature* executioner = nullptr;
-
- is->instance->LoadGrid(Executioner.GetPositionX(), Executioner.GetPositionY());
- if (Creature* kargath = ObjectAccessor::GetCreature(*player, is->GetGuidData(NPC_KARGATH_BLADEFIST)))
- {
- if (is->GetGuidData(NPC_SHATTERED_EXECUTIONER).IsEmpty())
- {
- executioner = kargath->SummonCreature(NPC_SHATTERED_EXECUTIONER, Executioner);
- kargath->AI()->SetData(1, is->GetData(DATA_TEAM_IN_INSTANCE));
- }
- }
-
- if (executioner)
- for (uint8 i = 0; i < VictimCount; ++i)
- executioner->SummonCreature(executionerVictims[i](is->GetData(DATA_TEAM_IN_INSTANCE)), executionerVictims[i].GetPos());
- }
- }
-
- return false;
- }
-};
-
-class boss_shattered_executioner : public CreatureScript
-{
- public:
- boss_shattered_executioner() : CreatureScript("boss_shattered_executioner") { }
-
- struct boss_shattered_executionerAI : public BossAI
- {
- boss_shattered_executionerAI(Creature* creature) : BossAI(creature, DATA_SHATTERED_EXECUTIONER)
- {
- Initialize();
- };
-
- void Initialize()
- {
- cleaveTimer = 500;
- me->ResetLootMode();
- switch (instance->GetData(DATA_PRISONERS_EXECUTED))
- {
- case 0:
- me->AddLootMode(LOOT_MODE_HARD_MODE_3);
- case 1:
- me->AddLootMode(LOOT_MODE_HARD_MODE_2);
- case 2:
- me->AddLootMode(LOOT_MODE_HARD_MODE_1);
- default:
- break;
- }
- }
-
- void Reset() override
- {
- _Reset();
- if (instance->GetBossState(DATA_KARGATH) == DONE)
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
- else
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
-
- Initialize();
- }
-
- void JustSummoned(Creature*) override { }
-
- void JustDied(Unit*) override
- {
- _JustDied();
- Map::PlayerList const &players = instance->instance->GetPlayers();
- for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
- {
- Player* pl = itr->GetSource();
- uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
- if (pl->GetQuestStatus(qId) != QUEST_STATUS_NONE && pl->GetQuestStatus(qId) != QUEST_STATUS_FAILED)
- pl->CompleteQuest(qId);
- }
- }
-
- void SetData(uint32 type, uint32 data) override
- {
- if (type == 1)
- {
- uint32 entry = executionerVictims[data - 1](instance->GetData(DATA_TEAM_IN_INSTANCE));
- if (Creature* victim = me->FindNearestCreature(entry, 30.0f, true))
- me->Kill(victim);
-
- if (data == 1)
- {
- Map::PlayerList const &players = instance->instance->GetPlayers();
- for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
- {
- Player* pl = itr->GetSource();
- uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
- if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE)
- pl->FailQuest(qId);
- }
- }
-
- switch (data)
- {
- case 3:
- me->RemoveLootMode(LOOT_MODE_HARD_MODE_1);
- case 2:
- me->RemoveLootMode(LOOT_MODE_HARD_MODE_2);
- case 1:
- me->RemoveLootMode(LOOT_MODE_HARD_MODE_3);
- default:
- break;
- }
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- if (cleaveTimer <= diff)
- {
- DoCast(SPELL_CLEAVE);
- cleaveTimer = urand(5000, 7000);
- }
- else
- cleaveTimer -= diff;
-
- DoMeleeAttackIfReady();
- }
- private:
- uint32 cleaveTimer;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_shattered_executionerAI>(creature);
- }
-};
-
-class spell_kargath_executioner : public SpellScriptLoader
-{
- public:
- spell_kargath_executioner() : SpellScriptLoader("spell_kargath_executioner") { }
-
- class spell_kargath_executioner_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_kargath_executioner_AuraScript);
-
- bool AreaCheck(Unit* target)
- {
- if (target->GetMap()->GetId() != 540)
- return false;
-
- return true;
- }
-
- bool Load() override
- {
- return GetCaster()->GetTypeId() == TYPEID_PLAYER;
- }
-
- void Register() override
- {
- DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_kargath_executioner_AuraScript::AreaCheck);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_kargath_executioner_AuraScript();
- }
-};
-
void AddSC_instance_shattered_halls()
{
new instance_shattered_halls();
- new at_nethekurse_exit();
- new boss_shattered_executioner();
- new spell_kargath_executioner();
}
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp
new file mode 100644
index 00000000000..500b0ae4bcb
--- /dev/null
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2008-2015 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 "SpellScript.h"
+#include "SpellAuraEffects.h"
+#include "InstanceScript.h"
+#include "Player.h"
+#include "SpellAuras.h"
+#include "shattered_halls.h"
+
+class at_nethekurse_exit : public AreaTriggerScript
+{
+ public:
+ at_nethekurse_exit() : AreaTriggerScript("at_nethekurse_exit") { };
+
+ bool OnTrigger(Player* player, AreaTriggerEntry const*) override
+ {
+ if (InstanceScript* is = player->GetInstanceScript())
+ {
+ if (is->instance->IsHeroic())
+ {
+ Creature* executioner = nullptr;
+
+ is->instance->LoadGrid(Executioner.GetPositionX(), Executioner.GetPositionY());
+ if (Creature* kargath = ObjectAccessor::GetCreature(*player, is->GetGuidData(NPC_KARGATH_BLADEFIST)))
+ {
+ if (is->GetGuidData(NPC_SHATTERED_EXECUTIONER).IsEmpty())
+ {
+ executioner = kargath->SummonCreature(NPC_SHATTERED_EXECUTIONER, Executioner);
+ kargath->AI()->DoAction(ACTION_EXECUTIONER_TAUNT);
+ }
+ }
+
+ if (executioner)
+ for (uint8 i = 0; i < VictimCount; ++i)
+ executioner->SummonCreature(executionerVictims[i](is->GetData(DATA_TEAM_IN_INSTANCE)), executionerVictims[i].GetPos());
+ }
+ }
+
+ return false;
+ }
+};
+
+enum Spells
+{
+ SPELL_CLEAVE = 15284
+};
+
+class boss_shattered_executioner : public CreatureScript
+{
+ public:
+ boss_shattered_executioner() : CreatureScript("boss_shattered_executioner") { }
+
+ struct boss_shattered_executionerAI : public BossAI
+ {
+ boss_shattered_executionerAI(Creature* creature) : BossAI(creature, DATA_SHATTERED_EXECUTIONER)
+ {
+ Initialize();
+ };
+
+ void Initialize()
+ {
+ cleaveTimer = 500;
+ }
+
+ void Reset() override
+ {
+ _Reset();
+
+ // _Reset() resets the loot mode, so we add them again, if any
+ uint32 prisonersExecuted = instance->GetData(DATA_PRISONERS_EXECUTED);
+ if (prisonersExecuted == 0)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_3);
+ if (prisonersExecuted <= 1)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_2);
+ if (prisonersExecuted <= 2)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_1);
+
+ if (instance->GetBossState(DATA_KARGATH) == DONE)
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+ else
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+
+ Initialize();
+ }
+
+ void JustSummoned(Creature*) override { } // avoid despawn of prisoners on death/reset
+
+ void JustDied(Unit*) override
+ {
+ _JustDied();
+
+ if (instance->GetData(DATA_PRISONERS_EXECUTED) > 0)
+ return;
+
+ Map::PlayerList const &players = instance->instance->GetPlayers();
+ for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
+ {
+ Player* pl = itr->GetSource();
+ uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
+ if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE)
+ pl->CompleteQuest(qId);
+ }
+ }
+
+ void SetData(uint32 type, uint32 data) override
+ {
+ if (type == DATA_PRISONERS_EXECUTED && data <= 3)
+ {
+ if (Creature* victim = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FIRST_PRISONER + data - 1)))
+ me->Kill(victim);
+
+ if (data == 1)
+ {
+ Map::PlayerList const &players = instance->instance->GetPlayers();
+ for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
+ {
+ Player* pl = itr->GetSource();
+ uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
+ if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE)
+ pl->FailQuest(qId);
+ }
+ }
+
+ switch (data)
+ {
+ case 3:
+ me->RemoveLootMode(LOOT_MODE_HARD_MODE_1);
+ case 2:
+ me->RemoveLootMode(LOOT_MODE_HARD_MODE_2);
+ case 1:
+ me->RemoveLootMode(LOOT_MODE_HARD_MODE_3);
+ default:
+ break;
+ }
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ if (cleaveTimer <= diff)
+ {
+ DoCast(SPELL_CLEAVE);
+ cleaveTimer = urand(5000, 7000);
+ }
+ else
+ cleaveTimer -= diff;
+
+ DoMeleeAttackIfReady();
+ }
+ private:
+ uint32 cleaveTimer;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_shattered_executionerAI>(creature);
+ }
+};
+
+class spell_kargath_executioner : public SpellScriptLoader
+{
+ public:
+ spell_kargath_executioner() : SpellScriptLoader("spell_kargath_executioner") { }
+
+ class spell_kargath_executioner_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_kargath_executioner_AuraScript);
+
+ bool AreaCheck(Unit* target)
+ {
+ if (target->GetMap()->GetId() != 540)
+ return false;
+
+ return true;
+ }
+
+ bool Load() override
+ {
+ return GetCaster()->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void Register() override
+ {
+ DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_kargath_executioner_AuraScript::AreaCheck);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_kargath_executioner_AuraScript();
+ }
+};
+
+class spell_remove_kargath_executioner : public SpellScriptLoader
+{
+ public:
+ spell_remove_kargath_executioner() : SpellScriptLoader("spell_remove_kargath_executioner") { }
+
+ class spell_remove_kargath_executioner_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_remove_kargath_executioner_SpellScript);
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Unit* target = GetCaster();
+
+ target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_1);
+ target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_2);
+ target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_3);
+ }
+
+ bool Load() override
+ {
+ return GetCaster()->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_remove_kargath_executioner_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_remove_kargath_executioner_SpellScript();
+ }
+};
+
+void AddSC_shattered_halls()
+{
+ new at_nethekurse_exit();
+ new boss_shattered_executioner();
+ new spell_kargath_executioner();
+ new spell_remove_kargath_executioner();
+}
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
index adc07bec2ff..894cc9c40a6 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
@@ -33,7 +33,11 @@ enum DataTypes
DATA_SHATTERED_EXECUTIONER = 3,
DATA_PRISONERS_EXECUTED = 4,
- DATA_TEAM_IN_INSTANCE = 5
+ DATA_TEAM_IN_INSTANCE = 5,
+
+ DATA_FIRST_PRISONER,
+ DATA_SECOND_PRISONER,
+ DATA_THIRD_PRISONER
};
enum CreatureIds
@@ -70,6 +74,20 @@ enum QuestIds
QUEST_IMPRISONED_H = 9525
};
+enum InstanceSpells
+{
+ SPELL_KARGATH_EXECUTIONER_1 = 39288,
+ SPELL_KARGATH_EXECUTIONER_2 = 39289,
+ SPELL_KARGATH_EXECUTIONER_3 = 39290,
+
+ SPELL_REMOVE_KARGATH_EXECUTIONER = 39291
+};
+
+enum Actions
+{
+ ACTION_EXECUTIONER_TAUNT = 1
+};
+
const Position Executioner = { 152.8524f, -83.63912f, 2.021005f, 0.06981317f };
struct FactionSpawnerHelper
@@ -77,7 +95,7 @@ struct FactionSpawnerHelper
FactionSpawnerHelper(uint32 allianceEntry, uint32 hordeEntry, const Position& pos) : _allianceNPC(allianceEntry), _hordeNPC(hordeEntry), _spawnPos(pos) { }
inline uint32 operator()(uint32 teamID) const { return teamID == ALLIANCE ? _allianceNPC : _hordeNPC; }
- inline const Position GetPos() const { return _spawnPos; }
+ inline Position const& GetPos() const { return _spawnPos; }
private:
const uint32 _allianceNPC;
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp
index cc825afd3a0..48508aa4790 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp
@@ -77,12 +77,11 @@ class boss_alar : public CreatureScript
public:
boss_alar() : CreatureScript("boss_alar") { }
- struct boss_alarAI : public ScriptedAI
+ struct boss_alarAI : public BossAI
{
- boss_alarAI(Creature* creature) : ScriptedAI(creature)
+ boss_alarAI(Creature* creature) : BossAI(creature, DATA_ALAR)
{
Initialize();
- instance = creature->GetInstanceScript();
DefaultMoveSpeedRate = creature->GetSpeedRate(MOVE_RUN);
DiveBomb_Timer = 0;
MeltArmor_Timer = 0;
@@ -105,8 +104,6 @@ class boss_alar : public CreatureScript
cur_wp = 4;
}
- InstanceScript* instance;
-
WaitEventType WaitEvent;
uint32 WaitTimer;
@@ -129,9 +126,8 @@ class boss_alar : public CreatureScript
void Reset() override
{
- instance->SetData(DATA_ALAREVENT, NOT_STARTED);
-
Initialize();
+ _Reset();
me->SetDisplayId(me->GetNativeDisplayId());
me->SetSpeed(MOVE_RUN, DefaultMoveSpeedRate);
@@ -145,18 +141,11 @@ class boss_alar : public CreatureScript
void EnterCombat(Unit* /*who*/) override
{
- instance->SetData(DATA_ALAREVENT, IN_PROGRESS);
-
+ _EnterCombat();
me->SetDisableGravity(true); // after enterevademode will be set walk movement
- DoZoneInCombat();
me->setActive(true);
}
- void JustDied(Unit* /*killer*/) override
- {
- instance->SetData(DATA_ALAREVENT, DONE);
- }
-
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() == CREATURE_EMBER_OF_ALAR)
@@ -508,7 +497,7 @@ class npc_ember_of_alar : public CreatureScript
DoCast(me, SPELL_EMBER_BLAST, true);
me->SetDisplayId(11686);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- if (instance->GetData(DATA_ALAREVENT) == 2)
+ if (instance->GetBossState(DATA_ALAR) == IN_PROGRESS)
{
if (Unit* Alar = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_ALAR)))
{
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp
index 6021e38d3cf..ff9bdf15276 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp
@@ -92,17 +92,13 @@ class boss_high_astromancer_solarian : public CreatureScript
{
public:
- boss_high_astromancer_solarian()
- : CreatureScript("boss_high_astromancer_solarian")
- {
- }
+ boss_high_astromancer_solarian() : CreatureScript("boss_high_astromancer_solarian") { }
- struct boss_high_astromancer_solarianAI : public ScriptedAI
+ struct boss_high_astromancer_solarianAI : public BossAI
{
- boss_high_astromancer_solarianAI(Creature* creature) : ScriptedAI(creature), Summons(me)
+ boss_high_astromancer_solarianAI(Creature* creature) : BossAI(creature, DATA_HIGH_ASTROMANCER_SOLARIAN)
{
Initialize();
- instance = creature->GetInstanceScript();
defaultarmor = creature->GetArmor();
defaultsize = creature->GetObjectScale();
@@ -126,9 +122,6 @@ class boss_high_astromancer_solarian : public CreatureScript
Phase = 1;
}
- InstanceScript* instance;
- SummonList Summons;
-
uint8 Phase;
uint32 ArcaneMissiles_Timer;
@@ -152,16 +145,13 @@ class boss_high_astromancer_solarian : public CreatureScript
void Reset() override
{
Initialize();
-
- instance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, NOT_STARTED);
-
+ _Reset();
me->SetArmor(defaultarmor);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetVisible(true);
me->SetObjectScale(defaultsize);
me->SetDisplayId(MODEL_HUMAN);
- Summons.DespawnAll();
}
void KilledUnit(Unit* /*victim*/) override
@@ -174,15 +164,13 @@ class boss_high_astromancer_solarian : public CreatureScript
me->SetObjectScale(defaultsize);
me->SetDisplayId(MODEL_HUMAN);
Talk(SAY_DEATH);
- instance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, DONE);
+ _JustDied();
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
- DoZoneInCombat();
-
- instance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, IN_PROGRESS);
+ _EnterCombat();
}
void SummonMinion(uint32 entry, float x, float y, float z)
@@ -193,7 +181,7 @@ class boss_high_astromancer_solarian : public CreatureScript
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
Summoned->AI()->AttackStart(target);
- Summons.Summon(Summoned);
+ summons.Summon(Summoned);
}
}
@@ -431,10 +419,7 @@ class npc_solarium_priest : public CreatureScript
{
public:
- npc_solarium_priest()
- : CreatureScript("npc_solarium_priest")
- {
- }
+ npc_solarium_priest() : CreatureScript("npc_solarium_priest") { }
struct npc_solarium_priestAI : public ScriptedAI
{
@@ -462,9 +447,7 @@ class npc_solarium_priest : public CreatureScript
Initialize();
}
- void EnterCombat(Unit* /*who*/) override
- {
- }
+ void EnterCombat(Unit* /*who*/) override { }
void UpdateAI(uint32 diff) override
{
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
index 9aa1981eabb..f5583c0bc53 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
@@ -286,17 +286,13 @@ class boss_kaelthas : public CreatureScript
{
public:
- boss_kaelthas()
- : CreatureScript("boss_kaelthas")
- {
- }
- //Kael'thas AI
- struct boss_kaelthasAI : public ScriptedAI
+ boss_kaelthas() : CreatureScript("boss_kaelthas") { }
+
+ struct boss_kaelthasAI : public BossAI
{
- boss_kaelthasAI(Creature* creature) : ScriptedAI(creature), summons(me)
+ boss_kaelthasAI(Creature* creature) : BossAI(creature, DATA_KAELTHAS)
{
Initialize();
- instance = creature->GetInstanceScript();
PhaseSubphase = 0;
Phase_Timer = 0;
}
@@ -320,8 +316,6 @@ class boss_kaelthas : public CreatureScript
ChainPyros = false;
}
- InstanceScript* instance;
-
uint32 Fireball_Timer;
uint32 ArcaneDisruption_Timer;
uint32 Phoenix_Timer;
@@ -341,8 +335,6 @@ class boss_kaelthas : public CreatureScript
bool IsCastingFireball;
bool ChainPyros;
- SummonList summons;
-
ObjectGuid m_auiAdvisorGuid[MAX_ADVISORS];
void Reset() override
@@ -351,8 +343,8 @@ class boss_kaelthas : public CreatureScript
if (me->IsInCombat())
PrepareAdvisors();
-
- summons.DespawnAll();
+
+ _Reset();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
@@ -413,7 +405,6 @@ class boss_kaelthas : public CreatureScript
}
void MoveInLineOfSight(Unit* who) override
-
{
if (!me->HasUnitState(UNIT_STATE_STUNNED) && me->CanCreatureAttack(who))
{
@@ -444,6 +435,8 @@ class boss_kaelthas : public CreatureScript
{
if (!instance->GetData(DATA_KAELTHASEVENT) && !Phase)
StartEvent();
+
+ instance->SetBossState(DATA_KAELTHAS, IN_PROGRESS);
}
void KilledUnit(Unit* /*victim*/) override
@@ -463,11 +456,6 @@ class boss_kaelthas : public CreatureScript
}
}
- void SummonedCreatureDespawn(Creature* summon) override
- {
- summons.Despawn(summon);
- }
-
void JustDied(Unit* /*killer*/) override
{
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
@@ -475,8 +463,6 @@ class boss_kaelthas : public CreatureScript
Talk(SAY_DEATH);
- summons.DespawnAll();
-
instance->SetData(DATA_KAELTHASEVENT, 0);
for (uint8 i = 0; i < MAX_ADVISORS; ++i)
@@ -484,6 +470,7 @@ class boss_kaelthas : public CreatureScript
if (Unit* pAdvisor = ObjectAccessor::GetUnit(*me, m_auiAdvisorGuid[i]))
pAdvisor->Kill(pAdvisor);
}
+ _JustDied();
}
void UpdateAI(uint32 diff) override
@@ -1024,10 +1011,8 @@ class boss_thaladred_the_darkener : public CreatureScript
{
public:
- boss_thaladred_the_darkener()
- : CreatureScript("boss_thaladred_the_darkener")
- {
- }
+ boss_thaladred_the_darkener() : CreatureScript("boss_thaladred_the_darkener") { }
+
struct boss_thaladred_the_darkenerAI : public advisorbase_ai
{
boss_thaladred_the_darkenerAI(Creature* creature) : advisorbase_ai(creature)
@@ -1130,10 +1115,8 @@ class boss_lord_sanguinar : public CreatureScript
{
public:
- boss_lord_sanguinar()
- : CreatureScript("boss_lord_sanguinar")
- {
- }
+ boss_lord_sanguinar() : CreatureScript("boss_lord_sanguinar") { }
+
struct boss_lord_sanguinarAI : public advisorbase_ai
{
boss_lord_sanguinarAI(Creature* creature) : advisorbase_ai(creature)
@@ -1205,10 +1188,8 @@ class boss_grand_astromancer_capernian : public CreatureScript
{
public:
- boss_grand_astromancer_capernian()
- : CreatureScript("boss_grand_astromancer_capernian")
- {
- }
+ boss_grand_astromancer_capernian() : CreatureScript("boss_grand_astromancer_capernian") { }
+
struct boss_grand_astromancer_capernianAI : public advisorbase_ai
{
boss_grand_astromancer_capernianAI(Creature* creature) : advisorbase_ai(creature)
@@ -1358,10 +1339,8 @@ class boss_master_engineer_telonicus : public CreatureScript
{
public:
- boss_master_engineer_telonicus()
- : CreatureScript("boss_master_engineer_telonicus")
- {
- }
+ boss_master_engineer_telonicus() : CreatureScript("boss_master_engineer_telonicus") { }
+
struct boss_master_engineer_telonicusAI : public advisorbase_ai
{
boss_master_engineer_telonicusAI(Creature* creature) : advisorbase_ai(creature)
@@ -1449,10 +1428,8 @@ class npc_kael_flamestrike : public CreatureScript
{
public:
- npc_kael_flamestrike()
- : CreatureScript("npc_kael_flamestrike")
- {
- }
+ npc_kael_flamestrike() : CreatureScript("npc_kael_flamestrike") { }
+
struct npc_kael_flamestrikeAI : public ScriptedAI
{
npc_kael_flamestrikeAI(Creature* creature) : ScriptedAI(creature)
@@ -1482,7 +1459,6 @@ class npc_kael_flamestrike : public CreatureScript
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void EnterCombat(Unit* /*who*/) override { }
void UpdateAI(uint32 diff) override
@@ -1523,10 +1499,8 @@ class npc_phoenix_tk : public CreatureScript
{
public:
- npc_phoenix_tk()
- : CreatureScript("npc_phoenix_tk")
- {
- }
+ npc_phoenix_tk() : CreatureScript("npc_phoenix_tk") { }
+
struct npc_phoenix_tkAI : public ScriptedAI
{
npc_phoenix_tkAI(Creature* creature) : ScriptedAI(creature)
@@ -1585,10 +1559,8 @@ class npc_phoenix_egg_tk : public CreatureScript
{
public:
- npc_phoenix_egg_tk()
- : CreatureScript("npc_phoenix_egg_tk")
- {
- }
+ npc_phoenix_egg_tk() : CreatureScript("npc_phoenix_egg_tk") { }
+
struct npc_phoenix_egg_tkAI : public ScriptedAI
{
npc_phoenix_egg_tkAI(Creature* creature) : ScriptedAI(creature)
@@ -1611,7 +1583,6 @@ class npc_phoenix_egg_tk : public CreatureScript
//ignore any
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void AttackStart(Unit* who) override
{
if (me->Attack(who, false))
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp
index 9186b491fa4..1aa7d5298e5 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp
@@ -47,17 +47,13 @@ class boss_void_reaver : public CreatureScript
{
public:
- boss_void_reaver()
- : CreatureScript("boss_void_reaver")
- {
- }
+ boss_void_reaver() : CreatureScript("boss_void_reaver") { }
- struct boss_void_reaverAI : public ScriptedAI
+ struct boss_void_reaverAI : public BossAI
{
- boss_void_reaverAI(Creature* creature) : ScriptedAI(creature)
+ boss_void_reaverAI(Creature* creature) : BossAI(creature, DATA_VOID_REAVER)
{
Initialize();
- instance = creature->GetInstanceScript();
}
void Initialize()
@@ -70,8 +66,6 @@ class boss_void_reaver : public CreatureScript
Enraged = false;
}
- InstanceScript* instance;
-
uint32 Pounding_Timer;
uint32 ArcaneOrb_Timer;
uint32 KnockAway_Timer;
@@ -82,9 +76,7 @@ class boss_void_reaver : public CreatureScript
void Reset() override
{
Initialize();
-
- if (me->IsAlive())
- instance->SetData(DATA_VOIDREAVEREVENT, NOT_STARTED);
+ _Reset();
}
void KilledUnit(Unit* /*victim*/) override
@@ -96,15 +88,13 @@ class boss_void_reaver : public CreatureScript
{
Talk(SAY_DEATH);
DoZoneInCombat();
-
- instance->SetData(DATA_VOIDREAVEREVENT, DONE);
+ _JustDied();
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
-
- instance->SetData(DATA_VOIDREAVEREVENT, IN_PROGRESS);
+ _EnterCombat();
}
void UpdateAI(uint32 diff) override
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp b/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp
index 38c9cdd487c..c421b9974ce 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp
@@ -27,8 +27,6 @@ EndScriptData */
#include "InstanceScript.h"
#include "the_eye.h"
-#define MAX_ENCOUNTER 5
-
/* The Eye encounters:
0 - Kael'thas event
1 - Al' ar event
@@ -39,20 +37,16 @@ EndScriptData */
class instance_the_eye : public InstanceMapScript
{
public:
- instance_the_eye()
- : InstanceMapScript("instance_the_eye", 550)
- {
- }
+ instance_the_eye() : InstanceMapScript("instance_the_eye", 550) { }
struct instance_the_eye_InstanceMapScript : public InstanceScript
{
instance_the_eye_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
- memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
+ SetBossNumber(EncounterCount);
KaelthasEventPhase = 0;
- AlarEventPhase = 0;
}
ObjectGuid ThaladredTheDarkener;
@@ -63,44 +57,34 @@ class instance_the_eye : public InstanceMapScript
ObjectGuid Astromancer;
ObjectGuid Alar;
uint8 KaelthasEventPhase;
- uint8 AlarEventPhase;
-
- uint32 m_auiEncounter[MAX_ENCOUNTER];
-
- bool IsEncounterInProgress() const override
- {
- for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- if (m_auiEncounter[i] == IN_PROGRESS)
- return true;
-
- return false;
- }
void OnCreatureCreate(Creature* creature) override
{
switch (creature->GetEntry())
{
- case 20064:
- ThaladredTheDarkener = creature->GetGUID();
- break;
- case 20063:
- MasterEngineerTelonicus = creature->GetGUID();
- break;
- case 20062:
- GrandAstromancerCapernian = creature->GetGUID();
- break;
- case 20060:
- LordSanguinar = creature->GetGUID();
- break;
- case 19622:
- Kaelthas = creature->GetGUID();
- break;
- case 18805:
- Astromancer = creature->GetGUID();
- break;
- case 19514:
- Alar = creature->GetGUID();
- break;
+ case NPC_SANGUINAR:
+ LordSanguinar = creature->GetGUID();
+ break;
+ case NPC_CAPERNIAN:
+ GrandAstromancerCapernian = creature->GetGUID();
+ break;
+ case NPC_TELONICUS:
+ MasterEngineerTelonicus = creature->GetGUID();
+ break;
+ case NPC_THALADRED:
+ ThaladredTheDarkener = creature->GetGUID();
+ break;
+ case NPC_KAELTHAS:
+ Kaelthas = creature->GetGUID();
+ break;
+ case NPC_HIGH_ASTROMANCER_SOLARIAN:
+ Astromancer = creature->GetGUID();
+ break;
+ case NPC_ALAR:
+ Alar = creature->GetGUID();
+ break;
+ default:
+ break;
}
}
@@ -113,7 +97,7 @@ class instance_the_eye : public InstanceMapScript
case DATA_GRANDASTROMANCERCAPERNIAN: return GrandAstromancerCapernian;
case DATA_MASTERENGINEERTELONICUS: return MasterEngineerTelonicus;
case DATA_KAELTHAS: return Kaelthas;
- case DATA_ASTROMANCER: return Astromancer;
+ case DATA_HIGH_ASTROMANCER_SOLARIAN: return Astromancer;
case DATA_ALAR: return Alar;
}
return ObjectGuid::Empty;
@@ -123,64 +107,23 @@ class instance_the_eye : public InstanceMapScript
{
switch (type)
{
- case DATA_ALAREVENT:
- AlarEventPhase = data;
- m_auiEncounter[0] = data;
- break;
- case DATA_HIGHASTROMANCERSOLARIANEVENT:
- m_auiEncounter[1] = data;
- break;
- case DATA_VOIDREAVEREVENT:
- m_auiEncounter[2] = data;
- break;
- case DATA_KAELTHASEVENT:
- KaelthasEventPhase = data;
- m_auiEncounter[3] = data;
- break;
+ case DATA_KAELTHASEVENT:
+ KaelthasEventPhase = data;
+ break;
+ default:
+ break;
}
- if (data == DONE)
- SaveToDB();
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
- case DATA_ALAREVENT: return AlarEventPhase;
- case DATA_HIGHASTROMANCERSOLARIANEVENT: return m_auiEncounter[1];
- case DATA_VOIDREAVEREVENT: return m_auiEncounter[2];
- case DATA_KAELTHASEVENT: return KaelthasEventPhase;
+ case DATA_KAELTHASEVENT:
+ return KaelthasEventPhase;
}
return 0;
}
-
- std::string GetSaveData() override
- {
- OUT_SAVE_INST_DATA;
-
- std::ostringstream stream;
- stream << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' ' << m_auiEncounter[2] << ' ' << m_auiEncounter[3];
-
- OUT_SAVE_INST_DATA_COMPLETE;
- return stream.str();
- }
-
- void Load(const char* in) override
- {
- if (!in)
- {
- OUT_LOAD_INST_DATA_FAIL;
- return;
- }
- OUT_LOAD_INST_DATA(in);
-
- std::istringstream stream(in);
- stream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3];
- for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- if (m_auiEncounter[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead.
- m_auiEncounter[i] = NOT_STARTED;
- OUT_LOAD_INST_DATA_COMPLETE;
- }
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h b/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h
index 718f37861d9..c46fe408274 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h
+++ b/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h
@@ -21,19 +21,33 @@
#define DataHeader "TE"
+uint32 const EncounterCount = 4;
+
enum DataTypes
{
- DATA_ALAREVENT = 1,
- DATA_ASTROMANCER = 2,
- DATA_GRANDASTROMANCERCAPERNIAN = 3,
- DATA_HIGHASTROMANCERSOLARIANEVENT = 4,
- DATA_KAELTHAS = 5,
+ // Encounter States/Boss GUIDs
+ DATA_KAELTHAS = 0,
+ DATA_ALAR = 1,
+ DATA_HIGH_ASTROMANCER_SOLARIAN = 2,
+ DATA_VOID_REAVER = 3,
+
+ DATA_ASTROMANCER = 4,
+ DATA_GRANDASTROMANCERCAPERNIAN = 5,
DATA_KAELTHASEVENT = 6,
DATA_LORDSANGUINAR = 7,
DATA_MASTERENGINEERTELONICUS = 8,
- DATA_THALADREDTHEDARKENER = 10,
- DATA_VOIDREAVEREVENT = 11,
- DATA_ALAR = 12
+ DATA_THALADREDTHEDARKENER = 9
+};
+
+enum CreatureIds
+{
+ NPC_SANGUINAR = 20060,
+ NPC_CAPERNIAN = 20062,
+ NPC_TELONICUS = 20063,
+ NPC_THALADRED = 20064,
+ NPC_KAELTHAS = 19622,
+ NPC_HIGH_ASTROMANCER_SOLARIAN = 18805,
+ NPC_ALAR = 19514
};
#endif
diff --git a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp
index 2a568a84a7c..d1a31906d58 100644
--- a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp
+++ b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp
@@ -420,10 +420,482 @@ public:
}
};
+enum ExorcismSpells
+{
+ SPELL_JULES_GOES_PRONE = 39283,
+ SPELL_JULES_THREATENS_AURA = 39284,
+ SPELL_JULES_GOES_UPRIGHT = 39294,
+ SPELL_JULES_VOMITS_AURA = 39295,
+
+ SPELL_BARADAS_COMMAND = 39277,
+ SPELL_BARADA_FALTERS = 39278,
+};
+
+enum ExorcismTexts
+{
+ SAY_BARADA_1 = 0,
+ SAY_BARADA_2 = 1,
+ SAY_BARADA_3 = 2,
+ SAY_BARADA_4 = 3,
+ SAY_BARADA_5 = 4,
+ SAY_BARADA_6 = 5,
+ SAY_BARADA_7 = 6,
+ SAY_BARADA_8 = 7,
+
+ SAY_JULES_1 = 0,
+ SAY_JULES_2 = 1,
+ SAY_JULES_3 = 2,
+ SAY_JULES_4 = 3,
+ SAY_JULES_5 = 4,
+};
+
+Position const exorcismPos[11] =
+{
+ { -707.123f, 2751.686f, 101.592f, 4.577416f }, //Barada Waypoint-1 0
+ { -710.731f, 2749.075f, 101.592f, 1.513286f }, //Barada Cast position 1
+ { -710.332f, 2754.394f, 102.948f, 3.207566f }, //Jules 2
+ { -714.261f, 2747.754f, 103.391f, 0.0f }, //Jules Waypoint-1 3
+ { -713.113f, 2750.194f, 103.391f, 0.0f }, //Jules Waypoint-2 4
+ { -710.385f, 2750.896f, 103.391f, 0.0f }, //Jules Waypoint-3 5
+ { -708.309f, 2750.062f, 103.391f, 0.0f }, //Jules Waypoint-4 6
+ { -707.401f, 2747.696f, 103.391f, 0.0f }, //Jules Waypoint-5 7
+ { -708.591f, 2745.266f, 103.391f, 0.0f }, //Jules Waypoint-6 8
+ { -710.597f, 2744.035f, 103.391f, 0.0f }, //Jules Waypoint-7 9
+ { -713.089f, 2745.302f, 103.391f, 0.0f }, //Jules Waypoint-8 10
+};
+
+enum ExorcismMisc
+{
+ NPC_DARKNESS_RELEASED = 22507,
+ NPC_FOUL_PURGE = 22506,
+ NPC_COLONEL_JULES = 22432,
+
+ BARADAS_GOSSIP_MESSAGE = 10683,
+
+ QUEST_THE_EXORCISM_OF_COLONEL_JULES = 10935,
+
+ ACTION_START_EVENT = 1,
+ ACTION_JULES_HOVER = 2,
+ ACTION_JULES_FLIGHT = 3,
+ ACTION_JULES_MOVE_HOME = 4,
+};
+
+enum ExorcismEvents
+{
+ EVENT_BARADAS_TALK = 1,
+
+ //Colonel Jules
+ EVENT_SUMMON_SKULL = 1,
+};
+
+/*######
+## npc_barada
+######*/
+
+class npc_barada : public CreatureScript
+{
+public:
+ npc_barada() : CreatureScript("npc_barada") { }
+
+ struct npc_baradaAI : public ScriptedAI
+ {
+ npc_baradaAI(Creature* creature) : ScriptedAI(creature)
+ {
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ step = 0;
+ }
+
+ void Reset() override
+ {
+ events.Reset();
+ Initialize();
+
+ playerGUID.Clear();
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
+ }
+
+ void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
+ {
+ player->PlayerTalkClass->ClearMenus();
+ switch (gossipListId)
+ {
+ case 1:
+ player->PlayerTalkClass->SendCloseGossip();
+ me->AI()->Talk(SAY_BARADA_1);
+ me->AI()->DoAction(ACTION_START_EVENT);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_START_EVENT)
+ {
+ if (Creature* jules = me->FindNearestCreature(NPC_COLONEL_JULES, 20.0f, true))
+ {
+ julesGUID = jules->GetGUID();
+ jules->AI()->Talk(SAY_JULES_1);
+ }
+
+ me->GetMotionMaster()->MovePoint(0, exorcismPos[1]);
+ Talk(SAY_BARADA_2);
+
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
+ }
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type != POINT_MOTION_TYPE)
+ return;
+
+ if (id == 0)
+ me->GetMotionMaster()->MovePoint(1, exorcismPos[1]);
+
+ if (id == 1)
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 2000);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ {
+ jules->AI()->DoAction(ACTION_JULES_MOVE_HOME);
+ jules->RemoveAllAuras();
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_BARADAS_TALK:
+ switch (step)
+ {
+ case 0:
+ me->SetFacingTo(1.513286f);
+
+ me->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 3000);
+ step++;
+ break;
+ case 1:
+ DoCast(SPELL_BARADAS_COMMAND);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 5000);
+ step++;
+ break;
+ case 2:
+ Talk(SAY_BARADA_3);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 7000);
+ step++;
+ break;
+ case 3:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_2);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 18000);
+ step++;
+ break;
+ case 4:
+ DoCast(SPELL_BARADA_FALTERS);
+ me->HandleEmoteCommand(EMOTE_STAND_STATE_NONE);
+
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->DoAction(ACTION_JULES_HOVER);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 11000);
+ step++;
+ break;
+ case 5:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_3);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 13000);
+ step++;
+ break;
+ case 6:
+ Talk(SAY_BARADA_4);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 5000);
+ step++;
+ break;
+ case 7:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_3);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 13000);
+ step++;
+ break;
+ case 8:
+ Talk(SAY_BARADA_4);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 12000);
+ step++;
+ break;
+ case 9:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_4);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 12000);
+ step++;
+ break;
+ case 10:
+ Talk(SAY_BARADA_4);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 5000);
+ step++;
+ break;
+ case 11:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->DoAction(ACTION_JULES_FLIGHT);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 12:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_4);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 8000);
+ step++;
+ break;
+ case 13:
+ Talk(SAY_BARADA_5);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 14:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_4);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 15:
+ Talk(SAY_BARADA_6);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 16:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_5);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 17:
+ Talk(SAY_BARADA_7);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 18:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_3);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 19:
+ Talk(SAY_BARADA_7);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 20:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ {
+ jules->AI()->DoAction(ACTION_JULES_MOVE_HOME);
+ jules->RemoveAura(SPELL_JULES_VOMITS_AURA);
+ }
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 21:
+ //End
+ if (Player* player = ObjectAccessor::FindPlayer(playerGUID))
+ player->KilledMonsterCredit(NPC_COLONEL_JULES, ObjectGuid::Empty);
+
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->RemoveAllAuras();
+
+ me->RemoveAura(SPELL_BARADAS_COMMAND);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
+
+ Talk(SAY_BARADA_8);
+ me->GetMotionMaster()->MoveTargetedHome();
+ EnterEvadeMode();
+ break;
+ }
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap events;
+ uint8 step;
+ ObjectGuid julesGUID;
+ ObjectGuid playerGUID;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_baradaAI(creature);
+ }
+};
+
+/*######
+## npc_colonel_jules
+######*/
+
+class npc_colonel_jules : public CreatureScript
+{
+public:
+ npc_colonel_jules() : CreatureScript("npc_colonel_jules") { }
+
+ struct npc_colonel_julesAI : public ScriptedAI
+ {
+ npc_colonel_julesAI(Creature* creature) : ScriptedAI(creature), summons(me)
+ {
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ circleRounds = 0;
+ point = 3;
+ wpreached = false;
+ }
+
+ void Reset() override
+ {
+ events.Reset();
+
+ summons.DespawnAll();
+ Initialize();
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_JULES_HOVER:
+ me->AddAura(SPELL_JULES_GOES_PRONE, me);
+ me->AddAura(SPELL_JULES_THREATENS_AURA, me);
+
+ me->SetCanFly(true);
+ me->SetSpeed(MOVE_RUN, 0.2f);
+
+ me->SetFacingTo(3.207566f);
+ me->GetMotionMaster()->MoveJump(exorcismPos[2], 2.0f, 2.0f);
+
+ events.ScheduleEvent(EVENT_SUMMON_SKULL, 10000);
+ break;
+ case ACTION_JULES_FLIGHT:
+ circleRounds++;
+
+ me->RemoveAura(SPELL_JULES_GOES_PRONE);
+
+ me->AddAura(SPELL_JULES_GOES_UPRIGHT, me);
+ me->AddAura(SPELL_JULES_VOMITS_AURA, me);
+
+ wpreached = true;
+ me->GetMotionMaster()->MovePoint(point, exorcismPos[point]);
+ break;
+ case ACTION_JULES_MOVE_HOME:
+ wpreached = false;
+ me->SetSpeed(MOVE_RUN, 1.0f);
+ me->GetMotionMaster()->MovePoint(11, exorcismPos[2]);
+
+ events.CancelEvent(EVENT_SUMMON_SKULL);
+ break;
+ }
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ summons.Summon(summon);
+ summon->GetMotionMaster()->MoveRandom(10.0f);
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type != POINT_MOTION_TYPE)
+ return;
+
+ if (id < 10)
+ wpreached = true;
+
+ if (id == 8)
+ {
+ for (uint8 i = 0; i < circleRounds; i++)
+ DoSummon(NPC_FOUL_PURGE, exorcismPos[8]);
+ }
+
+ if (id == 10)
+ {
+ wpreached = true;
+ point = 3;
+ circleRounds++;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (wpreached)
+ {
+ me->GetMotionMaster()->MovePoint(point, exorcismPos[point]);
+ point++;
+ wpreached = false;
+ }
+
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SUMMON_SKULL:
+ uint8 summonCount = urand(1,3);
+
+ for (uint8 i = 0; i < summonCount; i++)
+ me->SummonCreature(NPC_DARKNESS_RELEASED, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 1.5f, 0, TEMPSUMMON_MANUAL_DESPAWN);
+
+ events.ScheduleEvent(EVENT_SUMMON_SKULL, urand(10000, 15000));
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap events;
+ SummonList summons;
+
+ uint8 circleRounds;
+ uint8 point;
+
+ bool wpreached;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_colonel_julesAI(creature);
+ }
+};
+
void AddSC_hellfire_peninsula()
{
new npc_aeranas();
new npc_ancestral_wolf();
new npc_wounded_blood_elf();
new npc_fel_guard_hound();
+ new npc_barada();
+ new npc_colonel_jules();
}
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index 993e64f22dc..68c115f9faf 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -34,6 +34,7 @@
#include "Pet.h"
#include "ReputationMgr.h"
#include "SkillDiscovery.h"
+#include "SpellHistory.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
#include "Vehicle.h"
@@ -1293,8 +1294,8 @@ class spell_gen_divine_storm_cd_reset : public SpellScriptLoader
void HandleScript(SpellEffIndex /*effIndex*/)
{
Player* caster = GetCaster()->ToPlayer();
- if (caster->HasSpellCooldown(SPELL_DIVINE_STORM))
- caster->RemoveSpellCooldown(SPELL_DIVINE_STORM, true);
+ if (caster->GetSpellHistory()->HasCooldown(SPELL_DIVINE_STORM))
+ caster->GetSpellHistory()->ResetCooldown(SPELL_DIVINE_STORM, true);
}
void Register() override
@@ -3330,7 +3331,7 @@ class spell_pvp_trinket_wotf_shared_cd : public SpellScriptLoader
{
// This is only needed because spells cast from spell_linked_spell are triggered by default
// Spell::SendSpellCooldown() skips all spells with TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD
- GetCaster()->ToPlayer()->AddSpellAndCategoryCooldowns(GetSpellInfo(), GetCastItem() ? GetCastItem()->GetEntry() : 0, GetSpell());
+ GetCaster()->GetSpellHistory()->StartCooldown(GetSpellInfo(), 0, GetSpell());
}
void Register() override
diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp
index 3ee337f81d4..75df264360f 100644
--- a/src/server/scripts/Spells/spell_hunter.cpp
+++ b/src/server/scripts/Spells/spell_hunter.cpp
@@ -27,6 +27,7 @@
#include "CellImpl.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
+#include "SpellHistory.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
@@ -246,7 +247,7 @@ class spell_hun_chimera_shot : public SpellScriptLoader
if (spellId)
caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, true);
if (spellId == SPELL_HUNTER_CHIMERA_SHOT_SCORPID && caster->ToPlayer()) // Scorpid Sting - Add 1 minute cooldown
- caster->ToPlayer()->AddSpellCooldown(spellId, 0, uint32(time(NULL) + 60));
+ caster->GetSpellHistory()->AddCooldown(spellId, 0, std::chrono::minutes(1));
}
}
@@ -654,24 +655,20 @@ class spell_hun_readiness : public SpellScriptLoader
void HandleDummy(SpellEffIndex /*effIndex*/)
{
- Player* caster = GetCaster()->ToPlayer();
// immediately finishes the cooldown on your other Hunter abilities except Bestial Wrath
- const SpellCooldowns& cm = caster->ToPlayer()->GetSpellCooldownMap();
- for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
+ GetCaster()->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
+ SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
///! If spellId in cooldown map isn't valid, the above will return a null pointer.
- if (spellInfo &&
- spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER &&
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER &&
spellInfo->Id != SPELL_HUNTER_READINESS &&
spellInfo->Id != SPELL_HUNTER_BESTIAL_WRATH &&
spellInfo->Id != SPELL_DRAENEI_GIFT_OF_THE_NAARU &&
spellInfo->GetRecoveryTime() > 0)
- caster->RemoveSpellCooldown((itr++)->first, true);
- else
- ++itr;
- }
+ return true;
+ return false;
+ }, true);
}
void Register() override
diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp
index b290cb75a2b..717382a0e36 100644
--- a/src/server/scripts/Spells/spell_item.cpp
+++ b/src/server/scripts/Spells/spell_item.cpp
@@ -24,6 +24,7 @@
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellHistory.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
#include "SkillDiscovery.h"
@@ -1349,7 +1350,7 @@ class spell_item_red_rider_air_rifle : public SpellScriptLoader
caster->CastSpell(caster, SPELL_AIR_RIFLE_HOLD_VISUAL, true);
// needed because this spell shares GCD with its triggered spells (which must not be cast with triggered flag)
if (Player* player = caster->ToPlayer())
- player->GetGlobalCooldownMgr().CancelGlobalCooldown(GetSpellInfo());
+ player->GetSpellHistory()->CancelGlobalCooldown(GetSpellInfo());
if (urand(0, 4))
caster->CastSpell(target, SPELL_AIR_RIFLE_SHOOT, false);
else
@@ -2368,7 +2369,7 @@ class spell_item_rocket_boots : public SpellScriptLoader
if (Battleground* bg = caster->GetBattleground())
bg->EventPlayerDroppedFlag(caster);
- caster->RemoveSpellCooldown(SPELL_ROCKET_BOOTS_PROC);
+ caster->GetSpellHistory()->ResetCooldown(SPELL_ROCKET_BOOTS_PROC);
caster->CastSpell(caster, SPELL_ROCKET_BOOTS_PROC, true, NULL);
}
@@ -2548,14 +2549,14 @@ class spell_item_refocus : public SpellScriptLoader
if (!caster || caster->getClass() != CLASS_HUNTER)
return;
- if (caster->HasSpellCooldown(SPELL_AIMED_SHOT))
- caster->RemoveSpellCooldown(SPELL_AIMED_SHOT, true);
+ if (caster->GetSpellHistory()->HasCooldown(SPELL_AIMED_SHOT))
+ caster->GetSpellHistory()->ResetCooldown(SPELL_AIMED_SHOT, true);
- if (caster->HasSpellCooldown(SPELL_MULTISHOT))
- caster->RemoveSpellCooldown(SPELL_MULTISHOT, true);
+ if (caster->GetSpellHistory()->HasCooldown(SPELL_MULTISHOT))
+ caster->GetSpellHistory()->ResetCooldown(SPELL_MULTISHOT, true);
- if (caster->HasSpellCooldown(SPELL_VOLLEY))
- caster->RemoveSpellCooldown(SPELL_VOLLEY, true);
+ if (caster->GetSpellHistory()->HasCooldown(SPELL_VOLLEY))
+ caster->GetSpellHistory()->ResetCooldown(SPELL_VOLLEY, true);
}
void Register() override
diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp
index ba9f66d255b..4edbf8822f7 100644
--- a/src/server/scripts/Spells/spell_mage.cpp
+++ b/src/server/scripts/Spells/spell_mage.cpp
@@ -23,6 +23,7 @@
#include "Player.h"
#include "ScriptMgr.h"
+#include "SpellHistory.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
@@ -171,22 +172,12 @@ class spell_mage_cold_snap : public SpellScriptLoader
void HandleDummy(SpellEffIndex /*effIndex*/)
{
- Player* caster = GetCaster()->ToPlayer();
- // immediately finishes the cooldown on Frost spells
- const SpellCooldowns& cm = caster->GetSpellCooldownMap();
- for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
+ GetCaster()->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
{
SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
-
- if (spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
- (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) &&
- spellInfo->Id != SPELL_MAGE_COLD_SNAP && spellInfo->GetRecoveryTime() > 0)
- {
- caster->RemoveSpellCooldown((itr++)->first, true);
- }
- else
- ++itr;
- }
+ return spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) &&
+ spellInfo->Id != SPELL_MAGE_COLD_SNAP && spellInfo->GetRecoveryTime() > 0;
+ }, true);
}
void Register() override
diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp
index cf320a05346..197d55486a8 100644
--- a/src/server/scripts/Spells/spell_paladin.cpp
+++ b/src/server/scripts/Spells/spell_paladin.cpp
@@ -25,6 +25,7 @@
#include "ScriptMgr.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
+#include "SpellHistory.h"
#include "Group.h"
enum PaladinSpells
@@ -133,7 +134,7 @@ class spell_pal_ardent_defender : public SpellScriptLoader
int32 remainingHealth = victim->GetHealth() - dmgInfo.GetDamage();
uint32 allowedHealth = victim->CountPctFromMaxHealth(35);
// If damage kills us
- if (remainingHealth <= 0 && !victim->ToPlayer()->HasSpellCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL))
+ if (remainingHealth <= 0 && !victim->GetSpellHistory()->HasCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL))
{
// Cast healing spell, completely avoid damage
absorbAmount = dmgInfo.GetDamage();
@@ -148,7 +149,7 @@ class spell_pal_ardent_defender : public SpellScriptLoader
int32 healAmount = int32(victim->CountPctFromMaxHealth(uint32(healPct * pctFromDefense)));
victim->CastCustomSpell(victim, PAL_SPELL_ARDENT_DEFENDER_HEAL, &healAmount, NULL, NULL, true, NULL, aurEff);
- victim->ToPlayer()->AddSpellCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL, 0, time(NULL) + 120);
+ victim->GetSpellHistory()->AddCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL, 0, std::chrono::minutes(2));
}
else if (remainingHealth < int32(allowedHealth))
{
diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp
index d98ef2ec799..60ff67d74c0 100644
--- a/src/server/scripts/Spells/spell_quest.cpp
+++ b/src/server/scripts/Spells/spell_quest.cpp
@@ -208,22 +208,23 @@ class spell_q6124_6129_apply_salve : public SpellScriptLoader
if (GetCastItem())
if (Creature* creatureTarget = GetHitCreature())
{
- uint32 uiNewEntry = 0;
+ uint32 newEntry = 0;
switch (caster->GetTeam())
{
case HORDE:
if (creatureTarget->GetEntry() == NPC_SICKLY_GAZELLE)
- uiNewEntry = NPC_CURED_GAZELLE;
+ newEntry = NPC_CURED_GAZELLE;
break;
case ALLIANCE:
if (creatureTarget->GetEntry() == NPC_SICKLY_DEER)
- uiNewEntry = NPC_CURED_DEER;
+ newEntry = NPC_CURED_DEER;
break;
}
- if (uiNewEntry)
+ if (newEntry)
{
- creatureTarget->UpdateEntry(uiNewEntry);
+ creatureTarget->UpdateEntry(newEntry);
creatureTarget->DespawnOrUnsummon(DESPAWN_TIME);
+ caster->KilledMonsterCredit(newEntry);
}
}
}
@@ -338,7 +339,7 @@ class spell_q11396_11399_scourging_crystal_controller : public SpellScriptLoader
SpellScript* GetSpellScript() const override
{
return new spell_q11396_11399_scourging_crystal_controller_SpellScript();
- };
+ }
};
// 43882 Scourging Crystal Controller Dummy
@@ -374,7 +375,7 @@ class spell_q11396_11399_scourging_crystal_controller_dummy : public SpellScript
SpellScript* GetSpellScript() const override
{
return new spell_q11396_11399_scourging_crystal_controller_dummy_SpellScript();
- };
+ }
};
// http://www.wowhead.com/quest=11515 Blood for Blood
@@ -855,7 +856,7 @@ class spell_symbol_of_life_dummy : public SpellScriptLoader
SpellScript* GetSpellScript() const override
{
return new spell_symbol_of_life_dummy_SpellScript();
- };
+ }
};
// http://www.wowhead.com/quest=12659 Scalps!
@@ -898,7 +899,7 @@ class spell_q12659_ahunaes_knife : public SpellScriptLoader
SpellScript* GetSpellScript() const override
{
return new spell_q12659_ahunaes_knife_SpellScript();
- };
+ }
};
enum StoppingTheSpread
@@ -944,7 +945,7 @@ class spell_q9874_liquid_fire : public SpellScriptLoader
SpellScript* GetSpellScript() const override
{
return new spell_q9874_liquid_fire_SpellScript();
- };
+ }
};
enum SalvagingLifesStength
@@ -988,7 +989,7 @@ class spell_q12805_lifeblood_dummy : public SpellScriptLoader
SpellScript* GetSpellScript() const override
{
return new spell_q12805_lifeblood_dummy_SpellScript();
- };
+ }
};
/*
diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp
index edb5cd5260c..da50f471f1c 100644
--- a/src/server/scripts/Spells/spell_rogue.cpp
+++ b/src/server/scripts/Spells/spell_rogue.cpp
@@ -25,6 +25,7 @@
#include "ScriptMgr.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
+#include "SpellHistory.h"
#include "Containers.h"
enum RogueSpells
@@ -139,11 +140,11 @@ class spell_rog_cheat_death : public SpellScriptLoader
void Absorb(AuraEffect* /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount)
{
Player* target = GetTarget()->ToPlayer();
- if (dmgInfo.GetDamage() < target->GetHealth() || target->HasSpellCooldown(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN) || !roll_chance_i(absorbChance))
+ if (dmgInfo.GetDamage() < target->GetHealth() || target->GetSpellHistory()->HasCooldown(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN) || !roll_chance_i(absorbChance))
return;
target->CastSpell(target, SPELL_ROGUE_CHEAT_DEATH_COOLDOWN, true);
- target->AddSpellCooldown(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN, 0, time(NULL) + 60);
+ target->GetSpellHistory()->AddCooldown(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN, 0, std::chrono::minutes(1));
uint32 health10 = target->CountPctFromMaxHealth(10);
@@ -443,35 +444,21 @@ class spell_rog_preparation : public SpellScriptLoader
void HandleDummy(SpellEffIndex /*effIndex*/)
{
- Player* caster = GetCaster()->ToPlayer();
-
- //immediately finishes the cooldown on certain Rogue abilities
- const SpellCooldowns& cm = caster->GetSpellCooldownMap();
- for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
+ Unit* caster = GetCaster();
+ caster->GetSpellHistory()->ResetCooldowns([caster](SpellHistory::CooldownStorageType::iterator itr) -> bool
{
SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
-
- if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE)
- {
- if (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_COLDB_SHADOWSTEP || // Cold Blood, Shadowstep
- spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VAN_EVAS_SPRINT) // Vanish, Evasion, Sprint
- caster->RemoveSpellCooldown((itr++)->first, true);
- else if (caster->HasAura(SPELL_ROGUE_GLYPH_OF_PREPARATION))
- {
- if (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_DISMANTLE || // Dismantle
- spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_KICK || // Kick
- (spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_BLADE_FLURRY && // Blade Flurry
- spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_BLADE_FLURRY))
- caster->RemoveSpellCooldown((itr++)->first, true);
- else
- ++itr;
- }
- else
- ++itr;
- }
- else
- ++itr;
- }
+ if (spellInfo->SpellFamilyName != SPELLFAMILY_ROGUE)
+ return false;
+
+ return (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_COLDB_SHADOWSTEP || // Cold Blood, Shadowstep
+ spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VAN_EVAS_SPRINT) || // Vanish, Evasion, Sprint
+ (caster->HasAura(SPELL_ROGUE_GLYPH_OF_PREPARATION) &&
+ (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_DISMANTLE || // Dismantle
+ spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_KICK || // Kick
+ (spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_BLADE_FLURRY && // Blade Flurry
+ spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_BLADE_FLURRY)));
+ }, true);
}
void Register() override
diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp
index 2ee0d5091b5..5564a8275c8 100644
--- a/src/server/scripts/Spells/spell_shaman.cpp
+++ b/src/server/scripts/Spells/spell_shaman.cpp
@@ -25,6 +25,7 @@
#include "ScriptMgr.h"
#include "GridNotifiers.h"
#include "Unit.h"
+#include "SpellHistory.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
@@ -338,7 +339,7 @@ class spell_sha_earth_shield : public SpellScriptLoader
{
//! HACK due to currenct proc system implementation
if (Player* player = GetTarget()->ToPlayer())
- if (player->HasSpellCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL))
+ if (player->GetSpellHistory()->HasCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL))
return false;
return true;
}
@@ -351,7 +352,7 @@ class spell_sha_earth_shield : public SpellScriptLoader
/// @hack: due to currenct proc system implementation
if (Player* player = GetTarget()->ToPlayer())
- player->AddSpellCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL, 0, time(NULL) + 3);
+ player->GetSpellHistory()->AddCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL, 0, std::chrono::seconds(3));
}
void Register() override
@@ -804,7 +805,7 @@ class spell_sha_item_t10_elemental_2p_bonus : public SpellScriptLoader
{
PreventDefaultAction();
if (Player* target = GetTarget()->ToPlayer())
- target->ModifySpellCooldown(SPELL_SHAMAN_ELEMENTAL_MASTERY, -aurEff->GetAmount());
+ target->GetSpellHistory()->ModifyCooldown(SPELL_SHAMAN_ELEMENTAL_MASTERY, -aurEff->GetAmount());
}
void Register() override
diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp
index fa2b323e220..c7839a59608 100644
--- a/src/server/scripts/Spells/spell_warrior.cpp
+++ b/src/server/scripts/Spells/spell_warrior.cpp
@@ -23,6 +23,7 @@
#include "Player.h"
#include "ScriptMgr.h"
+#include "SpellHistory.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
@@ -847,7 +848,7 @@ class spell_warr_vigilance_trigger : public SpellScriptLoader
// Remove Taunt cooldown
if (Player* target = GetHitPlayer())
- target->RemoveSpellCooldown(SPELL_WARRIOR_TAUNT, true);
+ target->GetSpellHistory()->ResetCooldown(SPELL_WARRIOR_TAUNT, true);
}
void Register() override
diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp
index 93010f06283..d1d2ddc8a80 100644
--- a/src/server/scripts/World/npcs_special.cpp
+++ b/src/server/scripts/World/npcs_special.cpp
@@ -53,6 +53,7 @@ EndContentData */
#include "GridNotifiersImpl.h"
#include "Cell.h"
#include "CellImpl.h"
+#include "SpellHistory.h"
#include "SpellAuras.h"
#include "Pet.h"
#include "CreatureTextMgr.h"
@@ -1214,14 +1215,14 @@ public:
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
- if (player->HasSpellCooldown(SPELL_INT) ||
- player->HasSpellCooldown(SPELL_ARM) ||
- player->HasSpellCooldown(SPELL_DMG) ||
- player->HasSpellCooldown(SPELL_RES) ||
- player->HasSpellCooldown(SPELL_STR) ||
- player->HasSpellCooldown(SPELL_AGI) ||
- player->HasSpellCooldown(SPELL_STM) ||
- player->HasSpellCooldown(SPELL_SPI))
+ if (player->GetSpellHistory()->HasCooldown(SPELL_INT) ||
+ player->GetSpellHistory()->HasCooldown(SPELL_ARM) ||
+ player->GetSpellHistory()->HasCooldown(SPELL_DMG) ||
+ player->GetSpellHistory()->HasCooldown(SPELL_RES) ||
+ player->GetSpellHistory()->HasCooldown(SPELL_STR) ||
+ player->GetSpellHistory()->HasCooldown(SPELL_AGI) ||
+ player->GetSpellHistory()->HasCooldown(SPELL_STM) ||
+ player->GetSpellHistory()->HasCooldown(SPELL_SPI))
player->SEND_GOSSIP_MENU(7393, creature->GetGUID());
else
{
@@ -1281,52 +1282,44 @@ public:
bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) override
{
player->PlayerTalkClass->ClearMenus();
+ uint32 spellId = 0;
switch (sender)
{
case GOSSIP_SENDER_MAIN:
SendAction(player, creature, action);
break;
case GOSSIP_SENDER_MAIN + 1:
- creature->CastSpell(player, SPELL_DMG, false);
- player->AddSpellCooldown(SPELL_DMG, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_DMG;
break;
case GOSSIP_SENDER_MAIN + 2:
- creature->CastSpell(player, SPELL_RES, false);
- player->AddSpellCooldown(SPELL_RES, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_RES;
break;
case GOSSIP_SENDER_MAIN + 3:
- creature->CastSpell(player, SPELL_ARM, false);
- player->AddSpellCooldown(SPELL_ARM, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_ARM;
break;
case GOSSIP_SENDER_MAIN + 4:
- creature->CastSpell(player, SPELL_SPI, false);
- player->AddSpellCooldown(SPELL_SPI, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_SPI;
break;
case GOSSIP_SENDER_MAIN + 5:
- creature->CastSpell(player, SPELL_INT, false);
- player->AddSpellCooldown(SPELL_INT, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_INT;
break;
case GOSSIP_SENDER_MAIN + 6:
- creature->CastSpell(player, SPELL_STM, false);
- player->AddSpellCooldown(SPELL_STM, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_STM;
break;
case GOSSIP_SENDER_MAIN + 7:
- creature->CastSpell(player, SPELL_STR, false);
- player->AddSpellCooldown(SPELL_STR, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_STR;
break;
case GOSSIP_SENDER_MAIN + 8:
- creature->CastSpell(player, SPELL_AGI, false);
- player->AddSpellCooldown(SPELL_AGI, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_AGI;
break;
}
+
+ if (spellId)
+ {
+ creature->CastSpell(player, spellId, false);
+ player->GetSpellHistory()->AddCooldown(spellId, 0, std::chrono::hours(2));
+ SendAction(player, creature, action);
+ }
return true;
}
};
diff --git a/src/server/shared/Cryptography/SHA1.h b/src/server/shared/Cryptography/SHA1.h
index ebd9f721d4a..f59bdc25556 100644
--- a/src/server/shared/Cryptography/SHA1.h
+++ b/src/server/shared/Cryptography/SHA1.h
@@ -39,8 +39,8 @@ class SHA1Hash
void Initialize();
void Finalize();
- uint8 *GetDigest(void) { return mDigest; };
- int GetLength(void) const { return SHA_DIGEST_LENGTH; };
+ uint8 *GetDigest(void) { return mDigest; }
+ int GetLength(void) const { return SHA_DIGEST_LENGTH; }
private:
SHA_CTX mC;
diff --git a/src/server/shared/Database/Field.h b/src/server/shared/Database/Field.h
index b88fb56cb06..1bbd264482f 100644
--- a/src/server/shared/Database/Field.h
+++ b/src/server/shared/Database/Field.h
@@ -255,11 +255,7 @@ class Field
Field();
~Field();
- #if defined(__GNUC__)
- #pragma pack(1)
- #else
#pragma pack(push, 1)
- #endif
struct
{
uint32 length; // Length (prepared strings only)
@@ -267,11 +263,7 @@ class Field
enum_field_types type; // Field type
bool raw; // Raw bytes? (Prepared statement or ad hoc)
} data;
- #if defined(__GNUC__)
- #pragma pack()
- #else
#pragma pack(pop)
- #endif
void SetByteValue(void const* newValue, size_t const newSize, enum_field_types newType, uint32 length);
void SetStructuredValue(char* newValue, enum_field_types newType);
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
index c8632b8a3c2..1ca01501d01 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
@@ -105,7 +105,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_MAIL_COUNT, "SELECT COUNT(*) FROM mail WHERE receiver = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHARACTER_SOCIALLIST, "SELECT friend, flags, note FROM character_social JOIN characters ON characters.guid = character_social.friend WHERE character_social.guid = ? AND deleteinfos_name IS NULL LIMIT 255", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ FROM character_homebind WHERE guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, "SELECT spell, item, time FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, "SELECT spell, item, time FROM character_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_GUILD_MEMBER, "SELECT guildid, rank FROM guild_member WHERE guid = ?", CONNECTION_BOTH);
PrepareStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED, "SELECT g.guildid, g.name, gr.rname, gr.rid, gm.pnote, gm.offnote "
@@ -497,7 +497,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_UPD_CHAR_REP_FACTION_CHANGE, "UPDATE character_reputation SET faction = ?, standing = ? WHERE faction = ? AND guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHAR_TITLES_FACTION_CHANGE, "UPDATE characters SET knownTitles = ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_RES_CHAR_TITLES_FACTION_CHANGE, "UPDATE characters SET chosenTitle = 0 WHERE guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN, "DELETE FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_CHAR_SPELL_COOLDOWNS, "DELETE FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_CHAR_SPELL_COOLDOWN, "INSERT INTO character_spell_cooldown (guid, spell, item, time) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHARACTER, "DELETE FROM characters WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_ACTION, "DELETE FROM character_action WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_AURA, "DELETE FROM character_aura WHERE guid = ?", CONNECTION_ASYNC);
@@ -577,7 +578,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_INS_CHAR_PET_DECLINEDNAME, "INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_PET_AURA, "SELECT caster_guid, spell, effect_mask, recalculate_mask, stackcount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, maxduration, remaintime, remaincharges FROM pet_aura WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_PET_SPELL, "SELECT spell, active FROM pet_spell WHERE guid = ?", CONNECTION_SYNCH);
- PrepareStatement(CHAR_SEL_PET_SPELL_COOLDOWN, "SELECT spell, time FROM pet_spell_cooldown WHERE guid = ?", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_PET_SPELL_COOLDOWN, "SELECT spell, time FROM pet_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_PET_DECLINED_NAME, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_pet_declinedname WHERE owner = ? AND id = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_PET_AURAS, "DELETE FROM pet_aura WHERE guid = ?", CONNECTION_BOTH);
PrepareStatement(CHAR_DEL_PET_SPELLS, "DELETE FROM pet_spell WHERE guid = ?", CONNECTION_ASYNC);
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h
index e56a24d6865..f88a912e022 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.h
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.h
@@ -436,7 +436,8 @@ enum CharacterDatabaseStatements
CHAR_UPD_CHAR_REP_FACTION_CHANGE,
CHAR_UPD_CHAR_TITLES_FACTION_CHANGE,
CHAR_RES_CHAR_TITLES_FACTION_CHANGE,
- CHAR_DEL_CHAR_SPELL_COOLDOWN,
+ CHAR_DEL_CHAR_SPELL_COOLDOWNS,
+ CHAR_INS_CHAR_SPELL_COOLDOWN,
CHAR_DEL_CHARACTER,
CHAR_DEL_CHAR_ACTION,
CHAR_DEL_CHAR_AURA,
diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp
index f8f641a9ea7..e9f888f280d 100644
--- a/src/server/shared/Debugging/WheatyExceptionReport.cpp
+++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp
@@ -61,6 +61,9 @@ HANDLE WheatyExceptionReport::m_hDumpFile;
HANDLE WheatyExceptionReport::m_hProcess;
SymbolPairs WheatyExceptionReport::symbols;
std::stack<SymbolDetail> WheatyExceptionReport::symbolDetails;
+bool WheatyExceptionReport::stackOverflowException;
+bool WheatyExceptionReport::alreadyCrashed;
+std::mutex WheatyExceptionReport::alreadyCrashedLock;
// Declare global instance of class
WheatyExceptionReport g_WheatyExceptionReport;
@@ -72,6 +75,8 @@ WheatyExceptionReport::WheatyExceptionReport() // Constructor
// Install the unhandled exception filter function
m_previousFilter = SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter);
m_hProcess = GetCurrentProcess();
+ stackOverflowException = false;
+ alreadyCrashed = false;
if (!IsDebuggerPresent())
{
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
@@ -97,6 +102,16 @@ WheatyExceptionReport::~WheatyExceptionReport()
LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter(
PEXCEPTION_POINTERS pExceptionInfo)
{
+ std::unique_lock<std::mutex> guard(alreadyCrashedLock);
+ // Handle only 1 exception in the whole process lifetime
+ if (alreadyCrashed)
+ return EXCEPTION_EXECUTE_HANDLER;
+
+ alreadyCrashed = true;
+
+ if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)
+ stackOverflowException = true;
+
TCHAR module_folder_name[MAX_PATH];
GetModuleFileName(0, module_folder_name, MAX_PATH);
TCHAR* pos = _tcsrchr(module_folder_name, '\\');
@@ -419,107 +434,114 @@ void WheatyExceptionReport::printTracesForAllThreads(bool bWriteVariables)
void WheatyExceptionReport::GenerateExceptionReport(
PEXCEPTION_POINTERS pExceptionInfo)
{
- SYSTEMTIME systime;
- GetLocalTime(&systime);
-
- // Start out with a banner
- _tprintf(_T("Revision: %s\r\n"), _FULLVERSION);
- _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute);
- PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
-
- PrintSystemInfo();
- // First print information about the type of fault
- _tprintf(_T("\r\n//=====================================================\r\n"));
- _tprintf(_T("Exception code: %08X %s\r\n"),
- pExceptionRecord->ExceptionCode,
- GetExceptionString(pExceptionRecord->ExceptionCode));
-
- // Now print information about where the fault occured
- TCHAR szFaultingModule[MAX_PATH];
- DWORD section;
- DWORD_PTR offset;
- GetLogicalAddress(pExceptionRecord->ExceptionAddress,
- szFaultingModule,
- sizeof(szFaultingModule),
- section, offset);
+ __try
+ {
+ SYSTEMTIME systime;
+ GetLocalTime(&systime);
+
+ // Start out with a banner
+ _tprintf(_T("Revision: %s\r\n"), _FULLVERSION);
+ _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute);
+ PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
+
+ PrintSystemInfo();
+ // First print information about the type of fault
+ _tprintf(_T("\r\n//=====================================================\r\n"));
+ _tprintf(_T("Exception code: %08X %s\r\n"),
+ pExceptionRecord->ExceptionCode,
+ GetExceptionString(pExceptionRecord->ExceptionCode));
+
+ // Now print information about where the fault occured
+ TCHAR szFaultingModule[MAX_PATH];
+ DWORD section;
+ DWORD_PTR offset;
+ GetLogicalAddress(pExceptionRecord->ExceptionAddress,
+ szFaultingModule,
+ sizeof(szFaultingModule),
+ section, offset);
#ifdef _M_IX86
- _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"),
- pExceptionRecord->ExceptionAddress,
- section, offset, szFaultingModule);
+ _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"),
+ pExceptionRecord->ExceptionAddress,
+ section, offset, szFaultingModule);
#endif
#ifdef _M_X64
- _tprintf(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"),
- pExceptionRecord->ExceptionAddress,
- section, offset, szFaultingModule);
+ _tprintf(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"),
+ pExceptionRecord->ExceptionAddress,
+ section, offset, szFaultingModule);
#endif
- PCONTEXT pCtx = pExceptionInfo->ContextRecord;
+ PCONTEXT pCtx = pExceptionInfo->ContextRecord;
- // Show the registers
- #ifdef _M_IX86 // X86 Only!
- _tprintf(_T("\r\nRegisters:\r\n"));
+ // Show the registers
+#ifdef _M_IX86 // X86 Only!
+ _tprintf(_T("\r\nRegisters:\r\n"));
- _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n")
- , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx,
- pCtx->Esi, pCtx->Edi);
+ _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n")
+ , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx,
+ pCtx->Esi, pCtx->Edi);
- _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip);
- _tprintf(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"),
- pCtx->SegSs, pCtx->Esp, pCtx->Ebp);
- _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
- pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
- _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags);
- #endif
+ _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip);
+ _tprintf(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"),
+ pCtx->SegSs, pCtx->Esp, pCtx->Ebp);
+ _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
+ pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
+ _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags);
+#endif
- #ifdef _M_X64
- _tprintf(_T("\r\nRegisters:\r\n"));
- _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n")
- _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n")
- , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx,
- pCtx->Rsi, pCtx->Rdi, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15);
- _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip);
- _tprintf(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"),
- pCtx->SegSs, pCtx->Rsp, pCtx->Rbp);
- _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
- pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
- _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags);
- #endif
+#ifdef _M_X64
+ _tprintf(_T("\r\nRegisters:\r\n"));
+ _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n")
+ _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n")
+ , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx,
+ pCtx->Rsi, pCtx->Rdi, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15);
+ _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip);
+ _tprintf(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"),
+ pCtx->SegSs, pCtx->Rsp, pCtx->Rbp);
+ _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
+ pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
+ _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags);
+#endif
- SymSetOptions(SYMOPT_DEFERRED_LOADS);
+ SymSetOptions(SYMOPT_DEFERRED_LOADS);
- // Initialize DbgHelp
- if (!SymInitialize(GetCurrentProcess(), 0, TRUE))
- {
- _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"),
- ErrorMessage(GetLastError()));
- }
+ // Initialize DbgHelp
+ if (!SymInitialize(GetCurrentProcess(), 0, TRUE))
+ {
+ _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"),
+ ErrorMessage(GetLastError()));
+ }
- CONTEXT trashableContext = *pCtx;
+ CONTEXT trashableContext = *pCtx;
- WriteStackDetails(&trashableContext, false, NULL);
- printTracesForAllThreads(false);
+ WriteStackDetails(&trashableContext, false, NULL);
+ printTracesForAllThreads(false);
-// #ifdef _M_IX86 // X86 Only!
+ // #ifdef _M_IX86 // X86 Only!
- _tprintf(_T("========================\r\n"));
- _tprintf(_T("Local Variables And Parameters\r\n"));
+ _tprintf(_T("========================\r\n"));
+ _tprintf(_T("Local Variables And Parameters\r\n"));
- trashableContext = *pCtx;
- WriteStackDetails(&trashableContext, true, NULL);
- printTracesForAllThreads(true);
+ trashableContext = *pCtx;
+ WriteStackDetails(&trashableContext, true, NULL);
+ printTracesForAllThreads(true);
- /*_tprintf(_T("========================\r\n"));
- _tprintf(_T("Global Variables\r\n"));
+ /*_tprintf(_T("========================\r\n"));
+ _tprintf(_T("Global Variables\r\n"));
- SymEnumSymbols(GetCurrentProcess(),
+ SymEnumSymbols(GetCurrentProcess(),
(UINT_PTR)GetModuleHandle(szFaultingModule),
0, EnumerateSymbolsCallback, 0);*/
- // #endif // X86 Only!
+ // #endif // X86 Only!
- SymCleanup(GetCurrentProcess());
+ SymCleanup(GetCurrentProcess());
- _tprintf(_T("\r\n"));
+ _tprintf(_T("\r\n"));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ _tprintf(_T("Error writing the crash log\r\n"));
+ }
}
//======================================================================
@@ -1313,16 +1335,43 @@ DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer(DWORD_PTR address)
//============================================================================
int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...)
{
- TCHAR szBuff[WER_LARGE_BUFFER_SIZE];
int retValue;
- DWORD cbWritten;
va_list argptr;
-
va_start(argptr, format);
+ if (stackOverflowException)
+ {
+ retValue = heapprintf(format, argptr);
+ va_end(argptr);
+ }
+ else
+ {
+ retValue = stackprintf(format, argptr);
+ va_end(argptr);
+ }
+
+ return retValue;
+}
+
+int __cdecl WheatyExceptionReport::stackprintf(const TCHAR * format, va_list argptr)
+{
+ int retValue;
+ DWORD cbWritten;
+
+ TCHAR szBuff[WER_LARGE_BUFFER_SIZE];
retValue = vsprintf(szBuff, format, argptr);
- va_end(argptr);
+ WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0);
+ return retValue;
+}
+
+int __cdecl WheatyExceptionReport::heapprintf(const TCHAR * format, va_list argptr)
+{
+ int retValue;
+ DWORD cbWritten;
+ TCHAR* szBuff = (TCHAR*)malloc(sizeof(TCHAR) * WER_LARGE_BUFFER_SIZE);
+ retValue = vsprintf(szBuff, format, argptr);
WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0);
+ free(szBuff);
return retValue;
}
diff --git a/src/server/shared/Debugging/WheatyExceptionReport.h b/src/server/shared/Debugging/WheatyExceptionReport.h
index b7731daaa2b..ef6334add16 100644
--- a/src/server/shared/Debugging/WheatyExceptionReport.h
+++ b/src/server/shared/Debugging/WheatyExceptionReport.h
@@ -178,6 +178,8 @@ class WheatyExceptionReport
static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address);
static int __cdecl _tprintf(const TCHAR * format, ...);
+ static int __cdecl stackprintf(const TCHAR * format, va_list argptr);
+ static int __cdecl heapprintf(const TCHAR * format, va_list argptr);
static bool StoreSymbol(DWORD type , DWORD_PTR offset);
static void ClearSymbols();
@@ -191,6 +193,9 @@ class WheatyExceptionReport
static HANDLE m_hProcess;
static SymbolPairs symbols;
static std::stack<SymbolDetail> symbolDetails;
+ static bool stackOverflowException;
+ static bool alreadyCrashed;
+ static std::mutex alreadyCrashedLock;
static char* PushSymbolDetail(char* pszCurrBuffer);
static char* PopSymbolDetail(char* pszCurrBuffer);
diff --git a/src/server/shared/Networking/MessageBuffer.h b/src/server/shared/Networking/MessageBuffer.h
index 90afaf35796..95e26974626 100644
--- a/src/server/shared/Networking/MessageBuffer.h
+++ b/src/server/shared/Networking/MessageBuffer.h
@@ -55,9 +55,9 @@ public:
uint8* GetBasePointer() { return _storage.data(); }
- uint8* GetReadPointer() { return &_storage[_rpos]; }
+ uint8* GetReadPointer() { return GetBasePointer() + _rpos; }
- uint8* GetWritePointer() { return &_storage[_wpos]; }
+ uint8* GetWritePointer() { return GetBasePointer() + _wpos; }
void ReadCompleted(size_type bytes) { _rpos += bytes; }
diff --git a/src/server/shared/Networking/Socket.h b/src/server/shared/Networking/Socket.h
index 396d4bb3aab..1989411bccb 100644
--- a/src/server/shared/Networking/Socket.h
+++ b/src/server/shared/Networking/Socket.h
@@ -50,6 +50,7 @@ public:
virtual ~Socket()
{
+ _closed = true;
boost::system::error_code error;
_socket.close(error);
}
@@ -97,26 +98,6 @@ public:
std::bind(&Socket<T>::ReadHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
}
- void ReadData(std::size_t size)
- {
- if (!IsOpen())
- return;
-
- boost::system::error_code error;
-
- std::size_t bytesRead = boost::asio::read(_socket, boost::asio::buffer(_readBuffer.GetWritePointer(), size), error);
-
- _readBuffer.WriteCompleted(bytesRead);
-
- if (error || bytesRead != size)
- {
- TC_LOG_DEBUG("network", "Socket::ReadData: %s errored with: %i (%s)", GetRemoteIpAddress().to_string().c_str(), error.value(),
- error.message().c_str());
-
- CloseSocket();
- }
- }
-
void QueuePacket(MessageBuffer&& buffer, std::unique_lock<std::mutex>& guard)
{
_writeQueue.push(std::move(buffer));
diff --git a/src/server/shared/PrecompiledHeaders/sharedPCH.h b/src/server/shared/PrecompiledHeaders/sharedPCH.h
index d0c15b17f0c..87af9f44eb7 100644
--- a/src/server/shared/PrecompiledHeaders/sharedPCH.h
+++ b/src/server/shared/PrecompiledHeaders/sharedPCH.h
@@ -6,3 +6,4 @@
#include "SQLOperation.h"
#include "Errors.h"
#include "TypeList.h"
+#include "TaskScheduler.h"
diff --git a/src/server/shared/Threading/ProducerConsumerQueue.h b/src/server/shared/Threading/ProducerConsumerQueue.h
index ab01568309b..e2f13e5c339 100644
--- a/src/server/shared/Threading/ProducerConsumerQueue.h
+++ b/src/server/shared/Threading/ProducerConsumerQueue.h
@@ -70,7 +70,9 @@ public:
{
std::unique_lock<std::mutex> lock(_queueLock);
- _condition.wait(lock, [this]() { return !_queue.empty() || _shutdown; });
+ // we could be using .wait(lock, predicate) overload here but some threading error analysis tools produce false positives
+ while (_queue.empty() && !_shutdown)
+ _condition.wait(lock);
if (_queue.empty() || _shutdown)
return;
diff --git a/src/server/shared/Updater/DBUpdater.cpp b/src/server/shared/Updater/DBUpdater.cpp
index e5c571e4517..20ded669cec 100644
--- a/src/server/shared/Updater/DBUpdater.cpp
+++ b/src/server/shared/Updater/DBUpdater.cpp
@@ -349,8 +349,27 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos
args.push_back("-h" + host);
args.push_back("-u" + user);
args.push_back("-p" + password);
+
+ // Check if we want to connect through ip or socket (Unix only)
+#ifdef _WIN32
+
args.push_back("-P" + port_or_socket);
+#else
+
+ if (!std::isdigit(port_or_socket[0]))
+ {
+ // We can't check here if host == "." because is named localhost if socket option is enabled
+ args.push_back("-P0");
+ args.push_back("--protocol=SOCKET");
+ args.push_back("-S" + port_or_socket);
+ }
+ else
+ // generic case
+ args.push_back("-P" + port_or_socket);
+
+#endif
+
// Set the default charset to utf8
args.push_back("--default-character-set=utf8");
diff --git a/src/server/shared/Utilities/TaskScheduler.cpp b/src/server/shared/Utilities/TaskScheduler.cpp
new file mode 100644
index 00000000000..4b261413fd9
--- /dev/null
+++ b/src/server/shared/Utilities/TaskScheduler.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2008-2015 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 "TaskScheduler.h"
+
+TaskScheduler& TaskScheduler::Update()
+{
+ _now = clock_t::now();
+ Dispatch();
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::Update(size_t const milliseconds)
+{
+ return Update(std::chrono::milliseconds(milliseconds));
+}
+
+TaskScheduler& TaskScheduler::Async(std::function<void()> const& callable)
+{
+ _asyncHolder.push(callable);
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::CancelAll()
+{
+ /// Clear the task holder
+ _task_holder.Clear();
+ _asyncHolder = AsyncHolder();
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::CancelGroup(group_t const group)
+{
+ _task_holder.RemoveIf([group](TaskContainer const& task) -> bool
+ {
+ return task->IsInGroup(group);
+ });
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::CancelGroupsOf(std::vector<group_t> const& groups)
+{
+ std::for_each(groups.begin(), groups.end(),
+ std::bind(&TaskScheduler::CancelGroup, this, std::placeholders::_1));
+
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::InsertTask(TaskContainer task)
+{
+ _task_holder.Push(std::move(task));
+ return *this;
+}
+
+void TaskScheduler::Dispatch()
+{
+ // Process all asyncs
+ while (!_asyncHolder.empty())
+ {
+ _asyncHolder.front()();
+ _asyncHolder.pop();
+ }
+
+ while (!_task_holder.IsEmpty())
+ {
+ if (_task_holder.First()->_end > _now)
+ break;
+
+ // Perfect forward the context to the handler
+ // Use weak references to catch destruction before callbacks.
+ TaskContext context(_task_holder.Pop(), std::weak_ptr<TaskScheduler>(self_reference));
+
+ // Invoke the context
+ context.Invoke();
+ }
+}
+
+void TaskScheduler::TaskQueue::Push(TaskContainer&& task)
+{
+ container.insert(task);
+}
+
+auto TaskScheduler::TaskQueue::Pop() -> TaskContainer
+{
+ TaskContainer result = *container.begin();
+ container.erase(container.begin());
+ return result;
+}
+
+auto TaskScheduler::TaskQueue::First() const -> TaskContainer const&
+{
+ return *container.begin();
+}
+
+void TaskScheduler::TaskQueue::Clear()
+{
+ container.clear();
+}
+
+void TaskScheduler::TaskQueue::RemoveIf(std::function<bool(TaskContainer const&)> const& filter)
+{
+ for (auto itr = container.begin(); itr != container.end();)
+ if (filter(*itr))
+ itr = container.erase(itr);
+ else
+ ++itr;
+}
+
+void TaskScheduler::TaskQueue::ModifyIf(std::function<bool(TaskContainer const&)> const& filter)
+{
+ std::vector<TaskContainer> cache;
+ for (auto itr = container.begin(); itr != container.end();)
+ if (filter(*itr))
+ {
+ cache.push_back(*itr);
+ itr = container.erase(itr);
+ }
+ else
+ ++itr;
+
+ container.insert(cache.begin(), cache.end());
+}
+
+bool TaskScheduler::TaskQueue::IsEmpty() const
+{
+ return container.empty();
+}
+
+TaskContext& TaskContext::Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply)
+{
+ if (auto const owner = _owner.lock())
+ apply(*owner);
+
+ return *this;
+}
+
+bool TaskContext::IsExpired() const
+{
+ return _owner.expired();
+}
+
+bool TaskContext::IsInGroup(TaskScheduler::group_t const group) const
+{
+ return _task->IsInGroup(group);
+}
+
+TaskContext& TaskContext::SetGroup(TaskScheduler::group_t const group)
+{
+ _task->_group = group;
+ return *this;
+}
+
+TaskContext& TaskContext::ClearGroup()
+{
+ _task->_group = boost::none;
+ return *this;
+}
+
+TaskScheduler::repeated_t TaskContext::GetRepeatCounter() const
+{
+ return _task->_repeated;
+}
+
+TaskContext& TaskContext::Async(std::function<void()> const& callable)
+{
+ return Dispatch(std::bind(&TaskScheduler::Async, std::placeholders::_1, callable));
+}
+
+TaskContext& TaskContext::CancelAll()
+{
+ return Dispatch(std::mem_fn(&TaskScheduler::CancelAll));
+}
+
+TaskContext& TaskContext::CancelGroup(TaskScheduler::group_t const group)
+{
+ return Dispatch(std::bind(&TaskScheduler::CancelGroup, std::placeholders::_1, group));
+}
+
+TaskContext& TaskContext::CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups)
+{
+ return Dispatch(std::bind(&TaskScheduler::CancelGroupsOf, std::placeholders::_1, std::cref(groups)));
+}
+
+void TaskContext::AssertOnConsumed() const
+{
+ // This was adapted to TC to prevent static analysis tools from complaining.
+ // If you encounter this assertion check if you repeat a TaskContext more then 1 time!
+ ASSERT(!(*_consumed) && "Bad task logic, task context was consumed already!");
+}
+
+void TaskContext::Invoke()
+{
+ _task->_task(*this);
+}
diff --git a/src/server/shared/Utilities/TaskScheduler.h b/src/server/shared/Utilities/TaskScheduler.h
new file mode 100644
index 00000000000..98e210e55b1
--- /dev/null
+++ b/src/server/shared/Utilities/TaskScheduler.h
@@ -0,0 +1,627 @@
+/*
+ * Copyright (C) 2008-2015 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 _TASK_SCHEDULER_H_
+#define _TASK_SCHEDULER_H_
+
+#include <algorithm>
+#include <chrono>
+#include <vector>
+#include <queue>
+#include <memory>
+#include <utility>
+#include <set>
+
+#include <boost/optional.hpp>
+
+#include "Util.h"
+
+class TaskContext;
+
+/// The TaskScheduler class provides the ability to schedule std::function's in the near future.
+/// Use TaskScheduler::Update to update the scheduler.
+/// Popular methods are:
+/// * Schedule (Schedules a std::function which will be executed in the near future).
+/// * Schedules an asynchronous function which will be executed at the next update tick.
+/// * Cancel, Delay & Reschedule (Methods to manipulate already scheduled tasks).
+/// Tasks are organized in groups (uint), multiple tasks can have the same group id,
+/// you can provide a group or not, but keep in mind that you can only manipulate specific tasks through its group id!
+/// Tasks callbacks use the function signature void(TaskContext) where TaskContext provides
+/// access to the function schedule plan which makes it possible to repeat the task
+/// with the same duration or a new one.
+/// It also provides access to the repeat counter which is useful for task that repeat itself often
+/// but behave different every time (spoken event dialogs for example).
+class TaskScheduler
+{
+ friend class TaskContext;
+
+ // Time definitions (use steady clock)
+ typedef std::chrono::steady_clock clock_t;
+ typedef clock_t::time_point timepoint_t;
+ typedef clock_t::duration duration_t;
+
+ // Task group type
+ typedef uint32 group_t;
+ // Task repeated type
+ typedef uint32 repeated_t;
+ // Task handle type
+ typedef std::function<void(TaskContext)> task_handler_t;
+
+ class Task
+ {
+ friend class TaskContext;
+ friend class TaskScheduler;
+
+ timepoint_t _end;
+ duration_t _duration;
+ boost::optional<group_t> _group;
+ repeated_t _repeated;
+ task_handler_t _task;
+
+ public:
+ // All Argument construct
+ Task(timepoint_t const& end, duration_t const& duration, boost::optional<group_t> const& group,
+ repeated_t const repeated, task_handler_t const& task)
+ : _end(end), _duration(duration), _group(group), _repeated(repeated), _task(task) { }
+
+ // Minimal Argument construct
+ Task(timepoint_t const& end, duration_t const& duration, task_handler_t const& task)
+ : _end(end), _duration(duration), _group(boost::none), _repeated(0), _task(task) { }
+
+ // Copy construct
+ Task(Task const&) = delete;
+ // Move construct
+ Task(Task&&) = delete;
+ // Copy Assign
+ Task& operator= (Task const&) = default;
+ // Move Assign
+ Task& operator= (Task&& right) = delete;
+
+ // Order tasks by its end
+ inline bool operator< (Task const& other) const
+ {
+ return _end < other._end;
+ }
+
+ inline bool operator> (Task const& other) const
+ {
+ return _end > other._end;
+ }
+
+ // Compare tasks with its end
+ inline bool operator== (Task const& other)
+ {
+ return _end == other._end;
+ }
+
+ // Returns true if the task is in the given group
+ inline bool IsInGroup(group_t const group) const
+ {
+ return _group == group;
+ }
+ };
+
+ typedef std::shared_ptr<Task> TaskContainer;
+
+ /// Container which provides Task order, insert and reschedule operations.
+ struct Compare
+ {
+ bool operator() (TaskContainer const& left, TaskContainer const& right)
+ {
+ return (*left.get()) < (*right.get());
+ };
+ };
+
+ class TaskQueue
+ {
+ std::multiset<TaskContainer, Compare> container;
+
+ public:
+ // Pushes the task in the container
+ void Push(TaskContainer&& task);
+
+ /// Pops the task out of the container
+ TaskContainer Pop();
+
+ TaskContainer const& First() const;
+
+ void Clear();
+
+ void RemoveIf(std::function<bool(TaskContainer const&)> const& filter);
+
+ void ModifyIf(std::function<bool(TaskContainer const&)> const& filter);
+
+ bool IsEmpty() const;
+ };
+
+ /// Contains a self reference to track if this object was deleted or not.
+ std::shared_ptr<TaskScheduler> self_reference;
+
+ /// The current time point (now)
+ timepoint_t _now;
+
+ /// The Task Queue which contains all task objects.
+ TaskQueue _task_holder;
+
+ typedef std::queue<std::function<void()>> AsyncHolder;
+
+ /// Contains all asynchronous tasks which will be invoked at
+ /// the next update tick.
+ AsyncHolder _asyncHolder;
+
+public:
+ TaskScheduler() : self_reference(this, [](TaskScheduler const*) { }),
+ _now(clock_t::now()) { }
+
+ TaskScheduler(TaskScheduler const&) = delete;
+ TaskScheduler(TaskScheduler&&) = delete;
+ TaskScheduler& operator= (TaskScheduler const&) = delete;
+ TaskScheduler& operator= (TaskScheduler&&) = delete;
+
+ /// Update the scheduler to the current time.
+ TaskScheduler& Update();
+
+ /// Update the scheduler with a difftime in ms.
+ TaskScheduler& Update(size_t const milliseconds);
+
+ /// Update the scheduler with a difftime.
+ template<class _Rep, class _Period>
+ TaskScheduler& Update(std::chrono::duration<_Rep, _Period> const& difftime)
+ {
+ _now += difftime;
+ Dispatch();
+ return *this;
+ }
+
+ /// Schedule an callable function that is executed at the next update tick.
+ /// Its safe to modify the TaskScheduler from within the callable.
+ TaskScheduler& Async(std::function<void()> const& callable);
+
+ /// Schedule an event with a fixed rate.
+ /// Never call this from within a task context! Use TaskContext::Schedule instead!
+ template<class _Rep, class _Period>
+ TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time,
+ task_handler_t const& task)
+ {
+ return ScheduleAt(_now, time, task);
+ }
+
+ /// Schedule an event with a fixed rate.
+ /// Never call this from within a task context! Use TaskContext::Schedule instead!
+ template<class _Rep, class _Period>
+ TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time,
+ group_t const group, task_handler_t const& task)
+ {
+ return ScheduleAt(_now, time, group, task);
+ }
+
+ /// Schedule an event with a randomized rate between min and max rate.
+ /// Never call this from within a task context! Use TaskContext::Schedule instead!
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max, task_handler_t const& task)
+ {
+ return Schedule(RandomDurationBetween(min, max), task);
+ }
+
+ /// Schedule an event with a fixed rate.
+ /// Never call this from within a task context! Use TaskContext::Schedule instead!
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max, group_t const group,
+ task_handler_t const& task)
+ {
+ return Schedule(RandomDurationBetween(min, max), group, task);
+ }
+
+ /// Cancels all tasks.
+ /// Never call this from within a task context! Use TaskContext::CancelAll instead!
+ TaskScheduler& CancelAll();
+
+ /// Cancel all tasks of a single group.
+ /// Never call this from within a task context! Use TaskContext::CancelGroup instead!
+ TaskScheduler& CancelGroup(group_t const group);
+
+ /// Cancels all groups in the given std::vector.
+ /// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}"
+ TaskScheduler& CancelGroupsOf(std::vector<group_t> const& groups);
+
+ /// Delays all tasks with the given duration.
+ template<class _Rep, class _Period>
+ TaskScheduler& DelayAll(std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ _task_holder.ModifyIf([&duration](TaskContainer const& task) -> bool
+ {
+ task->_end += duration;
+ return true;
+ });
+ return *this;
+ }
+
+ /// Delays all tasks with a random duration between min and max.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskScheduler& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return DelayAll(RandomDurationBetween(min, max));
+ }
+
+ /// Delays all tasks of a group with the given duration.
+ template<class _Rep, class _Period>
+ TaskScheduler& DelayGroup(group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ _task_holder.ModifyIf([&duration, group](TaskContainer const& task) -> bool
+ {
+ if (task->IsInGroup(group))
+ {
+ task->_end += duration;
+ return true;
+ }
+ else
+ return false;
+ });
+ return *this;
+ }
+
+ /// Delays all tasks of a group with a random duration between min and max.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskScheduler& DelayGroup(group_t const group,
+ std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return DelayGroup(group, RandomDurationBetween(min, max));
+ }
+
+ /// Reschedule all tasks with a given duration.
+ template<class _Rep, class _Period>
+ TaskScheduler& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ auto const end = _now + duration;
+ _task_holder.ModifyIf([end](TaskContainer const& task) -> bool
+ {
+ task->_end = end;
+ return true;
+ });
+ return *this;
+ }
+
+ /// Reschedule all tasks with a random duration between min and max.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskScheduler& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return RescheduleAll(RandomDurationBetween(min, max));
+ }
+
+ /// Reschedule all tasks of a group with the given duration.
+ template<class _Rep, class _Period>
+ TaskScheduler& RescheduleGroup(group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ auto const end = _now + duration;
+ _task_holder.ModifyIf([end, group](TaskContainer const& task) -> bool
+ {
+ if (task->IsInGroup(group))
+ {
+ task->_end = end;
+ return true;
+ }
+ else
+ return false;
+ });
+ return *this;
+ }
+
+ /// Reschedule all tasks of a group with a random duration between min and max.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskScheduler& RescheduleGroup(group_t const group,
+ std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return RescheduleGroup(group, RandomDurationBetween(min, max));
+ }
+
+private:
+ /// Insert a new task to the enqueued tasks.
+ TaskScheduler& InsertTask(TaskContainer task);
+
+ template<class _Rep, class _Period>
+ TaskScheduler& ScheduleAt(timepoint_t const& end,
+ std::chrono::duration<_Rep, _Period> const& time, task_handler_t const& task)
+ {
+ return InsertTask(TaskContainer(new Task(end + time, time, task)));
+ }
+
+ /// Schedule an event with a fixed rate.
+ /// Never call this from within a task context! Use TaskContext::schedule instead!
+ template<class _Rep, class _Period>
+ TaskScheduler& ScheduleAt(timepoint_t const& end,
+ std::chrono::duration<_Rep, _Period> const& time,
+ group_t const group, task_handler_t const& task)
+ {
+ static repeated_t const DEFAULT_REPEATED = 0;
+ return InsertTask(TaskContainer(new Task(end + time, time, group, DEFAULT_REPEATED, task)));
+ }
+
+ // Returns a random duration between min and max
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ static std::chrono::milliseconds
+ RandomDurationBetween(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ auto const milli_min = std::chrono::duration_cast<std::chrono::milliseconds>(min);
+ auto const milli_max = std::chrono::duration_cast<std::chrono::milliseconds>(max);
+
+ // TC specific: use SFMT URandom
+ return std::chrono::milliseconds(urand(milli_min.count(), milli_max.count()));
+ }
+
+ /// Dispatch remaining tasks
+ void Dispatch();
+};
+
+class TaskContext
+{
+ friend class TaskScheduler;
+
+ /// Associated task
+ TaskScheduler::TaskContainer _task;
+
+ /// Owner
+ std::weak_ptr<TaskScheduler> _owner;
+
+ /// Marks the task as consumed
+ std::shared_ptr<bool> _consumed;
+
+ /// Dispatches an action safe on the TaskScheduler
+ TaskContext& Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply);
+
+public:
+ // Empty constructor
+ TaskContext()
+ : _task(), _owner(), _consumed(std::make_shared<bool>(true)) { }
+
+ // Construct from task and owner
+ explicit TaskContext(TaskScheduler::TaskContainer&& task, std::weak_ptr<TaskScheduler>&& owner)
+ : _task(task), _owner(owner), _consumed(std::make_shared<bool>(false)) { }
+
+ // Copy construct
+ TaskContext(TaskContext const& right)
+ : _task(right._task), _owner(right._owner), _consumed(right._consumed) { }
+
+ // Move construct
+ TaskContext(TaskContext&& right)
+ : _task(std::move(right._task)), _owner(std::move(right._owner)), _consumed(std::move(right._consumed)) { }
+
+ // Copy assign
+ TaskContext& operator= (TaskContext const& right)
+ {
+ _task = right._task;
+ _owner = right._owner;
+ _consumed = right._consumed;
+ return *this;
+ }
+
+ // Move assign
+ TaskContext& operator= (TaskContext&& right)
+ {
+ _task = std::move(right._task);
+ _owner = std::move(right._owner);
+ _consumed = std::move(right._consumed);
+ return *this;
+ }
+
+ /// Returns true if the owner was deallocated and this context has expired.
+ bool IsExpired() const;
+
+ /// Returns true if the event is in the given group
+ bool IsInGroup(TaskScheduler::group_t const group) const;
+
+ /// Sets the event in the given group
+ TaskContext& SetGroup(TaskScheduler::group_t const group);
+
+ /// Removes the group from the event
+ TaskContext& ClearGroup();
+
+ /// Returns the repeat counter which increases every time the task is repeated.
+ TaskScheduler::repeated_t GetRepeatCounter() const;
+
+ /// Repeats the event and sets a new duration.
+ /// std::chrono::seconds(5) for example.
+ /// This will consume the task context, its not possible to repeat the task again
+ /// from the same task context!
+ template<class _Rep, class _Period>
+ TaskContext& Repeat(std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ AssertOnConsumed();
+
+ // Set new duration, in-context timing and increment repeat counter
+ _task->_duration = duration;
+ _task->_end += duration;
+ _task->_repeated += 1;
+ (*_consumed) = true;
+ return Dispatch(std::bind(&TaskScheduler::InsertTask, std::placeholders::_1, _task));
+ }
+
+ /// Repeats the event with the same duration.
+ /// This will consume the task context, its not possible to repeat the task again
+ /// from the same task context!
+ TaskContext& Repeat()
+ {
+ return Repeat(_task->_duration);
+ }
+
+ /// Repeats the event and set a new duration that is randomized between min and max.
+ /// std::chrono::seconds(5) for example.
+ /// This will consume the task context, its not possible to repeat the task again
+ /// from the same task context!
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskContext& Repeat(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return Repeat(TaskScheduler::RandomDurationBetween(min, max));
+ }
+
+ /// Schedule a callable function that is executed at the next update tick from within the context.
+ /// Its safe to modify the TaskScheduler from within the callable.
+ TaskContext& Async(std::function<void()> const& callable);
+
+ /// Schedule an event with a fixed rate from within the context.
+ /// Its possible that the new event is executed immediately!
+ /// Use TaskScheduler::Async to create a task
+ /// which will be called at the next update tick.
+ template<class _Rep, class _Period>
+ TaskContext& Schedule(std::chrono::duration<_Rep, _Period> const& time,
+ TaskScheduler::task_handler_t const& task)
+ {
+ auto const end = _task->_end;
+ return Dispatch([end, time, task](TaskScheduler& scheduler) -> TaskScheduler&
+ {
+ return scheduler.ScheduleAt<_Rep, _Period>(end, time, task);
+ });
+ }
+
+ /// Schedule an event with a fixed rate from within the context.
+ /// Its possible that the new event is executed immediately!
+ /// Use TaskScheduler::Async to create a task
+ /// which will be called at the next update tick.
+ template<class _Rep, class _Period>
+ TaskContext& Schedule(std::chrono::duration<_Rep, _Period> const& time,
+ TaskScheduler::group_t const group, TaskScheduler::task_handler_t const& task)
+ {
+ auto const end = _task->_end;
+ return Dispatch([end, time, group, task](TaskScheduler& scheduler) -> TaskScheduler&
+ {
+ return scheduler.ScheduleAt<_Rep, _Period>(end, time, group, task);
+ });
+ }
+
+ /// Schedule an event with a randomized rate between min and max rate from within the context.
+ /// Its possible that the new event is executed immediately!
+ /// Use TaskScheduler::Async to create a task
+ /// which will be called at the next update tick.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskContext& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::task_handler_t const& task)
+ {
+ return Schedule(TaskScheduler::RandomDurationBetween(min, max), task);
+ }
+
+ /// Schedule an event with a randomized rate between min and max rate from within the context.
+ /// Its possible that the new event is executed immediately!
+ /// Use TaskScheduler::Async to create a task
+ /// which will be called at the next update tick.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskContext& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::group_t const group,
+ TaskScheduler::task_handler_t const& task)
+ {
+ return Schedule(TaskScheduler::RandomDurationBetween(min, max), group, task);
+ }
+
+ /// Cancels all tasks from within the context.
+ TaskContext& CancelAll();
+
+ /// Cancel all tasks of a single group from within the context.
+ TaskContext& CancelGroup(TaskScheduler::group_t const group);
+
+ /// Cancels all groups in the given std::vector from within the context.
+ /// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}"
+ TaskContext& CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups);
+
+ /// Delays all tasks with the given duration from within the context.
+ template<class _Rep, class _Period>
+ TaskContext& DelayAll(std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ return Dispatch(std::bind(&TaskScheduler::DelayAll<_Rep, _Period>, std::placeholders::_1, duration));
+ }
+
+ /// Delays all tasks with a random duration between min and max from within the context.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskContext& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return DelayAll(TaskScheduler::RandomDurationBetween(min, max));
+ }
+
+ /// Delays all tasks of a group with the given duration from within the context.
+ template<class _Rep, class _Period>
+ TaskContext& DelayGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ return Dispatch(std::bind(&TaskScheduler::DelayGroup<_Rep, _Period>, std::placeholders::_1, group, duration));
+ }
+
+ /// Delays all tasks of a group with a random duration between min and max from within the context.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskContext& DelayGroup(TaskScheduler::group_t const group,
+ std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return DelayGroup(group, TaskScheduler::RandomDurationBetween(min, max));
+ }
+
+ /// Reschedule all tasks with the given duration.
+ template<class _Rep, class _Period>
+ TaskContext& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ return Dispatch(std::bind(&TaskScheduler::RescheduleAll, std::placeholders::_1, duration));
+ }
+
+ /// Reschedule all tasks with a random duration between min and max.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskContext& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return RescheduleAll(TaskScheduler::RandomDurationBetween(min, max));
+ }
+
+ /// Reschedule all tasks of a group with the given duration.
+ template<class _Rep, class _Period>
+ TaskContext& RescheduleGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ return Dispatch(std::bind(&TaskScheduler::RescheduleGroup<_Rep, _Period>, std::placeholders::_1, group, duration));
+ }
+
+ /// Reschedule all tasks of a group with a random duration between min and max.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskContext& RescheduleGroup(TaskScheduler::group_t const group,
+ std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return RescheduleGroup(group, TaskScheduler::RandomDurationBetween(min, max));
+ }
+
+private:
+ /// Asserts if the task was consumed already.
+ void AssertOnConsumed() const;
+
+ /// Invokes the associated hook of the task.
+ void Invoke();
+};
+
+/// Milliseconds shorthand typedef.
+typedef std::chrono::milliseconds Milliseconds;
+
+/// Seconds shorthand typedef.
+typedef std::chrono::seconds Seconds;
+
+/// Minutes shorthand typedef.
+typedef std::chrono::minutes Minutes;
+
+/// Hours shorthand typedef.
+typedef std::chrono::hours Hours;
+
+#endif /// _TASK_SCHEDULER_H_
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index 2758c8e39cd..447ef9a45a8 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1021,7 +1021,7 @@ OffhandCheckAtSpellUnlearn = 1
# ClientCacheVersion
# Description: Client cache version for client cache data reset. Use any value different
# from DB and not recently been used to trigger client side cache reset.
-# Default: 0 - (Use DB value from world DB db_version.cache_id field)
+# Default: 0 - (Use DB value from world DB version.cache_id field)
ClientCacheVersion = 0
diff --git a/src/tools/map_extractor/mpq_libmpq.cpp b/src/tools/map_extractor/mpq_libmpq.cpp
index 3e12747e9c5..482e3a3abbd 100644
--- a/src/tools/map_extractor/mpq_libmpq.cpp
+++ b/src/tools/map_extractor/mpq_libmpq.cpp
@@ -71,7 +71,7 @@ MPQFile::MPQFile(const char* filename):
uint32_t filenum;
if(libmpq__file_number(mpq_a, filename, &filenum)) continue;
libmpq__off_t transferred;
- libmpq__file_unpacked_size(mpq_a, filenum, &size);
+ libmpq__file_size_unpacked(mpq_a, filenum, &size);
// HACK: in patch.mpq some files don't want to open and give 1 for filesize
if (size<=1) {
diff --git a/src/tools/map_extractor/mpq_libmpq04.h b/src/tools/map_extractor/mpq_libmpq04.h
index 470e7bd0c50..c6fe36a8221 100644
--- a/src/tools/map_extractor/mpq_libmpq04.h
+++ b/src/tools/map_extractor/mpq_libmpq04.h
@@ -43,7 +43,7 @@ public:
uint32_t filenum;
if(libmpq__file_number(mpq_a, "(listfile)", &filenum)) return;
libmpq__off_t size, transferred;
- libmpq__file_unpacked_size(mpq_a, filenum, &size);
+ libmpq__file_size_unpacked(mpq_a, filenum, &size);
char *buffer = new char[size+1];
buffer[size] = '\0';
diff --git a/src/tools/vmap4_extractor/mpq_libmpq.cpp b/src/tools/vmap4_extractor/mpq_libmpq.cpp
index 5e0effc1a77..f3eb3da96b6 100644
--- a/src/tools/vmap4_extractor/mpq_libmpq.cpp
+++ b/src/tools/vmap4_extractor/mpq_libmpq.cpp
@@ -71,7 +71,7 @@ MPQFile::MPQFile(const char* filename):
uint32 filenum;
if(libmpq__file_number(mpq_a, filename, &filenum)) continue;
libmpq__off_t transferred;
- libmpq__file_unpacked_size(mpq_a, filenum, &size);
+ libmpq__file_size_unpacked(mpq_a, filenum, &size);
// HACK: in patch.mpq some files don't want to open and give 1 for filesize
if (size<=1) {
diff --git a/src/tools/vmap4_extractor/mpq_libmpq04.h b/src/tools/vmap4_extractor/mpq_libmpq04.h
index bb842daf258..6196285627d 100644
--- a/src/tools/vmap4_extractor/mpq_libmpq04.h
+++ b/src/tools/vmap4_extractor/mpq_libmpq04.h
@@ -42,7 +42,7 @@ public:
uint32_t filenum;
if(libmpq__file_number(mpq_a, "(listfile)", &filenum)) return;
libmpq__off_t size, transferred;
- libmpq__file_unpacked_size(mpq_a, filenum, &size);
+ libmpq__file_size_unpacked(mpq_a, filenum, &size);
char *buffer = new char[size + 1];
buffer[size] = '\0';