aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/Common.h1
-rw-r--r--src/common/Metric/Metric.cpp2
-rw-r--r--src/common/Metric/Metric.h8
-rw-r--r--src/common/Utilities/Util.h32
-rw-r--r--src/server/authserver/Server/AuthSession.cpp77
-rw-r--r--src/server/authserver/Server/AuthSession.h10
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp6
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.cpp4
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.cpp13
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.cpp28
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.h38
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp8
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp12
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp12
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp25
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h11
-rw-r--r--src/server/game/Accounts/RBAC.h2
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp13
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBot.cpp67
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBot.h5
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp12
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp6
-rw-r--r--src/server/game/Battlefield/Battlefield.cpp8
-rw-r--r--src/server/game/Battlefield/Battlefield.h1
-rw-r--r--src/server/game/Battlefield/Zones/BattlefieldWG.cpp204
-rw-r--r--src/server/game/Battlefield/Zones/BattlefieldWG.h37
-rw-r--r--src/server/game/Battlegrounds/ArenaTeam.cpp12
-rw-r--r--src/server/game/Battlegrounds/ArenaTeam.h2
-rw-r--r--src/server/game/Battlegrounds/ArenaTeamMgr.cpp5
-rw-r--r--src/server/game/Battlegrounds/Battleground.cpp17
-rw-r--r--src/server/game/Battlegrounds/BattlegroundMgr.cpp2
-rw-r--r--src/server/game/Chat/Channels/Channel.cpp782
-rw-r--r--src/server/game/Chat/Channels/Channel.h95
-rw-r--r--src/server/game/Chat/Channels/ChannelAppenders.h476
-rw-r--r--src/server/game/Chat/Channels/ChannelMgr.cpp162
-rw-r--r--src/server/game/Chat/Channels/ChannelMgr.h27
-rw-r--r--src/server/game/Combat/HostileRefManager.cpp8
-rw-r--r--src/server/game/Combat/HostileRefManager.h11
-rw-r--r--src/server/game/Combat/ThreatManager.cpp29
-rw-r--r--src/server/game/Combat/ThreatManager.h37
-rw-r--r--src/server/game/Combat/UnitEvents.h39
-rw-r--r--src/server/game/Conditions/ConditionMgr.cpp1
-rw-r--r--src/server/game/Conditions/ConditionMgr.h2
-rw-r--r--src/server/game/DataStores/DBCEnums.h1
-rw-r--r--src/server/game/DataStores/DBCStructure.h12
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp44
-rw-r--r--src/server/game/Entities/Creature/Creature.h4
-rw-r--r--src/server/game/Entities/Creature/GossipDef.h1
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp71
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h9
-rw-r--r--src/server/game/Entities/Item/Item.cpp48
-rw-r--r--src/server/game/Entities/Item/Item.h14
-rw-r--r--src/server/game/Entities/Item/ItemTemplate.h195
-rw-r--r--src/server/game/Entities/Object/Object.cpp124
-rw-r--r--src/server/game/Entities/Object/Object.h12
-rw-r--r--src/server/game/Entities/Player/Player.cpp685
-rw-r--r--src/server/game/Entities/Player/Player.h151
-rw-r--r--src/server/game/Entities/Transport/Transport.cpp6
-rw-r--r--src/server/game/Entities/Unit/StatSystem.cpp27
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp5522
-rw-r--r--src/server/game/Entities/Unit/Unit.h428
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp23
-rw-r--r--src/server/game/Globals/ObjectMgr.h2
-rw-r--r--src/server/game/Grids/GridRefManager.h2
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.h416
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiersImpl.h20
-rw-r--r--src/server/game/Groups/Group.cpp2
-rw-r--r--src/server/game/Guilds/Guild.cpp285
-rw-r--r--src/server/game/Guilds/Guild.h1138
-rw-r--r--src/server/game/Handlers/AuctionHouseHandler.cpp2
-rw-r--r--src/server/game/Handlers/ChannelHandler.cpp132
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp7
-rw-r--r--src/server/game/Handlers/ChatHandler.cpp10
-rw-r--r--src/server/game/Handlers/ItemHandler.cpp12
-rw-r--r--src/server/game/Handlers/LootHandler.cpp4
-rw-r--r--src/server/game/Handlers/MailHandler.cpp6
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp6
-rw-r--r--src/server/game/Handlers/PetitionsHandler.cpp16
-rw-r--r--src/server/game/Handlers/SpellHandler.cpp8
-rw-r--r--src/server/game/Handlers/TradeHandler.cpp6
-rw-r--r--src/server/game/Loot/LootMgr.cpp149
-rw-r--r--src/server/game/Loot/LootMgr.h49
-rw-r--r--src/server/game/Maps/MapRefManager.h15
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h21
-rw-r--r--src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp2
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp23
-rw-r--r--src/server/game/Scripting/ScriptMgr.h5
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp774
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.h13
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp457
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h33
-rw-r--r--src/server/game/Spells/Spell.cpp1036
-rw-r--r--src/server/game/Spells/Spell.h51
-rw-r--r--src/server/game/Spells/SpellEffects.cpp182
-rw-r--r--src/server/game/Spells/SpellHistory.cpp4
-rw-r--r--src/server/game/Spells/SpellInfo.cpp1291
-rw-r--r--src/server/game/Spells/SpellInfo.h440
-rw-r--r--src/server/game/Spells/SpellMgr.cpp1103
-rw-r--r--src/server/game/Spells/SpellMgr.h89
-rw-r--r--src/server/game/Spells/SpellScript.cpp82
-rw-r--r--src/server/game/Spells/SpellScript.h25
-rw-r--r--src/server/game/World/World.cpp35
-rw-r--r--src/server/game/World/World.h3
-rw-r--r--src/server/scripts/Commands/cs_cast.cpp15
-rw-r--r--src/server/scripts/Commands/cs_guild.cpp9
-rw-r--r--src/server/scripts/Commands/cs_message.cpp43
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp35
-rw-r--r--src/server/scripts/Commands/cs_reload.cpp10
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h6
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp30
-rw-r--r--src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp119
-rw-r--r--src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.h4
-rw-r--r--src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp140
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp54
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp62
-rw-r--r--src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp72
-rw-r--r--src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp6
-rw-r--r--src/server/scripts/Kalimdor/zone_darkshore.cpp4
-rw-r--r--src/server/scripts/Kalimdor/zone_feralas.cpp5
-rw-r--r--src/server/scripts/Kalimdor/zone_stonetalon_mountains.cpp68
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h23
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp829
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp1175
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp971
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp46
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp45
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp429
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp6
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp20
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp8
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp44
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp5
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp818
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp54
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp6
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp8
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp3
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp4
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp5
-rw-r--r--src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp6
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp5
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp46
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp9
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp6
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp52
-rw-r--r--src/server/scripts/Northrend/zone_dragonblight.cpp26
-rw-r--r--src/server/scripts/Northrend/zone_howling_fjord.cpp188
-rw-r--r--src/server/scripts/Northrend/zone_storm_peaks.cpp1
-rw-r--r--src/server/scripts/Northrend/zone_wintergrasp.cpp340
-rw-r--r--src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp69
-rw-r--r--src/server/scripts/Outland/BlackTemple/black_temple.h18
-rw-r--r--src/server/scripts/Outland/BlackTemple/boss_illidan.cpp24
-rw-r--r--src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp93
-rw-r--r--src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp189
-rw-r--r--src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp12
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp6
-rw-r--r--src/server/scripts/Outland/boss_doomlord_kazzak.cpp60
-rw-r--r--src/server/scripts/Outland/outland_script_loader.cpp2
-rw-r--r--src/server/scripts/Outland/zone_hellfire_peninsula.cpp409
-rw-r--r--src/server/scripts/Pet/pet_hunter.cpp214
-rw-r--r--src/server/scripts/Pet/pet_priest.cpp10
-rw-r--r--src/server/scripts/Spells/spell_dk.cpp886
-rw-r--r--src/server/scripts/Spells/spell_druid.cpp1063
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp198
-rw-r--r--src/server/scripts/Spells/spell_hunter.cpp471
-rw-r--r--src/server/scripts/Spells/spell_item.cpp1350
-rw-r--r--src/server/scripts/Spells/spell_mage.cpp631
-rw-r--r--src/server/scripts/Spells/spell_paladin.cpp1002
-rw-r--r--src/server/scripts/Spells/spell_priest.cpp609
-rw-r--r--src/server/scripts/Spells/spell_quest.cpp144
-rw-r--r--src/server/scripts/Spells/spell_rogue.cpp341
-rw-r--r--src/server/scripts/Spells/spell_shaman.cpp1269
-rw-r--r--src/server/scripts/Spells/spell_warlock.cpp512
-rw-r--r--src/server/scripts/Spells/spell_warrior.cpp398
-rw-r--r--src/server/scripts/World/go_scripts.cpp311
-rw-r--r--src/server/scripts/World/npcs_special.cpp42
-rw-r--r--src/server/shared/Dynamic/LinkedList.h56
-rw-r--r--src/server/shared/Dynamic/LinkedReference/RefManager.h30
-rw-r--r--src/server/shared/Dynamic/LinkedReference/Reference.h7
-rw-r--r--src/server/worldserver/worldserver.conf.dist24
-rw-r--r--src/tools/vmap4_extractor/mpq_libmpq.cpp6
-rw-r--r--src/tools/vmap4_extractor/mpq_libmpq04.h12
183 files changed, 21245 insertions, 12769 deletions
diff --git a/src/common/Common.h b/src/common/Common.h
index aa04abacd30..af9b9b17321 100644
--- a/src/common/Common.h
+++ b/src/common/Common.h
@@ -35,6 +35,7 @@
#include <unordered_map>
#include <unordered_set>
#include <vector>
+#include <numeric>
#include <cmath>
#include <cstdio>
diff --git a/src/common/Metric/Metric.cpp b/src/common/Metric/Metric.cpp
index 9484cebcc72..cb6b3b1217b 100644
--- a/src/common/Metric/Metric.cpp
+++ b/src/common/Metric/Metric.cpp
@@ -22,7 +22,7 @@
void Metric::Initialize(std::string const& realmName, boost::asio::io_service& ioService, std::function<void()> overallStatusLogger)
{
- _realmName = realmName;
+ _realmName = FormatInfluxDBTagValue(realmName);
_batchTimer = Trinity::make_unique<boost::asio::deadline_timer>(ioService);
_overallStatusTimer = Trinity::make_unique<boost::asio::deadline_timer>(ioService);
_overallStatusLogger = overallStatusLogger;
diff --git a/src/common/Metric/Metric.h b/src/common/Metric/Metric.h
index 1855e1d0098..9230983da4d 100644
--- a/src/common/Metric/Metric.h
+++ b/src/common/Metric/Metric.h
@@ -79,6 +79,14 @@ private:
static std::string FormatInfluxDBValue(double value) { return std::to_string(value); }
static std::string FormatInfluxDBValue(float value) { return FormatInfluxDBValue(double(value)); }
+ static std::string FormatInfluxDBTagValue(std::string const& value)
+ {
+ // ToDo: should handle '=' and ',' characters too
+ return boost::replace_all_copy(value, " ", "\\ ");
+ }
+
+ // ToDo: should format TagKey and FieldKey too in the same way as TagValue
+
public:
static Metric* instance();
diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h
index fc322a89583..88708a79cd6 100644
--- a/src/common/Utilities/Util.h
+++ b/src/common/Utilities/Util.h
@@ -327,33 +327,35 @@ TC_COMMON_API bool StringToBool(std::string const& str);
// simple class for not-modifyable list
template <typename T>
-class HookList
+class HookList final
{
- typedef typename std::list<T>::iterator ListIterator;
private:
- typename std::list<T> m_list;
+ typedef std::vector<T> ContainerType;
+
+ ContainerType _container;
+
public:
- HookList<T> & operator+=(T t)
- {
- m_list.push_back(t);
- return *this;
- }
- HookList<T> & operator-=(T t)
+ typedef typename ContainerType::iterator iterator;
+
+ HookList<T>& operator+=(T t)
{
- m_list.remove(t);
+ _container.push_back(t);
return *this;
}
+
size_t size()
{
- return m_list.size();
+ return _container.size();
}
- ListIterator begin()
+
+ iterator begin()
{
- return m_list.begin();
+ return _container.begin();
}
- ListIterator end()
+
+ iterator end()
{
- return m_list.end();
+ return _container.end();
}
};
diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp
index e5e9524896f..b139d50ef8a 100644
--- a/src/server/authserver/Server/AuthSession.cpp
+++ b/src/server/authserver/Server/AuthSession.cpp
@@ -118,10 +118,10 @@ std::unordered_map<uint8, AuthHandler> AuthSession::InitHandlers()
{
std::unordered_map<uint8, AuthHandler> handlers;
- handlers[AUTH_LOGON_CHALLENGE] = { STATUS_CONNECTED, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleLogonChallenge };
- handlers[AUTH_LOGON_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::HandleLogonProof };
- handlers[AUTH_RECONNECT_CHALLENGE] = { STATUS_CONNECTED, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleReconnectChallenge };
- handlers[AUTH_RECONNECT_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::HandleReconnectProof };
+ handlers[AUTH_LOGON_CHALLENGE] = { STATUS_CHALLENGE, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleLogonChallenge };
+ handlers[AUTH_LOGON_PROOF] = { STATUS_LOGON_PROOF, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::HandleLogonProof };
+ handlers[AUTH_RECONNECT_CHALLENGE] = { STATUS_CHALLENGE, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleReconnectChallenge };
+ handlers[AUTH_RECONNECT_PROOF] = { STATUS_RECONNECT_PROOF, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::HandleReconnectProof };
handlers[REALM_LIST] = { STATUS_AUTHED, REALM_LIST_PACKET_SIZE, &AuthSession::HandleRealmList };
return handlers;
@@ -154,8 +154,7 @@ void AccountInfo::LoadResult(Field* fields)
}
AuthSession::AuthSession(tcp::socket&& socket) : Socket(std::move(socket)),
-_sentChallenge(false), _sentProof(false),
-_status(STATUS_CONNECTED), _build(0), _expversion(0)
+_status(STATUS_CHALLENGE), _build(0), _expversion(0)
{
N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
g.SetDword(7);
@@ -285,10 +284,7 @@ void AuthSession::SendPacket(ByteBuffer& packet)
bool AuthSession::HandleLogonChallenge()
{
- if (_sentChallenge)
- return false;
-
- _sentChallenge = true;
+ _status = STATUS_CLOSED;
sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer().GetReadPointer());
if (challenge->size - (sizeof(sAuthLogonChallenge_C) - AUTH_LOGON_CHALLENGE_INITIAL_SIZE - 1) != challenge->I_len)
@@ -428,7 +424,10 @@ void AuthSession::LogonChallengeCallback(PreparedQueryResult result)
// Fill the response packet with the result
if (AuthHelper::IsAcceptedClientBuild(_build))
+ {
pkt << uint8(WOW_SUCCESS);
+ _status = STATUS_LOGON_PROOF;
+ }
else
pkt << uint8(WOW_FAIL_VERSION_INVALID);
@@ -477,10 +476,7 @@ void AuthSession::LogonChallengeCallback(PreparedQueryResult result)
bool AuthSession::HandleLogonProof()
{
TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof");
- if (_sentProof)
- return false;
-
- _sentProof = true;
+ _status = STATUS_CLOSED;
// Read the packet
sAuthLogonProof_C *logonProof = reinterpret_cast<sAuthLogonProof_C*>(GetReadBuffer().GetReadPointer());
@@ -500,9 +496,7 @@ bool AuthSession::HandleLogonProof()
// SRP safeguard: abort if A == 0
if (A.IsZero())
- {
return false;
- }
SHA1Hash sha;
sha.UpdateBigNumbers(&A, &B, NULL);
@@ -571,24 +565,6 @@ bool AuthSession::HandleLogonProof()
// Check if SRP6 results match (password is correct), else send an error
if (!memcmp(M.AsByteArray(sha.GetLength()).get(), logonProof->M1, 20))
{
- TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo.Login.c_str());
-
- // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account
- // No SQL injection (escaped user name) and IP address as received by socket
-
- PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
- stmt->setString(0, K.AsHexStr());
- stmt->setString(1, GetRemoteIpAddress().to_string().c_str());
- stmt->setUInt32(2, GetLocaleByName(_localizationName));
- stmt->setString(3, _os);
- stmt->setString(4, _accountInfo.Login);
- LoginDatabase.DirectExecute(stmt);
-
- // Finish SRP6 and send the final result to the client
- sha.Initialize();
- sha.UpdateBigNumbers(&A, &M, &K, NULL);
- sha.Finalize();
-
// Check auth token
if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty())
{
@@ -610,6 +586,24 @@ bool AuthSession::HandleLogonProof()
}
}
+ TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo.Login.c_str());
+
+ // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account
+ // No SQL injection (escaped user name) and IP address as received by socket
+
+ PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
+ stmt->setString(0, K.AsHexStr());
+ stmt->setString(1, GetRemoteIpAddress().to_string().c_str());
+ stmt->setUInt32(2, GetLocaleByName(_localizationName));
+ stmt->setString(3, _os);
+ stmt->setString(4, _accountInfo.Login);
+ LoginDatabase.DirectExecute(stmt);
+
+ // Finish SRP6 and send the final result to the client
+ sha.Initialize();
+ sha.UpdateBigNumbers(&A, &M, &K, NULL);
+ sha.Finalize();
+
ByteBuffer packet;
if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients
{
@@ -657,7 +651,7 @@ bool AuthSession::HandleLogonProof()
if (sConfigMgr->GetBoolDefault("WrongPass.Logging", false))
{
PreparedStatement* logstmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FALP_IP_LOGGING);
- logstmt->setString(0, _accountInfo.Login);
+ logstmt->setUInt32(0, _accountInfo.Id);
logstmt->setString(1, GetRemoteIpAddress().to_string());
logstmt->setString(2, "Logged on failed AccountLogin due wrong password");
@@ -671,7 +665,7 @@ bool AuthSession::HandleLogonProof()
stmt->setString(0, _accountInfo.Login);
LoginDatabase.Execute(stmt);
- if (_accountInfo.FailedLogins >= MaxWrongPassCount)
+ if (++_accountInfo.FailedLogins >= MaxWrongPassCount)
{
uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600);
bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false);
@@ -705,10 +699,7 @@ bool AuthSession::HandleLogonProof()
bool AuthSession::HandleReconnectChallenge()
{
- if (_sentChallenge)
- return false;
-
- _sentChallenge = true;
+ _status = STATUS_CLOSED;
sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer().GetReadPointer());
if (challenge->size - (sizeof(sAuthLogonChallenge_C) - AUTH_LOGON_CHALLENGE_INITIAL_SIZE - 1) != challenge->I_len)
@@ -768,6 +759,7 @@ void AuthSession::ReconnectChallengeCallback(PreparedQueryResult result)
_accountInfo.LoadResult(fields);
K.SetHexStr(fields[9].GetCString());
_reconnectProof.SetRand(16 * 8);
+ _status = STATUS_RECONNECT_PROOF;
pkt << uint8(WOW_SUCCESS);
pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random
@@ -779,10 +771,7 @@ void AuthSession::ReconnectChallengeCallback(PreparedQueryResult result)
bool AuthSession::HandleReconnectProof()
{
TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof");
- if (_sentProof)
- return false;
-
- _sentProof = true;
+ _status = STATUS_CLOSED;
sAuthReconnectProof_C *reconnectProof = reinterpret_cast<sAuthReconnectProof_C*>(GetReadBuffer().GetReadPointer());
diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h
index 027011629eb..98d2cb9fcdb 100644
--- a/src/server/authserver/Server/AuthSession.h
+++ b/src/server/authserver/Server/AuthSession.h
@@ -34,8 +34,11 @@ struct AuthHandler;
enum AuthStatus
{
- STATUS_CONNECTED = 0,
- STATUS_AUTHED
+ STATUS_CHALLENGE = 0,
+ STATUS_LOGON_PROOF,
+ STATUS_RECONNECT_PROOF,
+ STATUS_AUTHED,
+ STATUS_CLOSED
};
struct AccountInfo
@@ -90,9 +93,6 @@ private:
BigNumber K;
BigNumber _reconnectProof;
- bool _sentChallenge;
- bool _sentProof;
-
AuthStatus _status;
AccountInfo _accountInfo;
std::string _tokenKey;
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index 658827662ec..6122e5aca7b 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -226,7 +226,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_CHAR_DATA_FOR_GUILD, "SELECT name, level, class, zone, account FROM characters WHERE guid = ?", CONNECTION_SYNCH);
// Chat channel handling
- PrepareStatement(CHAR_SEL_CHANNEL, "SELECT announce, ownership, password, bannedList FROM channels WHERE name = ? AND team = ?", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_CHANNEL, "SELECT name, announce, ownership, password, bannedList FROM channels WHERE name = ? AND team = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_INS_CHANNEL, "INSERT INTO channels(name, team, lastUsed) VALUES (?, ?, UNIX_TIMESTAMP())", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHANNEL, "UPDATE channels SET announce = ?, ownership = ?, password = ?, bannedList = ?, lastUsed = UNIX_TIMESTAMP() WHERE name = ? AND team = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHANNEL_USAGE, "UPDATE channels SET lastUsed = UNIX_TIMESTAMP() WHERE name = ? AND team = ?", CONNECTION_ASYNC);
@@ -243,8 +243,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_EQUIP_SET, "DELETE FROM character_equipmentsets WHERE setguid=?", CONNECTION_ASYNC);
// Auras
- PrepareStatement(CHAR_INS_AURA, "INSERT INTO character_aura (guid, casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, maxDuration, remainTime, remainCharges) "
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_AURA, "INSERT INTO character_aura (guid, casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, maxDuration, remainTime, remainCharges) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
// Account data
PrepareStatement(CHAR_SEL_ACCOUNT_DATA, "SELECT type, time, data FROM account_data WHERE accountId = ?", CONNECTION_ASYNC);
diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp
index 7ca949e01bb..c6f439e0d3d 100644
--- a/src/server/database/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/database/Database/Implementation/LoginDatabase.cpp
@@ -108,8 +108,8 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_INS_FACL_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, (SELECT last_attempt_ip FROM account WHERE id = ?), ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
// 0: uint32, 1: uint32, 2: uint8, 3: string, 4: string // Complete name: "Login_Insert_CharacterDelete_IP_Logging"
PrepareStatement(LOGIN_INS_CHAR_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
- // 0: string, 1: string, 2: string // Complete name: "Login_Insert_Failed_Account_Login_due_password_IP_Logging"
- PrepareStatement(LOGIN_INS_FALP_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES ((SELECT id FROM account WHERE username = ?), 0, 1, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
+ // 0: uint32, 1: string, 2: string // Complete name: "Login_Insert_Failed_Account_Login_due_password_IP_Logging"
+ PrepareStatement(LOGIN_INS_FALP_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, 0, 1, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS_BY_ID, "SELECT gmlevel, RealmID FROM account_access WHERE id = ? and (RealmID = ? OR RealmID = -1) ORDER BY gmlevel desc", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_BOTH);
diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp
index fbb79426bb8..a2967dc7391 100644
--- a/src/server/game/AI/CoreAI/UnitAI.cpp
+++ b/src/server/game/AI/CoreAI/UnitAI.cpp
@@ -56,16 +56,25 @@ void UnitAI::DoMeleeAttackIfReady()
if (!me->IsWithinMeleeRange(victim))
return;
+ bool sparAttack = me->GetFactionTemplateEntry()->ShouldSparAttack() && victim->GetFactionTemplateEntry()->ShouldSparAttack();
//Make sure our attack is ready and we aren't currently casting before checking distance
if (me->isAttackReady())
{
- me->AttackerStateUpdate(victim);
+ if (sparAttack)
+ me->FakeAttackerStateUpdate(victim);
+ else
+ me->AttackerStateUpdate(victim);
+
me->resetAttackTimer();
}
if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK))
{
- me->AttackerStateUpdate(victim, OFF_ATTACK);
+ if (sparAttack)
+ me->FakeAttackerStateUpdate(victim, OFF_ATTACK);
+ else
+ me->AttackerStateUpdate(victim, OFF_ATTACK);
+
me->resetAttackTimer(OFF_ATTACK);
}
}
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
index 241441db958..b6635db5daf 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
@@ -569,7 +569,7 @@ void BossAI::_DespawnAtEvade(uint32 delayToRespawn, Creature* who)
return;
}
- me->DespawnOrUnsummon(0, Seconds(delayToRespawn));
+ who->DespawnOrUnsummon(0, Seconds(delayToRespawn));
if (instance && who == me)
instance->SetBossState(_bossId, FAIL);
@@ -635,29 +635,3 @@ void WorldBossAI::UpdateAI(uint32 diff)
DoMeleeAttackIfReady();
}
-
-// SD2 grid searchers.
-Creature* GetClosestCreatureWithEntry(WorldObject* source, uint32 entry, float maxSearchRange, bool alive /*= true*/)
-{
- return source->FindNearestCreature(entry, maxSearchRange, alive);
-}
-
-GameObject* GetClosestGameObjectWithEntry(WorldObject* source, uint32 entry, float maxSearchRange)
-{
- return source->FindNearestGameObject(entry, maxSearchRange);
-}
-
-void GetCreatureListWithEntryInGrid(std::list<Creature*>& list, WorldObject* source, uint32 entry, float maxSearchRange)
-{
- source->GetCreatureListWithEntryInGrid(list, entry, maxSearchRange);
-}
-
-void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& list, WorldObject* source, uint32 entry, float maxSearchRange)
-{
- source->GetGameObjectListWithEntryInGrid(list, entry, maxSearchRange);
-}
-
-void GetPlayerListInGrid(std::list<Player*>& list, WorldObject* source, float maxSearchRange)
-{
- source->GetPlayerListInGrid(list, maxSearchRange);
-}
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
index e310c954838..37a7020752b 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
@@ -89,6 +89,12 @@ public:
return storage_.size();
}
+ // Clear the underlying storage. This does NOT despawn the creatures - use DespawnAll for that!
+ void clear()
+ {
+ storage_.clear();
+ }
+
void Summon(Creature const* summon) { storage_.push_back(summon->GetGUID()); }
void Despawn(Creature const* summon) { storage_.remove(summon->GetGUID()); }
void DespawnEntry(uint32 entry);
@@ -411,10 +417,32 @@ class TC_GAME_API WorldBossAI : public ScriptedAI
};
// SD2 grid searchers.
-TC_GAME_API Creature* GetClosestCreatureWithEntry(WorldObject* source, uint32 entry, float maxSearchRange, bool alive = true);
-TC_GAME_API GameObject* GetClosestGameObjectWithEntry(WorldObject* source, uint32 entry, float maxSearchRange);
-TC_GAME_API void GetCreatureListWithEntryInGrid(std::list<Creature*>& list, WorldObject* source, uint32 entry, float maxSearchRange);
-TC_GAME_API void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& list, WorldObject* source, uint32 entry, float maxSearchRange);
-TC_GAME_API void GetPlayerListInGrid(std::list<Player*>& list, WorldObject* source, float maxSearchRange);
+inline Creature* GetClosestCreatureWithEntry(WorldObject* source, uint32 entry, float maxSearchRange, bool alive = true)
+{
+ return source->FindNearestCreature(entry, maxSearchRange, alive);
+}
+
+inline GameObject* GetClosestGameObjectWithEntry(WorldObject* source, uint32 entry, float maxSearchRange)
+{
+ return source->FindNearestGameObject(entry, maxSearchRange);
+}
+
+template <typename Container>
+inline void GetCreatureListWithEntryInGrid(Container& container, WorldObject* source, uint32 entry, float maxSearchRange)
+{
+ source->GetCreatureListWithEntryInGrid(container, entry, maxSearchRange);
+}
+
+template <typename Container>
+inline void GetGameObjectListWithEntryInGrid(Container& container, WorldObject* source, uint32 entry, float maxSearchRange)
+{
+ source->GetGameObjectListWithEntryInGrid(container, entry, maxSearchRange);
+}
+
+template <typename Container>
+inline void GetPlayerListInGrid(Container& container, WorldObject* source, float maxSearchRange)
+{
+ source->GetPlayerListInGrid(container, maxSearchRange);
+}
#endif // SCRIPTEDCREATURE_H_
diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
index 89ad726b253..9e55b9d8187 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
@@ -150,14 +150,10 @@ void npc_escortAI::JustDied(Unit* /*killer*/)
{
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
if (Player* member = groupRef->GetSource())
- if (member->GetQuestStatus(m_pQuestForEscort->GetQuestId()) == QUEST_STATUS_INCOMPLETE)
- member->FailQuest(m_pQuestForEscort->GetQuestId());
+ member->FailQuest(m_pQuestForEscort->GetQuestId());
}
else
- {
- if (player->GetQuestStatus(m_pQuestForEscort->GetQuestId()) == QUEST_STATUS_INCOMPLETE)
- player->FailQuest(m_pQuestForEscort->GetQuestId());
- }
+ player->FailQuest(m_pQuestForEscort->GetQuestId());
}
}
diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
index 24de7344f99..9730370a77c 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
@@ -147,19 +147,11 @@ void FollowerAI::JustDied(Unit* /*killer*/)
if (Group* group = player->GetGroup())
{
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
- {
if (Player* member = groupRef->GetSource())
- {
- if (member->GetQuestStatus(m_pQuestForFollow->GetQuestId()) == QUEST_STATUS_INCOMPLETE)
- member->FailQuest(m_pQuestForFollow->GetQuestId());
- }
- }
+ member->FailQuest(m_pQuestForFollow->GetQuestId());
}
else
- {
- if (player->GetQuestStatus(m_pQuestForFollow->GetQuestId()) == QUEST_STATUS_INCOMPLETE)
- player->FailQuest(m_pQuestForFollow->GetQuestId());
- }
+ player->FailQuest(m_pQuestForFollow->GetQuestId());
}
}
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index b57717fa53d..97bbbfe2b72 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -73,11 +73,7 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c)
bool SmartAI::IsAIControlled() const
{
- if (me->IsControlledByPlayer())
- return false;
- if (mIsCharmed)
- return false;
- return true;
+ return !mIsCharmed;
}
void SmartAI::UpdateDespawn(const uint32 diff)
@@ -225,7 +221,7 @@ void SmartAI::EndPath(bool fail)
if (!fail && player->IsAtGroupRewardDistance(me) && !player->HasCorpse())
player->GroupEventHappens(mEscortQuestID, me);
- if (fail && player->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE)
+ if (fail)
player->FailQuest(mEscortQuestID);
if (Group* group = player->GetGroup())
@@ -236,7 +232,7 @@ void SmartAI::EndPath(bool fail)
if (!fail && groupGuy->IsAtGroupRewardDistance(me) && !groupGuy->HasCorpse())
groupGuy->AreaExploredOrEventHappens(mEscortQuestID);
- if (fail && groupGuy->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE)
+ else if (fail)
groupGuy->FailQuest(mEscortQuestID);
}
}
@@ -250,7 +246,7 @@ void SmartAI::EndPath(bool fail)
Player* player = (*iter)->ToPlayer();
if (!fail && player->IsAtGroupRewardDistance(me) && !player->HasCorpse())
player->AreaExploredOrEventHappens(mEscortQuestID);
- if (fail && player->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE)
+ else if (fail)
player->FailQuest(mEscortQuestID);
}
}
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 56e943a64c9..48315eb44ed 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -65,7 +65,6 @@ SmartScript::~SmartScript()
void SmartScript::OnReset()
{
- SetPhase(0);
ResetBaseObject();
for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i)
{
@@ -99,8 +98,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
//calc random
if (e.GetEventType() != SMART_EVENT_LINK && e.event.event_chance < 100 && e.event.event_chance)
{
- uint32 rnd = urand(1, 100);
- if (e.event.event_chance <= rnd)
+ if (!roll_chance_i(e.event.event_chance))
return;
}
e.runOnce = true;//used for repeat check
@@ -1069,20 +1067,10 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
- {
if (Creature* target = (*itr)->ToCreature())
- {
- if (target->IsAlive() && IsSmart(target))
- {
- ENSURE_AI(SmartAI, target->AI())->SetDespawnTime(e.action.forceDespawn.delay + 1); // Next tick
- ENSURE_AI(SmartAI, target->AI())->StartDespawn();
- }
- else
- target->DespawnOrUnsummon(e.action.forceDespawn.delay);
- }
+ target->DespawnOrUnsummon(e.action.forceDespawn.delay);
else if (GameObject* goTarget = (*itr)->ToGameObject())
goTarget->SetRespawnTime(e.action.forceDespawn.delay + 1);
- }
delete targets;
break;
@@ -1176,7 +1164,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (!IsCreature(*itr))
continue;
- if (!(e.event.event_flags & SMART_EVENT_FLAG_WHILE_CHARMED) && !IsCreatureInControlOfSelf(*itr))
+ if (!(e.event.event_flags & SMART_EVENT_FLAG_WHILE_CHARMED) && IsCharmedCreature(*itr))
continue;
Position pos = (*itr)->GetPosition();
@@ -1683,6 +1671,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
ResetBaseObject();
break;
case SMART_ACTION_CALL_SCRIPT_RESET:
+ SetPhase(0);
OnReset();
break;
case SMART_ACTION_SET_RANGED_MOVEMENT:
@@ -2854,7 +2843,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
if ((e.event.event_phase_mask && !IsInPhase(e.event.event_phase_mask)) || ((e.event.event_flags & SMART_EVENT_FLAG_NOT_REPEATABLE) && e.runOnce))
return;
- if (!(e.event.event_flags & SMART_EVENT_FLAG_WHILE_CHARMED) && IsCreature(me) && !IsCreatureInControlOfSelf(me))
+ if (!(e.event.event_flags & SMART_EVENT_FLAG_WHILE_CHARMED) && IsCharmedCreature(me))
return;
switch (e.GetEventType())
@@ -3599,10 +3588,6 @@ void SmartScript::FillScript(SmartAIEventList e, WorldObject* obj, AreaTriggerEn
}
mEvents.push_back((*i));//NOTE: 'world(0)' events still get processed in ANY instance mode
}
- if (mEvents.empty() && obj)
- TC_LOG_ERROR("sql.sql", "SmartScript: Entry %u has events but no events added to list because of instance flags.", obj->GetEntry());
- if (mEvents.empty() && at)
- TC_LOG_ERROR("sql.sql", "SmartScript: AreaTrigger %u has events but no events added to list because of instance flags. NOTE: triggers can not handle any instance flags.", at->id);
}
void SmartScript::GetScript()
diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h
index 8ac5b494911..3cb66faa033 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.h
+++ b/src/server/game/AI/SmartScripts/SmartScript.h
@@ -78,12 +78,15 @@ class TC_GAME_API SmartScript
return obj && obj->GetTypeId() == TYPEID_UNIT;
}
- static bool IsCreatureInControlOfSelf(WorldObject* obj)
+ static bool IsCharmedCreature(WorldObject* obj)
{
- if (Creature* creatureObj = obj ? obj->ToCreature() : nullptr)
- return !creatureObj->IsCharmed() && !creatureObj->IsControlledByPlayer();
- else
+ if (!obj)
return false;
+
+ if (Creature* creatureObj = obj->ToCreature())
+ return creatureObj->IsCharmed();
+
+ return false;
}
static bool IsGameObject(WorldObject* obj)
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index 80fc0b237b1..907a650e602 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -602,7 +602,7 @@ enum RBACPermissions
RBAC_PERM_COMMAND_RELOAD_SPELL_LOOT_TEMPLATE = 695,
RBAC_PERM_COMMAND_RELOAD_SPELL_LINKED_SPELL = 696,
RBAC_PERM_COMMAND_RELOAD_SPELL_PET_AURAS = 697,
- RBAC_PERM_COMMAND_RELOAD_SPELL_PROC_EVENT = 698,
+ // 698 - reuse
RBAC_PERM_COMMAND_RELOAD_SPELL_PROC = 699,
RBAC_PERM_COMMAND_RELOAD_SPELL_SCRIPTS = 700,
RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION = 701,
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index d9f5388e3ce..43bd28c7863 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -27,6 +27,7 @@
#include "ScriptMgr.h"
#include "AccountMgr.h"
#include "AuctionHouseMgr.h"
+#include "AuctionHouseBot.h"
#include "Item.h"
#include "Language.h"
#include "Log.h"
@@ -156,7 +157,7 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction&
}
// receiver exist
- if (bidder || bidderAccId)
+ if ((bidder || bidderAccId) && !sAuctionBotConfig->IsBotChar(auction->bidder))
{
// set owner to bidder (to prevent delete item with sender char deleting)
// owner in `data` will set at mail receive and item extracting
@@ -189,7 +190,7 @@ void AuctionHouseMgr::SendAuctionSalePendingMail(AuctionEntry* auction, SQLTrans
Player* owner = ObjectAccessor::FindConnectedPlayer(owner_guid);
uint32 owner_accId = sObjectMgr->GetPlayerAccountIdByGUID(owner_guid);
// owner exist (online or offline)
- if (owner || owner_accId)
+ if ((owner || owner_accId) && !sAuctionBotConfig->IsBotChar(auction->owner))
MailDraft(auction->BuildAuctionMailSubject(AUCTION_SALE_PENDING), AuctionEntry::BuildAuctionMailBody(auction->bidder, auction->bid, auction->buyout, auction->deposit, auction->GetAuctionCut()))
.SendMailTo(trans, MailReceiver(owner, auction->owner), auction, MAIL_CHECK_MASK_COPIED);
}
@@ -201,7 +202,7 @@ void AuctionHouseMgr::SendAuctionSuccessfulMail(AuctionEntry* auction, SQLTransa
Player* owner = ObjectAccessor::FindConnectedPlayer(owner_guid);
uint32 owner_accId = sObjectMgr->GetPlayerAccountIdByGUID(owner_guid);
// owner exist
- if (owner || owner_accId)
+ if ((owner || owner_accId) && !sAuctionBotConfig->IsBotChar(auction->owner))
{
uint32 profit = auction->bid + auction->deposit - auction->GetAuctionCut();
@@ -232,7 +233,7 @@ void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry* auction, SQLTransacti
Player* owner = ObjectAccessor::FindConnectedPlayer(owner_guid);
uint32 owner_accId = sObjectMgr->GetPlayerAccountIdByGUID(owner_guid);
// owner exist
- if (owner || owner_accId)
+ if ((owner || owner_accId) && !sAuctionBotConfig->IsBotChar(auction->owner))
{
if (owner)
owner->GetSession()->SendAuctionOwnerNotification(auction);
@@ -259,7 +260,7 @@ void AuctionHouseMgr::SendAuctionOutbiddedMail(AuctionEntry* auction, uint32 new
oldBidder_accId = sObjectMgr->GetPlayerAccountIdByGUID(oldBidder_guid);
// old bidder exist
- if (oldBidder || oldBidder_accId)
+ if ((oldBidder || oldBidder_accId) && !sAuctionBotConfig->IsBotChar(auction->bidder))
{
if (oldBidder && newBidder)
oldBidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, newBidder->GetGUID(), newPrice, auction->GetAuctionOutBid(), auction->itemEntry);
@@ -281,7 +282,7 @@ void AuctionHouseMgr::SendAuctionCancelledToBidderMail(AuctionEntry* auction, SQ
bidder_accId = sObjectMgr->GetPlayerAccountIdByGUID(bidder_guid);
// bidder exist
- if (bidder || bidder_accId)
+ if ((bidder || bidder_accId) && !sAuctionBotConfig->IsBotChar(auction->bidder))
MailDraft(auction->BuildAuctionMailSubject(AUCTION_CANCELLED_TO_BIDDER), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout, auction->deposit, 0))
.AddMoney(auction->bid)
.SendMailTo(trans, MailReceiver(bidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED);
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp
index 74f0aaf428a..4601495a70b 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp
@@ -15,10 +15,12 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "Containers.h"
#include "Log.h"
#include "Item.h"
#include "World.h"
#include "Config.h"
+#include "AccountMgr.h"
#include "AuctionHouseMgr.h"
#include "AuctionHouseBot.h"
#include "AuctionHouseBotBuyer.h"
@@ -56,6 +58,31 @@ bool AuctionBotConfig::Initialize()
_itemsPerCycleBoost = GetConfig(CONFIG_AHBOT_ITEMS_PER_CYCLE_BOOST);
_itemsPerCycleNormal = GetConfig(CONFIG_AHBOT_ITEMS_PER_CYCLE_NORMAL);
+ if (uint32 ahBotAccId = GetConfig(CONFIG_AHBOT_ACCOUNT_ID))
+ {
+ // check character count
+ if (AccountMgr::GetCharactersCount(GetConfig(CONFIG_AHBOT_ACCOUNT_ID)))
+ {
+ // find account guids associated with ahbot account
+ uint32 count = 0;
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID);
+ stmt->setUInt32(0, ahBotAccId);
+ if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ _AHBotCharacters.push_back(fields[0].GetUInt32());
+ ++count;
+ } while (result->NextRow());
+ }
+
+ TC_LOG_DEBUG("ahbot", "AuctionHouseBot found %u characters", count);
+ }
+ else
+ TC_LOG_WARN("ahbot", "AuctionHouseBot Account ID %u has no associated characters.", ahBotAccId);
+ }
+
return true;
}
@@ -111,6 +138,8 @@ void AuctionBotConfig::SetConfig(AuctionBotConfigFloatValues index, char const*
//Get AuctionHousebot configuration file
void AuctionBotConfig::GetConfigFromFile()
{
+ SetConfig(CONFIG_AHBOT_ACCOUNT_ID, "AuctionHouseBot.Account", 0);
+
SetConfigMax(CONFIG_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO, "AuctionHouseBot.Alliance.Items.Amount.Ratio", 100, 10000);
SetConfigMax(CONFIG_AHBOT_HORDE_ITEM_AMOUNT_RATIO, "AuctionHouseBot.Horde.Items.Amount.Ratio", 100, 10000);
SetConfigMax(CONFIG_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO, "AuctionHouseBot.Neutral.Items.Amount.Ratio", 100, 10000);
@@ -272,6 +301,40 @@ char const* AuctionBotConfig::GetHouseTypeName(AuctionHouseType houseType)
return names[houseType];
}
+// Picks a random character from the list of AHBot chars
+uint32 AuctionBotConfig::GetRandChar() const
+{
+ if (_AHBotCharacters.empty())
+ return 0;
+
+ return Trinity::Containers::SelectRandomContainerElement(_AHBotCharacters);
+}
+
+// Picks a random AHBot character, but excludes a specific one. This is used
+// to have another character than the auction owner place bids
+uint32 AuctionBotConfig::GetRandCharExclude(uint32 exclude) const
+{
+ if (_AHBotCharacters.empty())
+ return 0;
+
+ std::vector<uint32> filteredCharacters;
+ filteredCharacters.reserve(_AHBotCharacters.size() - 1);
+
+ for (uint32 charId : _AHBotCharacters)
+ if (charId != exclude)
+ filteredCharacters.push_back(charId);
+
+ if (filteredCharacters.empty())
+ return 0;
+
+ return Trinity::Containers::SelectRandomContainerElement(filteredCharacters);
+}
+
+bool AuctionBotConfig::IsBotChar(uint32 characterID) const
+{
+ return !characterID || std::find(_AHBotCharacters.begin(), _AHBotCharacters.end(), characterID) != _AHBotCharacters.end();
+}
+
uint32 AuctionBotConfig::GetConfigItemAmountRatio(AuctionHouseType houseType) const
{
switch (houseType)
@@ -408,7 +471,7 @@ void AuctionHouseBot::PrepareStatusInfos(AuctionHouseBotStatusInfo& statusInfo)
if (Item* item = sAuctionMgr->GetAItem(auctionEntry->itemGUIDLow))
{
ItemTemplate const* prototype = item->GetTemplate();
- if (!auctionEntry->owner) // Add only ahbot items
+ if (!auctionEntry->owner || sAuctionBotConfig->IsBotChar(auctionEntry->owner)) // Add only ahbot items
{
if (prototype->Quality < MAX_AUCTION_QUALITY)
++statusInfo[i].QualityInfo[prototype->Quality];
@@ -426,7 +489,7 @@ void AuctionHouseBot::Rebuild(bool all)
{
AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(AuctionHouseType(i));
for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionHouse->GetAuctionsBegin(); itr != auctionHouse->GetAuctionsEnd(); ++itr)
- if (!itr->second->owner) // ahbot auction
+ if (!itr->second->owner || sAuctionBotConfig->IsBotChar(itr->second->owner)) // ahbot auction
if (all || itr->second->bid == 0) // expire now auction if no bid or forced
itr->second->expire_time = sWorld->GetGameTime();
}
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBot.h b/src/server/game/AuctionHouseBot/AuctionHouseBot.h
index 1a438e01cdb..4f68a172255 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBot.h
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.h
@@ -152,6 +152,7 @@ enum AuctionBotConfigUInt32Values
CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_KEY,
CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_MISC,
CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_GLYPH,
+ CONFIG_AHBOT_ACCOUNT_ID,
CONFIG_UINT32_AHBOT_UINT32_COUNT
};
@@ -224,6 +225,9 @@ public:
uint32 GetItemPerCycleBoost() const { return _itemsPerCycleBoost; }
uint32 GetItemPerCycleNormal() const { return _itemsPerCycleNormal; }
+ uint32 GetRandChar() const;
+ uint32 GetRandCharExclude(uint32 exclude) const;
+ bool IsBotChar(uint32 characterID) const;
void Reload() { GetConfigFromFile(); }
static char const* GetHouseTypeName(AuctionHouseType houseType);
@@ -231,6 +235,7 @@ public:
private:
std::string _AHBotIncludes;
std::string _AHBotExcludes;
+ std::vector<uint32> _AHBotCharacters;
uint32 _itemsPerCycleBoost;
uint32 _itemsPerCycleNormal;
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp
index 6b1dcb85bec..0e6b3402db0 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp
@@ -103,7 +103,7 @@ uint32 AuctionBotBuyer::GetItemInformation(BuyerConfiguration& config)
{
AuctionEntry* entry = itr->second;
- if (!entry->owner)
+ if (!entry->owner || sAuctionBotConfig->IsBotChar(entry->owner))
continue; // Skip auctions owned by AHBot
Item* item = sAuctionMgr->GetAItem(entry->itemGUIDLow);
@@ -218,7 +218,7 @@ bool AuctionBotBuyer::RollBidChance(const BuyerItemInfo* ahInfo, const Item* ite
}
// If a player has bidded on item, have fifth of normal chance
- if (auction->bidder)
+ if (auction->bidder && !sAuctionBotConfig->IsBotChar(auction->bidder))
chance = chance / 5.f;
// Add config weigh in for quality
@@ -391,11 +391,11 @@ void AuctionBotBuyer::BuyEntry(AuctionEntry* auction, AuctionHouseObject* auctio
SQLTransaction trans = CharacterDatabase.BeginTransaction();
// Send mail to previous bidder if any
- if (auction->bidder)
+ if (auction->bidder && !sAuctionBotConfig->IsBotChar(auction->bidder))
sAuctionMgr->SendAuctionOutbiddedMail(auction, auction->buyout, NULL, trans);
// Set bot as bidder and set new bid amount
- auction->bidder = 0;
+ auction->bidder = sAuctionBotConfig->GetRandCharExclude(auction->owner);
auction->bid = auction->buyout;
// Mails must be under transaction control too to prevent data loss
@@ -422,11 +422,11 @@ void AuctionBotBuyer::PlaceBidToEntry(AuctionEntry* auction, uint32 bidPrice)
SQLTransaction trans = CharacterDatabase.BeginTransaction();
// Send mail to previous bidder if any
- if (auction->bidder)
+ if (auction->bidder && !sAuctionBotConfig->IsBotChar(auction->bidder))
sAuctionMgr->SendAuctionOutbiddedMail(auction, bidPrice, NULL, trans);
// Set bot as bidder and set new bid amount
- auction->bidder = 0;
+ auction->bidder = sAuctionBotConfig->GetRandCharExclude(auction->owner);
auction->bid = bidPrice;
// Update auction to DB
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
index 17b104eb388..34127f0c59f 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
@@ -320,7 +320,7 @@ bool AuctionBotSeller::Initialize()
continue;
}
- if (prototype->Flags & ITEM_FLAG_UNLOCKED)
+ if (prototype->Flags & ITEM_FLAG_HAS_LOOT)
{
// skip any not locked lootable items (mostly quest specific or reward cases)
if (!prototype->LockID)
@@ -640,7 +640,7 @@ uint32 AuctionBotSeller::SetStat(SellerConfiguration& config)
{
ItemTemplate const* prototype = item->GetTemplate();
if (prototype)
- if (!auctionEntry->owner) // Add only ahbot items
+ if (!auctionEntry->owner || sAuctionBotConfig->IsBotChar(auctionEntry->owner)) // Add only ahbot items
++itemsSaved[prototype->Quality][prototype->Class];
}
}
@@ -1019,7 +1019,7 @@ void AuctionBotSeller::AddNewAuctions(SellerConfiguration& config)
AuctionEntry* auctionEntry = new AuctionEntry();
auctionEntry->Id = sObjectMgr->GenerateAuctionID();
- auctionEntry->owner = 0;
+ auctionEntry->owner = sAuctionBotConfig->GetRandChar();
auctionEntry->itemGUIDLow = item->GetGUID().GetCounter();
auctionEntry->itemEntry = item->GetEntry();
auctionEntry->startbid = bidPrice;
diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp
index 093fccb5977..bcbdb948708 100644
--- a/src/server/game/Battlefield/Battlefield.cpp
+++ b/src/server/game/Battlefield/Battlefield.cpp
@@ -375,6 +375,14 @@ void Battlefield::AskToLeaveQueue(Player* player)
m_PlayersInQueue[player->GetTeamId()].erase(player->GetGUID());
}
+// Called in WorldSession::HandleHearthAndResurrect
+void Battlefield::PlayerAskToLeave(Player* player)
+{
+ // Player leaving Wintergrasp, teleport to Dalaran.
+ // ToDo: confirm teleport destination.
+ player->TeleportTo(571, 5804.1499f, 624.7710f, 647.7670f, 1.6400f);
+}
+
// Called in WorldSession::HandleBfEntryInviteResponse
void Battlefield::PlayerAcceptInviteToWar(Player* player)
{
diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h
index 566029cf9a1..a96b5400ccd 100644
--- a/src/server/game/Battlefield/Battlefield.h
+++ b/src/server/game/Battlefield/Battlefield.h
@@ -309,6 +309,7 @@ class TC_GAME_API Battlefield : public ZoneScript
void PlayerAcceptInviteToWar(Player* player);
uint32 GetBattleId() const { return m_BattleId; }
void AskToLeaveQueue(Player* player);
+ void PlayerAskToLeave(Player* player);
virtual void DoCompleteOrIncrementAchievement(uint32 /*achievement*/, Player* /*player*/, uint8 /*incrementNumber = 1*/) { }
diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp
index 361ee2b3e1f..8df95619ae5 100644
--- a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp
+++ b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp
@@ -61,9 +61,6 @@ G3D::Quat const WintergraspRelicRot = { 0.f, 0.f, -0.7933531f, 0.6087617f };
uint8 const WG_MAX_OBJ = 32;
uint8 const WG_MAX_TURRET = 15;
-uint8 const WG_MAX_KEEP_NPC = 39;
-uint8 const WG_MAX_OUTSIDE_NPC = 14;
-uint8 const WG_OUTSIDE_ALLIANCE_NPC = 7;
uint8 const WG_MAX_TELEPORTER = 12;
uint8 const WG_MAX_WORKSHOP = 6;
uint8 const WG_MAX_TOWER = 7;
@@ -177,76 +174,6 @@ struct WintergraspObjectPositionData
uint32 AllianceEntry;
};
-// Here there is all npc keeper spawn point
-WintergraspObjectPositionData const WGKeepNPC[WG_MAX_KEEP_NPC] =
-{
- // X Y Z O horde alliance
- // North East
- { { 5326.203125f, 2660.026367f, 409.100891f, 2.543383f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Roaming Guard
- { { 5298.430176f, 2738.760010f, 409.316010f, 3.971740f }, BATTLEFIELD_WG_NPC_VIERON_BLAZEFEATHER, BATTLEFIELD_WG_NPC_BOWYER_RANDOLPH }, // Vieron Blazefeather
- { { 5335.310059f, 2764.110107f, 409.274994f, 4.834560f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5349.810059f, 2763.629883f, 409.333008f, 4.660030f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- // North
- { { 5373.470215f, 2789.060059f, 409.322998f, 2.600540f }, BATTLEFIELD_WG_NPC_STONE_GUARD_MUKAR, BATTLEFIELD_WG_NPC_KNIGHT_DAMERON }, // Stone Guard Mukar
- { { 5296.560059f, 2789.870117f, 409.274994f, 0.733038f }, BATTLEFIELD_WG_NPC_HOODOO_MASTER_FU_JIN, BATTLEFIELD_WG_NPC_SORCERESS_KAYLANA }, // Voodoo Master Fu'jin
- { { 5372.670000f, 2786.740000f, 409.442000f, 2.809980f }, BATTLEFIELD_WG_NPC_CHAMPION_ROS_SLAI, BATTLEFIELD_WG_NPC_MARSHAL_MAGRUDER }, // Wintergrasp Quartermaster
- { { 5368.709961f, 2856.360107f, 409.322998f, 2.949610f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5367.910156f, 2826.520020f, 409.322998f, 3.333580f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5389.270020f, 2847.370117f, 418.759003f, 3.106690f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5388.560059f, 2834.770020f, 418.759003f, 3.071780f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5359.129883f, 2837.989990f, 409.364014f, 4.698930f }, BATTLEFIELD_WG_NPC_COMMANDER_DARDOSH, BATTLEFIELD_WG_NPC_COMMANDER_ZANNETH }, // Commander Dardosh
- { { 5366.129883f, 2833.399902f, 409.322998f, 3.141590f }, BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_KILRATH, BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_AHBRAMIS }, // Tactical Officer Kilrath
- // X Y Z O horde alliance
- // North West
- { { 5350.680176f, 2917.010010f, 409.274994f, 1.466080f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5335.120117f, 2916.800049f, 409.444000f, 1.500980f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5295.560059f, 2926.669922f, 409.274994f, 0.872665f }, BATTLEFIELD_WG_NPC_SIEGESMITH_STRONGHOOF, BATTLEFIELD_WG_NPC_SIEGE_MASTER_STOUTHANDLE }, // Stronghoof
- { { 5371.399902f, 3026.510010f, 409.205994f, 3.250030f }, BATTLEFIELD_WG_NPC_PRIMALIST_MULFORT, BATTLEFIELD_WG_NPC_ANCHORITE_TESSA }, // Primalist Mulfort
- { { 5392.123535f, 3031.110352f, 409.187683f, 3.677212f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Roaming Guard
- // South
- { { 5270.060059f, 2847.550049f, 409.274994f, 3.071780f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5270.160156f, 2833.479980f, 409.274994f, 3.124140f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5179.109863f, 2837.129883f, 409.274994f, 3.211410f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5179.669922f, 2846.600098f, 409.274994f, 3.089230f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5234.970215f, 2883.399902f, 409.274994f, 4.293510f }, BATTLEFIELD_WG_NPC_LIEUTENANT_MURP, BATTLEFIELD_WG_NPC_SENIOR_DEMOLITIONIST_LEGOSO }, // Lieutenant Murp
- // X Y Z O horde alliance
- // Portal guards (from around the fortress)
- { { 5319.209473f, 3055.947754f, 409.176636f, 1.020201f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5311.612305f, 3061.207275f, 408.734161f, 0.965223f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5264.713379f, 3017.283447f, 408.479706f, 3.482424f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5269.096191f, 3008.315918f, 408.826294f, 3.843706f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5201.414551f, 2945.096924f, 409.190735f, 0.945592f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5193.386230f, 2949.617188f, 409.190735f, 1.145859f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5148.116211f, 2904.761963f, 409.193756f, 3.368532f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5153.355957f, 2895.501465f, 409.199310f, 3.549174f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5154.353027f, 2787.349365f, 409.250183f, 2.555644f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5150.066406f, 2777.876953f, 409.343903f, 2.708797f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5193.706543f, 2732.882812f, 409.189514f, 4.845073f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5202.126953f, 2737.570557f, 409.189514f, 5.375215f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5269.181152f, 2671.174072f, 409.098999f, 2.457459f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5264.960938f, 2662.332520f, 409.098999f, 2.598828f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5307.111816f, 2616.006836f, 409.095734f, 5.355575f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
- { { 5316.770996f, 2619.430176f, 409.027740f, 5.363431f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A } // Standing Guard
-};
-
-WintergraspObjectPositionData const WGOutsideNPC[WG_MAX_OUTSIDE_NPC] =
-{
- { { 5032.04f, 3681.79f, 362.980f, 4.210f }, BATTLEFIELD_WG_NPC_VIERON_BLAZEFEATHER, 0 },
- { { 5020.71f, 3626.19f, 360.150f, 4.640f }, BATTLEFIELD_WG_NPC_HOODOO_MASTER_FU_JIN, 0 },
- { { 4994.85f, 3660.51f, 359.150f, 2.260f }, BATTLEFIELD_WG_NPC_COMMANDER_DARDOSH, 0 },
- { { 5015.46f, 3677.11f, 362.970f, 6.009f }, BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_KILRATH, 0 },
- { { 5031.12f, 3663.77f, 363.500f, 3.110f }, BATTLEFIELD_WG_NPC_SIEGESMITH_STRONGHOOF, 0 },
- { { 5042.74f, 3675.82f, 363.060f, 3.358f }, BATTLEFIELD_WG_NPC_PRIMALIST_MULFORT, 0 },
- { { 5014.45f, 3640.87f, 361.390f, 3.280f }, BATTLEFIELD_WG_NPC_LIEUTENANT_MURP, 0 },
- { { 5100.07f, 2168.89f, 365.779f, 1.972f }, 0, BATTLEFIELD_WG_NPC_BOWYER_RANDOLPH },
- { { 5081.70f, 2173.73f, 365.878f, 0.855f }, 0, BATTLEFIELD_WG_NPC_SORCERESS_KAYLANA },
- { { 5078.28f, 2183.70f, 365.029f, 1.466f }, 0, BATTLEFIELD_WG_NPC_COMMANDER_ZANNETH },
- { { 5088.49f, 2188.18f, 365.647f, 5.253f }, 0, BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_AHBRAMIS },
- { { 5095.67f, 2193.28f, 365.924f, 4.939f }, 0, BATTLEFIELD_WG_NPC_SIEGE_MASTER_STOUTHANDLE },
- { { 5088.61f, 2167.66f, 365.689f, 0.680f }, 0, BATTLEFIELD_WG_NPC_ANCHORITE_TESSA },
- { { 5080.40f, 2199.00f, 359.489f, 2.967f }, 0, BATTLEFIELD_WG_NPC_SENIOR_DEMOLITIONIST_LEGOSO },
-};
-
struct WintergraspGameObjectData
{
Position Pos;
@@ -551,7 +478,7 @@ bool BattlefieldWG::SetupBattlefield()
for (uint8 i = 0; i < WG_MAX_WORKSHOP; i++)
{
WintergraspWorkshop* workshop = new WintergraspWorkshop(this, i);
- if (i < BATTLEFIELD_WG_WORKSHOP_KEEP_WEST)
+ if (i < BATTLEFIELD_WG_WORKSHOP_NE)
workshop->GiveControlTo(GetAttackerTeam(), true);
else
workshop->GiveControlTo(GetDefenderTeam(), true);
@@ -560,38 +487,6 @@ bool BattlefieldWG::SetupBattlefield()
Workshops[i] = workshop;
}
- // Spawn NPCs in the defender's keep, both Horde and Alliance
- for (uint8 i = 0; i < WG_MAX_KEEP_NPC; ++i)
- {
- // Horde npc
- if (Creature* creature = SpawnCreature(WGKeepNPC[i].HordeEntry, WGKeepNPC[i].Pos))
- KeepCreature[TEAM_HORDE].push_back(creature->GetGUID());
-
- // Alliance npc
- if (Creature* creature = SpawnCreature(WGKeepNPC[i].AllianceEntry, WGKeepNPC[i].Pos))
- KeepCreature[TEAM_ALLIANCE].push_back(creature->GetGUID());
- }
-
- // Hide NPCs from the Attacker's team in the keep
- for (auto itr = KeepCreature[GetAttackerTeam()].begin(); itr != KeepCreature[GetAttackerTeam()].end(); ++itr)
- if (Creature* creature = GetCreature(*itr))
- HideNpc(creature);
-
- // Spawn Horde NPCs outside the keep
- for (uint8 i = 0; i < WG_OUTSIDE_ALLIANCE_NPC; ++i)
- if (Creature* creature = SpawnCreature(WGOutsideNPC[i].HordeEntry, WGOutsideNPC[i].Pos))
- OutsideCreature[TEAM_HORDE].push_back(creature->GetGUID());
-
- // Spawn Alliance NPCs outside the keep
- for (uint8 i = WG_OUTSIDE_ALLIANCE_NPC; i < WG_MAX_OUTSIDE_NPC; ++i)
- if (Creature* creature = SpawnCreature(WGOutsideNPC[i].AllianceEntry, WGOutsideNPC[i].Pos))
- OutsideCreature[TEAM_ALLIANCE].push_back(creature->GetGUID());
-
- // Hide units outside the keep that are defenders
- for (auto itr = OutsideCreature[GetDefenderTeam()].begin(); itr != OutsideCreature[GetDefenderTeam()].end(); ++itr)
- if (Creature* creature = GetCreature(*itr))
- HideNpc(creature);
-
// Spawn turrets and hide them per default
for (uint8 i = 0; i < WG_MAX_TURRET; i++)
{
@@ -667,7 +562,7 @@ void BattlefieldWG::OnBattleStart()
// Update faction of relic, only attacker can click on
relic->SetFaction(WintergraspFaction[GetAttackerTeam()]);
// Set in use (not allow to click on before last door is broken)
- relic->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
+ relic->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE | GO_FLAG_NOT_SELECTABLE);
m_titansRelicGUID = relic->GetGUID();
}
else
@@ -769,27 +664,6 @@ void BattlefieldWG::OnBattleEnd(bool endByTimer)
}
}
- if (!endByTimer) // One player triggered the relic
- {
- // Change all npc in keep
- for (auto itr = KeepCreature[GetAttackerTeam()].begin(); itr != KeepCreature[GetAttackerTeam()].end(); ++itr)
- if (Creature* creature = GetCreature(*itr))
- HideNpc(creature);
-
- for (auto itr = KeepCreature[GetDefenderTeam()].begin(); itr != KeepCreature[GetDefenderTeam()].end(); ++itr)
- if (Creature* creature = GetCreature(*itr))
- ShowNpc(creature, true);
-
- // Change all npc out of keep
- for (auto itr = OutsideCreature[GetDefenderTeam()].begin(); itr != OutsideCreature[GetDefenderTeam()].end(); ++itr)
- if (Creature* creature = GetCreature(*itr))
- HideNpc(creature);
-
- for (auto itr = OutsideCreature[GetAttackerTeam()].begin(); itr != OutsideCreature[GetAttackerTeam()].end(); ++itr)
- if (Creature* creature = GetCreature(*itr))
- ShowNpc(creature, true);
- }
-
// Update all graveyard, control is to defender when no wartime
for (uint8 i = 0; i < BATTLEFIELD_WG_GY_HORDE; i++)
if (BfGraveyard* graveyard = GetGraveyardById(i))
@@ -817,6 +691,9 @@ void BattlefieldWG::OnBattleEnd(bool endByTimer)
{
player->CastSpell(player, SPELL_ESSENCE_OF_WINTERGRASP, true);
player->CastSpell(player, SPELL_VICTORY_REWARD, true);
+ // Complete victory quests
+ player->AreaExploredOrEventHappens(QUEST_VICTORY_WINTERGRASP_A);
+ player->AreaExploredOrEventHappens(QUEST_VICTORY_WINTERGRASP_H);
// Send Wintergrasp victory achievement
DoCompleteOrIncrementAchievement(ACHIEVEMENTS_WIN_WG, player);
// Award achievement for succeeding in Wintergrasp in 10 minutes or less
@@ -1071,33 +948,9 @@ void BattlefieldWG::HandleKill(Player* killer, Unit* victim)
if (killer == victim)
return;
- bool again = false;
- TeamId killerTeam = killer->GetTeamId();
-
if (victim->GetTypeId() == TYPEID_PLAYER)
- {
- for (auto itr = m_PlayersInWar[killerTeam].begin(); itr != m_PlayersInWar[killerTeam].end(); ++itr)
- if (Player* player = ObjectAccessor::FindPlayer(*itr))
- if (player->GetDistance2d(killer) < 40)
- PromotePlayer(player);
- return;
- }
+ HandlePromotion(killer, victim);
- for (auto itr = KeepCreature[GetOtherTeam(killerTeam)].begin();
- itr != KeepCreature[GetOtherTeam(killerTeam)].end(); ++itr)
- {
- if (Creature* creature = GetCreature(*itr))
- {
- if (victim->GetEntry() == creature->GetEntry() && !again)
- {
- again = true;
- for (auto iter = m_PlayersInWar[killerTeam].begin(); iter != m_PlayersInWar[killerTeam].end(); ++iter)
- if (Player* player = ObjectAccessor::FindPlayer(*iter))
- if (player->GetDistance2d(killer) < 40.0f)
- PromotePlayer(player);
- }
- }
- }
/// @todoRecent PvP activity worldstate
}
@@ -1129,6 +982,16 @@ void BattlefieldWG::OnUnitDeath(Unit* unit)
UpdateVehicleCountWG();
}
+void BattlefieldWG::HandlePromotion(Player* playerKiller, Unit* unitKilled)
+{
+ uint32 teamId = playerKiller->GetTeamId();
+
+ for (auto iter = m_PlayersInWar[teamId].begin(); iter != m_PlayersInWar[teamId].end(); ++iter)
+ if (Player* player = ObjectAccessor::FindPlayer(*iter))
+ if (player->GetDistance2d(unitKilled) < 40.0f)
+ PromotePlayer(player);
+}
+
// Update rank for player
void BattlefieldWG::PromotePlayer(Player* killer)
{
@@ -1316,31 +1179,23 @@ void BattlefieldWG::SendInitWorldStatesToAll()
SendInitWorldStatesTo(player);
}
-void BattlefieldWG::BrokenWallOrTower(TeamId /*team*/)
-{
-/*
-uint32 const WGQuest[2][6] =
+void BattlefieldWG::BrokenWallOrTower(TeamId team, BfWGGameObjectBuilding* building)
{
- { 13186, 13181, 13222, 13538, 13177, 13179 },
- { 13185, 13183, 13223, 13539, 13178, 13180 },
-};
-*/
-
-// might be some use for this in the future. old code commented out below. KL
-/* if (team == GetDefenderTeam())
+ if (team == GetDefenderTeam())
{
- for (GuidSet::const_iterator itr = m_PlayersInWar[GetAttackerTeam()].begin(); itr != m_PlayersInWar[GetAttackerTeam()].end(); ++itr)
+ for (auto itr = m_PlayersInWar[GetAttackerTeam()].begin(); itr != m_PlayersInWar[GetAttackerTeam()].end(); ++itr)
{
if (Player* player = ObjectAccessor::FindPlayer(*itr))
- IncrementQuest(player, WGQuest[player->GetTeamId()][2], true);
+ if (player->GetDistance2d(GetGameObject(building->GetGUID())) < 50.0f)
+ player->KilledMonsterCredit(QUEST_CREDIT_DEFEND_SIEGE);
}
- }*/
+ }
}
// Called when a tower is broke
void BattlefieldWG::UpdatedDestroyedTowerCount(TeamId team)
{
- // Destroy an attack tower
+ // Southern tower
if (team == GetAttackerTeam())
{
// Update counter
@@ -1352,12 +1207,13 @@ void BattlefieldWG::UpdatedDestroyedTowerCount(TeamId team)
if (Player* player = ObjectAccessor::FindPlayer(*itr))
player->RemoveAuraFromStack(SPELL_TOWER_CONTROL);
- // Add buff stack to defenders
+ // Add buff stack to defenders and give achievement/quest credit
for (auto itr = m_PlayersInWar[GetDefenderTeam()].begin(); itr != m_PlayersInWar[GetDefenderTeam()].end(); ++itr)
{
if (Player* player = ObjectAccessor::FindPlayer(*itr))
{
player->CastSpell(player, SPELL_TOWER_CONTROL, true);
+ player->KilledMonsterCredit(QUEST_CREDIT_TOWERS_DESTROYED);
DoCompleteOrIncrementAchievement(ACHIEVEMENTS_WG_TOWER_DESTROY, player);
}
}
@@ -1372,7 +1228,7 @@ void BattlefieldWG::UpdatedDestroyedTowerCount(TeamId team)
SendInitWorldStatesToAll();
}
}
- else
+ else // Keep tower
{
UpdateData(BATTLEFIELD_WG_DATA_DAMAGED_TOWER_DEF, -1);
UpdateData(BATTLEFIELD_WG_DATA_BROKEN_TOWER_DEF, 1);
@@ -1620,7 +1476,7 @@ void BfWGGameObjectBuilding::Destroyed()
go->SetGoState(GO_STATE_ACTIVE);
_wg->SetRelicInteractible(true);
if (_wg->GetRelic())
- _wg->GetRelic()->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
+ _wg->GetRelic()->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE | GO_FLAG_NOT_SELECTABLE);
else
TC_LOG_ERROR("bg.battlefield.wg", "Titan Relic not found.");
break;
@@ -1628,7 +1484,7 @@ void BfWGGameObjectBuilding::Destroyed()
break;
}
- _wg->BrokenWallOrTower(_teamControl);
+ _wg->BrokenWallOrTower(_teamControl, this);
}
void BfWGGameObjectBuilding::Init(GameObject* go)
@@ -1952,8 +1808,8 @@ void WintergraspWorkshop::GiveControlTo(TeamId teamId, bool init /*= false*/)
void WintergraspWorkshop::UpdateGraveyardAndWorkshop()
{
- if (_staticInfo->WorkshopId < BATTLEFIELD_WG_WORKSHOP_KEEP_WEST)
- _wg->GetGraveyardById(_staticInfo->WorkshopId)->GiveControlTo(_teamControl);
+ if (_staticInfo->WorkshopId < BATTLEFIELD_WG_WORKSHOP_NE)
+ GiveControlTo(_wg->GetAttackerTeam(), true);
else
GiveControlTo(_wg->GetDefenderTeam(), true);
}
diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.h b/src/server/game/Battlefield/Zones/BattlefieldWG.h
index a357791468b..3bd719c1a60 100644
--- a/src/server/game/Battlefield/Zones/BattlefieldWG.h
+++ b/src/server/game/Battlefield/Zones/BattlefieldWG.h
@@ -150,6 +150,14 @@ enum WintergraspAreaIds
AREA_THE_CHILLED_QUAGMIRE = 4589
};
+enum WintergraspQuests
+{
+ QUEST_VICTORY_WINTERGRASP_A = 13181,
+ QUEST_VICTORY_WINTERGRASP_H = 13183,
+ QUEST_CREDIT_TOWERS_DESTROYED = 35074,
+ QUEST_CREDIT_DEFEND_SIEGE = 31284
+};
+
/*#########################
*####### Graveyards ######
*#########################*/
@@ -195,26 +203,6 @@ enum WintergraspNpcs
BATTLEFIELD_WG_NPC_GUARD_A = 30740,
BATTLEFIELD_WG_NPC_STALKER = 15214,
- BATTLEFIELD_WG_NPC_VIERON_BLAZEFEATHER = 31102,
- BATTLEFIELD_WG_NPC_STONE_GUARD_MUKAR = 32296, // <WINTERGRASP QUARTERMASTER>
- BATTLEFIELD_WG_NPC_HOODOO_MASTER_FU_JIN = 31101, // <MASTER HEXXER>
- BATTLEFIELD_WG_NPC_CHAMPION_ROS_SLAI = 39173, // <WINTERGRASP QUARTERMASTER>
- BATTLEFIELD_WG_NPC_COMMANDER_DARDOSH = 31091,
- BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_KILRATH = 31151,
- BATTLEFIELD_WG_NPC_SIEGESMITH_STRONGHOOF = 31106,
- BATTLEFIELD_WG_NPC_PRIMALIST_MULFORT = 31053,
- BATTLEFIELD_WG_NPC_LIEUTENANT_MURP = 31107,
-
- BATTLEFIELD_WG_NPC_BOWYER_RANDOLPH = 31052,
- BATTLEFIELD_WG_NPC_KNIGHT_DAMERON = 32294, // <WINTERGRASP QUARTERMASTER>
- BATTLEFIELD_WG_NPC_SORCERESS_KAYLANA = 31051, // <ENCHANTRESS>
- BATTLEFIELD_WG_NPC_MARSHAL_MAGRUDER = 39172, // <WINTERGRASP QUARTERMASTER>
- BATTLEFIELD_WG_NPC_COMMANDER_ZANNETH = 31036,
- BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_AHBRAMIS = 31153,
- BATTLEFIELD_WG_NPC_SIEGE_MASTER_STOUTHANDLE = 31108,
- BATTLEFIELD_WG_NPC_ANCHORITE_TESSA = 31054,
- BATTLEFIELD_WG_NPC_SENIOR_DEMOLITIONIST_LEGOSO = 31109,
-
NPC_TAUNKA_SPIRIT_GUIDE = 31841, // Horde spirit guide for Wintergrasp
NPC_DWARVEN_SPIRIT_GUIDE = 31842, // Alliance spirit guide for Wintergrasp
@@ -336,7 +324,7 @@ class TC_GAME_API BattlefieldWG : public Battlefield
* \brief Called when a wall/tower is broken
* - Update quest
*/
- void BrokenWallOrTower(TeamId team);
+ void BrokenWallOrTower(TeamId team, BfWGGameObjectBuilding* building);
/**
* \brief Called when a tower is damaged
@@ -381,6 +369,7 @@ class TC_GAME_API BattlefieldWG : public Battlefield
void HandleKill(Player* killer, Unit* victim) override;
void OnUnitDeath(Unit* unit) override;
+ void HandlePromotion(Player* killer, Unit* killed);
void PromotePlayer(Player* killer);
void UpdateTenacity();
@@ -403,8 +392,6 @@ class TC_GAME_API BattlefieldWG : public Battlefield
GuidUnorderedSet m_vehicles[BG_TEAMS_COUNT];
GuidVector CanonList;
- GuidVector KeepCreature[BG_TEAMS_COUNT];
- GuidVector OutsideCreature[BG_TEAMS_COUNT];
TeamId m_tenacityTeam;
uint32 m_tenacityStack;
@@ -450,10 +437,10 @@ enum WintergraspTowerIds
enum WintergraspWorkshopIds
{
- BATTLEFIELD_WG_WORKSHOP_NE,
- BATTLEFIELD_WG_WORKSHOP_NW,
BATTLEFIELD_WG_WORKSHOP_SE,
BATTLEFIELD_WG_WORKSHOP_SW,
+ BATTLEFIELD_WG_WORKSHOP_NE,
+ BATTLEFIELD_WG_WORKSHOP_NW,
BATTLEFIELD_WG_WORKSHOP_KEEP_WEST,
BATTLEFIELD_WG_WORKSHOP_KEEP_EAST
};
diff --git a/src/server/game/Battlegrounds/ArenaTeam.cpp b/src/server/game/Battlegrounds/ArenaTeam.cpp
index ec007df6b6c..f1747bc0d00 100644
--- a/src/server/game/Battlegrounds/ArenaTeam.cpp
+++ b/src/server/game/Battlegrounds/ArenaTeam.cpp
@@ -899,6 +899,10 @@ void ArenaTeam::SaveToDB()
for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
{
+ // Save the effort and go
+ if (itr->WeekGames == 0)
+ continue;
+
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ARENA_TEAM_MEMBER);
stmt->setUInt16(0, itr->PersonalRating);
stmt->setUInt16(1, itr->WeekGames);
@@ -919,8 +923,12 @@ void ArenaTeam::SaveToDB()
CharacterDatabase.CommitTransaction(trans);
}
-void ArenaTeam::FinishWeek()
+bool ArenaTeam::FinishWeek()
{
+ // No need to go further than this
+ if (Stats.WeekGames == 0)
+ return false;
+
// Reset team stats
Stats.WeekGames = 0;
Stats.WeekWins = 0;
@@ -931,6 +939,8 @@ void ArenaTeam::FinishWeek()
itr->WeekGames = 0;
itr->WeekWins = 0;
}
+
+ return true;
}
bool ArenaTeam::IsFighting() const
diff --git a/src/server/game/Battlegrounds/ArenaTeam.h b/src/server/game/Battlegrounds/ArenaTeam.h
index 7e9f490bff9..e283197346c 100644
--- a/src/server/game/Battlegrounds/ArenaTeam.h
+++ b/src/server/game/Battlegrounds/ArenaTeam.h
@@ -180,7 +180,7 @@ class TC_GAME_API ArenaTeam
void UpdateArenaPointsHelper(std::map<uint32, uint32> & PlayerPoints);
- void FinishWeek();
+ bool FinishWeek(); // returns true if arena team played this week
void FinishGame(int32 mod);
protected:
diff --git a/src/server/game/Battlegrounds/ArenaTeamMgr.cpp b/src/server/game/Battlegrounds/ArenaTeamMgr.cpp
index 37e26d7e448..6fe11e3bd8c 100644
--- a/src/server/game/Battlegrounds/ArenaTeamMgr.cpp
+++ b/src/server/game/Battlegrounds/ArenaTeamMgr.cpp
@@ -186,8 +186,9 @@ void ArenaTeamMgr::DistributeArenaPoints()
{
if (ArenaTeam* at = titr->second)
{
- at->FinishWeek();
- at->SaveToDB();
+ if (at->FinishWeek())
+ at->SaveToDB();
+
at->NotifyStatsChanged();
}
}
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp
index 2e66c587e15..2319a13233f 100644
--- a/src/server/game/Battlegrounds/Battleground.cpp
+++ b/src/server/game/Battlegrounds/Battleground.cpp
@@ -514,20 +514,15 @@ inline void Battleground::_ProcessJoin(uint32 diff)
if (!player->IsGameMaster())
{
// remove auras with duration lower than 30s
- Unit::AuraApplicationMap & auraMap = player->GetAppliedAuras();
- for (Unit::AuraApplicationMap::iterator iter = auraMap.begin(); iter != auraMap.end();)
+ player->RemoveAppliedAuras([](AuraApplication const* aurApp)
{
- AuraApplication * aurApp = iter->second;
Aura* aura = aurApp->GetBase();
- if (!aura->IsPermanent()
- && aura->GetDuration() <= 30*IN_MILLISECONDS
+ return !aura->IsPermanent()
+ && aura->GetDuration() <= 30 * IN_MILLISECONDS
&& aurApp->IsPositive()
- && (!aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
- && (!aura->HasEffectType(SPELL_AURA_MOD_INVISIBILITY)))
- player->RemoveAura(iter);
- else
- ++iter;
- }
+ && !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ && !aura->HasEffectType(SPELL_AURA_MOD_INVISIBILITY);
+ });
}
}
diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp
index 753d0f92ef3..1ae610ecf68 100644
--- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp
+++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp
@@ -843,7 +843,7 @@ void BattlegroundMgr::ScheduleQueueUpdate(uint32 arenaMatchmakerRating, uint8 ar
{
//This method must be atomic, @todo add mutex
//we will use only 1 number created of bgTypeId and bracket_id
- uint64 const scheduleId = ((uint64)arenaMatchmakerRating << 32) | (uint32(arenaType) << 24) | (bgQueueTypeId << 16) | (bgTypeId << 8) | bracket_id;
+ uint64 const scheduleId = ((uint64)arenaMatchmakerRating << 32) | ((uint64)arenaType << 24) | ((uint64)bgQueueTypeId << 16) | ((uint64)bgTypeId << 8) | (uint64)bracket_id;
if (std::find(m_QueueUpdateScheduler.begin(), m_QueueUpdateScheduler.end(), scheduleId) == m_QueueUpdateScheduler.end())
m_QueueUpdateScheduler.push_back(scheduleId);
}
diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp
index 22601b711d1..afaa0063a45 100644
--- a/src/server/game/Chat/Channels/Channel.cpp
+++ b/src/server/game/Chat/Channels/Channel.cpp
@@ -17,93 +17,124 @@
*/
#include "Channel.h"
+#include "ChannelAppenders.h"
#include "Chat.h"
+#include "GridNotifiers.h"
+#include "GridNotifiersImpl.h"
#include "ObjectMgr.h"
+#include "Language.h"
#include "SocialMgr.h"
#include "World.h"
#include "DatabaseEnv.h"
#include "AccountMgr.h"
#include "Player.h"
-Channel::Channel(std::string const& name, uint32 channelId, uint32 team /*= 0*/):
- _announceEnabled(true),
- _ownershipEnabled(true),
+Channel::Channel(uint32 channelId, uint32 team /*= 0*/, AreaTableEntry const* zoneEntry /*= nullptr*/) :
+ _announceEnabled(false), // no join/leave announces
+ _ownershipEnabled(false), // no ownership handout
_persistentChannel(false),
_isOwnerInvisible(false),
- _channelFlags(0),
+ _channelFlags(CHANNEL_FLAG_GENERAL), // for all built-in channels
_channelId(channelId),
_channelTeam(team),
_ownerGuid(),
- _channelName(name),
- _channelPassword()
+ _channelName(),
+ _channelPassword(),
+ _zoneEntry(zoneEntry)
{
- // set special flags if built-in channel
- if (ChatChannelsEntry const* ch = sChatChannelsStore.LookupEntry(channelId)) // check whether it's a built-in channel
- {
- _announceEnabled = false; // no join/leave announces
- _ownershipEnabled = false; // no ownership handout
+ ChatChannelsEntry const* channelEntry = sChatChannelsStore.AssertEntry(channelId);
+ if (channelEntry->flags & CHANNEL_DBC_FLAG_TRADE) // for trade channel
+ _channelFlags |= CHANNEL_FLAG_TRADE;
- _channelFlags |= CHANNEL_FLAG_GENERAL; // for all built-in channels
+ if (channelEntry->flags & CHANNEL_DBC_FLAG_CITY_ONLY2) // for city only channels
+ _channelFlags |= CHANNEL_FLAG_CITY;
- if (ch->flags & CHANNEL_DBC_FLAG_TRADE) // for trade channel
- _channelFlags |= CHANNEL_FLAG_TRADE;
-
- if (ch->flags & CHANNEL_DBC_FLAG_CITY_ONLY2) // for city only channels
- _channelFlags |= CHANNEL_FLAG_CITY;
+ if (channelEntry->flags & CHANNEL_DBC_FLAG_LFG) // for LFG channel
+ _channelFlags |= CHANNEL_FLAG_LFG;
+ else // for all other channels
+ _channelFlags |= CHANNEL_FLAG_NOT_LFG;
+}
- if (ch->flags & CHANNEL_DBC_FLAG_LFG) // for LFG channel
- _channelFlags |= CHANNEL_FLAG_LFG;
- else // for all other channels
- _channelFlags |= CHANNEL_FLAG_NOT_LFG;
- }
- else // it's custom channel
+Channel::Channel(std::string const& name, uint32 team /*= 0*/) :
+ _announceEnabled(true),
+ _ownershipEnabled(true),
+ _persistentChannel(false),
+ _isOwnerInvisible(false),
+ _channelFlags(CHANNEL_FLAG_CUSTOM),
+ _channelId(0),
+ _channelTeam(team),
+ _ownerGuid(),
+ _channelName(name),
+ _channelPassword(),
+ _zoneEntry(nullptr)
+{
+ // If storing custom channels in the db is enabled either load or save the channel
+ if (sWorld->getBoolConfig(CONFIG_PRESERVE_CUSTOM_CHANNELS))
{
- _channelFlags |= CHANNEL_FLAG_CUSTOM;
-
- // If storing custom channels in the db is enabled either load or save the channel
- if (sWorld->getBoolConfig(CONFIG_PRESERVE_CUSTOM_CHANNELS))
+ PreparedStatement *stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHANNEL);
+ stmt->setString(0, name);
+ stmt->setUInt32(1, _channelTeam);
+ if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) // load
{
- PreparedStatement *stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHANNEL);
- stmt->setString(0, name);
- stmt->setUInt32(1, _channelTeam);
- PreparedQueryResult result = CharacterDatabase.Query(stmt);
-
- if (result) //load
+ Field* fields = result->Fetch();
+ _channelName = fields[0].GetString(); // re-get channel name. MySQL table collation is case insensitive
+ _announceEnabled = fields[1].GetBool();
+ _ownershipEnabled = fields[2].GetBool();
+ _channelPassword = fields[3].GetString();
+ std::string db_BannedList = fields[4].GetString();
+
+ if (!db_BannedList.empty())
{
- Field* fields = result->Fetch();
- _announceEnabled = fields[0].GetBool();
- _ownershipEnabled = fields[1].GetBool();
- _channelPassword = fields[2].GetString();
- char const* db_BannedList = fields[3].GetCString();
-
- if (db_BannedList)
+ Tokenizer tokens(db_BannedList, ' ');
+ for (auto const& token : tokens)
{
- Tokenizer tokens(db_BannedList, ' ');
- for (Tokenizer::const_iterator i = tokens.begin(); i != tokens.end(); ++i)
+ ObjectGuid banned_guid(uint64(atoull(token)));
+ if (banned_guid)
{
- ObjectGuid banned_guid(uint64(atoull(*i)));
- if (banned_guid)
- {
- TC_LOG_DEBUG("chat.system", "Channel(%s) loaded bannedStore %s", name.c_str(), banned_guid.ToString().c_str());
- _bannedStore.insert(banned_guid);
- }
+ TC_LOG_DEBUG("chat.system", "Channel(%s) loaded player %s into bannedStore", name.c_str(), banned_guid.ToString().c_str());
+ _bannedStore.insert(banned_guid);
}
}
}
- else // save
- {
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHANNEL);
- stmt->setString(0, name);
- stmt->setUInt32(1, _channelTeam);
- CharacterDatabase.Execute(stmt);
- TC_LOG_DEBUG("chat.system", "Channel(%s) saved in database", name.c_str());
- }
+ }
+ else // save
+ {
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHANNEL);
+ stmt->setString(0, name);
+ stmt->setUInt32(1, _channelTeam);
+ CharacterDatabase.Execute(stmt);
+ TC_LOG_DEBUG("chat.system", "Channel(%s) saved in database", name.c_str());
+ }
- _persistentChannel = true;
+ _persistentChannel = true;
+ }
+}
+
+void Channel::GetChannelName(std::string& channelName, uint32 channelId, LocaleConstant locale, AreaTableEntry const* zoneEntry)
+{
+ if (channelId)
+ {
+ ChatChannelsEntry const* channelEntry = sChatChannelsStore.AssertEntry(channelId);
+ if (!(channelEntry->flags & CHANNEL_DBC_FLAG_GLOBAL))
+ {
+ if (channelEntry->flags & CHANNEL_DBC_FLAG_CITY_ONLY)
+ channelName = Trinity::StringFormat(channelEntry->pattern[locale], sObjectMgr->GetTrinityString(LANG_CHANNEL_CITY, locale));
+ else
+ channelName = Trinity::StringFormat(channelEntry->pattern[locale], ASSERT_NOTNULL(zoneEntry)->area_name[locale]);
}
+ else
+ channelName = channelEntry->pattern[locale];
}
}
+std::string Channel::GetName(LocaleConstant locale /*= DEFAULT_LOCALE*/) const
+{
+ std::string result = _channelName;
+ Channel::GetChannelName(result, _channelId, locale, _zoneEntry);
+
+ return result;
+}
+
void Channel::UpdateChannelInDB() const
{
if (_persistentChannel)
@@ -155,26 +186,26 @@ void Channel::JoinChannel(Player* player, std::string const& pass)
// Do not send error message for built-in channels
if (!IsConstant())
{
- WorldPacket data;
- MakePlayerAlreadyMember(&data, guid);
- SendToOne(&data, guid);
+ PlayerAlreadyMemberAppend appender(guid);
+ ChannelNameBuilder<PlayerAlreadyMemberAppend> builder(this, appender);
+ SendToOne(builder, guid);
}
return;
}
if (IsBanned(guid))
{
- WorldPacket data;
- MakeBanned(&data);
- SendToOne(&data, guid);
+ BannedAppend appender;
+ ChannelNameBuilder<BannedAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
if (!_channelPassword.empty() && pass != _channelPassword)
{
- WorldPacket data;
- MakeWrongPassword(&data);
- SendToOne(&data, guid);
+ WrongPasswordAppend appender;
+ ChannelNameBuilder<WrongPasswordAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
@@ -183,9 +214,9 @@ void Channel::JoinChannel(Player* player, std::string const& pass)
AccountMgr::IsPlayerAccount(player->GetSession()->GetSecurity()) && //FIXME: Move to RBAC
player->GetGroup())
{
- WorldPacket data;
- MakeNotInLfg(&data);
- SendToOne(&data, guid);
+ NotInLFGAppend appender;
+ ChannelNameBuilder<NotInLFGAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
@@ -193,9 +224,9 @@ void Channel::JoinChannel(Player* player, std::string const& pass)
if (_announceEnabled && !player->GetSession()->HasPermission(rbac::RBAC_PERM_SILENTLY_JOIN_CHANNEL))
{
- WorldPacket data;
- MakeJoined(&data, guid);
- SendToAll(&data);
+ JoinedAppend appender(guid);
+ ChannelNameBuilder<JoinedAppend> builder(this, appender);
+ SendToAll(builder);
}
bool newChannel = _playersStore.empty();
@@ -204,9 +235,9 @@ void Channel::JoinChannel(Player* player, std::string const& pass)
pinfo.flags = MEMBER_FLAG_NONE;
pinfo.invisible = !player->isGMVisible();
- WorldPacket data;
- MakeYouJoined(&data);
- SendToOne(&data, guid);
+ YouJoinedAppend appender(this);
+ ChannelNameBuilder<YouJoinedAppend> builder(this, appender);
+ SendToOne(builder, guid);
JoinNotify(guid);
@@ -236,20 +267,20 @@ void Channel::LeaveChannel(Player* player, bool send)
{
if (send)
{
- WorldPacket data;
- MakeNotMember(&data);
- SendToOne(&data, guid);
+ NotMemberAppend appender;
+ ChannelNameBuilder<NotMemberAppend> builder(this, appender);
+ SendToOne(builder, guid);
}
return;
}
if (send)
{
- WorldPacket data;
- MakeYouLeft(&data);
- SendToOne(&data, guid);
+ YouLeftAppend appender(this);
+ ChannelNameBuilder<YouLeftAppend> builder(this, appender);
+ SendToOne(builder, guid);
+
player->LeftChannel(this);
- data.clear();
}
PlayerInfo& info = _playersStore.at(guid);
@@ -258,9 +289,9 @@ void Channel::LeaveChannel(Player* player, bool send)
if (_announceEnabled && !player->GetSession()->HasPermission(rbac::RBAC_PERM_SILENTLY_JOIN_CHANNEL))
{
- WorldPacket data;
- MakeLeft(&data, guid);
- SendToAll(&data);
+ LeftAppend appender(guid);
+ ChannelNameBuilder<LeftAppend> builder(this, appender);
+ SendToAll(builder);
}
LeaveNotify(guid);
@@ -302,18 +333,18 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b
if (!IsOn(good))
{
- WorldPacket data;
- MakeNotMember(&data);
- SendToOne(&data, good);
+ NotMemberAppend appender;
+ ChannelNameBuilder<NotMemberAppend> builder(this, appender);
+ SendToOne(builder, good);
return;
}
PlayerInfo& info = _playersStore.at(good);
if (!info.IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR))
{
- WorldPacket data;
- MakeNotModerator(&data);
- SendToOne(&data, good);
+ NotModeratorAppend appender;
+ ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
+ SendToOne(builder, good);
return;
}
@@ -321,9 +352,9 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b
ObjectGuid victim = bad ? bad->GetGUID() : ObjectGuid::Empty;
if (!victim || !IsOn(victim))
{
- WorldPacket data;
- MakePlayerNotFound(&data, badname);
- SendToOne(&data, good);
+ PlayerNotFoundAppend appender(badname);
+ ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
+ SendToOne(builder, good);
return;
}
@@ -331,9 +362,9 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b
if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR) && changeowner && good != _ownerGuid)
{
- WorldPacket data;
- MakeNotOwner(&data);
- SendToOne(&data, good);
+ NotOwnerAppend appender;
+ ChannelNameBuilder<NotOwnerAppend> builder(this, appender);
+ SendToOne(builder, good);
return;
}
@@ -344,16 +375,16 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b
if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_SILENTLY_JOIN_CHANNEL))
{
- WorldPacket data;
- MakePlayerBanned(&data, victim, good);
- SendToAll(&data);
+ PlayerBannedAppend appender(good, victim);
+ ChannelNameBuilder<PlayerBannedAppend> builder(this, appender);
+ SendToAll(builder);
}
}
else if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_SILENTLY_JOIN_CHANNEL))
{
- WorldPacket data;
- MakePlayerKicked(&data, victim, good);
- SendToAll(&data);
+ PlayerKickedAppend appender(good, victim);
+ ChannelNameBuilder<PlayerKickedAppend> builder(this, appender);
+ SendToAll(builder);
}
_playersStore.erase(victim);
@@ -373,18 +404,18 @@ void Channel::UnBan(Player const* player, std::string const& badname)
if (!IsOn(good))
{
- WorldPacket data;
- MakeNotMember(&data);
- SendToOne(&data, good);
+ NotMemberAppend appender;
+ ChannelNameBuilder<NotMemberAppend> builder(this, appender);
+ SendToOne(builder, good);
return;
}
PlayerInfo& info = _playersStore.at(good);
if (!info.IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR))
{
- WorldPacket data;
- MakeNotModerator(&data);
- SendToOne(&data, good);
+ NotModeratorAppend appender;
+ ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
+ SendToOne(builder, good);
return;
}
@@ -393,17 +424,17 @@ void Channel::UnBan(Player const* player, std::string const& badname)
if (!victim || !IsBanned(victim))
{
- WorldPacket data;
- MakePlayerNotFound(&data, badname);
- SendToOne(&data, good);
+ PlayerNotFoundAppend appender(badname);
+ ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
+ SendToOne(builder, good);
return;
}
_bannedStore.erase(victim);
- WorldPacket data;
- MakePlayerUnbanned(&data, victim, good);
- SendToAll(&data);
+ PlayerUnbannedAppend appender(good, victim);
+ ChannelNameBuilder<PlayerUnbannedAppend> builder(this, appender);
+ SendToAll(builder);
UpdateChannelInDB();
}
@@ -415,26 +446,26 @@ void Channel::Password(Player const* player, std::string const& pass)
ChatHandler chat(player->GetSession());
if (!IsOn(guid))
{
- WorldPacket data;
- MakeNotMember(&data);
- SendToOne(&data, guid);
+ NotMemberAppend appender;
+ ChannelNameBuilder<NotMemberAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
PlayerInfo& info = _playersStore.at(guid);
if (!info.IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR))
{
- WorldPacket data;
- MakeNotModerator(&data);
- SendToOne(&data, guid);
+ NotModeratorAppend appender;
+ ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
_channelPassword = pass;
- WorldPacket data;
- MakePasswordChanged(&data, guid);
- SendToAll(&data);
+ PasswordChangedAppend appender(guid);
+ ChannelNameBuilder<PasswordChangedAppend> builder(this, appender);
+ SendToAll(builder);
UpdateChannelInDB();
}
@@ -445,18 +476,18 @@ void Channel::SetMode(Player const* player, std::string const& p2n, bool mod, bo
if (!IsOn(guid))
{
- WorldPacket data;
- MakeNotMember(&data);
- SendToOne(&data, guid);
+ NotMemberAppend appender;
+ ChannelNameBuilder<NotMemberAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
PlayerInfo& info = _playersStore.at(guid);
if (!info.IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR))
{
- WorldPacket data;
- MakeNotModerator(&data);
- SendToOne(&data, guid);
+ NotModeratorAppend appender;
+ ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
@@ -471,17 +502,17 @@ void Channel::SetMode(Player const* player, std::string const& p2n, bool mod, bo
(!player->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL) ||
!newp->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL))))
{
- WorldPacket data;
- MakePlayerNotFound(&data, p2n);
- SendToOne(&data, guid);
+ PlayerNotFoundAppend appender(p2n);
+ ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
if (_ownerGuid == victim && _ownerGuid != guid)
{
- WorldPacket data;
- MakeNotOwner(&data);
- SendToOne(&data, guid);
+ NotOwnerAppend appender;
+ ChannelNameBuilder<NotOwnerAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
@@ -504,23 +535,57 @@ void Channel::SetInvisible(Player const* player, bool on)
_isOwnerInvisible = on;
}
+void Channel::SetModerator(ObjectGuid guid, bool set)
+{
+ if (!IsOn(guid))
+ return;
+
+ PlayerInfo& playerInfo = _playersStore.at(guid);
+ if (playerInfo.IsModerator() != set)
+ {
+ uint8 oldFlag = GetPlayerFlags(guid);
+ playerInfo.SetModerator(set);
+
+ ModeChangeAppend appender(guid, oldFlag, GetPlayerFlags(guid));
+ ChannelNameBuilder<ModeChangeAppend> builder(this, appender);
+ SendToAll(builder);
+ }
+}
+
+void Channel::SetMute(ObjectGuid guid, bool set)
+{
+ if (!IsOn(guid))
+ return;
+
+ PlayerInfo& playerInfo = _playersStore.at(guid);
+ if (playerInfo.IsMuted() != set)
+ {
+ uint8 oldFlag = GetPlayerFlags(guid);
+ playerInfo.SetMuted(set);
+
+ ModeChangeAppend appender(guid, oldFlag, GetPlayerFlags(guid));
+ ChannelNameBuilder<ModeChangeAppend> builder(this, appender);
+ SendToAll(builder);
+ }
+}
+
void Channel::SetOwner(Player const* player, std::string const& newname)
{
ObjectGuid guid = player->GetGUID();
if (!IsOn(guid))
{
- WorldPacket data;
- MakeNotMember(&data);
- SendToOne(&data, guid);
+ NotMemberAppend appender;
+ ChannelNameBuilder<NotMemberAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR) && guid != _ownerGuid)
{
- WorldPacket data;
- MakeNotOwner(&data);
- SendToOne(&data, guid);
+ NotOwnerAppend appender;
+ ChannelNameBuilder<NotOwnerAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
@@ -532,9 +597,9 @@ void Channel::SetOwner(Player const* player, std::string const& newname)
(!player->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL) ||
!newp->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL))))
{
- WorldPacket data;
- MakePlayerNotFound(&data, newname);
- SendToOne(&data, guid);
+ PlayerNotFoundAppend appender(newname);
+ ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
@@ -545,12 +610,18 @@ void Channel::SetOwner(Player const* player, std::string const& newname)
void Channel::SendWhoOwner(ObjectGuid guid)
{
- WorldPacket data;
if (IsOn(guid))
- MakeChannelOwner(&data);
+ {
+ ChannelOwnerAppend appender(this, _ownerGuid);
+ ChannelNameBuilder<ChannelOwnerAppend> builder(this, appender);
+ SendToOne(builder, guid);
+ }
else
- MakeNotMember(&data);
- SendToOne(&data, guid);
+ {
+ NotMemberAppend appender;
+ ChannelNameBuilder<NotMemberAppend> builder(this, appender);
+ SendToOne(builder, guid);
+ }
}
void Channel::List(Player const* player) const
@@ -559,18 +630,19 @@ void Channel::List(Player const* player) const
if (!IsOn(guid))
{
- WorldPacket data;
- MakeNotMember(&data);
- SendToOne(&data, guid);
+ NotMemberAppend appender;
+ ChannelNameBuilder<NotMemberAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
+ std::string channelName = GetName(player->GetSession()->GetSessionDbcLocale());
TC_LOG_DEBUG("chat.system", "SMSG_CHANNEL_LIST %s Channel: %s",
- player->GetSession()->GetPlayerInfo().c_str(), GetName().c_str());
+ player->GetSession()->GetPlayerInfo().c_str(), channelName.c_str());
- WorldPacket data(SMSG_CHANNEL_LIST, 1+(GetName().size()+1)+1+4+_playersStore.size()*(8+1));
+ WorldPacket data(SMSG_CHANNEL_LIST, 1 + (channelName.size() + 1) + 1 + 4 + _playersStore.size() * (8 + 1));
data << uint8(1); // channel type?
- data << GetName(); // channel name
+ data << channelName; // channel name
data << uint8(GetFlags()); // channel flags?
size_t pos = data.wpos();
@@ -597,8 +669,7 @@ void Channel::List(Player const* player) const
}
data.put<uint32>(pos, count);
-
- SendToOne(&data, guid);
+ player->SendDirectMessage(&data);
}
void Channel::Announce(Player const* player)
@@ -607,29 +678,35 @@ void Channel::Announce(Player const* player)
if (!IsOn(guid))
{
- WorldPacket data;
- MakeNotMember(&data);
- SendToOne(&data, guid);
+ NotMemberAppend appender;
+ ChannelNameBuilder<NotMemberAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
PlayerInfo& info = _playersStore.at(guid);
if (!info.IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR))
{
- WorldPacket data;
- MakeNotModerator(&data);
- SendToOne(&data, guid);
+ NotModeratorAppend appender;
+ ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
_announceEnabled = !_announceEnabled;
- WorldPacket data;
if (_announceEnabled)
- MakeAnnouncementsOn(&data, guid);
+ {
+ AnnouncementsOnAppend appender(guid);
+ ChannelNameBuilder<AnnouncementsOnAppend> builder(this, appender);
+ SendToAll(builder);
+ }
else
- MakeAnnouncementsOff(&data, guid);
- SendToAll(&data);
+ {
+ AnnouncementsOffAppend appender(guid);
+ ChannelNameBuilder<AnnouncementsOffAppend> builder(this, appender);
+ SendToAll(builder);
+ }
UpdateChannelInDB();
}
@@ -645,28 +722,32 @@ void Channel::Say(ObjectGuid guid, std::string const& what, uint32 lang) const
if (!IsOn(guid))
{
- WorldPacket data;
- MakeNotMember(&data);
- SendToOne(&data, guid);
+ NotMemberAppend appender;
+ ChannelNameBuilder<NotMemberAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
PlayerInfo const& info = _playersStore.at(guid);
if (info.IsMuted())
{
- WorldPacket data;
- MakeMuted(&data);
- SendToOne(&data, guid);
+ MutedAppend appender;
+ ChannelNameBuilder<MutedAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
- WorldPacket data;
- if (Player* player = ObjectAccessor::FindConnectedPlayer(guid))
- ChatHandler::BuildChatPacket(data, CHAT_MSG_CHANNEL, Language(lang), player, player, what, 0, _channelName);
- else
- ChatHandler::BuildChatPacket(data, CHAT_MSG_CHANNEL, Language(lang), guid, guid, what, 0, "", "", 0, false, _channelName);
+ auto builder = [&](WorldPacket& data, LocaleConstant locale)
+ {
+ LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
+
+ if (Player* player = ObjectAccessor::FindConnectedPlayer(guid))
+ ChatHandler::BuildChatPacket(data, CHAT_MSG_CHANNEL, Language(lang), player, player, what, 0, GetName(localeIdx));
+ else
+ ChatHandler::BuildChatPacket(data, CHAT_MSG_CHANNEL, Language(lang), guid, guid, what, 0, "", "", 0, false, GetName(localeIdx));
+ };
- SendToAll(&data, !info.IsModerator() ? guid : ObjectGuid::Empty);
+ SendToAll(builder, !info.IsModerator() ? guid : ObjectGuid::Empty);
}
void Channel::Invite(Player const* player, std::string const& newname)
@@ -675,26 +756,26 @@ void Channel::Invite(Player const* player, std::string const& newname)
if (!IsOn(guid))
{
- WorldPacket data;
- MakeNotMember(&data);
- SendToOne(&data, guid);
+ NotMemberAppend appender;
+ ChannelNameBuilder<NotMemberAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
Player* newp = ObjectAccessor::FindConnectedPlayerByName(newname);
if (!newp || !newp->isGMVisible())
{
- WorldPacket data;
- MakePlayerNotFound(&data, newname);
- SendToOne(&data, guid);
+ PlayerNotFoundAppend appender(newname);
+ ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
if (IsBanned(newp->GetGUID()))
{
- WorldPacket data;
- MakePlayerInviteBanned(&data, newname);
- SendToOne(&data, guid);
+ PlayerInviteBannedAppend appender(newname);
+ ChannelNameBuilder<PlayerInviteBannedAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
@@ -702,31 +783,30 @@ void Channel::Invite(Player const* player, std::string const& newname)
(!player->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL) ||
!newp->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL)))
{
- WorldPacket data;
- MakeInviteWrongFaction(&data);
- SendToOne(&data, guid);
+ InviteWrongFactionAppend appender;
+ ChannelNameBuilder<InviteWrongFactionAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
if (IsOn(newp->GetGUID()))
{
- WorldPacket data;
- MakePlayerAlreadyMember(&data, newp->GetGUID());
- SendToOne(&data, guid);
+ PlayerAlreadyMemberAppend appender(newp->GetGUID());
+ ChannelNameBuilder<PlayerAlreadyMemberAppend> builder(this, appender);
+ SendToOne(builder, guid);
return;
}
if (!newp->GetSocial()->HasIgnore(guid.GetCounter()))
{
- WorldPacket data;
- MakeInvite(&data, guid);
- SendToOne(&data, newp->GetGUID());
- data.clear();
+ InviteAppend appender(guid);
+ ChannelNameBuilder<InviteAppend> builder(this, appender);
+ SendToOne(builder, newp->GetGUID());
}
- WorldPacket data;
- MakePlayerInvited(&data, newp->GetName());
- SendToOne(&data, guid);
+ PlayerInvitedAppend appender(newp->GetName());
+ ChannelNameBuilder<PlayerInvitedAppend> builder(this, appender);
+ SendToOne(builder, guid);
}
void Channel::SetOwner(ObjectGuid guid, bool exclaim)
@@ -749,42 +829,21 @@ void Channel::SetOwner(ObjectGuid guid, bool exclaim)
itr->second.SetModerator(true);
itr->second.SetOwner(true);
- WorldPacket data;
- MakeModeChange(&data, _ownerGuid, oldFlag);
- SendToAll(&data);
+ ModeChangeAppend appender(_ownerGuid, oldFlag, GetPlayerFlags(_ownerGuid));
+ ChannelNameBuilder<ModeChangeAppend> builder(this, appender);
+ SendToAll(builder);
if (exclaim)
{
- MakeOwnerChanged(&data, _ownerGuid);
- SendToAll(&data);
+ OwnerChangedAppend appender(_ownerGuid);
+ ChannelNameBuilder<OwnerChangedAppend> builder(this, appender);
+ SendToAll(builder);
}
UpdateChannelInDB();
}
}
-void Channel::SendToAll(WorldPacket* data, ObjectGuid guid) const
-{
- for (PlayerContainer::const_iterator i = _playersStore.begin(); i != _playersStore.end(); ++i)
- if (Player* player = ObjectAccessor::FindConnectedPlayer(i->first))
- if (!guid || !player->GetSocial()->HasIgnore(guid.GetCounter()))
- player->GetSession()->SendPacket(data);
-}
-
-void Channel::SendToAllButOne(WorldPacket* data, ObjectGuid who) const
-{
- for (PlayerContainer::const_iterator i = _playersStore.begin(); i != _playersStore.end(); ++i)
- if (i->first != who)
- if (Player* player = ObjectAccessor::FindConnectedPlayer(i->first))
- player->GetSession()->SendPacket(data);
-}
-
-void Channel::SendToOne(WorldPacket* data, ObjectGuid who) const
-{
- if (Player* player = ObjectAccessor::FindConnectedPlayer(who))
- player->GetSession()->SendPacket(data);
-}
-
void Channel::Voice(ObjectGuid /*guid1*/, ObjectGuid /*guid2*/) const
{
@@ -795,245 +854,72 @@ void Channel::DeVoice(ObjectGuid /*guid1*/, ObjectGuid /*guid2*/) const
}
-void Channel::MakeNotifyPacket(WorldPacket* data, uint8 notify_type) const
-{
- data->Initialize(SMSG_CHANNEL_NOTIFY, 1 + _channelName.size());
- *data << uint8(notify_type);
- *data << _channelName;
-}
-
-void Channel::MakeJoined(WorldPacket* data, ObjectGuid guid) const
-{
- MakeNotifyPacket(data, CHAT_JOINED_NOTICE);
- *data << uint64(guid);
-}
-
-void Channel::MakeLeft(WorldPacket* data, ObjectGuid guid) const
-{
- MakeNotifyPacket(data, CHAT_LEFT_NOTICE);
- *data << uint64(guid);
-}
-
-void Channel::MakeYouJoined(WorldPacket* data) const
-{
- MakeNotifyPacket(data, CHAT_YOU_JOINED_NOTICE);
- *data << uint8(GetFlags());
- *data << uint32(GetChannelId());
- *data << uint32(0);
-}
-
-void Channel::MakeYouLeft(WorldPacket* data) const
-{
- MakeNotifyPacket(data, CHAT_YOU_LEFT_NOTICE);
- *data << uint32(GetChannelId());
- *data << uint8(IsConstant());
-}
-
-void Channel::MakeWrongPassword(WorldPacket* data) const
-{
- MakeNotifyPacket(data, CHAT_WRONG_PASSWORD_NOTICE);
-}
-
-void Channel::MakeNotMember(WorldPacket* data) const
-{
- MakeNotifyPacket(data, CHAT_NOT_MEMBER_NOTICE);
-}
-
-void Channel::MakeNotModerator(WorldPacket* data) const
-{
- MakeNotifyPacket(data, CHAT_NOT_MODERATOR_NOTICE);
-}
-
-void Channel::MakePasswordChanged(WorldPacket* data, ObjectGuid guid) const
-{
- MakeNotifyPacket(data, CHAT_PASSWORD_CHANGED_NOTICE);
- *data << uint64(guid);
-}
-
-void Channel::MakeOwnerChanged(WorldPacket* data, ObjectGuid guid) const
-{
- MakeNotifyPacket(data, CHAT_OWNER_CHANGED_NOTICE);
- *data << uint64(guid);
-}
-
-void Channel::MakePlayerNotFound(WorldPacket* data, std::string const& name) const
-{
- MakeNotifyPacket(data, CHAT_PLAYER_NOT_FOUND_NOTICE);
- *data << name;
-}
-
-void Channel::MakeNotOwner(WorldPacket* data) const
+void Channel::JoinNotify(ObjectGuid guid) const
{
- MakeNotifyPacket(data, CHAT_NOT_OWNER_NOTICE);
-}
+ auto builder = [&](WorldPacket& data, LocaleConstant locale)
+ {
+ LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
-void Channel::MakeChannelOwner(WorldPacket* data) const
-{
- std::string name;
+ data.Initialize(IsConstant() ? SMSG_USERLIST_ADD : SMSG_USERLIST_UPDATE, 8 + 1 + 1 + 4 + 30 /*channelName buffer*/);
+ data << uint64(guid);
+ data << uint8(GetPlayerFlags(guid));
+ data << uint8(GetFlags());
+ data << uint32(GetNumPlayers());
+ data << GetName(localeIdx);
+ };
- CharacterInfo const* cInfo = sWorld->GetCharacterInfo(_ownerGuid);
- if (!cInfo || cInfo->Name.empty())
- name = "PLAYER_NOT_FOUND";
+ if (IsConstant())
+ SendToAllButOne(builder, guid);
else
- name = cInfo->Name;
-
- MakeNotifyPacket(data, CHAT_CHANNEL_OWNER_NOTICE);
- *data << ((IsConstant() || !_ownerGuid) ? "Nobody" : name);
-}
-
-void Channel::MakeModeChange(WorldPacket* data, ObjectGuid guid, uint8 oldflags) const
-{
- MakeNotifyPacket(data, CHAT_MODE_CHANGE_NOTICE);
- *data << uint64(guid);
- *data << uint8(oldflags);
- *data << uint8(GetPlayerFlags(guid));
-}
-
-void Channel::MakeAnnouncementsOn(WorldPacket* data, ObjectGuid guid) const
-{
- MakeNotifyPacket(data, CHAT_ANNOUNCEMENTS_ON_NOTICE);
- *data << uint64(guid);
-}
-
-void Channel::MakeAnnouncementsOff(WorldPacket* data, ObjectGuid guid) const
-{
- MakeNotifyPacket(data, CHAT_ANNOUNCEMENTS_OFF_NOTICE);
- *data << uint64(guid);
-}
-
-void Channel::MakeMuted(WorldPacket* data) const
-{
- MakeNotifyPacket(data, CHAT_MUTED_NOTICE);
-}
-
-void Channel::MakePlayerKicked(WorldPacket* data, ObjectGuid bad, ObjectGuid good) const
-{
- MakeNotifyPacket(data, CHAT_PLAYER_KICKED_NOTICE);
- *data << uint64(bad);
- *data << uint64(good);
-}
-
-void Channel::MakeBanned(WorldPacket* data) const
-{
- MakeNotifyPacket(data, CHAT_BANNED_NOTICE);
-}
-
-void Channel::MakePlayerBanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good) const
-{
- MakeNotifyPacket(data, CHAT_PLAYER_BANNED_NOTICE);
- *data << uint64(bad);
- *data << uint64(good);
-}
-
-void Channel::MakePlayerUnbanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good) const
-{
- MakeNotifyPacket(data, CHAT_PLAYER_UNBANNED_NOTICE);
- *data << uint64(bad);
- *data << uint64(good);
-}
-
-void Channel::MakePlayerNotBanned(WorldPacket* data, const std::string &name) const
-{
- MakeNotifyPacket(data, CHAT_PLAYER_NOT_BANNED_NOTICE);
- *data << name;
+ SendToAll(builder);
}
-void Channel::MakePlayerAlreadyMember(WorldPacket* data, ObjectGuid guid) const
-{
- MakeNotifyPacket(data, CHAT_PLAYER_ALREADY_MEMBER_NOTICE);
- *data << uint64(guid);
-}
-
-void Channel::MakeInvite(WorldPacket* data, ObjectGuid guid) const
-{
- MakeNotifyPacket(data, CHAT_INVITE_NOTICE);
- *data << uint64(guid);
-}
-
-void Channel::MakeInviteWrongFaction(WorldPacket* data) const
-{
- MakeNotifyPacket(data, CHAT_INVITE_WRONG_FACTION_NOTICE);
-}
-
-void Channel::MakeWrongFaction(WorldPacket* data) const
-{
- MakeNotifyPacket(data, CHAT_WRONG_FACTION_NOTICE);
-}
-
-void Channel::MakeInvalidName(WorldPacket* data) const
-{
- MakeNotifyPacket(data, CHAT_INVALID_NAME_NOTICE);
-}
-
-void Channel::MakeNotModerated(WorldPacket* data) const
-{
- MakeNotifyPacket(data, CHAT_NOT_MODERATED_NOTICE);
-}
-
-void Channel::MakePlayerInvited(WorldPacket* data, std::string const& name) const
-{
- MakeNotifyPacket(data, CHAT_PLAYER_INVITED_NOTICE);
- *data << name;
-}
-
-void Channel::MakePlayerInviteBanned(WorldPacket* data, std::string const& name) const
-{
- MakeNotifyPacket(data, CHAT_PLAYER_INVITE_BANNED_NOTICE);
- *data << name;
-}
-
-void Channel::MakeThrottled(WorldPacket* data) const
+void Channel::LeaveNotify(ObjectGuid guid) const
{
- MakeNotifyPacket(data, CHAT_THROTTLED_NOTICE);
-}
+ auto builder = [&](WorldPacket& data, LocaleConstant locale)
+ {
+ LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
-void Channel::MakeNotInArea(WorldPacket* data) const
-{
- MakeNotifyPacket(data, CHAT_NOT_IN_AREA_NOTICE);
-}
+ data.Initialize(SMSG_USERLIST_REMOVE, 8 + 1 + 4 + 30 /*channelName buffer*/);
+ data << uint64(guid);
+ data << uint8(GetFlags());
+ data << uint32(GetNumPlayers());
+ data << GetName(localeIdx);
+ };
-void Channel::MakeNotInLfg(WorldPacket* data) const
-{
- MakeNotifyPacket(data, CHAT_NOT_IN_LFG_NOTICE);
+ if (IsConstant())
+ SendToAllButOne(builder, guid);
+ else
+ SendToAll(builder);
}
-void Channel::MakeVoiceOn(WorldPacket* data, ObjectGuid guid) const
+template<class Builder>
+void Channel::SendToAll(Builder& builder, ObjectGuid guid /*= ObjectGuid::Empty*/) const
{
- MakeNotifyPacket(data, CHAT_VOICE_ON_NOTICE);
- *data << uint64(guid);
-}
+ Trinity::LocalizedPacketDo<Builder> localizer(builder);
-void Channel::MakeVoiceOff(WorldPacket* data, ObjectGuid guid) const
-{
- MakeNotifyPacket(data, CHAT_VOICE_OFF_NOTICE);
- *data << uint64(guid);
+ for (PlayerContainer::const_iterator i = _playersStore.begin(); i != _playersStore.end(); ++i)
+ if (Player* player = ObjectAccessor::FindConnectedPlayer(i->first))
+ if (!guid || !player->GetSocial()->HasIgnore(guid.GetCounter()))
+ localizer(player);
}
-void Channel::JoinNotify(ObjectGuid guid) const
+template<class Builder>
+void Channel::SendToAllButOne(Builder& builder, ObjectGuid who) const
{
- WorldPacket data(IsConstant() ? SMSG_USERLIST_ADD : SMSG_USERLIST_UPDATE, 8 + 1 + 1 + 4 + GetName().size());
- data << uint64(guid);
- data << uint8(GetPlayerFlags(guid));
- data << uint8(GetFlags());
- data << uint32(GetNumPlayers());
- data << GetName();
+ Trinity::LocalizedPacketDo<Builder> localizer(builder);
- if (IsConstant())
- SendToAllButOne(&data, guid);
- else
- SendToAll(&data);
+ for (PlayerContainer::const_iterator i = _playersStore.begin(); i != _playersStore.end(); ++i)
+ if (i->first != who)
+ if (Player* player = ObjectAccessor::FindConnectedPlayer(i->first))
+ localizer(player);
}
-void Channel::LeaveNotify(ObjectGuid guid) const
+template<class Builder>
+void Channel::SendToOne(Builder& builder, ObjectGuid who) const
{
- WorldPacket data(SMSG_USERLIST_REMOVE, 8 + 1 + 4 + GetName().size());
- data << uint64(guid);
- data << uint8(GetFlags());
- data << uint32(GetNumPlayers());
- data << GetName();
+ Trinity::LocalizedPacketDo<Builder> localizer(builder);
- if (IsConstant())
- SendToAllButOne(&data, guid);
- else
- SendToAll(&data);
+ if (Player* player = ObjectAccessor::FindConnectedPlayer(who))
+ localizer(player);
}
diff --git a/src/server/game/Chat/Channels/Channel.h b/src/server/game/Chat/Channels/Channel.h
index 4859a984967..8c01a474854 100644
--- a/src/server/game/Chat/Channels/Channel.h
+++ b/src/server/game/Chat/Channels/Channel.h
@@ -150,9 +150,11 @@ class TC_GAME_API Channel
};
public:
- Channel(std::string const& name, uint32 channel_id, uint32 team = 0);
+ Channel(uint32 channelId, uint32 team = 0, AreaTableEntry const* zoneEntry = nullptr); // built-in channel ctor
+ Channel(std::string const& name, uint32 team = 0); // custom player channel ctor
- std::string const& GetName() const { return _channelName; }
+ static void GetChannelName(std::string& channelName, uint32 channelId, LocaleConstant locale, AreaTableEntry const* zoneEntry);
+ std::string GetName(LocaleConstant locale = DEFAULT_LOCALE) const;
uint32 GetChannelId() const { return _channelId; }
bool IsConstant() const { return _channelId != 0; }
@@ -169,6 +171,8 @@ class TC_GAME_API Channel
uint8 GetFlags() const { return _channelFlags; }
bool HasFlag(uint8 flag) const { return (_channelFlags & flag) != 0; }
+ AreaTableEntry const* GetZoneEntry() const { return _zoneEntry; }
+
void JoinChannel(Player* player, std::string const& pass);
void LeaveChannel(Player* player, bool send = true);
@@ -203,47 +207,15 @@ class TC_GAME_API Channel
static void CleanOldChannelsInDB();
private:
- // initial packet data (notify type and channel name)
- void MakeNotifyPacket(WorldPacket* data, uint8 notify_type) const;
- // type specific packet data
- void MakeJoined(WorldPacket* data, ObjectGuid guid) const; //+ 0x00
- void MakeLeft(WorldPacket* data, ObjectGuid guid) const; //+ 0x01
- void MakeYouJoined(WorldPacket* data) const; //+ 0x02
- void MakeYouLeft(WorldPacket* data) const; //+ 0x03
- void MakeWrongPassword(WorldPacket* data) const; //? 0x04
- void MakeNotMember(WorldPacket* data) const; //? 0x05
- void MakeNotModerator(WorldPacket* data) const; //? 0x06
- void MakePasswordChanged(WorldPacket* data, ObjectGuid guid) const; //+ 0x07
- void MakeOwnerChanged(WorldPacket* data, ObjectGuid guid) const; //? 0x08
- void MakePlayerNotFound(WorldPacket* data, std::string const& name) const; //+ 0x09
- void MakeNotOwner(WorldPacket* data) const; //? 0x0A
- void MakeChannelOwner(WorldPacket* data) const; //? 0x0B
- void MakeModeChange(WorldPacket* data, ObjectGuid guid, uint8 oldflags) const; //+ 0x0C
- void MakeAnnouncementsOn(WorldPacket* data, ObjectGuid guid) const; //+ 0x0D
- void MakeAnnouncementsOff(WorldPacket* data, ObjectGuid guid) const; //+ 0x0E
- void MakeMuted(WorldPacket* data) const; //? 0x11
- void MakePlayerKicked(WorldPacket* data, ObjectGuid bad, ObjectGuid good) const; //? 0x12
- void MakeBanned(WorldPacket* data) const; //? 0x13
- void MakePlayerBanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good) const; //? 0x14
- void MakePlayerUnbanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good) const; //? 0x15
- void MakePlayerNotBanned(WorldPacket* data, std::string const& name) const; //? 0x16
- void MakePlayerAlreadyMember(WorldPacket* data, ObjectGuid guid) const; //+ 0x17
- void MakeInvite(WorldPacket* data, ObjectGuid guid) const; //? 0x18
- void MakeInviteWrongFaction(WorldPacket* data) const; //? 0x19
- void MakeWrongFaction(WorldPacket* data) const; //? 0x1A
- void MakeInvalidName(WorldPacket* data) const; //? 0x1B
- void MakeNotModerated(WorldPacket* data) const; //? 0x1C
- void MakePlayerInvited(WorldPacket* data, std::string const& name) const; //+ 0x1D
- void MakePlayerInviteBanned(WorldPacket* data, std::string const& name) const; //? 0x1E
- void MakeThrottled(WorldPacket* data) const; //? 0x1F
- void MakeNotInArea(WorldPacket* data) const; //? 0x20
- void MakeNotInLfg(WorldPacket* data) const; //? 0x21
- void MakeVoiceOn(WorldPacket* data, ObjectGuid guid) const; //+ 0x22
- void MakeVoiceOff(WorldPacket* data, ObjectGuid guid) const; //+ 0x23
-
- void SendToAll(WorldPacket* data, ObjectGuid guid = ObjectGuid::Empty) const;
- void SendToAllButOne(WorldPacket* data, ObjectGuid who) const;
- void SendToOne(WorldPacket* data, ObjectGuid who) const;
+
+ template<class Builder>
+ void SendToAll(Builder&, ObjectGuid guid = ObjectGuid::Empty) const;
+
+ template<class Builder>
+ void SendToAllButOne(Builder& builder, ObjectGuid who) const;
+
+ template<class Builder>
+ void SendToOne(Builder& builder, ObjectGuid who) const;
bool IsOn(ObjectGuid who) const { return _playersStore.count(who) != 0; }
bool IsBanned(ObjectGuid guid) const { return _bannedStore.count(guid) != 0; }
@@ -257,39 +229,8 @@ class TC_GAME_API Channel
return itr != _playersStore.end() ? itr->second.flags : 0;
}
- void SetModerator(ObjectGuid guid, bool set)
- {
- if (!IsOn(guid))
- return;
-
- PlayerInfo& playerInfo = _playersStore.at(guid);
- if (playerInfo.IsModerator() != set)
- {
- uint8 oldFlag = GetPlayerFlags(guid);
- playerInfo.SetModerator(set);
-
- WorldPacket data;
- MakeModeChange(&data, guid, oldFlag);
- SendToAll(&data);
- }
- }
-
- void SetMute(ObjectGuid guid, bool set)
- {
- if (!IsOn(guid))
- return;
-
- PlayerInfo& playerInfo = _playersStore.at(guid);
- if (playerInfo.IsMuted() != set)
- {
- uint8 oldFlag = GetPlayerFlags(guid);
- playerInfo.SetMuted(set);
-
- WorldPacket data;
- MakeModeChange(&data, guid, oldFlag);
- SendToAll(&data);
- }
- }
+ void SetModerator(ObjectGuid guid, bool set);
+ void SetMute(ObjectGuid guid, bool set);
typedef std::map<ObjectGuid, PlayerInfo> PlayerContainer;
typedef GuidUnorderedSet BannedContainer;
@@ -307,6 +248,8 @@ class TC_GAME_API Channel
std::string _channelPassword;
PlayerContainer _playersStore;
BannedContainer _bannedStore;
+
+ AreaTableEntry const* _zoneEntry;
};
#endif
diff --git a/src/server/game/Chat/Channels/ChannelAppenders.h b/src/server/game/Chat/Channels/ChannelAppenders.h
new file mode 100644
index 00000000000..3dfdc3f32cf
--- /dev/null
+++ b/src/server/game/Chat/Channels/ChannelAppenders.h
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CHANNELAPPENDERS_H
+#define _CHANNELAPPENDERS_H
+
+#include "Channel.h"
+
+// initial packet data (notify type and channel name)
+template<class PacketModifier>
+class ChannelNameBuilder
+{
+ public:
+ ChannelNameBuilder(Channel const* source, PacketModifier const& modifier)
+ : _source(source), _modifier(modifier){ }
+
+ void operator()(WorldPacket& data, LocaleConstant locale) const
+ {
+ // LocalizedPacketDo sends client DBC locale, we need to get available to server locale
+ LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
+
+ data.Initialize(SMSG_CHANNEL_NOTIFY, 60); // guess size
+ data << uint8(_modifier.NotificationType);
+ data << _source->GetName(localeIdx);
+ _modifier.Append(data);
+ }
+
+ private:
+ Channel const* _source;
+ PacketModifier _modifier;
+};
+
+struct JoinedAppend
+{
+ explicit JoinedAppend(ObjectGuid const& guid) : _guid(guid) { }
+
+ static uint8 const NotificationType = CHAT_JOINED_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint64(_guid);
+ }
+
+private:
+ ObjectGuid _guid;
+};
+
+struct LeftAppend
+{
+ explicit LeftAppend(ObjectGuid const& guid) : _guid(guid) { }
+
+ static uint8 const NotificationType = CHAT_LEFT_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint64(_guid);
+ }
+
+private:
+ ObjectGuid _guid;
+};
+
+struct YouJoinedAppend
+{
+ explicit YouJoinedAppend(Channel const* channel) : _channel(channel) { }
+
+ static uint8 const NotificationType = CHAT_YOU_JOINED_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint8(_channel->GetFlags());
+ data << uint32(_channel->GetChannelId());
+ data << uint32(0);
+ }
+
+private:
+ Channel const* _channel;
+};
+
+struct YouLeftAppend
+{
+ explicit YouLeftAppend(Channel const* channel) : _channel(channel) { }
+
+ static uint8 const NotificationType = CHAT_YOU_LEFT_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint32(_channel->GetChannelId());
+ data << uint8(_channel->IsConstant());
+ }
+
+private:
+ Channel const* _channel;
+};
+
+struct WrongPasswordAppend
+{
+ static uint8 const NotificationType = CHAT_WRONG_PASSWORD_NOTICE;
+
+ void Append(WorldPacket& /*data*/) const { }
+};
+
+struct NotMemberAppend
+{
+ static uint8 const NotificationType = CHAT_NOT_MEMBER_NOTICE;
+
+ void Append(WorldPacket& /*data*/) const { }
+};
+
+struct NotModeratorAppend
+{
+ static uint8 const NotificationType = CHAT_NOT_MODERATOR_NOTICE;
+
+ void Append(WorldPacket& /*data*/) const { }
+};
+
+struct PasswordChangedAppend
+{
+ explicit PasswordChangedAppend(ObjectGuid const& guid) : _guid(guid) { }
+
+ static uint8 const NotificationType = CHAT_PASSWORD_CHANGED_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint64(_guid);
+ }
+
+private:
+ ObjectGuid _guid;
+};
+
+struct OwnerChangedAppend
+{
+ explicit OwnerChangedAppend(ObjectGuid const& guid) : _guid(guid) { }
+
+ static uint8 const NotificationType = CHAT_OWNER_CHANGED_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint64(_guid);
+ }
+
+private:
+ ObjectGuid _guid;
+};
+
+struct PlayerNotFoundAppend
+{
+ explicit PlayerNotFoundAppend(std::string const& playerName) : _playerName(playerName) { }
+
+ static uint8 const NotificationType = CHAT_PLAYER_NOT_FOUND_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << _playerName;
+ }
+
+private:
+ std::string _playerName;
+};
+
+struct NotOwnerAppend
+{
+ static uint8 const NotificationType = CHAT_NOT_OWNER_NOTICE;
+
+ void Append(WorldPacket& /*data*/) const { }
+};
+
+struct ChannelOwnerAppend
+{
+ explicit ChannelOwnerAppend(Channel const* channel, ObjectGuid const& ownerGuid) : _channel(channel), _ownerGuid(ownerGuid)
+ {
+ CharacterInfo const* cInfo = sWorld->GetCharacterInfo(_ownerGuid);
+ if (!cInfo || cInfo->Name.empty())
+ _ownerName = "PLAYER_NOT_FOUND";
+ else
+ _ownerName = cInfo->Name;
+ }
+
+ static uint8 const NotificationType = CHAT_CHANNEL_OWNER_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << ((_channel->IsConstant() || !_ownerGuid) ? "Nobody" : _ownerName);
+ }
+
+private:
+ Channel const* _channel;
+ ObjectGuid _ownerGuid;
+
+ std::string _ownerName;
+};
+
+struct ModeChangeAppend
+{
+ explicit ModeChangeAppend(ObjectGuid const& guid, uint8 oldFlags, uint8 newFlags) : _guid(guid), _oldFlags(oldFlags), _newFlags(newFlags) { }
+
+ static uint8 const NotificationType = CHAT_MODE_CHANGE_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint64(_guid);
+ data << uint8(_oldFlags);
+ data << uint8(_newFlags);
+ }
+
+private:
+ ObjectGuid _guid;
+ uint8 _oldFlags;
+ uint8 _newFlags;
+};
+
+struct AnnouncementsOnAppend
+{
+ explicit AnnouncementsOnAppend(ObjectGuid const& guid) : _guid(guid) { }
+
+ static uint8 const NotificationType = CHAT_ANNOUNCEMENTS_ON_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint64(_guid);
+ }
+
+private:
+ ObjectGuid _guid;
+};
+
+struct AnnouncementsOffAppend
+{
+ explicit AnnouncementsOffAppend(ObjectGuid const& guid) : _guid(guid) { }
+
+ static uint8 const NotificationType = CHAT_ANNOUNCEMENTS_OFF_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint64(_guid);
+ }
+
+private:
+ ObjectGuid _guid;
+};
+
+struct MutedAppend
+{
+ static uint8 const NotificationType = CHAT_MUTED_NOTICE;
+
+ void Append(WorldPacket& /*data*/) const { }
+};
+
+struct PlayerKickedAppend
+{
+ explicit PlayerKickedAppend(ObjectGuid const& kicker, ObjectGuid const& kickee) : _kicker(kicker), _kickee(kickee) { }
+
+ static uint8 const NotificationType = CHAT_PLAYER_KICKED_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint64(_kickee);
+ data << uint64(_kicker);
+ }
+
+private:
+ ObjectGuid _kicker;
+ ObjectGuid _kickee;
+};
+
+struct BannedAppend
+{
+ static uint8 const NotificationType = CHAT_BANNED_NOTICE;
+
+ void Append(WorldPacket& /*data*/) const { }
+};
+
+struct PlayerBannedAppend
+{
+ explicit PlayerBannedAppend(ObjectGuid const& moderator, ObjectGuid const& banned) : _moderator(moderator), _banned(banned) { }
+
+ static uint8 const NotificationType = CHAT_PLAYER_BANNED_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint64(_banned);
+ data << uint64(_moderator);
+ }
+
+private:
+ ObjectGuid _moderator;
+ ObjectGuid _banned;
+};
+
+struct PlayerUnbannedAppend
+{
+ explicit PlayerUnbannedAppend(ObjectGuid const& moderator, ObjectGuid const& unbanned) : _moderator(moderator), _unbanned(unbanned) { }
+
+ static uint8 const NotificationType = CHAT_PLAYER_UNBANNED_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint64(_unbanned);
+ data << uint64(_moderator);
+ }
+
+private:
+ ObjectGuid _moderator;
+ ObjectGuid _unbanned;
+};
+
+struct PlayerNotBannedAppend
+{
+ explicit PlayerNotBannedAppend(std::string const& playerName) : _playerName(playerName) { }
+
+ static uint8 const NotificationType = CHAT_PLAYER_NOT_BANNED_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << _playerName;
+ }
+
+private:
+ std::string _playerName;
+};
+
+struct PlayerAlreadyMemberAppend
+{
+ explicit PlayerAlreadyMemberAppend(ObjectGuid const& guid) : _guid(guid) { }
+
+ static uint8 const NotificationType = CHAT_PLAYER_ALREADY_MEMBER_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint64(_guid);
+ }
+
+private:
+ ObjectGuid _guid;
+};
+
+struct InviteAppend
+{
+ explicit InviteAppend(ObjectGuid const& guid) : _guid(guid) { }
+
+ static uint8 const NotificationType = CHAT_INVITE_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint64(_guid);
+ }
+
+private:
+ ObjectGuid _guid;
+};
+
+struct InviteWrongFactionAppend
+{
+ static uint8 const NotificationType = CHAT_INVITE_WRONG_FACTION_NOTICE;
+
+ void Append(WorldPacket& /*data*/) const { }
+};
+
+struct WrongFactionAppend
+{
+ static uint8 const NotificationType = CHAT_WRONG_FACTION_NOTICE;
+
+ void Append(WorldPacket& /*data*/) const { }
+};
+
+struct InvalidNameAppend
+{
+ static uint8 const NotificationType = CHAT_INVALID_NAME_NOTICE;
+
+ void Append(WorldPacket& /*data*/) const { }
+};
+
+struct NotModeratedAppend
+{
+ static uint8 const NotificationType = CHAT_NOT_MODERATED_NOTICE;
+
+ void Append(WorldPacket& /*data*/) const { }
+};
+
+struct PlayerInvitedAppend
+{
+ explicit PlayerInvitedAppend(std::string const& playerName) : _playerName(playerName) { }
+
+ static uint8 const NotificationType = CHAT_PLAYER_INVITED_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << _playerName;
+ }
+
+private:
+ std::string _playerName;
+};
+
+struct PlayerInviteBannedAppend
+{
+ explicit PlayerInviteBannedAppend(std::string const& playerName) : _playerName(playerName) { }
+
+ static uint8 const NotificationType = CHAT_PLAYER_INVITE_BANNED_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << _playerName;
+ }
+
+private:
+ std::string _playerName;
+};
+
+struct ThrottledAppend
+{
+ static uint8 const NotificationType = CHAT_THROTTLED_NOTICE;
+
+ void Append(WorldPacket& /*data*/) const { }
+};
+
+struct NotInAreaAppend
+{
+ static uint8 const NotificationType = CHAT_NOT_IN_AREA_NOTICE;
+
+ void Append(WorldPacket& /*data*/) const { }
+};
+
+struct NotInLFGAppend
+{
+ static uint8 const NotificationType = CHAT_NOT_IN_LFG_NOTICE;
+
+ void Append(WorldPacket& /*data*/) const { }
+};
+
+struct VoiceOnAppend
+{
+ explicit VoiceOnAppend(ObjectGuid const& guid) : _guid(guid) { }
+
+ static uint8 const NotificationType = CHAT_VOICE_ON_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint64(_guid);
+ }
+
+private:
+ ObjectGuid _guid;
+};
+
+struct VoiceOffAppend
+{
+ explicit VoiceOffAppend(ObjectGuid const& guid) : _guid(guid) { }
+
+ static uint8 const NotificationType = CHAT_VOICE_OFF_NOTICE;
+
+ void Append(WorldPacket& data) const
+ {
+ data << uint64(_guid);
+ }
+
+private:
+ ObjectGuid _guid;
+};
+
+#endif // _CHANNELAPPENDERS_H
diff --git a/src/server/game/Chat/Channels/ChannelMgr.cpp b/src/server/game/Chat/Channels/ChannelMgr.cpp
index 043d4bdc2bc..ee1f463aae2 100644
--- a/src/server/game/Chat/Channels/ChannelMgr.cpp
+++ b/src/server/game/Chat/Channels/ChannelMgr.cpp
@@ -16,20 +16,25 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "Channel.h"
#include "ChannelMgr.h"
#include "Player.h"
#include "World.h"
ChannelMgr::~ChannelMgr()
{
- for (ChannelMap::iterator itr = channels.begin(); itr != channels.end(); ++itr)
+ for (auto itr = _channels.begin(); itr != _channels.end(); ++itr)
+ delete itr->second;
+
+ for (auto itr = _customChannels.begin(); itr != _customChannels.end(); ++itr)
delete itr->second;
}
ChannelMgr* ChannelMgr::forTeam(uint32 team)
{
- static ChannelMgr allianceChannelMgr;
- static ChannelMgr hordeChannelMgr;
+ static ChannelMgr allianceChannelMgr(ALLIANCE);
+ static ChannelMgr hordeChannelMgr(HORDE);
+
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL))
return &allianceChannelMgr; // cross-faction
@@ -42,69 +47,148 @@ ChannelMgr* ChannelMgr::forTeam(uint32 team)
return nullptr;
}
-Channel* ChannelMgr::GetJoinChannel(std::string const& name, uint32 channelId)
+Channel* ChannelMgr::GetChannelForPlayerByNamePart(std::string const& namePart, Player* playerSearcher)
{
- std::wstring wname;
- if (!Utf8toWStr(name, wname))
+ std::wstring channelNamePart;
+ if (!Utf8toWStr(namePart, channelNamePart))
return nullptr;
- wstrToLower(wname);
+ wstrToLower(channelNamePart);
+ for (Channel* channel : playerSearcher->GetJoinedChannels())
+ {
+ std::string chanName = channel->GetName(playerSearcher->GetSession()->GetSessionDbcLocale());
- ChannelMap::const_iterator i = channels.find(wname);
+ std::wstring channelNameW;
+ if (!Utf8toWStr(chanName, channelNameW))
+ continue;
- if (i == channels.end())
- {
- Channel* nchan = new Channel(name, channelId, team);
- channels[wname] = nchan;
- return nchan;
+ wstrToLower(channelNameW);
+ if (!channelNameW.compare(0, channelNamePart.size(), channelNamePart))
+ return channel;
}
- return i->second;
+ return nullptr;
}
-Channel* ChannelMgr::GetChannel(std::string const& name, Player* player, bool pkt)
+Channel* ChannelMgr::GetJoinChannel(uint32 channelId, std::string const& name, AreaTableEntry const* zoneEntry /*= nullptr*/)
{
- std::wstring wname;
- if (!Utf8toWStr(name, wname))
- return nullptr;
+ if (channelId) // builtin
+ {
+ ChatChannelsEntry const* channelEntry = sChatChannelsStore.AssertEntry(channelId);
+ uint32 zoneId = zoneEntry ? zoneEntry->ID : 0;
+ if (channelEntry->flags & (CHANNEL_DBC_FLAG_GLOBAL | CHANNEL_DBC_FLAG_CITY_ONLY))
+ zoneId = 0;
- wstrToLower(wname);
+ std::pair<uint32, uint32> key = std::make_pair(channelId, zoneId);
- ChannelMap::const_iterator i = channels.find(wname);
+ auto itr = _channels.find(key);
+ if (itr != _channels.end())
+ return itr->second;
- if (i == channels.end())
+ Channel* newChannel = new Channel(channelId, _team, zoneEntry);
+ _channels[key] = newChannel;
+ return newChannel;
+ }
+ else // custom
{
- if (pkt)
- {
- WorldPacket data;
- MakeNotOnPacket(&data, name);
- player->GetSession()->SendPacket(&data);
- }
+ std::wstring channelName;
+ if (!Utf8toWStr(name, channelName))
+ return nullptr;
+
+ wstrToLower(channelName);
+ auto itr = _customChannels.find(channelName);
+ if (itr != _customChannels.end())
+ return itr->second;
+
+ Channel* newChannel = new Channel(name, _team);
+ _customChannels[channelName] = newChannel;
+ return newChannel;
+ }
+}
- return nullptr;
+Channel* ChannelMgr::GetChannel(uint32 channelId, std::string const& name, Player* player, bool pkt /*= true*/, AreaTableEntry const* zoneEntry /*= nullptr*/) const
+{
+ Channel* ret = nullptr;
+ bool send = false;
+
+ if (channelId) // builtin
+ {
+ ChatChannelsEntry const* channelEntry = sChatChannelsStore.AssertEntry(channelId);
+ uint32 zoneId = zoneEntry ? zoneEntry->ID : 0;
+ if (channelEntry->flags & (CHANNEL_DBC_FLAG_GLOBAL | CHANNEL_DBC_FLAG_CITY_ONLY))
+ zoneId = 0;
+
+ std::pair<uint32, uint32> key = std::make_pair(channelId, zoneId);
+
+ auto itr = _channels.find(key);
+ if (itr != _channels.end())
+ ret = itr->second;
+ else
+ send = true;
}
+ else // custom
+ {
+ std::wstring channelName;
+ if (!Utf8toWStr(name, channelName))
+ return nullptr;
+
+ wstrToLower(channelName);
+ auto itr = _customChannels.find(channelName);
+ if (itr != _customChannels.end())
+ ret = itr->second;
+ else
+ send = true;
+ }
+
+ if (send && pkt)
+ {
+ std::string channelName = name;
+ Channel::GetChannelName(channelName, channelId, player->GetSession()->GetSessionDbcLocale(), zoneEntry);
- return i->second;
+ WorldPacket data;
+ ChannelMgr::MakeNotOnPacket(&data, channelName);
+ player->SendDirectMessage(&data);
+ }
+
+ return ret;
}
void ChannelMgr::LeftChannel(std::string const& name)
{
- std::wstring wname;
- if (!Utf8toWStr(name, wname))
+ std::wstring channelName;
+ if (!Utf8toWStr(name, channelName))
return;
- wstrToLower(wname);
+ wstrToLower(channelName);
+ auto itr = _customChannels.find(channelName);
+ if (itr == _customChannels.end())
+ return;
- ChannelMap::const_iterator i = channels.find(wname);
+ Channel* channel = itr->second;
+ if (!channel->GetNumPlayers())
+ {
+ _customChannels.erase(itr);
+ delete channel;
+ }
+}
- if (i == channels.end())
- return;
+void ChannelMgr::LeftChannel(uint32 channelId, AreaTableEntry const* zoneEntry)
+{
+ ChatChannelsEntry const* channelEntry = sChatChannelsStore.AssertEntry(channelId);
+ uint32 zoneId = zoneEntry ? zoneEntry->ID : 0;
+ if (channelEntry->flags & (CHANNEL_DBC_FLAG_GLOBAL | CHANNEL_DBC_FLAG_CITY_ONLY))
+ zoneId = 0;
+
+ std::pair<uint32, uint32> key = std::make_pair(channelId, zoneId);
- Channel* channel = i->second;
+ auto itr = _channels.find(key);
+ if (itr == _channels.end())
+ return;
- if (!channel->GetNumPlayers() && !channel->IsConstant())
+ Channel* channel = itr->second;
+ if (!channel->GetNumPlayers())
{
- channels.erase(wname);
+ _channels.erase(itr);
delete channel;
}
}
@@ -112,5 +196,5 @@ void ChannelMgr::LeftChannel(std::string const& name)
void ChannelMgr::MakeNotOnPacket(WorldPacket* data, std::string const& name)
{
data->Initialize(SMSG_CHANNEL_NOTIFY, 1 + name.size());
- (*data) << uint8(5) << name;
+ (*data) << uint8(CHAT_NOT_MEMBER_NOTICE) << name;
}
diff --git a/src/server/game/Chat/Channels/ChannelMgr.h b/src/server/game/Chat/Channels/ChannelMgr.h
index abe45690997..5f6fa55516a 100644
--- a/src/server/game/Chat/Channels/ChannelMgr.h
+++ b/src/server/game/Chat/Channels/ChannelMgr.h
@@ -19,36 +19,33 @@
#define __TRINITY_CHANNELMGR_H
#include "Common.h"
-#include "Channel.h"
-#include <map>
-#include <string>
-
-#include "World.h"
-
-#define MAX_CHANNEL_PASS_STR 31
+class Channel;
class TC_GAME_API ChannelMgr
{
- typedef std::map<std::wstring, Channel*> ChannelMap;
+ typedef std::unordered_map<std::wstring, Channel*> CustomChannelContainer; // custom channels only differ in name
+ typedef std::unordered_map<std::pair<uint32 /*channelId*/, uint32 /*zoneId*/>, Channel*> BuiltinChannelContainer; //identify builtin (DBC) channels by zoneId instead, since name changes by client locale
protected:
- ChannelMgr() : team(0) { }
+ explicit ChannelMgr(uint32 team) : _team(team) { }
~ChannelMgr();
public:
static ChannelMgr* forTeam(uint32 team);
- void setTeam(uint32 newTeam) { team = newTeam; }
+ static Channel* GetChannelForPlayerByNamePart(std::string const& namePart, Player* playerSearcher);
- Channel* GetJoinChannel(std::string const& name, uint32 channel_id);
- Channel* GetChannel(std::string const& name, Player* p, bool pkt = true);
+ Channel* GetJoinChannel(uint32 channelId, std::string const& name, AreaTableEntry const* zoneEntry = nullptr);
+ Channel* GetChannel(uint32 channelId, std::string const& name, Player* player, bool pkt = true, AreaTableEntry const* zoneEntry = nullptr) const;
void LeftChannel(std::string const& name);
+ void LeftChannel(uint32 channelId, AreaTableEntry const* zoneEntry);
private:
- ChannelMap channels;
- uint32 team;
+ CustomChannelContainer _customChannels;
+ BuiltinChannelContainer _channels;
+ uint32 const _team;
- void MakeNotOnPacket(WorldPacket* data, std::string const& name);
+ static void MakeNotOnPacket(WorldPacket* data, std::string const& name);
};
#endif
diff --git a/src/server/game/Combat/HostileRefManager.cpp b/src/server/game/Combat/HostileRefManager.cpp
index 397fd59b7d1..965b910c3f4 100644
--- a/src/server/game/Combat/HostileRefManager.cpp
+++ b/src/server/game/Combat/HostileRefManager.cpp
@@ -28,8 +28,8 @@ HostileRefManager::~HostileRefManager()
}
//=================================================
-// send threat to all my hateres for the victim
-// The victim is hated than by them as well
+// send threat to all my haters for the victim
+// The victim is then hated by them as well
// use for buffs and healing threat functionality
void HostileRefManager::threatAssist(Unit* victim, float baseThreat, SpellInfo const* threatSpell)
@@ -37,9 +37,10 @@ void HostileRefManager::threatAssist(Unit* victim, float baseThreat, SpellInfo c
if (getSize() == 0)
return;
- HostileReference* ref = getFirst();
float threat = ThreatCalcHelper::calcThreat(victim, iOwner, baseThreat, (threatSpell ? threatSpell->GetSchoolMask() : SPELL_SCHOOL_MASK_NORMAL), threatSpell);
threat /= getSize();
+
+ HostileReference* ref = getFirst();
while (ref)
{
if (ThreatCalcHelper::isValidProcess(victim, ref->GetSource()->GetOwner(), threatSpell))
@@ -54,7 +55,6 @@ void HostileRefManager::threatAssist(Unit* victim, float baseThreat, SpellInfo c
void HostileRefManager::addTempThreat(float threat, bool apply)
{
HostileReference* ref = getFirst();
-
while (ref)
{
if (apply)
diff --git a/src/server/game/Combat/HostileRefManager.h b/src/server/game/Combat/HostileRefManager.h
index 855f9e3d272..859bee3caf7 100644
--- a/src/server/game/Combat/HostileRefManager.h
+++ b/src/server/game/Combat/HostileRefManager.h
@@ -31,18 +31,16 @@ class SpellInfo;
class TC_GAME_API HostileRefManager : public RefManager<Unit, ThreatManager>
{
- private:
- Unit* iOwner;
public:
- explicit HostileRefManager(Unit* owner) { iOwner = owner; }
+ explicit HostileRefManager(Unit* owner) : iOwner(owner) { }
~HostileRefManager();
- Unit* GetOwner() { return iOwner; }
+ Unit* GetOwner() const { return iOwner; }
// send threat to all my hateres for the victim
// The victim is hated than by them as well
// use for buffs and healing threat functionality
- void threatAssist(Unit* victim, float baseThreat, SpellInfo const* threatSpell = NULL);
+ void threatAssist(Unit* victim, float baseThreat, SpellInfo const* threatSpell = nullptr);
void addTempThreat(float threat, bool apply);
@@ -68,6 +66,9 @@ class TC_GAME_API HostileRefManager : public RefManager<Unit, ThreatManager>
void deleteReference(Unit* creature);
void UpdateVisibility();
+
+ private:
+ Unit* iOwner;
};
//=================================================
#endif
diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp
index 9767d69e2aa..fec4ec300cc 100644
--- a/src/server/game/Combat/ThreatManager.cpp
+++ b/src/server/game/Combat/ThreatManager.cpp
@@ -30,7 +30,7 @@
//==============================================================
// The hatingUnit is not used yet
-float ThreatCalcHelper::calcThreat(Unit* hatedUnit, Unit* /*hatingUnit*/, float threat, SpellSchoolMask schoolMask, SpellInfo const* threatSpell)
+float ThreatCalcHelper::calcThreat(Unit* hatedUnit, Unit* /*hatingUnit*/, float threat, SpellSchoolMask schoolMask, SpellInfo const* threatSpell /*= nullptr*/)
{
if (threatSpell)
{
@@ -39,18 +39,18 @@ float ThreatCalcHelper::calcThreat(Unit* hatedUnit, Unit* /*hatingUnit*/, float
threat *= threatEntry->pctMod;
// Energize is not affected by Mods
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; i++)
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (threatSpell->Effects[i].Effect == SPELL_EFFECT_ENERGIZE || threatSpell->Effects[i].ApplyAuraName == SPELL_AURA_PERIODIC_ENERGIZE)
return threat;
if (Player* modOwner = hatedUnit->GetSpellModOwner())
- modOwner->ApplySpellMod(threatSpell->Id, SPELLMOD_THREAT, threat);
+ modOwner->ApplySpellMod<SPELLMOD_THREAT>(threatSpell->Id, threat);
}
return hatedUnit->ApplyTotalThreatModifier(threat, schoolMask);
}
-bool ThreatCalcHelper::isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellInfo const* threatSpell)
+bool ThreatCalcHelper::isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellInfo const* threatSpell /*= nullptr*/)
{
//function deals with adding threat and adding players and pets into ThreatList
//mobs, NPCs, guards have ThreatList and HateOfflineList
@@ -134,18 +134,20 @@ void HostileReference::fireStatusChanged(ThreatRefStatusChangeEvent& threatRefSt
void HostileReference::addThreat(float modThreat)
{
+ if (!modThreat)
+ return;
+
iThreat += modThreat;
+
// the threat is changed. Source and target unit have to be available
// if the link was cut before relink it again
if (!isOnline())
updateOnlineStatus();
- if (modThreat != 0.0f)
- {
- ThreatRefStatusChangeEvent event(UEV_THREAT_REF_THREAT_CHANGE, this, modThreat);
- fireStatusChanged(event);
- }
- if (isValid() && modThreat >= 0.0f)
+ ThreatRefStatusChangeEvent event(UEV_THREAT_REF_THREAT_CHANGE, this, modThreat);
+ fireStatusChanged(event);
+
+ if (isValid() && modThreat > 0.0f)
{
Unit* victimOwner = getTarget()->GetCharmerOrOwner();
if (victimOwner && victimOwner->IsAlive())
@@ -155,9 +157,7 @@ void HostileReference::addThreat(float modThreat)
void HostileReference::addThreatPercent(int32 percent)
{
- float tmpThreat = iThreat;
- AddPct(tmpThreat, percent);
- addThreat(tmpThreat - iThreat);
+ addThreat(CalculatePct(iThreat, percent));
}
//============================================================
@@ -193,6 +193,7 @@ void HostileReference::updateOnlineStatus()
else
accessible = true;
}
+
setAccessibleState(accessible);
setOnlineOfflineState(online);
}
@@ -221,7 +222,7 @@ void HostileReference::setAccessibleState(bool isAccessible)
{
iAccessible = isAccessible;
- ThreatRefStatusChangeEvent event(UEV_THREAT_REF_ASSECCIBLE_STATUS, this);
+ ThreatRefStatusChangeEvent event(UEV_THREAT_REF_ACCESSIBLE_STATUS, this);
fireStatusChanged(event);
}
}
diff --git a/src/server/game/Combat/ThreatManager.h b/src/server/game/Combat/ThreatManager.h
index a68d803304d..cad62659317 100644
--- a/src/server/game/Combat/ThreatManager.h
+++ b/src/server/game/Combat/ThreatManager.h
@@ -41,8 +41,8 @@ class SpellInfo;
struct TC_GAME_API ThreatCalcHelper
{
- static float calcThreat(Unit* hatedUnit, Unit* hatingUnit, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* threatSpell = NULL);
- static bool isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellInfo const* threatSpell = NULL);
+ static float calcThreat(Unit* hatedUnit, Unit* hatingUnit, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* threatSpell = nullptr);
+ static bool isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellInfo const* threatSpell = nullptr);
};
//==============================================================
@@ -54,11 +54,11 @@ class TC_GAME_API HostileReference : public Reference<Unit, ThreatManager>
//=================================================
void addThreat(float modThreat);
- void setThreat(float threat) { addThreat(threat - getThreat()); }
+ void setThreat(float threat) { addThreat(threat - iThreat); }
void addThreatPercent(int32 percent);
- float getThreat() const { return iThreat; }
+ float getThreat() const { return iThreat + iTempThreatModifier; }
bool isOnline() const { return iOnline; }
@@ -66,27 +66,27 @@ class TC_GAME_API HostileReference : public Reference<Unit, ThreatManager>
// in this case online = true, but accessible = false
bool isAccessible() const { return iAccessible; }
- // used for temporary setting a threat and reducting it later again.
+ // used for temporary setting a threat and reducing it later again.
// the threat modification is stored
void setTempThreat(float threat)
{
- addTempThreat(threat - getThreat());
+ addTempThreat(threat - iTempThreatModifier);
}
void addTempThreat(float threat)
{
- iTempThreatModifier = threat;
- if (iTempThreatModifier != 0.0f)
- addThreat(iTempThreatModifier);
+ if (!threat)
+ return;
+
+ iTempThreatModifier += threat;
+
+ ThreatRefStatusChangeEvent event(UEV_THREAT_REF_THREAT_CHANGE, this, threat);
+ fireStatusChanged(event);
}
void resetTempThreat()
{
- if (iTempThreatModifier != 0.0f)
- {
- addThreat(-iTempThreatModifier);
- iTempThreatModifier = 0.0f;
- }
+ addTempThreat(-iTempThreatModifier);
}
float getTempThreatModifier() { return iTempThreatModifier; }
@@ -100,7 +100,7 @@ class TC_GAME_API HostileReference : public Reference<Unit, ThreatManager>
void setAccessibleState(bool isAccessible);
//=================================================
- bool operator == (const HostileReference& hostileRef) const { return hostileRef.getUnitGuid() == getUnitGuid(); }
+ bool operator==(HostileReference const& hostileRef) const { return hostileRef.getUnitGuid() == getUnitGuid(); }
//=================================================
@@ -113,7 +113,7 @@ class TC_GAME_API HostileReference : public Reference<Unit, ThreatManager>
//=================================================
- HostileReference* next() { return ((HostileReference*) Reference<Unit, ThreatManager>::next()); }
+ HostileReference* next() { return static_cast<HostileReference*>(Reference<Unit, ThreatManager>::next()); }
//=================================================
@@ -125,14 +125,17 @@ class TC_GAME_API HostileReference : public Reference<Unit, ThreatManager>
// Tell our refFrom (source) object, that the link is cut (Target destroyed)
void sourceObjectDestroyLink() override;
+
private:
// Inform the source, that the status of that reference was changed
void fireStatusChanged(ThreatRefStatusChangeEvent& threatRefStatusChangeEvent);
Unit* GetSourceUnit();
+
private:
float iThreat;
- float iTempThreatModifier; // used for taunt
+ float iTempThreatModifier; // used for SPELL_AURA_MOD_TOTAL_THREAT
+
ObjectGuid iUnitGuid;
bool iOnline;
bool iAccessible;
diff --git a/src/server/game/Combat/UnitEvents.h b/src/server/game/Combat/UnitEvents.h
index f50edcf3c7d..ee1a960c524 100644
--- a/src/server/game/Combat/UnitEvents.h
+++ b/src/server/game/Combat/UnitEvents.h
@@ -40,7 +40,7 @@ enum UNIT_EVENT_TYPE
UEV_THREAT_REF_REMOVE_FROM_LIST = 1<<2,
// Player/Pet entered/left water or some other place where it is/was not accessible for the creature
- UEV_THREAT_REF_ASSECCIBLE_STATUS = 1<<3,
+ UEV_THREAT_REF_ACCESSIBLE_STATUS = 1<<3,
// Threat list is going to be sorted (if dirty flag is set)
UEV_THREAT_SORT_LIST = 1<<4,
@@ -58,7 +58,7 @@ enum UNIT_EVENT_TYPE
//UEV_UNIT_HEALTH_CHANGE = 1<<8,
};
-#define UEV_THREAT_REF_EVENT_MASK (UEV_THREAT_REF_ONLINE_STATUS | UEV_THREAT_REF_THREAT_CHANGE | UEV_THREAT_REF_REMOVE_FROM_LIST | UEV_THREAT_REF_ASSECCIBLE_STATUS)
+#define UEV_THREAT_REF_EVENT_MASK (UEV_THREAT_REF_ONLINE_STATUS | UEV_THREAT_REF_THREAT_CHANGE | UEV_THREAT_REF_REMOVE_FROM_LIST | UEV_THREAT_REF_ACCESSIBLE_STATUS)
#define UEV_THREAT_MANAGER_EVENT_MASK (UEV_THREAT_SORT_LIST | UEV_THREAT_SET_NEXT_TARGET | UEV_THREAT_VICTIM_CHANGED)
#define UEV_ALL_EVENT_MASK (0xffffffff)
@@ -69,14 +69,16 @@ enum UNIT_EVENT_TYPE
class UnitBaseEvent
{
- private:
- uint32 iType;
public:
- UnitBaseEvent(uint32 pType) { iType = pType; }
+ explicit UnitBaseEvent(uint32 pType) { iType = pType; }
uint32 getType() const { return iType; }
bool matchesTypeMask(uint32 pMask) const { return (iType & pMask) != 0; }
- void setType(uint32 pType) { iType = pType; }
+ private:
+ uint32 iType;
+
+ protected:
+ ~UnitBaseEvent() { }
};
//==============================================================
@@ -92,14 +94,15 @@ class TC_GAME_API ThreatRefStatusChangeEvent : public UnitBaseEvent
bool iBValue;
};
ThreatManager* iThreatManager;
+
public:
- ThreatRefStatusChangeEvent(uint32 pType) : UnitBaseEvent(pType), iThreatManager(NULL) { iHostileReference = NULL; }
+ explicit ThreatRefStatusChangeEvent(uint32 pType) : UnitBaseEvent(pType), iHostileReference(nullptr), iThreatManager(nullptr) { }
- ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference) : UnitBaseEvent(pType), iThreatManager(NULL) { iHostileReference = pHostileReference; }
+ ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference) : UnitBaseEvent(pType), iHostileReference(pHostileReference), iThreatManager(nullptr) { }
- ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference, float pValue) : UnitBaseEvent(pType), iThreatManager(NULL) { iHostileReference = pHostileReference; iFValue = pValue; }
+ ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference, float pValue) : UnitBaseEvent(pType), iHostileReference(pHostileReference), iFValue(pValue), iThreatManager(nullptr) { }
- ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference, bool pValue) : UnitBaseEvent(pType), iThreatManager(NULL) { iHostileReference = pHostileReference; iBValue = pValue; }
+ ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference, bool pValue) : UnitBaseEvent(pType), iHostileReference(pHostileReference), iBValue(pValue), iThreatManager(nullptr) { }
int32 getIValue() const { return iIValue; }
@@ -116,20 +119,4 @@ class TC_GAME_API ThreatRefStatusChangeEvent : public UnitBaseEvent
ThreatManager* getThreatManager() const { return iThreatManager; }
};
-//==============================================================
-
-class ThreatManagerEvent : public ThreatRefStatusChangeEvent
-{
- private:
- ThreatContainer* iThreatContainer;
- public:
- ThreatManagerEvent(uint32 pType) : ThreatRefStatusChangeEvent(pType), iThreatContainer(NULL) { }
- ThreatManagerEvent(uint32 pType, HostileReference* pHostileReference) : ThreatRefStatusChangeEvent(pType, pHostileReference), iThreatContainer(NULL) { }
-
- void setThreatContainer(ThreatContainer* pThreatContainer) { iThreatContainer = pThreatContainer; }
-
- ThreatContainer* getThreatContainer() const { return iThreatContainer; }
-};
-
-//==============================================================
#endif
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index c859031b573..7ee775ec676 100644
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -1671,7 +1671,6 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const
break;
}
case CONDITION_SOURCE_TYPE_QUEST_ACCEPT:
- case CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK:
if (!sObjectMgr->GetQuestTemplate(cond->SourceEntry))
{
TC_LOG_ERROR("sql.sql", "%s SourceEntry specifies non-existing quest, skipped.", cond->ToString().c_str());
diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h
index 7bda1376a0d..4d32c3f36dc 100644
--- a/src/server/game/Conditions/ConditionMgr.h
+++ b/src/server/game/Conditions/ConditionMgr.h
@@ -130,7 +130,7 @@ enum ConditionSourceType
CONDITION_SOURCE_TYPE_SPELL = 17,
CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT = 18,
CONDITION_SOURCE_TYPE_QUEST_ACCEPT = 19,
- CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK = 20,
+ // Condition source type 20 unused
CONDITION_SOURCE_TYPE_VEHICLE_SPELL = 21,
CONDITION_SOURCE_TYPE_SMART_EVENT = 22,
CONDITION_SOURCE_TYPE_NPC_VENDOR = 23,
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index cb2f26e567f..99d7b49f82f 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -312,6 +312,7 @@ enum SpawnMask
enum FactionTemplateFlags
{
+ FACTION_TEMPLATE_ENEMY_SPAR = 0x00000020, // guessed, sparring with enemies?
FACTION_TEMPLATE_FLAG_PVP = 0x00000800, // flagged for PvP
FACTION_TEMPLATE_FLAG_CONTESTED_GUARD = 0x00001000, // faction will attack players that were involved in PvP combats
FACTION_TEMPLATE_FLAG_HOSTILE_BY_DEFAULT= 0x00002000
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index c85344b9bd1..8431f369b69 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -192,6 +192,17 @@ struct AreaTableEntry
return true;
return (flags & AREA_FLAG_SANCTUARY) != 0;
}
+
+ bool IsFlyable() const
+ {
+ if (flags & AREA_FLAG_OUTLAND)
+ {
+ if (!(flags & AREA_FLAG_NO_FLY_ZONE))
+ return true;
+ }
+
+ return false;
+ }
};
#define MAX_GROUP_AREA_IDS 6
@@ -673,6 +684,7 @@ struct FactionTemplateEntry
return hostileMask == 0 && friendlyMask == 0;
}
bool IsContestedGuardFaction() const { return (factionFlags & FACTION_TEMPLATE_FLAG_CONTESTED_GUARD) != 0; }
+ bool ShouldSparAttack() const { return (factionFlags & FACTION_TEMPLATE_ENEMY_SPAR) != 0; }
};
struct GameObjectDisplayInfoEntry
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index ba20bb68750..9df9d2ad53c 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -438,10 +438,9 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/,
if (updateLevel)
SelectLevel();
+ UpdateLevelDependantStats();
+
SetMeleeDamageSchool(SpellSchools(cInfo->dmgschool));
- CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(getLevel(), cInfo->unit_class);
- float armor = (float)stats->GenerateArmor(cInfo); /// @todo Why is this treated as uint32 when it's a float?
- SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, armor);
SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_HOLY]));
SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FIRE]));
SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_NATURE]));
@@ -1177,15 +1176,18 @@ void Creature::SelectLevel()
{
CreatureTemplate const* cInfo = GetCreatureTemplate();
- uint32 rank = IsPet() ? 0 : cInfo->rank;
-
// level
uint8 minlevel = std::min(cInfo->maxlevel, cInfo->minlevel);
uint8 maxlevel = std::max(cInfo->maxlevel, cInfo->minlevel);
uint8 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel);
SetLevel(level);
+}
- CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(level, cInfo->unit_class);
+void Creature::UpdateLevelDependantStats()
+{
+ CreatureTemplate const* cInfo = GetCreatureTemplate();
+ uint32 rank = IsPet() ? 0 : cInfo->rank;
+ CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(getLevel(), cInfo->unit_class);
// health
float healthmod = _GetHealthMod(rank);
@@ -1228,6 +1230,9 @@ void Creature::SelectLevel()
SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, stats->AttackPower);
SetModifierValue(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, stats->RangedAttackPower);
+
+ float armor = (float)stats->GenerateArmor(cInfo); /// @todo Why is this treated as uint32 when it's a float?
+ SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, armor);
}
float Creature::_GetHealthMod(int32 Rank)
@@ -1445,23 +1450,21 @@ void Creature::LoadEquipment(int8 id, bool force /*= true*/)
void Creature::SetSpawnHealth()
{
+ if (!m_creatureData)
+ return;
+
uint32 curhealth;
if (!m_regenHealth)
{
- if (m_creatureData)
+ curhealth = m_creatureData->curhealth;
+ if (curhealth)
{
- curhealth = m_creatureData->curhealth;
- if (curhealth)
- {
- curhealth = uint32(curhealth*_GetHealthMod(GetCreatureTemplate()->rank));
- if (curhealth < 1)
- curhealth = 1;
- }
- SetPower(POWER_MANA, m_creatureData->curmana);
+ curhealth = uint32(curhealth*_GetHealthMod(GetCreatureTemplate()->rank));
+ if (curhealth < 1)
+ curhealth = 1;
}
- else
- curhealth = GetHealth();
+ SetPower(POWER_MANA, m_creatureData->curmana);
}
else
{
@@ -1658,6 +1661,7 @@ void Creature::setDeathState(DeathState s)
SaveRespawnTime();
ReleaseFocus(nullptr, false); // remove spellcast focus
+ DoNotReacquireTarget(); // cancel delayed re-target
SetTarget(ObjectGuid::Empty); // drop target - dead mobs shouldn't ever target things
SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
@@ -1691,6 +1695,7 @@ void Creature::setDeathState(DeathState s)
SetLootRecipient(nullptr);
ResetPlayerDamageReq();
+ SetCannotReachTarget(false);
UpdateMovementFlags();
ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~UNIT_STATE_IGNORE_PATHFINDING));
@@ -1762,6 +1767,8 @@ void Creature::Respawn(bool force)
}
GetMotionMaster()->InitDefault();
+ //Re-initialize reactstate that could be altered by movementgenerators
+ InitializeReactState();
//Call AI respawn virtual function
if (IsAIEnabled)
@@ -1774,9 +1781,6 @@ void Creature::Respawn(bool force)
uint32 poolid = GetSpawnId() ? sPoolMgr->IsPartOfAPool<Creature>(GetSpawnId()) : 0;
if (poolid)
sPoolMgr->UpdatePool<Creature>(poolid, GetSpawnId());
-
- //Re-initialize reactstate that could be altered by movementgenerators
- InitializeReactState();
}
UpdateObjectVisibility();
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 2bcd7b5cd23..d79e55b623e 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -339,7 +339,7 @@ struct VendorItem
uint32 ExtendedCost;
//helpers
- bool IsGoldRequired(ItemTemplate const* pProto) const { return pProto->Flags2 & ITEM_FLAGS_EXTRA_EXT_COST_REQUIRES_GOLD || !ExtendedCost; }
+ bool IsGoldRequired(ItemTemplate const* pProto) const { return (pProto->Flags2 & ITEM_FLAG2_DONT_IGNORE_BUY_PRICE) || !ExtendedCost; }
};
typedef std::vector<VendorItem*> VendorItemList;
@@ -441,6 +441,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
bool Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, uint32 entry, float x, float y, float z, float ang, CreatureData const* data = nullptr, uint32 vehId = 0);
bool LoadCreaturesAddon();
void SelectLevel();
+ void UpdateLevelDependantStats();
void LoadEquipment(int8 id = 1, bool force = false);
void SetSpawnHealth();
@@ -690,6 +691,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
// Handling caster facing during spellcast
void SetTarget(ObjectGuid guid) override;
void MustReacquireTarget() { m_shouldReacquireTarget = true; } // flags the Creature for forced (client displayed) target reacquisition in the next ::Update call
+ void DoNotReacquireTarget() { m_shouldReacquireTarget = false; m_suppressedTarget = ObjectGuid::Empty; m_suppressedOrientation = 0.0f; }
void FocusTarget(Spell const* focusSpell, WorldObject const* target);
bool IsFocusing(Spell const* focusSpell = nullptr, bool withDelay = false);
void ReleaseFocus(Spell const* focusSpell = nullptr, bool withDelay = true);
diff --git a/src/server/game/Entities/Creature/GossipDef.h b/src/server/game/Entities/Creature/GossipDef.h
index 01b27032286..623b3de00a1 100644
--- a/src/server/game/Entities/Creature/GossipDef.h
+++ b/src/server/game/Entities/Creature/GossipDef.h
@@ -51,6 +51,7 @@ enum Gossip_Option
GOSSIP_OPTION_UNLEARNPETTALENTS = 17, //UNIT_NPC_FLAG_TRAINER (16) (bonus option for GOSSIP_OPTION_TRAINER)
GOSSIP_OPTION_LEARNDUALSPEC = 18, //UNIT_NPC_FLAG_TRAINER (16) (bonus option for GOSSIP_OPTION_TRAINER)
GOSSIP_OPTION_OUTDOORPVP = 19, //added by code (option for outdoor pvp creatures)
+ GOSSIP_OPTION_DUALSPEC_INFO = 20, //UNIT_NPC_FLAG_TRAINER (16) (bonus option for GOSSIP_OPTION_TRAINER)
GOSSIP_OPTION_MAX
};
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index b495b02ee72..f1365ac3150 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -310,6 +310,18 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u
if (map->Is25ManRaid())
loot.maxDuplicates = 3;
+ if (uint32 linkedEntry = GetGOInfo()->GetLinkedGameObjectEntry())
+ {
+ GameObject* linkedGO = new GameObject();
+ if (linkedGO->Create(map->GenerateLowGuid<HighGuid::GameObject>(), linkedEntry, map, phaseMask, pos, rotation, 255, GO_STATE_READY))
+ {
+ SetLinkedTrap(linkedGO);
+ map->AddToMap(linkedGO);
+ }
+ else
+ delete linkedGO;
+ }
+
return true;
}
@@ -428,6 +440,10 @@ void GameObject::Update(uint32 diff)
m_SkillupList.clear();
m_usetimes = 0;
+ // If nearby linked trap exists, respawn it
+ if (GameObject* linkedTrap = GetLinkedTrap())
+ linkedTrap->SetLootState(GO_READY);
+
switch (GetGoType())
{
case GAMEOBJECT_TYPE_FISHINGNODE: // can't fish now
@@ -511,11 +527,9 @@ void GameObject::Update(uint32 diff)
if (Unit* owner = GetOwner())
{
// Hunter trap: Search units which are unfriendly to the trap's owner
- Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck checker(this, owner, radius);
- Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck> searcher(this, target, checker);
- VisitNearbyGridObject(radius, searcher);
- if (!target)
- VisitNearbyWorldObject(radius, searcher);
+ Trinity::NearestAttackableNoTotemUnitInObjectRangeCheck checker(this, owner, radius);
+ Trinity::UnitLastSearcher<Trinity::NearestAttackableNoTotemUnitInObjectRangeCheck> searcher(this, target, checker);
+ VisitNearbyObject(radius, searcher);
}
else
{
@@ -613,6 +627,10 @@ void GameObject::Update(uint32 diff)
}
case GO_JUST_DEACTIVATED:
{
+ // If nearby linked trap exists, despawn it
+ if (GameObject* linkedTrap = GetLinkedTrap())
+ linkedTrap->SetLootState(GO_JUST_DEACTIVATED);
+
//if Gameobject should cast spell, then this, but some GOs (type = 10) should be destroyed
if (GetGoType() == GAMEOBJECT_TYPE_GOOBER)
{
@@ -1092,25 +1110,8 @@ void GameObject::TriggeringLinkedGameObject(uint32 trapEntry, Unit* target)
if (!trapSpell) // checked at load already
return;
- float range = float(target->GetSpellMaxRangeForTarget(GetOwner(), trapSpell));
-
- // search nearest linked GO
- GameObject* trapGO = nullptr;
- {
- // using original GO distance
- CellCoord p(Trinity::ComputeCellCoord(GetPositionX(), GetPositionY()));
- Cell cell(p);
-
- Trinity::NearestGameObjectEntryInObjectRangeCheck go_check(*target, trapEntry, range);
- Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> checker(this, trapGO, go_check);
-
- TypeContainerVisitor<Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck>, GridTypeMapContainer > object_checker(checker);
- cell.Visit(p, object_checker, *GetMap(), *target, range);
- }
-
- // found correct GO
- if (trapGO)
- trapGO->CastSpell(target, trapInfo->trap.spellId);
+ if (GameObject* trapGO = GetLinkedTrap())
+ trapGO->CastSpell(target, trapSpell->Id);
}
GameObject* GameObject::LookupFishingHoleAround(float range)
@@ -1828,18 +1829,23 @@ void GameObject::CastSpell(Unit* target, uint32 spellId, TriggerCastFlags trigge
if (!trigger)
return;
+ // remove immunity flags, to allow spell to target anything
+ trigger->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_IMMUNE_TO_PC);
+
if (Unit* owner = GetOwner())
{
trigger->setFaction(owner->getFaction());
if (owner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE))
trigger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
+ // copy pvp state flags from owner
+ trigger->SetByteValue(UNIT_FIELD_BYTES_2, 1, owner->GetByteValue(UNIT_FIELD_BYTES_2, 1));
// needed for GO casts for proper target validation checks
trigger->SetOwnerGUID(owner->GetGUID());
trigger->CastSpell(target ? target : trigger, spellInfo, triggered, nullptr, nullptr, owner->GetGUID());
}
else
{
- trigger->setFaction(14);
+ trigger->setFaction(spellInfo->IsPositive() ? 35 : 14);
// Set owner guid for target if no owner available - needed by trigger auras
// - trigger gets despawned and there's no caster avalible (see AuraEffect::TriggerSpell())
trigger->CastSpell(target ? target : trigger, spellInfo, triggered, nullptr, nullptr, target ? target->GetGUID() : ObjectGuid::Empty);
@@ -2187,7 +2193,7 @@ Group* GameObject::GetLootRecipientGroup() const
return sGroupMgr->GetGroupByGUID(m_lootRecipientGroup);
}
-void GameObject::SetLootRecipient(Unit* unit)
+void GameObject::SetLootRecipient(Unit* unit, Group* group)
{
// set the player whose group should receive the right
// to loot the creature after it dies
@@ -2196,7 +2202,7 @@ void GameObject::SetLootRecipient(Unit* unit)
if (!unit)
{
m_lootRecipient.Clear();
- m_lootRecipientGroup = 0;
+ m_lootRecipientGroup = group ? group->GetLowGUID() : 0;
return;
}
@@ -2208,8 +2214,12 @@ void GameObject::SetLootRecipient(Unit* unit)
return;
m_lootRecipient = player->GetGUID();
- if (Group* group = player->GetGroup())
+
+ // either get the group from the passed parameter or from unit's one
+ if (group)
m_lootRecipientGroup = group->GetLowGUID();
+ else if (Group* unitGroup = player->GetGroup())
+ m_lootRecipientGroup = unitGroup->GetLowGUID();
}
bool GameObject::IsLootAllowedFor(Player const* player) const
@@ -2227,6 +2237,11 @@ bool GameObject::IsLootAllowedFor(Player const* player) const
return true;
}
+GameObject* GameObject::GetLinkedTrap()
+{
+ return ObjectAccessor::GetGameObject(*this, m_linkedTrap);
+}
+
void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const
{
if (!target)
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index 842d5400fb2..dc7d99bb622 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -495,6 +495,7 @@ struct GameObjectTemplate
{
switch (type)
{
+ case GAMEOBJECT_TYPE_BUTTON: return button.linkedTrap;
case GAMEOBJECT_TYPE_CHEST: return chest.linkedTrapId;
case GAMEOBJECT_TYPE_SPELL_FOCUS: return spellFocus.linkedTrapId;
case GAMEOBJECT_TYPE_GOOBER: return goober.linkedTrapId;
@@ -812,12 +813,15 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
Player* GetLootRecipient() const;
Group* GetLootRecipientGroup() const;
- void SetLootRecipient(Unit* unit);
+ void SetLootRecipient(Unit* unit, Group* group = nullptr);
bool IsLootAllowedFor(Player const* player) const;
bool HasLootRecipient() const { return !m_lootRecipient.IsEmpty() || m_lootRecipientGroup; }
uint32 m_groupLootTimer; // (msecs)timer used for group loot
ObjectGuid::LowType lootingGroupLowGUID; // used to find group which is looting
+ GameObject* GetLinkedTrap();
+ void SetLinkedTrap(GameObject* linkedTrap) { m_linkedTrap = linkedTrap->GetGUID(); }
+
bool hasQuest(uint32 quest_id) const override;
bool hasInvolvedQuest(uint32 quest_id) const override;
bool ActivateToQuest(Player* target) const;
@@ -925,6 +929,9 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
ObjectGuid m_lootRecipient;
uint32 m_lootRecipientGroup;
uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
+
+ ObjectGuid m_linkedTrap;
+
private:
void RemoveFromOwner();
void SwitchDoorOrButton(bool activate, bool alternative = false);
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index a8dad0b2fbc..1173831be0b 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -256,11 +256,11 @@ Item::Item()
m_paidExtendedCost = 0;
}
-bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owner)
+bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemId, Player const* owner)
{
Object::_Create(guidlow, 0, HighGuid::Item);
- SetEntry(itemid);
+ SetEntry(itemId);
SetObjectScale(1.0f);
if (owner)
@@ -269,7 +269,7 @@ bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owne
SetGuidValue(ITEM_FIELD_CONTAINED, owner->GetGUID());
}
- ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(itemid);
+ ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(itemId);
if (!itemProto)
return false;
@@ -357,7 +357,7 @@ void Item::SaveToDB(SQLTransaction& trans)
trans->Append(stmt);
- if ((uState == ITEM_CHANGED) && HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))
+ if ((uState == ITEM_CHANGED) && HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED))
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GIFT_OWNER);
stmt->setUInt32(0, GetOwnerGUID().GetCounter());
@@ -372,7 +372,7 @@ void Item::SaveToDB(SQLTransaction& trans)
stmt->setUInt32(0, guid);
trans->Append(stmt);
- if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))
+ if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED))
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT);
stmt->setUInt32(0, guid);
@@ -443,7 +443,7 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fi
// Remove bind flag for items vs NO_BIND set
if (IsSoulBound() && proto->Bonding == NO_BIND)
{
- ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND, false);
+ ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND, false);
need_save = true;
}
@@ -746,7 +746,7 @@ bool Item::CanBeTraded(bool mail, bool trade) const
if (m_lootGenerated)
return false;
- if ((!mail || !IsBoundAccountWide()) && (IsSoulBound() && (!HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE) || !trade)))
+ if ((!mail || !IsBoundAccountWide()) && (IsSoulBound() && (!HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE) || !trade)))
return false;
if (IsBag() && (Player::IsBagPos(GetPos()) || !((Bag const*)this)->IsEmpty()))
@@ -824,13 +824,13 @@ bool Item::IsFitToSpellRequirements(SpellInfo const* spellInfo) const
{
ItemTemplate const* proto = GetTemplate();
+ bool const isEnchantSpell = spellInfo->HasEffect(SPELL_EFFECT_ENCHANT_ITEM) || spellInfo->HasEffect(SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) || spellInfo->HasEffect(SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC);
if (spellInfo->EquippedItemClass != -1) // -1 == any item class
{
// Special case - accept vellum for armor/weapon requirements
- if ((spellInfo->EquippedItemClass == ITEM_CLASS_ARMOR && proto->IsArmorVellum())
- ||(spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && proto->IsWeaponVellum()))
- if (spellInfo->IsAbilityOfSkillType(SKILL_ENCHANTING)) // only for enchanting spells
- return true;
+ if (isEnchantSpell && ((spellInfo->EquippedItemClass == ITEM_CLASS_ARMOR && proto->IsArmorVellum())
+ || (spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && proto->IsWeaponVellum())))
+ return true;
if (spellInfo->EquippedItemClass != int32(proto->Class))
return false; // wrong item class
@@ -842,7 +842,7 @@ bool Item::IsFitToSpellRequirements(SpellInfo const* spellInfo) const
}
}
- if (spellInfo->EquippedItemInventoryTypeMask != 0) // 0 == any inventory type
+ if (isEnchantSpell && spellInfo->EquippedItemInventoryTypeMask != 0) // 0 == any inventory type
{
// Special case - accept weapon type for main and offhand requirements
if (proto->InventoryType == INVTYPE_WEAPON &&
@@ -1017,10 +1017,10 @@ void Item::SendTimeUpdate(Player* owner)
owner->GetSession()->SendPacket(&data);
}
-Item* Item::CreateItem(uint32 itemEntry, uint32 count, Player const* player)
+Item* Item::CreateItem(uint32 itemEntry, uint32 count, Player const* player /*= nullptr*/)
{
if (count < 1)
- return NULL; //don't create item at zero count
+ return nullptr; //don't create item at zero count
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry);
if (proto)
@@ -1041,18 +1041,18 @@ Item* Item::CreateItem(uint32 itemEntry, uint32 count, Player const* player)
}
else
ABORT();
- return NULL;
+ return nullptr;
}
-Item* Item::CloneItem(uint32 count, Player const* player) const
+Item* Item::CloneItem(uint32 count, Player const* player /*= nullptr*/) const
{
Item* newItem = CreateItem(GetEntry(), count, player);
if (!newItem)
- return NULL;
+ return nullptr;
newItem->SetGuidValue(ITEM_FIELD_CREATOR, GetGuidValue(ITEM_FIELD_CREATOR));
newItem->SetGuidValue(ITEM_FIELD_GIFTCREATOR, GetGuidValue(ITEM_FIELD_GIFTCREATOR));
- newItem->SetUInt32Value(ITEM_FIELD_FLAGS, GetUInt32Value(ITEM_FIELD_FLAGS) & ~(ITEM_FLAG_REFUNDABLE | ITEM_FLAG_BOP_TRADEABLE));
+ newItem->SetUInt32Value(ITEM_FIELD_FLAGS, GetUInt32Value(ITEM_FIELD_FLAGS) & ~(ITEM_FIELD_FLAG_REFUNDABLE | ITEM_FIELD_FLAG_BOP_TRADEABLE));
newItem->SetUInt32Value(ITEM_FIELD_DURATION, GetUInt32Value(ITEM_FIELD_DURATION));
// player CAN be NULL in which case we must not update random properties because that accesses player's item update queue
if (player)
@@ -1070,7 +1070,7 @@ bool Item::IsBindedNotWith(Player const* player) const
if (GetOwnerGUID() == player->GetGUID())
return false;
- if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE))
+ if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE))
if (allowedGUIDs.find(player->GetGUID().GetCounter()) != allowedGUIDs.end())
return false;
@@ -1131,10 +1131,10 @@ void Item::DeleteRefundDataFromDB(SQLTransaction* trans)
void Item::SetNotRefundable(Player* owner, bool changestate /*=true*/, SQLTransaction* trans /*=NULL*/)
{
- if (!HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE))
+ if (!HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE))
return;
- RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE);
+ RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE);
// Following is not applicable in the trading procedure
if (changestate)
SetState(ITEM_CHANGED, owner);
@@ -1189,13 +1189,13 @@ bool Item::IsRefundExpired()
void Item::SetSoulboundTradeable(AllowedLooterSet const& allowedLooters)
{
- SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE);
+ SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE);
allowedGUIDs = allowedLooters;
}
void Item::ClearSoulboundTradeable(Player* currentOwner)
{
- RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE);
+ RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE);
if (allowedGUIDs.empty())
return;
@@ -1346,7 +1346,7 @@ bool Item::ItemContainerLoadLootFromDB()
// If container item is in a bag, add that player as an allowed looter
if (GetBagSlot())
- loot_item.allowedGUIDs.insert(GetOwner()->GetGUID().GetCounter());
+ loot_item.AddAllowedLooter(GetOwner());
// Finally add the LootItem to the container
loot.items.push_back(loot_item);
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index 5e00a816cab..edc7001e1c4 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -206,12 +206,12 @@ bool ItemCanGoIntoBag(ItemTemplate const* proto, ItemTemplate const* pBagProto);
class TC_GAME_API Item : public Object
{
public:
- static Item* CreateItem(uint32 itemEntry, uint32 count, Player const* player = NULL);
- Item* CloneItem(uint32 count, Player const* player = NULL) const;
+ static Item* CreateItem(uint32 itemEntry, uint32 count, Player const* player = nullptr);
+ Item* CloneItem(uint32 count, Player const* player = nullptr) const;
Item();
- virtual bool Create(ObjectGuid::LowType guidlow, ObjectGuid::LowType itemid, Player const* owner);
+ virtual bool Create(ObjectGuid::LowType guidlow, uint32 itemId, Player const* owner);
ItemTemplate const* GetTemplate() const;
@@ -219,9 +219,9 @@ class TC_GAME_API Item : public Object
void SetOwnerGUID(ObjectGuid guid) { SetGuidValue(ITEM_FIELD_OWNER, guid); }
Player* GetOwner()const;
- void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND, val); }
- bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND); }
- bool IsBoundAccountWide() const { return (GetTemplate()->Flags & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT) != 0; }
+ void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND, val); }
+ bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND); }
+ bool IsBoundAccountWide() const { return (GetTemplate()->Flags & ITEM_FLAG_IS_BOUND_TO_ACCOUNT) != 0; }
bool IsBindedNotWith(Player const* player) const;
bool IsBoundByEnchant() const;
virtual void SaveToDB(SQLTransaction& trans);
@@ -245,7 +245,7 @@ class TC_GAME_API Item : public Object
Bag* ToBag() { if (IsBag()) return reinterpret_cast<Bag*>(this); else return NULL; }
const Bag* ToBag() const { if (IsBag()) return reinterpret_cast<const Bag*>(this); else return NULL; }
- bool IsLocked() const { return !HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_UNLOCKED); }
+ bool IsLocked() const { return !HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_UNLOCKED); }
bool IsBag() const { return GetTemplate()->InventoryType == INVTYPE_BAG; }
bool IsCurrencyToken() const { return GetTemplate()->IsCurrencyToken(); }
bool IsNotEmptyBag() const;
diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h
index 0ff3f00a08b..8cc408b47fb 100644
--- a/src/server/game/Entities/Item/ItemTemplate.h
+++ b/src/server/game/Entities/Item/ItemTemplate.h
@@ -103,88 +103,117 @@ enum ItemBondingType
#define MAX_BIND_TYPE 6
/* /// @todo: Requiring actual cases in which using (an) item isn't allowed while shapeshifted. Else, this flag would need an implementation.
- ITEM_PROTO_FLAG_USABLE_WHEN_SHAPESHIFTED = 0x00800000, // Item can be used in shapeshift forms */
-
-enum ItemProtoFlags
-{
- ITEM_PROTO_FLAG_NO_PICKUP = 0x00000001, // ?
- ITEM_PROTO_FLAG_CONJURED = 0x00000002, // Conjured item
- ITEM_PROTO_FLAG_HAS_LOOT = 0x00000004, // Item can be right clicked to open for loot
- ITEM_PROTO_FLAG_HEROIC = 0x00000008, // Makes green "Heroic" text appear on item
- ITEM_PROTO_FLAG_DEPRECATED = 0x00000010, // Cannot equip or use
- ITEM_PROTO_FLAG_INDESTRUCTIBLE = 0x00000020, // Item can not be destroyed, except by using spell (item can be reagent for spell)
- ITEM_PROTO_FLAG_PLAYER_CAST = 0x00000040, // Item's spells are castable by players
- ITEM_PROTO_FLAG_NO_EQUIP_COOLDOWN = 0x00000080, // No default 30 seconds cooldown when equipped
- ITEM_PROTO_FLAG_INT_BONUS_INSTEAD = 0x00000100, // ?
- ITEM_PROTO_FLAG_IS_WRAPPER = 0x00000200, // Item can wrap other items
- ITEM_PROTO_FLAG_USES_RESOURCES = 0x00000400, // ?
- ITEM_PROTO_FLAG_MULTI_DROP = 0x00000800, // Looting this item does not remove it from available loot
- ITEM_PROTO_FLAG_REFUNDABLE = 0x00001000, // Item can be returned to vendor for its original cost (extended cost)
- ITEM_PROTO_FLAG_PETITION = 0x00002000, // Item is guild or arena charter
- ITEM_PROTO_FLAG_UNK5 = 0x00004000, // Only readable items have this (but not all)
- ITEM_PROTO_FLAG_UNK6 = 0x00008000, // ?
- ITEM_PROTO_FLAG_UNK7 = 0x00010000, // ?
- ITEM_PROTO_FLAG_UNK8 = 0x00020000, // ?
- ITEM_PROTO_FLAG_PROSPECTABLE = 0x00040000, // Item can be prospected
- ITEM_PROTO_FLAG_UNIQUE_EQUIPPED = 0x00080000, // You can only equip one of these
- ITEM_PROTO_FLAG_UNK9 = 0x00100000, // ?
- ITEM_PROTO_FLAG_USEABLE_IN_ARENA = 0x00200000, // Item can be used during arena match
- ITEM_PROTO_FLAG_THROWABLE = 0x00400000, // Some Thrown weapons have it (and only Thrown) but not all
- ITEM_PROTO_FLAG_USABLE_WHEN_SHAPESHIFTED = 0x00800000, // Item can be used in shapeshift forms
- ITEM_PROTO_FLAG_UNK10 = 0x01000000, // ?
- ITEM_PROTO_FLAG_SMART_LOOT = 0x02000000, // Profession recipes: can only be looted if you meet requirements and don't already know it
- ITEM_PROTO_FLAG_NOT_USEABLE_IN_ARENA = 0x04000000, // Item cannot be used in arena
- ITEM_PROTO_FLAG_BIND_TO_ACCOUNT = 0x08000000, // Item binds to account and can be sent only to your own characters
- ITEM_PROTO_FLAG_TRIGGERED_CAST = 0x10000000, // Spell is cast with triggered flag
- ITEM_PROTO_FLAG_MILLABLE = 0x20000000, // Item can be milled
- ITEM_PROTO_FLAG_UNK11 = 0x40000000, // ?
- ITEM_PROTO_FLAG_UNK12 = 0x80000000 // ?
-};
-
-enum ItemFieldFlags
-{
- ITEM_FLAG_SOULBOUND = 0x00000001, // Item is soulbound and cannot be traded <<--
- ITEM_FLAG_UNK1 = 0x00000002, // ?
- ITEM_FLAG_UNLOCKED = 0x00000004, // Item had lock but can be opened now
- ITEM_FLAG_WRAPPED = 0x00000008, // Item is wrapped and contains another item
- ITEM_FLAG_UNK2 = 0x00000010, // ?
- ITEM_FLAG_UNK3 = 0x00000020, // ?
- ITEM_FLAG_UNK4 = 0x00000040, // ?
- ITEM_FLAG_UNK5 = 0x00000080, // ?
- ITEM_FLAG_BOP_TRADEABLE = 0x00000100, // Allows trading soulbound items
- ITEM_FLAG_READABLE = 0x00000200, // Opens text page when right clicked
- ITEM_FLAG_UNK6 = 0x00000400, // ?
- ITEM_FLAG_UNK7 = 0x00000800, // ?
- ITEM_FLAG_REFUNDABLE = 0x00001000, // Item can be returned to vendor for its original cost (extended cost)
- ITEM_FLAG_UNK8 = 0x00002000, // ?
- ITEM_FLAG_UNK9 = 0x00004000, // ?
- ITEM_FLAG_UNK10 = 0x00008000, // ?
- ITEM_FLAG_UNK11 = 0x00010000, // ?
- ITEM_FLAG_UNK12 = 0x00020000, // ?
- ITEM_FLAG_UNK13 = 0x00040000, // ?
- ITEM_FLAG_UNK14 = 0x00080000, // ?
- ITEM_FLAG_UNK15 = 0x00100000, // ?
- ITEM_FLAG_UNK16 = 0x00200000, // ?
- ITEM_FLAG_UNK17 = 0x00400000, // ?
- ITEM_FLAG_UNK18 = 0x00800000, // ?
- ITEM_FLAG_UNK19 = 0x01000000, // ?
- ITEM_FLAG_UNK20 = 0x02000000, // ?
- ITEM_FLAG_UNK21 = 0x04000000, // ?
- ITEM_FLAG_UNK22 = 0x08000000, // ?
- ITEM_FLAG_UNK23 = 0x10000000, // ?
- ITEM_FLAG_UNK24 = 0x20000000, // ?
- ITEM_FLAG_UNK25 = 0x40000000, // ?
- ITEM_FLAG_UNK26 = 0x80000000, // ?
-
- ITEM_FLAG_MAIL_TEXT_MASK = ITEM_FLAG_READABLE | ITEM_FLAG_UNK13 | ITEM_FLAG_UNK14
-};
-
-enum ItemFlagsExtra
-{
- ITEM_FLAGS_EXTRA_HORDE_ONLY = 0x00000001,
- ITEM_FLAGS_EXTRA_ALLIANCE_ONLY = 0x00000002,
- ITEM_FLAGS_EXTRA_EXT_COST_REQUIRES_GOLD = 0x00000004, // when item uses extended cost, gold is also required
- ITEM_FLAGS_EXTRA_NEED_ROLL_DISABLED = 0x00000100
+ ITEM_FLAG_USE_WHEN_SHAPESHIFTED = 0x00800000, // Item can be used in shapeshift forms */
+
+// ITEM_FIELD_FLAGS
+enum ItemFieldFlags : uint32
+{
+ ITEM_FIELD_FLAG_SOULBOUND = 0x00000001, // Item is soulbound and cannot be traded <<--
+ ITEM_FIELD_FLAG_UNK1 = 0x00000002, // ?
+ ITEM_FIELD_FLAG_UNLOCKED = 0x00000004, // Item had lock but can be opened now
+ ITEM_FIELD_FLAG_WRAPPED = 0x00000008, // Item is wrapped and contains another item
+ ITEM_FIELD_FLAG_UNK2 = 0x00000010, // ?
+ ITEM_FIELD_FLAG_UNK3 = 0x00000020, // ?
+ ITEM_FIELD_FLAG_UNK4 = 0x00000040, // ?
+ ITEM_FIELD_FLAG_UNK5 = 0x00000080, // ?
+ ITEM_FIELD_FLAG_BOP_TRADEABLE = 0x00000100, // Allows trading soulbound items
+ ITEM_FIELD_FLAG_READABLE = 0x00000200, // Opens text page when right clicked
+ ITEM_FIELD_FLAG_UNK6 = 0x00000400, // ?
+ ITEM_FIELD_FLAG_UNK7 = 0x00000800, // ?
+ ITEM_FIELD_FLAG_REFUNDABLE = 0x00001000, // Item can be returned to vendor for its original cost (extended cost)
+ ITEM_FIELD_FLAG_UNK8 = 0x00002000, // ?
+ ITEM_FIELD_FLAG_UNK9 = 0x00004000, // ?
+ ITEM_FIELD_FLAG_UNK10 = 0x00008000, // ?
+ ITEM_FIELD_FLAG_UNK11 = 0x00010000, // ?
+ ITEM_FIELD_FLAG_UNK12 = 0x00020000, // ?
+ ITEM_FIELD_FLAG_UNK13 = 0x00040000, // ?
+ ITEM_FIELD_FLAG_UNK14 = 0x00080000, // ?
+ ITEM_FIELD_FLAG_UNK15 = 0x00100000, // ?
+ ITEM_FIELD_FLAG_UNK16 = 0x00200000, // ?
+ ITEM_FIELD_FLAG_UNK17 = 0x00400000, // ?
+ ITEM_FIELD_FLAG_UNK18 = 0x00800000, // ?
+ ITEM_FIELD_FLAG_UNK19 = 0x01000000, // ?
+ ITEM_FIELD_FLAG_UNK20 = 0x02000000, // ?
+ ITEM_FIELD_FLAG_UNK21 = 0x04000000, // ?
+ ITEM_FIELD_FLAG_UNK22 = 0x08000000, // ?
+ ITEM_FIELD_FLAG_UNK23 = 0x10000000, // ?
+ ITEM_FIELD_FLAG_UNK24 = 0x20000000, // ?
+ ITEM_FIELD_FLAG_UNK25 = 0x40000000, // ?
+ ITEM_FIELD_FLAG_UNK26 = 0x80000000, // ?
+
+ ITEM_FLAG_MAIL_TEXT_MASK = ITEM_FIELD_FLAG_READABLE | ITEM_FIELD_FLAG_UNK13 | ITEM_FIELD_FLAG_UNK14
+};
+
+enum ItemFlags : uint32
+{
+ ITEM_FLAG_NO_PICKUP = 0x00000001,
+ ITEM_FLAG_CONJURED = 0x00000002, // Conjured item
+ ITEM_FLAG_HAS_LOOT = 0x00000004, // Item can be right clicked to open for loot
+ ITEM_FLAG_HEROIC_TOOLTIP = 0x00000008, // Makes green "Heroic" text appear on item
+ ITEM_FLAG_DEPRECATED = 0x00000010, // Cannot equip or use
+ ITEM_FLAG_NO_USER_DESTROY = 0x00000020, // Item can not be destroyed, except by using spell (item can be reagent for spell)
+ ITEM_FLAG_PLAYERCAST = 0x00000040, // Item's spells are castable by players
+ ITEM_FLAG_NO_EQUIP_COOLDOWN = 0x00000080, // No default 30 seconds cooldown when equipped
+ ITEM_FLAG_MULTI_LOOT_QUEST = 0x00000100,
+ ITEM_FLAG_IS_WRAPPER = 0x00000200, // Item can wrap other items
+ ITEM_FLAG_USES_RESOURCES = 0x00000400,
+ ITEM_FLAG_MULTI_DROP = 0x00000800, // Looting this item does not remove it from available loot
+ ITEM_FLAG_ITEM_PURCHASE_RECORD = 0x00001000, // Item can be returned to vendor for its original cost (extended cost)
+ ITEM_FLAG_PETITION = 0x00002000, // Item is guild or arena charter
+ ITEM_FLAG_HAS_TEXT = 0x00004000, // Only readable items have this (but not all)
+ ITEM_FLAG_NO_DISENCHANT = 0x00008000,
+ ITEM_FLAG_REAL_DURATION = 0x00010000,
+ ITEM_FLAG_NO_CREATOR = 0x00020000,
+ ITEM_FLAG_IS_PROSPECTABLE = 0x00040000, // Item can be prospected
+ ITEM_FLAG_UNIQUE_EQUIPPABLE = 0x00080000, // You can only equip one of these
+ ITEM_FLAG_IGNORE_FOR_AURAS = 0x00100000,
+ ITEM_FLAG_IGNORE_DEFAULT_ARENA_RESTRICTIONS = 0x00200000, // Item can be used during arena match
+ ITEM_FLAG_NO_DURABILITY_LOSS = 0x00400000, // Some Thrown weapons have it (and only Thrown) but not all
+ ITEM_FLAG_USE_WHEN_SHAPESHIFTED = 0x00800000, // Item can be used in shapeshift forms
+ ITEM_FLAG_HAS_QUEST_GLOW = 0x01000000,
+ ITEM_FLAG_HIDE_UNUSABLE_RECIPE = 0x02000000, // Profession recipes: can only be looted if you meet requirements and don't already know it
+ ITEM_FLAG_NOT_USEABLE_IN_ARENA = 0x04000000, // Item cannot be used in arena
+ ITEM_FLAG_IS_BOUND_TO_ACCOUNT = 0x08000000, // Item binds to account and can be sent only to your own characters
+ ITEM_FLAG_NO_REAGENT_COST = 0x10000000, // Spell is cast ignoring reagents
+ ITEM_FLAG_IS_MILLABLE = 0x20000000, // Item can be milled
+ ITEM_FLAG_REPORT_TO_GUILD_CHAT = 0x40000000,
+ ITEM_FLAG_NO_PROGRESSIVE_LOOT = 0x80000000
+};
+
+enum ItemFlags2 : uint32
+{
+ ITEM_FLAG2_FACTION_HORDE = 0x00000001,
+ ITEM_FLAG2_FACTION_ALLIANCE = 0x00000002,
+ ITEM_FLAG2_DONT_IGNORE_BUY_PRICE = 0x00000004, // when item uses extended cost, gold is also required
+ ITEM_FLAG2_CLASSIFY_AS_CASTER = 0x00000008,
+ ITEM_FLAG2_CLASSIFY_AS_PHYSICAL = 0x00000010,
+ ITEM_FLAG2_EVERYONE_CAN_ROLL_NEED = 0x00000020,
+ ITEM_FLAG2_NO_TRADE_BIND_ON_ACQUIRE = 0x00000040,
+ ITEM_FLAG2_CAN_TRADE_BIND_ON_ACQUIRE = 0x00000080,
+ ITEM_FLAG2_CAN_ONLY_ROLL_GREED = 0x00000100,
+ ITEM_FLAG2_CASTER_WEAPON = 0x00000200,
+ ITEM_FLAG2_DELETE_ON_LOGIN = 0x00000400,
+ ITEM_FLAG2_INTERNAL_ITEM = 0x00000800,
+ ITEM_FLAG2_NO_VENDOR_VALUE = 0x00001000,
+ ITEM_FLAG2_SHOW_BEFORE_DISCOVERED = 0x00002000,
+ ITEM_FLAG2_OVERRIDE_GOLD_COST = 0x00004000,
+ ITEM_FLAG2_IGNORE_DEFAULT_RATED_BG_RESTRICTIONS = 0x00008000,
+ ITEM_FLAG2_NOT_USABLE_IN_RATED_BG = 0x00010000,
+ ITEM_FLAG2_BNET_ACCOUNT_TRADE_OK = 0x00020000,
+ ITEM_FLAG2_CONFIRM_BEFORE_USE = 0x00040000,
+ ITEM_FLAG2_REEVALUATE_BONDING_ON_TRANSFORM = 0x00080000,
+ ITEM_FLAG2_NO_TRANSFORM_ON_CHARGE_DEPLETION = 0x00100000,
+ ITEM_FLAG2_NO_ALTER_ITEM_VISUAL = 0x00200000,
+ ITEM_FLAG2_NO_SOURCE_FOR_ITEM_VISUAL = 0x00400000,
+ ITEM_FLAG2_IGNORE_QUALITY_FOR_ITEM_VISUAL_SOURCE = 0x00800000,
+ ITEM_FLAG2_NO_DURABILITY = 0x01000000,
+ ITEM_FLAG2_ROLE_TANK = 0x02000000,
+ ITEM_FLAG2_ROLE_HEALER = 0x04000000,
+ ITEM_FLAG2_ROLE_DAMAGE = 0x08000000,
+ ITEM_FLAG2_CAN_DROP_IN_CHALLENGE_MODE = 0x10000000,
+ ITEM_FLAG2_NEVER_STACK_IN_LOOT_UI = 0x20000000,
+ ITEM_FLAG2_DISENCHANT_TO_LOOT_TABLE = 0x40000000,
+ ITEM_FLAG2_USED_IN_A_TRADESKILL = 0x80000000
};
enum ItemFlagsCustom
@@ -674,7 +703,7 @@ struct ItemTemplate
bool IsPotion() const { return Class == ITEM_CLASS_CONSUMABLE && SubClass == ITEM_SUBCLASS_POTION; }
bool IsWeaponVellum() const { return Class == ITEM_CLASS_TRADE_GOODS && SubClass == ITEM_SUBCLASS_WEAPON_ENCHANTMENT; }
bool IsArmorVellum() const { return Class == ITEM_CLASS_TRADE_GOODS && SubClass == ITEM_SUBCLASS_ARMOR_ENCHANTMENT; }
- bool IsConjuredConsumable() const { return Class == ITEM_CLASS_CONSUMABLE && (Flags & ITEM_PROTO_FLAG_CONJURED); }
+ bool IsConjuredConsumable() const { return Class == ITEM_CLASS_CONSUMABLE && (Flags & ITEM_FLAG_CONJURED); }
};
// Benchmarked: Faster than std::map (insert/find)
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index d3daab43b91..a5f5aa18b1d 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -173,7 +173,7 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c
if (flags & UPDATEFLAG_STATIONARY_POSITION)
{
// UPDATETYPE_CREATE_OBJECT2 dynamic objects, corpses...
- if (isType(TYPEMASK_DYNAMICOBJECT) || isType(TYPEMASK_CORPSE) || isType(TYPEMASK_PLAYER))
+ if (isType(TYPEMASK_DYNAMICOBJECT | TYPEMASK_CORPSE | TYPEMASK_PLAYER))
updateType = UPDATETYPE_CREATE_OBJECT2;
// UPDATETYPE_CREATE_OBJECT2 for pets...
@@ -2116,114 +2116,42 @@ GameObject* WorldObject::FindNearestGameObjectOfType(GameobjectTypes type, float
return go;
}
-void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>& gameobjectList, uint32 entry, float maxSearchRange) const
+template <typename Container>
+void WorldObject::GetGameObjectListWithEntryInGrid(Container& gameObjectContainer, uint32 entry, float maxSearchRange /*= 250.0f*/) const
{
- CellCoord pair(Trinity::ComputeCellCoord(this->GetPositionX(), this->GetPositionY()));
+ CellCoord pair(Trinity::ComputeCellCoord(GetPositionX(), GetPositionY()));
Cell cell(pair);
cell.SetNoCreate();
Trinity::AllGameObjectsWithEntryInRange check(this, entry, maxSearchRange);
- Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInRange> searcher(this, gameobjectList, check);
+ Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInRange> searcher(this, gameObjectContainer, check);
TypeContainerVisitor<Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInRange>, GridTypeMapContainer> visitor(searcher);
- cell.Visit(pair, visitor, *(this->GetMap()), *this, maxSearchRange);
+ cell.Visit(pair, visitor, *GetMap(), *this, maxSearchRange);
}
-void WorldObject::GetCreatureListWithEntryInGrid(std::list<Creature*>& creatureList, uint32 entry, float maxSearchRange) const
+template <typename Container>
+void WorldObject::GetCreatureListWithEntryInGrid(Container& creatureContainer, uint32 entry, float maxSearchRange /*= 250.0f*/) const
{
- CellCoord pair(Trinity::ComputeCellCoord(this->GetPositionX(), this->GetPositionY()));
+ CellCoord pair(Trinity::ComputeCellCoord(GetPositionX(), GetPositionY()));
Cell cell(pair);
cell.SetNoCreate();
Trinity::AllCreaturesOfEntryInRange check(this, entry, maxSearchRange);
- Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange> searcher(this, creatureList, check);
+ Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange> searcher(this, creatureContainer, check);
TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange>, GridTypeMapContainer> visitor(searcher);
- cell.Visit(pair, visitor, *(this->GetMap()), *this, maxSearchRange);
+ cell.Visit(pair, visitor, *GetMap(), *this, maxSearchRange);
}
-void WorldObject::GetPlayerListInGrid(std::list<Player*>& playerList, float maxSearchRange) const
+template <typename Container>
+void WorldObject::GetPlayerListInGrid(Container& playerContainer, float maxSearchRange) const
{
Trinity::AnyPlayerInObjectRangeCheck checker(this, maxSearchRange);
- Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(this, playerList, checker);
- this->VisitNearbyWorldObject(maxSearchRange, searcher);
+ Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(this, playerContainer, checker);
+ VisitNearbyWorldObject(maxSearchRange, searcher);
}
-/*
-namespace Trinity
-{
- class NearUsedPosDo
- {
- public:
- NearUsedPosDo(WorldObject const& obj, WorldObject const* searcher, float angle, ObjectPosSelector& selector)
- : i_object(obj), i_searcher(searcher), i_angle(angle), i_selector(selector) { }
-
- void operator()(Corpse*) const { }
- void operator()(DynamicObject*) const { }
-
- void operator()(Creature* c) const
- {
- // skip self or target
- if (c == i_searcher || c == &i_object)
- return;
-
- float x, y, z;
-
- if (!c->IsAlive() || c->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED) ||
- !c->GetMotionMaster()->GetDestination(x, y, z))
- {
- x = c->GetPositionX();
- y = c->GetPositionY();
- }
-
- add(c, x, y);
- }
-
- template<class T>
- void operator()(T* u) const
- {
- // skip self or target
- if (u == i_searcher || u == &i_object)
- return;
-
- float x, y;
-
- x = u->GetPositionX();
- y = u->GetPositionY();
-
- add(u, x, y);
- }
-
- // we must add used pos that can fill places around center
- void add(WorldObject* u, float x, float y) const
- {
- // u is too nearest/far away to i_object
- if (!i_object.IsInRange2d(x, y, i_selector.m_dist - i_selector.m_size, i_selector.m_dist + i_selector.m_size))
- return;
-
- float angle = i_object.GetAngle(u)-i_angle;
-
- // move angle to range -pi ... +pi
- while (angle > M_PI)
- angle -= 2.0f * M_PI;
- while (angle < -M_PI)
- angle += 2.0f * M_PI;
-
- // dist include size of u
- float dist2d = i_object.GetDistance2d(x, y);
- i_selector.AddUsedPos(u->GetObjectSize(), angle, dist2d + i_object.GetObjectSize());
- }
- private:
- WorldObject const& i_object;
- WorldObject const* i_searcher;
- float i_angle;
- ObjectPosSelector& i_selector;
- };
-} // namespace Trinity
-*/
-
-//===================================================================================================
-
void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float absAngle) const
{
x = GetPositionX() + (GetObjectSize() + distance2d) * std::cos(absAngle);
@@ -2475,6 +2403,16 @@ void WorldObject::PlayDirectSound(uint32 sound_id, Player* target /*= NULL*/)
SendMessageToSet(&data, true);
}
+void WorldObject::PlayDirectMusic(uint32 music_id, Player* target /*= NULL*/)
+{
+ WorldPacket data(SMSG_PLAY_MUSIC, 4);
+ data << uint32(music_id);
+ if (target)
+ target->SendDirectMessage(&data);
+ else
+ SendMessageToSet(&data, true);
+}
+
void WorldObject::DestroyForNearbyPlayers()
{
if (!IsInWorld())
@@ -2613,3 +2551,15 @@ ObjectGuid WorldObject::GetTransGUID() const
return GetTransport()->GetGUID();
return ObjectGuid::Empty;
}
+
+template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>&, uint32, float) const;
+template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::deque<GameObject*>&, uint32, float) const;
+template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::vector<GameObject*>&, uint32, float) const;
+
+template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::list<Creature*>&, uint32, float) const;
+template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::deque<Creature*>&, uint32, float) const;
+template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::vector<Creature*>&, uint32, float) const;
+
+template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::list<Player*>&, float) const;
+template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::deque<Player*>&, float) const;
+template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::vector<Player*>&, float) const;
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index 22528f8508a..e107a5f6bfd 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -513,6 +513,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
void PlayDistanceSound(uint32 sound_id, Player* target = NULL);
void PlayDirectSound(uint32 sound_id, Player* target = NULL);
+ void PlayDirectMusic(uint32 music_id, Player* target = NULL);
void SendObjectDeSpawnAnim(ObjectGuid guid);
@@ -557,9 +558,14 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
GameObject* FindNearestGameObject(uint32 entry, float range) const;
GameObject* FindNearestGameObjectOfType(GameobjectTypes type, float range) const;
- void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& lList, uint32 uiEntry = 0, float fMaxSearchRange = 250.0f) const;
- void GetCreatureListWithEntryInGrid(std::list<Creature*>& lList, uint32 uiEntry = 0, float fMaxSearchRange = 250.0f) const;
- void GetPlayerListInGrid(std::list<Player*>& lList, float fMaxSearchRange) const;
+ template <typename Container>
+ void GetGameObjectListWithEntryInGrid(Container& gameObjectContainer, uint32 entry, float maxSearchRange = 250.0f) const;
+
+ template <typename Container>
+ void GetCreatureListWithEntryInGrid(Container& creatureContainer, uint32 entry, float maxSearchRange = 250.0f) const;
+
+ template <typename Container>
+ void GetPlayerListInGrid(Container& playerContainer, float maxSearchRange) const;
void DestroyForNearbyPlayers();
virtual void UpdateObjectVisibility(bool forced = true);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 7a07b9d980c..3e0f9078c2c 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -401,6 +401,7 @@ Player::Player(WorldSession* session): Unit(true)
m_canParry = false;
m_canBlock = false;
m_canTitanGrip = false;
+ m_titanGripPenaltySpellId = 0;
m_ammoDPS = 0.0f;
m_temporaryUnsummonedPetNumber = 0;
@@ -938,12 +939,21 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage)
// Absorb, resist some environmental damage type
uint32 absorb = 0;
uint32 resist = 0;
- if (type == DAMAGE_LAVA)
- CalcAbsorbResist(this, SPELL_SCHOOL_MASK_FIRE, DIRECT_DAMAGE, damage, &absorb, &resist);
- else if (type == DAMAGE_SLIME)
- CalcAbsorbResist(this, SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, damage, &absorb, &resist);
-
- damage -= absorb + resist;
+ switch (type)
+ {
+ case DAMAGE_LAVA:
+ case DAMAGE_SLIME:
+ {
+ DamageInfo dmgInfo(this, this, damage, nullptr, type == DAMAGE_LAVA ? SPELL_SCHOOL_MASK_FIRE : SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, BASE_ATTACK);
+ CalcAbsorbResist(dmgInfo);
+ absorb = dmgInfo.GetAbsorb();
+ resist = dmgInfo.GetResist();
+ damage = dmgInfo.GetDamage();
+ break;
+ }
+ default:
+ break;
+ }
DealDamageMods(this, damage, &absorb);
@@ -3313,7 +3323,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
if (active)
{
if (spellInfo->IsPassive() && IsNeedCastPassiveSpellAtLearn(spellInfo))
- CastSpell (this, spellId, true);
+ CastSpell(this, spellId, true);
}
else if (IsInWorld())
{
@@ -3587,6 +3597,15 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const
bool need_cast = (!spellInfo->Stances || (form && (spellInfo->Stances & (UI64LIT(1) << (form - 1)))) ||
(!form && spellInfo->HasAttribute(SPELL_ATTR2_NOT_NEED_SHAPESHIFT)));
+ // Check EquippedItemClass
+ // passive spells which apply aura and have an item requirement are to be added in Player::ApplyItemDependentAuras
+ if (spellInfo->IsPassive() && spellInfo->EquippedItemClass >= 0)
+ {
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (spellInfo->Effects[i].IsAura())
+ return false;
+ }
+
//Check CasterAuraStates
return need_cast && (!spellInfo->CasterAuraState || HasAuraState(AuraStateType(spellInfo->CasterAuraState)));
}
@@ -3816,7 +3835,11 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
}
if (spell_id == 46917 && m_canTitanGrip)
+ {
+ RemoveAurasDueToSpell(m_titanGripPenaltySpellId);
SetCanTitanGrip(false);
+ }
+
if (spell_id == 674 && m_canDualWield)
SetCanDualWield(false);
@@ -4211,9 +4234,10 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
charDelete_method = CHAR_DELETE_REMOVE;
}
+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
if (ObjectGuid::LowType guildId = GetGuildIdFromDB(playerguid))
if (Guild* guild = sGuildMgr->GetGuildById(guildId))
- guild->DeleteMember(playerguid, false, false, true);
+ guild->DeleteMember(trans, playerguid, false, false, true);
// close player ticket if any
GmTicket* ticket = sTicketMgr->GetTicketByPlayer(playerguid);
@@ -4240,8 +4264,6 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
// Completely remove from the database
case CHAR_DELETE_REMOVE:
{
- SQLTransaction trans = CharacterDatabase.BeginTransaction();
-
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_COD_ITEM_MAIL);
stmt->setUInt32(0, guid);
PreparedQueryResult resultMail = CharacterDatabase.Query(stmt);
@@ -4530,26 +4552,27 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
trans->Append(stmt);
Corpse::DeleteFromDB(playerguid, trans);
-
- CharacterDatabase.CommitTransaction(trans);
break;
}
// The character gets unlinked from the account, the name gets freed up and appears as deleted ingame
case CHAR_DELETE_UNLINK:
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_DELETE_INFO);
-
stmt->setUInt32(0, guid);
-
- CharacterDatabase.Execute(stmt);
+ trans->Append(stmt);
break;
}
default:
TC_LOG_ERROR("entities.player.cheat", "Player::DeleteFromDB: Tried to delete player (%s) with unsupported delete method (%u).",
playerguid.ToString().c_str(), charDelete_method);
+
+ if (trans->GetSize() > 0)
+ CharacterDatabase.CommitTransaction(trans);
return;
}
+ CharacterDatabase.CommitTransaction(trans);
+
if (updateRealmChars)
sWorld->UpdateRealmCharCount(accountId);
@@ -5167,8 +5190,15 @@ void Player::CleanupChannels()
Channel* ch = *m_channels.begin();
m_channels.erase(m_channels.begin()); // remove from player's channel list
ch->LeaveChannel(this, false); // not send to client, not remove from player's channel list
+
+ // delete channel if empty
if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetTeam()))
- cMgr->LeftChannel(ch->GetName()); // deleted channel if empty
+ {
+ if (ch->IsConstant())
+ cMgr->LeftChannel(ch->GetChannelId(), ch->GetZoneEntry());
+ else
+ cMgr->LeftChannel(ch->GetName());
+ }
}
TC_LOG_DEBUG("chat.system", "Player::CleanupChannels: Channels of player '%s' (%s) cleaned up.", GetName().c_str(), GetGUID().ToString().c_str());
}
@@ -5186,7 +5216,6 @@ void Player::UpdateLocalChannels(uint32 newZone)
if (!cMgr)
return;
- std::string current_zone_name = current_zone->area_name[GetSession()->GetSessionDbcLocale()];
for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i)
{
ChatChannelsEntry const* channelEntry = sChatChannelsStore.LookupEntry(i);
@@ -5214,14 +5243,7 @@ void Player::UpdateLocalChannels(uint32 newZone)
if (channelEntry->flags & CHANNEL_DBC_FLAG_CITY_ONLY && usedChannel)
continue; // Already on the channel, as city channel names are not changing
- std::string currentNameExt;
- if (channelEntry->flags & CHANNEL_DBC_FLAG_CITY_ONLY)
- currentNameExt = sObjectMgr->GetTrinityStringForDBCLocale(LANG_CHANNEL_CITY);
- else
- currentNameExt = current_zone_name;
-
- std::string newChannelName = Trinity::StringFormat(channelEntry->pattern[m_session->GetSessionDbcLocale()], currentNameExt.c_str());
- joinChannel = cMgr->GetJoinChannel(newChannelName, channelEntry->ChannelID);
+ joinChannel = cMgr->GetJoinChannel(channelEntry->ChannelID, std::string(), current_zone);
if (usedChannel)
{
if (joinChannel != usedChannel)
@@ -5234,7 +5256,7 @@ void Player::UpdateLocalChannels(uint32 newZone)
}
}
else
- joinChannel = cMgr->GetJoinChannel(channelEntry->pattern[m_session->GetSessionDbcLocale()], channelEntry->ChannelID);
+ joinChannel = cMgr->GetJoinChannel(channelEntry->ChannelID, std::string());
}
else
removeChannel = usedChannel;
@@ -5244,10 +5266,10 @@ void Player::UpdateLocalChannels(uint32 newZone)
if (removeChannel)
{
- removeChannel->LeaveChannel(this, sendRemove); // Leave old channel
- std::string name = removeChannel->GetName(); // Store name, (*i)erase in LeftChannel
- LeftChannel(removeChannel); // Remove from player's channel list
- cMgr->LeftChannel(name); // Delete if empty
+ removeChannel->LeaveChannel(this, sendRemove); // Leave old channel
+
+ LeftChannel(removeChannel); // Remove from player's channel list
+ cMgr->LeftChannel(removeChannel->GetChannelId(), removeChannel->GetZoneEntry()); // Delete if empty
}
}
}
@@ -5892,7 +5914,7 @@ void Player::UpdateWeaponSkill(WeaponAttackType attType)
UpdateAllCritPercentages();
}
-void Player::UpdateCombatSkills(Unit* victim, WeaponAttackType attType, bool defence)
+void Player::UpdateCombatSkills(Unit* victim, WeaponAttackType attType, bool defense)
{
uint8 plevel = getLevel(); // if defense than victim == attacker
uint8 greylevel = Trinity::XP::GetGrayLevel(plevel);
@@ -5905,12 +5927,12 @@ void Player::UpdateCombatSkills(Unit* victim, WeaponAttackType attType, bool def
if (lvldif < 3)
lvldif = 3;
- uint32 skilldif = 5 * plevel - (defence ? GetBaseDefenseSkillValue() : GetBaseWeaponSkillValue(attType));
+ uint32 skilldif = 5 * plevel - (defense ? GetBaseDefenseSkillValue() : GetBaseWeaponSkillValue(attType));
if (skilldif <= 0)
return;
float chance = float(3 * lvldif * skilldif) / plevel;
- if (!defence)
+ if (!defense)
if (getClass() == CLASS_WARRIOR || getClass() == CLASS_ROGUE)
chance += chance * 0.02f * GetStat(STAT_INTELLECT);
@@ -5918,7 +5940,7 @@ void Player::UpdateCombatSkills(Unit* victim, WeaponAttackType attType, bool def
if (roll_chance_f(chance))
{
- if (defence)
+ if (defense)
UpdateDefense();
else
UpdateWeaponSkill(attType);
@@ -7373,20 +7395,16 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply)
TC_LOG_DEBUG("entities.player.items", "Player::_ApplyItemMods: Applying mods for item %s", item->GetGUID().ToString().c_str());
- uint8 attacktype = Player::GetAttackBySlot(slot);
-
if (proto->Socket[0].Color) //only (un)equipping of items with sockets can influence metagems, so no need to waste time with normal items
CorrectMetaGemEnchants(slot, apply);
- if (attacktype < MAX_ATTACK)
- _ApplyWeaponDependentAuraMods(item, WeaponAttackType(attacktype), apply);
-
_ApplyItemBonuses(proto, slot, apply);
if (slot == EQUIPMENT_SLOT_RANGED)
_ApplyAmmoBonuses();
ApplyItemEquipSpell(item, apply);
+ ApplyItemDependentAuras(item, apply);
ApplyEnchantment(item, apply);
TC_LOG_DEBUG("entities.player.items", "Player::_ApplyItemMods: completed");
@@ -7740,86 +7758,26 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt
UpdateDamagePhysical(attType);
}
-void Player::_ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply)
-{
- AuraEffectList const& auraCritList = GetAuraEffectsByType(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT);
- for (AuraEffectList::const_iterator itr = auraCritList.begin(); itr != auraCritList.end(); ++itr)
- _ApplyWeaponDependentAuraCritMod(item, attackType, *itr, apply);
-
- AuraEffectList const& auraDamageFlatList = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE);
- for (AuraEffectList::const_iterator itr = auraDamageFlatList.begin(); itr != auraDamageFlatList.end(); ++itr)
- _ApplyWeaponDependentAuraDamageMod(item, attackType, *itr, apply);
-
- AuraEffectList const& auraDamagePctList = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
- for (AuraEffectList::const_iterator itr = auraDamagePctList.begin(); itr != auraDamagePctList.end(); ++itr)
- _ApplyWeaponDependentAuraDamageMod(item, attackType, *itr, apply);
-}
-
-void Player::_ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply)
-{
- // don't apply mod if item is broken or cannot be used
- if (item->IsBroken() || !CanUseAttackType(attackType))
- return;
-
- // generic not weapon specific case processes in aura code
- if (aura->GetSpellInfo()->EquippedItemClass == -1)
- return;
-
- BaseModGroup mod;
- switch (attackType)
- {
- case BASE_ATTACK: mod = CRIT_PERCENTAGE; break;
- case OFF_ATTACK: mod = OFFHAND_CRIT_PERCENTAGE;break;
- case RANGED_ATTACK: mod = RANGED_CRIT_PERCENTAGE; break;
- default: return;
- }
-
- if (item->IsFitToSpellRequirements(aura->GetSpellInfo()))
- HandleBaseModValue(mod, FLAT_MOD, float (aura->GetAmount()), apply);
-}
-
-void Player::_ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply)
+void Player::ApplyItemDependentAuras(Item* item, bool apply)
{
- // don't apply mod if item is broken or cannot be used
- if (item->IsBroken() || !CanUseAttackType(attackType))
- return;
-
- // ignore spell mods for not wands
- if ((aura->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) == 0 && (getClassMask() & CLASSMASK_WAND_USERS) == 0)
- return;
-
- // generic not weapon specific case processes in aura code
- if (aura->GetSpellInfo()->EquippedItemClass == -1)
- return;
-
- UnitMods unitMod;
- switch (attackType)
+ if (apply)
{
- case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
- case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
- case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
- default: return;
- }
+ PlayerSpellMap const& spells = GetSpellMap();
+ for (auto itr = spells.begin(); itr != spells.end(); ++itr)
+ {
+ if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled)
+ continue;
- UnitModifierType unitModType;
- switch (aura->GetAuraType())
- {
- case SPELL_AURA_MOD_DAMAGE_DONE: unitModType = TOTAL_VALUE; break;
- case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE: unitModType = TOTAL_PCT; break;
- default: return;
- }
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
+ if (!spellInfo || !spellInfo->IsPassive() || spellInfo->EquippedItemClass < 0)
+ continue;
- if (item->IsFitToSpellRequirements(aura->GetSpellInfo()))
- {
- HandleStatModifier(unitMod, unitModType, float(aura->GetAmount()), apply);
- if (unitModType == TOTAL_VALUE)
- {
- if (aura->GetAmount() > 0)
- ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, aura->GetAmount(), apply);
- else
- ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, aura->GetAmount(), apply);
+ if (!HasAura(itr->first) && HasItemFitToSpellRequirements(spellInfo))
+ AddAura(itr->first, this); // no SMSG_SPELL_GO in sniff found
}
}
+ else
+ RemoveItemDependentAurasAndCasts(item);
}
void Player::ApplyItemEquipSpell(Item* item, bool apply, bool form_change)
@@ -7918,8 +7876,10 @@ void Player::UpdateEquipSpellsAtFormChange()
}
}
}
-void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx)
+
+void Player::CastItemCombatSpell(DamageInfo const& damageInfo)
{
+ Unit* target = damageInfo.GetVictim();
if (!target || !target->IsAlive() || target == this)
return;
@@ -7927,7 +7887,9 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
{
// If usable, try to cast item spell
if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (!item->IsBroken() && CanUseAttackType(attType))
+ {
+ if (!item->IsBroken() && CanUseAttackType(damageInfo.GetAttackType()))
+ {
if (ItemTemplate const* proto = item->GetTemplate())
{
// Additional check for weapons
@@ -7935,30 +7897,42 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
{
// offhand item cannot proc from main hand hit etc
EquipmentSlots slot;
- switch (attType)
+ switch (damageInfo.GetAttackType())
{
- case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
- case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
- case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
- default: slot = EQUIPMENT_SLOT_END; break;
+ case BASE_ATTACK:
+ slot = EQUIPMENT_SLOT_MAINHAND;
+ break;
+ case OFF_ATTACK:
+ slot = EQUIPMENT_SLOT_OFFHAND;
+ break;
+ case RANGED_ATTACK:
+ slot = EQUIPMENT_SLOT_RANGED;
+ break;
+ default:
+ slot = EQUIPMENT_SLOT_END;
+ break;
}
if (slot != i)
continue;
// Check if item is useable (forms or disarm)
- if (attType == BASE_ATTACK)
+ if (damageInfo.GetAttackType() == BASE_ATTACK)
if (!IsUseEquipedWeapon(true) && !IsInFeralForm())
continue;
}
- CastItemCombatSpell(target, attType, procVictim, procEx, item, proto);
+
+ CastItemCombatSpell(damageInfo, item, proto);
}
+ }
+ }
}
}
-void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto)
+void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto)
{
// Can do effect if any damage done to target
- if (procVictim & PROC_FLAG_TAKEN_DAMAGE)
- //if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
+ // for done procs allow normal + critical + absorbs by default
+ bool canTrigger = (damageInfo.GetHitMask() & (PROC_HIT_NORMAL | PROC_HIT_CRITICAL | PROC_HIT_ABSORB)) != 0;
+ if (canTrigger)
{
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
@@ -7988,14 +7962,14 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
if (spellData.SpellPPMRate)
{
- uint32 WeaponSpeed = GetAttackTime(attType);
+ uint32 WeaponSpeed = GetAttackTime(damageInfo.GetAttackType());
chance = GetPPMProcChance(WeaponSpeed, spellData.SpellPPMRate, spellInfo);
}
else if (chance > 100.0f)
chance = GetWeaponProcChance();
if (roll_chance_f(chance))
- CastSpell(target, spellInfo->Id, true, item);
+ CastSpell(damageInfo.GetVictim(), spellInfo->Id, true, item);
}
}
@@ -8013,18 +7987,17 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
continue;
SpellEnchantProcEntry const* entry = sSpellMgr->GetSpellEnchantProcEvent(enchant_id);
-
if (entry && entry->procEx)
{
// Check hit/crit/dodge/parry requirement
- if ((entry->procEx & procEx) == 0)
+ if ((entry->procEx & damageInfo.GetHitMask()) == 0)
continue;
}
else
{
// Can do effect if any damage done to target
- if (!(procVictim & PROC_FLAG_TAKEN_DAMAGE))
- //if (!(damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE))
+ // for done procs allow normal + critical + absorbs by default
+ if (!canTrigger)
continue;
}
@@ -8037,7 +8010,6 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
}
float chance = pEnchant->amount[s] != 0 ? float(pEnchant->amount[s]) : GetWeaponProcChance();
-
if (entry)
{
if (entry->PPMChance)
@@ -8047,7 +8019,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
}
// Apply spell mods
- ApplySpellMod(pEnchant->spellid[s], SPELLMOD_CHANCE_OF_SUCCESS, chance);
+ ApplySpellMod<SPELLMOD_CHANCE_OF_SUCCESS>(pEnchant->spellid[s], chance);
// Shiv has 100% chance to apply the poison
if (FindCurrentSpellBySpellId(5938) && e_slot == TEMP_ENCHANTMENT_SLOT)
@@ -8058,7 +8030,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
if (spellInfo->IsPositive())
CastSpell(this, spellInfo, true, item);
else
- CastSpell(target, spellInfo, true, item);
+ CastSpell(damageInfo.GetVictim(), spellInfo, true, item);
}
}
}
@@ -8180,10 +8152,7 @@ void Player::_RemoveAllItemMods()
if (!proto)
continue;
- uint32 attacktype = Player::GetAttackBySlot(i);
- if (attacktype < MAX_ATTACK)
- _ApplyWeaponDependentAuraMods(m_items[i], WeaponAttackType(attacktype), false);
-
+ ApplyItemDependentAuras(m_items[i], false);
_ApplyItemBonuses(proto, i, false);
if (i == EQUIPMENT_SLOT_RANGED)
@@ -8209,10 +8178,7 @@ void Player::_ApplyAllItemMods()
if (!proto)
continue;
- uint32 attacktype = Player::GetAttackBySlot(i);
- if (attacktype < MAX_ATTACK)
- _ApplyWeaponDependentAuraMods(m_items[i], WeaponAttackType(attacktype), true);
-
+ ApplyItemDependentAuras(m_items[i], true);
_ApplyItemBonuses(proto, i, true);
if (i == EQUIPMENT_SLOT_RANGED)
@@ -9368,7 +9334,7 @@ void Player::SendBattlefieldWorldStates() const
/// Send misc stuff that needs to be sent on every login, like the battle timers.
if (sWorld->getBoolConfig(CONFIG_WINTERGRASP_ENABLE))
{
- if (BattlefieldWG* wg = (BattlefieldWG*)sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG))
+ if (BattlefieldWG* wg = static_cast<BattlefieldWG*>(sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG)))
{
SendUpdateWorldState(BATTLEFIELD_WG_WORLD_STATE_ACTIVE, wg->IsWarTime() ? 0 : 1);
uint32 timer = wg->IsWarTime() ? 0 : (wg->GetTimer() / 1000); // 0 - Time to next battle
@@ -10122,7 +10088,7 @@ bool Player::HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_
return false;
}
-bool Player::HasItemOrGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot) const
+bool Player::HasItemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot) const
{
uint32 tempcount = 0;
for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
@@ -10144,6 +10110,26 @@ bool Player::HasItemOrGemWithLimitCategoryEquipped(uint32 limitCategory, uint32
if (tempcount >= count)
return true;
}
+ }
+
+ return false;
+}
+
+bool Player::HasGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot) const
+{
+ uint32 tempcount = 0;
+ for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
+ {
+ if (i == except_slot)
+ continue;
+
+ Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
+ if (!pItem)
+ continue;
+
+ ItemTemplate const* pProto = pItem->GetTemplate();
+ if (!pProto)
+ continue;
if (pProto->Socket[0].Color || pItem->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT))
{
@@ -11609,10 +11595,8 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const
if (!proto)
return EQUIP_ERR_ITEM_NOT_FOUND;
- if ((proto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && GetTeam() != HORDE)
- return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
-
- if ((proto->Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) && GetTeam() != ALLIANCE)
+ if (((proto->Flags2 & ITEM_FLAG2_FACTION_HORDE) && GetTeam() != HORDE) ||
+ (((proto->Flags2 & ITEM_FLAG2_FACTION_ALLIANCE) && GetTeam() != ALLIANCE)))
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0)
@@ -12074,6 +12058,9 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
return pItem2;
}
+ if (slot == EQUIPMENT_SLOT_MAINHAND || slot == EQUIPMENT_SLOT_OFFHAND)
+ CheckTitanGripPenalty();
+
// only for full equip instead adding to stack
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM, pItem->GetEntry());
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM, pItem->GetEntry(), slot);
@@ -12097,6 +12084,9 @@ void Player::QuickEquipItem(uint16 pos, Item* pItem)
pItem->SendUpdateToPlayer(this);
}
+ if (slot == EQUIPMENT_SLOT_MAINHAND || slot == EQUIPMENT_SLOT_OFFHAND)
+ CheckTitanGripPenalty();
+
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM, pItem->GetEntry());
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM, pItem->GetEntry(), slot);
}
@@ -12179,9 +12169,6 @@ void Player::RemoveItem(uint8 bag, uint8 slot, bool update)
// remove item dependent auras and casts (only weapon and armor slots)
if (slot < EQUIPMENT_SLOT_END)
{
- if (update)
- RemoveItemDependentAurasAndCasts(pItem);
-
// remove held enchantments, update expertise
if (slot == EQUIPMENT_SLOT_MAINHAND)
{
@@ -12217,7 +12204,11 @@ void Player::RemoveItem(uint8 bag, uint8 slot, bool update)
SetGuidValue(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2), ObjectGuid::Empty);
if (slot < EQUIPMENT_SLOT_END)
+ {
SetVisibleItemSlot(slot, nullptr);
+ if (slot == EQUIPMENT_SLOT_MAINHAND || slot == EQUIPMENT_SLOT_OFFHAND)
+ CheckTitanGripPenalty();
+ }
}
else if (Bag* pBag = GetBagByPos(bag))
pBag->RemoveItem(slot, update);
@@ -12268,7 +12259,7 @@ void Player::MoveItemToInventory(ItemPosCountVec const& dest, Item* pItem, bool
// in case trade we already have item in other player inventory
pLastItem->SetState(in_characterInventoryDB ? ITEM_CHANGED : ITEM_NEW, this);
- if (pLastItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE))
+ if (pLastItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE))
AddTradeableItem(pLastItem);
}
}
@@ -12286,7 +12277,7 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
for (uint8 i = 0; i < MAX_BAG_SIZE; ++i)
DestroyItem(slot, i, update);
- if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))
+ if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED))
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT);
@@ -12328,9 +12319,6 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
if (slot < EQUIPMENT_SLOT_END)
{
- // remove item dependent auras and casts (only weapon and armor slots)
- RemoveItemDependentAurasAndCasts(pItem);
-
// update expertise and armor penetration - passive auras may need it
switch (slot)
{
@@ -12359,7 +12347,7 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
// Delete rolled money / loot from db.
// MUST be done before RemoveFromWorld() or GetTemplate() fails
if (ItemTemplate const* pTmp = pItem->GetTemplate())
- if (pTmp->Flags & ITEM_PROTO_FLAG_HAS_LOOT)
+ if (pTmp->Flags & ITEM_FLAG_HAS_LOOT)
pItem->ItemContainerDeleteLootMoneyAndLootItemsFromDB();
if (IsInWorld() && update)
@@ -13299,12 +13287,52 @@ bool Player::IsUseEquipedWeapon(bool mainhand) const
return !IsInFeralForm() && (!mainhand || !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED));
}
+void Player::SetCanTitanGrip(bool value, uint32 penaltySpellId /*= 0*/)
+{
+ if (value == m_canTitanGrip)
+ return;
+
+ m_canTitanGrip = value;
+ m_titanGripPenaltySpellId = penaltySpellId;
+}
+
+void Player::CheckTitanGripPenalty()
+{
+ if (!CanTitanGrip())
+ return;
+
+ bool apply = IsUsingTwoHandedWeaponInOneHand();
+ if (apply)
+ {
+ if (!HasAura(m_titanGripPenaltySpellId))
+ CastSpell((Unit*)nullptr, m_titanGripPenaltySpellId, true);
+ }
+ else
+ RemoveAurasDueToSpell(m_titanGripPenaltySpellId);
+}
+
bool Player::IsTwoHandUsed() const
{
Item* mainItem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
return mainItem && mainItem->GetTemplate()->InventoryType == INVTYPE_2HWEAPON && !CanTitanGrip();
}
+bool Player::IsUsingTwoHandedWeaponInOneHand() const
+{
+ Item* offItem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
+ if (offItem && offItem->GetTemplate()->InventoryType == INVTYPE_2HWEAPON)
+ return true;
+
+ Item* mainItem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
+ if (!mainItem || mainItem->GetTemplate()->InventoryType != INVTYPE_2HWEAPON)
+ return false;
+
+ if (!offItem)
+ return false;
+
+ return true;
+}
+
void Player::TradeCancel(bool sendback)
{
if (m_trade)
@@ -13661,7 +13689,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
break;
case ITEM_MOD_DEFENSE_SKILL_RATING:
ApplyRatingMod(CR_DEFENSE_SKILL, enchant_amount, apply);
- TC_LOG_DEBUG("entities.player.items", "+ %u DEFENCE", enchant_amount);
+ TC_LOG_DEBUG("entities.player.items", "+ %u DEFENSE", enchant_amount);
break;
case ITEM_MOD_DODGE_RATING:
ApplyRatingMod(CR_DODGE, enchant_amount, apply);
@@ -14014,6 +14042,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool
break;
}
case GOSSIP_OPTION_LEARNDUALSPEC:
+ case GOSSIP_OPTION_DUALSPEC_INFO:
if (!(GetSpecsCount() == 1 && creature->isCanTrainingAndResetTalentsOf(this) && !(getLevel() < sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL))))
canTalk = false;
break;
@@ -14195,6 +14224,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men
switch (gossipOptionId)
{
case GOSSIP_OPTION_GOSSIP:
+ case GOSSIP_OPTION_DUALSPEC_INFO:
{
if (menuItemData->GossipActionPoi)
PlayerTalkClass->SendPointOfInterest(menuItemData->GossipActionPoi);
@@ -14236,8 +14266,8 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men
CastSpell(this, 63680, true, nullptr, nullptr, GetGUID());
CastSpell(this, 63624, true, nullptr, nullptr, GetGUID());
- // Should show another Gossip text with "Congratulations..."
- PlayerTalkClass->SendCloseGossip();
+ PrepareGossipMenu(source, menuItemData->GossipActionMenuId);
+ SendPreparedGossip(source);
}
break;
case GOSSIP_OPTION_UNLEARNTALENTS:
@@ -14755,7 +14785,9 @@ bool Player::CanRewardQuest(Quest const* quest, uint32 reward, bool msg)
InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, quest->RewardChoiceItemId[reward], quest->RewardChoiceItemCount[reward]);
if (res != EQUIP_ERR_OK)
{
- SendEquipError(res, nullptr, nullptr, quest->RewardChoiceItemId[reward]);
+ if (msg)
+ SendQuestFailed(quest->GetQuestId(), res);
+
return false;
}
}
@@ -14770,7 +14802,9 @@ bool Player::CanRewardQuest(Quest const* quest, uint32 reward, bool msg)
InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, quest->RewardItemId[i], quest->RewardItemIdCount[i]);
if (res != EQUIP_ERR_OK)
{
- SendEquipError(res, nullptr, nullptr, quest->RewardItemId[i]);
+ if (msg)
+ SendQuestFailed(quest->GetQuestId(), res);
+
return false;
}
}
@@ -14919,20 +14953,20 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
{
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RequiredItemId[i]))
{
- if (quest->RequiredItemCount[i] > 0 && (itemTemplate->Bonding == BIND_QUEST_ITEM || itemTemplate->Bonding == BIND_QUEST_ITEM1))
- DestroyItemCount(quest->RequiredItemId[i], 9999, true, true);
+ if (quest->RequiredItemCount[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM && !quest->IsRepeatable() && !HasQuestForItem(quest->RequiredItemId[i], quest_id, true))
+ DestroyItemCount(quest->RequiredItemId[i], 9999, true);
else
- DestroyItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i], true, true);
+ DestroyItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i], true);
}
}
for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i)
{
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i]))
{
- if (quest->ItemDropQuantity[i] > 0 && (itemTemplate->Bonding == BIND_QUEST_ITEM || itemTemplate->Bonding == BIND_QUEST_ITEM1))
- DestroyItemCount(quest->ItemDrop[i], 9999, true, true);
+ if (quest->ItemDropQuantity[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM && !quest->IsRepeatable() && !HasQuestForItem(quest->ItemDrop[i], quest_id))
+ DestroyItemCount(quest->ItemDrop[i], 9999, true);
else
- DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true, true);
+ DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true);
}
}
@@ -15053,10 +15087,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
RemoveActiveQuest(quest_id, false);
if (quest->CanIncreaseRewardedQuestCounters())
- {
- m_RewardedQuests.insert(quest_id);
- m_RewardedQuestsSave[quest_id] = QUEST_DEFAULT_SAVE_TYPE;
- }
+ SetRewardedQuest(quest_id);
// StoreNewItem, mail reward, etc. save data directly to the database
// to prevent exploitable data desynchronisation we save the quest status to the database too
@@ -15112,15 +15143,24 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
sScriptMgr->OnQuestStatusChange(this, quest_id);
}
-void Player::FailQuest(uint32 questId)
+void Player::SetRewardedQuest(uint32 quest_id)
{
+ m_RewardedQuests.insert(quest_id);
+ m_RewardedQuestsSave[quest_id] = QUEST_DEFAULT_SAVE_TYPE;
+}
+void Player::FailQuest(uint32 questId)
+{
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
{
// Already complete quests shouldn't turn failed.
if (GetQuestStatus(questId) == QUEST_STATUS_COMPLETE && !quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED))
return;
+ // You can't fail a quest if you don't have it, or if it's already rewarded.
+ if (GetQuestStatus(questId) == QUEST_STATUS_NONE || GetQuestStatus(questId) == QUEST_STATUS_REWARDED)
+ return;
+
SetQuestStatus(questId, QUEST_STATUS_FAILED);
uint16 log_slot = FindQuestSlot(questId);
@@ -15146,13 +15186,13 @@ void Player::FailQuest(uint32 questId)
// Destroy quest items on quest failure.
for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RequiredItemId[i]))
- if (quest->RequiredItemCount[i] > 0 && (itemTemplate->Bonding == BIND_QUEST_ITEM || itemTemplate->Bonding == BIND_QUEST_ITEM1))
- DestroyItemCount(quest->RequiredItemId[i], 9999, true, true);
+ if (quest->RequiredItemCount[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM)
+ DestroyItemCount(quest->RequiredItemId[i], 9999, true);
for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i)
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i]))
- if (quest->ItemDropQuantity[i] > 0 && (itemTemplate->Bonding == BIND_QUEST_ITEM || itemTemplate->Bonding == BIND_QUEST_ITEM1))
- DestroyItemCount(quest->ItemDrop[i], 9999, true, true);
+ if (quest->ItemDropQuantity[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM)
+ DestroyItemCount(quest->ItemDrop[i], 9999, true);
}
}
@@ -15163,13 +15203,13 @@ void Player::AbandonQuest(uint32 questId)
// Destroy quest items on quest abandon.
for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RequiredItemId[i]))
- if (quest->RequiredItemCount[i] > 0 && (itemTemplate->Bonding == BIND_QUEST_ITEM || itemTemplate->Bonding == BIND_QUEST_ITEM1))
- DestroyItemCount(quest->RequiredItemId[i], 9999, true, true);
+ if (quest->RequiredItemCount[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM)
+ DestroyItemCount(quest->RequiredItemId[i], 9999, true);
for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i)
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i]))
- if (quest->ItemDropQuantity[i] > 0 && (itemTemplate->Bonding == BIND_QUEST_ITEM || itemTemplate->Bonding == BIND_QUEST_ITEM1))
- DestroyItemCount(quest->ItemDrop[i], 9999, true, true);
+ if (quest->ItemDropQuantity[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM)
+ DestroyItemCount(quest->ItemDrop[i], 9999, true);
}
}
@@ -15419,6 +15459,17 @@ bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg)
bool Player::SatisfyQuestStatus(Quest const* qInfo, bool msg) const
{
+ if (GetQuestStatus(qInfo->GetQuestId()) == QUEST_STATUS_REWARDED)
+ {
+ if (msg)
+ {
+ SendCanTakeQuestResponse(INVALIDREASON_QUEST_ALREADY_DONE);
+ TC_LOG_DEBUG("misc", "Player::SatisfyQuestStatus: Sent QUEST_STATUS_REWARDED (QuestID: %u) because player '%s' (%s) quest status is already REWARDED.",
+ qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str());
+ }
+ return false;
+ }
+
if (GetQuestStatus(qInfo->GetQuestId()) != QUEST_STATUS_NONE)
{
if (msg)
@@ -15862,21 +15913,18 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver)
if (!quest)
continue;
- if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK, quest->GetQuestId(), this))
+ if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_QUEST_ACCEPT, quest->GetQuestId(), this))
continue;
QuestStatus status = GetQuestStatus(questId);
- if ((status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus(questId)) ||
- (quest->IsAutoComplete() && CanTakeQuest(quest, false)))
- {
- if (quest->IsAutoComplete() && quest->IsRepeatable() && !quest->IsDailyOrWeekly())
- result2 = DIALOG_STATUS_REWARD_REP;
- else
- result2 = DIALOG_STATUS_REWARD;
- }
+ if (status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus(questId))
+ result2 = DIALOG_STATUS_REWARD;
else if (status == QUEST_STATUS_INCOMPLETE)
result2 = DIALOG_STATUS_INCOMPLETE;
+ if (quest->IsAutoComplete() && CanTakeQuest(quest, false) && quest->IsRepeatable() && !quest->IsDailyOrWeekly())
+ result2 = DIALOG_STATUS_REWARD_REP;
+
if (result2 > result)
result = result2;
}
@@ -15889,7 +15937,7 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver)
if (!quest)
continue;
- if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK, quest->GetQuestId(), this))
+ if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_QUEST_ACCEPT, quest->GetQuestId(), this))
continue;
QuestStatus status = GetQuestStatus(questId);
@@ -15899,9 +15947,7 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver)
{
if (SatisfyQuestLevel(quest, false))
{
- if (quest->IsAutoComplete())
- result2 = DIALOG_STATUS_REWARD_REP;
- else if (getLevel() <= (GetQuestLevel(quest) + sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF)))
+ if (getLevel() <= (GetQuestLevel(quest) + sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF)))
{
if (quest->IsDaily())
result2 = DIALOG_STATUS_AVAILABLE_REP;
@@ -16462,12 +16508,12 @@ void Player::ReputationChanged2(FactionEntry const* factionEntry)
}
}
-bool Player::HasQuestForItem(uint32 itemid) const
+bool Player::HasQuestForItem(uint32 itemid, uint32 excludeQuestId /* 0 */, bool turnIn /* false */) const
{
for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i)
{
uint32 questid = GetQuestSlotQuestId(i);
- if (questid == 0)
+ if (questid == 0 || questid == excludeQuestId)
continue;
QuestStatusMap::const_iterator qs_itr = m_QuestStatus.find(questid);
@@ -16476,7 +16522,7 @@ bool Player::HasQuestForItem(uint32 itemid) const
QuestStatusData const& q_status = qs_itr->second;
- if (q_status.Status == QUEST_STATUS_INCOMPLETE)
+ if ((q_status.Status == QUEST_STATUS_INCOMPLETE) || (turnIn && q_status.Status == QUEST_STATUS_COMPLETE))
{
Quest const* qinfo = sObjectMgr->GetQuestTemplate(questid);
if (!qinfo)
@@ -16491,7 +16537,7 @@ bool Player::HasQuestForItem(uint32 itemid) const
// This part for ReqItem drop
for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j)
{
- if (itemid == qinfo->RequiredItemId[j] && q_status.ItemCount[j] < qinfo->RequiredItemCount[j])
+ if ((itemid == qinfo->RequiredItemId[j] && q_status.ItemCount[j] < qinfo->RequiredItemCount[j]) || (turnIn && q_status.ItemCount[j] >= qinfo->RequiredItemCount[j]))
return true;
}
// This part - for ReqSource
@@ -16501,17 +16547,17 @@ bool Player::HasQuestForItem(uint32 itemid) const
if (qinfo->ItemDrop[j] == itemid)
{
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid);
-
+ uint32 ownedCount = GetItemCount(itemid, true);
// 'unique' item
- if (pProto->MaxCount && int32(GetItemCount(itemid, true)) < pProto->MaxCount)
+ if ((pProto->MaxCount && int32(ownedCount) < pProto->MaxCount) || (turnIn && int32(ownedCount) >= pProto->MaxCount))
return true;
// allows custom amount drop when not 0
if (qinfo->ItemDropQuantity[j])
{
- if (GetItemCount(itemid, true) < qinfo->ItemDropQuantity[j])
+ if ((ownedCount < qinfo->ItemDropQuantity[j]) || (turnIn && ownedCount >= qinfo->ItemDropQuantity[j]))
return true;
- } else if (GetItemCount(itemid, true) < pProto->GetMaxStackSize())
+ } else if (ownedCount < pProto->GetMaxStackSize())
return true;
}
}
@@ -17995,13 +18041,13 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F
remove = true;
}
// "Conjured items disappear if you are logged out for more than 15 minutes"
- else if (timeDiff > 15 * MINUTE && proto->Flags & ITEM_PROTO_FLAG_CONJURED)
+ else if (timeDiff > 15 * MINUTE && proto->Flags & ITEM_FLAG_CONJURED)
{
TC_LOG_DEBUG("entities.player.loading", "Player::_LoadInventory: player (GUID: %u, name: '%s', diff: %u) has conjured item (GUID: %u, entry: %u) with expired lifetime (15 minutes). Deleting item.",
GetGUID().GetCounter(), GetName().c_str(), timeDiff, item->GetGUID().GetCounter(), item->GetEntry());
remove = true;
}
- else if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE))
+ else if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE))
{
if (item->GetPlayedTime() > (2 * HOUR))
{
@@ -18012,7 +18058,7 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F
stmt->setUInt32(0, item->GetGUID().GetCounter());
trans->Append(stmt);
- item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE);
+ item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE);
}
else
{
@@ -18030,11 +18076,11 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F
{
TC_LOG_DEBUG("entities.player.loading", "Player::_LoadInventory: player (GUID: %u, name: '%s') has item (GUID: %u, entry: %u) with refundable flags, but without data in item_refund_instance. Removing flag.",
GetGUID().GetCounter(), GetName().c_str(), item->GetGUID().GetCounter(), item->GetEntry());
- item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE);
+ item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE);
}
}
}
- else if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE))
+ else if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE))
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_BOP_TRADE);
stmt->setUInt32(0, item->GetGUID().GetCounter());
@@ -18058,7 +18104,7 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F
{
TC_LOG_DEBUG("entities.player.loading", "Player::_LoadInventory: player (GUID: %u, name: '%s') has item (GUID: %u, entry: %u) with ITEM_FLAG_BOP_TRADEABLE flag, but without data in item_soulbound_trade_data. Removing flag.",
GetGUID().GetCounter(), GetName().c_str(), item->GetGUID().GetCounter(), item->GetEntry());
- item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE);
+ item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE);
}
}
else if (proto->HolidayId)
@@ -19454,7 +19500,6 @@ void Player::_SaveAuras(SQLTransaction& trans)
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AURA);
stmt->setUInt32(index++, GetGUID().GetCounter());
stmt->setUInt64(index++, itr->second->GetCasterGUID().GetRawValue());
- stmt->setUInt64(index++, itr->second->GetCastItemGUID().GetRawValue());
stmt->setUInt32(index++, itr->second->GetId());
stmt->setUInt8(index++, effMask);
stmt->setUInt8(index++, recalculateMask);
@@ -20748,13 +20793,13 @@ void Player::SendRemoveControlBar() const
GetSession()->SendPacket(&data);
}
-bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell) const
+bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell)
{
if (!mod || !spellInfo)
return false;
- // Mod out of charges
- if (spell && mod->charges == -1 && spell->m_appliedMods.find(mod->ownerAura) == spell->m_appliedMods.end())
+ // First time this aura applies a mod to us and is out of charges
+ if (spell && mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges() && !spell->m_appliedMods.count(mod->ownerAura))
return false;
// +duration to infinite duration spells making them limited
@@ -20769,62 +20814,57 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply)
TC_LOG_DEBUG("spells", "Player::AddSpellMod: Player '%s' (%s), SpellID: %d", GetName().c_str(), GetGUID().ToString().c_str(), mod->spellId);
uint16 Opcode = (mod->type == SPELLMOD_FLAT) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER;
- int i = 0;
- flag96 _mask = 0;
- for (int eff = 0; eff < 96; ++eff)
+ flag96 modMask;
+ for (uint8 i = 0; i < 3; ++i)
{
- if (eff != 0 && eff%32 == 0)
- _mask[i++] = 0;
-
- _mask[i] = uint32(1) << (eff-(32*i));
- if (mod->mask & _mask)
+ for (uint32 eff = 0; eff < 32; ++eff)
{
- int32 val = 0;
- for (SpellModList::iterator itr = m_spellMods[mod->op].begin(); itr != m_spellMods[mod->op].end(); ++itr)
+ modMask[i] = uint32(1) << eff;
+ if ((mod->mask & modMask))
{
- if ((*itr)->type == mod->type && (*itr)->mask & _mask)
- val += (*itr)->value;
+ int32 val = 0;
+ for (SpellModifier* spellMod : m_spellMods[mod->op])
+ {
+ if (spellMod->type == mod->type && (spellMod->mask & modMask))
+ val += spellMod->value;
+ }
+ val += apply ? mod->value : -(mod->value);
+ WorldPacket data(Opcode, (1 + 1 + 4));
+ data << uint8(eff + 32 * i);
+ data << uint8(mod->op);
+ data << int32(val);
+ SendDirectMessage(&data);
}
- val += apply ? mod->value : -(mod->value);
- WorldPacket data(Opcode, (1+1+4));
- data << uint8(eff);
- data << uint8(mod->op);
- data << int32(val);
- SendDirectMessage(&data);
}
+
+ modMask[i] = 0;
}
if (apply)
- m_spellMods[mod->op].push_back(mod);
+ m_spellMods[mod->op].insert(mod);
else
- {
- m_spellMods[mod->op].remove(mod);
- // mods bound to aura will be removed in AuraEffect::~AuraEffect
- if (!mod->ownerAura)
- delete mod;
- }
+ m_spellMods[mod->op].erase(mod);
}
// Restore spellmods in case of failed cast
-void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura)
+void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId /*= 0*/, Aura* aura /*= nullptr*/)
{
if (!spell || spell->m_appliedMods.empty())
return;
std::list<Aura*> aurasQueue;
-
- for (uint8 i=0; i<MAX_SPELLMOD; ++i)
+ for (uint8 i = 0; i < MAX_SPELLMOD; ++i)
{
- for (SpellModList::iterator itr = m_spellMods[i].begin(); itr != m_spellMods[i].end(); ++itr)
+ for (auto itr = m_spellMods[i].begin(); itr != m_spellMods[i].end(); ++itr)
{
SpellModifier* mod = *itr;
- // Spellmods without aura set cannot be charged
- if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges())
+ // Spellmods without charged aura cannot be charged
+ if (!mod->ownerAura->IsUsingCharges())
continue;
// Restore only specific owner aura mods
- if (ownerAuraId && (ownerAuraId != mod->ownerAura->GetSpellInfo()->Id))
+ if (ownerAuraId && mod->spellId != ownerAuraId)
continue;
if (aura && mod->ownerAura != aura)
@@ -20845,84 +20885,33 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura)
// only see the first of its modifier restored)
aurasQueue.push_back(mod->ownerAura);
- // add mod charges back to mod
- if (mod->charges == -1)
- mod->charges = 1;
- else
- mod->charges++;
-
- // Do not set more spellmods than available
- if (mod->ownerAura->GetCharges() < mod->charges)
- mod->charges = mod->ownerAura->GetCharges();
-
- // Skip this check for now - aura charges may change due to various reason
- /// @todo track these changes correctly
- //ASSERT (mod->ownerAura->GetCharges() <= mod->charges);
+ // add charges back to aura
+ mod->ownerAura->ModCharges(1);
}
}
- for (std::list<Aura*>::iterator itr = aurasQueue.begin(); itr != aurasQueue.end(); ++itr)
- {
- Spell::UsedSpellMods::iterator iterMod = spell->m_appliedMods.find(*itr);
- if (iterMod != spell->m_appliedMods.end())
- spell->m_appliedMods.erase(iterMod);
- }
+ for (Aura* aura : aurasQueue)
+ spell->m_appliedMods.erase(aura);
}
-void Player::RestoreAllSpellMods(uint32 ownerAuraId, Aura* aura)
+void Player::RestoreAllSpellMods(uint32 ownerAuraId /*= 0*/, Aura* aura /*= nullptr*/)
{
for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
- if (m_currentSpells[i])
- RestoreSpellMods(m_currentSpells[i], ownerAuraId, aura);
+ if (Spell* spell = m_currentSpells[i])
+ RestoreSpellMods(spell, ownerAuraId, aura);
}
-void Player::RemoveSpellMods(Spell* spell)
+void Player::ApplyModToSpell(SpellModifier* mod, Spell* spell)
{
if (!spell)
return;
- if (spell->m_appliedMods.empty())
+ // don't do anything with no charges
+ if (mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges())
return;
- for (uint8 i=0; i<MAX_SPELLMOD; ++i)
- {
- for (SpellModList::const_iterator itr = m_spellMods[i].begin(); itr != m_spellMods[i].end();)
- {
- SpellModifier* mod = *itr;
- ++itr;
-
- // spellmods without aura set cannot be charged
- if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges())
- continue;
-
- // check if mod affected this spell
- Spell::UsedSpellMods::iterator iterMod = spell->m_appliedMods.find(mod->ownerAura);
- if (iterMod == spell->m_appliedMods.end())
- continue;
-
- // remove from list
- spell->m_appliedMods.erase(iterMod);
-
- if (mod->ownerAura->DropCharge(AURA_REMOVE_BY_EXPIRE))
- itr = m_spellMods[i].begin();
- }
- }
-}
-
-void Player::DropModCharge(SpellModifier* mod, Spell* spell)
-{
- // don't handle spells with proc_event entry defined
- // this is a temporary workaround, because all spellmods should be handled like that
- if (sSpellMgr->GetSpellProcEvent(mod->spellId))
- return;
-
- if (spell && mod->ownerAura && mod->charges > 0)
- {
- if (--mod->charges == 0)
- mod->charges = -1;
-
- spell->m_appliedMods.insert(mod->ownerAura);
- }
+ // register inside spell, proc system uses this to drop charges
+ spell->m_appliedMods.insert(mod->ownerAura);
}
void Player::SetSpellModTakingSpell(Spell* spell, bool apply)
@@ -20933,7 +20922,7 @@ void Player::SetSpellModTakingSpell(Spell* spell, bool apply)
if (apply && spell->getState() == SPELL_STATE_FINISHED)
return;
- m_spellModTakingSpell = apply ? spell : NULL;
+ m_spellModTakingSpell = apply ? spell : nullptr;
}
// send Proficiency
@@ -21072,7 +21061,7 @@ void Player::SetRestBonus(float rest_bonus_new)
SetUInt32Value(PLAYER_REST_STATE_EXPERIENCE, uint32(m_rest_bonus));
}
-bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc /*= NULL*/, uint32 spellid /*= 0*/)
+bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc /*= nullptr*/, uint32 spellid /*= 0*/)
{
if (nodes.size() < 2)
return false;
@@ -21142,11 +21131,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
// check node starting pos data set case if provided
if (node->x != 0.0f || node->y != 0.0f || node->z != 0.0f)
{
- if (node->map_id != GetMapId() ||
- (node->x - GetPositionX())*(node->x - GetPositionX())+
- (node->y - GetPositionY())*(node->y - GetPositionY())+
- (node->z - GetPositionZ())*(node->z - GetPositionZ()) >
- (2*INTERACTION_DISTANCE)*(2*INTERACTION_DISTANCE)*(2*INTERACTION_DISTANCE))
+ if (node->map_id != GetMapId() || !IsInDist(node->x, node->y, node->z, 2 * INTERACTION_DISTANCE))
{
GetSession()->SendActivateTaxiReply(ERR_TAXITOOFARAWAY);
return false;
@@ -21307,10 +21292,7 @@ void Player::ContinueTaxiFlight() const
TaxiPathNodeList const& nodeList = sTaxiPathNodesByPath[path];
float distPrev;
- float distNext =
- (nodeList[0]->LocX - GetPositionX())*(nodeList[0]->LocX - GetPositionX()) +
- (nodeList[0]->LocY - GetPositionY())*(nodeList[0]->LocY - GetPositionY()) +
- (nodeList[0]->LocZ - GetPositionZ())*(nodeList[0]->LocZ - GetPositionZ());
+ float distNext = GetExactDistSq(nodeList[0]->LocX, nodeList[0]->LocY, nodeList[0]->LocZ);
for (uint32 i = 1; i < nodeList.size(); ++i)
{
@@ -21323,10 +21305,7 @@ void Player::ContinueTaxiFlight() const
distPrev = distNext;
- distNext =
- (node->LocX - GetPositionX())*(node->LocX - GetPositionX()) +
- (node->LocY - GetPositionY())*(node->LocY - GetPositionY()) +
- (node->LocZ - GetPositionZ())*(node->LocZ - GetPositionZ());
+ distNext = GetExactDistSq(node->LocX, node->LocY, node->LocZ);
float distNodes =
(node->LocX - prevNode->LocX)*(node->LocX - prevNode->LocX) +
@@ -21465,9 +21444,9 @@ inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 c
if (!bStore)
AutoUnequipOffhandIfNeed();
- if (pProto->Flags & ITEM_PROTO_FLAG_REFUNDABLE && crItem->ExtendedCost && pProto->GetMaxStackSize() == 1)
+ if (pProto->Flags & ITEM_FLAG_ITEM_PURCHASE_RECORD && crItem->ExtendedCost && pProto->GetMaxStackSize() == 1)
{
- it->SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE);
+ it->SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE);
it->SetRefundRecipient(GetGUID().GetCounter());
it->SetPaidMoney(price);
it->SetPaidExtendedCost(crItem->ExtendedCost);
@@ -21504,7 +21483,7 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin
return false;
}
- if (!IsGameMaster() && ((pProto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY && GetTeam() == ALLIANCE) || (pProto->Flags2 == ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && GetTeam() == HORDE)))
+ if (!IsGameMaster() && ((pProto->Flags2 & ITEM_FLAG2_FACTION_HORDE && GetTeam() == ALLIANCE) || (pProto->Flags2 == ITEM_FLAG2_FACTION_ALLIANCE && GetTeam() == HORDE)))
return false;
Creature* creature = GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR);
@@ -22692,9 +22671,10 @@ void Player::SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint3
void Player::ApplyEquipCooldown(Item* pItem)
{
- if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_PROTO_FLAG_NO_EQUIP_COOLDOWN))
+ if (pItem->GetTemplate()->Flags & ITEM_FLAG_NO_EQUIP_COOLDOWN)
return;
+ std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
_Spell const& spellData = pItem->GetTemplate()->Spells[i];
@@ -22703,6 +22683,18 @@ void Player::ApplyEquipCooldown(Item* pItem)
if (spellData.SpellId <= 0)
continue;
+ // apply proc cooldown to equip auras if we have any
+ if (spellData.SpellTrigger == ITEM_SPELLTRIGGER_ON_EQUIP)
+ {
+ SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(spellData.SpellId);
+ if (!procEntry)
+ continue;
+
+ if (Aura* itemAura = GetAura(spellData.SpellId, GetGUID(), pItem->GetGUID()))
+ itemAura->AddProcCooldown(now + procEntry->Cooldown);
+ continue;
+ }
+
// wrong triggering type (note: ITEM_SPELLTRIGGER_ON_NO_DELAY_USE not have cooldown)
if (spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_USE)
continue;
@@ -23532,9 +23524,9 @@ void Player::RemoveItemDependentAurasAndCasts(Item* pItem)
{
Aura* aura = itr->second;
- // skip passive (passive item dependent spells work in another way) and not self applied auras
+ // skip not self applied auras
SpellInfo const* spellInfo = aura->GetSpellInfo();
- if (aura->IsPassive() || aura->GetCasterGUID() != GetGUID())
+ if (aura->GetCasterGUID() != GetGUID())
{
++itr;
continue;
@@ -24579,9 +24571,9 @@ void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore cons
void Player::StoreLootItem(uint8 lootSlot, Loot* loot)
{
- QuestItem* qitem = nullptr;
- QuestItem* ffaitem = nullptr;
- QuestItem* conditem = nullptr;
+ NotNormalLootItem* qitem = nullptr;
+ NotNormalLootItem* ffaitem = nullptr;
+ NotNormalLootItem* conditem = nullptr;
LootItem* item = loot->LootItemInSlot(lootSlot, this, &qitem, &ffaitem, &conditem);
@@ -24847,7 +24839,7 @@ InventoryResult Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limi
InventoryResult Player::CanEquipUniqueItem(ItemTemplate const* itemProto, uint8 except_slot, uint32 limit_count) const
{
// check unique-equipped on item
- if (itemProto->Flags & ITEM_PROTO_FLAG_UNIQUE_EQUIPPED)
+ if (itemProto->Flags & ITEM_FLAG_UNIQUE_EQUIPPABLE)
{
// there is an equip limit on this item
if (HasItemOrGemWithIdEquipped(itemProto->ItemId, 1, except_slot))
@@ -24867,7 +24859,9 @@ InventoryResult Player::CanEquipUniqueItem(ItemTemplate const* itemProto, uint8
return EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED;
// there is an equip limit on this item
- if (HasItemOrGemWithLimitCategoryEquipped(itemProto->ItemLimitCategory, limitEntry->maxCount - limit_count + 1, except_slot))
+ if (HasItemWithLimitCategoryEquipped(itemProto->ItemLimitCategory, limitEntry->maxCount - limit_count + 1, except_slot))
+ return EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED;
+ else if (HasGemWithLimitCategoryEquipped(itemProto->ItemLimitCategory, limitEntry->maxCount - limit_count + 1, except_slot))
return EQUIP_ERR_ITEM_MAX_COUNT_EQUIPPED_SOCKETED;
}
@@ -25831,6 +25825,20 @@ void Player::ActivateSpec(uint8 spec)
UnsummonAllTotems();
ExitVehicle();
RemoveAllControlled();
+
+ // remove single target auras at other targets
+ AuraList& scAuras = GetSingleCastAuras();
+ for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
+ {
+ Aura* aura = *iter;
+ if (aura->GetUnitOwner() != this)
+ {
+ aura->Remove();
+ iter = scAuras.begin();
+ }
+ else
+ ++iter;
+ }
/*RemoveAllAurasOnDeath();
if (GetPet())
GetPet()->RemoveAllAurasOnDeath();*/
@@ -25948,6 +25956,13 @@ void Player::ActivateSpec(uint8 spec)
SetPower(POWER_MANA, 0); // Mana must be 0 even if it isn't the active power type.
SetPower(pw, 0);
+
+ Unit::AuraEffectList const& shapeshiftAuras = GetAuraEffectsByType(SPELL_AURA_MOD_SHAPESHIFT);
+ for (AuraEffect* aurEff : shapeshiftAuras)
+ {
+ aurEff->HandleShapeshiftBoosts(this, false);
+ aurEff->HandleShapeshiftBoosts(this, true);
+ }
}
void Player::ResetTimeSync()
@@ -26007,7 +26022,7 @@ void Player::SendRefundInfo(Item* item)
// This function call unsets ITEM_FLAGS_REFUNDABLE if played time is over 2 hours.
item->UpdatePlayedTime(this);
- if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE))
+ if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE))
{
TC_LOG_DEBUG("entities.player.items", "Item refund: item not refundable!");
return;
@@ -26067,7 +26082,7 @@ bool Player::AddItem(uint32 itemId, uint32 count)
void Player::RefundItem(Item* item)
{
- if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE))
+ if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE))
{
TC_LOG_DEBUG("entities.player.items", "Item refund: item not refundable!");
return;
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 5a572d9caa9..ed5dc7e954f 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -66,10 +66,10 @@ typedef std::deque<Mail*> PlayerMails;
#define PLAYER_EXPLORED_ZONES_SIZE 128
// Note: SPELLMOD_* values is aura types in fact
-enum SpellModType
+enum SpellModType : uint8
{
- SPELLMOD_FLAT = 107, // SPELL_AURA_ADD_FLAT_MODIFIER
- SPELLMOD_PCT = 108 // SPELL_AURA_ADD_PCT_MODIFIER
+ SPELLMOD_FLAT = SPELL_AURA_ADD_FLAT_MODIFIER,
+ SPELLMOD_PCT = SPELL_AURA_ADD_PCT_MODIFIER
};
// 2^n values, Player::m_isunderwater is a bitmask. These are Trinity internal values, they are never send to any client
@@ -118,10 +118,11 @@ struct PlayerTalent
// Spell modifier (used for modify other spells)
struct SpellModifier
{
- SpellModifier(Aura* _ownerAura = nullptr) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), charges(0), value(0), mask(), spellId(0), ownerAura(_ownerAura) { }
- SpellModOp op : 8;
- SpellModType type : 8;
- int16 charges : 16;
+ SpellModifier(Aura* _ownerAura) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), value(0), mask(), spellId(0), ownerAura(_ownerAura) { }
+
+ SpellModOp op;
+ SpellModType type;
+
int32 value;
flag96 mask;
uint32 spellId;
@@ -130,7 +131,7 @@ struct SpellModifier
typedef std::unordered_map<uint32, PlayerTalent*> PlayerTalentMap;
typedef std::unordered_map<uint32, PlayerSpell*> PlayerSpellMap;
-typedef std::list<SpellModifier*> SpellModList;
+typedef std::unordered_set<SpellModifier*> SpellModContainer;
typedef std::unordered_map<uint32 /*instanceId*/, time_t/*releaseTime*/> InstanceTimeMap;
@@ -1198,7 +1199,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item const* ignoreItem = nullptr) const;
bool CanNoReagentCast(SpellInfo const* spellInfo) const;
bool HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_slot = NULL_SLOT) const;
- bool HasItemOrGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot = NULL_SLOT) const;
+ bool HasItemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot = NULL_SLOT) const;
+ bool HasGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot = NULL_SLOT) const;
InventoryResult CanTakeMoreSimilarItems(Item* pItem, uint32* itemLimitCategory = NULL) const { return CanTakeMoreSimilarItems(pItem->GetEntry(), pItem->GetCount(), pItem, NULL, itemLimitCategory); }
InventoryResult CanTakeMoreSimilarItems(uint32 entry, uint32 count, uint32* itemLimitCategory = NULL) const { return CanTakeMoreSimilarItems(entry, count, NULL, NULL, itemLimitCategory); }
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 item, uint32 count, uint32* no_space_count = nullptr) const;
@@ -1268,6 +1270,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
uint32 GetArmorProficiency() const { return m_ArmorProficiency; }
bool IsUseEquipedWeapon(bool mainhand) const;
bool IsTwoHandUsed() const;
+ bool IsUsingTwoHandedWeaponInOneHand() const;
void SendNewItem(Item* item, uint32 count, bool received, bool created, bool broadcast = false);
bool BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot);
bool _StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot, int32 price, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore);
@@ -1339,6 +1342,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void CompleteQuest(uint32 quest_id);
void IncompleteQuest(uint32 quest_id);
void RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, bool announce = true);
+ void SetRewardedQuest(uint32 quest_id);
void FailQuest(uint32 quest_id);
bool SatisfyQuestSkill(Quest const* qInfo, bool msg) const;
bool SatisfyQuestLevel(Quest const* qInfo, bool msg) const;
@@ -1402,7 +1406,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void MoneyChanged(uint32 value);
void ReputationChanged(FactionEntry const* factionEntry);
void ReputationChanged2(FactionEntry const* factionEntry);
- bool HasQuestForItem(uint32 itemId) const;
+ bool HasQuestForItem(uint32 itemId, uint32 excludeQuestId = 0, bool turnIn = false) const;
bool HasQuestForGO(int32 goId) const;
void UpdateForQuestWorldObjects();
bool CanShareQuest(uint32 questId) const;
@@ -1600,13 +1604,12 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
PlayerSpellMap & GetSpellMap() { return m_spells; }
void AddSpellMod(SpellModifier* mod, bool apply);
- bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr) const;
- template <class T>
- void ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell = nullptr);
- void RemoveSpellMods(Spell* spell);
+ static bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr);
+ template <SpellModOp op, class T>
+ void ApplySpellMod(uint32 spellId, T& basevalue, Spell* spell = nullptr) const;
void RestoreSpellMods(Spell* spell, uint32 ownerAuraId = 0, Aura* aura = nullptr);
void RestoreAllSpellMods(uint32 ownerAuraId = 0, Aura* aura = nullptr);
- void DropModCharge(SpellModifier* mod, Spell* spell);
+ static void ApplyModToSpell(SpellModifier* mod, Spell* spell);
void SetSpellModTakingSpell(Spell* spell, bool apply);
void RemoveArenaSpellCooldowns(bool removeActivePetCooldowns = false);
@@ -1739,7 +1742,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void RecalculateRating(CombatRating cr) { ApplyRatingMod(cr, 0, true);}
float GetMeleeCritFromAgility() const;
void GetDodgeFromAgility(float &diminishing, float &nondiminishing) const;
- float GetMissPercentageFromDefence() const;
+ float GetMissPercentageFromDefense() const;
float GetSpellCritFromIntellect() const;
float OCTRegenHPPerSpirit() const;
float OCTRegenMPPerSpirit() const;
@@ -1845,9 +1848,12 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void UpdateLocalChannels(uint32 newZone);
void LeaveLFGChannel();
+ typedef std::list<Channel*> JoinedChannelsList;
+ JoinedChannelsList const& GetJoinedChannels() const { return m_channels; }
+
void UpdateDefense();
void UpdateWeaponSkill (WeaponAttackType attType);
- void UpdateCombatSkills(Unit* victim, WeaponAttackType attType, bool defence);
+ void UpdateCombatSkills(Unit* victim, WeaponAttackType attType, bool defense);
void SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal);
uint16 GetMaxSkillValue(uint32 skill) const; // max + perm. bonus + temp bonus
@@ -1937,7 +1943,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool CanBlock() const { return m_canBlock; }
void SetCanBlock(bool value);
bool CanTitanGrip() const { return m_canTitanGrip; }
- void SetCanTitanGrip(bool value) { m_canTitanGrip = value; }
+ void SetCanTitanGrip(bool value, uint32 penaltySpellId = 0);
+ void CheckTitanGripPenalty();
bool CanTameExoticPets() const { return IsGameMaster() || HasAuraType(SPELL_AURA_ALLOW_TAME_PET_TYPE); }
void SetRegularAttackTime();
@@ -1951,9 +1958,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void ResetAllPowers();
- void _ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply);
- void _ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply);
- void _ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply);
+ void ApplyItemDependentAuras(Item* item, bool apply);
void _ApplyItemMods(Item* item, uint8 slot, bool apply);
void _RemoveAllItemMods();
@@ -1970,9 +1975,9 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void ApplyItemEquipSpell(Item* item, bool apply, bool form_change = false);
void ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply, bool form_change = false);
void UpdateEquipSpellsAtFormChange();
- void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx);
+ void CastItemCombatSpell(DamageInfo const& damageInfo);
+ void CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto);
void CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 cast_count, uint32 glyphIndex);
- void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto);
void SendEquipmentSetList();
void SetEquipmentSet(uint32 index, EquipmentSet eqset);
@@ -2438,7 +2443,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
uint32 m_baseHealthRegen;
int32 m_spellPenetrationItemMod;
- SpellModList m_spellMods[MAX_SPELLMOD];
+ SpellModContainer m_spellMods[MAX_SPELLMOD];
EnchantDurationList m_enchantDuration;
ItemDurationList m_itemDuration;
@@ -2451,7 +2456,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
WorldSession* m_session;
- typedef std::list<Channel*> JoinedChannelsList;
JoinedChannelsList m_channels;
uint8 m_cinematic;
@@ -2479,6 +2483,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool m_canParry;
bool m_canBlock;
bool m_canTitanGrip;
+ uint32 m_titanGripPenaltySpellId;
uint8 m_swingErrorMsg;
float m_ammoDPS;
@@ -2610,8 +2615,8 @@ TC_GAME_API void AddItemsSetItem(Player* player, Item* item);
TC_GAME_API void RemoveItemsSetItem(Player* player, ItemTemplate const* proto);
// "the bodies of template functions must be made available in a header file"
-template <class T>
-void Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell /*= nullptr*/)
+template <SpellModOp op, class T>
+void Player::ApplySpellMod(uint32 spellId, T& basevalue, Spell* spell /*= nullptr*/) const
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo)
@@ -2624,33 +2629,89 @@ void Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* s
if (m_spellModTakingSpell)
spell = m_spellModTakingSpell;
- for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr)
+ switch (op)
{
- SpellModifier* mod = *itr;
+ // special case, if a mod makes spell instant, only consume that mod
+ case SPELLMOD_CASTING_TIME:
+ {
+ SpellModifier* modInstantSpell = nullptr;
+ for (SpellModifier* mod : m_spellMods[SPELLMOD_CASTING_TIME])
+ {
+ if (!IsAffectedBySpellmod(spellInfo, mod, spell))
+ continue;
+
+ if (mod->type == SPELLMOD_PCT && basevalue < T(10000) && mod->value <= -100)
+ {
+ modInstantSpell = mod;
+ break;
+ }
+ }
+
+ if (modInstantSpell)
+ {
+ Player::ApplyModToSpell(modInstantSpell, spell);
+ basevalue = T(0);
+ return;
+ }
+ break;
+ }
+ // special case if two mods apply 100% critical chance, only consume one
+ case SPELLMOD_CRITICAL_CHANCE:
+ {
+ SpellModifier* modCritical = nullptr;
+ for (SpellModifier* mod : m_spellMods[SPELLMOD_CRITICAL_CHANCE])
+ {
+ if (!IsAffectedBySpellmod(spellInfo, mod, spell))
+ continue;
+
+ if (mod->type == SPELLMOD_FLAT && mod->value >= 100)
+ {
+ modCritical = mod;
+ break;
+ }
+ }
- // Charges can be set only for mods with auras
- if (!mod->ownerAura)
- ASSERT(mod->charges == 0);
+ if (modCritical)
+ {
+ Player::ApplyModToSpell(modCritical, spell);
+ basevalue = T(100);
+ return;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ for (SpellModifier* mod : m_spellMods[op])
+ {
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
continue;
- if (mod->type == SPELLMOD_FLAT)
- totalflat += mod->value;
- else if (mod->type == SPELLMOD_PCT)
+ switch (mod->type)
{
- // skip percent mods for null basevalue (most important for spell mods with charges)
- if (basevalue == T(0))
- continue;
-
- // special case (skip > 10sec spell casts for instant cast setting)
- if (mod->op == SPELLMOD_CASTING_TIME && basevalue >= T(10000) && mod->value <= -100)
- continue;
-
- totalmul += CalculatePct(1.0f, mod->value);
+ case SPELLMOD_FLAT:
+ totalflat += mod->value;
+ break;
+ case SPELLMOD_PCT:
+ {
+ // skip percent mods for null basevalue (most important for spell mods with charges)
+ if (basevalue == T(0))
+ continue;
+
+ // special case (skip > 10sec spell casts for instant cast setting)
+ if (op == SPELLMOD_CASTING_TIME)
+ {
+ if (mod->value <= -100 && basevalue >= T(10000))
+ continue;
+ }
+
+ totalmul += CalculatePct(1.0f, mod->value);
+ break;
+ }
}
- DropModCharge(mod, spell);
+ Player::ApplyModToSpell(mod, spell);
}
basevalue = T(float(basevalue + totalflat) * totalmul);
diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp
index fad197949a8..cdb4b931a07 100644
--- a/src/server/game/Entities/Transport/Transport.cpp
+++ b/src/server/game/Entities/Transport/Transport.cpp
@@ -131,6 +131,7 @@ void Transport::Update(uint32 diff)
m_goValue.Transport.PathProgress += diff;
uint32 timer = m_goValue.Transport.PathProgress % GetTransportPeriod();
+ bool justStopped = false;
// Set current waypoint
// Desired outcome: _currentFrame->DepartureTime < timer < _nextFrame->ArriveTime
@@ -149,6 +150,7 @@ void Transport::Update(uint32 diff)
if (timer < _currentFrame->DepartureTime)
{
SetMoving(false);
+ justStopped = true;
if (_pendingStop && GetGoState() != GO_STATE_READY)
{
SetGoState(GO_STATE_READY);
@@ -203,12 +205,14 @@ void Transport::Update(uint32 diff)
_positionChangeTimer.Reset(positionUpdateDelay);
if (IsMoving())
{
- float t = CalculateSegmentPos(float(timer) * 0.001f);
+ float t = !justStopped ? CalculateSegmentPos(float(timer) * 0.001f) : 1.0f;
G3D::Vector3 pos, dir;
_currentFrame->Spline->evaluate_percent(_currentFrame->Index, t, pos);
_currentFrame->Spline->evaluate_derivative(_currentFrame->Index, t, dir);
UpdatePosition(pos.x, pos.y, pos.z, std::atan2(dir.y, dir.x) + float(M_PI));
}
+ else if (justStopped)
+ UpdatePosition(_currentFrame->Node->LocX, _currentFrame->Node->LocY, _currentFrame->Node->LocZ, _currentFrame->InitialOrientation);
else
{
/* There are four possible scenarios that trigger loading/unloading passengers:
diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp
index d1984da9648..0cad0b2cb05 100644
--- a/src/server/game/Entities/Unit/StatSystem.cpp
+++ b/src/server/game/Entities/Unit/StatSystem.cpp
@@ -184,8 +184,17 @@ void Player::UpdateSpellDamageAndHealingBonus()
// Get healing bonus for all schools
SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, SpellBaseHealingBonusDone(SPELL_SCHOOL_MASK_ALL));
// Get damage bonus for all schools
- for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
- SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonusDone(SpellSchoolMask(1 << i)));
+ Unit::AuraEffectList const& modDamageAuras = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE);
+ for (uint16 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
+ {
+ SetInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + i, std::accumulate(modDamageAuras.begin(), modDamageAuras.end(), 0, [i](int32 negativeMod, AuraEffect const* aurEff)
+ {
+ if (aurEff->GetAmount() < 0 && aurEff->GetMiscValue() & (1 << i))
+ negativeMod += aurEff->GetAmount();
+ return negativeMod;
+ }));
+ SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + i, SpellBaseDamageBonusDone(SpellSchoolMask(1 << i)) - GetInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + i));
+ }
}
bool Player::UpdateAllStats()
@@ -530,9 +539,9 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo
break;
}
- float attackSpeedMod = GetAPMultiplier(attType, normalized);
+ float const attackPowerMod = std::max(GetAPMultiplier(attType, normalized), 0.25f);
- float baseValue = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * attackSpeedMod;
+ float baseValue = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * attackPowerMod;
float basePct = GetModifierValue(unitMod, BASE_PCT);
float totalValue = GetModifierValue(unitMod, TOTAL_VALUE);
float totalPct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f;
@@ -546,8 +555,8 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo
if (lvl > 60)
lvl = 60;
- weaponMinDamage = lvl * 0.85f * attackSpeedMod;
- weaponMaxDamage = lvl * 1.25f * attackSpeedMod;
+ weaponMinDamage = lvl * 0.85f * attackPowerMod;
+ weaponMaxDamage = lvl * 1.25f * attackPowerMod;
}
else if (!CanUseAttackType(attType)) // check if player not in form but still can't use (disarm case)
{
@@ -563,8 +572,8 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo
}
else if (attType == RANGED_ATTACK) // add ammo DPS to ranged damage
{
- weaponMinDamage += GetAmmoDPS() * attackSpeedMod;
- weaponMaxDamage += GetAmmoDPS() * attackSpeedMod;
+ weaponMinDamage += GetAmmoDPS() * attackPowerMod;
+ weaponMaxDamage += GetAmmoDPS() * attackPowerMod;
}
minDamage = ((weaponMinDamage + baseValue) * basePct + totalValue) * totalPct;
@@ -666,7 +675,7 @@ const float m_diminishing_k[MAX_CLASSES] =
0.9720f // Druid
};
-float Player::GetMissPercentageFromDefence() const
+float Player::GetMissPercentageFromDefense() const
{
float const miss_cap[MAX_CLASSES] =
{
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 4581037d87a..7ff01efa363 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -92,37 +92,80 @@ float playerBaseMoveSpeed[MAX_MOVE_TYPE] =
3.14f // MOVE_PITCH_RATE
};
-// Used for prepare can/can`t triggr aura
-static bool InitTriggerAuraData();
-// Define can trigger auras
-static bool isTriggerAura[TOTAL_AURAS];
-// Define can't trigger auras (need for disable second trigger)
-static bool isNonTriggerAura[TOTAL_AURAS];
-// Triggered always, even from triggered spells
-static bool isAlwaysTriggeredAura[TOTAL_AURAS];
-// Prepare lists
-static bool procPrepared = InitTriggerAuraData();
-
-DamageInfo::DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType)
-: m_attacker(_attacker), m_victim(_victim), m_damage(_damage), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask),
-m_damageType(_damageType), m_attackType(BASE_ATTACK)
-{
- m_absorb = 0;
- m_resist = 0;
- m_block = 0;
-}
-DamageInfo::DamageInfo(CalcDamageInfo& dmgInfo)
-: m_attacker(dmgInfo.attacker), m_victim(dmgInfo.target), m_damage(dmgInfo.damage), m_spellInfo(NULL), m_schoolMask(SpellSchoolMask(dmgInfo.damageSchoolMask)),
-m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.attackType)
-{
- m_absorb = 0;
- m_resist = 0;
- m_block = 0;
+DamageInfo::DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType)
+ : m_attacker(attacker), m_victim(victim), m_damage(damage), m_spellInfo(spellInfo), m_schoolMask(schoolMask), m_damageType(damageType), m_attackType(attackType),
+ m_absorb(0), m_resist(0), m_block(0), m_hitMask(0)
+{
+}
+
+DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo)
+ : m_attacker(dmgInfo.attacker), m_victim(dmgInfo.target), m_damage(dmgInfo.damage), m_spellInfo(nullptr), m_schoolMask(SpellSchoolMask(dmgInfo.damageSchoolMask)),
+ m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.attackType), m_absorb(dmgInfo.absorb), m_resist(dmgInfo.resist), m_block(dmgInfo.blocked_amount), m_hitMask(0)
+{
+ switch (dmgInfo.TargetState)
+ {
+ case VICTIMSTATE_IS_IMMUNE:
+ m_hitMask |= PROC_HIT_IMMUNE;
+ break;
+ case VICTIMSTATE_BLOCKS:
+ m_hitMask |= PROC_HIT_FULL_BLOCK;
+ break;
+ }
+
+ if (dmgInfo.HitInfo & (HITINFO_PARTIAL_ABSORB | HITINFO_FULL_ABSORB))
+ m_hitMask |= PROC_HIT_ABSORB;
+
+ if (dmgInfo.HitInfo & HITINFO_FULL_RESIST)
+ m_hitMask |= PROC_HIT_FULL_RESIST;
+
+ if (m_block)
+ m_hitMask |= PROC_HIT_BLOCK;
+
+ bool const damageNullified = (dmgInfo.HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 ||
+ (m_hitMask & (PROC_HIT_IMMUNE | PROC_HIT_FULL_BLOCK)) != 0;
+ switch (dmgInfo.hitOutCome)
+ {
+ case MELEE_HIT_MISS:
+ m_hitMask |= PROC_HIT_MISS;
+ break;
+ case MELEE_HIT_DODGE:
+ m_hitMask |= PROC_HIT_DODGE;
+ break;
+ case MELEE_HIT_PARRY:
+ m_hitMask |= PROC_HIT_PARRY;
+ break;
+ case MELEE_HIT_EVADE:
+ m_hitMask |= PROC_HIT_EVADE;
+ break;
+ case MELEE_HIT_CRUSHING:
+ case MELEE_HIT_GLANCING:
+ case MELEE_HIT_NORMAL:
+ if (!damageNullified)
+ m_hitMask |= PROC_HIT_NORMAL;
+ break;
+ case MELEE_HIT_CRIT:
+ if (!damageNullified)
+ m_hitMask |= PROC_HIT_CRITICAL;
+ break;
+ default:
+ break;
+ }
+}
+
+DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, uint32 hitMask)
+ : m_attacker(spellNonMeleeDamage.attacker), m_victim(spellNonMeleeDamage.target), m_damage(spellNonMeleeDamage.damage),
+ m_spellInfo(sSpellMgr->GetSpellInfo(spellNonMeleeDamage.SpellID)), m_schoolMask(SpellSchoolMask(spellNonMeleeDamage.schoolMask)), m_damageType(damageType),
+ m_attackType(attackType), m_absorb(spellNonMeleeDamage.absorb), m_resist(spellNonMeleeDamage.resist), m_block(spellNonMeleeDamage.blocked), m_hitMask(hitMask)
+{
+ if (spellNonMeleeDamage.blocked)
+ m_hitMask |= PROC_HIT_BLOCK;
+ if (spellNonMeleeDamage.absorb)
+ m_hitMask |= PROC_HIT_ABSORB;
}
void DamageInfo::ModifyDamage(int32 amount)
{
- amount = std::min(amount, int32(GetDamage()));
+ amount = std::max(amount, -static_cast<int32>(GetDamage()));
m_damage += amount;
}
@@ -131,6 +174,7 @@ void DamageInfo::AbsorbDamage(uint32 amount)
amount = std::min(amount, GetDamage());
m_absorb += amount;
m_damage -= amount;
+ m_hitMask |= PROC_HIT_ABSORB;
}
void DamageInfo::ResistDamage(uint32 amount)
@@ -138,6 +182,11 @@ void DamageInfo::ResistDamage(uint32 amount)
amount = std::min(amount, GetDamage());
m_resist += amount;
m_damage -= amount;
+ if (!m_damage)
+ {
+ m_hitMask |= PROC_HIT_FULL_RESIST;
+ m_hitMask &= ~(PROC_HIT_NORMAL | PROC_HIT_CRITICAL);
+ }
}
void DamageInfo::BlockDamage(uint32 amount)
@@ -145,6 +194,37 @@ void DamageInfo::BlockDamage(uint32 amount)
amount = std::min(amount, GetDamage());
m_block += amount;
m_damage -= amount;
+ m_hitMask |= PROC_HIT_BLOCK;
+ if (!m_damage)
+ {
+ m_hitMask |= PROC_HIT_FULL_BLOCK;
+ m_hitMask &= ~(PROC_HIT_NORMAL | PROC_HIT_CRITICAL);
+ }
+}
+
+uint32 DamageInfo::GetHitMask() const
+{
+ return m_hitMask;
+}
+
+HealInfo::HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask)
+ : _healer(healer), _target(target), _heal(heal), _effectiveHeal(0), _absorb(0), _spellInfo(spellInfo), _schoolMask(schoolMask), _hitMask(0)
+{
+}
+
+void HealInfo::AbsorbHeal(uint32 amount)
+{
+ amount = std::min(amount, GetHeal());
+ _absorb += amount;
+ _heal -= amount;
+ amount = std::min(amount, GetEffectiveHeal());
+ _effectiveHeal -= amount;
+ _hitMask |= PROC_HIT_ABSORB;
+}
+
+uint32 HealInfo::GetHitMask() const
+{
+ return _hitMask;
}
ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget,
@@ -224,9 +304,6 @@ Unit::Unit(bool isWorldObject) :
m_transform = 0;
m_canModifyStats = false;
- for (uint8 i = 0; i < MAX_SPELL_IMMUNITY; ++i)
- m_spellImmune[i].clear();
-
for (uint8 i = 0; i < UNIT_MOD_END; ++i)
{
m_auraModifiersGroup[i][BASE_VALUE] = 0.0f;
@@ -576,7 +653,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons
|| HasBreakableByDamageAuraType(SPELL_AURA_TRANSFORM, excludeAura));
}
-void Unit::DealDamageMods(Unit* victim, uint32 &damage, uint32* absorb)
+void Unit::DealDamageMods(Unit const* victim, uint32 &damage, uint32* absorb) const
{
if (!victim || !victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
{
@@ -897,7 +974,7 @@ void Unit::CastSpell(Unit* victim, uint32 spellId, bool triggered, Item* castIte
CastSpell(victim, spellId, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster);
}
-void Unit::CastSpell(Unit* victim, uint32 spellId, TriggerCastFlags triggerFlags /*= TRIGGER_NONE*/, Item* castItem /*= NULL*/, AuraEffect const* triggeredByAura /*= NULL*/, ObjectGuid originalCaster /*= ObjectGuid::Empty*/)
+void Unit::CastSpell(Unit* victim, uint32 spellId, TriggerCastFlags triggerFlags /*= TRIGGER_NONE*/, Item* castItem /*= nullptr*/, AuraEffect const* triggeredByAura /*= nullptr*/, ObjectGuid originalCaster /*= ObjectGuid::Empty*/)
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo)
@@ -909,7 +986,7 @@ void Unit::CastSpell(Unit* victim, uint32 spellId, TriggerCastFlags triggerFlags
CastSpell(victim, spellInfo, triggerFlags, castItem, triggeredByAura, originalCaster);
}
-void Unit::CastSpell(Unit* victim, SpellInfo const* spellInfo, bool triggered, Item* castItem/*= NULL*/, AuraEffect const* triggeredByAura /*= NULL*/, ObjectGuid originalCaster /*= ObjectGuid::Empty*/)
+void Unit::CastSpell(Unit* victim, SpellInfo const* spellInfo, bool triggered, Item* castItem/*= nullptr*/, AuraEffect const* triggeredByAura /*= nullptr*/, ObjectGuid originalCaster /*= ObjectGuid::Empty*/)
{
CastSpell(victim, spellInfo, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster);
}
@@ -918,7 +995,7 @@ void Unit::CastSpell(Unit* victim, SpellInfo const* spellInfo, TriggerCastFlags
{
SpellCastTargets targets;
targets.SetUnitTarget(victim);
- CastSpell(targets, spellInfo, NULL, triggerFlags, castItem, triggeredByAura, originalCaster);
+ CastSpell(targets, spellInfo, nullptr, triggerFlags, castItem, triggeredByAura, originalCaster);
}
void Unit::CastCustomSpell(Unit* target, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, ObjectGuid originalCaster)
@@ -972,10 +1049,10 @@ void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered,
SpellCastTargets targets;
targets.SetDst(x, y, z, GetOrientation());
- CastSpell(targets, spellInfo, NULL, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster);
+ CastSpell(targets, spellInfo, nullptr, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster);
}
-void Unit::CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castItem, AuraEffect* triggeredByAura, ObjectGuid originalCaster)
+void Unit::CastSpell(float x, float y, float z, uint32 spellId, TriggerCastFlags triggerFlags, Item* castItem, AuraEffect const* triggeredByAura, ObjectGuid originalCaster)
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo)
@@ -984,26 +1061,23 @@ void Unit::CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castI
return;
}
SpellCastTargets targets;
- targets.SetGOTarget(go);
+ targets.SetDst(x, y, z, GetOrientation());
- CastSpell(targets, spellInfo, NULL, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster);
+ CastSpell(targets, spellInfo, nullptr, triggerFlags, castItem, triggeredByAura, originalCaster);
}
-// Obsolete func need remove, here only for comotability vs another patches
-uint32 Unit::SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage)
+void Unit::CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castItem, AuraEffect* triggeredByAura, ObjectGuid originalCaster)
{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID);
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo)
- return 0;
- SpellNonMeleeDamage damageInfo(this, victim, spellInfo->Id, spellInfo->SchoolMask);
- damage = SpellDamageBonusDone(victim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
- damage = victim->SpellDamageBonusTaken(this, spellInfo, damage, SPELL_DIRECT_DAMAGE);
+ {
+ TC_LOG_ERROR("entities.unit", "CastSpell: unknown spell id %u by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUID().GetCounter() : GetEntry()));
+ return;
+ }
+ SpellCastTargets targets;
+ targets.SetGOTarget(go);
- CalculateSpellDamageTaken(&damageInfo, damage, spellInfo);
- DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
- SendSpellNonMeleeDamageLog(&damageInfo);
- DealSpellDamage(&damageInfo, true);
- return damageInfo.damage;
+ CastSpell(targets, spellInfo, nullptr, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster);
}
void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType, bool crit)
@@ -1047,7 +1121,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
uint32 crit_bonus = damage;
// Apply crit_damage bonus for melee spells
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
+ modOwner->ApplySpellMod<SPELLMOD_CRIT_DAMAGE_BONUS>(spellInfo->Id, crit_bonus);
damage += crit_bonus;
// Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
@@ -1074,18 +1148,21 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
// double blocked amount if block is critical
if (victim->isBlockCritical())
damageInfo->blocked += damageInfo->blocked;
- if (damage < int32(damageInfo->blocked))
+ if (damage <= int32(damageInfo->blocked))
+ {
damageInfo->blocked = uint32(damage);
+ damageInfo->fullBlock = true;
+ }
damage -= damageInfo->blocked;
}
if (attackType != RANGED_ATTACK)
- ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_MELEE);
+ ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_MELEE);
else
- ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_RANGED);
+ ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_RANGED);
break;
}
- // Magical Attacks
+ // Magical Attacks
case SPELL_DAMAGE_CLASS_NONE:
case SPELL_DAMAGE_CLASS_MAGIC:
{
@@ -1096,7 +1173,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
damage = SpellCriticalDamageBonus(spellInfo, damage, victim);
}
- ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_SPELL);
+ ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_SPELL);
break;
}
default:
@@ -1108,24 +1185,30 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
sScriptMgr->ModifySpellDamageTaken(damageInfo->target, damageInfo->attacker, damage);
// Calculate absorb resist
- if (damage > 0)
- {
- CalcAbsorbResist(victim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo);
- damage -= damageInfo->absorb + damageInfo->resist;
- }
- else
+ if (damage < 0)
damage = 0;
damageInfo->damage = damage;
+ DamageInfo dmgInfo(*damageInfo, SPELL_DIRECT_DAMAGE, BASE_ATTACK, PROC_HIT_NONE);
+ CalcAbsorbResist(dmgInfo);
+ damageInfo->absorb = dmgInfo.GetAbsorb();
+ damageInfo->resist = dmgInfo.GetResist();
+
+ if (damageInfo->absorb)
+ damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
+
+ if (damageInfo->resist)
+ damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
+
+ damageInfo->damage = dmgInfo.GetDamage();
}
void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss)
{
- if (damageInfo == 0)
+ if (!damageInfo)
return;
Unit* victim = damageInfo->target;
-
if (!victim)
return;
@@ -1161,7 +1244,6 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
damageInfo->HitInfo = 0;
damageInfo->procAttacker = PROC_FLAG_NONE;
damageInfo->procVictim = PROC_FLAG_NONE;
- damageInfo->procEx = PROC_EX_NONE;
damageInfo->hitOutCome = MELEE_HIT_EVADE;
if (!victim)
@@ -1192,7 +1274,6 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
damageInfo->HitInfo |= HITINFO_NORMALSWING;
damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
- damageInfo->procEx |= PROC_EX_IMMUNE;
damageInfo->damage = 0;
damageInfo->cleanDamage = 0;
return;
@@ -1222,27 +1303,23 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
case MELEE_HIT_EVADE:
damageInfo->HitInfo |= HITINFO_MISS | HITINFO_SWINGNOHITSOUND;
damageInfo->TargetState = VICTIMSTATE_EVADES;
- damageInfo->procEx |= PROC_EX_EVADE;
damageInfo->damage = 0;
damageInfo->cleanDamage = 0;
return;
case MELEE_HIT_MISS:
damageInfo->HitInfo |= HITINFO_MISS;
damageInfo->TargetState = VICTIMSTATE_INTACT;
- damageInfo->procEx |= PROC_EX_MISS;
damageInfo->damage = 0;
damageInfo->cleanDamage = 0;
break;
case MELEE_HIT_NORMAL:
damageInfo->TargetState = VICTIMSTATE_HIT;
- damageInfo->procEx |= PROC_EX_NORMAL_HIT;
break;
case MELEE_HIT_CRIT:
{
damageInfo->HitInfo |= HITINFO_CRITICALHIT;
damageInfo->TargetState = VICTIMSTATE_HIT;
- damageInfo->procEx |= PROC_EX_CRITICAL_HIT;
// Crit bonus calc
damageInfo->damage += damageInfo->damage;
float mod = 0.0f;
@@ -1265,32 +1342,27 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
}
case MELEE_HIT_PARRY:
damageInfo->TargetState = VICTIMSTATE_PARRY;
- damageInfo->procEx |= PROC_EX_PARRY;
damageInfo->cleanDamage += damageInfo->damage;
damageInfo->damage = 0;
break;
case MELEE_HIT_DODGE:
damageInfo->TargetState = VICTIMSTATE_DODGE;
- damageInfo->procEx |= PROC_EX_DODGE;
damageInfo->cleanDamage += damageInfo->damage;
damageInfo->damage = 0;
break;
case MELEE_HIT_BLOCK:
damageInfo->TargetState = VICTIMSTATE_HIT;
damageInfo->HitInfo |= HITINFO_BLOCK;
- damageInfo->procEx |= PROC_EX_BLOCK;
damageInfo->blocked_amount = damageInfo->target->GetShieldBlockValue();
// double blocked amount if block is critical
if (damageInfo->target->isBlockCritical())
- damageInfo->blocked_amount+=damageInfo->blocked_amount;
+ damageInfo->blocked_amount += damageInfo->blocked_amount;
if (damageInfo->blocked_amount >= damageInfo->damage)
{
damageInfo->TargetState = VICTIMSTATE_BLOCKS;
damageInfo->blocked_amount = damageInfo->damage;
- damageInfo->procEx |= PROC_EX_FULL_BLOCK;
}
- else
- damageInfo->procEx |= PROC_EX_NORMAL_HIT;
+
damageInfo->damage -= damageInfo->blocked_amount;
damageInfo->cleanDamage += damageInfo->blocked_amount;
break;
@@ -1298,11 +1370,15 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
{
damageInfo->HitInfo |= HITINFO_GLANCING;
damageInfo->TargetState = VICTIMSTATE_HIT;
- damageInfo->procEx |= PROC_EX_NORMAL_HIT;
int32 leveldif = int32(victim->getLevel()) - int32(getLevel());
if (leveldif > 3)
leveldif = 3;
- float reducePercent = 1 - leveldif * 0.1f;
+
+ // against boss-level targets - 24% chance of 25% average damage reduction (damage reduction range : 20-30%)
+ // against level 82 elites - 18% chance of 15% average damage reduction (damage reduction range : 10-20%)
+ int32 const reductionMax = leveldif * 10;
+ int32 const reductionMin = reductionMax - 10;
+ float reducePercent = 1.f - irand(reductionMin, reductionMax) / 100.0f;
damageInfo->cleanDamage += damageInfo->damage - uint32(reducePercent * damageInfo->damage);
damageInfo->damage = uint32(reducePercent * damageInfo->damage);
break;
@@ -1310,7 +1386,6 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
case MELEE_HIT_CRUSHING:
damageInfo->HitInfo |= HITINFO_CRUSHING;
damageInfo->TargetState = VICTIMSTATE_HIT;
- damageInfo->procEx |= PROC_EX_NORMAL_HIT;
// 150% normal damage
damageInfo->damage += (damageInfo->damage / 2);
break;
@@ -1334,18 +1409,18 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
{
damageInfo->procVictim |= PROC_FLAG_TAKEN_DAMAGE;
// Calculate absorb & resists
- CalcAbsorbResist(damageInfo->target, SpellSchoolMask(damageInfo->damageSchoolMask), DIRECT_DAMAGE, damageInfo->damage, &damageInfo->absorb, &damageInfo->resist);
+ DamageInfo dmgInfo(*damageInfo);
+ CalcAbsorbResist(dmgInfo);
+ damageInfo->absorb = dmgInfo.GetAbsorb();
+ damageInfo->resist = dmgInfo.GetResist();
if (damageInfo->absorb)
- {
damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
- damageInfo->procEx |= PROC_EX_ABSORB;
- }
if (damageInfo->resist)
damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
- damageInfo->damage -= damageInfo->absorb + damageInfo->resist;
+ damageInfo->damage = dmgInfo.GetDamage();
}
else // Impossible get negative result but....
damageInfo->damage = 0;
@@ -1430,7 +1505,10 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
}
if (GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->CastItemCombatSpell(victim, damageInfo->attackType, damageInfo->procVictim, damageInfo->procEx);
+ {
+ DamageInfo dmgInfo(*damageInfo);
+ ToPlayer()->CastItemCombatSpell(dmgInfo);
+ }
// Do effect if any damage done to target
if (damageInfo->damage)
@@ -1438,46 +1516,47 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
// We're going to call functions which can modify content of the list during iteration over it's elements
// Let's copy the list so we can prevent iterator invalidation
AuraEffectList vDamageShieldsCopy(victim->GetAuraEffectsByType(SPELL_AURA_DAMAGE_SHIELD));
- for (AuraEffectList::const_iterator dmgShieldItr = vDamageShieldsCopy.begin(); dmgShieldItr != vDamageShieldsCopy.end(); ++dmgShieldItr)
+ for (AuraEffect const* aurEff : vDamageShieldsCopy)
{
- SpellInfo const* i_spellProto = (*dmgShieldItr)->GetSpellInfo();
+ SpellInfo const* spellInfo = aurEff->GetSpellInfo();
+
// Damage shield can be resisted...
- if (SpellMissInfo missInfo = victim->SpellHitResult(this, i_spellProto, false))
+ SpellMissInfo missInfo = victim->SpellHitResult(this, spellInfo, false);
+ if (missInfo != SPELL_MISS_NONE)
{
- victim->SendSpellMiss(this, i_spellProto->Id, missInfo);
+ victim->SendSpellMiss(this, spellInfo->Id, missInfo);
continue;
}
// ...or immuned
- if (IsImmunedToDamage(i_spellProto))
+ if (IsImmunedToDamage(spellInfo))
{
- victim->SendSpellDamageImmune(this, i_spellProto->Id);
+ victim->SendSpellDamageImmune(this, spellInfo->Id);
continue;
}
- uint32 damage = (*dmgShieldItr)->GetAmount();
-
- if (Unit* caster = (*dmgShieldItr)->GetCaster())
+ uint32 damage = aurEff->GetAmount();
+ if (Unit* caster = aurEff->GetCaster())
{
- damage = caster->SpellDamageBonusDone(this, i_spellProto, damage, SPELL_DIRECT_DAMAGE);
- damage = this->SpellDamageBonusTaken(caster, i_spellProto, damage, SPELL_DIRECT_DAMAGE);
+ damage = caster->SpellDamageBonusDone(this, spellInfo, damage, SPELL_DIRECT_DAMAGE);
+ damage = SpellDamageBonusTaken(caster, spellInfo, damage, SPELL_DIRECT_DAMAGE);
}
// No Unit::CalcAbsorbResist here - opcode doesn't send that data - this damage is probably not affected by that
- victim->DealDamageMods(this, damage, NULL);
+ victim->DealDamageMods(this, damage, nullptr);
/// @todo Move this to a packet handler
WorldPacket data(SMSG_SPELLDAMAGESHIELD, 8 + 8 + 4 + 4 + 4 + 4 + 4);
data << uint64(victim->GetGUID());
data << uint64(GetGUID());
- data << uint32(i_spellProto->Id);
+ data << uint32(spellInfo->Id);
data << uint32(damage); // Damage
- int32 overkill = int32(damage) - int32(GetHealth());
- data << uint32(overkill > 0 ? overkill : 0); // Overkill
- data << uint32(i_spellProto->SchoolMask);
+ int32 const overkill = int32(damage) - int32(GetHealth());
+ data << uint32(std::max(overkill, 0)); // Overkill
+ data << uint32(spellInfo->SchoolMask);
victim->SendMessageToSet(&data, true);
- victim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, i_spellProto->GetSchoolMask(), i_spellProto, true);
+ victim->DealDamage(this, damage, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true);
}
}
}
@@ -1522,7 +1601,7 @@ uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo
if (spellInfo)
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor);
+ modOwner->ApplySpellMod<SPELLMOD_IGNORE_ARMOR>(spellInfo->Id, armor);
AuraEffectList const& resIgnoreAurasAb = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
for (AuraEffectList::const_iterator j = resIgnoreAurasAb.begin(); j != resIgnoreAurasAb.end(); ++j)
@@ -1669,57 +1748,49 @@ uint32 Unit::CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, Spell
return resistance * 10;
}
-void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint32 const damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo /*= NULL*/)
+void Unit::CalcAbsorbResist(DamageInfo& damageInfo)
{
- if (!victim || !victim->IsAlive() || !damage)
+ if (!damageInfo.GetVictim() || !damageInfo.GetVictim()->IsAlive() || !damageInfo.GetDamage())
return;
- DamageInfo dmgInfo = DamageInfo(this, victim, damage, spellInfo, schoolMask, damagetype);
-
- uint32 spellResistance = CalcSpellResistance(victim, schoolMask, spellInfo);
- dmgInfo.ResistDamage(CalculatePct(damage, spellResistance));
+ uint32 spellResistance = CalcSpellResistance(damageInfo.GetVictim(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo());
+ damageInfo.ResistDamage(CalculatePct(damageInfo.GetDamage(), spellResistance));
// Ignore Absorption Auras
- float auraAbsorbMod = 0;
- AuraEffectList const& AbsIgnoreAurasA = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL);
- for (AuraEffectList::const_iterator itr = AbsIgnoreAurasA.begin(); itr != AbsIgnoreAurasA.end(); ++itr)
+ float auraAbsorbMod(GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL, damageInfo.GetSchoolMask()));
+
+ AuraEffectList const& abilityAbsorbAuras = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL);
+ for (AuraEffect const* aurEff : abilityAbsorbAuras)
{
- if (!((*itr)->GetMiscValue() & schoolMask))
+ if (!(aurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
continue;
- if ((*itr)->GetAmount() > auraAbsorbMod)
- auraAbsorbMod = float((*itr)->GetAmount());
- }
-
- AuraEffectList const& AbsIgnoreAurasB = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL);
- for (AuraEffectList::const_iterator itr = AbsIgnoreAurasB.begin(); itr != AbsIgnoreAurasB.end(); ++itr)
- {
- if (!((*itr)->GetMiscValue() & schoolMask))
+ if (!aurEff->IsAffectedOnSpell(damageInfo.GetSpellInfo()))
continue;
- if (((*itr)->GetAmount() > auraAbsorbMod) && (*itr)->IsAffectedOnSpell(spellInfo))
- auraAbsorbMod = float((*itr)->GetAmount());
+ if ((aurEff->GetAmount() > auraAbsorbMod))
+ auraAbsorbMod = float(aurEff->GetAmount());
}
RoundToInterval(auraAbsorbMod, 0.0f, 100.0f);
- int32 absorbIgnoringDamage = CalculatePct(dmgInfo.GetDamage(), auraAbsorbMod);
- dmgInfo.ModifyDamage(-absorbIgnoringDamage);
+ int32 absorbIgnoringDamage = CalculatePct(damageInfo.GetDamage(), auraAbsorbMod);
+ damageInfo.ModifyDamage(-absorbIgnoringDamage);
// We're going to call functions which can modify content of the list during iteration over it's elements
// Let's copy the list so we can prevent iterator invalidation
- AuraEffectList vSchoolAbsorbCopy(victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB));
+ AuraEffectList vSchoolAbsorbCopy(damageInfo.GetVictim()->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB));
vSchoolAbsorbCopy.sort(Trinity::AbsorbAuraOrderPred());
// absorb without mana cost
- for (AuraEffectList::iterator itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
+ for (AuraEffectList::iterator itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
{
AuraEffect* absorbAurEff = *itr;
// Check if aura was removed during iteration - we don't need to work on such auras
- AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID());
+ AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
if (!aurApp)
continue;
- if (!(absorbAurEff->GetMiscValue() & schoolMask))
+ if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
continue;
// get amount which can be still absorbed by the aura
@@ -1732,19 +1803,19 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
bool defaultPrevented = false;
- absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb, defaultPrevented);
+ absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
currentAbsorb = tempAbsorb;
if (defaultPrevented)
continue;
// absorb must be smaller than the damage itself
- currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage()));
+ currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
- dmgInfo.AbsorbDamage(currentAbsorb);
+ damageInfo.AbsorbDamage(currentAbsorb);
tempAbsorb = currentAbsorb;
- absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb);
+ absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
// Check if our aura is using amount to count damage
if (absorbAurEff->GetAmount() >= 0)
@@ -1758,16 +1829,16 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
}
// absorb by mana cost
- AuraEffectList vManaShieldCopy(victim->GetAuraEffectsByType(SPELL_AURA_MANA_SHIELD));
- for (AuraEffectList::const_iterator itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
+ AuraEffectList vManaShieldCopy(damageInfo.GetVictim()->GetAuraEffectsByType(SPELL_AURA_MANA_SHIELD));
+ for (AuraEffectList::const_iterator itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
{
AuraEffect* absorbAurEff = *itr;
// Check if aura was removed during iteration - we don't need to work on such auras
- AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID());
+ AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
if (!aurApp)
continue;
// check damage school mask
- if (!(absorbAurEff->GetMiscValue() & schoolMask))
+ if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
continue;
// get amount which can be still absorbed by the aura
@@ -1780,14 +1851,14 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
bool defaultPrevented = false;
- absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb, defaultPrevented);
+ absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
currentAbsorb = tempAbsorb;
if (defaultPrevented)
continue;
// absorb must be smaller than the damage itself
- currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage()));
+ currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
int32 manaReduction = currentAbsorb;
@@ -1795,15 +1866,15 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
if (float manaMultiplier = absorbAurEff->GetSpellInfo()->Effects[absorbAurEff->GetEffIndex()].CalcValueMultiplier(absorbAurEff->GetCaster()))
manaReduction = int32(float(manaReduction) * manaMultiplier);
- int32 manaTaken = -victim->ModifyPower(POWER_MANA, -manaReduction);
+ int32 manaTaken = -damageInfo.GetVictim()->ModifyPower(POWER_MANA, -manaReduction);
// take case when mana has ended up into account
currentAbsorb = currentAbsorb ? int32(float(currentAbsorb) * (float(manaTaken) / float(manaReduction))) : 0;
- dmgInfo.AbsorbDamage(currentAbsorb);
+ damageInfo.AbsorbDamage(currentAbsorb);
tempAbsorb = currentAbsorb;
- absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb);
+ absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
// Check if our aura is using amount to count damage
if (absorbAurEff->GetAmount() >= 0)
@@ -1814,39 +1885,39 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
}
}
- dmgInfo.ModifyDamage(absorbIgnoringDamage);
+ damageInfo.ModifyDamage(absorbIgnoringDamage);
// split damage auras - only when not damaging self
- if (victim != this)
+ if (damageInfo.GetVictim() != this)
{
// We're going to call functions which can modify content of the list during iteration over it's elements
// Let's copy the list so we can prevent iterator invalidation
- AuraEffectList vSplitDamageFlatCopy(victim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_FLAT));
- for (AuraEffectList::iterator itr = vSplitDamageFlatCopy.begin(); (itr != vSplitDamageFlatCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
+ AuraEffectList vSplitDamageFlatCopy(damageInfo.GetVictim()->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_FLAT));
+ for (AuraEffectList::iterator itr = vSplitDamageFlatCopy.begin(); (itr != vSplitDamageFlatCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
{
// Check if aura was removed during iteration - we don't need to work on such auras
- if (!((*itr)->GetBase()->IsAppliedOnTarget(victim->GetGUID())))
+ if (!((*itr)->GetBase()->IsAppliedOnTarget(damageInfo.GetVictim()->GetGUID())))
continue;
// check damage school mask
- if (!((*itr)->GetMiscValue() & schoolMask))
+ if (!((*itr)->GetMiscValue() & damageInfo.GetSchoolMask()))
continue;
// Damage can be splitted only if aura has an alive caster
Unit* caster = (*itr)->GetCaster();
- if (!caster || (caster == victim) || !caster->IsInWorld() || !caster->IsAlive())
+ if (!caster || (caster == damageInfo.GetVictim()) || !caster->IsInWorld() || !caster->IsAlive())
continue;
int32 splitDamage = (*itr)->GetAmount();
// absorb must be smaller than the damage itself
- splitDamage = RoundToInterval(splitDamage, 0, int32(dmgInfo.GetDamage()));
+ splitDamage = RoundToInterval(splitDamage, 0, int32(damageInfo.GetDamage()));
- dmgInfo.AbsorbDamage(splitDamage);
+ damageInfo.AbsorbDamage(splitDamage);
// check if caster is immune to damage
- if (caster->IsImmunedToDamage(schoolMask))
+ if (caster->IsImmunedToDamage(damageInfo.GetSchoolMask()))
{
- victim->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE);
+ damageInfo.GetVictim()->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE);
continue;
}
@@ -1854,78 +1925,77 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
uint32 splitted_absorb = 0;
DealDamageMods(caster, splitted, &splitted_absorb);
- SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false);
+ SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitted, damageInfo.GetSchoolMask(), splitted_absorb, 0, false, 0, false);
CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
- DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellInfo(), false);
+ DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
}
// We're going to call functions which can modify content of the list during iteration over it's elements
// Let's copy the list so we can prevent iterator invalidation
- AuraEffectList vSplitDamagePctCopy(victim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_PCT));
- for (AuraEffectList::iterator itr = vSplitDamagePctCopy.begin(); itr != vSplitDamagePctCopy.end() && dmgInfo.GetDamage() > 0; ++itr)
+ AuraEffectList vSplitDamagePctCopy(damageInfo.GetVictim()->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_PCT));
+ for (AuraEffectList::iterator itr = vSplitDamagePctCopy.begin(); itr != vSplitDamagePctCopy.end() && damageInfo.GetDamage() > 0; ++itr)
{
// Check if aura was removed during iteration - we don't need to work on such auras
- AuraApplication const* aurApp = (*itr)->GetBase()->GetApplicationOfTarget(victim->GetGUID());
+ AuraApplication const* aurApp = (*itr)->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
if (!aurApp)
continue;
// check damage school mask
- if (!((*itr)->GetMiscValue() & schoolMask))
+ if (!((*itr)->GetMiscValue() & damageInfo.GetSchoolMask()))
continue;
// Damage can be splitted only if aura has an alive caster
Unit* caster = (*itr)->GetCaster();
- if (!caster || (caster == victim) || !caster->IsInWorld() || !caster->IsAlive())
+ if (!caster || (caster == damageInfo.GetVictim()) || !caster->IsInWorld() || !caster->IsAlive())
continue;
- uint32 splitDamage = CalculatePct(dmgInfo.GetDamage(), (*itr)->GetAmount());
+ uint32 splitDamage = CalculatePct(damageInfo.GetDamage(), (*itr)->GetAmount());
- (*itr)->GetBase()->CallScriptEffectSplitHandlers((*itr), aurApp, dmgInfo, splitDamage);
+ (*itr)->GetBase()->CallScriptEffectSplitHandlers((*itr), aurApp, damageInfo, splitDamage);
// absorb must be smaller than the damage itself
- splitDamage = RoundToInterval(splitDamage, uint32(0), uint32(dmgInfo.GetDamage()));
+ splitDamage = RoundToInterval(splitDamage, uint32(0), uint32(damageInfo.GetDamage()));
- dmgInfo.AbsorbDamage(splitDamage);
+ damageInfo.AbsorbDamage(splitDamage);
// check if caster is immune to damage
- if (caster->IsImmunedToDamage(schoolMask))
+ if (caster->IsImmunedToDamage(damageInfo.GetSchoolMask()))
{
- victim->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE);
+ damageInfo.GetVictim()->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE);
continue;
}
uint32 split_absorb = 0;
DealDamageMods(caster, splitDamage, &split_absorb);
- SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitDamage, schoolMask, split_absorb, 0, false, 0, false);
+ SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitDamage, damageInfo.GetSchoolMask(), split_absorb, 0, false, 0, false);
CleanDamage cleanDamage = CleanDamage(splitDamage, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
- DealDamage(caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellInfo(), false);
+ DealDamage(caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
+
// break 'Fear' and similar auras
- caster->ProcDamageAndSpellFor(true, this, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_NORMAL_HIT, BASE_ATTACK, (*itr)->GetSpellInfo(), splitDamage);
+ ProcSkillsAndAuras(caster, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, PROC_HIT_NONE, nullptr, &damageInfo, nullptr);
}
}
-
- *resist = dmgInfo.GetResist();
- *absorb = dmgInfo.GetAbsorb();
}
-void Unit::CalcHealAbsorb(Unit* victim, SpellInfo const* healSpell, uint32 &healAmount, uint32 &absorb)
+void Unit::CalcHealAbsorb(HealInfo& healInfo) const
{
- if (!healAmount)
+ if (!healInfo.GetHeal())
return;
- int32 RemainingHeal = healAmount;
+ int32 const healing = static_cast<int32>(healInfo.GetHeal());
+ int32 absorbAmount = 0;
// Need remove expired auras after
bool existExpired = false;
// absorb without mana cost
- AuraEffectList const& vHealAbsorb = victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_HEAL_ABSORB);
- for (AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end() && RemainingHeal > 0; ++i)
+ AuraEffectList const& vHealAbsorb = healInfo.GetTarget()->GetAuraEffectsByType(SPELL_AURA_SCHOOL_HEAL_ABSORB);
+ for (AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end() && absorbAmount <= healing; ++i)
{
- if (!((*i)->GetMiscValue() & healSpell->SchoolMask))
+ if (!((*i)->GetMiscValue() & healInfo.GetSpellInfo()->SchoolMask))
continue;
// Max Amount can be absorbed by this aura
@@ -1940,10 +2010,10 @@ void Unit::CalcHealAbsorb(Unit* victim, SpellInfo const* healSpell, uint32 &heal
// currentAbsorb - damage can be absorbed by shield
// If need absorb less damage
- if (RemainingHeal < currentAbsorb)
- currentAbsorb = RemainingHeal;
+ if (healing < currentAbsorb + absorbAmount)
+ currentAbsorb = healing - absorbAmount;
- RemainingHeal -= currentAbsorb;
+ absorbAmount += currentAbsorb;
// Reduce shield amount
(*i)->SetAmount((*i)->GetAmount() - currentAbsorb);
@@ -1961,19 +2031,19 @@ void Unit::CalcHealAbsorb(Unit* victim, SpellInfo const* healSpell, uint32 &heal
++i;
if (auraEff->GetAmount() <= 0)
{
- uint32 removedAuras = victim->m_removedAurasCount;
+ uint32 removedAuras = healInfo.GetTarget()->m_removedAurasCount;
auraEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
- if (removedAuras+1 < victim->m_removedAurasCount)
+ if (removedAuras + 1 < healInfo.GetTarget()->m_removedAurasCount)
i = vHealAbsorb.begin();
}
}
}
- absorb = RemainingHeal > 0 ? (healAmount - RemainingHeal) : healAmount;
- healAmount = RemainingHeal;
+ if (absorbAmount > 0)
+ healInfo.AbsorbHeal(absorbAmount);
}
-void Unit::AttackerStateUpdate (Unit* victim, WeaponAttackType attType, bool extra)
+void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra)
{
if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
return;
@@ -2007,8 +2077,8 @@ void Unit::AttackerStateUpdate (Unit* victim, WeaponAttackType attType, bool ext
DealDamageMods(victim, damageInfo.damage, &damageInfo.absorb);
SendAttackStateUpdate(&damageInfo);
- //TriggerAurasProcOnEvent(damageInfo);
- ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
+ DamageInfo dmgInfo(damageInfo);
+ ProcSkillsAndAuras(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr);
DealMeleeDamage(&damageInfo, true);
@@ -2021,6 +2091,49 @@ void Unit::AttackerStateUpdate (Unit* victim, WeaponAttackType attType, bool ext
}
}
+void Unit::FakeAttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BASE_ATTACK*/)
+{
+ if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
+ return;
+
+ if (!victim->IsAlive())
+ return;
+
+ if ((attType == BASE_ATTACK || attType == OFF_ATTACK) && !IsWithinLOSInMap(victim))
+ return;
+
+ CombatStart(victim);
+ RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MELEE_ATTACK);
+
+ if (attType != BASE_ATTACK && attType != OFF_ATTACK)
+ return; // ignore ranged case
+
+ if (GetTypeId() == TYPEID_UNIT && !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
+ SetFacingToObject(victim); // update client side facing to face the target (prevents visual glitches when casting untargeted spells)
+
+ CalcDamageInfo damageInfo;
+ damageInfo.attacker = this;
+ damageInfo.target = victim;
+ damageInfo.damageSchoolMask = GetMeleeDamageSchoolMask();
+ damageInfo.attackType = attType;
+ damageInfo.damage = 0;
+ damageInfo.cleanDamage = 0;
+ damageInfo.absorb = 0;
+ damageInfo.resist = 0;
+ damageInfo.blocked_amount = 0;
+
+ damageInfo.TargetState = VICTIMSTATE_HIT;
+ damageInfo.HitInfo = HITINFO_AFFECTS_VICTIM | HITINFO_NORMALSWING | HITINFO_FAKE_DAMAGE;
+ if (attType == OFF_ATTACK)
+ damageInfo.HitInfo |= HITINFO_OFFHAND;
+
+ damageInfo.procAttacker = PROC_FLAG_NONE;
+ damageInfo.procVictim = PROC_FLAG_NONE;
+ damageInfo.hitOutCome = MELEE_HIT_NORMAL;
+
+ SendAttackStateUpdate(&damageInfo);
+}
+
void Unit::HandleProcExtraAttackFor(Unit* victim)
{
while (m_extraAttacks)
@@ -2030,7 +2143,7 @@ void Unit::HandleProcExtraAttackFor(Unit* victim)
}
}
-MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* victim, WeaponAttackType attType) const
+MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackType attType) const
{
// This is only wrapper
@@ -2041,10 +2154,9 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* victim, WeaponAttackTy
// Critical hit chance
float crit_chance = GetUnitCriticalChance(attType, victim);
- // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case)
- float dodge_chance = victim->GetUnitDodgeChance();
- float block_chance = victim->GetUnitBlockChance();
- float parry_chance = victim->GetUnitParryChance();
+ float dodge_chance = GetUnitDodgeChance(attType, victim);
+ float block_chance = GetUnitBlockChance(attType, victim);
+ float parry_chance = GetUnitParryChance(attType, victim);
// Useful if want to specify crit & miss chances for melee, else it could be removed
TC_LOG_DEBUG("entities.unit", "MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance, crit_chance, dodge_chance, parry_chance, block_chance);
@@ -2052,123 +2164,68 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* victim, WeaponAttackTy
return RollMeleeOutcomeAgainst(victim, attType, int32(crit_chance*100), int32(miss_chance*100), int32(dodge_chance*100), int32(parry_chance*100), int32(block_chance*100));
}
-MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const
+MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const
{
if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks())
return MELEE_HIT_EVADE;
+ // melee attack table implementation
+ // outcome priority:
+ // 1. > 2. > 3. > 4. > 5. > 6. > 7. > 8.
+ // MISS > DODGE > PARRY > GLANCING > BLOCK > CRIT > CRUSHING > HIT
+
int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(victim);
int32 victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
int32 attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
int32 victimDefenseSkill = victim->GetDefenseSkillValue(this);
- // bonus from skills is 0.04%
- int32 skillBonus = 4 * (attackerWeaponSkill - victimMaxSkillValueForLevel);
int32 sum = 0, tmp = 0;
- int32 roll = urand (0, 10000);
+ int32 roll = urand(0, 9999);
- TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus);
- TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d",
- roll, miss_chance, dodge_chance, parry_chance, block_chance, crit_chance);
+ // check if attack comes from behind, nobody can parry or block if attacker is behind
+ bool canParryOrBlock = victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION);
- tmp = miss_chance;
+ // only creatures can dodge if attacker is behind
+ bool canDodge = victim->GetTypeId() != TYPEID_PLAYER || canParryOrBlock;
- if (tmp > 0 && roll < (sum += tmp))
+ // if victim is casting or cc'd it can't avoid attacks
+ if (victim->IsNonMeleeSpellCast(false) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
{
- TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: MISS");
- return MELEE_HIT_MISS;
+ canDodge = false;
+ canParryOrBlock = false;
}
+ // 1. MISS
+ tmp = miss_chance;
+ if (tmp > 0 && roll < (sum += tmp))
+ return MELEE_HIT_MISS;
+
// always crit against a sitting target (except 0 crit chance)
if (victim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !victim->IsStandState())
- {
- TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRIT (sitting victim)");
return MELEE_HIT_CRIT;
- }
- // Dodge chance
-
- // only players can't dodge if attacker is behind
- if (victim->GetTypeId() == TYPEID_PLAYER && !victim->HasInArc(float(M_PI), this) && !victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
- {
- TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: attack came from behind and victim was a player.");
- }
- else
+ // 2. DODGE
+ if (canDodge)
{
- // Reduce dodge chance by attacker expertise rating
- if (GetTypeId() == TYPEID_PLAYER)
- dodge_chance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100);
- else
- dodge_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
-
- // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
- dodge_chance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE) * 100;
- dodge_chance = int32 (float (dodge_chance) * GetTotalAuraMultiplier(SPELL_AURA_MOD_ENEMY_DODGE));
-
tmp = dodge_chance;
- if ((tmp > 0) // check if unit _can_ dodge
- && ((tmp -= skillBonus) > 0)
+ if (tmp > 0 // check if unit _can_ dodge
&& roll < (sum += tmp))
- {
- TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum);
return MELEE_HIT_DODGE;
- }
- }
-
- // parry & block chances
-
- // check if attack comes from behind, nobody can parry or block if attacker is behind
- if (!victim->HasInArc(float(M_PI), this) && !victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
- TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: attack came from behind.");
- else
- {
- // Reduce parry chance by attacker expertise rating
- if (GetTypeId() == TYPEID_PLAYER)
- parry_chance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100);
- else
- parry_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
-
- if (victim->GetTypeId() == TYPEID_PLAYER || !(victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY))
- {
- int32 tmp2 = int32(parry_chance);
- if (tmp2 > 0 // check if unit _can_ parry
- && (tmp2 -= skillBonus) > 0
- && roll < (sum += tmp2))
- {
- TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp2, sum);
- return MELEE_HIT_PARRY;
- }
- }
-
- if (victim->GetTypeId() == TYPEID_PLAYER || !(victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK))
- {
- tmp = block_chance;
- if (tmp > 0 // check if unit _can_ block
- && (tmp -= skillBonus) > 0
- && roll < (sum += tmp))
- {
- TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum);
- return MELEE_HIT_BLOCK;
- }
- }
}
- // Critical chance
- tmp = crit_chance;
-
- if (tmp > 0 && roll < (sum += tmp))
+ // 3. PARRY
+ if (canParryOrBlock)
{
- TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum);
- if (GetTypeId() == TYPEID_UNIT && (ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRIT))
- TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRIT DISABLED)");
- else
- return MELEE_HIT_CRIT;
+ tmp = parry_chance;
+ if (tmp > 0 // check if unit _can_ parry
+ && roll < (sum += tmp))
+ return MELEE_HIT_PARRY;
}
+ // 4. GLANCING
// Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon)
- if (attType != RANGED_ATTACK &&
- (GetTypeId() == TYPEID_PLAYER || IsPet()) &&
+ if ((GetTypeId() == TYPEID_PLAYER || IsPet()) &&
victim->GetTypeId() != TYPEID_PLAYER && !victim->IsPet() &&
getLevel() < victim->getLevelForTarget(this))
{
@@ -2177,15 +2234,29 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackT
int32 maxskill = attackerMaxSkillValueForLevel;
skill = (skill > maxskill) ? maxskill : skill;
- tmp = (10 + (victimDefenseSkill - skill)) * 100;
- tmp = tmp > 4000 ? 4000 : tmp;
- if (roll < (sum += tmp))
- {
- TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum);
+ // against boss-level targets - 24% chance of 25% average damage reduction (damage reduction range : 20-30%)
+ // against level 82 elites - 18% chance of 15% average damage reduction (damage reduction range : 10-20%)
+ tmp = 600 + (victimDefenseSkill - skill) * 120;
+ tmp = std::min(tmp, 4000);
+ if (tmp > 0 && roll < (sum += tmp))
return MELEE_HIT_GLANCING;
- }
}
+ // 5. BLOCK
+ if (canParryOrBlock)
+ {
+ tmp = block_chance;
+ if (tmp > 0 // check if unit _can_ block
+ && roll < (sum += tmp))
+ return MELEE_HIT_BLOCK;
+ }
+
+ // 6.CRIT
+ tmp = crit_chance;
+ if (tmp > 0 && roll < (sum += tmp))
+ return MELEE_HIT_CRIT;
+
+ // 7. CRUSHING
// mobs can score crushing blows if they're 4 or more levels above victim
if (getLevelForTarget(victim) >= victim->getLevelForTarget(this) + 4 &&
// can be from by creature (if can) or from controlled player that considered as creature
@@ -2194,24 +2265,20 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackT
{
// when their weapon skill is 15 or more above victim's defense skill
tmp = victimDefenseSkill;
- int32 tmpmax = victimMaxSkillValueForLevel;
// having defense above your maximum (from items, talents etc.) has no effect
- tmp = tmp > tmpmax ? tmpmax : tmp;
+ tmp = std::min(tmp, victimMaxSkillValueForLevel);
// tmp = mob's level * 5 - player's current defense skill
tmp = attackerMaxSkillValueForLevel - tmp;
- if (tmp >= 15)
- {
- // add 2% chance per lacking skill point, min. is 15%
- tmp = tmp * 200 - 1500;
- if (roll < (sum += tmp))
- {
- TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum);
- return MELEE_HIT_CRUSHING;
- }
- }
+ // minimum of 20 points diff (4 levels difference)
+ tmp = std::max(tmp, 20);
+
+ // add 2% chance per lacking skill point
+ tmp = tmp * 200 - 1500;
+ if (tmp > 0 && roll < (sum += tmp))
+ return MELEE_HIT_CRUSHING;
}
- TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: NORMAL");
+ // 8. HIT
return MELEE_HIT_NORMAL;
}
@@ -2302,21 +2369,20 @@ void Unit::SendMeleeAttackStop(Unit* victim)
bool Unit::isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType)
{
// These spells can't be blocked
- if (spellProto && spellProto->HasAttribute(SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK))
+ if (spellProto && (spellProto->HasAttribute(SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK) || spellProto->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT)))
+ return false;
+
+ // Can't block when casting/controlled
+ if (victim->IsNonMeleeSpellCast(false) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
return false;
if (victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION) || victim->HasInArc(float(M_PI), this))
{
- // Check creatures flags_extra for disable block
- if (victim->GetTypeId() == TYPEID_UNIT &&
- victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK)
- return false;
-
- float blockChance = victim->GetUnitBlockChance();
- blockChance += (int32(GetWeaponSkillValue(attackType)) - int32(victim->GetMaxSkillValueForLevel())) * 0.04f;
- if (roll_chance_f(blockChance))
+ float blockChance = GetUnitBlockChance(attackType, victim);
+ if (blockChance && roll_chance_f(blockChance))
return true;
}
+
return false;
}
@@ -2346,7 +2412,8 @@ int32 Unit::GetMechanicResistChance(SpellInfo const* spellInfo) const
resistMech = temp;
}
}
- return resistMech;
+
+ return std::max(resistMech, 0);
}
bool Unit::CanUseAttackType(uint8 attacktype) const
@@ -2365,13 +2432,8 @@ bool Unit::CanUseAttackType(uint8 attacktype) const
}
// Melee based spells hit result calculations
-SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo)
+SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const
{
- // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
- // resist and deflect chances
- if (spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
- return SPELL_MISS_NONE;
-
WeaponAttackType attType = BASE_ATTACK;
// Check damage class instead of attack type to correctly handle judgements
@@ -2380,16 +2442,15 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
attType = RANGED_ATTACK;
int32 attackerWeaponSkill;
- // skill value for these spells (for example judgements) is 5* level
+ // skill value for these spells (for example judgements) is 5 * level
if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED && !spellInfo->IsRangedWeaponSpell())
- attackerWeaponSkill = getLevel() * 5;
- // bonus from skills is 0.04% per skill Diff
+ attackerWeaponSkill = GetMaxSkillValueForLevel();
else
attackerWeaponSkill = int32(GetWeaponSkillValue(attType, victim));
int32 skillDiff = attackerWeaponSkill - int32(victim->GetMaxSkillValueForLevel(this));
- uint32 roll = urand (0, 10000);
+ uint32 roll = urand(0, 9999);
uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, skillDiff, spellInfo->Id) * 100.0f);
// Roll miss
@@ -2411,6 +2472,14 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
bool canParry = true;
bool canBlock = spellInfo->HasAttribute(SPELL_ATTR3_BLOCKABLE_SPELL);
+ // if victim is casting or cc'd it can't avoid attacks
+ if (victim->IsNonMeleeSpellCast(false) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
+ {
+ canDodge = false;
+ canParry = false;
+ canBlock = false;
+ }
+
// Ranged attacks can only miss, resist and deflect
if (attType == RANGED_ATTACK)
{
@@ -2418,7 +2487,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
canDodge = false;
// only if in front
- if (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
+ if (!victim->HasUnitState(UNIT_STATE_CONTROLLED) && (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)))
{
int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
tmp += deflect_chance;
@@ -2433,10 +2502,10 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
{
if (!victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
{
- // Can`t dodge from behind in PvP (but its possible in PvE)
+ // Can't dodge from behind in PvP (but its possible in PvE)
if (victim->GetTypeId() == TYPEID_PLAYER)
canDodge = false;
- // Can`t parry or block
+ // Can't parry or block
canParry = false;
canBlock = false;
}
@@ -2446,23 +2515,15 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
canParry = false;
}
}
- // Check creatures flags_extra for disable parry
- if (victim->GetTypeId() == TYPEID_UNIT)
- {
- uint32 flagEx = victim->ToCreature()->GetCreatureTemplate()->flags_extra;
- if (flagEx & CREATURE_FLAG_EXTRA_NO_PARRY)
- canParry = false;
- // Check creatures flags_extra for disable block
- if (flagEx & CREATURE_FLAG_EXTRA_NO_BLOCK)
- canBlock = false;
- }
+
// Ignore combat result aura
AuraEffectList const& ignore = GetAuraEffectsByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
- for (AuraEffectList::const_iterator i = ignore.begin(); i != ignore.end(); ++i)
+ for (AuraEffect const* aurEff : ignore)
{
- if (!(*i)->IsAffectedOnSpell(spellInfo))
+ if (!aurEff->IsAffectedOnSpell(spellInfo))
continue;
- switch ((*i)->GetMiscValue())
+
+ switch (aurEff->GetMiscValue())
{
case MELEE_HIT_DODGE:
canDodge = false;
@@ -2474,7 +2535,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
canParry = false;
break;
default:
- TC_LOG_DEBUG("entities.unit", "Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT has unhandled state %d", (*i)->GetId(), (*i)->GetMiscValue());
+ TC_LOG_DEBUG("entities.unit", "Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT has unhandled state %d", aurEff->GetId(), aurEff->GetMiscValue());
break;
}
}
@@ -2482,15 +2543,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
if (canDodge)
{
// Roll dodge
- int32 dodgeChance = int32(victim->GetUnitDodgeChance() * 100.0f) - skillDiff * 4;
- // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
- dodgeChance += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE) * 100;
- dodgeChance = int32(float(dodgeChance) * GetTotalAuraMultiplier(SPELL_AURA_MOD_ENEMY_DODGE));
- // Reduce dodge chance by attacker expertise rating
- if (GetTypeId() == TYPEID_PLAYER)
- dodgeChance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
- else
- dodgeChance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
+ int32 dodgeChance = int32(GetUnitDodgeChance(attType, victim) * 100.0f);
if (dodgeChance < 0)
dodgeChance = 0;
@@ -2501,12 +2554,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
if (canParry)
{
// Roll parry
- int32 parryChance = int32(victim->GetUnitParryChance() * 100.0f) - skillDiff * 4;
- // Reduce parry chance by attacker expertise rating
- if (GetTypeId() == TYPEID_PLAYER)
- parryChance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
- else
- parryChance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
+ int32 parryChance = int32(GetUnitParryChance(attType, victim) * 100.0f);
if (parryChance < 0)
parryChance = 0;
@@ -2517,7 +2565,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
if (canBlock)
{
- int32 blockChance = int32(victim->GetUnitBlockChance() * 100.0f) - skillDiff * 4;
+ int32 blockChance = int32(GetUnitBlockChance(attType, victim) * 100.0f);
if (blockChance < 0)
blockChance = 0;
tmp += blockChance;
@@ -2530,10 +2578,10 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
}
/// @todo need use unit spell resistances in calculations
-SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo)
+SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const
{
// Can`t miss on dead target (on skinning for example)
- if ((!victim->IsAlive() && victim->GetTypeId() != TYPEID_PLAYER) || spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
+ if ((!victim->IsAlive() && victim->GetTypeId() != TYPEID_PLAYER))
return SPELL_MISS_NONE;
SpellSchoolMask schoolMask = spellInfo->GetSchoolMask();
@@ -2553,7 +2601,7 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
// Spellmod from SPELLMOD_RESIST_MISS_CHANCE
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
+ modOwner->ApplySpellMod<SPELLMOD_RESIST_MISS_CHANCE>(spellInfo->Id, modHitChance);
// Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
modHitChance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask);
@@ -2576,8 +2624,7 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
int32 tmp = 10000 - HitChance;
- int32 rand = irand(0, 10000);
-
+ int32 rand = irand(0, 9999);
if (rand < tmp)
return SPELL_MISS_MISS;
@@ -2599,10 +2646,7 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
}
if (hasAura)
- {
- tmp += victim->GetMaxPositiveAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spellInfo->Dispel)) * 100;
- tmp += victim->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spellInfo->Dispel)) * 100;
- }
+ tmp += victim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, static_cast<int32>(spellInfo->Dispel)) * 100;
}
// Roll chance
@@ -2610,7 +2654,7 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
return SPELL_MISS_RESIST;
// cast by caster in front of victim
- if (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
+ if (!victim->HasUnitState(UNIT_STATE_CONTROLLED) && (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)))
{
int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
tmp += deflect_chance;
@@ -2631,19 +2675,23 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
// Resist
SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool CanReflect)
{
+ if (spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
+ return SPELL_MISS_NONE;
+
// Check for immune
if (victim->IsImmunedToSpell(spellInfo))
return SPELL_MISS_IMMUNE;
+ // Damage immunity is only checked if the spell has damage effects, this immunity must not prevent aura apply
+ // returns SPELL_MISS_IMMUNE in that case, for other spells, the SMSG_SPELL_GO must show hit
+ if (spellInfo->HasOnlyDamageEffects() && victim->IsImmunedToDamage(spellInfo))
+ return SPELL_MISS_IMMUNE;
+
// All positive spells can`t miss
/// @todo client not show miss log for this spells - so need find info for this in dbc and use it!
if (spellInfo->IsPositive() && !IsHostileTo(victim)) // prevent from affecting enemy by "positive" spell
return SPELL_MISS_NONE;
- // Check for immune
- if (victim->IsImmunedToDamage(spellInfo))
- return SPELL_MISS_IMMUNE;
-
if (this == victim)
return SPELL_MISS_NONE;
@@ -2659,12 +2707,9 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, boo
for (Unit::AuraEffectList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
if ((*i)->GetMiscValue() & spellInfo->GetSchoolMask())
reflectchance += (*i)->GetAmount();
+
if (reflectchance > 0 && roll_chance_i(reflectchance))
- {
- // Start triggers for remove charges if need (trigger only for victim, and mark as active spell)
- ProcDamageAndSpell(victim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_REFLECT, 1, BASE_ATTACK, spellInfo);
return SPELL_MISS_REFLECT;
- }
}
switch (spellInfo->DmgClass)
@@ -2715,55 +2760,93 @@ uint32 Unit::GetDefenseSkillValue(Unit const* target) const
return GetUnitMeleeSkill(target);
}
-float Unit::GetUnitDodgeChance() const
+float Unit::GetUnitDodgeChance(WeaponAttackType attType, Unit const* victim) const
{
- if (IsNonMeleeSpellCast(false) || HasUnitState(UNIT_STATE_CONTROLLED))
- return 0.0f;
+ int32 const attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
+ int32 const victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
+ int32 const skillDiff = victimMaxSkillValueForLevel - attackerWeaponSkill;
- if (GetTypeId() == TYPEID_PLAYER)
- return GetFloatValue(PLAYER_DODGE_PERCENTAGE);
+ float chance = 0.0f;
+ float skillBonus = 0.0f;
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ {
+ chance = victim->GetFloatValue(PLAYER_DODGE_PERCENTAGE);
+ skillBonus = 0.04f * skillDiff;
+ }
else
{
- if (IsTotem())
- return 0.0f;
- else
+ if (!victim->IsTotem())
{
- float dodge = 5.0f;
- dodge += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
- return dodge > 0.0f ? dodge : 0.0f;
+ chance = 5.0f;
+ chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
+
+ if (skillDiff <= 10)
+ skillBonus = skillDiff * 0.1f;
+ else
+ skillBonus = 1.0f + (skillDiff - 10) * 0.1f;
}
}
+
+ chance += skillBonus;
+
+ // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
+ chance += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE);
+
+ // reduce dodge by SPELL_AURA_MOD_ENEMY_DODGE
+ chance += GetTotalAuraModifier(SPELL_AURA_MOD_ENEMY_DODGE);
+
+ // Reduce dodge chance by attacker expertise rating
+ if (GetTypeId() == TYPEID_PLAYER)
+ chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType);
+ else
+ chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) / 4.0f;
+ return std::max(chance, 0.0f);
}
-float Unit::GetUnitParryChance() const
+float Unit::GetUnitParryChance(WeaponAttackType attType, Unit const* victim) const
{
- if (IsNonMeleeSpellCast(false) || HasUnitState(UNIT_STATE_CONTROLLED))
- return 0.0f;
+ int32 const attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
+ int32 const victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
+ int32 const skillDiff = victimMaxSkillValueForLevel - attackerWeaponSkill;
float chance = 0.0f;
-
- if (Player const* player = ToPlayer())
+ float skillBonus = 0.0f;
+ if (Player const* playerVictim = victim->ToPlayer())
{
- if (player->CanParry())
+ if (playerVictim->CanParry())
{
- Item* tmpitem = player->GetWeaponForAttack(BASE_ATTACK, true);
+ Item* tmpitem = playerVictim->GetWeaponForAttack(BASE_ATTACK, true);
if (!tmpitem)
- tmpitem = player->GetWeaponForAttack(OFF_ATTACK, true);
+ tmpitem = playerVictim->GetWeaponForAttack(OFF_ATTACK, true);
if (tmpitem)
- chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE);
+ chance = playerVictim->GetFloatValue(PLAYER_PARRY_PERCENTAGE);
+
+ skillBonus = 0.04f * skillDiff;
}
}
- else if (GetTypeId() == TYPEID_UNIT)
+ else
{
- if (GetCreatureType() == CREATURE_TYPE_HUMANOID)
+ if (!victim->IsTotem() && !(victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY))
{
chance = 5.0f;
- chance += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
+ chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
+
+ if (skillDiff <= 10)
+ skillBonus = skillDiff * 0.1f;
+ else
+ skillBonus = 1.0f + (skillDiff - 10) * 1.6f;
}
}
- return chance > 0.0f ? chance : 0.0f;
+ chance += skillBonus;
+
+ // Reduce parry chance by attacker expertise rating
+ if (GetTypeId() == TYPEID_PLAYER)
+ chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType);
+ else
+ chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) / 4.0f;
+ return std::max(chance, 0.0f);
}
float Unit::GetUnitMissChance(WeaponAttackType attType) const
@@ -2771,7 +2854,7 @@ float Unit::GetUnitMissChance(WeaponAttackType attType) const
float miss_chance = 5.00f;
if (Player const* player = ToPlayer())
- miss_chance += player->GetMissPercentageFromDefence();
+ miss_chance += player->GetMissPercentageFromDefense();
if (attType == RANGED_ATTACK)
miss_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
@@ -2781,70 +2864,86 @@ float Unit::GetUnitMissChance(WeaponAttackType attType) const
return miss_chance;
}
-float Unit::GetUnitBlockChance() const
+float Unit::GetUnitBlockChance(WeaponAttackType attType, Unit const* victim) const
{
- if (IsNonMeleeSpellCast(false) || HasUnitState(UNIT_STATE_CONTROLLED))
- return 0.0f;
+ int32 const attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
+ int32 const victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
+ int32 const skillDiff = victimMaxSkillValueForLevel - attackerWeaponSkill;
- if (Player const* player = ToPlayer())
+ float chance = 0.0f;
+ float skillBonus = 0.0f;
+ if (Player const* playerVictim = victim->ToPlayer())
{
- if (player->CanBlock())
+ if (playerVictim->CanBlock())
{
- Item* tmpitem = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
+ Item* tmpitem = playerVictim->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
if (tmpitem && !tmpitem->IsBroken() && tmpitem->GetTemplate()->Block)
- return GetFloatValue(PLAYER_BLOCK_PERCENTAGE);
+ {
+ chance = playerVictim->GetFloatValue(PLAYER_BLOCK_PERCENTAGE);
+ skillBonus = 0.04f * skillDiff;
+ }
}
- // is player but has no block ability or no not broken shield equipped
- return 0.0f;
}
else
{
- if (IsTotem())
- return 0.0f;
- else
+ if (!victim->IsTotem() && !(victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK))
{
- float block = 5.0f;
- block += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT);
- return block > 0.0f ? block : 0.0f;
+ chance = 5.0f;
+ chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT);
+
+ if (skillDiff <= 10)
+ skillBonus = skillDiff * 0.1f;
+ else
+ skillBonus = 1.0f + (skillDiff - 10) * 0.1f;
}
}
+
+ chance += skillBonus;
+ return std::max(chance, 0.0f);
}
-float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit* victim) const
+float Unit::GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victim) const
{
- float crit;
+ int32 const attackerWeaponSkill = GetWeaponSkillValue(attackType, victim);
+ int32 const victimDefenseSkill = victim->GetDefenseSkillValue(this);
+ int32 const skillDiff = victimDefenseSkill - attackerWeaponSkill;
+ float chance = 0.0f;
+ float skillBonus = 0.0f;
if (GetTypeId() == TYPEID_PLAYER)
{
switch (attackType)
{
case BASE_ATTACK:
- crit = GetFloatValue(PLAYER_CRIT_PERCENTAGE);
+ chance = GetFloatValue(PLAYER_CRIT_PERCENTAGE);
break;
case OFF_ATTACK:
- crit = GetFloatValue(PLAYER_OFFHAND_CRIT_PERCENTAGE);
+ chance = GetFloatValue(PLAYER_OFFHAND_CRIT_PERCENTAGE);
break;
case RANGED_ATTACK:
- crit = GetFloatValue(PLAYER_RANGED_CRIT_PERCENTAGE);
+ chance = GetFloatValue(PLAYER_RANGED_CRIT_PERCENTAGE);
break;
// Just for good manner
default:
- crit = 0.0f;
+ chance = 0.0f;
break;
}
}
else
{
- crit = 5.0f;
- crit += GetTotalAuraModifier(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT);
- crit += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PCT);
+ if (!(ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRIT))
+ {
+ chance = 5.0f;
+ chance += GetTotalAuraModifier(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT);
+ chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PCT);
+ }
}
// flat aura mods
if (attackType == RANGED_ATTACK)
- crit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE);
+ chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE);
else
- crit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE);
+ chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE);
AuraEffectList const& critChanceForCaster = victim->GetAuraEffectsByType(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER);
for (AuraEffect const* aurEff : critChanceForCaster)
@@ -2852,31 +2951,32 @@ float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit* victi
if (aurEff->GetCasterGUID() != GetGUID())
continue;
- crit += aurEff->GetAmount();
+ chance += aurEff->GetAmount();
}
- crit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
+ chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
// reduce crit chance from Rating for players
if (attackType != RANGED_ATTACK)
- {
- ApplyResilience(victim, &crit, NULL, false, CR_CRIT_TAKEN_MELEE);
- // Glyph of barkskin
- if (victim->HasAura(63057) && victim->HasAura(22812))
- crit -= 25.0f;
- }
+ ApplyResilience(victim, &chance, nullptr, false, CR_CRIT_TAKEN_MELEE);
else
- ApplyResilience(victim, &crit, NULL, false, CR_CRIT_TAKEN_RANGED);
+ ApplyResilience(victim, &chance, nullptr, false, CR_CRIT_TAKEN_RANGED);
- // Apply crit chance from defence skill
- crit += (int32(GetMaxSkillValueForLevel(victim)) - int32(victim->GetDefenseSkillValue(this))) * 0.04f;
+ // Apply crit chance from defense skill
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ skillBonus = -skillDiff * 0.04f;
+ else
+ {
+ skillBonus = -skillDiff * 0.12f;
+ if (skillDiff >= 15)
+ skillBonus -= 3.0f;
+ }
- if (crit < 0.0f)
- crit = 0.0f;
- return crit;
+ chance += skillBonus;
+ return std::max(chance, 0.0f);
}
-uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target) const
+uint32 Unit::GetWeaponSkillValue(WeaponAttackType attType, Unit const* target) const
{
uint32 value = 0;
if (Player const* player = ToPlayer())
@@ -2903,15 +3003,22 @@ uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target)
value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL));
switch (attType)
{
- case BASE_ATTACK: value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND)); break;
- case OFF_ATTACK: value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND)); break;
- case RANGED_ATTACK: value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED)); break;
- default: break;
+ case BASE_ATTACK:
+ value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND));
+ break;
+ case OFF_ATTACK:
+ value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND));
+ break;
+ case RANGED_ATTACK:
+ value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED));
+ break;
+ default:
+ break;
}
}
else
value = GetUnitMeleeSkill(target);
- return value;
+ return value;
}
void Unit::_DeleteRemovedAuras()
@@ -3193,10 +3300,13 @@ int32 Unit::GetCurrentSpellCastTime(uint32 spell_id) const
bool Unit::CanMoveDuringChannel() const
{
if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
- if (spell->getState() != SPELL_STATE_FINISHED)
- return spell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING) && spell->IsChannelActive();
+ {
+ if (spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive())
+ if (!spell->GetSpellInfo()->IsMoveAllowedChannel())
+ return false;
+ }
- return false;
+ return true;
}
bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
@@ -3277,7 +3387,7 @@ void Unit::DeMorph()
SetDisplayId(GetNativeDisplayId());
}
-Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, ObjectGuid casterGUID /*= 0*/)
+Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, bool resetPeriodicTimer /*= true*/)
{
ASSERT(casterGUID || caster);
@@ -3300,7 +3410,7 @@ Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8
// extremely rare case
// let's just recreate aura
if (effMask != foundAura->GetEffectMask())
- return NULL;
+ return nullptr;
// update basepoints with new values - effect amount will be recalculated in ModStackAmount
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
@@ -3326,12 +3436,12 @@ Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8
}
// try to increase stack amount
- foundAura->ModStackAmount(1);
+ foundAura->ModStackAmount(1, AURA_REMOVE_BY_DEFAULT, resetPeriodicTimer);
return foundAura;
}
}
- return NULL;
+ return nullptr;
}
void Unit::_AddAura(UnitAura* aura, Unit* caster)
@@ -3939,7 +4049,7 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, U
if (aura->IsSingleTarget())
aura->UnregisterSingleTarget();
- if (Aura* newAura = Aura::TryRefreshStackOrCreate(aura->GetSpellInfo(), effMask, stealer, NULL, &baseDamage[0], NULL, aura->GetCasterGUID()))
+ if (Aura* newAura = Aura::TryRefreshStackOrCreate(aura->GetSpellInfo(), effMask, stealer, nullptr, &baseDamage[0], nullptr, aura->GetCasterGUID()))
{
// created aura must not be single target aura,, so stealer won't loose it on recast
if (newAura->IsSingleTarget())
@@ -4182,17 +4292,13 @@ void Unit::RemoveArenaAuras()
{
// in join, remove positive buffs, on end, remove negative
// used to remove positive visible auras in arenas
- for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
+ RemoveAppliedAuras([](AuraApplication const* aurApp)
{
- AuraApplication const* aurApp = iter->second;
Aura const* aura = aurApp->GetBase();
- if (!aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_UNK21) // don't remove stances, shadowform, pally/hunter auras
- && !aura->IsPassive() // don't remove passive auras
- && (aurApp->IsPositive() || !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR3_DEATH_PERSISTENT))) // not negative death persistent auras
- RemoveAura(iter);
- else
- ++iter;
- }
+ return !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_UNK21) // don't remove stances, shadowform, pally/hunter auras
+ && !aura->IsPassive() // don't remove passive auras
+ && (aurApp->IsPositive() || !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR3_DEATH_PERSISTENT)); // not negative death persistent auras
+ });
}
void Unit::RemoveAurasOnEvade()
@@ -4469,8 +4575,8 @@ void Unit::GetDispellableAuraList(Unit* caster, uint32 dispelMask, DispelCharges
// The charges / stack amounts don't count towards the total number of auras that can be dispelled.
// Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
// Polymorph instead of 1 / (5 + 1) -> 16%.
- bool dispel_charges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
- uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount();
+ bool dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
+ uint8 charges = dispelCharges ? aura->GetCharges() : aura->GetStackAmount();
if (charges > 0)
dispelList.push_back(std::make_pair(aura, charges));
}
@@ -5140,15 +5246,16 @@ void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 SpellID, uint32 Damag
SendSpellNonMeleeDamageLog(&log);
}
-void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpell, SpellInfo const* procAura)
+void Unit::ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
{
- // Not much to do if no flags are set.
- if (procAttacker)
- ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpell, amount, procAura);
- // Now go on with a victim's events'n'auras
- // Not much to do if no flags are set or there is no victim
- if (victim && victim->IsAlive() && procVictim)
- victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpell, amount, procAura);
+ WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK;
+ if (typeMaskActor)
+ ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType);
+
+ if (typeMaskActionTarget && actionTarget)
+ actionTarget->ProcSkillsAndReactives(true, this, typeMaskActionTarget, hitMask, attType);
+
+ TriggerAurasProcOnEvent(actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
}
void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo)
@@ -5235,8 +5342,8 @@ void Unit::SendAttackStateUpdate(CalcDamageInfo* damageInfo)
{
TC_LOG_DEBUG("entities.unit", "WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
- uint32 count = 1;
- size_t maxsize = 4+5+5+4+4+1+4+4+4+4+4+1+4+4+4+4+4*12;
+ uint32 const count = 1;
+ size_t const maxsize = 4+5+5+4+4+1+4+4+4+4+4+1+4+4+4+4+4*12;
WorldPacket data(SMSG_ATTACKERSTATEUPDATE, maxsize); // we guess size
data << uint32(damageInfo->HitInfo);
data << damageInfo->attacker->GetPackGUID();
@@ -5310,2970 +5417,6 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType
SendAttackStateUpdate(&dmgInfo);
}
-//victim may be NULL
-bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, Milliseconds& cooldown)
-{
- SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo();
- uint32 effIndex = triggeredByAura->GetEffIndex();
- int32 triggerAmount = triggeredByAura->GetAmount();
-
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
-
- uint32 triggered_spell_id = 0;
- Unit* target = victim;
- int32 basepoints0 = 0;
- ObjectGuid originalCaster;
-
- switch (dummySpell->SpellFamilyName)
- {
- case SPELLFAMILY_GENERIC:
- {
- switch (dummySpell->Id)
- {
- // Unstable Power
- case 24658:
- {
- if (!procSpell || procSpell->Id == 24659)
- return false;
- // Need remove one 24659 aura
- RemoveAuraFromStack(24659);
- return true;
- }
- // Restless Strength
- case 24661:
- {
- // Need remove one 24662 aura
- RemoveAuraFromStack(24662);
- return true;
- }
- // Mark of Malice
- case 33493:
- {
- // Cast finish spell at last charge
- if (triggeredByAura->GetBase()->GetCharges() > 1)
- return false;
-
- target = this;
- triggered_spell_id = 33494;
- break;
- }
- // Twisted Reflection (boss spell)
- case 21063:
- triggered_spell_id = 21064;
- break;
- // Vampiric Aura (boss spell)
- case 38196:
- {
- basepoints0 = 3 * damage; // 300%
- if (basepoints0 < 0)
- return false;
-
- triggered_spell_id = 31285;
- target = this;
- break;
- }
- // Aura of Madness (Darkmoon Card: Madness trinket)
- //=====================================================
- // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior)
- // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid)
- // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid)
- // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin)
- // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes)
- // 41005 Manic: +35 haste (spell, melee and ranged) (All classes)
- // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
- // 41011 Martyr Complex: +35 stamina (All classes)
- // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
- // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
- case 39446:
- {
- if (GetTypeId() != TYPEID_PLAYER || !IsAlive())
- return false;
-
- // Select class defined buff
- switch (getClass())
- {
- case CLASS_PALADIN: // 39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409
- case CLASS_DRUID: // 39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409
- triggered_spell_id = RAND(39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409);
- break;
- case CLASS_ROGUE: // 39511, 40997, 40998, 41002, 41005, 41011
- case CLASS_WARRIOR: // 39511, 40997, 40998, 41002, 41005, 41011
- case CLASS_DEATH_KNIGHT:
- triggered_spell_id = RAND(39511, 40997, 40998, 41002, 41005, 41011);
- break;
- case CLASS_PRIEST: // 40999, 41002, 41005, 41009, 41011, 41406, 41409
- case CLASS_SHAMAN: // 40999, 41002, 41005, 41009, 41011, 41406, 41409
- case CLASS_MAGE: // 40999, 41002, 41005, 41009, 41011, 41406, 41409
- case CLASS_WARLOCK: // 40999, 41002, 41005, 41009, 41011, 41406, 41409
- triggered_spell_id = RAND(40999, 41002, 41005, 41009, 41011, 41406, 41409);
- break;
- case CLASS_HUNTER: // 40997, 40999, 41002, 41005, 41009, 41011, 41406, 41409
- triggered_spell_id = RAND(40997, 40999, 41002, 41005, 41009, 41011, 41406, 41409);
- break;
- default:
- return false;
- }
-
- target = this;
- if (roll_chance_i(10))
- ToPlayer()->Say("This is Madness!", LANG_UNIVERSAL); /// @todo It should be moved to database, shouldn't it?
- break;
- }
- // Sunwell Exalted Caster Neck (??? neck)
- // cast ??? Light's Wrath if Exalted by Aldor
- // cast ??? Arcane Bolt if Exalted by Scryers
- case 46569:
- return false; // old unused version
- // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
- // cast 45479 Light's Wrath if Exalted by Aldor
- // cast 45429 Arcane Bolt if Exalted by Scryers
- case 45481:
- {
- Player* player = ToPlayer();
- if (!player)
- return false;
-
- // Get Aldor reputation rank
- if (player->GetReputationRank(932) == REP_EXALTED)
- {
- target = this;
- triggered_spell_id = 45479;
- break;
- }
- // Get Scryers reputation rank
- if (player->GetReputationRank(934) == REP_EXALTED)
- {
- // triggered at positive/self casts also, current attack target used then
- if (target && IsFriendlyTo(target))
- {
- target = GetVictim();
- if (!target)
- {
- target = player->GetSelectedUnit();
- if (!target)
- return false;
- }
- if (IsFriendlyTo(target))
- return false;
- }
-
- triggered_spell_id = 45429;
- break;
- }
- return false;
- }
- // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck)
- // cast 45480 Light's Strength if Exalted by Aldor
- // cast 45428 Arcane Strike if Exalted by Scryers
- case 45482:
- {
- if (GetTypeId() != TYPEID_PLAYER)
- return false;
-
- // Get Aldor reputation rank
- if (ToPlayer()->GetReputationRank(932) == REP_EXALTED)
- {
- target = this;
- triggered_spell_id = 45480;
- break;
- }
- // Get Scryers reputation rank
- if (ToPlayer()->GetReputationRank(934) == REP_EXALTED)
- {
- triggered_spell_id = 45428;
- break;
- }
- return false;
- }
- // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck)
- // cast 45431 Arcane Insight if Exalted by Aldor
- // cast 45432 Light's Ward if Exalted by Scryers
- case 45483:
- {
- if (GetTypeId() != TYPEID_PLAYER)
- return false;
-
- // Get Aldor reputation rank
- if (ToPlayer()->GetReputationRank(932) == REP_EXALTED)
- {
- target = this;
- triggered_spell_id = 45432;
- break;
- }
- // Get Scryers reputation rank
- if (ToPlayer()->GetReputationRank(934) == REP_EXALTED)
- {
- target = this;
- triggered_spell_id = 45431;
- break;
- }
- return false;
- }
- // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck)
- // cast 45478 Light's Salvation if Exalted by Aldor
- // cast 45430 Arcane Surge if Exalted by Scryers
- case 45484:
- {
- if (GetTypeId() != TYPEID_PLAYER)
- return false;
-
- // Get Aldor reputation rank
- if (ToPlayer()->GetReputationRank(932) == REP_EXALTED)
- {
- target = this;
- triggered_spell_id = 45478;
- break;
- }
- // Get Scryers reputation rank
- if (ToPlayer()->GetReputationRank(934) == REP_EXALTED)
- {
- triggered_spell_id = 45430;
- break;
- }
- return false;
- }
- // Kill command
- case 58914:
- {
- // Remove aura stack from pet
- RemoveAuraFromStack(58914);
- Unit* owner = GetOwner();
- if (!owner)
- return true;
- // reduce the owner's aura stack
- owner->RemoveAuraFromStack(34027);
- return true;
- }
- // Vampiric Touch (generic, used by some boss)
- case 52723:
- case 60501:
- {
- triggered_spell_id = 52724;
- basepoints0 = damage / 2;
- target = this;
- break;
- }
- // Shadowfiend Death (Gain mana if pet dies with Glyph of Shadowfiend)
- case 57989:
- {
- Unit* owner = GetOwner();
- if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
- return false;
- // Glyph of Shadowfiend (need cast as self cast for owner, no hidden cooldown)
- owner->CastSpell(owner, 58227, true, castItem, triggeredByAura);
- return true;
- }
- // Divine purpose
- case 31871:
- case 31872:
- {
- // Roll chane
- if (!victim || !victim->IsAlive() || !roll_chance_i(triggerAmount))
- return false;
-
- // Remove any stun effect on target
- victim->RemoveAurasWithMechanic(1<<MECHANIC_STUN, AURA_REMOVE_BY_ENEMY_SPELL);
- return true;
- }
- // Glyph of Scourge Strike
- case 58642:
- {
- triggered_spell_id = 69961; // Glyph of Scourge Strike
- break;
- }
- // Glyph of Life Tap
- case 63320:
- {
- triggered_spell_id = 63321; // Life Tap
- break;
- }
- // Purified Shard of the Scale - Onyxia 10 Caster Trinket
- case 69755:
- {
- triggered_spell_id = (procFlag & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS) ? 69733 : 69729;
- break;
- }
- // Shiny Shard of the Scale - Onyxia 25 Caster Trinket
- case 69739:
- {
- triggered_spell_id = (procFlag & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS) ? 69734 : 69730;
- break;
- }
- case 71519: // Deathbringer's Will Normal
- {
- if (GetTypeId() != TYPEID_PLAYER)
- return false;
-
- std::vector<uint32> RandomSpells;
- switch (getClass())
- {
- case CLASS_WARRIOR:
- case CLASS_PALADIN:
- case CLASS_DEATH_KNIGHT:
- RandomSpells.push_back(71484);
- RandomSpells.push_back(71491);
- RandomSpells.push_back(71492);
- break;
- case CLASS_SHAMAN:
- case CLASS_ROGUE:
- RandomSpells.push_back(71486);
- RandomSpells.push_back(71485);
- RandomSpells.push_back(71492);
- break;
- case CLASS_DRUID:
- RandomSpells.push_back(71484);
- RandomSpells.push_back(71485);
- RandomSpells.push_back(71492);
- break;
- case CLASS_HUNTER:
- RandomSpells.push_back(71486);
- RandomSpells.push_back(71491);
- RandomSpells.push_back(71485);
- break;
- default:
- return false;
- }
- if (RandomSpells.empty()) // shouldn't happen
- return false;
-
- uint8 rand_spell = urand(0, (RandomSpells.size() - 1));
- CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster);
- break;
- }
- case 71562: // Deathbringer's Will Heroic
- {
- if (GetTypeId() != TYPEID_PLAYER)
- return false;
-
- std::vector<uint32> RandomSpells;
- switch (getClass())
- {
- case CLASS_WARRIOR:
- case CLASS_PALADIN:
- case CLASS_DEATH_KNIGHT:
- RandomSpells.push_back(71561);
- RandomSpells.push_back(71559);
- RandomSpells.push_back(71560);
- break;
- case CLASS_SHAMAN:
- case CLASS_ROGUE:
- RandomSpells.push_back(71558);
- RandomSpells.push_back(71556);
- RandomSpells.push_back(71560);
- break;
- case CLASS_DRUID:
- RandomSpells.push_back(71561);
- RandomSpells.push_back(71556);
- RandomSpells.push_back(71560);
- break;
- case CLASS_HUNTER:
- RandomSpells.push_back(71558);
- RandomSpells.push_back(71559);
- RandomSpells.push_back(71556);
- break;
- default:
- return false;
- }
- if (RandomSpells.empty()) // shouldn't happen
- return false;
-
- uint8 rand_spell = urand(0, (RandomSpells.size() - 1));
- CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster);
- break;
- }
- case 65032: // Boom aura (321 Boombot)
- {
- if (victim->GetEntry() != 33343) // Scrapbot
- return false;
-
- InstanceScript* instance = GetInstanceScript();
- if (!instance)
- return false;
-
- instance->DoCastSpellOnPlayers(65037); // Achievement criteria marker
- break;
- }
- }
- break;
- }
- case SPELLFAMILY_MAGE:
- {
- // Magic Absorption
- if (dummySpell->SpellIconID == 459) // only this spell has SpellIconID == 459 and dummy aura
- {
- if (getPowerType() != POWER_MANA)
- return false;
-
- // mana reward
- basepoints0 = CalculatePct(int32(GetMaxPower(POWER_MANA)), triggerAmount);
- target = this;
- triggered_spell_id = 29442;
- break;
- }
- // Arcane Potency
- if (dummySpell->SpellIconID == 2120)
- {
- if (!procSpell)
- return false;
-
- target = this;
- switch (dummySpell->Id)
- {
- case 31571: triggered_spell_id = 57529; break;
- case 31572: triggered_spell_id = 57531; break;
- default:
- TC_LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non handled spell id: %u", dummySpell->Id);
- return false;
- }
- break;
- }
- // Hot Streak
- if (dummySpell->SpellIconID == 2999)
- {
- if (effIndex != 0)
- return false;
- AuraEffect* counter = triggeredByAura->GetBase()->GetEffect(EFFECT_1);
- if (!counter)
- return true;
-
- // Count spell criticals in a row in second aura
- if (procEx & PROC_EX_CRITICAL_HIT)
- {
- counter->SetAmount(counter->GetAmount() * 2);
- if (counter->GetAmount() < 100) // not enough
- return true;
- // Crititcal counted -> roll chance
- if (roll_chance_i(triggerAmount))
- CastSpell(this, 48108, true, castItem, triggeredByAura);
- }
- counter->SetAmount(25);
- return true;
- }
- // Incanter's Regalia set (add trigger chance to Mana Shield)
- if (dummySpell->SpellFamilyFlags[0] & 0x8000)
- {
- if (GetTypeId() != TYPEID_PLAYER)
- return false;
-
- target = this;
- triggered_spell_id = 37436;
- break;
- }
- switch (dummySpell->Id)
- {
- // Glyph of Polymorph
- case 56375:
- {
- if (!target)
- return false;
- target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, ObjectGuid::Empty, target->GetAura(32409)); // SW:D shall not be removed.
- target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
- target->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
- return true;
- }
- // Glyph of Icy Veins
- case 56374:
- {
- RemoveAurasByType(SPELL_AURA_HASTE_SPELLS, ObjectGuid::Empty, 0, true, false);
- RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
- return true;
- }
- // Glyph of Ice Block
- case 56372:
- {
- if (GetTypeId() != TYPEID_PLAYER)
- return false;
-
- GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
- {
- SpellInfo const* cdSpell = sSpellMgr->GetSpellInfo(itr->first);
- if (!cdSpell || cdSpell->SpellFamilyName != SPELLFAMILY_MAGE
- || !(cdSpell->SpellFamilyFlags[0] & 0x00000040))
- return false;
- return true;
- }, true);
- break;
- }
- case 47020: // Enter vehicle XT-002 (Scrapbot)
- {
- if (GetTypeId() != TYPEID_UNIT)
- return false;
-
- Unit* vehicleBase = GetVehicleBase();
- if (!vehicleBase)
- return false;
-
- /// @todo Check if this amount is blizzlike
- vehicleBase->ModifyHealth(int32(vehicleBase->CountPctFromMaxHealth(1)));
- break;
- }
- }
- break;
- }
- case SPELLFAMILY_WARRIOR:
- {
- switch (dummySpell->Id)
- {
- // Victorious
- case 32216:
- {
- RemoveAura(dummySpell->Id);
- return false;
- }
- // Improved Spell Reflection
- case 59088:
- case 59089:
- {
- triggered_spell_id = 59725;
- target = this;
- break;
- }
- }
- // Second Wind
- if (dummySpell->SpellIconID == 1697)
- {
- // only for spells and hit/crit (trigger start always) and not start from self cast spells (5530 Mace Stun Effect for example)
- if (!procSpell || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == victim)
- return false;
- // Need stun or root mechanic
- if (!(procSpell->GetAllEffectsMechanicMask() & ((1<<MECHANIC_ROOT)|(1<<MECHANIC_STUN))))
- return false;
-
- switch (dummySpell->Id)
- {
- case 29838: triggered_spell_id=29842; break;
- case 29834: triggered_spell_id=29841; break;
- case 42770: triggered_spell_id=42771; break;
- default:
- TC_LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non handled spell id: %u (SW)", dummySpell->Id);
- return false;
- }
-
- target = this;
- break;
- }
- // Glyph of Blocking
- if (dummySpell->Id == 58375)
- {
- triggered_spell_id = 58374;
- break;
- }
- break;
- }
- case SPELLFAMILY_WARLOCK:
- {
- // Seed of Corruption
- if (dummySpell->SpellFamilyFlags[1] & 0x00000010)
- {
- if (procSpell && procSpell->SpellFamilyFlags[1] & 0x8000)
- return false;
- // if damage is more than need or target die from damage deal finish spell
- if (triggeredByAura->GetAmount() <= int32(damage) || GetHealth() <= damage)
- {
- // remember caster before aura delete
- Unit* caster = triggeredByAura->GetCaster();
-
- // Remove aura (before cast for prevent infinite loop handlers)
- RemoveAurasDueToSpell(triggeredByAura->GetId());
-
- uint32 spell = sSpellMgr->GetSpellWithRank(27285, dummySpell->GetRank());
-
- // Cast finish spell (triggeredByAura already not exist!)
- if (caster)
- caster->CastSpell(this, spell, true, castItem);
- return true; // no hidden cooldown
- }
-
- // Damage counting
- triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage);
- return true;
- }
- // Seed of Corruption (Mobs cast) - no die req
- if (dummySpell->SpellFamilyFlags.IsEqual(0, 0, 0) && dummySpell->SpellIconID == 1932)
- {
- // if damage is more than need deal finish spell
- if (triggeredByAura->GetAmount() <= int32(damage))
- {
- // remember caster before aura delete
- Unit* caster = triggeredByAura->GetCaster();
-
- // Remove aura (before cast for prevent infinite loop handlers)
- RemoveAurasDueToSpell(triggeredByAura->GetId());
-
- // Cast finish spell (triggeredByAura already not exist!)
- if (caster)
- caster->CastSpell(this, 32865, true, castItem);
- return true; // no hidden cooldown
- }
- // Damage counting
- triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage);
- return true;
- }
- switch (dummySpell->Id)
- {
- // Nightfall
- case 18094:
- case 18095:
- // Glyph of corruption
- case 56218:
- {
- target = this;
- triggered_spell_id = 17941;
- break;
- }
- // Soul Leech
- case 30293:
- case 30295:
- case 30296:
- {
- // Improved Soul Leech
- AuraEffectList const& SoulLeechAuras = GetAuraEffectsByType(SPELL_AURA_DUMMY);
- for (Unit::AuraEffectList::const_iterator i = SoulLeechAuras.begin(); i != SoulLeechAuras.end(); ++i)
- {
- if ((*i)->GetId() == 54117 || (*i)->GetId() == 54118)
- {
- if ((*i)->GetEffIndex() != 0)
- continue;
- basepoints0 = int32((*i)->GetAmount());
- target = GetGuardianPet();
- if (target)
- {
- // regen mana for pet
- CastCustomSpell(target, 54607, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- }
- // regen mana for caster
- CastCustomSpell(this, 59117, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- // Get second aura of spell for replenishment effect on party
- if (AuraEffect const* aurEff = (*i)->GetBase()->GetEffect(EFFECT_1))
- {
- // Replenishment - roll chance
- if (roll_chance_i(aurEff->GetAmount()))
- CastSpell(this, 57669, true, castItem, triggeredByAura);
- }
- break;
- }
- }
- // health
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- target = this;
- triggered_spell_id = 30294;
- break;
- }
- // Shadowflame (Voidheart Raiment set bonus)
- case 37377:
- {
- triggered_spell_id = 37379;
- break;
- }
- // Pet Healing (Corruptor Raiment or Rift Stalker Armor)
- case 37381:
- {
- target = GetGuardianPet();
- if (!target)
- return false;
-
- // heal amount
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- triggered_spell_id = 37382;
- break;
- }
- // Shadowflame Hellfire (Voidheart Raiment set bonus)
- case 39437:
- {
- triggered_spell_id = 37378;
- break;
- }
- // Glyph of Succubus
- case 56250:
- {
- if (!target)
- return false;
- target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, ObjectGuid::Empty, target->GetAura(32409)); // SW:D shall not be removed.
- target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
- target->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
- return true;
- }
- }
- break;
- }
- case SPELLFAMILY_PRIEST:
- {
- // Vampiric Touch
- if (dummySpell->SpellFamilyFlags[1] & 0x00000400)
- {
- if (!victim || !victim->IsAlive())
- return false;
-
- if (effIndex != 0)
- return false;
-
- // victim is caster of aura
- if (triggeredByAura->GetCasterGUID() != victim->GetGUID())
- return false;
-
- // Energize 0.25% of max. mana
- victim->CastSpell(victim, 57669, true, castItem, triggeredByAura);
- return true; // no hidden cooldown
- }
- // Body and Soul
- if (dummySpell->SpellIconID == 2218)
- {
- // Proc only from Abolish desease on self cast
- if (!procSpell || procSpell->Id != 552 || victim != this || !roll_chance_i(triggerAmount))
- return false;
- triggered_spell_id = 64136;
- target = this;
- break;
- }
- switch (dummySpell->Id)
- {
- // Vampiric Embrace
- case 15286:
- {
- if (!victim || !victim->IsAlive() || !procSpell || procSpell->SpellFamilyFlags[1] & 0x80000)
- return false;
-
- // heal amount
- int32 total = CalculatePct(int32(damage), triggerAmount);
- int32 team = total / 5;
- int32 self = total - team;
- CastCustomSpell(this, 15290, &team, &self, NULL, true, castItem, triggeredByAura);
- return true; // no hidden cooldown
- }
- // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
- case 40438:
- {
- // Shadow Word: Pain
- if (!procSpell)
- return false;
- else if (procSpell->SpellFamilyFlags[0] & 0x8000)
- triggered_spell_id = 40441;
- // Renew
- else if (procSpell->SpellFamilyFlags[0] & 0x40)
- triggered_spell_id = 40440;
- else
- return false;
-
- target = this;
- break;
- }
- // Improved Shadowform
- case 47570:
- case 47569:
- {
- if (!roll_chance_i(triggerAmount))
- return false;
-
- RemoveMovementImpairingAuras();
- break;
- }
- // Glyph of Dispel Magic
- case 55677:
- {
- // Dispel Magic shares spellfamilyflag with abolish disease
- if (!procSpell || procSpell->SpellIconID != 74)
- return false;
- if (!target || !target->IsFriendlyTo(this))
- return false;
-
- basepoints0 = int32(target->CountPctFromMaxHealth(triggerAmount));
- triggered_spell_id = 56131;
- break;
- }
- // Oracle Healing Bonus ("Garments of the Oracle" set)
- case 26169:
- {
- // heal amount
- basepoints0 = int32(CalculatePct(damage, 10));
- target = this;
- triggered_spell_id = 26170;
- break;
- }
- // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set
- case 39372:
- {
- if (!procSpell || (procSpell->GetSchoolMask() & (SPELL_SCHOOL_MASK_FROST | SPELL_SCHOOL_MASK_SHADOW)) == 0)
- return false;
-
- // heal amount
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- target = this;
- triggered_spell_id = 39373;
- break;
- }
- // Greater Heal (Vestments of Faith (Priest Tier 3) - 4 pieces bonus)
- case 28809:
- {
- triggered_spell_id = 28810;
- break;
- }
- // Priest T10 Healer 2P Bonus
- case 70770:
- // Flash Heal
- if (procSpell && procSpell->SpellFamilyFlags[0] & 0x800)
- {
- triggered_spell_id = 70772;
- SpellInfo const* blessHealing = sSpellMgr->GetSpellInfo(triggered_spell_id);
- if (!blessHealing)
- return false;
- basepoints0 = int32(CalculatePct(damage, triggerAmount) / (blessHealing->GetMaxDuration() / blessHealing->Effects[0].Amplitude));
- }
- break;
- }
- break;
- }
- case SPELLFAMILY_DRUID:
- {
- switch (dummySpell->Id)
- {
- // Glyph of Innervate
- case 54832:
- {
- if (!procSpell || procSpell->SpellIconID != 62)
- return false;
-
- int32 mana_perc = triggeredByAura->GetSpellInfo()->Effects[triggeredByAura->GetEffIndex()].CalcValue();
- basepoints0 = int32(CalculatePct(GetCreatePowers(POWER_MANA), mana_perc) / 10);
- triggered_spell_id = 54833;
- target = this;
- break;
- }
- // Glyph of Starfire
- case 54845:
- {
- triggered_spell_id = 54846;
- break;
- }
- // Glyph of Shred
- case 54815:
- {
- if (!target)
- return false;
-
- // try to find spell Rip on the target
- if (AuraEffect const* AurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00800000, 0x0, 0x0, GetGUID()))
- {
- // Rip's max duration, note: spells which modifies Rip's duration also counted like Glyph of Rip
- uint32 CountMin = AurEff->GetBase()->GetMaxDuration();
-
- // just Rip's max duration without other spells
- uint32 CountMax = AurEff->GetSpellInfo()->GetMaxDuration();
-
- // add possible auras' and Glyph of Shred's max duration
- CountMax += 3 * triggerAmount * IN_MILLISECONDS; // Glyph of Shred -> +6 seconds
- CountMax += HasAura(54818) ? 4 * IN_MILLISECONDS : 0; // Glyph of Rip -> +4 seconds
- CountMax += HasAura(60141) ? 4 * IN_MILLISECONDS : 0; // Rip Duration/Lacerate Damage -> +4 seconds
-
- // if min < max -> that means caster didn't cast 3 shred yet
- // so set Rip's duration and max duration
- if (CountMin < CountMax)
- {
- AurEff->GetBase()->SetDuration(AurEff->GetBase()->GetDuration() + triggerAmount * IN_MILLISECONDS);
- AurEff->GetBase()->SetMaxDuration(CountMin + triggerAmount * IN_MILLISECONDS);
- return true;
- }
- }
- // if not found Rip
- return false;
- }
- // Glyph of Rake
- case 54821:
- {
- if (procSpell && procSpell->SpellVisual[0] == 750 && procSpell->Effects[1].ApplyAuraName == 3)
- {
- if (target && target->GetTypeId() == TYPEID_UNIT)
- {
- triggered_spell_id = 54820;
- break;
- }
- }
- return false;
- }
- // Leader of the Pack
- case 24932:
- {
- if (triggerAmount <= 0)
- return false;
- basepoints0 = int32(CountPctFromMaxHealth(triggerAmount));
- target = this;
- triggered_spell_id = 34299;
- if (triggeredByAura->GetCasterGUID() != GetGUID())
- break;
- int32 basepoints1 = CalculatePct(GetMaxPower(Powers(POWER_MANA)), triggerAmount * 2);
- // Improved Leader of the Pack
- // Check cooldown of heal spell cooldown
- if (!GetSpellHistory()->HasCooldown(34299))
- CastCustomSpell(this, 68285, &basepoints1, 0, 0, true, 0, triggeredByAura);
- break;
- }
- // Healing Touch (Dreamwalker Raiment set)
- case 28719:
- {
- if (procSpell)
- {
- // mana back
- basepoints0 = int32(CalculatePct(procSpell->ManaCost, 30));
- target = this;
- triggered_spell_id = 28742;
- }
- break;
- }
- // Glyph of Rejuvenation
- case 54754:
- {
- if (!victim || !victim->HealthBelowPct(uint32(triggerAmount)))
- return false;
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- triggered_spell_id = 54755;
- break;
- }
- // Healing Touch Refund (Idol of Longevity trinket)
- case 28847:
- {
- target = this;
- triggered_spell_id = 28848;
- break;
- }
- // Mana Restore (Malorne Raiment set / Malorne Regalia set)
- case 37288:
- case 37295:
- {
- target = this;
- triggered_spell_id = 37238;
- break;
- }
- // Druid Tier 6 Trinket
- case 40442:
- {
- float chance;
-
- if (!procSpell)
- return false;
- // Starfire
- else if (procSpell->SpellFamilyFlags[0] & 0x4)
- {
- triggered_spell_id = 40445;
- chance = 25.0f;
- }
- // Rejuvenation
- else if (procSpell->SpellFamilyFlags[0] & 0x10)
- {
- triggered_spell_id = 40446;
- chance = 25.0f;
- }
- // Mangle (Bear) and Mangle (Cat)
- else if (procSpell->SpellFamilyFlags[1] & 0x00000440)
- {
- triggered_spell_id = 40452;
- chance = 40.0f;
- }
- else
- return false;
-
- if (!roll_chance_f(chance))
- return false;
-
- target = this;
- break;
- }
- // Maim Interrupt
- case 44835:
- {
- // Deadly Interrupt Effect
- triggered_spell_id = 32747;
- break;
- }
- // Item - Druid T10 Balance 4P Bonus
- case 70723:
- {
- // Wrath & Starfire
- if (procSpell && (procSpell->SpellFamilyFlags[0] & 0x5) && (procEx & PROC_EX_CRITICAL_HIT))
- {
- triggered_spell_id = 71023;
- SpellInfo const* triggeredSpell = sSpellMgr->GetSpellInfo(triggered_spell_id);
- if (!triggeredSpell)
- return false;
- basepoints0 = CalculatePct(int32(damage), triggerAmount) / (triggeredSpell->GetMaxDuration() / triggeredSpell->Effects[0].Amplitude);
- // Add remaining ticks to damage done
- basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
- }
- break;
- }
- // Item - Druid T10 Restoration 4P Bonus (Rejuvenation)
- case 70664:
- {
- // Proc only from normal Rejuvenation
- if (!procSpell || procSpell->SpellVisual[0] != 32)
- return false;
-
- Player* caster = ToPlayer();
- if (!caster)
- return false;
- if (!caster->GetGroup() && victim == this)
- return false;
-
- CastCustomSpell(70691, SPELLVALUE_BASE_POINT0, damage, victim, true);
- return true;
- }
- }
- break;
- }
- case SPELLFAMILY_ROGUE:
- {
- switch (dummySpell->Id)
- {
- case 56800: // Glyph of Backstab
- {
- triggered_spell_id = 63975;
- break;
- }
- case 32748: // Deadly Throw Interrupt
- {
- // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw
- if (this == victim)
- return false;
-
- triggered_spell_id = 32747;
- break;
- }
- }
-
- switch (dummySpell->SpellIconID)
- {
- case 2116: // Quick Recovery
- {
- if (!procSpell)
- return false;
-
- // energy cost save
- basepoints0 = CalculatePct(int32(procSpell->ManaCost), triggerAmount);
- if (basepoints0 <= 0)
- return false;
-
- target = this;
- triggered_spell_id = 31663;
- break;
- }
- case 2909: // Cut to the Chase
- {
- // "refresh your Slice and Dice duration to its 5 combo point maximum"
- // lookup Slice and Dice
- if (AuraEffect const* aur = GetAuraEffect(SPELL_AURA_MOD_MELEE_HASTE, SPELLFAMILY_ROGUE, 0x40000, 0, 0))
- {
- aur->GetBase()->SetDuration(aur->GetSpellInfo()->GetMaxDuration(), true);
- return true;
- }
- return false;
- }
- case 2963: // Deadly Brew
- {
- triggered_spell_id = 3409;
- break;
- }
- }
- break;
- }
- case SPELLFAMILY_HUNTER:
- {
- switch (dummySpell->SpellIconID)
- {
- case 2236: // Thrill of the Hunt
- {
- if (!procSpell)
- return false;
-
- Spell* spell = ToPlayer()->m_spellModTakingSpell;
-
- // Disable charge drop because of Lock and Load
- ToPlayer()->SetSpellModTakingSpell(spell, false);
-
- // Explosive Shot
- if (procSpell->SpellFamilyFlags[2] & 0x200)
- {
- if (!victim)
- return false;
- if (AuraEffect const* pEff = victim->GetAuraEffect(SPELL_AURA_PERIODIC_DUMMY, SPELLFAMILY_HUNTER, 0x0, 0x80000000, 0x0, GetGUID()))
- basepoints0 = pEff->GetSpellInfo()->CalcPowerCost(this, SpellSchoolMask(pEff->GetSpellInfo()->SchoolMask)) * 4/10/3;
- }
- else
- basepoints0 = procSpell->CalcPowerCost(this, SpellSchoolMask(procSpell->SchoolMask)) * 4/10;
-
- ToPlayer()->SetSpellModTakingSpell(spell, true);
-
- if (basepoints0 <= 0)
- return false;
-
- target = this;
- triggered_spell_id = 34720;
- break;
- }
- case 3406: // Hunting Party
- {
- triggered_spell_id = 57669;
- target = this;
- break;
- }
- case 3560: // Rapid Recuperation
- {
- // This effect only from Rapid Killing (mana regen)
- if (!procSpell || !(procSpell->SpellFamilyFlags[1] & 0x01000000))
- return false;
-
- target = this;
-
- switch (dummySpell->Id)
- {
- case 53228: // Rank 1
- triggered_spell_id = 56654;
- break;
- case 53232: // Rank 2
- triggered_spell_id = 58882;
- break;
- }
- break;
- }
- }
-
- switch (dummySpell->Id)
- {
- case 57870: // Glyph of Mend Pet
- {
- victim->CastSpell(victim, 57894, true, NULL, NULL, GetGUID());
- return true;
- }
- }
- break;
- }
- case SPELLFAMILY_PALADIN:
- {
- // Judgements of the Wise
- if (dummySpell->SpellIconID == 3017)
- {
- target = this;
- triggered_spell_id = 31930;
- // replenishment
- CastSpell(this, 57669, true, castItem, triggeredByAura);
- break;
- }
- // Righteous Vengeance
- if (dummySpell->SpellIconID == 3025)
- {
- // 4 damage tick
- basepoints0 = triggerAmount * damage / 400;
- triggered_spell_id = 61840;
- // Add remaining ticks to damage done
- basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
- break;
- }
- // Sheath of Light
- if (dummySpell->SpellIconID == 3030)
- {
- // 4 healing tick
- basepoints0 = triggerAmount * damage / 400;
- triggered_spell_id = 54203;
- // Add remaining ticks to healing done
- basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_HEAL);
- break;
- }
- switch (dummySpell->Id)
- {
- // Sacred Shield
- case 53601:
- {
- if (procFlag & PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS)
- return false;
-
- if (damage > 0)
- triggered_spell_id = 58597;
-
- // Item - Paladin T8 Holy 4P Bonus
- if (Unit* caster = triggeredByAura->GetCaster())
- if (AuraEffect const* aurEff = caster->GetAuraEffect(64895, 0))
- cooldown = Milliseconds(aurEff->GetAmount());
-
- target = this;
- break;
- }
- // Heart of the Crusader
- case 20335: // rank 1
- triggered_spell_id = 21183;
- break;
- case 20336: // rank 2
- triggered_spell_id = 54498;
- break;
- case 20337: // rank 3
- triggered_spell_id = 54499;
- break;
- // Judgement of Light
- case 20185:
- {
- if (!victim)
- return false;
-
- // 2% of maximum health
- basepoints0 = int32(victim->CountPctFromMaxHealth(2));
- victim->CastCustomSpell(victim, 20267, &basepoints0, 0, 0, true, 0, triggeredByAura);
- return true;
- }
- // Judgement of Wisdom
- case 20186:
- {
- if (victim && victim->IsAlive() && victim->getPowerType() == POWER_MANA)
- {
- // 2% of base mana
- basepoints0 = int32(CalculatePct(victim->GetCreateMana(), 2));
- victim->CastCustomSpell(victim, 20268, &basepoints0, NULL, NULL, true, 0, triggeredByAura);
- }
- return true;
- }
- // Holy Power (Redemption Armor set)
- case 28789:
- {
- if (!victim)
- return false;
-
- // Set class defined buff
- switch (victim->getClass())
- {
- case CLASS_PALADIN:
- case CLASS_PRIEST:
- case CLASS_SHAMAN:
- case CLASS_DRUID:
- triggered_spell_id = 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
- break;
- case CLASS_MAGE:
- case CLASS_WARLOCK:
- triggered_spell_id = 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
- break;
- case CLASS_HUNTER:
- case CLASS_ROGUE:
- triggered_spell_id = 28791; // Increases the friendly target's attack power by $s1 for $d.
- break;
- case CLASS_WARRIOR:
- triggered_spell_id = 28790; // Increases the friendly target's armor
- break;
- default:
- return false;
- }
- break;
- }
- // Seal of Vengeance (damage calc on apply aura)
- case 31801:
- {
- if (effIndex != 0) // effect 1, 2 used by seal unleashing code
- return false;
-
- // At melee attack or Hammer of the Righteous spell damage considered as melee attack
- bool stacker = procSpell ? procSpell->Id == 53595 : true;
- // spells with SPELL_DAMAGE_CLASS_MELEE excluding Judgements
- bool damager = procSpell ? (procSpell->EquippedItemClass != -1 || (procSpell->SpellIconID == 243 && procSpell->SpellVisual[0] == 39)) : false;
-
- if (!stacker && !damager)
- return false;
-
- triggered_spell_id = 31803;
-
- // On target with 5 stacks of Holy Vengeance direct damage is done
- if (Aura* aur = victim->GetAura(triggered_spell_id, GetGUID()))
- {
- if (aur->GetStackAmount() == 5)
- {
- if (stacker)
- aur->RefreshDuration();
- CastSpell(victim, 42463, true);
- return true;
- }
- }
-
- if (!stacker)
- return false;
- break;
- }
- // Seal of Corruption
- case 53736:
- {
- if (effIndex != 0) // effect 1, 2 used by seal unleashing code
- return false;
-
- // At melee attack or Hammer of the Righteous spell damage considered as melee attack
- bool stacker = procSpell ? procSpell->Id == 53595 : true;
- // spells with SPELL_DAMAGE_CLASS_MELEE excluding Judgements
- bool damager = procSpell ? (procSpell->EquippedItemClass != -1 || (procSpell->SpellIconID == 243 && procSpell->SpellVisual[0] == 39)) : false;
-
- if (!stacker && !damager)
- return false;
-
- triggered_spell_id = 53742;
-
- // On target with 5 stacks of Blood Corruption direct damage is done
- if (Aura* aur = victim->GetAura(triggered_spell_id, GetGUID()))
- {
- if (aur->GetStackAmount() == 5)
- {
- if (stacker)
- aur->RefreshDuration();
- CastSpell(victim, 53739, true);
- return true;
- }
- }
-
- if (!stacker)
- return false;
- break;
- }
- // Spiritual Attunement
- case 31785:
- case 33776:
- {
- // if healed by another unit (victim)
- if (this == victim)
- return false;
-
- // heal amount
- basepoints0 = int32(CalculatePct(std::min(damage, GetMaxHealth() - GetHealth()), triggerAmount));
- target = this;
-
- if (basepoints0)
- triggered_spell_id = 31786;
- break;
- }
- // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
- case 40470:
- {
- if (!procSpell)
- return false;
-
- float chance;
-
- // Flash of light/Holy light
- if (procSpell->SpellFamilyFlags[0] & 0xC0000000)
- {
- triggered_spell_id = 40471;
- chance = 15.0f;
- }
- // Judgement (any)
- else if (procSpell->GetSpellSpecific() == SPELL_SPECIFIC_JUDGEMENT)
- {
- triggered_spell_id = 40472;
- chance = 50.0f;
- }
- else
- return false;
-
- if (!roll_chance_f(chance))
- return false;
-
- break;
- }
- // Glyph of Holy Light
- case 54937:
- {
- triggered_spell_id = 54968;
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- break;
- }
- // Item - Paladin T8 Holy 2P Bonus
- case 64890:
- {
- triggered_spell_id = 64891;
- basepoints0 = triggerAmount * damage / 300;
- break;
- }
- case 71406: // Tiny Abomination in a Jar
- case 71545: // Tiny Abomination in a Jar (Heroic)
- {
- if (!victim || !victim->IsAlive())
- return false;
-
- CastSpell(this, 71432, true, NULL, triggeredByAura);
-
- Aura const* dummy = GetAura(71432);
- if (!dummy || dummy->GetStackAmount() < (dummySpell->Id == 71406 ? 8 : 7))
- return false;
-
- RemoveAurasDueToSpell(71432);
- triggered_spell_id = 71433; // default main hand attack
- // roll if offhand
- if (Player const* player = ToPlayer())
- if (player->GetWeaponForAttack(OFF_ATTACK, true) && urand(0, 1))
- triggered_spell_id = 71434;
- target = victim;
- break;
- }
- // Item - Icecrown 25 Normal Dagger Proc
- case 71880:
- {
- switch (getPowerType())
- {
- case POWER_MANA:
- triggered_spell_id = 71881;
- break;
- case POWER_RAGE:
- triggered_spell_id = 71883;
- break;
- case POWER_ENERGY:
- triggered_spell_id = 71882;
- break;
- case POWER_RUNIC_POWER:
- triggered_spell_id = 71884;
- break;
- default:
- return false;
- }
- break;
- }
- // Item - Icecrown 25 Heroic Dagger Proc
- case 71892:
- {
- switch (getPowerType())
- {
- case POWER_MANA:
- triggered_spell_id = 71888;
- break;
- case POWER_RAGE:
- triggered_spell_id = 71886;
- break;
- case POWER_ENERGY:
- triggered_spell_id = 71887;
- break;
- case POWER_RUNIC_POWER:
- triggered_spell_id = 71885;
- break;
- default:
- return false;
- }
- break;
- }
- }
- break;
- }
- case SPELLFAMILY_SHAMAN:
- {
- switch (dummySpell->Id)
- {
- // Tidal Force
- case 55198:
- {
- // Remove aura stack from caster
- RemoveAuraFromStack(55166);
- // drop charges
- return false;
- }
- // Totemic Power (The Earthshatterer set)
- case 28823:
- {
- if (!victim)
- return false;
-
- // Set class defined buff
- switch (victim->getClass())
- {
- case CLASS_PALADIN:
- case CLASS_PRIEST:
- case CLASS_SHAMAN:
- case CLASS_DRUID:
- triggered_spell_id = 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
- break;
- case CLASS_MAGE:
- case CLASS_WARLOCK:
- triggered_spell_id = 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
- break;
- case CLASS_HUNTER:
- case CLASS_ROGUE:
- triggered_spell_id = 28826; // Increases the friendly target's attack power by $s1 for $d.
- break;
- case CLASS_WARRIOR:
- triggered_spell_id = 28827; // Increases the friendly target's armor
- break;
- default:
- return false;
- }
- break;
- }
- // Lesser Healing Wave (Totem of Flowing Water Relic)
- case 28849:
- {
- target = this;
- triggered_spell_id = 28850;
- break;
- }
- // Windfury Weapon (Passive) 1-8 Ranks
- case 33757:
- {
- Player* player = ToPlayer();
- if (!player || !castItem || !castItem->IsEquipped() || !victim || !victim->IsAlive())
- return false;
-
- if (triggeredByAura->GetBase() && castItem->GetGUID() != triggeredByAura->GetBase()->GetCastItemGUID())
- return false;
-
- WeaponAttackType attType = WeaponAttackType(player->GetAttackBySlot(castItem->GetSlot()));
- if ((attType != BASE_ATTACK && attType != OFF_ATTACK)
- || (attType == BASE_ATTACK && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK)
- || (attType == OFF_ATTACK && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK))
- return false;
-
- // Now compute real proc chance...
- uint32 chance = 20;
- player->ApplySpellMod(dummySpell->Id, SPELLMOD_CHANCE_OF_SUCCESS, chance);
-
- Item* addWeapon = player->GetWeaponForAttack(attType == BASE_ATTACK ? OFF_ATTACK : BASE_ATTACK, true);
- uint32 enchant_id_add = addWeapon ? addWeapon->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)) : 0;
- SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id_add);
- if (pEnchant && pEnchant->spellid[0] == dummySpell->Id)
- chance += 14;
-
- if (!roll_chance_i(chance))
- return false;
-
- // Now amount of extra power stored in 1 effect of Enchant spell
- // Get it by item enchant id
- uint32 spellId;
- switch (castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)))
- {
- case 283: spellId = 8232; break; // 1 Rank
- case 284: spellId = 8235; break; // 2 Rank
- case 525: spellId = 10486; break; // 3 Rank
- case 1669:spellId = 16362; break; // 4 Rank
- case 2636:spellId = 25505; break; // 5 Rank
- case 3785:spellId = 58801; break; // 6 Rank
- case 3786:spellId = 58803; break; // 7 Rank
- case 3787:spellId = 58804; break; // 8 Rank
- default:
- {
- TC_LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
- castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)), dummySpell->Id);
- return false;
- }
- }
-
- SpellInfo const* windfurySpellInfo = sSpellMgr->GetSpellInfo(spellId);
- if (!windfurySpellInfo)
- {
- TC_LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non-existing spell id: %u (Windfury)", spellId);
- return false;
- }
-
- int32 extra_attack_power = CalculateSpellDamage(victim, windfurySpellInfo, 1);
-
- // Value gained from additional AP
- basepoints0 = int32(extra_attack_power / 14.0f * GetAttackTime(attType) / 1000);
-
- if (procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK)
- triggered_spell_id = 25504;
-
- if (procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK)
- triggered_spell_id = 33750;
-
- // apply cooldown before cast to prevent processing itself
- triggeredByAura->GetBase()->AddProcCooldown(std::chrono::steady_clock::now() + cooldown);
- cooldown = Milliseconds::zero();
-
- // Attack Twice
- for (uint32 i = 0; i < 2; ++i)
- CastCustomSpell(victim, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
-
- return true;
- }
- // Shaman Tier 6 Trinket
- case 40463:
- {
- if (!procSpell)
- return false;
-
- float chance;
- if (procSpell->SpellFamilyFlags[0] & 0x1)
- {
- triggered_spell_id = 40465; // Lightning Bolt
- chance = 15.0f;
- }
- else if (procSpell->SpellFamilyFlags[0] & 0x80)
- {
- triggered_spell_id = 40465; // Lesser Healing Wave
- chance = 10.0f;
- }
- else if (procSpell->SpellFamilyFlags[1] & 0x00000010)
- {
- triggered_spell_id = 40466; // Stormstrike
- chance = 50.0f;
- }
- else
- return false;
-
- if (!roll_chance_f(chance))
- return false;
-
- target = this;
- break;
- }
- // Glyph of Healing Wave
- case 55440:
- {
- // Not proc from self heals
- if (this == victim)
- return false;
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- target = this;
- triggered_spell_id = 55533;
- break;
- }
- // Spirit Hunt
- case 58877:
- {
- // Cast on owner
- target = GetOwner();
- if (!target)
- return false;
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- triggered_spell_id = 58879;
- // Cast on spirit wolf
- CastCustomSpell(this, triggered_spell_id, &basepoints0, NULL, NULL, true, NULL, triggeredByAura);
- break;
- }
- // Shaman T8 Elemental 4P Bonus
- case 64928:
- {
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- triggered_spell_id = 64930; // Electrified
- break;
- }
- // Shaman T9 Elemental 4P Bonus
- case 67228:
- {
- // Lava Burst
- if (procSpell && procSpell->SpellFamilyFlags[1] & 0x1000)
- {
- triggered_spell_id = 71824;
- SpellInfo const* triggeredSpell = sSpellMgr->GetSpellInfo(triggered_spell_id);
- if (!triggeredSpell)
- return false;
- basepoints0 = CalculatePct(int32(damage), triggerAmount) / (triggeredSpell->GetMaxDuration() / triggeredSpell->Effects[0].Amplitude);
- }
- break;
- }
- // Item - Shaman T10 Restoration 4P Bonus
- case 70808:
- {
- // Chain Heal
- if (procSpell && (procSpell->SpellFamilyFlags[0] & 0x100) && (procEx & PROC_EX_CRITICAL_HIT))
- {
- triggered_spell_id = 70809;
- SpellInfo const* triggeredSpell = sSpellMgr->GetSpellInfo(triggered_spell_id);
- if (!triggeredSpell)
- return false;
- basepoints0 = CalculatePct(int32(damage), triggerAmount) / (triggeredSpell->GetMaxDuration() / triggeredSpell->Effects[0].Amplitude);
- // Add remaining ticks to healing done
- basepoints0 += GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_HEAL);
- }
- break;
- }
- // Item - Shaman T10 Elemental 4P Bonus
- case 70817:
- {
- if (!target)
- return false;
- // try to find spell Flame Shock on the target
- if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0x0, 0x0, GetGUID()))
- {
- Aura* flameShock = aurEff->GetBase();
- int32 maxDuration = flameShock->GetMaxDuration();
- int32 newDuration = flameShock->GetDuration() + 2 * aurEff->GetAmplitude();
-
- flameShock->SetDuration(newDuration);
- // is it blizzlike to change max duration for FS?
- if (newDuration > maxDuration)
- flameShock->SetMaxDuration(newDuration);
-
- return true;
- }
- // if not found Flame Shock
- return false;
- }
- case 63280: // Glyph of Totem of Wrath
- {
- if (!procSpell || procSpell->SpellIconID != 2019)
- return false;
-
- if (Creature* totem = GetMap()->GetCreature(m_SummonSlot[1])) // Fire totem summon slot
- {
- if (SpellInfo const* totemSpell = sSpellMgr->GetSpellInfo(totem->m_spells[0]))
- {
- int32 bp0 = CalculatePct(totemSpell->Effects[EFFECT_0].CalcValue(), triggerAmount);
- int32 bp1 = CalculatePct(totemSpell->Effects[EFFECT_1].CalcValue(), triggerAmount);
- CastCustomSpell(this, 63283, &bp0, &bp1, NULL, true);
- return true;
- }
- }
- return false;
- }
- break;
- }
- // Frozen Power
- if (dummySpell->SpellIconID == 3780)
- {
- if (!target)
- return false;
- if (GetDistance(target) < 15.0f)
- return false;
- float chance = (float)triggerAmount;
- if (!roll_chance_f(chance))
- return false;
-
- triggered_spell_id = 63685;
- break;
- }
- // Ancestral Awakening
- if (dummySpell->SpellIconID == 3065)
- {
- triggered_spell_id = 52759;
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- target = this;
- break;
- }
- // Flametongue Weapon (Passive)
- if (dummySpell->SpellFamilyFlags[0] & 0x200000)
- {
- if (GetTypeId() != TYPEID_PLAYER || !victim || !victim->IsAlive() || !castItem || !castItem->IsEquipped())
- return false;
-
- WeaponAttackType attType = WeaponAttackType(Player::GetAttackBySlot(castItem->GetSlot()));
- if ((attType != BASE_ATTACK && attType != OFF_ATTACK)
- || (attType == BASE_ATTACK && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK)
- || (attType == OFF_ATTACK && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK))
- return false;
-
- float fire_onhit = float(CalculatePct(dummySpell->Effects[EFFECT_0]. CalcValue(), 1.0f));
-
- float add_spellpower = (float)(SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE)
- + victim->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_FIRE));
-
- // 1.3speed = 5%, 2.6speed = 10%, 4.0 speed = 15%, so, 1.0speed = 3.84%
- ApplyPct(add_spellpower, 3.84f);
-
- // Enchant on Off-Hand and ready?
- if (castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK)
- {
- float BaseWeaponSpeed = GetAttackTime(OFF_ATTACK) / 1000.0f;
-
- // Value1: add the tooltip damage by swingspeed + Value2: add spelldmg by swingspeed
- basepoints0 = int32((fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed));
- triggered_spell_id = 10444;
- }
-
- // Enchant on Main-Hand and ready?
- else if (castItem->GetSlot() == EQUIPMENT_SLOT_MAINHAND && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK)
- {
- float BaseWeaponSpeed = GetAttackTime(BASE_ATTACK) / 1000.0f;
-
- // Value1: add the tooltip damage by swingspeed + Value2: add spelldmg by swingspeed
- basepoints0 = int32((fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed));
- triggered_spell_id = 10444;
- }
-
- // If not ready, we should return, shouldn't we?!
- else
- return false;
-
- CastCustomSpell(victim, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- return true;
- }
- // Improved Water Shield
- if (dummySpell->SpellIconID == 2287)
- {
- // Default chance for Healing Wave and Riptide
- float chance = (float)triggeredByAura->GetAmount();
-
- if (!procSpell)
- return false; //This is the same than putting chance *= 0.0f;
- else if (procSpell->SpellFamilyFlags[0] & 0x80)
- // Lesser Healing Wave - 0.6 of default
- chance *= 0.6f;
- else if (procSpell->SpellFamilyFlags[0] & 0x100)
- // Chain heal - 0.3 of default
- chance *= 0.3f;
-
- if (!roll_chance_f(chance))
- return false;
-
- // Water Shield
- if (AuraEffect const* aurEff = GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0, 0x00000020, 0))
- {
- uint32 spell = aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell;
- CastSpell(this, spell, true, castItem, triggeredByAura);
- return true;
- }
- return false;
- }
- // Lightning Overload
- if (dummySpell->SpellIconID == 2018) // only this spell has SpellFamily Shaman SpellIconID == 2018 and dummy aura
- {
- if (!procSpell || GetTypeId() != TYPEID_PLAYER || !victim)
- return false;
-
- uint32 spellId = 0;
- // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost
- switch (procSpell->Id)
- {
- // Lightning Bolt
- case 403: spellId = 45284; break; // Rank 1
- case 529: spellId = 45286; break; // Rank 2
- case 548: spellId = 45287; break; // Rank 3
- case 915: spellId = 45288; break; // Rank 4
- case 943: spellId = 45289; break; // Rank 5
- case 6041: spellId = 45290; break; // Rank 6
- case 10391: spellId = 45291; break; // Rank 7
- case 10392: spellId = 45292; break; // Rank 8
- case 15207: spellId = 45293; break; // Rank 9
- case 15208: spellId = 45294; break; // Rank 10
- case 25448: spellId = 45295; break; // Rank 11
- case 25449: spellId = 45296; break; // Rank 12
- case 49237: spellId = 49239; break; // Rank 13
- case 49238: spellId = 49240; break; // Rank 14
- // Chain Lightning
- case 421: spellId = 45297; break; // Rank 1
- case 930: spellId = 45298; break; // Rank 2
- case 2860: spellId = 45299; break; // Rank 3
- case 10605: spellId = 45300; break; // Rank 4
- case 25439: spellId = 45301; break; // Rank 5
- case 25442: spellId = 45302; break; // Rank 6
- case 49270: spellId = 49268; break; // Rank 7
- case 49271: spellId = 49269; break; // Rank 8
- default:
- TC_LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell->Id);
- return false;
- }
-
- // Chain Lightning
- if (procSpell->SpellFamilyFlags[0] & 0x2)
- {
- // Chain lightning has [LightOverload_Proc_Chance] / [Max_Number_of_Targets] chance to proc of each individual target hit.
- // A maxed LO would have a 33% / 3 = 11% chance to proc of each target.
- // LO chance was already "accounted" at the proc chance roll, now need to divide the chance by [Max_Number_of_Targets]
- float chance = 100.0f / procSpell->Effects[effIndex].ChainTarget;
- if (!roll_chance_f(chance))
- return false;
- }
-
- CastSpell(victim, spellId, true, castItem, triggeredByAura);
- return true;
- }
- // Static Shock
- if (dummySpell->SpellIconID == 3059)
- {
- // Lightning Shield
- if (AuraEffect const* aurEff = GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x400, 0, 0))
- {
- uint32 spell = sSpellMgr->GetSpellWithRank(26364, aurEff->GetSpellInfo()->GetRank());
-
- // custom cooldown processing case
- if (GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(spell))
- GetSpellHistory()->ResetCooldown(spell);
-
- CastSpell(target, spell, true, castItem, triggeredByAura);
- aurEff->GetBase()->DropCharge();
- return true;
- }
- return false;
- }
- break;
- }
- case SPELLFAMILY_DEATHKNIGHT:
- {
- // Blood-Caked Strike - Blood-Caked Blade
- if (dummySpell->SpellIconID == 138)
- {
- if (!target || !target->IsAlive())
- return false;
-
- triggered_spell_id = dummySpell->Effects[effIndex].TriggerSpell;
- break;
- }
- // Improved Blood Presence
- if (dummySpell->SpellIconID == 2636)
- {
- if (GetTypeId() != TYPEID_PLAYER)
- return false;
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- break;
- }
- // Butchery
- if (dummySpell->SpellIconID == 2664)
- {
- basepoints0 = triggerAmount;
- triggered_spell_id = 50163;
- target = this;
- break;
- }
- // Dancing Rune Weapon
- if (dummySpell->Id == 49028)
- {
- // 1 dummy aura for dismiss rune blade
- if (effIndex != 1)
- return false;
-
- Unit* pPet = NULL;
- for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) // Find Rune Weapon
- if ((*itr)->GetEntry() == 27893)
- {
- pPet = *itr;
- break;
- }
-
- if (pPet && pPet->GetVictim() && damage && procSpell)
- {
- uint32 procDmg = damage / 2;
- pPet->SendSpellNonMeleeDamageLog(pPet->GetVictim(), procSpell->Id, procDmg, procSpell->GetSchoolMask(), 0, 0, false, 0, false);
- pPet->DealDamage(pPet->GetVictim(), procDmg, NULL, SPELL_DIRECT_DAMAGE, procSpell->GetSchoolMask(), procSpell, true);
- break;
- }
- else
- return false;
- }
- // Mark of Blood
- if (dummySpell->Id == 49005)
- {
- /// @todo need more info (cooldowns/PPM)
- triggered_spell_id = 61607;
- break;
- }
- // Unholy Blight
- if (dummySpell->Id == 49194)
- {
- triggered_spell_id = 50536;
- SpellInfo const* unholyBlight = sSpellMgr->GetSpellInfo(triggered_spell_id);
- if (!unholyBlight)
- return false;
-
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
-
- //Glyph of Unholy Blight
- if (AuraEffect* glyph=GetAuraEffect(63332, 0))
- AddPct(basepoints0, glyph->GetAmount());
-
- basepoints0 = basepoints0 / (unholyBlight->GetMaxDuration() / unholyBlight->Effects[0].Amplitude);
- basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
- break;
- }
- // Vendetta
- if (dummySpell->SpellFamilyFlags[0] & 0x10000)
- {
- basepoints0 = int32(CountPctFromMaxHealth(triggerAmount));
- triggered_spell_id = 50181;
- target = this;
- break;
- }
- // Necrosis
- if (dummySpell->SpellIconID == 2709)
- {
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- triggered_spell_id = 51460;
- break;
- }
- // Threat of Thassarian
- if (dummySpell->SpellIconID == 2023)
- {
- // Must Dual Wield
- if (!procSpell || !haveOffhandWeapon())
- return false;
- // Chance as basepoints for dummy aura
- if (!roll_chance_i(triggerAmount))
- return false;
-
- switch (procSpell->Id)
- {
- // Obliterate
- case 49020: triggered_spell_id = 66198; break; // Rank 1
- case 51423: triggered_spell_id = 66972; break; // Rank 2
- case 51424: triggered_spell_id = 66973; break; // Rank 3
- case 51425: triggered_spell_id = 66974; break; // Rank 4
-
- // Frost Strike
- case 49143: triggered_spell_id = 66196; break; // Rank 1
- case 51416: triggered_spell_id = 66958; break; // Rank 2
- case 51417: triggered_spell_id = 66959; break; // Rank 3
- case 51418: triggered_spell_id = 66960; break; // Rank 4
- case 51419: triggered_spell_id = 66961; break; // Rank 5
- case 55268: triggered_spell_id = 66962; break; // Rank 6
-
- // Plague Strike
- case 45462: triggered_spell_id = 66216; break; // Rank 1
- case 49917: triggered_spell_id = 66988; break; // Rank 2
- case 49918: triggered_spell_id = 66989; break; // Rank 3
- case 49919: triggered_spell_id = 66990; break; // Rank 4
- case 49920: triggered_spell_id = 66991; break; // Rank 5
- case 49921: triggered_spell_id = 66992; break; // Rank 6
-
- // Death Strike
- case 49998: triggered_spell_id = 66188; break; // Rank 1
- case 49999: triggered_spell_id = 66950; break; // Rank 2
- case 45463: triggered_spell_id = 66951; break; // Rank 3
- case 49923: triggered_spell_id = 66952; break; // Rank 4
- case 49924: triggered_spell_id = 66953; break; // Rank 5
-
- // Rune Strike
- case 56815: triggered_spell_id = 66217; break; // Rank 1
-
- // Blood Strike
- case 45902: triggered_spell_id = 66215; break; // Rank 1
- case 49926: triggered_spell_id = 66975; break; // Rank 2
- case 49927: triggered_spell_id = 66976; break; // Rank 3
- case 49928: triggered_spell_id = 66977; break; // Rank 4
- case 49929: triggered_spell_id = 66978; break; // Rank 5
- case 49930: triggered_spell_id = 66979; break; // Rank 6
- default:
- return false;
- }
- break;
- }
- // Runic Power Back on Snare/Root
- if (dummySpell->Id == 61257)
- {
- // only for spells and hit/crit (trigger start always) and not start from self cast spells
- if (!procSpell || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == victim)
- return false;
- // Need snare or root mechanic
- if (!(procSpell->GetAllEffectsMechanicMask() & ((1<<MECHANIC_ROOT)|(1<<MECHANIC_SNARE))))
- return false;
- triggered_spell_id = 61258;
- target = this;
- break;
- }
- // Wandering Plague
- if (dummySpell->SpellIconID == 1614)
- {
- if (!roll_chance_f(GetUnitCriticalChance(BASE_ATTACK, victim)))
- return false;
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- triggered_spell_id = 50526;
- break;
- }
- // Sudden Doom
- if (dummySpell->SpellIconID == 1939 && GetTypeId() == TYPEID_PLAYER)
- {
- SpellChainNode const* chain = NULL;
- // get highest rank of the Death Coil spell
- PlayerSpellMap const& sp_list = ToPlayer()->GetSpellMap();
- for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
- {
- // check if shown in spell book
- if (!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
- continue;
-
- SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(itr->first);
- if (!spellProto)
- continue;
-
- if (spellProto->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT
- && spellProto->SpellFamilyFlags[0] & 0x2000)
- {
- SpellChainNode const* newChain = sSpellMgr->GetSpellChainNode(itr->first);
-
- // No chain entry or entry lower than found entry
- if (!chain || !newChain || (chain->rank < newChain->rank))
- {
- triggered_spell_id = itr->first;
- chain = newChain;
- }
- else
- continue;
- // Found spell is last in chain - do not need to look more
- // Optimisation for most common case
- if (chain && chain->last->Id == itr->first)
- break;
- }
- }
- }
- break;
- }
- case SPELLFAMILY_POTION:
- {
- // alchemist's stone
- if (procSpell && dummySpell->Id == 17619)
- {
- if (procSpell->SpellFamilyName == SPELLFAMILY_POTION)
- {
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; i++)
- {
- if (procSpell->Effects[i].Effect == SPELL_EFFECT_HEAL)
- {
- triggered_spell_id = 21399;
- }
- else if (procSpell->Effects[i].Effect == SPELL_EFFECT_ENERGIZE)
- {
- triggered_spell_id = 21400;
- }
- else
- continue;
-
- basepoints0 = int32(CalculateSpellDamage(this, procSpell, i) * 0.4f);
- CastCustomSpell(this, triggered_spell_id, &basepoints0, NULL, NULL, true, NULL, triggeredByAura);
- }
- return true;
- }
- }
- break;
- }
- case SPELLFAMILY_PET:
- {
- switch (dummySpell->SpellIconID)
- {
- // Guard Dog
- case 201:
- {
- if (!victim || !procSpell)
- return false;
-
- triggered_spell_id = 54445;
- target = this;
- float addThreat = float(CalculatePct(procSpell->Effects[0].CalcValue(this), triggerAmount));
- victim->AddThreat(this, addThreat);
- break;
- }
- // Silverback
- case 1582:
- triggered_spell_id = dummySpell->Id == 62765 ? 62801 : 62800;
- target = this;
- break;
- }
- break;
- }
- default:
- break;
- }
-
- // if not handled by custom case, get triggered spell from dummySpell proto
- if (!triggered_spell_id)
- triggered_spell_id = dummySpell->Effects[triggeredByAura->GetEffIndex()].TriggerSpell;
-
- // processed charge only counting case
- if (!triggered_spell_id)
- return true;
-
- SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id);
- if (!triggerEntry)
- {
- TC_LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: Spell %u has non-existing triggered spell %u", dummySpell->Id, triggered_spell_id);
- return false;
- }
-
- if (basepoints0)
- CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura, originalCaster);
- else
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura, originalCaster);
-
- return true;
-}
-
-// Used in case when access to whole aura is needed
-// All procs should be handled like this...
-bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 /*procFlag*/, uint32 procEx, bool* handled)
-{
- SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo();
-
- switch (dummySpell->SpellFamilyName)
- {
- case SPELLFAMILY_GENERIC:
- switch (dummySpell->Id)
- {
- // Nevermelting Ice Crystal
- case 71564:
- RemoveAuraFromStack(71564);
- *handled = true;
- break;
- // Gaseous Bloat
- case 70672:
- case 72455:
- case 72832:
- case 72833:
- {
- *handled = true;
- uint32 stack = triggeredByAura->GetStackAmount();
- int32 const mod = (GetMap()->GetSpawnMode() & 1) ? 1500 : 1250;
- int32 dmg = 0;
- for (uint8 i = 1; i <= stack; ++i)
- dmg += mod * i;
- if (Unit* caster = triggeredByAura->GetCaster())
- caster->CastCustomSpell(70701, SPELLVALUE_BASE_POINT0, dmg);
- break;
- }
- // Ball of Flames Proc
- case 71756:
- case 72782:
- case 72783:
- case 72784:
- RemoveAuraFromStack(dummySpell->Id);
- *handled = true;
- break;
- // Discerning Eye of the Beast
- case 59915:
- {
- CastSpell(this, 59914, true); // 59914 already has correct basepoints in DBC, no need for custom bp
- *handled = true;
- break;
- }
- // Swift Hand of Justice
- case 59906:
- {
- int32 bp0 = CalculatePct(GetMaxHealth(), dummySpell->Effects[EFFECT_0]. CalcValue());
- CastCustomSpell(this, 59913, &bp0, NULL, NULL, true);
- *handled = true;
- break;
- }
- }
-
- break;
- case SPELLFAMILY_PALADIN:
- {
- // Infusion of Light
- if (procSpell && dummySpell->SpellIconID == 3021)
- {
- // Flash of Light HoT on Flash of Light when Sacred Shield active
- if (procSpell->SpellFamilyFlags[0] & 0x40000000 && procSpell->SpellIconID == 242)
- {
- *handled = true;
- if (victim && victim->HasAura(53601))
- {
- int32 bp0 = CalculatePct(int32(damage / 12), dummySpell->Effects[EFFECT_2].CalcValue());
- // Item - Paladin T9 Holy 4P Bonus
- if (AuraEffect const* aurEff = GetAuraEffect(67191, 0))
- AddPct(bp0, aurEff->GetAmount());
- CastCustomSpell(victim, 66922, &bp0, NULL, NULL, true);
- return true;
- }
- }
- // but should not proc on non-critical Holy Shocks
- else if ((procSpell->SpellFamilyFlags[0] & 0x200000 || procSpell->SpellFamilyFlags[1] & 0x10000) && !(procEx & PROC_EX_CRITICAL_HIT))
- *handled = true;
- break;
- }
- // Judgements of the Just
- else if (dummySpell->SpellIconID == 3015)
- {
- *handled = true;
- CastSpell(victim, 68055, true);
- return true;
- }
- // Glyph of Divinity
- else if (dummySpell->Id == 54939)
- {
- if (!procSpell)
- return false;
- *handled = true;
- // Check if we are the target and prevent mana gain
- if (victim && triggeredByAura->GetCasterGUID() == victim->GetGUID())
- return false;
- // Lookup base amount mana restore
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; i++)
- {
- if (procSpell->Effects[i].Effect == SPELL_EFFECT_ENERGIZE)
- {
- // value multiplied by 2 because you should get twice amount
- int32 mana = procSpell->Effects[i].CalcValue() * 2;
- CastCustomSpell(this, 54986, 0, &mana, NULL, true);
- }
- }
- return true;
- }
- break;
- }
- case SPELLFAMILY_MAGE:
- {
- // Combustion
- switch (dummySpell->Id)
- {
- case 11129:
- {
- *handled = true;
- Unit* caster = triggeredByAura->GetCaster();
- if (!caster || !damage)
- return false;
-
- // last charge and crit
- if (triggeredByAura->GetCharges() <= 1 && (procEx & PROC_EX_CRITICAL_HIT))
- return true; // charge counting (will removed)
-
- CastSpell(this, 28682, true);
-
- return (procEx & PROC_EX_CRITICAL_HIT) != 0;
- }
- // Empowered Fire
- case 31656:
- case 31657:
- case 31658:
- {
- *handled = true;
-
- SpellInfo const* spInfo = sSpellMgr->GetSpellInfo(67545);
- if (!spInfo)
- return false;
-
- int32 bp0 = int32(CalculatePct(GetCreateMana(), spInfo->Effects[0].CalcValue()));
- CastCustomSpell(this, 67545, &bp0, NULL, NULL, true, NULL, triggeredByAura->GetEffect(EFFECT_0), GetGUID());
- return true;
- }
- case 44401: //Missile Barrage
- case 48108: //Hot Streak
- case 57761: //Fireball!
- {
- *handled = true;
-
- // Prevent double proc for Arcane missiles
- if (this == victim)
- return false;
-
- if (HasAura(70752)) // Item - Mage T10 2P Bonus
- CastSpell((Unit*)nullptr, 70753, true);
-
- // Proc chance is unknown, we'll just use dummy aura amount
- if (AuraEffect const* aurEff = GetAuraEffect(64869, EFFECT_0)) // Item - Mage T8 4P Bonus
- if (roll_chance_i(aurEff->GetAmount())) // do not proc charges
- return false;
-
- // @workaround: We'll take care of removing the aura on next update tick
- // This is needed for 44401 to affect Arcane Missiles, else the spellmod will not be applied
- // it only works because EventProcessor will always update first scheduled event,
- // as cast is already in progress the SpellEvent for Arcane Missiles is already in queue.
- triggeredByAura->DropChargeDelayed(1);
- return false;
- }
- }
- break;
- }
- case SPELLFAMILY_DEATHKNIGHT:
- {
- // Blood of the North
- // Reaping
- // Death Rune Mastery
- /// @todo move those to spell scripts
- if (dummySpell->SpellIconID == 3041 || (dummySpell->SpellIconID == 22 && dummySpell->Id != 62459) || dummySpell->SpellIconID == 2622)
- {
- *handled = true;
- // Convert recently used Blood Rune to Death Rune
- if (Player* player = ToPlayer())
- {
- if (player->getClass() != CLASS_DEATH_KNIGHT)
- return false;
-
- RuneType rune = ToPlayer()->GetLastUsedRune();
- // can't proc from death rune use
- if (rune == RUNE_DEATH)
- return false;
- AuraEffect* aurEff = triggeredByAura->GetEffect(EFFECT_0);
- if (!aurEff)
- return false;
-
- // Reset amplitude - set death rune remove timer to 30s
- aurEff->ResetPeriodic(true);
- uint32 runesLeft;
-
- if (dummySpell->SpellIconID == 2622)
- runesLeft = 2;
- else
- runesLeft = 1;
-
- for (uint8 i = 0; i < MAX_RUNES && runesLeft; ++i)
- {
- if (dummySpell->SpellIconID == 2622)
- {
- if (player->GetCurrentRune(i) == RUNE_DEATH ||
- player->GetBaseRune(i) == RUNE_BLOOD)
- continue;
- }
- else
- {
- if (player->GetCurrentRune(i) == RUNE_DEATH ||
- player->GetBaseRune(i) != RUNE_BLOOD)
- continue;
- }
- if (player->GetRuneCooldown(i) != (player->GetRuneBaseCooldown(i) - player->GetLastRuneGraceTimer(i)))
- continue;
-
- --runesLeft;
- // Mark aura as used
- player->AddRuneByAuraEffect(i, RUNE_DEATH, aurEff);
- }
- return true;
- }
- return false;
- }
-
- switch (dummySpell->Id)
- {
- // Bone Shield cooldown
- case 49222:
- {
- *handled = true;
- return true;
- }
- // Hungering Cold aura drop
- case 51209:
- *handled = true;
- // Drop only in not disease case
- if (procSpell && procSpell->Dispel == DISPEL_DISEASE)
- return false;
- return true;
- }
- break;
- }
- case SPELLFAMILY_WARRIOR:
- {
- switch (dummySpell->Id)
- {
- // Item - Warrior T10 Protection 4P Bonus
- case 70844:
- {
- int32 basepoints0 = CalculatePct(GetMaxHealth(), dummySpell->Effects[EFFECT_1]. CalcValue());
- CastCustomSpell(this, 70845, &basepoints0, NULL, NULL, true);
- break;
- }
- // Recklessness
- case 1719:
- {
- //! Possible hack alert
- //! Don't drop charges on proc, they will be dropped on SpellMod removal
- //! Before this change, it was dropping two charges per attack, one in ProcDamageAndSpellFor, and one in RemoveSpellMods.
- //! The reason of this behaviour is Recklessness having three auras, 2 of them can not proc (isTriggeredAura array) but the other one can, making the whole spell proc.
- *handled = true;
- break;
- }
- default:
- break;
- }
- break;
- }
- }
- return false;
-}
-
-bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx)
-{
- // Get triggered aura spell info
- SpellInfo const* auraSpellInfo = triggeredByAura->GetSpellInfo();
-
- // Basepoints of trigger aura
- int32 triggerAmount = triggeredByAura->GetAmount();
-
- // Set trigger spell id, target, custom basepoints
- uint32 trigger_spell_id = auraSpellInfo->Effects[triggeredByAura->GetEffIndex()].TriggerSpell;
-
- Unit* target = NULL;
- int32 basepoints0 = 0;
-
- if (triggeredByAura->GetAuraType() == SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE)
- basepoints0 = triggerAmount;
-
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
-
- // Try handle unknown trigger spells
- // triggered spells exists only in serverside spell_dbc
- /// @todo: reverify and move these spells to spellscripts
- {
- switch (auraSpellInfo->SpellFamilyName)
- {
- case SPELLFAMILY_WARLOCK:
- {
- // Drain Soul
- if (auraSpellInfo->SpellFamilyFlags[0] & 0x4000)
- {
- // Improved Drain Soul
- Unit::AuraEffectList const& mAddFlatModifier = GetAuraEffectsByType(SPELL_AURA_DUMMY);
- for (Unit::AuraEffectList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
- {
- if ((*i)->GetMiscValue() == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellInfo()->SpellIconID == 113)
- {
- int32 value2 = CalculateSpellDamage(this, (*i)->GetSpellInfo(), 2);
- basepoints0 = int32(CalculatePct(GetMaxPower(POWER_MANA), value2));
- // Drain Soul
- CastCustomSpell(this, 18371, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- break;
- }
- }
- // Not remove charge (aura removed on death in any cases)
- // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura
- return false;
- }
- }
- default:
- break;
- }
- }
-
- // All ok. Check current trigger spell
- SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(trigger_spell_id);
- if (triggerEntry == NULL)
- {
- // Don't cast unknown spell
- TC_LOG_ERROR("entities.unit.handleproctriggerspell", "Unit::HandleProcTriggerSpell: Spell %u (effIndex: %u) has unknown TriggerSpell %u. Unhandled custom case?", auraSpellInfo->Id, triggeredByAura->GetEffIndex(), trigger_spell_id);
- return false;
- }
-
- // not allow proc extra attack spell at extra attack
- if (m_extraAttacks && triggerEntry->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
- return false;
-
- // Custom requirements (not listed in procEx) Warning! damage dealing after this
- // Custom triggered spells
- switch (auraSpellInfo->Id)
- {
- // Deep Wounds
- case 12834:
- case 12849:
- case 12867:
- {
- if (GetTypeId() != TYPEID_PLAYER)
- return false;
-
- float averageDmg = 0;
- // now compute approximate weapon damage by formula from wowwiki.com
- if (procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK)
- averageDmg = (GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE)) / 2.f;
- else
- averageDmg = (GetFloatValue(UNIT_FIELD_MINDAMAGE) + GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2.f;
-
- basepoints0 = int32(averageDmg);
- break;
- }
- // Persistent Shield (Scarab Brooch trinket)
- // This spell originally trigger 13567 - Dummy Trigger (vs dummy efect)
- case 26467:
- {
- basepoints0 = int32(CalculatePct(damage, 15));
- target = victim;
- trigger_spell_id = 26470;
- break;
- }
- // Unyielding Knights (item exploit 29108\29109)
- case 38164:
- {
- if (!victim || victim->GetEntry() != 19457) // Proc only if your target is Grillok
- return false;
- break;
- }
- // Deflection
- case 52420:
- {
- if (!HealthBelowPct(35))
- return false;
- break;
- }
-
- // Cheat Death
- case 28845:
- {
- // When your health drops below 20%
- if (HealthBelowPctDamaged(20, damage) || HealthBelowPct(20))
- return false;
- break;
- }
- // Deadly Swiftness (Rank 1)
- case 31255:
- {
- // whenever you deal damage to a target who is below 20% health.
- if (!victim || !victim->IsAlive() || victim->HealthAbovePct(20))
- return false;
-
- target = this;
- trigger_spell_id = 22588;
- }
- // Greater Heal Refund (Avatar Raiment set)
- case 37594:
- {
- if (!victim || !victim->IsAlive())
- return false;
-
- // Doesn't proc if target already has full health
- if (victim->IsFullHealth())
- return false;
- // If your Greater Heal brings the target to full health, you gain $37595s1 mana.
- if (victim->GetHealth() + damage < victim->GetMaxHealth())
- return false;
- break;
- }
- // Bonus Healing (Crystal Spire of Karabor mace)
- case 40971:
- {
- // If your target is below $s1% health
- if (!victim || !victim->IsAlive() || victim->HealthAbovePct(triggerAmount))
- return false;
- break;
- }
- // Rapid Recuperation
- case 53228:
- case 53232:
- {
- // This effect only from Rapid Fire (ability cast)
- if (!procSpell || !(procSpell->SpellFamilyFlags[0] & 0x20))
- return false;
- break;
- }
- // Decimation
- case 63156:
- case 63158:
- // Can proc only if target has hp below 35%
- if (!victim || !victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, procSpell, this))
- return false;
- break;
- // Deathbringer Saurfang - Blood Beast's Blood Link
- case 72176:
- basepoints0 = 3;
- break;
- case 15337: // Improved Spirit Tap (Rank 1)
- case 15338: // Improved Spirit Tap (Rank 2)
- {
- if (!procSpell)
- return false;
-
- if (procSpell->SpellFamilyFlags[0] & 0x800000)
- if ((procSpell->Id != 58381) || !roll_chance_i(50))
- return false;
-
- target = victim;
- break;
- }
- // Professor Putricide - Ooze Spell Tank Protection
- case 71770:
- if (victim)
- victim->CastSpell(victim, trigger_spell_id, true); // EffectImplicitTarget is self
- return true;
- case 45057: // Evasive Maneuvers (Commendation of Kael`thas trinket)
- case 71634: // Item - Icecrown 25 Normal Tank Trinket 1
- case 71640: // Item - Icecrown 25 Heroic Tank Trinket 1
- case 75475: // Item - Chamber of Aspects 25 Normal Tank Trinket
- case 75481: // Item - Chamber of Aspects 25 Heroic Tank Trinket
- {
- // Procs only if damage takes health below $s1%
- if (!HealthBelowPctDamaged(triggerAmount, damage))
- return false;
- break;
- }
- default:
- break;
- }
-
- // Blade Barrier
- if (auraSpellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && auraSpellInfo->SpellIconID == 85 && procSpell)
- {
- Player* player = ToPlayer();
- if (!player || player->getClass() != CLASS_DEATH_KNIGHT)
- return false;
-
- if (!player->IsBaseRuneSlotsOnCooldown(RUNE_BLOOD))
- return false;
- }
-
- // Rime
- else if (auraSpellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && auraSpellInfo->SpellIconID == 56)
- {
- if (GetTypeId() != TYPEID_PLAYER)
- return false;
-
- // Howling Blast
- 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
- // dummy basepoints or other customs
- switch (trigger_spell_id)
- {
- // Auras which should proc on area aura source (caster in this case):
- // Turn the Tables
- case 52914:
- case 52915:
- case 52910:
- {
- target = triggeredByAura->GetBase()->GetCaster();
- if (!target)
- return false;
-
- target->CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura);
- return true;
- }
- // Cast positive spell on enemy target
- case 7099: // Curse of Mending
- case 39703: // Curse of Mending
- case 29494: // Temptation
- case 20233: // Improved Lay on Hands (cast on target)
- {
- target = victim;
- break;
- }
- // Combo points add triggers (need add combopoint only for main target, and after possible combopoints reset)
- case 15250: // Rogue Setup
- {
- // applied only for main target
- if (!victim || (GetTypeId() == TYPEID_PLAYER && victim != ToPlayer()->GetSelectedUnit()))
- return false;
- break; // continue normal case
- }
- // Finish movies that add combo
- case 14189: // Seal Fate (Netherblade set)
- case 14157: // Ruthlessness
- {
- if (!victim || victim == this)
- return false;
- // Need add combopoint AFTER finish movie (or they dropped in finish phase)
- break;
- }
- // Item - Druid T10 Balance 2P Bonus
- case 16870:
- {
- if (HasAura(70718))
- CastSpell(this, 70721, true);
- break;
- }
- // Shamanistic Rage triggered spell
- case 30824:
- {
- basepoints0 = int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), triggerAmount));
- break;
- }
- // Enlightenment (trigger only from mana cost spells)
- case 35095:
- {
- if (!procSpell || procSpell->PowerType != POWER_MANA || (procSpell->ManaCost == 0 && procSpell->ManaCostPercentage == 0 && procSpell->ManaCostPerlevel == 0))
- return false;
- break;
- }
- // Demonic Pact
- case 48090:
- {
- // Get talent aura from owner
- if (IsPet())
- if (Unit* owner = GetOwner())
- {
- if (AuraEffect* aurEff = owner->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 3220, 0))
- {
- basepoints0 = int32((aurEff->GetAmount() * owner->SpellBaseDamageBonusDone(SpellSchoolMask(SPELL_SCHOOL_MASK_MAGIC)) + 100.0f) / 100.0f); /// @todo Is it right?
- CastCustomSpell(this, trigger_spell_id, &basepoints0, &basepoints0, NULL, true, castItem, triggeredByAura);
- return true;
- }
- }
- break;
- }
- case 46916: // Slam! (Bloodsurge proc)
- case 52437: // Sudden Death
- {
- // Item - Warrior T10 Melee 4P Bonus
- if (AuraEffect const* aurEff = GetAuraEffect(70847, 0))
- {
- if (!roll_chance_i(aurEff->GetAmount()))
- break;
- CastSpell(this, 70849, true, castItem, triggeredByAura); // Extra Charge!
- CastSpell(this, 71072, true, castItem, triggeredByAura); // Slam GCD Reduced
- CastSpell(this, 71069, true, castItem, triggeredByAura); // Execute GCD Reduced
- }
- break;
- }
- // Sword and Board
- case 50227:
- {
- // Remove cooldown on Shield Slam
- GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
- {
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
- return spellInfo && spellInfo->GetCategory() == 1209;
- }, true);
- break;
- }
- // Maelstrom Weapon
- case 53817:
- {
- // has rank dependant proc chance, ignore too often cases
- // PPM = 2.5 * (rank of talent),
- uint32 rank = auraSpellInfo->GetRank();
- // 5 rank -> 100% 4 rank -> 80% and etc from full rate
- if (!roll_chance_i(20*rank))
- return false;
- // Item - Shaman T10 Enhancement 4P Bonus
- if (AuraEffect const* aurEff = GetAuraEffect(70832, 0))
- if (Aura const* maelstrom = GetAura(53817))
- if ((maelstrom->GetStackAmount() == maelstrom->GetSpellInfo()->StackAmount) && roll_chance_i(aurEff->GetAmount()))
- CastSpell(this, 70831, true, castItem, triggeredByAura);
- break;
- }
- // Astral Shift
- case 52179:
- {
- if (!procSpell || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == victim)
- return false;
-
- // Need stun, fear or silence mechanic
- if (!(procSpell->GetAllEffectsMechanicMask() & ((1<<MECHANIC_SILENCE)|(1<<MECHANIC_STUN)|(1<<MECHANIC_FEAR))))
- return false;
- break;
- }
- // Burning Determination
- case 54748:
- {
- if (!procSpell)
- return false;
- // Need Interrupt or Silenced mechanic
- if (!(procSpell->GetAllEffectsMechanicMask() & ((1<<MECHANIC_INTERRUPT)|(1<<MECHANIC_SILENCE))))
- return false;
- break;
- }
- // Glyph of Death's Embrace
- case 58679:
- {
- // Proc only from healing part of Death Coil. Check is essential as all Death Coil spells have 0x2000 mask in SpellFamilyFlags
- if (!procSpell || !(procSpell->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && procSpell->SpellFamilyFlags[0] == 0x80002000))
- return false;
- break;
- }
- // Glyph of Death Grip
- case 58628:
- {
- // remove cooldown of Death Grip
- GetSpellHistory()->ResetCooldown(49576, true);
- return true;
- }
- // Savage Defense
- case 62606:
- {
- basepoints0 = CalculatePct(triggerAmount, GetTotalAttackPowerValue(BASE_ATTACK));
- break;
- }
- // Body and Soul
- case 64128:
- case 65081:
- {
- // Proc only from PW:S cast
- if (!procSpell || !(procSpell->SpellFamilyFlags[0] & 0x00000001))
- return false;
- break;
- }
- // Culling the Herd
- case 70893:
- {
- if (!procSpell)
- return false;
- // check if we're doing a critical hit
- if (!(procSpell->SpellFamilyFlags[1] & 0x10000000) && (procEx != PROC_EX_CRITICAL_HIT))
- return false;
- // check if we're procced by Claw, Bite or Smack (need to use the spell icon ID to detect it)
- if (!(procSpell->SpellIconID == 262 || procSpell->SpellIconID == 1680 || procSpell->SpellIconID == 473))
- return false;
- break;
- }
- }
-
- // extra attack should hit same target
- if (triggerEntry->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
- target = victim;
-
- // try detect target manually if not set
- if (target == NULL)
- target = !(procFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS)) && triggerEntry->IsPositive() ? this : victim;
-
- if (basepoints0)
- CastCustomSpell(target, trigger_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura);
-
- return true;
-}
-
-bool Unit::HandleOverrideClassScriptAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* procSpell)
-{
- int32 scriptId = triggeredByAura->GetMiscValue();
-
- if (!victim || !victim->IsAlive())
- return false;
-
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
-
- uint32 triggered_spell_id = 0;
-
- switch (scriptId)
- {
- case 836: // Improved Blizzard (Rank 1)
- {
- if (!procSpell || procSpell->SpellVisual[0] != 9487)
- return false;
- triggered_spell_id = 12484;
- break;
- }
- case 988: // Improved Blizzard (Rank 2)
- {
- if (!procSpell || procSpell->SpellVisual[0] != 9487)
- return false;
- triggered_spell_id = 12485;
- break;
- }
- case 989: // Improved Blizzard (Rank 3)
- {
- if (!procSpell || procSpell->SpellVisual[0] != 9487)
- return false;
- triggered_spell_id = 12486;
- break;
- }
- case 4533: // Dreamwalker Raiment 2 pieces bonus
- {
- // Chance 50%
- if (!roll_chance_i(50))
- return false;
-
- switch (victim->getPowerType())
- {
- case POWER_MANA: triggered_spell_id = 28722; break;
- case POWER_RAGE: triggered_spell_id = 28723; break;
- case POWER_ENERGY: triggered_spell_id = 28724; break;
- default:
- return false;
- }
- break;
- }
- case 4537: // Dreamwalker Raiment 6 pieces bonus
- triggered_spell_id = 28750; // Blessing of the Claw
- break;
- case 5497: // Improved Mana Gems
- triggered_spell_id = 37445; // Mana Surge
- break;
- case 7010: // Revitalize - can proc on full hp target
- case 7011:
- case 7012:
- {
- if (!roll_chance_i(triggeredByAura->GetAmount()))
- return false;
- switch (victim->getPowerType())
- {
- case POWER_MANA: triggered_spell_id = 48542; break;
- case POWER_RAGE: triggered_spell_id = 48541; break;
- case POWER_ENERGY: triggered_spell_id = 48540; break;
- case POWER_RUNIC_POWER: triggered_spell_id = 48543; break;
- default:
- break;
- }
- break;
- }
- default:
- break;
- }
-
- // not processed
- if (!triggered_spell_id)
- return false;
-
- // standard non-dummy case
- SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id);
-
- if (!triggerEntry)
- {
- TC_LOG_ERROR("entities.unit", "Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u", triggered_spell_id, scriptId);
- return false;
- }
-
- CastSpell(victim, triggered_spell_id, true, castItem, triggeredByAura);
- return true;
-}
-
void Unit::setPowerType(Powers new_powertype)
{
if (getPowerType() == new_powertype)
@@ -8335,6 +5478,8 @@ FactionTemplateEntry const* Unit::GetFactionTemplateEntry() const
TC_LOG_ERROR("entities.unit", "Creature (template id: %u) has invalid faction (faction template id) #%u", creature->GetCreatureTemplate()->Entry, getFaction());
else
TC_LOG_ERROR("entities.unit", "Unit (name=%s, type=%u) has invalid faction (faction template id) #%u", GetName().c_str(), uint32(GetTypeId()), getFaction());
+
+ ABORT();
}
return entry;
}
@@ -8390,8 +5535,7 @@ ReputationRank Unit::GetReactionTo(Unit const* target) const
}
// check FFA_PVP
- if (GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_FFA_PVP
- && target->GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_FFA_PVP)
+ if (IsFFAPvP() && target->IsFFAPvP())
return REP_HOSTILE;
if (selfPlayerOwner)
@@ -8623,7 +5767,7 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
}
// delay offhand weapon attack to next attack time
- if (haveOffhandWeapon())
+ if (haveOffhandWeapon() && GetTypeId() != TYPEID_PLAYER)
resetAttackTimer(OFF_ATTACK);
if (meleeAttack)
@@ -8769,17 +5913,14 @@ void Unit::ModifyAuraState(AuraStateType flag, bool apply)
{
RemoveFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
- if (flag != AURA_STATE_ENRAGE) // enrage aura state triggering continues auras
+ Unit::AuraApplicationMap& tAuras = GetAppliedAuras();
+ for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
{
- Unit::AuraApplicationMap& tAuras = GetAppliedAuras();
- for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
- {
- SpellInfo const* spellProto = (*itr).second->GetBase()->GetSpellInfo();
- if (spellProto->CasterAuraState == uint32(flag))
- RemoveAura(itr);
- else
- ++itr;
- }
+ SpellInfo const* spellProto = itr->second->GetBase()->GetSpellInfo();
+ if (itr->second->GetBase()->GetCasterGUID() == GetGUID() && spellProto->CasterAuraState == uint32(flag) && (spellProto->IsPassive() || flag != AURA_STATE_ENRAGE))
+ RemoveAura(itr);
+ else
+ ++itr;
}
}
}
@@ -8789,9 +5930,9 @@ uint32 Unit::BuildAuraStateUpdateForTarget(Unit* target) const
{
uint32 auraStates = GetUInt32Value(UNIT_FIELD_AURASTATE) &~(PER_CASTER_AURA_STATE_MASK);
for (AuraStateAurasMap::const_iterator itr = m_auraStateAuras.begin(); itr != m_auraStateAuras.end(); ++itr)
- if ((1<<(itr->first-1)) & PER_CASTER_AURA_STATE_MASK)
+ if ((1 << (itr->first - 1)) & PER_CASTER_AURA_STATE_MASK)
if (itr->second->GetBase()->GetCasterGUID() == target->GetGUID())
- auraStates |= (1<<(itr->first-1));
+ auraStates |= (1 << (itr->first - 1));
return auraStates;
}
@@ -8803,13 +5944,14 @@ bool Unit::HasAuraState(AuraStateType flag, SpellInfo const* spellProto, Unit co
if (spellProto)
{
AuraEffectList const& stateAuras = Caster->GetAuraEffectsByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
- for (AuraEffectList::const_iterator j = stateAuras.begin(); j != stateAuras.end(); ++j)
- if ((*j)->IsAffectedOnSpell(spellProto))
+ for (AuraEffect const* aurEff : stateAuras)
+ if (aurEff->IsAffectedOnSpell(spellProto))
return true;
}
+
// Check per caster aura state
// If aura with aurastate by caster not found return false
- if ((1<<(flag-1)) & PER_CASTER_AURA_STATE_MASK)
+ if ((1 << (flag - 1)) & PER_CASTER_AURA_STATE_MASK)
{
AuraStateAurasMapBounds range = m_auraStateAuras.equal_range(flag);
for (AuraStateAurasMap::const_iterator itr = range.first; itr != range.second; ++itr)
@@ -8819,7 +5961,7 @@ bool Unit::HasAuraState(AuraStateType flag, SpellInfo const* spellProto, Unit co
}
}
- return HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
+ return HasFlag(UNIT_FIELD_AURASTATE, 1 << (flag - 1));
}
void Unit::SetOwnerGUID(ObjectGuid owner)
@@ -9193,9 +6335,11 @@ void Unit::SetCharm(Unit* charm, bool apply)
}
}
-int32 Unit::DealHeal(Unit* victim, uint32 addhealth)
+void Unit::DealHeal(HealInfo& healInfo)
{
int32 gain = 0;
+ Unit* victim = healInfo.GetTarget();
+ uint32 addhealth = healInfo.GetHeal();
if (victim->IsAIEnabled)
victim->GetAI()->HealReceived(this, addhealth);
@@ -9232,7 +6376,8 @@ int32 Unit::DealHeal(Unit* victim, uint32 addhealth)
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED, addhealth);
}
- return gain;
+ if (gain)
+ healInfo.SetEffectiveHeal(gain > 0 ? static_cast<uint32>(gain) : 0UL);
}
bool Unit::IsMagnet() const
@@ -9445,30 +6590,29 @@ void Unit::UnsummonAllTotems()
}
}
-void Unit::SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical)
+void Unit::SendHealSpellLog(HealInfo& healInfo, bool critical /*= false*/)
{
// we guess size
WorldPacket data(SMSG_SPELLHEALLOG, 8 + 8 + 4 + 4 + 4 + 4 + 1 + 1);
- data << victim->GetPackGUID();
- data << GetPackGUID();
- data << uint32(SpellID);
- data << uint32(Damage);
- data << uint32(OverHeal);
- data << uint32(Absorb); // Absorb amount
+ data << healInfo.GetTarget()->GetPackGUID();
+ data << healInfo.GetHealer()->GetPackGUID();
+ data << uint32(healInfo.GetSpellInfo()->Id);
+ data << uint32(healInfo.GetHeal());
+ data << uint32(healInfo.GetHeal() - healInfo.GetEffectiveHeal());
+ data << uint32(healInfo.GetAbsorb()); // Absorb amount
data << uint8(critical ? 1 : 0);
data << uint8(0); // unused
SendMessageToSet(&data, true);
}
-int32 Unit::HealBySpell(Unit* victim, SpellInfo const* spellInfo, uint32 addHealth, bool critical)
+int32 Unit::HealBySpell(HealInfo& healInfo, bool critical /*= false*/)
{
- uint32 absorb = 0;
// calculate heal absorb and reduce healing
- CalcHealAbsorb(victim, spellInfo, addHealth, absorb);
+ CalcHealAbsorb(healInfo);
- int32 gain = DealHeal(victim, addHealth);
- SendHealSpellLog(victim, spellInfo->Id, addHealth, uint32(addHealth - gain), absorb, critical);
- return gain;
+ DealHeal(healInfo);
+ SendHealSpellLog(healInfo, critical);
+ return healInfo.GetEffectiveHeal();
}
void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellId, int32 damage, Powers powerType)
@@ -9541,11 +6685,12 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
// Impurity (dummy effect)
if (GetTypeId() == TYPEID_PLAYER)
{
- PlayerSpellMap playerSpells = ToPlayer()->GetSpellMap();
- for (PlayerSpellMap::const_iterator itr = playerSpells.begin(); itr != playerSpells.end(); ++itr)
+ PlayerSpellMap const& playerSpells = ToPlayer()->GetSpellMap();
+ for (auto itr = playerSpells.begin(); itr != playerSpells.end(); ++itr)
{
if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled)
continue;
+
switch (itr->first)
{
case 49220:
@@ -9554,7 +6699,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
case 49636:
case 49638:
if (SpellInfo const* proto = sSpellMgr->GetSpellInfo(itr->first))
- AddPct(ApCoeffMod, proto->Effects[0].CalcValue());
+ AddPct(ApCoeffMod, proto->Effects[EFFECT_0].CalcValue());
break;
}
}
@@ -9570,33 +6715,28 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
DoneAdvertisedBenefit += ((Guardian*)this)->GetBonusDamage();
// Check for table values
- float coeff = 0;
+ float coeff = 0.0f;
SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id);
if (bonus)
{
+ WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK;
+ float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS));
+ APbonus += GetTotalAttackPowerValue(attType);
+
if (damagetype == DOT)
{
coeff = bonus->dot_damage;
if (bonus->ap_dot_bonus > 0)
- {
- WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK;
- float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS));
- APbonus += GetTotalAttackPowerValue(attType);
DoneTotal += int32(bonus->ap_dot_bonus * stack * ApCoeffMod * APbonus);
- }
}
else
{
coeff = bonus->direct_damage;
if (bonus->ap_bonus > 0)
- {
- WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK;
- float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS));
- APbonus += GetTotalAttackPowerValue(attType);
DoneTotal += int32(bonus->ap_bonus * stack * ApCoeffMod * APbonus);
- }
}
}
+
// Default calculation
if (DoneAdvertisedBenefit)
{
@@ -9608,17 +6748,24 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
if (Player* modOwner = GetSpellModOwner())
{
coeff *= 100.0f;
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
+ modOwner->ApplySpellMod<SPELLMOD_BONUS_MULTIPLIER>(spellProto->Id, coeff);
coeff /= 100.0f;
}
DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod);
}
+ float tmpDamage = (int32(pdamage) + DoneTotal);
+
+ // DOTs calculated in AuraEffect::PeriodicDamageAurasTick
// 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);
+ if (damagetype != DOT)
+ {
+ tmpDamage *= SpellDamagePctDone(victim, spellProto, damagetype);
+
+ // apply spellmod to Done damage (flat and pct)
+ if (Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod<SPELLMOD_DAMAGE>(spellProto->Id, tmpDamage);
+ }
return uint32(std::max(tmpDamage, 0.0f));
}
@@ -9643,22 +6790,17 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage
if (GetTypeId() == TYPEID_UNIT && !IsPet())
DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureTemplate()->rank);
- AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
- for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
+ float maxModDamagePercentSchool = 0.0f;
+ if (GetTypeId() == TYPEID_PLAYER)
{
- if (spellProto->EquippedItemClass == -1 && (*i)->GetSpellInfo()->EquippedItemClass != -1) //prevent apply mods from weapon specific case to non weapon specific spells (Example: thunder clap and two-handed weapon specialization)
- continue;
-
- if ((*i)->GetMiscValue() & spellProto->GetSchoolMask())
- {
- if ((*i)->GetSpellInfo()->EquippedItemClass == -1)
- AddPct(DoneTotalMod, (*i)->GetAmount());
- else if (!(*i)->GetSpellInfo()->HasAttribute(SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0))
- AddPct(DoneTotalMod, (*i)->GetAmount());
- else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellInfo()))
- AddPct(DoneTotalMod, (*i)->GetAmount());
- }
+ for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
+ if (spellProto->GetSchoolMask() & (1 << i))
+ maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, GetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i));
}
+ else
+ maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, spellProto->GetSchoolMask());
+
+ DoneTotalMod *= maxModDamagePercentSchool;
uint32 creatureTypeMask = victim->GetCreatureTypeMask();
@@ -10007,7 +7149,7 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui
if (Player* modOwner = GetSpellModOwner())
{
coeff *= 100.0f;
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
+ modOwner->ApplySpellMod<SPELLMOD_BONUS_MULTIPLIER>(spellProto->Id, coeff);
coeff /= 100.0f;
}
TakenTotal += int32(TakenAdvertisedBenefit * coeff * factorMod);
@@ -10039,13 +7181,9 @@ int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const
int32 DoneAdvertisedBenefit = 0;
AuraEffectList const& mDamageDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE);
- for (AuraEffectList::const_iterator i = mDamageDone.begin(); i != mDamageDone.end(); ++i)
- if (((*i)->GetMiscValue() & schoolMask) != 0 &&
- (*i)->GetSpellInfo()->EquippedItemClass == -1 &&
- // -1 == any item class (not wand then)
- (*i)->GetSpellInfo()->EquippedItemInventoryTypeMask == 0)
- // 0 == any inventory type (not wand then)
- DoneAdvertisedBenefit += (*i)->GetAmount();
+ for (AuraEffect const* aurEff : mDamageDone)
+ if (aurEff->GetMiscValue() & schoolMask)
+ DoneAdvertisedBenefit += aurEff->GetAmount();
if (GetTypeId() == TYPEID_PLAYER)
{
@@ -10054,22 +7192,20 @@ int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const
// Damage bonus from stats
AuraEffectList const& mDamageDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT);
- for (AuraEffectList::const_iterator i = mDamageDoneOfStatPercent.begin(); i != mDamageDoneOfStatPercent.end(); ++i)
+ for (AuraEffect const* aurEff : mDamageDoneOfStatPercent)
{
- if ((*i)->GetMiscValue() & schoolMask)
+ if ((aurEff->GetMiscValue() & schoolMask) != 0)
{
// stat used stored in miscValueB for this aura
- Stats usedStat = Stats((*i)->GetMiscValueB());
- DoneAdvertisedBenefit += int32(CalculatePct(GetStat(usedStat), (*i)->GetAmount()));
+ Stats const usedStat = static_cast<Stats>(aurEff->GetMiscValueB());
+ DoneAdvertisedBenefit += static_cast<int32>(CalculatePct(GetStat(usedStat), aurEff->GetAmount()));
}
}
- // ... and attack power
- AuraEffectList const& mDamageDonebyAP = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER);
- for (AuraEffectList::const_iterator i =mDamageDonebyAP.begin(); i != mDamageDonebyAP.end(); ++i)
- if ((*i)->GetMiscValue() & schoolMask)
- DoneAdvertisedBenefit += int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), (*i)->GetAmount()));
+ // ... and attack power
+ DoneAdvertisedBenefit += static_cast<int32>(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER, schoolMask)));
}
+
return DoneAdvertisedBenefit;
}
@@ -10139,37 +7275,37 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
crit_chance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask);
// Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
crit_chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
- ApplyResilience(victim, &crit_chance, NULL, false, CR_CRIT_TAKEN_SPELL);
+ ApplyResilience(victim, &crit_chance, nullptr, false, CR_CRIT_TAKEN_SPELL);
}
// scripted (increase crit chance ... against ... target by x%
AuraEffectList const& mOverrideClassScript = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
+ for (AuraEffect const* aurEff : mOverrideClassScript)
{
- if (!((*i)->IsAffectedOnSpell(spellProto)))
+ if (!aurEff->IsAffectedOnSpell(spellProto))
continue;
- switch ((*i)->GetMiscValue())
+ float modChance = 0.f;
+ switch (aurEff->GetMiscValue())
{
+ case 911: // Shatter (Rank 3)
+ modChance += 16.f;
+ case 910: // Shatter (Rank 2)
+ modChance += 17.f;
case 849: // Shatter (Rank 1)
- if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
- crit_chance += 17;
+ modChance += 17.f;
+ if (!victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
+ break;
+
+ crit_chance += modChance;
break;
- case 910: // Shatter (Rank 2)
- if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
- crit_chance += 34;
- break;
- case 911: // Shatter (Rank 3)
- if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
- crit_chance += 50;
- break;
case 7917: // Glyph of Shadowburn
if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
- crit_chance+=(*i)->GetAmount();
+ crit_chance += aurEff->GetAmount();
break;
case 7997: // Renewed Hope
case 7998:
if (victim->HasAura(6788))
- crit_chance+=(*i)->GetAmount();
+ crit_chance += aurEff->GetAmount();
break;
default:
break;
@@ -10236,6 +7372,13 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
}
break;
}
+
+ // Spell crit suppression
+ if (victim->GetTypeId() == TYPEID_UNIT)
+ {
+ int32 const levelDiff = static_cast<int32>(victim->getLevelForTarget(this)) - getLevel();
+ crit_chance -= levelDiff * 0.7f;
+ }
}
break;
}
@@ -10284,7 +7427,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
// percent done
// only players use intelligence for critical chance computations
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
+ modOwner->ApplySpellMod<SPELLMOD_CRITICAL_CHANCE>(spellProto->Id, crit_chance);
// for this types the bonus was already added in GetUnitCriticalChance, do not add twice
if (spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE && spellProto->DmgClass != SPELL_DAMAGE_CLASS_RANGED)
@@ -10299,7 +7442,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
}
}
- return crit_chance > 0.0f ? crit_chance : 0.0f;
+ return std::max(crit_chance, 0.0f);
}
uint32 Unit::SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim)
@@ -10334,7 +7477,7 @@ uint32 Unit::SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage
{
// adds additional damage to critBonus (from talents)
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
+ modOwner->ApplySpellMod<SPELLMOD_CRIT_DAMAGE_BONUS>(spellProto->Id, crit_bonus);
}
crit_bonus += damage;
@@ -10383,6 +7526,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
return healamount;
+ float ApCoeffMod = 1.0f;
int32 DoneTotal = 0;
// done scripted mod (take it from owner)
@@ -10404,6 +7548,35 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
}
}
+ // Custom scripted damage
+ switch (spellProto->SpellFamilyName)
+ {
+ case SPELLFAMILY_DEATHKNIGHT:
+ // Impurity (dummy effect)
+ if (GetTypeId() == TYPEID_PLAYER)
+ {
+ PlayerSpellMap const& playerSpells = ToPlayer()->GetSpellMap();
+ for (auto itr = playerSpells.begin(); itr != playerSpells.end(); ++itr)
+ {
+ if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled)
+ continue;
+
+ switch (itr->first)
+ {
+ case 49220:
+ case 49633:
+ case 49635:
+ case 49636:
+ case 49638:
+ if (SpellInfo const* proto = sSpellMgr->GetSpellInfo(itr->first))
+ AddPct(ApCoeffMod, proto->Effects[EFFECT_0].CalcValue());
+ break;
+ }
+ }
+ }
+ break;
+ }
+
// Done fixed damage bonus auras
int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(spellProto->GetSchoolMask());
@@ -10417,15 +7590,15 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
{
coeff = bonus->dot_damage;
if (bonus->ap_dot_bonus > 0)
- DoneTotal += int32(bonus->ap_dot_bonus * stack * GetTotalAttackPowerValue(
- (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK));
+ DoneTotal += int32(bonus->ap_dot_bonus * ApCoeffMod * stack * GetTotalAttackPowerValue(
+ (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK));
}
else
{
coeff = bonus->direct_damage;
if (bonus->ap_bonus > 0)
- DoneTotal += int32(bonus->ap_bonus * stack * GetTotalAttackPowerValue(
- (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK));
+ DoneTotal += int32(bonus->ap_bonus * ApCoeffMod * stack * GetTotalAttackPowerValue(
+ (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK));
}
}
else
@@ -10446,7 +7619,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
if (Player* modOwner = GetSpellModOwner())
{
coeff *= 100.0f;
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
+ modOwner->ApplySpellMod<SPELLMOD_BONUS_MULTIPLIER>(spellProto->Id, coeff);
coeff /= 100.0f;
}
@@ -10471,11 +7644,18 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
DoneTotal = 0;
}
+ float heal = float(int32(healamount) + DoneTotal);
+
+ // DOTs calculated in AuraEffect::HandlePeriodicHealAurasTick
// 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);
+ if (damagetype != DOT)
+ {
+ heal *= SpellHealingPctDone(victim, spellProto);
+
+ // apply spellmod to Done amount
+ if (Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod<SPELLMOD_DAMAGE>(spellProto->Id, heal);
+ }
return uint32(std::max(heal, 0.0f));
}
@@ -10621,7 +7801,7 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u
if (Player* modOwner = GetSpellModOwner())
{
coeff *= 100.0f;
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
+ modOwner->ApplySpellMod<SPELLMOD_BONUS_MULTIPLIER>(spellProto->Id, coeff);
coeff /= 100.0f;
}
@@ -10701,18 +7881,18 @@ int32 Unit::SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) const
return advertisedBenefit;
}
-bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask) const
+bool Unit::IsImmunedToDamage(SpellSchoolMask schoolMask) const
{
// If m_immuneToSchool type contain this school type, IMMUNE damage.
- SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
- for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
- if (itr->type & shoolMask)
+ SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
+ for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
+ if ((itr->first & schoolMask) != 0)
return true;
// If m_immuneToDamage type contain magic, IMMUNE damage.
- SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
- for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
- if (itr->type & shoolMask)
+ SpellImmuneContainer const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
+ for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
+ if ((itr->first & schoolMask) != 0)
return true;
return false;
@@ -10720,23 +7900,27 @@ bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask) const
bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
{
- if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
+ if (!spellInfo)
return false;
- uint32 shoolMask = spellInfo->GetSchoolMask();
- if (spellInfo->Id != 42292 && spellInfo->Id != 59752)
- {
- // If m_immuneToSchool type contain this school type, IMMUNE damage.
- SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
- for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
- if (itr->type & shoolMask && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->spellId)))
- return true;
- }
+ // for example 40175
+ if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) && spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
+ return false;
+
+ if (spellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) || spellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
+ return false;
+
+ uint32 schoolMask = spellInfo->GetSchoolMask();
+ // If m_immuneToSchool type contain this school type, IMMUNE damage.
+ SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
+ for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
+ if ((itr->first & schoolMask) && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->second)))
+ return true;
// If m_immuneToDamage type contain magic, IMMUNE damage.
- SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
- for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
- if (itr->type & shoolMask)
+ SpellImmuneContainer const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
+ for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
+ if ((itr->first & schoolMask) != 0)
return true;
return false;
@@ -10748,29 +7932,26 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const
return false;
// Single spell immunity.
- SpellImmuneList const& idList = m_spellImmune[IMMUNITY_ID];
- for (SpellImmuneList::const_iterator itr = idList.begin(); itr != idList.end(); ++itr)
- if (itr->type == spellInfo->Id)
- return true;
+ SpellImmuneContainer const& idList = m_spellImmune[IMMUNITY_ID];
+ if (idList.count(spellInfo->Id) > 0)
+ return true;
if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return false;
- if (spellInfo->Dispel)
+ if (uint32 dispel = spellInfo->Dispel)
{
- SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
- for (SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
- if (itr->type == spellInfo->Dispel)
- return true;
+ SpellImmuneContainer const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
+ if (dispelList.count(dispel) > 0)
+ return true;
}
// Spells that don't have effectMechanics.
- if (spellInfo->Mechanic)
+ if (uint32 mechanic = spellInfo->Mechanic)
{
- SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
- for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
- if (itr->type == spellInfo->Mechanic)
- return true;
+ SpellImmuneContainer const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
+ if (mechanicList.count(mechanic) > 0)
+ return true;
}
bool immuneToAllEffects = true;
@@ -10778,8 +7959,6 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const
{
// State/effect immunities applied by aura expect full spell immunity
// Ignore effects with mechanic, they are supposed to be checked separately
- if (!spellInfo->Effects[i].IsEffect())
- continue;
if (!IsImmunedToSpellEffect(spellInfo, i))
{
immuneToAllEffects = false;
@@ -10790,13 +7969,13 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const
if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
return true;
- if (spellInfo->Id != 42292 && spellInfo->Id != 59752)
+ if (!spellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !spellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
{
- SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
- for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
+ SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
+ for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
{
- SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->spellId);
- if ((itr->type & spellInfo->GetSchoolMask())
+ SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second);
+ if ((itr->first & spellInfo->GetSchoolMask())
&& !(immuneSpellInfo && immuneSpellInfo->IsPositive() && spellInfo->IsPositive())
&& !spellInfo->CanPierceImmuneAura(immuneSpellInfo))
return true;
@@ -10809,9 +7988,9 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const
uint32 Unit::GetSchoolImmunityMask() const
{
uint32 mask = 0;
- SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_SCHOOL];
- for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
- mask |= itr->type;
+ SpellImmuneContainer const& mechanicList = m_spellImmune[IMMUNITY_SCHOOL];
+ for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
+ mask |= itr->first;
return mask;
}
@@ -10819,9 +7998,9 @@ uint32 Unit::GetSchoolImmunityMask() const
uint32 Unit::GetMechanicImmunityMask() const
{
uint32 mask = 0;
- SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
- for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
- mask |= (1 << itr->type);
+ SpellImmuneContainer const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
+ for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
+ mask |= (1 << itr->first);
return mask;
}
@@ -10836,33 +8015,35 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
// If m_immuneToEffect type contain this effect type, IMMUNE effect.
uint32 effect = spellInfo->Effects[index].Effect;
- SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT];
- for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr)
- if (itr->type == effect)
- return true;
+ auto const& effectList = m_spellImmune[IMMUNITY_EFFECT];
+ if (effectList.count(effect) > 0)
+ return true;
if (uint32 mechanic = spellInfo->Effects[index].Mechanic)
{
- SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
- for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
- if (itr->type == mechanic)
- return true;
+ auto const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
+ if (mechanicList.count(mechanic) > 0)
+ return true;
}
- if (uint32 aura = spellInfo->Effects[index].ApplyAuraName)
+ if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
{
- SpellImmuneList const& list = m_spellImmune[IMMUNITY_STATE];
- for (SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
- if (itr->type == aura)
- if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
- return true;
-
- // Check for immune to application of harmful magical effects
- AuraEffectList const& immuneAuraApply = GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL);
- for (AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter)
- if (((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) && // Check school
- !spellInfo->IsPositiveEffect(index)) // Harmful
+ if (uint32 aura = spellInfo->Effects[index].ApplyAuraName)
+ {
+ SpellImmuneContainer const& list = m_spellImmune[IMMUNITY_STATE];
+ if (list.count(aura) > 0)
return true;
+
+ if (!spellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
+ {
+ // Check for immune to application of harmful magical effects
+ AuraEffectList const& immuneAuraApply = GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL);
+ for (AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter)
+ if (((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) && // Check school
+ !spellInfo->IsPositiveEffect(index)) // Harmful
+ return true;
+ }
+ }
}
return false;
@@ -10913,15 +8094,8 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType
if (APbonus != 0) // Can be negative
{
- bool normalized = false;
- if (spellProto)
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- if (spellProto->Effects[i].Effect == SPELL_EFFECT_NORMALIZED_WEAPON_DMG)
- {
- normalized = true;
- break;
- }
- DoneFlatBenefit += int32(APbonus/14.0f * GetAPMultiplier(attType, normalized));
+ bool const normalized = spellProto && spellProto->HasEffect(SPELL_EFFECT_NORMALIZED_WEAPON_DMG);
+ DoneFlatBenefit += int32(APbonus / 14.0f * GetAPMultiplier(attType, normalized));
}
// Done total percent damage auras
@@ -10929,22 +8103,23 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType
// Some spells don't benefit from pct done mods
if (spellProto)
- if (!spellProto->HasAttribute(SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS))
+ {
+ // mods for SPELL_SCHOOL_MASK_NORMAL are already factored in base melee damage calculation
+ if (!spellProto->HasAttribute(SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS) && !(spellProto->GetSchoolMask() & SPELL_SCHOOL_MASK_NORMAL))
{
- AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
- for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
+ float maxModDamagePercentSchool = 0.0f;
+ if (GetTypeId() == TYPEID_PLAYER)
{
- if ((*i)->GetMiscValue() & spellProto->GetSchoolMask() && !(spellProto->GetSchoolMask() & SPELL_SCHOOL_MASK_NORMAL))
- {
- if ((*i)->GetSpellInfo()->EquippedItemClass == -1)
- AddPct(DoneTotalMod, (*i)->GetAmount());
- else if (!(*i)->GetSpellInfo()->HasAttribute(SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0))
- AddPct(DoneTotalMod, (*i)->GetAmount());
- else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellInfo()))
- AddPct(DoneTotalMod, (*i)->GetAmount());
- }
+ for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
+ if (spellProto->GetSchoolMask() & (1 << i))
+ maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, GetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i));
}
+ else
+ maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, spellProto->GetSchoolMask());
+
+ DoneTotalMod *= maxModDamagePercentSchool;
}
+ }
AuraEffectList const& mDamageDoneVersus = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
for (AuraEffectList::const_iterator i = mDamageDoneVersus.begin(); i != mDamageDoneVersus.end(); ++i)
@@ -11037,7 +8212,7 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType
// apply spellmod to Done damage
if (spellProto)
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage);
+ modOwner->ApplySpellMod<SPELLMOD_DAMAGE>(spellProto->Id, tmpDamage);
// bonus result can be negative
return uint32(std::max(tmpDamage, 0.0f));
@@ -11168,52 +8343,14 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
{
if (apply)
- {
- for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next)
- {
- next = itr; ++next;
- if (itr->type == type)
- {
- m_spellImmune[op].erase(itr);
- next = m_spellImmune[op].begin();
- }
- }
- SpellImmune Immune;
- Immune.spellId = spellId;
- Immune.type = type;
- m_spellImmune[op].push_back(Immune);
- }
+ m_spellImmune[op].emplace(type, spellId);
else
{
- for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr)
- {
- if (itr->spellId == spellId && itr->type == type)
- {
- m_spellImmune[op].erase(itr);
- break;
- }
- }
- }
-}
-
-void Unit::ApplySpellDispelImmunity(const SpellInfo* spellProto, DispelType type, bool apply)
-{
- ApplySpellImmune(spellProto->Id, IMMUNITY_DISPEL, type, apply);
-
- if (apply && spellProto->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
- {
- // Create dispel mask by dispel type
- uint32 dispelMask = SpellInfo::GetDispelMask(type);
- // Dispel all existing auras vs current dispel type
- AuraApplicationMap& auras = GetAppliedAuras();
- for (AuraApplicationMap::iterator itr = auras.begin(); itr != auras.end();)
+ auto bounds = m_spellImmune[op].equal_range(type);
+ for (auto itr = bounds.first; itr != bounds.second;)
{
- SpellInfo const* spell = itr->second->GetBase()->GetSpellInfo();
- if (spell->GetDispelMask() & dispelMask)
- {
- // Dispel aura
- RemoveAura(itr);
- }
+ if (itr->second == spellId)
+ itr = m_spellImmune[op].erase(itr);
else
++itr;
}
@@ -11240,7 +8377,7 @@ float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, const SpellInfo* spe
// Apply chance modifer aura
if (spellProto)
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_PROC_PER_MINUTE, PPM);
+ modOwner->ApplySpellMod<SPELLMOD_PROC_PER_MINUTE>(spellProto->Id, PPM);
return std::floor((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
}
@@ -11531,14 +8668,26 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
|| (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster()))
return false;
- // can't attack own vehicle or passenger
- if (m_vehicle)
- if (IsOnVehicle(target) || m_vehicle->GetBase()->IsOnVehicle(target))
- return false;
+ // visibility checks
+ // skip visibility check for GO casts, needs removal when go cast is implemented. Also ignore for gameobject and dynauras
+ if (GetEntry() != WORLD_TRIGGER && (!obj || !obj->isType(TYPEMASK_GAMEOBJECT | TYPEMASK_DYNAMICOBJECT)))
+ {
+ // can't attack invisible
+ if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE))
+ {
+ if (obj && !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()))
+ return false;
+ else if (!obj)
+ {
+ // ignore stealth for aoe spells. Ignore stealth if target is player and unit in combat with same player
+ bool const ignoreStealthCheck = (bySpell && bySpell->IsAffectingArea()) ||
+ (target->GetTypeId() == TYPEID_PLAYER && target->HasStealthAura() && target->IsInCombat() && IsInCombatWith(target));
- // can't attack invisible (ignore stealth for aoe spells) also if the area being looked at is from a spell use the dynamic object created instead of the casting unit. Ignore stealth if target is player and unit in combat with same player
- if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && (obj ? !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()) : !CanSeeOrDetect(target, (bySpell && bySpell->IsAffectingArea()) || (target->GetTypeId() == TYPEID_PLAYER && target->HasStealthAura() && target->IsInCombat() && IsInCombatWith(target)))))
- return false;
+ if (!CanSeeOrDetect(target, ignoreStealthCheck))
+ return false;
+ }
+ }
+ }
// can't attack dead
if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && !target->IsAlive())
@@ -11569,7 +8718,7 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
// PvP, PvC, CvP case
// can't attack friendly targets
- if ( GetReactionTo(target) > REP_NEUTRAL
+ if (GetReactionTo(target) > REP_NEUTRAL
|| target->GetReactionTo(this) > REP_NEUTRAL)
return false;
@@ -11577,10 +8726,8 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
Player const* playerAffectingTarget = target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr;
// Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar)
- if (
- (playerAffectingAttacker && !playerAffectingTarget) ||
- (!playerAffectingAttacker && playerAffectingTarget)
- )
+ if ((playerAffectingAttacker && !playerAffectingTarget) ||
+ (!playerAffectingAttacker && playerAffectingTarget))
{
Player const* player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget;
Unit const* creature = playerAffectingAttacker ? target : this;
@@ -11614,15 +8761,14 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
// additional checks - only PvP case
if (playerAffectingAttacker && playerAffectingTarget)
{
- if (target->GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_PVP)
+ if (target->IsPvP())
return true;
- if (GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_FFA_PVP
- && target->GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_FFA_PVP)
+ if (IsFFAPvP() && target->IsFFAPvP())
return true;
- return (GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_UNK1)
- || (target->GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_UNK1);
+ return HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_UNK1)
+ || target->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_UNK1);
}
return true;
}
@@ -12151,6 +9297,7 @@ void Unit::setDeathState(DeathState s)
// do not why since in IncreaseMaxHealth currenthealth is checked
SetHealth(0);
SetPower(getPowerType(), 0);
+ SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
// players in instance don't have ZoneScript, but they have InstanceScript
if (ZoneScript* zoneScript = GetZoneScript() ? GetZoneScript() : GetInstanceScript())
@@ -12419,17 +9566,17 @@ float Unit::ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effect_index
{
if (Player* modOwner = GetSpellModOwner())
{
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_ALL_EFFECTS, value);
+ modOwner->ApplySpellMod<SPELLMOD_ALL_EFFECTS>(spellProto->Id, value);
switch (effect_index)
{
- case 0:
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT1, value);
+ case EFFECT_0:
+ modOwner->ApplySpellMod<SPELLMOD_EFFECT1>(spellProto->Id, value);
break;
- case 1:
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT2, value);
+ case EFFECT_1:
+ modOwner->ApplySpellMod<SPELLMOD_EFFECT2>(spellProto->Id, value);
break;
- case 2:
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT3, value);
+ case EFFECT_2:
+ modOwner->ApplySpellMod<SPELLMOD_EFFECT3>(spellProto->Id, value);
break;
}
}
@@ -12572,7 +9719,7 @@ void Unit::ModSpellCastTime(SpellInfo const* spellInfo, int32 & castTime, Spell*
// called from caster
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell);
+ modOwner->ApplySpellMod<SPELLMOD_CASTING_TIME>(spellInfo->Id, castTime, spell);
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))
@@ -12593,7 +9740,7 @@ void Unit::ModSpellDurationTime(SpellInfo const* spellInfo, int32 & duration, Sp
// called from caster
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, duration, spell);
+ modOwner->ApplySpellMod<SPELLMOD_CASTING_TIME>(spellInfo->Id, duration, spell);
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))
@@ -12604,63 +9751,53 @@ void Unit::ModSpellDurationTime(SpellInfo const* spellInfo, int32 & duration, Sp
DiminishingLevels Unit::GetDiminishing(DiminishingGroup group)
{
- for (Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
- {
- if (i->DRGroup != group)
- continue;
-
- if (!i->hitCount)
- return DIMINISHING_LEVEL_1;
-
- if (!i->hitTime)
- return DIMINISHING_LEVEL_1;
+ DiminishingReturn& diminish = m_Diminishing[group];
+ if (!diminish.hitCount)
+ return DIMINISHING_LEVEL_1;
- // If last spell was cast more than 15 seconds ago - reset the count.
- if (i->stack == 0 && getMSTimeDiff(i->hitTime, getMSTime()) > 15000)
- {
- i->hitCount = DIMINISHING_LEVEL_1;
- return DIMINISHING_LEVEL_1;
- }
- // or else increase the count.
- else
- return DiminishingLevels(i->hitCount);
+ // If last spell was cast more than 15 seconds ago - reset the count.
+ if (!diminish.stack && GetMSTimeDiffToNow(diminish.hitTime) > 15000)
+ {
+ diminish.hitCount = DIMINISHING_LEVEL_1;
+ return DIMINISHING_LEVEL_1;
}
- return DIMINISHING_LEVEL_1;
+
+ return DiminishingLevels(diminish.hitCount);
}
-void Unit::IncrDiminishing(DiminishingGroup group)
+void Unit::IncrDiminishing(SpellInfo const* auraSpellInfo, bool triggered)
{
+ DiminishingGroup const group = auraSpellInfo->GetDiminishingReturnsGroupForSpell(triggered);
+ DiminishingLevels const maxLevel = auraSpellInfo->GetDiminishingReturnsMaxLevel(triggered);
+
// Checking for existing in the table
- for (Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
- {
- if (i->DRGroup != group)
- continue;
- if (int32(i->hitCount) < GetDiminishingReturnsMaxLevel(group))
- i->hitCount += 1;
- return;
- }
- m_Diminishing.push_back(DiminishingReturn(group, getMSTime(), DIMINISHING_LEVEL_2));
+ DiminishingReturn& diminish = m_Diminishing[group];
+ if (static_cast<int32>(diminish.hitCount) < maxLevel)
+ ++diminish.hitCount;
}
-float Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration, Unit* caster, DiminishingLevels Level, int32 limitduration)
+float Unit::ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, bool triggered, int32& duration, Unit* caster, DiminishingLevels previousLevel)
{
+ DiminishingGroup const group = auraSpellInfo->GetDiminishingReturnsGroupForSpell(triggered);
if (duration == -1 || group == DIMINISHING_NONE)
return 1.0f;
+ int32 const limitDuration = auraSpellInfo->GetDiminishingReturnsLimitDuration(triggered);
+
// test pet/charm masters instead pets/charmeds
- Unit const* tarGetOwner = GetCharmerOrOwner();
+ Unit const* targetOwner = GetCharmerOrOwner();
Unit const* casterOwner = caster->GetCharmerOrOwner();
// Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
- if (limitduration > 0 && duration > limitduration)
+ if (limitDuration > 0 && duration > limitDuration)
{
- Unit const* target = tarGetOwner ? tarGetOwner : this;
+ Unit const* target = targetOwner ? targetOwner : this;
Unit const* source = casterOwner ? casterOwner : caster;
if ((target->GetTypeId() == TYPEID_PLAYER
|| target->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_ALL_DIMINISH)
&& source->GetTypeId() == TYPEID_PLAYER)
- duration = limitduration;
+ duration = limitDuration;
}
float mod = 1.0f;
@@ -12669,7 +9806,7 @@ float Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,
{
if (GetTypeId() == TYPEID_UNIT && (ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_TAUNT_DIMINISH))
{
- DiminishingLevels diminish = Level;
+ DiminishingLevels diminish = previousLevel;
switch (diminish)
{
case DIMINISHING_LEVEL_1: break;
@@ -12682,12 +9819,12 @@ float Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,
}
}
// Some diminishings applies to mobs too (for example, Stun)
- else if ((GetDiminishingReturnsGroupType(group) == DRTYPE_PLAYER
- && ((tarGetOwner ? (tarGetOwner->GetTypeId() == TYPEID_PLAYER) : (GetTypeId() == TYPEID_PLAYER))
+ else if ((auraSpellInfo->GetDiminishingReturnsGroupType(triggered) == DRTYPE_PLAYER
+ && ((targetOwner ? (targetOwner->GetTypeId() == TYPEID_PLAYER) : (GetTypeId() == TYPEID_PLAYER))
|| (GetTypeId() == TYPEID_UNIT && ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_ALL_DIMINISH)))
- || GetDiminishingReturnsGroupType(group) == DRTYPE_ALL)
+ || auraSpellInfo->GetDiminishingReturnsGroupType(triggered) == DRTYPE_ALL)
{
- DiminishingLevels diminish = Level;
+ DiminishingLevels diminish = previousLevel;
switch (diminish)
{
case DIMINISHING_LEVEL_1: break;
@@ -12705,24 +9842,26 @@ float Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,
void Unit::ApplyDiminishingAura(DiminishingGroup group, bool apply)
{
// Checking for existing in the table
- for (Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
+ DiminishingReturn& diminish = m_Diminishing[group];
+
+ if (apply)
+ ++diminish.stack;
+ else if (diminish.stack)
{
- if (i->DRGroup != group)
- continue;
+ --diminish.stack;
- if (apply)
- i->stack += 1;
- else if (i->stack)
- {
- i->stack -= 1;
- // Remember time after last aura from group removed
- if (i->stack == 0)
- i->hitTime = getMSTime();
- }
- break;
+ // Remember time after last aura from group removed
+ if (!diminish.stack)
+ diminish.hitTime = getMSTime();
}
}
+void Unit::ClearDiminishings()
+{
+ for (uint32 i = 0; i < DIMINISHING_MAX; ++i)
+ m_Diminishing[i].Clear();
+}
+
float Unit::GetSpellMaxRangeForTarget(Unit const* target, SpellInfo const* spellInfo) const
{
if (!spellInfo->RangeEntry)
@@ -13634,152 +10773,110 @@ bool Unit::isFrozen() const
return HasAuraState(AURA_STATE_FROZEN);
}
-struct ProcTriggeredData
-{
- ProcTriggeredData(Aura* _aura)
- : aura(_aura)
- {
- effMask = 0;
- spellProcEvent = NULL;
- }
- SpellProcEventEntry const* spellProcEvent;
- Aura* aura;
- uint32 effMask;
-};
-
-typedef std::list< ProcTriggeredData > ProcTriggeredList;
-
-// List of auras that CAN be trigger but may not exist in spell_proc_event
-// in most case need for drop charges
-// in some types of aura need do additional check
-// for example SPELL_AURA_MECHANIC_IMMUNITY - need check for mechanic
-bool InitTriggerAuraData()
-{
- for (uint16 i = 0; i < TOTAL_AURAS; ++i)
- {
- isTriggerAura[i] = false;
- isNonTriggerAura[i] = false;
- isAlwaysTriggeredAura[i] = false;
- }
- isTriggerAura[SPELL_AURA_DUMMY] = true;
- isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true;
- isTriggerAura[SPELL_AURA_MOD_THREAT] = true;
- isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura does not have charges but needs to be removed on trigger
- isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
- isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
- isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
- isTriggerAura[SPELL_AURA_MOD_STEALTH] = true;
- isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura does not have charges but needs to be removed on trigger
- isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
- isTriggerAura[SPELL_AURA_TRANSFORM] = true;
- isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
- isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
- isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
- isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true;
- isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true;
- isTriggerAura[SPELL_AURA_SCHOOL_ABSORB] = true; // Savage Defense untested
- isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true;
- isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true;
- isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true;
- isTriggerAura[SPELL_AURA_MECHANIC_IMMUNITY] = true;
- isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true;
- isTriggerAura[SPELL_AURA_SPELL_MAGNET] = true;
- isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true;
- isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true;
- isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
- isTriggerAura[SPELL_AURA_MOD_MECHANIC_RESISTANCE] = true;
- isTriggerAura[SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS] = true;
- isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE] = true;
- isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE] = true;
- isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE] = true;
- isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE] = true;
- isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true;
- isTriggerAura[SPELL_AURA_MOD_DAMAGE_FROM_CASTER] = true;
- isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true;
- isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true;
-
- isNonTriggerAura[SPELL_AURA_MOD_POWER_REGEN] = true;
- isNonTriggerAura[SPELL_AURA_REDUCE_PUSHBACK] = true;
-
- isAlwaysTriggeredAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
- isAlwaysTriggeredAura[SPELL_AURA_MOD_FEAR] = true;
- isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true;
- isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true;
- isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true;
- isAlwaysTriggeredAura[SPELL_AURA_SPELL_MAGNET] = true;
- isAlwaysTriggeredAura[SPELL_AURA_SCHOOL_ABSORB] = true;
- isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true;
-
- return true;
-}
-
-uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition)
+uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition)
{
- uint32 procEx = PROC_EX_NONE;
+ uint32 hitMask = PROC_HIT_NONE;
// Check victim state
if (missCondition != SPELL_MISS_NONE)
+ {
switch (missCondition)
{
- case SPELL_MISS_MISS: procEx|=PROC_EX_MISS; break;
- case SPELL_MISS_RESIST: procEx|=PROC_EX_RESIST; break;
- case SPELL_MISS_DODGE: procEx|=PROC_EX_DODGE; break;
- case SPELL_MISS_PARRY: procEx|=PROC_EX_PARRY; break;
- case SPELL_MISS_BLOCK: procEx|=PROC_EX_BLOCK; break;
- case SPELL_MISS_EVADE: procEx|=PROC_EX_EVADE; break;
- case SPELL_MISS_IMMUNE: procEx|=PROC_EX_IMMUNE; break;
- case SPELL_MISS_IMMUNE2: procEx|=PROC_EX_IMMUNE; break;
- case SPELL_MISS_DEFLECT: procEx|=PROC_EX_DEFLECT;break;
- case SPELL_MISS_ABSORB: procEx|=PROC_EX_ABSORB; break;
- case SPELL_MISS_REFLECT: procEx|=PROC_EX_REFLECT;break;
+ case SPELL_MISS_MISS:
+ hitMask |= PROC_HIT_MISS;
+ break;
+ case SPELL_MISS_DODGE:
+ hitMask |= PROC_HIT_DODGE;
+ break;
+ case SPELL_MISS_PARRY:
+ hitMask |= PROC_HIT_PARRY;
+ break;
+ case SPELL_MISS_BLOCK:
+ // spells can't be partially blocked (it's damage can though)
+ hitMask |= PROC_HIT_BLOCK | PROC_HIT_FULL_BLOCK;
+ break;
+ case SPELL_MISS_EVADE:
+ hitMask |= PROC_HIT_EVADE;
+ break;
+ case SPELL_MISS_IMMUNE:
+ case SPELL_MISS_IMMUNE2:
+ hitMask |= PROC_HIT_IMMUNE;
+ break;
+ case SPELL_MISS_DEFLECT:
+ hitMask |= PROC_HIT_DEFLECT;
+ break;
+ case SPELL_MISS_ABSORB:
+ hitMask |= PROC_HIT_ABSORB;
+ break;
+ case SPELL_MISS_REFLECT:
+ hitMask |= PROC_HIT_REFLECT;
+ break;
+ case SPELL_MISS_RESIST:
+ hitMask |= PROC_HIT_FULL_RESIST;
+ break;
default:
break;
}
+ }
else
{
// On block
if (damageInfo->blocked)
- procEx|=PROC_EX_BLOCK;
+ {
+ hitMask |= PROC_HIT_BLOCK;
+ if (damageInfo->fullBlock)
+ hitMask |= PROC_HIT_FULL_BLOCK;
+ }
// On absorb
if (damageInfo->absorb)
- procEx|=PROC_EX_ABSORB;
- // On crit
- if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT)
- procEx|=PROC_EX_CRITICAL_HIT;
- else
- procEx|=PROC_EX_NORMAL_HIT;
+ hitMask |= PROC_HIT_ABSORB;
+
+ // Don't set hit/crit hitMask if damage is nullified
+ bool const damageNullified = (damageInfo->HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 || (hitMask & PROC_HIT_FULL_BLOCK) != 0;
+ if (!damageNullified)
+ {
+ // On crit
+ if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT)
+ hitMask |= PROC_HIT_CRITICAL;
+ else
+ hitMask |= PROC_HIT_NORMAL;
+ }
+ else if ((damageInfo->HitInfo & HITINFO_FULL_RESIST) != 0)
+ hitMask |= PROC_HIT_FULL_RESIST;
}
- return procEx;
+
+ return hitMask;
}
-void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpell, uint32 damage, SpellInfo const* procAura)
+void Unit::ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMask, uint32 hitMask, WeaponAttackType attType)
{
// Player is loaded now - do not allow passive spell casts to proc
if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetSession()->PlayerLoading())
return;
+
// For melee/ranged based attack need update skills and set some Aura states if victim present
- if (procFlag & MELEE_BASED_TRIGGER_MASK && target)
+ if (typeMask & MELEE_BASED_TRIGGER_MASK && procTarget)
{
// Update skills here for players
if (GetTypeId() == TYPEID_PLAYER)
{
// On melee based hit/miss/resist need update skill (for victim and attacker)
- if (procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_MISS|PROC_EX_RESIST))
+ if (hitMask & (PROC_HIT_NORMAL | PROC_HIT_MISS | PROC_HIT_FULL_RESIST))
{
- if (target->GetTypeId() != TYPEID_PLAYER && !target->IsCritter())
- ToPlayer()->UpdateCombatSkills(target, attType, isVictim);
+ if (procTarget->GetTypeId() != TYPEID_PLAYER && !procTarget->IsCritter())
+ ToPlayer()->UpdateCombatSkills(procTarget, attType, isVictim);
}
- // Update defence if player is victim and parry/dodge/block
- else if (isVictim && procExtra & (PROC_EX_DODGE|PROC_EX_PARRY|PROC_EX_BLOCK))
- ToPlayer()->UpdateCombatSkills(target, attType, true);
+ // Update defense if player is victim and parry/dodge/block
+ else if (isVictim && (hitMask & (PROC_HIT_DODGE | PROC_HIT_PARRY | PROC_HIT_BLOCK)))
+ ToPlayer()->UpdateCombatSkills(procTarget, attType, true);
}
// If exist crit/parry/dodge/block need update aura state (for victim and attacker)
- if (procExtra & (PROC_EX_CRITICAL_HIT|PROC_EX_PARRY|PROC_EX_DODGE|PROC_EX_BLOCK))
+ if (hitMask & (PROC_HIT_CRITICAL | PROC_HIT_PARRY | PROC_HIT_DODGE | PROC_HIT_BLOCK))
{
// for victim
if (isVictim)
{
// if victim and dodge attack
- if (procExtra & PROC_EX_DODGE)
+ if (hitMask & PROC_HIT_DODGE)
{
// Update AURA_STATE on dodge
if (getClass() != CLASS_ROGUE) // skip Rogue Riposte
@@ -13789,7 +10886,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
}
}
// if victim and parry attack
- if (procExtra & PROC_EX_PARRY)
+ if (hitMask & PROC_HIT_PARRY)
{
// For Hunters only Counterattack (skip Mongoose bite)
if (getClass() == CLASS_HUNTER)
@@ -13804,7 +10901,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
}
}
// if and victim block attack
- if (procExtra & PROC_EX_BLOCK)
+ if (hitMask & PROC_HIT_BLOCK)
{
ModifyAuraState(AURA_STATE_DEFENSE, true);
StartReactiveTimer(REACTIVE_DEFENSE);
@@ -13813,362 +10910,42 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
else // For attacker
{
// Overpower on victim dodge
- if (procExtra & PROC_EX_DODGE && GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR)
+ if ((hitMask & PROC_HIT_DODGE) && GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR)
{
- ToPlayer()->AddComboPoints(target, 1);
+ ToPlayer()->AddComboPoints(procTarget, 1);
StartReactiveTimer(REACTIVE_OVERPOWER);
}
}
}
}
-
- Unit* actor = isVictim ? target : this;
- Unit* actionTarget = !isVictim ? target : this;
-
- DamageInfo damageInfo = DamageInfo(actor, actionTarget, damage, procSpell, procSpell ? SpellSchoolMask(procSpell->SchoolMask) : SPELL_SCHOOL_MASK_NORMAL, SPELL_DIRECT_DAMAGE);
- HealInfo healInfo = HealInfo(actor, actionTarget, damage, procSpell, procSpell ? SpellSchoolMask(procSpell->SchoolMask) : SPELL_SCHOOL_MASK_NORMAL);
- ProcEventInfo eventInfo = ProcEventInfo(actor, actionTarget, target, procFlag, 0, 0, procExtra, nullptr, &damageInfo, &healInfo);
-
- std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
- ProcTriggeredList procTriggered;
- // Fill procTriggered list
- for (AuraApplicationMap::const_iterator itr = GetAppliedAuras().begin(); itr!= GetAppliedAuras().end(); ++itr)
- {
- // Do not allow auras to proc from effect triggered by itself
- if (procAura && procAura->Id == itr->first)
- continue;
-
- if (itr->second->GetBase()->IsProcOnCooldown(now))
- continue;
-
- ProcTriggeredData triggerData(itr->second->GetBase());
- // Defensive procs are active on absorbs (so absorption effects are not a hindrance)
- bool active = damage || (procExtra & PROC_EX_BLOCK && isVictim);
- if (isVictim)
- procExtra &= ~PROC_EX_INTERNAL_REQ_FAMILY;
-
- SpellInfo const* spellProto = itr->second->GetBase()->GetSpellInfo();
-
- // only auras that has triggered spell should proc from fully absorbed damage
- if (procExtra & PROC_EX_ABSORB && isVictim)
- if (damage || spellProto->Effects[EFFECT_0].TriggerSpell || spellProto->Effects[EFFECT_1].TriggerSpell || spellProto->Effects[EFFECT_2].TriggerSpell)
- active = true;
-
- if (!IsTriggeredAtSpellProcEvent(target, triggerData.aura, procSpell, procFlag, procExtra, attType, isVictim, active, triggerData.spellProcEvent))
- continue;
-
- // do checks using conditions table
- if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_SPELL_PROC, spellProto->Id, eventInfo.GetActor(), eventInfo.GetActionTarget()))
- continue;
-
- // AuraScript Hook
- if (!triggerData.aura->CallScriptCheckProcHandlers(itr->second, eventInfo))
- continue;
-
- bool procSuccess = RollProcResult(target, triggerData.aura, attType, isVictim, triggerData.spellProcEvent);
- if (!procSuccess)
- continue;
-
- bool triggeredCanProcAura = true;
- // Additional checks for triggered spells (ignore trap casts)
- if (procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_DONE_TRAP_ACTIVATION))
- {
- if (!spellProto->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED))
- triggeredCanProcAura = false;
- }
-
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
- if (itr->second->HasEffect(i))
- {
- AuraEffect* aurEff = itr->second->GetBase()->GetEffect(i);
- // Skip this auras
- if (isNonTriggerAura[aurEff->GetAuraType()])
- continue;
- // If not trigger by default and spellProcEvent == NULL - skip
- if (!isTriggerAura[aurEff->GetAuraType()] && triggerData.spellProcEvent == NULL)
- continue;
- // Some spells must always trigger
- if (triggeredCanProcAura || isAlwaysTriggeredAura[aurEff->GetAuraType()])
- triggerData.effMask |= 1<<i;
- }
- }
- if (triggerData.effMask)
- procTriggered.push_front(triggerData);
- }
-
- // Nothing found
- if (procTriggered.empty())
- return;
-
- // Note: must SetCantProc(false) before return
- if (procExtra & (PROC_EX_INTERNAL_TRIGGERED | PROC_EX_INTERNAL_CANT_PROC))
- SetCantProc(true);
-
- // Handle effects proceed this time
- for (ProcTriggeredList::const_iterator i = procTriggered.begin(); i != procTriggered.end(); ++i)
- {
- // look for aura in auras list, it may be removed while proc event processing
- if (i->aura->IsRemoved())
- continue;
-
- bool useCharges = i->aura->IsUsingCharges();
- // no more charges to use, prevent proc
- if (useCharges && !i->aura->GetCharges())
- continue;
-
- bool takeCharges = false;
- SpellInfo const* spellInfo = i->aura->GetSpellInfo();
- uint32 Id = i->aura->GetId();
-
- AuraApplication* aurApp = i->aura->GetApplicationOfTarget(GetGUID());
-
- bool prepare = i->aura->CallScriptPrepareProcHandlers(aurApp, eventInfo);
-
- Milliseconds cooldown = Milliseconds::zero();
- if (prepare && i->spellProcEvent && i->spellProcEvent->cooldown)
- cooldown = Seconds(i->spellProcEvent->cooldown);
-
- // Note: must SetCantProc(false) before return
- if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
- SetCantProc(true);
-
- bool handled = i->aura->CallScriptProcHandlers(aurApp, eventInfo);
-
- // "handled" is needed as long as proc can be handled in multiple places
- if (!handled && HandleAuraProc(target, damage, i->aura, procSpell, procFlag, procExtra, &handled))
- {
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell %u (triggered with value by %s aura of spell %u)", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), Id);
- takeCharges = true;
- }
-
- if (!handled)
- {
- for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
- {
- if (!(i->effMask & (1 << effIndex)))
- continue;
-
- AuraEffect* triggeredByAura = i->aura->GetEffect(effIndex);
- ASSERT(triggeredByAura);
-
- bool prevented = i->aura->CallScriptEffectProcHandlers(triggeredByAura, aurApp, eventInfo);
- if (prevented)
- {
- takeCharges = true;
- continue;
- }
-
- switch (triggeredByAura->GetAuraType())
- {
- case SPELL_AURA_PROC_TRIGGER_SPELL:
- {
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)",
- spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
- // Don`t drop charge or add cooldown for not started trigger
- if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpell, procFlag, procExtra))
- takeCharges = true;
- break;
- }
- case SPELL_AURA_PROC_TRIGGER_DAMAGE:
- {
- // target has to be valid
- if (!eventInfo.GetProcTarget())
- break;
-
- triggeredByAura->HandleProcTriggerDamageAuraProc(aurApp, eventInfo); // this function is part of the new proc system
- takeCharges = true;
- break;
- }
- case SPELL_AURA_MANA_SHIELD:
- case SPELL_AURA_DUMMY:
- {
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)",
- spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
- if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- takeCharges = true;
- break;
- }
- case SPELL_AURA_OBS_MOD_POWER:
- case SPELL_AURA_MOD_SPELL_CRIT_CHANCE:
- case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
- case SPELL_AURA_MOD_MELEE_HASTE:
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)",
- spellInfo->Id, isVictim ? "a victim's" : "an attacker's", triggeredByAura->GetId());
- takeCharges = true;
- break;
- case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
- {
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)",
- spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
- if (HandleOverrideClassScriptAuraProc(target, damage, triggeredByAura, procSpell))
- takeCharges = true;
- break;
- }
- case SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE:
- {
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
- (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
-
- HandleAuraRaidProcFromChargeWithValue(triggeredByAura);
- takeCharges = true;
- break;
- }
- case SPELL_AURA_RAID_PROC_FROM_CHARGE:
- {
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
- (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
-
- HandleAuraRaidProcFromCharge(triggeredByAura);
- takeCharges = true;
- break;
- }
- case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE:
- {
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell %u (triggered with value by %s aura of spell %u)",
- spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
-
- if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpell, procFlag, procExtra))
- takeCharges = true;
- break;
- }
- case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK:
- // Skip melee hits or instant cast spells
- if (procSpell && procSpell->CalcCastTime() != 0)
- takeCharges = true;
- break;
- case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
- // Skip Melee hits and spells ws wrong school
- if (procSpell && (triggeredByAura->GetMiscValue() & procSpell->SchoolMask)) // School check
- takeCharges = true;
- break;
- case SPELL_AURA_SPELL_MAGNET:
- // Skip Melee hits and targets with magnet aura
- if (procSpell && (triggeredByAura->GetBase()->GetUnitOwner()->ToUnit() == ToUnit())) // Magnet
- takeCharges = true;
- break;
- case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT:
- case SPELL_AURA_MOD_POWER_COST_SCHOOL:
- // Skip melee hits and spells ws wrong school or zero cost
- if (procSpell &&
- (procSpell->ManaCost != 0 || procSpell->ManaCostPercentage != 0) && // Cost check
- (triggeredByAura->GetMiscValue() & procSpell->SchoolMask)) // School check
- takeCharges = true;
- break;
- case SPELL_AURA_MECHANIC_IMMUNITY:
- // Compare mechanic
- if (procSpell && procSpell->Mechanic == uint32(triggeredByAura->GetMiscValue()))
- takeCharges = true;
- break;
- case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
- // Compare mechanic
- if (procSpell && procSpell->Mechanic == uint32(triggeredByAura->GetMiscValue()))
- takeCharges = true;
- break;
- case SPELL_AURA_MOD_DAMAGE_FROM_CASTER:
- // Compare casters
- if (triggeredByAura->GetCasterGUID() == target->GetGUID())
- takeCharges = true;
- break;
- // CC Auras which use their amount amount to drop
- // Are there any more auras which need this?
- case SPELL_AURA_MOD_CONFUSE:
- case SPELL_AURA_MOD_FEAR:
- case SPELL_AURA_MOD_STUN:
- case SPELL_AURA_MOD_ROOT:
- case SPELL_AURA_TRANSFORM:
- {
- // chargeable mods are breaking on hit
- if (useCharges)
- takeCharges = true;
- else
- {
- // Spell own direct damage at apply wont break the CC
- if (procSpell && (procSpell->Id == triggeredByAura->GetId()))
- {
- Aura* aura = triggeredByAura->GetBase();
- // called from spellcast, should not have ticked yet
- if (aura->GetDuration() == aura->GetMaxDuration())
- break;
- }
- int32 damageLeft = triggeredByAura->GetAmount();
- // No damage left
- if (damageLeft < int32(damage))
- i->aura->Remove();
- else
- triggeredByAura->SetAmount(damageLeft - damage);
- }
- break;
- }
- //case SPELL_AURA_ADD_FLAT_MODIFIER:
- //case SPELL_AURA_ADD_PCT_MODIFIER:
- // HandleSpellModAuraProc
- //break;
- default:
- // nothing do, just charges counter
- takeCharges = true;
- break;
- } // switch (triggeredByAura->GetAuraType())
- i->aura->CallScriptAfterEffectProcHandlers(triggeredByAura, aurApp, eventInfo);
- } // for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
- } // if (!handled)
-
- if (prepare && takeCharges && cooldown != Milliseconds::zero())
- i->aura->AddProcCooldown(now + cooldown);
-
- // Remove charge (aura can be removed by triggers)
- if (prepare && useCharges && takeCharges)
- {
- // Set charge drop delay (only for missiles)
- if ((procExtra & PROC_EX_REFLECT) && target && procSpell && procSpell->Speed > 0.0f)
- {
- // Set up missile speed based delay (from Spell.cpp: Spell::AddUnitTarget()::L2237)
- uint32 delay = uint32(std::floor(std::max<float>(target->GetDistance(this), 5.0f) / procSpell->Speed * 1000.0f));
- // Schedule charge drop
- i->aura->DropChargeDelayed(delay);
- }
- else
- i->aura->DropCharge();
- }
-
- i->aura->CallScriptAfterProcHandlers(aurApp, eventInfo);
-
- if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
- SetCantProc(false);
- }
-
- // Cleanup proc requirements
- if (procExtra & (PROC_EX_INTERNAL_TRIGGERED | PROC_EX_INTERNAL_CANT_PROC))
- SetCantProc(false);
}
-void Unit::GetProcAurasTriggeredOnEvent(std::list<AuraApplication*>& aurasTriggeringProc, std::list<AuraApplication*>* procAuras, ProcEventInfo eventInfo)
+void Unit::GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTriggeringProc, AuraApplicationList* procAuras, ProcEventInfo& eventInfo)
{
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
// use provided list of auras which can proc
if (procAuras)
{
- for (std::list<AuraApplication*>::iterator itr = procAuras->begin(); itr!= procAuras->end(); ++itr)
+ for (AuraApplication* aurApp : *procAuras)
{
- ASSERT((*itr)->GetTarget() == this);
- if (!(*itr)->GetRemoveMode())
- if ((*itr)->GetBase()->IsProcTriggeredOnEvent(*itr, eventInfo, now))
- {
- (*itr)->GetBase()->PrepareProcToTrigger(*itr, eventInfo, now);
- aurasTriggeringProc.push_back(*itr);
- }
+ ASSERT(aurApp->GetTarget() == this);
+ if (uint8 procEffectMask = aurApp->GetBase()->GetProcEffectMask(aurApp, eventInfo, now))
+ {
+ aurApp->GetBase()->PrepareProcToTrigger(aurApp, eventInfo, now);
+ aurasTriggeringProc.emplace_back(procEffectMask, aurApp);
+ }
}
}
// or generate one on our own
else
{
- for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr!= GetAppliedAuras().end(); ++itr)
+ for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr != GetAppliedAuras().end(); ++itr)
{
- if (itr->second->GetBase()->IsProcTriggeredOnEvent(itr->second, eventInfo, now))
+ if (uint8 procEffectMask = itr->second->GetBase()->GetProcEffectMask(itr->second, eventInfo, now))
{
itr->second->GetBase()->PrepareProcToTrigger(itr->second, eventInfo, now);
- aurasTriggeringProc.push_back(itr->second);
+ aurasTriggeringProc.emplace_back(procEffectMask, itr->second);
}
}
}
@@ -14177,35 +10954,73 @@ void Unit::GetProcAurasTriggeredOnEvent(std::list<AuraApplication*>& aurasTrigge
void Unit::TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo)
{
DamageInfo dmgInfo = DamageInfo(damageInfo);
- TriggerAurasProcOnEvent(NULL, NULL, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, 0, 0, damageInfo.procEx, NULL, &dmgInfo, NULL);
+ TriggerAurasProcOnEvent(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr);
}
-void Unit::TriggerAurasProcOnEvent(std::list<AuraApplication*>* myProcAuras, std::list<AuraApplication*>* targetProcAuras, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
+void Unit::TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
{
// prepare data for self trigger
- ProcEventInfo myProcEventInfo = ProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
- std::list<AuraApplication*> myAurasTriggeringProc;
- GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, myProcAuras, myProcEventInfo);
-
- // prepare data for target trigger
- ProcEventInfo targetProcEventInfo = ProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
- std::list<AuraApplication*> targetAurasTriggeringProc;
- if (typeMaskActionTarget)
- GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, targetProcAuras, targetProcEventInfo);
+ ProcEventInfo myProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
+ if (typeMaskActor)
+ {
+ AuraApplicationProcContainer myAurasTriggeringProc;
+ GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, nullptr, myProcEventInfo);
- TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc);
+ // needed for example for Cobra Strikes, pet does the attack, but aura is on owner
+ if (Player* modOwner = GetSpellModOwner())
+ {
+ if (modOwner != this && spell)
+ {
+ AuraApplicationList modAuras;
+ for (auto itr = modOwner->GetAppliedAuras().begin(); itr != modOwner->GetAppliedAuras().end(); ++itr)
+ {
+ if (spell->m_appliedMods.count(itr->second->GetBase()) != 0)
+ modAuras.push_back(itr->second);
+ }
+ modOwner->GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, &modAuras, myProcEventInfo);
+ }
+ }
+ TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc);
+ }
- if (typeMaskActionTarget)
- TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc);
+ // prepare data for target trigger
+ ProcEventInfo targetProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
+ if (typeMaskActionTarget && actionTarget)
+ {
+ AuraApplicationProcContainer targetAurasTriggeringProc;
+ actionTarget->GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, nullptr, targetProcEventInfo);
+ actionTarget->TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc);
+ }
}
-void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, std::list<AuraApplication*>& aurasTriggeringProc)
+void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProcContainer& aurasTriggeringProc)
{
- for (std::list<AuraApplication*>::iterator itr = aurasTriggeringProc.begin(); itr != aurasTriggeringProc.end(); ++itr)
+ Spell const* triggeringSpell = eventInfo.GetProcSpell();
+ bool const disableProcs = triggeringSpell && triggeringSpell->IsProcDisabled();
+ if (disableProcs)
+ SetCantProc(true);
+
+ for (auto const& aurAppProc : aurasTriggeringProc)
{
- if (!(*itr)->GetRemoveMode())
- (*itr)->GetBase()->TriggerProcOnEvent(*itr, eventInfo);
+ AuraApplication* aurApp;
+ uint8 procEffectMask;
+ std::tie(procEffectMask, aurApp) = aurAppProc;
+
+ if (aurApp->GetRemoveMode())
+ continue;
+
+ SpellInfo const* spellInfo = aurApp->GetBase()->GetSpellInfo();
+ if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
+ SetCantProc(true);
+
+ aurApp->GetBase()->TriggerProcOnEvent(procEffectMask, aurApp, eventInfo);
+
+ if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
+ SetCantProc(false);
}
+
+ if (disableProcs)
+ SetCantProc(false);
}
SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const
@@ -14655,26 +11470,41 @@ float Unit::CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffect
float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized)
{
- if (!normalized || GetTypeId() != TYPEID_PLAYER)
- return float(GetAttackTime(attType)) / 1000.0f;
+ if (GetTypeId() != TYPEID_PLAYER)
+ return GetAttackTime(attType) / 1000.0f;
- Item* Weapon = ToPlayer()->GetWeaponForAttack(attType, true);
- if (!Weapon)
- return 2.4f; // fist attack
+ Item* weapon = ToPlayer()->GetWeaponForAttack(attType, true);
+ if (!weapon)
+ return BASE_ATTACK_TIME / 1000.0f;
- switch (Weapon->GetTemplate()->InventoryType)
+ if (!normalized)
+ return weapon->GetTemplate()->Delay / 1000.0f;
+
+ switch (weapon->GetTemplate()->SubClass)
{
- case INVTYPE_2HWEAPON:
+ case ITEM_SUBCLASS_WEAPON_AXE2:
+ case ITEM_SUBCLASS_WEAPON_MACE2:
+ case ITEM_SUBCLASS_WEAPON_POLEARM:
+ case ITEM_SUBCLASS_WEAPON_SWORD2:
+ case ITEM_SUBCLASS_WEAPON_STAFF:
+ case ITEM_SUBCLASS_WEAPON_FISHING_POLE:
return 3.3f;
- case INVTYPE_RANGED:
- case INVTYPE_RANGEDRIGHT:
- case INVTYPE_THROWN:
+ case ITEM_SUBCLASS_WEAPON_BOW:
+ case ITEM_SUBCLASS_WEAPON_GUN:
+ case ITEM_SUBCLASS_WEAPON_CROSSBOW:
+ case ITEM_SUBCLASS_WEAPON_THROWN:
return 2.8f;
- case INVTYPE_WEAPON:
- case INVTYPE_WEAPONMAINHAND:
- case INVTYPE_WEAPONOFFHAND:
+ case ITEM_SUBCLASS_WEAPON_AXE:
+ case ITEM_SUBCLASS_WEAPON_MACE:
+ case ITEM_SUBCLASS_WEAPON_SWORD:
+ case ITEM_SUBCLASS_WEAPON_EXOTIC:
+ case ITEM_SUBCLASS_WEAPON_EXOTIC2:
+ case ITEM_SUBCLASS_WEAPON_FIST:
+ return 2.4f;
+ case ITEM_SUBCLASS_WEAPON_DAGGER:
+ return 1.7f;
default:
- return Weapon->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER ? 1.7f : 2.4f;
+ return weapon->GetTemplate()->Delay / 1000.0f;
}
}
@@ -14789,203 +11619,6 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)
return true;
}
-bool Unit::IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, SpellInfo const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent)
-{
- SpellInfo const* spellInfo = aura->GetSpellInfo();
-
- // let the aura be handled by new proc system if it has new entry
- if (sSpellMgr->GetSpellProcEntry(spellInfo->Id))
- return false;
-
- // Get proc Event Entry
- spellProcEvent = sSpellMgr->GetSpellProcEvent(spellInfo->Id);
-
- // Get EventProcFlag
- uint32 EventProcFlag;
- if (spellProcEvent && spellProcEvent->procFlags) // if exist get custom spellProcEvent->procFlags
- EventProcFlag = spellProcEvent->procFlags;
- else
- EventProcFlag = spellInfo->ProcFlags; // else get from spell proto
- // Continue if no trigger exist
- if (!EventProcFlag)
- return false;
-
- // Check spellProcEvent data requirements
- if (!sSpellMgr->IsSpellProcEventCanTriggeredBy(spellInfo, spellProcEvent, EventProcFlag, procSpell, procFlag, procExtra, active))
- return false;
- // In most cases req get honor or XP from kill
- if (EventProcFlag & PROC_FLAG_KILL && GetTypeId() == TYPEID_PLAYER)
- {
- bool allow = false;
-
- if (victim)
- allow = ToPlayer()->isHonorOrXPTarget(victim);
-
- // Shadow Word: Death - can trigger from every kill
- if (aura->GetId() == 32409)
- allow = true;
- if (!allow)
- return false;
- }
- // Aura added by spell can`t trigger from self (prevent drop charges/do triggers)
- // But except periodic and kill triggers (can triggered from self)
- if (procSpell && procSpell->Id == spellInfo->Id
- && !(spellInfo->ProcFlags&(PROC_FLAG_TAKEN_PERIODIC | PROC_FLAG_KILL)))
- return false;
-
- // Check if current equipment allows aura to proc
- if (!isVictim && GetTypeId() == TYPEID_PLAYER)
- {
- Player* player = ToPlayer();
- if (spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON)
- {
- Item* item = NULL;
- if (attType == BASE_ATTACK)
- item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
- else if (attType == OFF_ATTACK)
- item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
- else
- item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
-
- if (player->IsInFeralForm())
- return false;
-
- if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_WEAPON || !((1<<item->GetTemplate()->SubClass) & spellInfo->EquippedItemSubClassMask))
- return false;
- }
- else if (spellInfo->EquippedItemClass == ITEM_CLASS_ARMOR)
- {
- // Check if player is wearing shield
- Item* item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
- if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_ARMOR || !((1<<item->GetTemplate()->SubClass) & spellInfo->EquippedItemSubClassMask))
- return false;
- }
- }
-
- return true;
-}
-
-bool Unit::RollProcResult(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, SpellProcEventEntry const* spellProcEvent)
-{
- SpellInfo const* spellInfo = aura->GetSpellInfo();
- // Get chance from spell
- float chance = float(spellInfo->ProcChance);
- // If in spellProcEvent exist custom chance, chance = spellProcEvent->customChance;
- if (spellProcEvent && spellProcEvent->customChance)
- chance = spellProcEvent->customChance;
- // If PPM exist calculate chance from PPM
- if (spellProcEvent && spellProcEvent->ppmRate != 0)
- {
- if (!isVictim)
- {
- uint32 weaponSpeed = GetAttackTime(attType);
- chance = GetPPMProcChance(weaponSpeed, spellProcEvent->ppmRate, spellInfo);
- }
- else if (victim)
- {
- uint32 weaponSpeed = victim->GetAttackTime(attType);
- chance = victim->GetPPMProcChance(weaponSpeed, spellProcEvent->ppmRate, spellInfo);
- }
- }
- // Apply chance modifer aura
- if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CHANCE_OF_SUCCESS, chance);
-
- return roll_chance_f(chance);
-}
-
-bool Unit::HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura)
-{
- // aura can be deleted at casts
- SpellInfo const* spellProto = triggeredByAura->GetSpellInfo();
- int32 heal = triggeredByAura->GetAmount();
- ObjectGuid caster_guid = triggeredByAura->GetCasterGUID();
-
- // Currently only Prayer of Mending
- if (!(spellProto->SpellFamilyName == SPELLFAMILY_PRIEST && spellProto->SpellFamilyFlags[1] & 0x20))
- {
- TC_LOG_DEBUG("spells", "Unit::HandleAuraRaidProcFromChargeWithValue, received not handled spell: %u", spellProto->Id);
- return false;
- }
-
- // jumps
- int32 jumps = triggeredByAura->GetBase()->GetCharges()-1;
-
- // current aura expire
- triggeredByAura->GetBase()->SetCharges(1); // will removed at next charges decrease
-
- // next target selection
- if (jumps > 0)
- {
- if (Unit* caster = triggeredByAura->GetCaster())
- {
- float radius = triggeredByAura->GetSpellInfo()->Effects[triggeredByAura->GetEffIndex()].CalcRadius(caster);
-
- if (Unit* target = GetNextRandomRaidMemberOrPet(radius))
- {
- CastCustomSpell(target, spellProto->Id, &heal, NULL, NULL, true, NULL, triggeredByAura, caster_guid);
- if (Aura* aura = target->GetAura(spellProto->Id, caster->GetGUID()))
- aura->SetCharges(jumps);
- }
- }
- }
-
- // heal
- CastCustomSpell(this, 33110, &heal, NULL, NULL, true, NULL, NULL, caster_guid);
- return true;
-
-}
-bool Unit::HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura)
-{
- // aura can be deleted at casts
- SpellInfo const* spellProto = triggeredByAura->GetSpellInfo();
-
- uint32 damageSpellId;
- switch (spellProto->Id)
- {
- case 57949: // shiver
- damageSpellId = 57952;
- //animationSpellId = 57951; dummy effects for jump spell have unknown use (see also 41637)
- break;
- case 59978: // shiver
- damageSpellId = 59979;
- break;
- case 43593: // Cold Stare
- damageSpellId = 43594;
- break;
- default:
- TC_LOG_ERROR("entities.unit", "Unit::HandleAuraRaidProcFromCharge, received unhandled spell: %u", spellProto->Id);
- return false;
- }
-
- ObjectGuid caster_guid = triggeredByAura->GetCasterGUID();
-
- // jumps
- int32 jumps = triggeredByAura->GetBase()->GetCharges()-1;
-
- // current aura expire
- triggeredByAura->GetBase()->SetCharges(1); // will removed at next charges decrease
-
- // next target selection
- if (jumps > 0)
- {
- if (Unit* caster = triggeredByAura->GetCaster())
- {
- float radius = triggeredByAura->GetSpellInfo()->Effects[triggeredByAura->GetEffIndex()].CalcRadius(caster);
- if (Unit* target= GetNextRandomRaidMemberOrPet(radius))
- {
- CastSpell(target, spellProto, true, NULL, triggeredByAura, caster_guid);
- if (Aura* aura = target->GetAura(spellProto->Id, caster->GetGUID()))
- aura->SetCharges(jumps);
- }
- }
- }
-
- CastSpell(this, damageSpellId, true, NULL, triggeredByAura, caster_guid);
-
- return true;
-}
-
void Unit::Kill(Unit* victim, bool durabilityLoss)
{
// Prevent killing unit twice (and giving reward from kill twice)
@@ -15080,14 +11713,17 @@ void Unit::Kill(Unit* victim, bool durabilityLoss)
// Do KILL and KILLED procs. KILL proc is called only for the unit who landed the killing blow (and its owner - for pets and totems) regardless of who tapped the victim
if (IsPet() || IsTotem())
+ {
+ // proc only once for victim
if (Unit* owner = GetOwner())
- owner->ProcDamageAndSpell(victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_EX_NONE, 0);
+ owner->ProcSkillsAndAuras(victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
+ }
if (!victim->IsCritter())
- ProcDamageAndSpell(victim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0);
+ ProcSkillsAndAuras(victim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
// Proc auras on death - must be before aura/combat remove
- victim->ProcDamageAndSpell(NULL, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, BASE_ATTACK, 0);
+ victim->ProcSkillsAndAuras(victim, PROC_FLAG_NONE, PROC_FLAG_DEATH, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
// update get killing blow achievements, must be done before setDeathState to be able to require auras on target
// and before Spirit of Redemption as it also removes auras
@@ -15896,8 +12532,9 @@ bool Unit::IsInPartyWith(Unit const* unit) const
else if ((u2->GetTypeId() == TYPEID_PLAYER && u1->GetTypeId() == TYPEID_UNIT && u1->ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT) ||
(u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_UNIT && u2->ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT))
return true;
- else
- return false;
+
+ // else u1->GetTypeId() == u2->GetTypeId() == TYPEID_UNIT
+ return u1->getFaction() == u2->getFaction();
}
bool Unit::IsInRaidWith(Unit const* unit) const
@@ -15915,8 +12552,9 @@ bool Unit::IsInRaidWith(Unit const* unit) const
else if ((u2->GetTypeId() == TYPEID_PLAYER && u1->GetTypeId() == TYPEID_UNIT && u1->ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT) ||
(u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_UNIT && u2->ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT))
return true;
- else
- return false;
+
+ // else u1->GetTypeId() == u2->GetTypeId() == TYPEID_UNIT
+ return u1->getFaction() == u2->getFaction();
}
void Unit::GetPartyMembers(std::list<Unit*> &TagUnitMap)
@@ -15981,7 +12619,7 @@ Aura* Unit::AddAura(uint32 spellId, Unit* target)
if (!spellInfo)
return NULL;
- if (!target->IsAlive() && !spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE) && !spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_DEAD))
+ if (!target->IsAlive() && !spellInfo->IsPassive() && !spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_DEAD))
return NULL;
return AddAura(spellInfo, MAX_EFFECT_MASK, target);
@@ -16122,7 +12760,7 @@ float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, i
if (spellId)
{
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, hitChance);
+ modOwner->ApplySpellMod<SPELLMOD_RESIST_MISS_CHANCE>(spellId, hitChance);
}
missChance += hitChance - 100.0f;
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index aa232577d3d..917e5d24c79 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -81,42 +81,42 @@ enum SpellAuraInterruptFlags
AURA_INTERRUPT_FLAG_NOT_VICTIM = (AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE | AURA_INTERRUPT_FLAG_DIRECT_DAMAGE)
};
-enum SpellModOp
-{
- SPELLMOD_DAMAGE = 0,
- SPELLMOD_DURATION = 1,
- SPELLMOD_THREAT = 2,
- SPELLMOD_EFFECT1 = 3,
- SPELLMOD_CHARGES = 4,
- SPELLMOD_RANGE = 5,
- SPELLMOD_RADIUS = 6,
- SPELLMOD_CRITICAL_CHANCE = 7,
- SPELLMOD_ALL_EFFECTS = 8,
- SPELLMOD_NOT_LOSE_CASTING_TIME = 9,
- SPELLMOD_CASTING_TIME = 10,
- SPELLMOD_COOLDOWN = 11,
- SPELLMOD_EFFECT2 = 12,
- SPELLMOD_IGNORE_ARMOR = 13,
- SPELLMOD_COST = 14,
- SPELLMOD_CRIT_DAMAGE_BONUS = 15,
- SPELLMOD_RESIST_MISS_CHANCE = 16,
- SPELLMOD_JUMP_TARGETS = 17,
- SPELLMOD_CHANCE_OF_SUCCESS = 18,
- SPELLMOD_ACTIVATION_TIME = 19,
- SPELLMOD_DAMAGE_MULTIPLIER = 20,
- SPELLMOD_GLOBAL_COOLDOWN = 21,
- SPELLMOD_DOT = 22,
- SPELLMOD_EFFECT3 = 23,
- SPELLMOD_BONUS_MULTIPLIER = 24,
+enum SpellModOp : uint8
+{
+ SPELLMOD_DAMAGE = 0,
+ SPELLMOD_DURATION = 1,
+ SPELLMOD_THREAT = 2,
+ SPELLMOD_EFFECT1 = 3,
+ SPELLMOD_CHARGES = 4,
+ SPELLMOD_RANGE = 5,
+ SPELLMOD_RADIUS = 6,
+ SPELLMOD_CRITICAL_CHANCE = 7,
+ SPELLMOD_ALL_EFFECTS = 8,
+ SPELLMOD_NOT_LOSE_CASTING_TIME = 9,
+ SPELLMOD_CASTING_TIME = 10,
+ SPELLMOD_COOLDOWN = 11,
+ SPELLMOD_EFFECT2 = 12,
+ SPELLMOD_IGNORE_ARMOR = 13,
+ SPELLMOD_COST = 14,
+ SPELLMOD_CRIT_DAMAGE_BONUS = 15,
+ SPELLMOD_RESIST_MISS_CHANCE = 16,
+ SPELLMOD_JUMP_TARGETS = 17,
+ SPELLMOD_CHANCE_OF_SUCCESS = 18,
+ SPELLMOD_ACTIVATION_TIME = 19,
+ SPELLMOD_DAMAGE_MULTIPLIER = 20,
+ SPELLMOD_GLOBAL_COOLDOWN = 21,
+ SPELLMOD_DOT = 22,
+ SPELLMOD_EFFECT3 = 23,
+ SPELLMOD_BONUS_MULTIPLIER = 24,
// spellmod 25
- SPELLMOD_PROC_PER_MINUTE = 26,
- SPELLMOD_VALUE_MULTIPLIER = 27,
- SPELLMOD_RESIST_DISPEL_CHANCE = 28,
- SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell
- SPELLMOD_SPELL_COST_REFUND_ON_FAIL = 30
-};
+ SPELLMOD_PROC_PER_MINUTE = 26,
+ SPELLMOD_VALUE_MULTIPLIER = 27,
+ SPELLMOD_RESIST_DISPEL_CHANCE = 28,
+ SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell
+ SPELLMOD_SPELL_COST_REFUND_ON_FAIL = 30,
-#define MAX_SPELLMOD 32
+ MAX_SPELLMOD
+};
enum SpellValueMod
{
@@ -324,20 +324,21 @@ enum HitInfo
HITINFO_FULL_RESIST = 0x00000080,
HITINFO_PARTIAL_RESIST = 0x00000100,
HITINFO_CRITICALHIT = 0x00000200, // critical hit
- // 0x00000400
- // 0x00000800
- // 0x00001000
+ HITINFO_UNK10 = 0x00000400,
+ HITINFO_UNK11 = 0x00000800,
+ HITINFO_UNK12 = 0x00001000,
HITINFO_BLOCK = 0x00002000, // blocked damage
- // 0x00004000 // Hides worldtext for 0 damage
- // 0x00008000 // Related to blood visual
+ HITINFO_UNK14 = 0x00004000, // set only if meleespellid is present// no world text when victim is hit for 0 dmg(HideWorldTextForNoDamage?)
+ HITINFO_UNK15 = 0x00008000, // player victim?// something related to blod sprut visual (BloodSpurtInBack?)
HITINFO_GLANCING = 0x00010000,
HITINFO_CRUSHING = 0x00020000,
HITINFO_NO_ANIMATION = 0x00040000,
- // 0x00080000
- // 0x00100000
+ HITINFO_UNK19 = 0x00080000,
+ HITINFO_UNK20 = 0x00100000,
HITINFO_SWINGNOHITSOUND = 0x00200000, // unused?
- // 0x00400000
- HITINFO_RAGE_GAIN = 0x00800000
+ HITINFO_UNK22 = 0x00400000,
+ HITINFO_RAGE_GAIN = 0x00800000,
+ HITINFO_FAKE_DAMAGE = 0x01000000 // enables damage animation even if no damage done, set only if no damage
};
//i would like to remove this: (it is defined in item.h
@@ -376,13 +377,7 @@ class SpellCastTargets;
typedef std::list<Unit*> UnitList;
typedef std::list<std::pair<Aura*, uint8>> DispelChargesList;
-struct SpellImmune
-{
- uint32 type;
- uint32 spellId;
-};
-
-typedef std::list<SpellImmune> SpellImmuneList;
+typedef std::unordered_multimap<uint32 /*type*/, uint32 /*spellId*/> SpellImmuneContainer;
enum UnitModifierType
{
@@ -424,12 +419,18 @@ enum TriggerCastFlags
TRIGGERED_IGNORE_SET_FACING = 0x00000200, //! Will not adjust facing to target (if any)
TRIGGERED_IGNORE_SHAPESHIFT = 0x00000400, //! Will ignore shapeshift checks
TRIGGERED_IGNORE_CASTER_AURASTATE = 0x00000800, //! Will ignore caster aura states including combat requirements and death state
+ TRIGGERED_DISALLOW_PROC_EVENTS = 0x00001000, //! Disallows proc events from triggered spell (default)
TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE = 0x00002000, //! Will ignore mounted/on vehicle restrictions
+ // reuse = 0x00004000,
+ // reuse = 0x00008000,
TRIGGERED_IGNORE_CASTER_AURAS = 0x00010000, //! Will ignore caster aura restrictions or requirements
- TRIGGERED_DISALLOW_PROC_EVENTS = 0x00020000, //! Disallows proc events from triggered spell (default)
+ TRIGGERED_DONT_RESET_PERIODIC_TIMER = 0x00020000, //! Will allow periodic aura timers to keep ticking (instead of resetting)
TRIGGERED_DONT_REPORT_CAST_ERROR = 0x00040000, //! Will return SPELL_FAILED_DONT_REPORT in CheckCast functions
+ TRIGGERED_FULL_MASK = 0x0007FFFF, //! Used when doing CastSpell with triggered == true
+
+ // debug flags (used with .cast triggered commands)
TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT = 0x00080000, //! Will ignore equipped item requirements
- TRIGGERED_FULL_MASK = 0xFFFFFFFF
+ TRIGGERED_FULL_DEBUG_MASK = 0xFFFFFFFF
};
enum UnitMods
@@ -801,17 +802,21 @@ namespace Movement{
struct DiminishingReturn
{
- DiminishingReturn(DiminishingGroup group, uint32 t, uint32 count)
- : DRGroup(group), stack(0), hitTime(t), hitCount(count)
- { }
+ DiminishingReturn() : stack(0), hitTime(0), hitCount(DIMINISHING_LEVEL_1) { }
- DiminishingGroup DRGroup:16;
- uint16 stack:16;
+ void Clear()
+ {
+ stack = 0;
+ hitTime = 0;
+ hitCount = DIMINISHING_LEVEL_1;
+ }
+
+ uint16 stack;
uint32 hitTime;
uint32 hitCount;
};
-enum MeleeHitOutcome
+enum MeleeHitOutcome : uint8
{
MELEE_HIT_EVADE, MELEE_HIT_MISS, MELEE_HIT_DODGE, MELEE_HIT_BLOCK, MELEE_HIT_PARRY,
MELEE_HIT_GLANCING, MELEE_HIT_CRIT, MELEE_HIT_CRUSHING, MELEE_HIT_NORMAL
@@ -819,21 +824,18 @@ enum MeleeHitOutcome
class DispelInfo
{
-public:
- explicit DispelInfo(Unit* dispeller, uint32 dispellerSpellId, uint8 chargesRemoved) :
- _dispellerUnit(dispeller), _dispellerSpell(dispellerSpellId), _chargesRemoved(chargesRemoved) { }
+ public:
+ explicit DispelInfo(Unit* dispeller, uint32 dispellerSpellId, uint8 chargesRemoved) :
+ _dispellerUnit(dispeller), _dispellerSpell(dispellerSpellId), _chargesRemoved(chargesRemoved) { }
- Unit* GetDispeller() const { return _dispellerUnit; }
- uint32 GetDispellerSpellId() const { return _dispellerSpell; }
- uint8 GetRemovedCharges() const { return _chargesRemoved; }
- void SetRemovedCharges(uint8 amount)
- {
- _chargesRemoved = amount;
- }
-private:
- Unit* _dispellerUnit;
- uint32 _dispellerSpell;
- uint8 _chargesRemoved;
+ Unit* GetDispeller() const { return _dispellerUnit; }
+ uint32 GetDispellerSpellId() const { return _dispellerSpell; }
+ uint8 GetRemovedCharges() const { return _chargesRemoved; }
+ void SetRemovedCharges(uint8 amount) { _chargesRemoved = amount; }
+ private:
+ Unit* _dispellerUnit;
+ uint32 _dispellerSpell;
+ uint8 _chargesRemoved;
};
struct CleanDamage
@@ -849,103 +851,110 @@ struct CleanDamage
};
struct CalcDamageInfo;
+struct SpellNonMeleeDamage;
class TC_GAME_API DamageInfo
{
-private:
- Unit* const m_attacker;
- Unit* const m_victim;
- uint32 m_damage;
- SpellInfo const* const m_spellInfo;
- SpellSchoolMask const m_schoolMask;
- DamageEffectType const m_damageType;
- WeaponAttackType m_attackType;
- uint32 m_absorb;
- uint32 m_resist;
- uint32 m_block;
-public:
- explicit DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType);
- explicit DamageInfo(CalcDamageInfo& dmgInfo);
-
- void ModifyDamage(int32 amount);
- void AbsorbDamage(uint32 amount);
- void ResistDamage(uint32 amount);
- void BlockDamage(uint32 amount);
-
- Unit* GetAttacker() const { return m_attacker; }
- Unit* GetVictim() const { return m_victim; }
- SpellInfo const* GetSpellInfo() const { return m_spellInfo; }
- SpellSchoolMask GetSchoolMask() const { return m_schoolMask; }
- DamageEffectType GetDamageType() const { return m_damageType; }
- WeaponAttackType GetAttackType() const { return m_attackType; }
- uint32 GetDamage() const { return m_damage; }
- uint32 GetAbsorb() const { return m_absorb; }
- uint32 GetResist() const { return m_resist; }
- uint32 GetBlock() const { return m_block; }
+ private:
+ Unit* const m_attacker;
+ Unit* const m_victim;
+ uint32 m_damage;
+ SpellInfo const* const m_spellInfo;
+ SpellSchoolMask const m_schoolMask;
+ DamageEffectType const m_damageType;
+ WeaponAttackType m_attackType;
+ uint32 m_absorb;
+ uint32 m_resist;
+ uint32 m_block;
+ uint32 m_hitMask;
+ public:
+ DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType);
+ explicit DamageInfo(CalcDamageInfo const& dmgInfo);
+ DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, uint32 hitMask);
+
+ void ModifyDamage(int32 amount);
+ void AbsorbDamage(uint32 amount);
+ void ResistDamage(uint32 amount);
+ void BlockDamage(uint32 amount);
+
+ Unit* GetAttacker() const { return m_attacker; }
+ Unit* GetVictim() const { return m_victim; }
+ SpellInfo const* GetSpellInfo() const { return m_spellInfo; }
+ SpellSchoolMask GetSchoolMask() const { return m_schoolMask; }
+ DamageEffectType GetDamageType() const { return m_damageType; }
+ WeaponAttackType GetAttackType() const { return m_attackType; }
+ uint32 GetDamage() const { return m_damage; }
+ uint32 GetAbsorb() const { return m_absorb; }
+ uint32 GetResist() const { return m_resist; }
+ uint32 GetBlock() const { return m_block; }
+
+ uint32 GetHitMask() const;
};
-class HealInfo
+class TC_GAME_API HealInfo
{
-private:
- Unit* const _healer;
- Unit* const _target;
- uint32 _heal;
- uint32 _absorb;
- SpellInfo const* const _spellInfo;
- SpellSchoolMask const _schoolMask;
+ private:
+ Unit* const _healer;
+ Unit* const _target;
+ uint32 _heal;
+ uint32 _effectiveHeal;
+ uint32 _absorb;
+ SpellInfo const* const _spellInfo;
+ SpellSchoolMask const _schoolMask;
+ uint32 _hitMask;
-public:
- explicit HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask)
- : _healer(healer), _target(target), _heal(heal), _absorb(0), _spellInfo(spellInfo), _schoolMask(schoolMask) { }
+ public:
+ HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask);
- void AbsorbHeal(uint32 amount)
- {
- amount = std::min(amount, GetHeal());
- _absorb += amount;
- _heal -= amount;
- }
+ void AbsorbHeal(uint32 amount);
+ void SetEffectiveHeal(uint32 amount) { _effectiveHeal = amount; }
- Unit* GetHealer() const { return _healer; }
- Unit* GetTarget() const { return _target; }
- uint32 GetHeal() const { return _heal; }
- uint32 GetAbsorb() const { return _absorb; }
- SpellInfo const* GetSpellInfo() const { return _spellInfo; };
- SpellSchoolMask GetSchoolMask() const { return _schoolMask; };
+ Unit* GetHealer() const { return _healer; }
+ Unit* GetTarget() const { return _target; }
+ uint32 GetHeal() const { return _heal; }
+ uint32 GetEffectiveHeal() const { return _effectiveHeal; }
+ uint32 GetAbsorb() const { return _absorb; }
+ SpellInfo const* GetSpellInfo() const { return _spellInfo; };
+ SpellSchoolMask GetSchoolMask() const { return _schoolMask; };
+
+ uint32 GetHitMask() const;
};
class TC_GAME_API ProcEventInfo
{
-public:
- ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask,
- uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask,
- Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo);
+ public:
+ ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask,
+ uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask,
+ Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo);
- Unit* GetActor() { return _actor; }
- Unit* GetActionTarget() const { return _actionTarget; }
- Unit* GetProcTarget() const { return _procTarget; }
+ Unit* GetActor() { return _actor; }
+ Unit* GetActionTarget() const { return _actionTarget; }
+ Unit* GetProcTarget() const { return _procTarget; }
- uint32 GetTypeMask() const { return _typeMask; }
- uint32 GetSpellTypeMask() const { return _spellTypeMask; }
- uint32 GetSpellPhaseMask() const { return _spellPhaseMask; }
- uint32 GetHitMask() const { return _hitMask; }
+ uint32 GetTypeMask() const { return _typeMask; }
+ uint32 GetSpellTypeMask() const { return _spellTypeMask; }
+ uint32 GetSpellPhaseMask() const { return _spellPhaseMask; }
+ uint32 GetHitMask() const { return _hitMask; }
- SpellInfo const* GetSpellInfo() const;
- SpellSchoolMask GetSchoolMask() const;
+ SpellInfo const* GetSpellInfo() const;
+ SpellSchoolMask GetSchoolMask() const;
- DamageInfo* GetDamageInfo() const { return _damageInfo; }
- HealInfo* GetHealInfo() const { return _healInfo; }
+ DamageInfo* GetDamageInfo() const { return _damageInfo; }
+ HealInfo* GetHealInfo() const { return _healInfo; }
-private:
- Unit* const _actor;
- Unit* const _actionTarget;
- Unit* const _procTarget;
- uint32 _typeMask;
- uint32 _spellTypeMask;
- uint32 _spellPhaseMask;
- uint32 _hitMask;
- Spell* _spell;
- DamageInfo* _damageInfo;
- HealInfo* _healInfo;
+ Spell const* GetProcSpell() const { return _spell; }
+
+ private:
+ Unit* const _actor;
+ Unit* const _actionTarget;
+ Unit* const _procTarget;
+ uint32 _typeMask;
+ uint32 _spellTypeMask;
+ uint32 _spellPhaseMask;
+ uint32 _hitMask;
+ Spell* _spell;
+ DamageInfo* _damageInfo;
+ HealInfo* _healInfo;
};
// Struct for use in Unit::CalculateMeleeDamage
@@ -965,7 +974,6 @@ struct CalcDamageInfo
WeaponAttackType attackType; //
uint32 procAttacker;
uint32 procVictim;
- uint32 procEx;
uint32 cleanDamage; // Used only for rage calculation
MeleeHitOutcome hitOutCome; /// @todo remove this field (need use TargetState)
};
@@ -975,7 +983,7 @@ struct TC_GAME_API SpellNonMeleeDamage
{
SpellNonMeleeDamage(Unit* _attacker, Unit* _target, uint32 _SpellID, uint32 _schoolMask)
: target(_target), attacker(_attacker), SpellID(_SpellID), damage(0), overkill(0), schoolMask(_schoolMask),
- absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0)
+ absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0), fullBlock(false)
{ }
Unit *target;
@@ -992,6 +1000,7 @@ struct TC_GAME_API SpellNonMeleeDamage
uint32 HitInfo;
// Used for help
uint32 cleanDamage;
+ bool fullBlock;
};
struct SpellPeriodicAuraLogInfo
@@ -1008,7 +1017,7 @@ struct SpellPeriodicAuraLogInfo
bool critical;
};
-uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition);
+uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition);
struct RedirectThreatInfo
{
@@ -1232,8 +1241,6 @@ enum PlayerTotemType
#define ATTACK_DISPLAY_DELAY 200
#define MAX_PLAYER_STEALTH_DETECT_RANGE 30.0f // max distance for detection targets by player
-struct SpellProcEventEntry; // used only privately
-
class TC_GAME_API Unit : public WorldObject
{
public:
@@ -1254,7 +1261,9 @@ class TC_GAME_API Unit : public WorldObject
typedef std::list<AuraEffect*> AuraEffectList;
typedef std::list<Aura*> AuraList;
typedef std::list<AuraApplication *> AuraApplicationList;
- typedef std::list<DiminishingReturn> Diminishing;
+ typedef std::array<DiminishingReturn, DIMINISHING_MAX> Diminishing;
+
+ typedef std::vector<std::pair<uint8 /*procEffectMask*/, AuraApplication*>> AuraApplicationProcContainer;
typedef std::map<uint8, AuraApplication*> VisibleAuraMap;
@@ -1269,11 +1278,11 @@ class TC_GAME_API Unit : public WorldObject
void CleanupBeforeRemoveFromMap(bool finalCleanup);
void CleanupsBeforeDelete(bool finalCleanup = true) override; // used in ~Creature/~Player (or before mass creature delete to remove cross-references to already deleted units)
- DiminishingLevels GetDiminishing(DiminishingGroup group);
- void IncrDiminishing(DiminishingGroup group);
- float ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration, Unit* caster, DiminishingLevels Level, int32 limitduration);
- void ApplyDiminishingAura(DiminishingGroup group, bool apply);
- void ClearDiminishings() { m_Diminishing.clear(); }
+ DiminishingLevels GetDiminishing(DiminishingGroup group);
+ void IncrDiminishing(SpellInfo const* auraSpellInfo, bool triggered);
+ float ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, bool triggered, int32& duration, Unit* caster, DiminishingLevels previousLevel);
+ void ApplyDiminishingAura(DiminishingGroup group, bool apply);
+ void ClearDiminishings();
// target dependent range checks
float GetSpellMaxRangeForTarget(Unit const* target, SpellInfo const* spellInfo) const;
@@ -1425,25 +1434,26 @@ class TC_GAME_API Unit : public WorldObject
void Dismount();
uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; }
- void DealDamageMods(Unit* victim, uint32 &damage, uint32* absorb);
+ void DealDamageMods(Unit const* victim, uint32 &damage, uint32* absorb) const;
uint32 DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDamage = NULL, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = NULL, bool durabilityLoss = true);
void Kill(Unit* victim, bool durabilityLoss = true);
void KillSelf(bool durabilityLoss = true) { Kill(this, durabilityLoss); }
- int32 DealHeal(Unit* victim, uint32 addhealth);
+ void DealHeal(HealInfo& healInfo);
- void ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpell = NULL, SpellInfo const* procAura = NULL);
- void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpell, uint32 damage, SpellInfo const* procAura = NULL);
+ void ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget,
+ uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell,
+ DamageInfo* damageInfo, HealInfo* healInfo);
- void GetProcAurasTriggeredOnEvent(AuraApplicationList& aurasTriggeringProc, AuraApplicationList* procAuras, ProcEventInfo eventInfo);
+ void GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTriggeringProc, AuraApplicationList* procAuras, ProcEventInfo& eventInfo);
void TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo);
- void TriggerAurasProcOnEvent(AuraApplicationList* myProcAuras, AuraApplicationList* targetProcAuras,
- Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget,
+ void TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget,
uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell,
DamageInfo* damageInfo, HealInfo* healInfo);
- void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationList& procAuras);
+ void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProcContainer& procAuras);
void HandleEmoteCommand(uint32 anim_id);
void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false);
+ void FakeAttackerStateUpdate(Unit* victim, WeaponAttackType attType = BASE_ATTACK);
void CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK);
void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss);
@@ -1470,28 +1480,28 @@ class TC_GAME_API Unit : public WorldObject
void ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type) const;
float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const;
- SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo);
- SpellMissInfo MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo);
+ SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const;
+ SpellMissInfo MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const;
SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect = false);
- float GetUnitDodgeChance() const;
- float GetUnitParryChance() const;
- float GetUnitBlockChance() const;
+ float GetUnitDodgeChance(WeaponAttackType attType, Unit const* victim) const;
+ float GetUnitParryChance(WeaponAttackType attType, Unit const* victim) const;
+ float GetUnitBlockChance(WeaponAttackType attType, Unit const* victim) const;
float GetUnitMissChance(WeaponAttackType attType) const;
- float GetUnitCriticalChance(WeaponAttackType attackType, const Unit* victim) const;
+ float GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victim) const;
int32 GetMechanicResistChance(SpellInfo const* spellInfo) const;
bool CanUseAttackType(uint8 attacktype) const;
- virtual uint32 GetShieldBlockValue() const =0;
+ virtual uint32 GetShieldBlockValue() const = 0;
uint32 GetShieldBlockValue(uint32 soft_cap, uint32 hard_cap) const;
- uint32 GetUnitMeleeSkill(Unit const* target = NULL) const;
- uint32 GetDefenseSkillValue(Unit const* target = NULL) const;
- uint32 GetWeaponSkillValue(WeaponAttackType attType, Unit const* target = NULL) const;
+ uint32 GetUnitMeleeSkill(Unit const* target = nullptr) const;
+ uint32 GetDefenseSkillValue(Unit const* target = nullptr) const;
+ uint32 GetWeaponSkillValue(WeaponAttackType attType, Unit const* target = nullptr) const;
float GetWeaponProcChance() const;
float GetPPMProcChance(uint32 WeaponSpeed, float PPM, const SpellInfo* spellProto) const;
- MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackType attType) const;
- MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const;
+ MeleeHitOutcome RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackType attType) const;
+ MeleeHitOutcome RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const;
bool IsVendor() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_VENDOR); }
bool IsTrainer() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_TRAINER); }
@@ -1547,23 +1557,23 @@ class TC_GAME_API Unit : public WorldObject
virtual void UpdateUnderwaterState(Map* m, float x, float y, float z);
bool isInAccessiblePlaceFor(Creature const* c) const;
- void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false);
- int32 HealBySpell(Unit* victim, SpellInfo const* spellInfo, uint32 addHealth, bool critical = false);
+ void SendHealSpellLog(HealInfo& healInfo, bool critical = false);
+ int32 HealBySpell(HealInfo& healInfo, bool critical = false);
void SendEnergizeSpellLog(Unit* victim, uint32 spellID, int32 damage, Powers powerType);
void EnergizeBySpell(Unit* victim, uint32 SpellID, int32 Damage, Powers powertype);
- uint32 SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage);
-
- void CastSpell(SpellCastTargets const& targets, SpellInfo const* spellInfo, CustomSpellValues const* value, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty);
- void CastSpell(Unit* victim, uint32 spellId, bool triggered, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty);
- void CastSpell(Unit* victim, uint32 spellId, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty);
- void CastSpell(Unit* victim, SpellInfo const* spellInfo, bool triggered, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty);
- void CastSpell(Unit* victim, SpellInfo const* spellInfo, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty);
- void CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty);
- void CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castItem = NULL, AuraEffect* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty);
- void CastCustomSpell(Unit* victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty);
- void CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* victim, bool triggered, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty);
- void CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* victim = NULL, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty);
- void CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit* victim = NULL, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty);
+
+ void CastSpell(SpellCastTargets const& targets, SpellInfo const* spellInfo, CustomSpellValues const* value, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
+ void CastSpell(Unit* victim, uint32 spellId, bool triggered, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
+ void CastSpell(Unit* victim, uint32 spellId, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
+ void CastSpell(Unit* victim, SpellInfo const* spellInfo, bool triggered, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
+ void CastSpell(Unit* victim, SpellInfo const* spellInfo, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
+ void CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
+ void CastSpell(float x, float y, float z, uint32 spellId, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
+ void CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castItem = nullptr, AuraEffect* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
+ void CastCustomSpell(Unit* victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
+ void CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* victim, bool triggered, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
+ void CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* victim = nullptr, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
+ void CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit* victim = nullptr, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
Aura* AddAura(uint32 spellId, Unit* target);
Aura* AddAura(SpellInfo const* spellInfo, uint8 effMask, Unit* target);
void SetAuraStack(uint32 spellId, Unit* target, uint32 stack);
@@ -1704,16 +1714,14 @@ class TC_GAME_API Unit : public WorldObject
bool InitTamedPet(Pet* pet, uint8 level, uint32 spell_id);
// aura apply/remove helpers - you should better not use these
- Aura* _TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount = NULL, Item* castItem = NULL, ObjectGuid casterGUID = ObjectGuid::Empty);
+ Aura* _TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount = nullptr, Item* castItem = nullptr, ObjectGuid casterGUID = ObjectGuid::Empty, bool resetPeriodicTimer = true);
void _AddAura(UnitAura* aura, Unit* caster);
AuraApplication * _CreateAuraApplication(Aura* aura, uint8 effMask);
void _ApplyAuraEffect(Aura* aura, uint8 effIndex);
void _ApplyAura(AuraApplication * aurApp, uint8 effMask);
void _UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode);
void _UnapplyAura(AuraApplication * aurApp, AuraRemoveMode removeMode);
- void _RemoveNoStackAuraApplicationsDueToAura(Aura* aura);
void _RemoveNoStackAurasDueToAura(Aura* aura);
- bool _IsNoStackAuraDueToAura(Aura* appliedAura, Aura* existingAura) const;
void _RegisterAuraEffect(AuraEffect* aurEff, bool apply);
// m_ownedAuras container management
@@ -1929,7 +1937,7 @@ class TC_GAME_API Unit : public WorldObject
void SetPhaseMask(uint32 newPhaseMask, bool update) override;// overwrite WorldObject::SetPhaseMask
void UpdateObjectVisibility(bool forced = true) override;
- SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY];
+ SpellImmuneContainer m_spellImmune[MAX_SPELL_IMMUNITY];
uint32 m_lastSanctuaryTime;
// Threat related methods
@@ -2014,7 +2022,6 @@ class TC_GAME_API Unit : public WorldObject
uint32 GetRemainingPeriodicAmount(ObjectGuid caster, uint32 spellId, AuraType auraType, uint8 effectIndex = 0) const;
void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply);
- void ApplySpellDispelImmunity(const SpellInfo* spellProto, DispelType type, bool apply);
virtual bool IsImmunedToSpell(SpellInfo const* spellInfo) const; // redefined in Creature
uint32 GetSchoolImmunityMask() const;
uint32 GetMechanicImmunityMask() const;
@@ -2026,8 +2033,8 @@ class TC_GAME_API Unit : public WorldObject
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const* spellInfo = NULL, uint8 effIndex = MAX_SPELL_EFFECTS);
uint32 CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = MAX_ATTACK);
uint32 CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) const;
- void CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint32 const damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo = NULL);
- void CalcHealAbsorb(Unit* victim, SpellInfo const* spellInfo, uint32& healAmount, uint32& absorb);
+ void CalcAbsorbResist(DamageInfo& damageInfo);
+ void CalcHealAbsorb(HealInfo& healInfo) const;
void UpdateSpeed(UnitMoveType mtype);
float GetSpeed(UnitMoveType mtype) const;
@@ -2089,7 +2096,7 @@ class TC_GAME_API Unit : public WorldObject
void UpdateAuraForGroup(uint8 slot);
// proc trigger system
- bool CanProc() const {return !m_procDeep;}
+ bool CanProc() const { return !m_procDeep; }
void SetCantProc(bool apply);
// pet auras
@@ -2260,15 +2267,8 @@ class TC_GAME_API Unit : public WorldObject
bool IsAlwaysDetectableFor(WorldObject const* seer) const override;
void DisableSpline();
+
private:
- bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, SpellInfo const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent);
- bool RollProcResult(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, SpellProcEventEntry const* spellProcEvent);
- bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, Milliseconds& cooldown);
- bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, bool* handled);
- bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx);
- bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell);
- bool HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura);
- bool HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura);
void UpdateSplineMovement(uint32 t_diff);
void UpdateSplinePosition();
@@ -2277,6 +2277,8 @@ class TC_GAME_API Unit : public WorldObject
float GetCombatRatingReduction(CombatRating cr) const;
uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const;
+ void ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMask, uint32 hitMask, WeaponAttackType attType);
+
void SetFeared(bool apply);
void SetConfused(bool apply);
void SetStunned(bool apply);
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 781d30f148d..e594cf7f289 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -804,7 +804,10 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction);
if (!factionTemplate)
- TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has non-existing faction template (%u).", cInfo->Entry, cInfo->faction);
+ {
+ TC_LOG_FATAL("sql.sql", "Creature (Entry: %u) has non-existing faction template (%u). This can lead to crashes, aborting.", cInfo->Entry, cInfo->faction);
+ ABORT();
+ }
// used later for scale
CreatureDisplayInfoEntry const* displayScaleEntry = nullptr;
@@ -2545,23 +2548,23 @@ void ObjectMgr::LoadItemTemplates()
itemTemplate.Quality = ITEM_QUALITY_NORMAL;
}
- if (itemTemplate.Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY)
+ if (itemTemplate.Flags2 & ITEM_FLAG2_FACTION_HORDE)
{
if (FactionEntry const* faction = sFactionStore.LookupEntry(HORDE))
if ((itemTemplate.AllowableRace & faction->BaseRepRaceMask[0]) == 0)
- TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has value (%u) in `AllowableRace` races, not compatible with ITEM_FLAGS_EXTRA_HORDE_ONLY (%u) in Flags field, item cannot be equipped or used by these races.",
- entry, itemTemplate.AllowableRace, ITEM_FLAGS_EXTRA_HORDE_ONLY);
+ TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has value (%u) in `AllowableRace` races, not compatible with ITEM_FLAG2_FACTION_HORDE (%u) in Flags field, item cannot be equipped or used by these races.",
+ entry, itemTemplate.AllowableRace, ITEM_FLAG2_FACTION_HORDE);
- if (itemTemplate.Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY)
- TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has value (%u) in `Flags2` flags (ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) and ITEM_FLAGS_EXTRA_HORDE_ONLY (%u) in Flags field, this is a wrong combination.",
- entry, ITEM_FLAGS_EXTRA_ALLIANCE_ONLY, ITEM_FLAGS_EXTRA_HORDE_ONLY);
+ if (itemTemplate.Flags2 & ITEM_FLAG2_FACTION_ALLIANCE)
+ TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has value (%u) in `Flags2` flags (ITEM_FLAG2_FACTION_ALLIANCE) and ITEM_FLAG2_FACTION_HORDE (%u) in Flags field, this is a wrong combination.",
+ entry, ITEM_FLAG2_FACTION_ALLIANCE, ITEM_FLAG2_FACTION_HORDE);
}
- else if (itemTemplate.Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY)
+ else if (itemTemplate.Flags2 & ITEM_FLAG2_FACTION_ALLIANCE)
{
if (FactionEntry const* faction = sFactionStore.LookupEntry(ALLIANCE))
if ((itemTemplate.AllowableRace & faction->BaseRepRaceMask[0]) == 0)
- TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has value (%u) in `AllowableRace` races, not compatible with ITEM_FLAGS_EXTRA_ALLIANCE_ONLY (%u) in Flags field, item cannot be equipped or used by these races.",
- entry, itemTemplate.AllowableRace, ITEM_FLAGS_EXTRA_ALLIANCE_ONLY);
+ TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has value (%u) in `AllowableRace` races, not compatible with ITEM_FLAG2_FACTION_ALLIANCE (%u) in Flags field, item cannot be equipped or used by these races.",
+ entry, itemTemplate.AllowableRace, ITEM_FLAG2_FACTION_ALLIANCE);
}
if (itemTemplate.BuyCount <= 0)
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index ea0a4da8d62..a30d92ad68a 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -428,7 +428,7 @@ struct BroadcastText
std::string const& GetText(LocaleConstant locale = DEFAULT_LOCALE, uint8 gender = GENDER_MALE, bool forceGender = false) const
{
- if (gender == GENDER_FEMALE && (forceGender || !FemaleText[DEFAULT_LOCALE].empty()))
+ if ((gender == GENDER_FEMALE || gender == GENDER_NONE) && (forceGender || !FemaleText[DEFAULT_LOCALE].empty()))
{
if (FemaleText.size() > size_t(locale) && !FemaleText[locale].empty())
return FemaleText[locale];
diff --git a/src/server/game/Grids/GridRefManager.h b/src/server/game/Grids/GridRefManager.h
index 755417d873d..ceaf632aa63 100644
--- a/src/server/game/Grids/GridRefManager.h
+++ b/src/server/game/Grids/GridRefManager.h
@@ -35,8 +35,6 @@ class GridRefManager : public RefManager<GridRefManager<OBJECT>, OBJECT>
iterator begin() { return iterator(getFirst()); }
iterator end() { return iterator(NULL); }
- iterator rbegin() { return iterator(getLast()); }
- iterator rend() { return iterator(NULL); }
};
#endif
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h
index 8304054c663..ac153f31b8e 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.h
@@ -170,6 +170,31 @@ namespace Trinity
// WorldObject searchers & workers
+ // Generic base class to insert elements into arbitrary containers using push_back
+ template<typename Type>
+ class ContainerInserter {
+ using InserterType = void(*)(void*, Type&&);
+
+ void* ref;
+ InserterType inserter;
+
+ // MSVC workaround
+ template<typename T>
+ static void InserterOf(void* ref, Type&& type)
+ {
+ static_cast<T*>(ref)->push_back(std::move(type));
+ }
+
+ protected:
+ template<typename T>
+ ContainerInserter(T& ref_) : ref(&ref_), inserter(&InserterOf<T>) { }
+
+ void Insert(Type type)
+ {
+ inserter(ref, std::move(type));
+ }
+ };
+
template<class Check>
struct WorldObjectSearcher
{
@@ -211,15 +236,16 @@ namespace Trinity
};
template<class Check>
- struct WorldObjectListSearcher
+ struct WorldObjectListSearcher : ContainerInserter<WorldObject*>
{
uint32 i_mapTypeMask;
uint32 i_phaseMask;
- std::list<WorldObject*> &i_objects;
Check& i_check;
- WorldObjectListSearcher(WorldObject const* searcher, std::list<WorldObject*> &objects, Check & check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
- : i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) { }
+ template<typename Container>
+ WorldObjectListSearcher(WorldObject const* searcher, Container& container, Check & check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
+ : ContainerInserter<WorldObject*>(container),
+ i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_check(check) { }
void Visit(PlayerMapType &m);
void Visit(CreatureMapType &m);
@@ -321,14 +347,15 @@ namespace Trinity
};
template<class Check>
- struct GameObjectListSearcher
+ struct GameObjectListSearcher : ContainerInserter<GameObject*>
{
uint32 i_phaseMask;
- std::list<GameObject*> &i_objects;
Check& i_check;
- GameObjectListSearcher(WorldObject const* searcher, std::list<GameObject*> &objects, Check & check)
- : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) { }
+ template<typename Container>
+ GameObjectListSearcher(WorldObject const* searcher, Container& container, Check & check)
+ : ContainerInserter<GameObject*>(container),
+ i_phaseMask(searcher->GetPhaseMask()), i_check(check) { }
void Visit(GameObjectMapType &m);
@@ -393,14 +420,15 @@ namespace Trinity
// All accepted by Check units if any
template<class Check>
- struct UnitListSearcher
+ struct UnitListSearcher : ContainerInserter<Unit*>
{
uint32 i_phaseMask;
- std::list<Unit*> &i_objects;
Check& i_check;
- UnitListSearcher(WorldObject const* searcher, std::list<Unit*> &objects, Check & check)
- : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) { }
+ template<typename Container>
+ UnitListSearcher(WorldObject const* searcher, Container& container, Check& check)
+ : ContainerInserter<Unit*>(container),
+ i_phaseMask(searcher->GetPhaseMask()), i_check(check) { }
void Visit(PlayerMapType &m);
void Visit(CreatureMapType &m);
@@ -442,14 +470,15 @@ namespace Trinity
};
template<class Check>
- struct CreatureListSearcher
+ struct CreatureListSearcher : ContainerInserter<Creature*>
{
uint32 i_phaseMask;
- std::list<Creature*> &i_objects;
Check& i_check;
- CreatureListSearcher(WorldObject const* searcher, std::list<Creature*> &objects, Check & check)
- : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) { }
+ template<typename Container>
+ CreatureListSearcher(WorldObject const* searcher, Container& container, Check & check)
+ : ContainerInserter<Creature*>(container),
+ i_phaseMask(searcher->GetPhaseMask()), i_check(check) { }
void Visit(CreatureMapType &m);
@@ -493,14 +522,15 @@ namespace Trinity
};
template<class Check>
- struct PlayerListSearcher
+ struct PlayerListSearcher : ContainerInserter<Player*>
{
uint32 i_phaseMask;
- std::list<Player*> &i_objects;
Check& i_check;
- PlayerListSearcher(WorldObject const* searcher, std::list<Player*> &objects, Check & check)
- : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) { }
+ template<typename Container>
+ PlayerListSearcher(WorldObject const* searcher, Container& container, Check & check)
+ : ContainerInserter<Player*>(container),
+ i_phaseMask(searcher->GetPhaseMask()), i_check(check) { }
void Visit(PlayerMapType &m);
@@ -612,6 +642,7 @@ namespace Trinity
{
public:
GameObjectFocusCheck(Unit const* unit, uint32 focusId) : i_unit(unit), i_focusId(focusId) { }
+
bool operator()(GameObject* go) const
{
if (go->GetGOInfo()->type != GAMEOBJECT_TYPE_SPELL_FOCUS)
@@ -627,6 +658,7 @@ namespace Trinity
return go->IsWithinDistInMap(i_unit, dist);
}
+
private:
Unit const* i_unit;
uint32 i_focusId;
@@ -637,6 +669,7 @@ namespace Trinity
{
public:
NearestGameObjectFishingHole(WorldObject const& obj, float range) : i_obj(obj), i_range(range) { }
+
bool operator()(GameObject* go)
{
if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_FISHINGHOLE && go->isSpawned() && i_obj.IsWithinDistInMap(go, i_range) && i_obj.IsWithinDistInMap(go, (float)go->GetGOInfo()->fishinghole.radius))
@@ -646,19 +679,20 @@ namespace Trinity
}
return false;
}
- float GetLastRange() const { return i_range; }
+
private:
WorldObject const& i_obj;
- float i_range;
+ float i_range;
// prevent clone
- NearestGameObjectFishingHole(NearestGameObjectFishingHole const&);
+ NearestGameObjectFishingHole(NearestGameObjectFishingHole const&) = delete;
};
class NearestGameObjectCheck
{
public:
- NearestGameObjectCheck(WorldObject const& obj) : i_obj(obj), i_range(999) { }
+ NearestGameObjectCheck(WorldObject const& obj) : i_obj(obj), i_range(999.f) { }
+
bool operator()(GameObject* go)
{
if (i_obj.IsWithinDistInMap(go, i_range))
@@ -668,13 +702,13 @@ namespace Trinity
}
return false;
}
- float GetLastRange() const { return i_range; }
+
private:
WorldObject const& i_obj;
float i_range;
// prevent clone this object
- NearestGameObjectCheck(NearestGameObjectCheck const&);
+ NearestGameObjectCheck(NearestGameObjectCheck const&) = delete;
};
// Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest GO)
@@ -682,6 +716,7 @@ namespace Trinity
{
public:
NearestGameObjectEntryInObjectRangeCheck(WorldObject const& obj, uint32 entry, float range) : i_obj(obj), i_entry(entry), i_range(range) { }
+
bool operator()(GameObject* go)
{
if (go->GetEntry() == i_entry && i_obj.IsWithinDistInMap(go, i_range))
@@ -691,38 +726,39 @@ namespace Trinity
}
return false;
}
- float GetLastRange() const { return i_range; }
+
private:
WorldObject const& i_obj;
uint32 i_entry;
float i_range;
// prevent clone this object
- NearestGameObjectEntryInObjectRangeCheck(NearestGameObjectEntryInObjectRangeCheck const&);
+ NearestGameObjectEntryInObjectRangeCheck(NearestGameObjectEntryInObjectRangeCheck const&) = delete;
};
// Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest GO with a certain type)
class NearestGameObjectTypeInObjectRangeCheck
{
- public:
- NearestGameObjectTypeInObjectRangeCheck(WorldObject const& obj, GameobjectTypes type, float range) : i_obj(obj), i_type(type), i_range(range) { }
- bool operator()(GameObject* go)
- {
- if (go->GetGoType() == i_type && i_obj.IsWithinDistInMap(go, i_range))
+ public:
+ NearestGameObjectTypeInObjectRangeCheck(WorldObject const& obj, GameobjectTypes type, float range) : i_obj(obj), i_type(type), i_range(range) { }
+
+ bool operator()(GameObject* go)
{
- i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check
- return true;
+ if (go->GetGoType() == i_type && i_obj.IsWithinDistInMap(go, i_range))
+ {
+ i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check
+ return true;
+ }
+ return false;
}
- return false;
- }
- float GetLastRange() const { return i_range; }
- private:
- WorldObject const& i_obj;
- GameobjectTypes i_type;
- float i_range;
- // prevent clone this object
- NearestGameObjectTypeInObjectRangeCheck(NearestGameObjectTypeInObjectRangeCheck const&);
+ private:
+ WorldObject const& i_obj;
+ GameobjectTypes i_type;
+ float i_range;
+
+ // prevent clone this object
+ NearestGameObjectTypeInObjectRangeCheck(NearestGameObjectTypeInObjectRangeCheck const&) = delete;
};
// Unit checks
@@ -731,6 +767,7 @@ namespace Trinity
{
public:
MostHPMissingInRange(Unit const* obj, float range, uint32 hp) : i_obj(obj), i_range(range), i_hp(hp) { }
+
bool operator()(Unit* u)
{
if (u->IsAlive() && u->IsInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && u->GetMaxHealth() - u->GetHealth() > i_hp)
@@ -740,6 +777,7 @@ namespace Trinity
}
return false;
}
+
private:
Unit const* i_obj;
float i_range;
@@ -750,7 +788,8 @@ namespace Trinity
{
public:
FriendlyCCedInRange(Unit const* obj, float range) : i_obj(obj), i_range(range) { }
- bool operator()(Unit* u)
+
+ bool operator()(Unit* u) const
{
if (u->IsAlive() && u->IsInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) &&
(u->isFeared() || u->IsCharmed() || u->isFrozen() || u->HasUnitState(UNIT_STATE_STUNNED) || u->HasUnitState(UNIT_STATE_CONFUSED)))
@@ -759,6 +798,7 @@ namespace Trinity
}
return false;
}
+
private:
Unit const* i_obj;
float i_range;
@@ -768,15 +808,15 @@ namespace Trinity
{
public:
FriendlyMissingBuffInRange(Unit const* obj, float range, uint32 spellid) : i_obj(obj), i_range(range), i_spell(spellid) { }
- bool operator()(Unit* u)
+
+ bool operator()(Unit* u) const
{
- if (u->IsAlive() && u->IsInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) &&
- !(u->HasAura(i_spell)))
- {
+ if (u->IsAlive() && u->IsInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && !u->HasAura(i_spell))
return true;
- }
+
return false;
}
+
private:
Unit const* i_obj;
float i_range;
@@ -787,23 +827,26 @@ namespace Trinity
{
public:
AnyUnfriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) { }
- bool operator()(Unit* u)
+
+ bool operator()(Unit* u) const
{
if (u->IsAlive() && i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u))
return true;
- else
- return false;
+
+ return false;
}
+
private:
WorldObject const* i_obj;
Unit const* i_funit;
float i_range;
};
- class AnyUnfriendlyNoTotemUnitInObjectRangeCheck
+ class NearestAttackableNoTotemUnitInObjectRangeCheck
{
public:
- AnyUnfriendlyNoTotemUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) { }
+ NearestAttackableNoTotemUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) { }
+
bool operator()(Unit* u)
{
if (!u->IsAlive())
@@ -812,14 +855,19 @@ namespace Trinity
if (u->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET)
return false;
- if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->IsTotem())
+ if (u->GetTypeId() == TYPEID_UNIT && u->ToCreature()->IsTotem())
return false;
if (!u->isTargetableForAttack(false))
return false;
- return i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u);
+ if (!i_obj->IsWithinDistInMap(u, i_range) || !i_funit->_IsValidAttackTarget(u, nullptr, i_obj))
+ return false;
+
+ i_range = i_obj->GetDistance(*u);
+ return true;
}
+
private:
WorldObject const* i_obj;
Unit const* i_funit;
@@ -830,13 +878,15 @@ namespace Trinity
{
public:
AnyFriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, bool playerOnly = false) : i_obj(obj), i_funit(funit), i_range(range), i_playerOnly(playerOnly) { }
- bool operator()(Unit* u)
+
+ bool operator()(Unit* u) const
{
if (u->IsAlive() && i_obj->IsWithinDistInMap(u, i_range) && i_funit->IsFriendlyTo(u) && (!i_playerOnly || u->GetTypeId() == TYPEID_PLAYER))
return true;
else
return false;
}
+
private:
WorldObject const* i_obj;
Unit const* i_funit;
@@ -847,10 +897,14 @@ namespace Trinity
class AnyGroupedUnitInObjectRangeCheck
{
public:
- AnyGroupedUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, bool raid) : _source(obj), _refUnit(funit), _range(range), _raid(raid) { }
- bool operator()(Unit* u)
+ AnyGroupedUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, bool raid, bool playerOnly = false) : _source(obj), _refUnit(funit), _range(range), _raid(raid), _playerOnly(playerOnly) { }
+
+ bool operator()(Unit* u) const
{
- if (G3D::fuzzyEq(_range, 0))
+ if (G3D::fuzzyEq(_range, 0.0f))
+ return false;
+
+ if (_playerOnly && u->GetTypeId() != TYPEID_PLAYER)
return false;
if (_raid)
@@ -869,19 +923,22 @@ namespace Trinity
Unit const* _refUnit;
float _range;
bool _raid;
+ bool _playerOnly;
};
class AnyUnitInObjectRangeCheck
{
public:
AnyUnitInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) { }
- bool operator()(Unit* u)
+
+ bool operator()(Unit* u) const
{
if (u->IsAlive() && i_obj->IsWithinDistInMap(u, i_range))
return true;
return false;
}
+
private:
WorldObject const* i_obj;
float i_range;
@@ -892,6 +949,7 @@ namespace Trinity
{
public:
NearestAttackableUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) { }
+
bool operator()(Unit* u)
{
if (u->isTargetableForAttack() && i_obj->IsWithinDistInMap(u, i_range) &&
@@ -903,42 +961,40 @@ namespace Trinity
return false;
}
+
private:
WorldObject const* i_obj;
Unit const* i_funit;
float i_range;
// prevent clone this object
- NearestAttackableUnitInObjectRangeCheck(NearestAttackableUnitInObjectRangeCheck const&);
+ NearestAttackableUnitInObjectRangeCheck(NearestAttackableUnitInObjectRangeCheck const&) = delete;
};
class AnyAoETargetUnitInObjectRangeCheck
{
public:
- AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range)
- : i_obj(obj), i_funit(funit), _spellInfo(NULL), i_range(range)
+ AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, SpellInfo const* spellInfo = nullptr)
+ : i_obj(obj), i_funit(funit), _spellInfo(spellInfo), i_range(range)
{
- Unit const* check = i_funit;
- Unit const* owner = i_funit->GetOwner();
- if (owner)
- check = owner;
- i_targetForPlayer = (check->GetTypeId() == TYPEID_PLAYER);
- if (DynamicObject const* dynObj = i_obj->ToDynObject())
- _spellInfo = sSpellMgr->GetSpellInfo(dynObj->GetSpellId());
+ if (!_spellInfo)
+ if (DynamicObject const* dynObj = i_obj->ToDynObject())
+ _spellInfo = sSpellMgr->GetSpellInfo(dynObj->GetSpellId());
}
- bool operator()(Unit* u)
+
+ bool operator()(Unit* u) const
{
// Check contains checks for: live, non-selectable, non-attackable flags, flight check and GM check, ignore totems
if (u->GetTypeId() == TYPEID_UNIT && u->IsTotem())
return false;
- if (i_funit->_IsValidAttackTarget(u, _spellInfo, i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : NULL) && i_obj->IsWithinDistInMap(u, i_range))
- return true;
+ if (_spellInfo && _spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS) && u->GetTypeId() != TYPEID_PLAYER)
+ return false;
- return false;
+ return i_funit->_IsValidAttackTarget(u, _spellInfo, i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : nullptr) && i_obj->IsWithinDistInMap(u, i_range);
}
+
private:
- bool i_targetForPlayer;
WorldObject const* i_obj;
Unit const* i_funit;
SpellInfo const* _spellInfo;
@@ -950,9 +1006,9 @@ namespace Trinity
{
public:
CallOfHelpCreatureInRangeDo(Unit* funit, Unit* enemy, float range)
- : i_funit(funit), i_enemy(enemy), i_range(range)
- { }
- void operator()(Creature* u)
+ : i_funit(funit), i_enemy(enemy), i_range(range) { }
+
+ void operator()(Creature* u) const
{
if (u == i_funit)
return;
@@ -977,27 +1033,16 @@ namespace Trinity
float i_range;
};
- struct AnyDeadUnitCheck
- {
- bool operator()(Unit* u) { return !u->IsAlive(); }
- };
-
- /*
- struct AnyStealthedCheck
- {
- bool operator()(Unit* u) { return u->GetVisibility() == VISIBILITY_GROUP_STEALTH; }
- };
- */
-
// Creature checks
class NearestHostileUnitCheck
{
public:
- explicit NearestHostileUnitCheck(Creature const* creature, float dist = 0, bool playerOnly = false) : me(creature), i_playerOnly(playerOnly)
+ explicit NearestHostileUnitCheck(Creature const* creature, float dist = 0.f, bool playerOnly = false) : me(creature), i_playerOnly(playerOnly)
{
- m_range = (dist == 0 ? 9999 : dist);
+ m_range = (dist == 0.f ? 9999.f : dist);
}
+
bool operator()(Unit* u)
{
if (!me->IsWithinDistInMap(u, m_range))
@@ -1013,21 +1058,22 @@ namespace Trinity
return true;
}
- private:
+ private:
Creature const* me;
float m_range;
bool i_playerOnly;
- NearestHostileUnitCheck(NearestHostileUnitCheck const&);
+ NearestHostileUnitCheck(NearestHostileUnitCheck const&) = delete;
};
class NearestHostileUnitInAttackDistanceCheck
{
public:
- explicit NearestHostileUnitInAttackDistanceCheck(Creature const* creature, float dist = 0) : me(creature)
+ explicit NearestHostileUnitInAttackDistanceCheck(Creature const* creature, float dist = 0.f) : me(creature)
{
- m_range = (dist == 0 ? 9999 : dist);
- m_force = (dist == 0 ? false : true);
+ m_range = (dist == 0.f ? 9999.f : dist);
+ m_force = (dist == 0.f ? false : true);
}
+
bool operator()(Unit* u)
{
if (!me->IsWithinDistInMap(u, m_range))
@@ -1047,21 +1093,20 @@ namespace Trinity
m_range = me->GetDistance(u); // use found unit range as new range limit for next check
return true;
}
- float GetLastRange() const { return m_range; }
+
private:
Creature const* me;
float m_range;
bool m_force;
- NearestHostileUnitInAttackDistanceCheck(NearestHostileUnitInAttackDistanceCheck const&);
+ NearestHostileUnitInAttackDistanceCheck(NearestHostileUnitInAttackDistanceCheck const&) = delete;
};
class NearestHostileUnitInAggroRangeCheck
{
public:
- explicit NearestHostileUnitInAggroRangeCheck(Creature const* creature, bool useLOS = false) : _me(creature), _useLOS(useLOS)
- {
- }
- bool operator()(Unit* u)
+ explicit NearestHostileUnitInAggroRangeCheck(Creature const* creature, bool useLOS = false) : _me(creature), _useLOS(useLOS) { }
+
+ bool operator()(Unit* u) const
{
if (!u->IsHostileTo(_me))
return false;
@@ -1078,20 +1123,19 @@ namespace Trinity
return true;
}
- private:
+ private:
Creature const* _me;
bool _useLOS;
- NearestHostileUnitInAggroRangeCheck(NearestHostileUnitInAggroRangeCheck const&);
+ NearestHostileUnitInAggroRangeCheck(NearestHostileUnitInAggroRangeCheck const&) = delete;
};
class AnyAssistCreatureInRangeCheck
{
public:
AnyAssistCreatureInRangeCheck(Unit* funit, Unit* enemy, float range)
- : i_funit(funit), i_enemy(enemy), i_range(range)
- {
- }
- bool operator()(Creature* u)
+ : i_funit(funit), i_enemy(enemy), i_range(range) { }
+
+ bool operator()(Creature* u) const
{
if (u == i_funit)
return false;
@@ -1109,6 +1153,7 @@ namespace Trinity
return true;
}
+
private:
Unit* const i_funit;
Unit* const i_enemy;
@@ -1137,14 +1182,14 @@ namespace Trinity
i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check
return true;
}
- float GetLastRange() const { return i_range; }
+
private:
Creature* const i_obj;
Unit* const i_enemy;
float i_range;
// prevent clone this object
- NearestAssistCreatureInCreatureRangeCheck(NearestAssistCreatureInCreatureRangeCheck const&);
+ NearestAssistCreatureInCreatureRangeCheck(NearestAssistCreatureInCreatureRangeCheck const&) = delete;
};
// Success at unit in range, range update for next check (this can be use with CreatureLastSearcher to find nearest creature)
@@ -1163,7 +1208,7 @@ namespace Trinity
}
return false;
}
- float GetLastRange() const { return i_range; }
+
private:
WorldObject const& i_obj;
uint32 i_entry;
@@ -1171,14 +1216,15 @@ namespace Trinity
float i_range;
// prevent clone this object
- NearestCreatureEntryWithLiveStateInObjectRangeCheck(NearestCreatureEntryWithLiveStateInObjectRangeCheck const&);
+ NearestCreatureEntryWithLiveStateInObjectRangeCheck(NearestCreatureEntryWithLiveStateInObjectRangeCheck const&) = delete;
};
class AnyPlayerInObjectRangeCheck
{
public:
AnyPlayerInObjectRangeCheck(WorldObject const* obj, float range, bool reqAlive = true) : _obj(obj), _range(range), _reqAlive(reqAlive) { }
- bool operator()(Player* u)
+
+ bool operator()(Player* u) const
{
if (_reqAlive && !u->IsAlive())
return false;
@@ -1198,9 +1244,7 @@ namespace Trinity
class NearestPlayerInObjectRangeCheck
{
public:
- NearestPlayerInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range)
- {
- }
+ NearestPlayerInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) { }
bool operator()(Player* u)
{
@@ -1216,46 +1260,51 @@ namespace Trinity
WorldObject const* i_obj;
float i_range;
- NearestPlayerInObjectRangeCheck(NearestPlayerInObjectRangeCheck const&);
+ NearestPlayerInObjectRangeCheck(NearestPlayerInObjectRangeCheck const&) = delete;
};
class AllFriendlyCreaturesInGrid
{
- public:
- AllFriendlyCreaturesInGrid(Unit const* obj) : unit(obj) { }
- bool operator() (Unit* u)
- {
- if (u->IsAlive() && u->IsVisible() && u->IsFriendlyTo(unit))
- return true;
+ public:
+ AllFriendlyCreaturesInGrid(Unit const* obj) : unit(obj) { }
- return false;
- }
- private:
- Unit const* unit;
+ bool operator()(Unit* u) const
+ {
+ if (u->IsAlive() && u->IsVisible() && u->IsFriendlyTo(unit))
+ return true;
+
+ return false;
+ }
+
+ private:
+ Unit const* unit;
};
class AllGameObjectsWithEntryInRange
{
- public:
- AllGameObjectsWithEntryInRange(const WorldObject* object, uint32 entry, float maxRange) : m_pObject(object), m_uiEntry(entry), m_fRange(maxRange) { }
- bool operator() (GameObject* go)
- {
- if ((!m_uiEntry || go->GetEntry() == m_uiEntry) && m_pObject->IsWithinDist(go, m_fRange, false))
- return true;
+ public:
+ AllGameObjectsWithEntryInRange(const WorldObject* object, uint32 entry, float maxRange) : m_pObject(object), m_uiEntry(entry), m_fRange(maxRange) { }
- return false;
- }
- private:
- const WorldObject* m_pObject;
- uint32 m_uiEntry;
- float m_fRange;
+ bool operator()(GameObject* go) const
+ {
+ if ((!m_uiEntry || go->GetEntry() == m_uiEntry) && m_pObject->IsWithinDist(go, m_fRange, false))
+ return true;
+
+ return false;
+ }
+
+ private:
+ WorldObject const* m_pObject;
+ uint32 m_uiEntry;
+ float m_fRange;
};
class AllCreaturesOfEntryInRange
{
public:
AllCreaturesOfEntryInRange(const WorldObject* object, uint32 entry, float maxRange) : m_pObject(object), m_uiEntry(entry), m_fRange(maxRange) { }
- bool operator() (Unit* unit)
+
+ bool operator()(Unit* unit) const
{
if ((!m_uiEntry || unit->GetEntry() == m_uiEntry) && m_pObject->IsWithinDist(unit, m_fRange, false))
return true;
@@ -1264,63 +1313,69 @@ namespace Trinity
}
private:
- const WorldObject* m_pObject;
+ WorldObject const* m_pObject;
uint32 m_uiEntry;
float m_fRange;
};
class PlayerAtMinimumRangeAway
{
- public:
- PlayerAtMinimumRangeAway(Unit const* unit, float fMinRange) : unit(unit), fRange(fMinRange) { }
- bool operator() (Player* player)
- {
- //No threat list check, must be done explicit if expected to be in combat with creature
- if (!player->IsGameMaster() && player->IsAlive() && !unit->IsWithinDist(player, fRange, false))
- return true;
+ public:
+ PlayerAtMinimumRangeAway(Unit const* unit, float fMinRange) : unit(unit), fRange(fMinRange) { }
- return false;
- }
+ bool operator()(Player* player) const
+ {
+ //No threat list check, must be done explicit if expected to be in combat with creature
+ if (!player->IsGameMaster() && player->IsAlive() && !unit->IsWithinDist(player, fRange, false))
+ return true;
- private:
- Unit const* unit;
- float fRange;
+ return false;
+ }
+
+ private:
+ Unit const* unit;
+ float fRange;
};
class GameObjectInRangeCheck
{
- public:
- GameObjectInRangeCheck(float _x, float _y, float _z, float _range, uint32 _entry = 0) :
- x(_x), y(_y), z(_z), range(_range), entry(_entry) { }
- bool operator() (GameObject* go)
- {
- if (!entry || (go->GetGOInfo() && go->GetGOInfo()->entry == entry))
- return go->IsInRange(x, y, z, range);
- else return false;
- }
- private:
- float x, y, z, range;
- uint32 entry;
+ public:
+ GameObjectInRangeCheck(float _x, float _y, float _z, float _range, uint32 _entry = 0) :
+ x(_x), y(_y), z(_z), range(_range), entry(_entry) { }
+
+ bool operator()(GameObject* go) const
+ {
+ if (!entry || (go->GetGOInfo() && go->GetGOInfo()->entry == entry))
+ return go->IsInRange(x, y, z, range);
+ else return false;
+ }
+
+ private:
+ float x, y, z, range;
+ uint32 entry;
};
class AllWorldObjectsInRange
{
- public:
- AllWorldObjectsInRange(const WorldObject* object, float maxRange) : m_pObject(object), m_fRange(maxRange) { }
- bool operator() (WorldObject* go)
- {
- return m_pObject->IsWithinDist(go, m_fRange, false) && m_pObject->InSamePhase(go);
- }
- private:
- const WorldObject* m_pObject;
- float m_fRange;
+ public:
+ AllWorldObjectsInRange(const WorldObject* object, float maxRange) : m_pObject(object), m_fRange(maxRange) { }
+
+ bool operator()(WorldObject* go) const
+ {
+ return m_pObject->IsWithinDist(go, m_fRange, false) && m_pObject->InSamePhase(go);
+ }
+
+ private:
+ WorldObject const* m_pObject;
+ float m_fRange;
};
class ObjectTypeIdCheck
{
public:
ObjectTypeIdCheck(TypeID typeId, bool equals) : _typeId(typeId), _equals(equals) { }
- bool operator()(WorldObject* object)
+
+ bool operator()(WorldObject* object) const
{
return (object->GetTypeId() == _typeId) == _equals;
}
@@ -1334,7 +1389,8 @@ namespace Trinity
{
public:
ObjectGUIDCheck(ObjectGuid GUID) : _GUID(GUID) { }
- bool operator()(WorldObject* object)
+
+ bool operator()(WorldObject* object) const
{
return object->GetGUID() == _GUID;
}
@@ -1347,6 +1403,7 @@ namespace Trinity
{
public:
UnitAuraCheck(bool present, uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty) : _present(present), _spellId(spellId), _casterGUID(casterGUID) { }
+
bool operator()(Unit* unit) const
{
return unit->HasAura(_spellId, _casterGUID) == _present;
@@ -1377,6 +1434,7 @@ namespace Trinity
for (size_t i = 0; i < i_data_cache.size(); ++i)
delete i_data_cache[i];
}
+
void operator()(Player* p);
private:
diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
index 340531c5883..5a3f41e5351 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
@@ -246,7 +246,7 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(PlayerMapType &m)
for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (i_check(itr->GetSource()))
- i_objects.push_back(itr->GetSource());
+ Insert(itr->GetSource());
}
template<class Check>
@@ -257,7 +257,7 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(CreatureMapType &m)
for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (i_check(itr->GetSource()))
- i_objects.push_back(itr->GetSource());
+ Insert(itr->GetSource());
}
template<class Check>
@@ -268,7 +268,7 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(CorpseMapType &m)
for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (i_check(itr->GetSource()))
- i_objects.push_back(itr->GetSource());
+ Insert(itr->GetSource());
}
template<class Check>
@@ -279,7 +279,7 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(GameObjectMapType &m)
for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (i_check(itr->GetSource()))
- i_objects.push_back(itr->GetSource());
+ Insert(itr->GetSource());
}
template<class Check>
@@ -290,7 +290,7 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(DynamicObjectMapType &m)
for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (i_check(itr->GetSource()))
- i_objects.push_back(itr->GetSource());
+ Insert(itr->GetSource());
}
// Gameobject searchers
@@ -334,7 +334,7 @@ void Trinity::GameObjectListSearcher<Check>::Visit(GameObjectMapType &m)
for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->GetSource()->InSamePhase(i_phaseMask))
if (i_check(itr->GetSource()))
- i_objects.push_back(itr->GetSource());
+ Insert(itr->GetSource());
}
// Unit searchers
@@ -411,7 +411,7 @@ void Trinity::UnitListSearcher<Check>::Visit(PlayerMapType &m)
for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->GetSource()->InSamePhase(i_phaseMask))
if (i_check(itr->GetSource()))
- i_objects.push_back(itr->GetSource());
+ Insert(itr->GetSource());
}
template<class Check>
@@ -420,7 +420,7 @@ void Trinity::UnitListSearcher<Check>::Visit(CreatureMapType &m)
for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->GetSource()->InSamePhase(i_phaseMask))
if (i_check(itr->GetSource()))
- i_objects.push_back(itr->GetSource());
+ Insert(itr->GetSource());
}
// Creature searchers
@@ -464,7 +464,7 @@ void Trinity::CreatureListSearcher<Check>::Visit(CreatureMapType &m)
for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->GetSource()->InSamePhase(i_phaseMask))
if (i_check(itr->GetSource()))
- i_objects.push_back(itr->GetSource());
+ Insert(itr->GetSource());
}
template<class Check>
@@ -473,7 +473,7 @@ void Trinity::PlayerListSearcher<Check>::Visit(PlayerMapType &m)
for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->GetSource()->InSamePhase(i_phaseMask))
if (i_check(itr->GetSource()))
- i_objects.push_back(itr->GetSource());
+ Insert(itr->GetSource());
}
template<class Check>
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index ccfd4845dc3..e99ee78991d 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -1154,7 +1154,7 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject)
if (item->DisenchantID && m_maxEnchantingLevel >= item->RequiredDisenchantSkill)
r->rollVoteMask |= ROLL_FLAG_TYPE_DISENCHANT;
- if (item->Flags2 & ITEM_FLAGS_EXTRA_NEED_ROLL_DISABLED)
+ if (item->Flags2 & ITEM_FLAG2_CAN_ONLY_ROLL_GREED)
r->rollVoteMask &= ~ROLL_FLAG_TYPE_NEED;
loot->items[itemSlot].is_blocked = true;
diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp
index b95d2ed1981..84b2da9b2ea 100644
--- a/src/server/game/Guilds/Guild.cpp
+++ b/src/server/game/Guilds/Guild.cpp
@@ -29,10 +29,13 @@
#include "SocialMgr.h"
#include "Opcodes.h"
-#define MAX_GUILD_BANK_TAB_TEXT_LEN 500
-#define EMBLEM_PRICE 10 * GOLD
-std::string _GetGuildEventString(GuildEvents event)
+size_t const MAX_GUILD_BANK_TAB_TEXT_LEN = 500;
+
+uint32 const EMBLEM_PRICE = 10 * GOLD;
+
+// only used in logs
+char const* GetGuildEventString(GuildEvents event)
{
switch (event)
{
@@ -82,18 +85,13 @@ std::string _GetGuildEventString(GuildEvents event)
return "<None>";
}
-inline uint32 _GetGuildBankTabPrice(uint8 tabId)
+inline uint32 GetGuildBankTabPrice(uint8 tabId)
{
- switch (tabId)
- {
- case 0: return 100;
- case 1: return 250;
- case 2: return 500;
- case 3: return 1000;
- case 4: return 2500;
- case 5: return 5000;
- default: return 0;
- }
+ // these prices are in gold units, not copper
+ static uint32 const tabPrices[GUILD_BANK_MAX_TABS] = { 100, 250, 500, 1000, 2500, 5000 };
+ ASSERT(tabId < GUILD_BANK_MAX_TABS);
+
+ return tabPrices[tabId];
}
void Guild::SendCommandResult(WorldSession* session, GuildCommandType type, GuildCommandError errCode, std::string const& param)
@@ -121,7 +119,7 @@ void Guild::SendSaveEmblemResult(WorldSession* session, GuildEmblemError errCode
Guild::LogHolder::~LogHolder()
{
// Cleanup
- for (GuildLog::iterator itr = m_log.begin(); itr != m_log.end(); ++itr)
+ for (auto itr = m_log.begin(); itr != m_log.end(); ++itr)
delete (*itr);
}
@@ -154,7 +152,7 @@ inline void Guild::LogHolder::AddEvent(SQLTransaction& trans, LogEntry* entry)
inline void Guild::LogHolder::WritePacket(WorldPacket& data) const
{
data << uint8(m_log.size());
- for (GuildLog::const_iterator itr = m_log.begin(); itr != m_log.end(); ++itr)
+ for (auto itr = m_log.begin(); itr != m_log.end(); ++itr)
(*itr)->WritePacket(data);
}
@@ -175,7 +173,7 @@ void Guild::EventLogEntry::SaveToDB(SQLTransaction& trans) const
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_EVENTLOG);
stmt->setUInt32(0, m_guildId);
stmt->setUInt32(1, m_guid);
- CharacterDatabase.ExecuteOrAppend(trans, stmt);
+ trans->Append(stmt);
uint8 index = 0;
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_EVENTLOG);
@@ -186,7 +184,7 @@ void Guild::EventLogEntry::SaveToDB(SQLTransaction& trans) const
stmt->setUInt32(++index, m_playerGuid2);
stmt->setUInt8 (++index, m_newRank);
stmt->setUInt64(++index, m_timestamp);
- CharacterDatabase.ExecuteOrAppend(trans, stmt);
+ trans->Append(stmt);
}
void Guild::EventLogEntry::WritePacket(WorldPacket& data) const
@@ -202,7 +200,7 @@ void Guild::EventLogEntry::WritePacket(WorldPacket& data) const
if (m_eventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || m_eventType == GUILD_EVENT_LOG_DEMOTE_PLAYER)
data << uint8(m_newRank);
// Event timestamp
- data << uint32(::time(NULL) - m_timestamp);
+ data << uint32(::time(nullptr) - m_timestamp);
}
// BankEventLogEntry
@@ -214,7 +212,7 @@ void Guild::BankEventLogEntry::SaveToDB(SQLTransaction& trans) const
stmt->setUInt32( index, m_guildId);
stmt->setUInt32(++index, m_guid);
stmt->setUInt8 (++index, m_bankTabId);
- CharacterDatabase.ExecuteOrAppend(trans, stmt);
+ trans->Append(stmt);
index = 0;
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_BANK_EVENTLOG);
@@ -227,7 +225,7 @@ void Guild::BankEventLogEntry::SaveToDB(SQLTransaction& trans) const
stmt->setUInt16(++index, m_itemStackCount);
stmt->setUInt8 (++index, m_destTabId);
stmt->setUInt64(++index, m_timestamp);
- CharacterDatabase.ExecuteOrAppend(trans, stmt);
+ trans->Append(stmt);
}
void Guild::BankEventLogEntry::WritePacket(WorldPacket& data) const
@@ -252,7 +250,7 @@ void Guild::BankEventLogEntry::WritePacket(WorldPacket& data) const
data << uint32(m_itemOrMoney);
}
- data << uint32(time(NULL) - m_timestamp);
+ data << uint32(time(nullptr) - m_timestamp);
}
// RankInfo
@@ -434,14 +432,16 @@ bool Guild::BankTab::LoadItemFromDB(Field* fields)
void Guild::BankTab::Delete(SQLTransaction& trans, bool removeItemsFromDB)
{
for (uint8 slotId = 0; slotId < GUILD_BANK_MAX_SLOTS; ++slotId)
+ {
if (Item* pItem = m_items[slotId])
{
pItem->RemoveFromWorld();
if (removeItemsFromDB)
pItem->DeleteFromDB(trans);
delete pItem;
- pItem = NULL;
+ pItem = nullptr;
}
+ }
}
inline void Guild::BankTab::WritePacket(WorldPacket& data) const
@@ -491,12 +491,14 @@ bool Guild::BankTab::WriteSlotPacket(WorldPacket& data, uint8 slotId, bool ignor
data << uint8(enchCount); // Number of enchantments
for (uint32 i = PERM_ENCHANTMENT_SLOT; i < MAX_ENCHANTMENT_SLOT; ++i)
+ {
if (uint32 enchId = pItem->GetEnchantmentId(EnchantmentSlot(i)))
{
data << uint8(i);
data << uint32(enchId);
++enchCount;
}
+ }
data.put<uint8>(enchCountPos, enchCount);
}
return true;
@@ -534,7 +536,7 @@ void Guild::BankTab::SetText(std::string const& text)
}
// Sets/removes contents of specified slot.
-// If pItem == NULL contents are removed.
+// If pItem == nullptr contents are removed.
bool Guild::BankTab::SetItem(SQLTransaction& trans, uint8 slotId, Item* item)
{
if (slotId >= GUILD_BANK_MAX_SLOTS)
@@ -546,7 +548,7 @@ bool Guild::BankTab::SetItem(SQLTransaction& trans, uint8 slotId, Item* item)
stmt->setUInt32(0, m_guildId);
stmt->setUInt8 (1, m_tabId);
stmt->setUInt8 (2, slotId);
- CharacterDatabase.ExecuteOrAppend(trans, stmt);
+ trans->Append(stmt);
if (item)
{
@@ -555,13 +557,14 @@ bool Guild::BankTab::SetItem(SQLTransaction& trans, uint8 slotId, Item* item)
stmt->setUInt8 (1, m_tabId);
stmt->setUInt8 (2, slotId);
stmt->setUInt32(3, item->GetGUID().GetCounter());
- CharacterDatabase.ExecuteOrAppend(trans, stmt);
+ trans->Append(stmt);
item->SetGuidValue(ITEM_FIELD_CONTAINED, ObjectGuid::Empty);
item->SetGuidValue(ITEM_FIELD_OWNER, ObjectGuid::Empty);
item->FSetState(ITEM_NEW);
item->SaveToDB(trans); // Not in inventory and can be saved standalone
}
+
return true;
}
@@ -629,7 +632,7 @@ void Guild::Member::SetOfficerNote(std::string const& officerNote)
CharacterDatabase.Execute(stmt);
}
-void Guild::Member::ChangeRank(uint8 newRank)
+void Guild::Member::ChangeRank(SQLTransaction& trans, uint8 newRank)
{
m_rankId = newRank;
@@ -640,7 +643,7 @@ void Guild::Member::ChangeRank(uint8 newRank)
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_MEMBER_RANK);
stmt->setUInt8 (0, newRank);
stmt->setUInt32(1, m_guid.GetCounter());
- CharacterDatabase.Execute(stmt);
+ CharacterDatabase.ExecuteOrAppend(trans, stmt);
}
void Guild::Member::SaveToDB(SQLTransaction& trans) const
@@ -714,7 +717,7 @@ void Guild::Member::WritePacket(WorldPacket& data, bool sendOfficerNote) const
<< uint32(m_zoneId);
if (!m_flags)
- data << float(float(::time(NULL) - m_logoutTime) / DAY);
+ data << float(float(::time(nullptr) - m_logoutTime) / DAY);
data << m_publicNote;
@@ -839,7 +842,7 @@ void Guild::MoveItemData::LogAction(MoveItemData* pFrom) const
inline void Guild::MoveItemData::CopySlots(SlotIds& ids) const
{
- for (ItemPosCountVec::const_iterator itr = m_vec.begin(); itr != m_vec.end(); ++itr)
+ for (auto itr = m_vec.begin(); itr != m_vec.end(); ++itr)
ids.insert(uint8(itr->pos));
}
@@ -853,16 +856,16 @@ bool Guild::PlayerMoveItemData::InitItem()
if (m_pItem->IsNotEmptyBag())
{
m_pPlayer->SendEquipError(EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS, m_pItem);
- m_pItem = NULL;
+ m_pItem = nullptr;
}
// Bound items cannot be put into bank.
else if (!m_pItem->CanBeTraded())
{
m_pPlayer->SendEquipError(EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, m_pItem);
- m_pItem = NULL;
+ m_pItem = nullptr;
}
}
- return (m_pItem != NULL);
+ return (m_pItem != nullptr);
}
void Guild::PlayerMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* /*pOther*/, uint32 splitedAmount)
@@ -877,7 +880,7 @@ void Guild::PlayerMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData*
{
m_pPlayer->MoveItemFromInventory(m_container, m_slotId, true);
m_pItem->DeleteFromInventoryDB(trans);
- m_pItem = NULL;
+ m_pItem = nullptr;
}
}
@@ -906,7 +909,7 @@ inline InventoryResult Guild::PlayerMoveItemData::CanStore(Item* pItem, bool swa
bool Guild::BankMoveItemData::InitItem()
{
m_pItem = m_pGuild->_GetItem(m_container, m_slotId);
- return (m_pItem != NULL);
+ return (m_pItem != nullptr);
}
bool Guild::BankMoveItemData::HasStoreRights(MoveItemData* pOther) const
@@ -944,7 +947,7 @@ void Guild::BankMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* pO
else
{
m_pGuild->_RemoveItem(trans, m_container, m_slotId);
- m_pItem = NULL;
+ m_pItem = nullptr;
}
// Decrease amount of player's remaining items (if item is moved to different tab or to player)
if (!pOther->IsBank() || pOther->GetContainer() != m_container)
@@ -954,14 +957,14 @@ void Guild::BankMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* pO
Item* Guild::BankMoveItemData::StoreItem(SQLTransaction& trans, Item* pItem)
{
if (!pItem)
- return NULL;
+ return nullptr;
BankTab* pTab = m_pGuild->GetBankTab(m_container);
if (!pTab)
- return NULL;
+ return nullptr;
Item* pLastItem = pItem;
- for (ItemPosCountVec::const_iterator itr = m_vec.begin(); itr != m_vec.end(); )
+ for (auto itr = m_vec.begin(); itr != m_vec.end(); )
{
ItemPosCount pos(*itr);
++itr;
@@ -1025,7 +1028,7 @@ Item* Guild::BankMoveItemData::_StoreItem(SQLTransaction& trans, BankTab* pTab,
if (pItem && pTab->SetItem(trans, slotId, pItem))
return pItem;
- return NULL;
+ return nullptr;
}
// Tries to reserve space for source item.
@@ -1065,10 +1068,10 @@ void Guild::BankMoveItemData::CanStoreItemInTab(Item* pItem, uint8 skipSlotId, b
Item* pItemDest = m_pGuild->_GetItem(m_container, slotId);
if (pItemDest == pItem)
- pItemDest = NULL;
+ pItemDest = nullptr;
// If merge skip empty, if not merge skip non-empty
- if ((pItemDest != NULL) != merge)
+ if ((pItemDest != nullptr) != merge)
continue;
_ReserveSpace(slotId, pItem, pItemDest, count);
@@ -1095,7 +1098,7 @@ InventoryResult Guild::BankMoveItemData::CanStore(Item* pItem, bool swap)
Item* pItemDest = m_pGuild->_GetItem(m_container, m_slotId);
// Ignore swapped item (this slot will be empty after move)
if ((pItemDest == pItem) || swap)
- pItemDest = NULL;
+ pItemDest = nullptr;
if (!_ReserveSpace(m_slotId, pItem, pItemDest, count))
return EQUIP_ERR_ITEM_CANT_STACK;
@@ -1128,30 +1131,30 @@ Guild::Guild():
m_createdDate(0),
m_accountsNumber(0),
m_bankMoney(0),
- m_eventLog(NULL)
+ m_eventLog(nullptr)
{
memset(&m_bankEventLog, 0, (GUILD_BANK_MAX_TABS + 1) * sizeof(LogHolder*));
}
Guild::~Guild()
{
- SQLTransaction temp(NULL);
+ SQLTransaction temp(nullptr);
_DeleteBankItems(temp);
// Cleanup
delete m_eventLog;
- m_eventLog = NULL;
+ m_eventLog = nullptr;
for (uint8 tabId = 0; tabId <= GUILD_BANK_MAX_TABS; ++tabId)
{
delete m_bankEventLog[tabId];
- m_bankEventLog[tabId] = NULL;
+ m_bankEventLog[tabId] = nullptr;
}
- for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ for (auto itr = m_members.begin(); itr != m_members.end(); ++itr)
{
delete itr->second;
- itr->second = NULL;
+ itr->second = nullptr;
}
}
@@ -1172,7 +1175,7 @@ bool Guild::Create(Player* pLeader, std::string const& name)
m_info = "";
m_motd = "No message set.";
m_bankMoney = 0;
- m_createdDate = ::time(NULL);
+ m_createdDate = ::time(nullptr);
_CreateLogHolders();
TC_LOG_DEBUG("guild", "GUILD: creating guild [%s] for leader %s (%u)",
@@ -1200,9 +1203,10 @@ bool Guild::Create(Player* pLeader, std::string const& name)
stmt->setUInt64(++index, m_bankMoney);
trans->Append(stmt);
+ _CreateDefaultGuildRanks(trans, pLeaderSession->GetSessionDbLocaleIndex()); // Create default ranks
+ bool ret = AddMember(trans, m_leaderGuid, GR_GUILDMASTER); // Add guildmaster
+
CharacterDatabase.CommitTransaction(trans);
- _CreateDefaultGuildRanks(pLeaderSession->GetSessionDbLocaleIndex()); // Create default ranks
- bool ret = AddMember(m_leaderGuid, GR_GUILDMASTER); // Add guildmaster
if (ret)
sScriptMgr->OnGuildCreate(this, pLeader, name);
@@ -1217,15 +1221,15 @@ void Guild::Disband()
sScriptMgr->OnGuildDisband(this);
_BroadcastEvent(GE_DISBANDED, ObjectGuid::Empty);
+
+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
// Remove all members
while (!m_members.empty())
{
- Members::const_iterator itr = m_members.begin();
- DeleteMember(itr->second->GetGUID(), true);
+ auto itr = m_members.begin();
+ DeleteMember(trans, itr->second->GetGUID(), true);
}
- SQLTransaction trans = CharacterDatabase.BeginTransaction();
-
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD);
stmt->setUInt32(0, m_id);
trans->Append(stmt);
@@ -1313,10 +1317,10 @@ void Guild::HandleRoster(WorldSession* session)
data << m_info;
data << uint32(_GetRanksSize());
- for (Ranks::const_iterator ritr = m_ranks.begin(); ritr != m_ranks.end(); ++ritr)
+ for (auto ritr = m_ranks.begin(); ritr != m_ranks.end(); ++ritr)
ritr->WritePacket(data);
- for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ for (auto itr = m_members.begin(); itr != m_members.end(); ++itr)
itr->second->WritePacket(data, _HasRankRight(session->GetPlayer(), GR_RIGHT_VIEWOFFNOTE));
TC_LOG_DEBUG("guild", "SMSG_GUILD_ROSTER [%s]", session->GetPlayerInfo().c_str());
@@ -1420,7 +1424,9 @@ void Guild::HandleSetLeader(WorldSession* session, std::string const& name)
if (Member* pNewLeader = GetMember(name))
{
_SetLeaderGUID(pNewLeader);
- pOldLeader->ChangeRank(GR_OFFICER);
+
+ SQLTransaction trans(nullptr);
+ pOldLeader->ChangeRank(trans, GR_OFFICER);
_BroadcastEvent(GE_LEADER_CHANGED, ObjectGuid::Empty, player->GetName().c_str(), name.c_str());
}
}
@@ -1436,11 +1442,8 @@ void Guild::HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string
return;
}
- char aux[2];
- sprintf(aux, "%u", tabId);
-
tab->SetInfo(name, icon);
- _BroadcastEvent(GE_BANK_TAB_UPDATED, ObjectGuid::Empty, aux, name.c_str(), icon.c_str());
+ _BroadcastEvent(GE_BANK_TAB_UPDATED, ObjectGuid::Empty, std::to_string(tabId).c_str(), name.c_str(), icon.c_str());
}
void Guild::HandleSetMemberNote(WorldSession* session, std::string const& name, std::string const& note, bool officer)
@@ -1472,12 +1475,10 @@ void Guild::HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string c
rankInfo->SetRights(rights);
_SetRankBankMoneyPerDay(rankId, moneyPerDay);
- for (GuildBankRightsAndSlotsVec::const_iterator itr = rightsAndSlots.begin(); itr != rightsAndSlots.end(); ++itr)
+ for (auto itr = rightsAndSlots.begin(); itr != rightsAndSlots.end(); ++itr)
_SetRankBankTabRightsAndSlots(rankId, *itr);
- char aux[2];
- sprintf(aux, "%u", rankId);
- _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, aux, name.c_str());
+ _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, std::to_string(rankId).c_str(), name.c_str());
}
}
@@ -1497,10 +1498,10 @@ void Guild::HandleBuyBankTab(WorldSession* session, uint8 tabId)
if (tabId != _GetPurchasedTabsSize())
return;
- uint32 tabCost = _GetGuildBankTabPrice(tabId) * GOLD;
- if (!tabCost)
+ if (tabId >= GUILD_BANK_MAX_TABS)
return;
+ uint32 tabCost = GetGuildBankTabPrice(tabId) * GOLD;
if (!player->HasEnoughMoney(tabCost)) // Should not happen, this is checked by client
return;
@@ -1570,7 +1571,8 @@ void Guild::HandleAcceptMember(WorldSession* session)
player->GetTeam() != sObjectMgr->GetPlayerTeamByGUID(GetLeaderGUID()))
return;
- AddMember(player->GetGUID());
+ SQLTransaction trans(nullptr);
+ AddMember(trans, player->GetGUID());
}
void Guild::HandleLeaveMember(WorldSession* session)
@@ -1593,7 +1595,8 @@ void Guild::HandleLeaveMember(WorldSession* session)
}
else
{
- DeleteMember(player->GetGUID(), false, false);
+ SQLTransaction trans(nullptr);
+ DeleteMember(trans, player->GetGUID(), false, false);
_LogEvent(GUILD_EVENT_LOG_LEAVE_GUILD, player->GetGUID().GetCounter());
_BroadcastEvent(GE_LEFT, player->GetGUID(), player->GetName().c_str());
@@ -1627,8 +1630,10 @@ void Guild::HandleRemoveMember(WorldSession* session, std::string const& name)
else
{
ObjectGuid guid = member->GetGUID();
+
// After call to DeleteMember pointer to member becomes invalid
- DeleteMember(guid, false, true);
+ SQLTransaction trans(nullptr);
+ DeleteMember(trans, guid, false, true);
_LogEvent(GUILD_EVENT_LOG_UNINVITE_PLAYER, player->GetGUID().GetCounter(), guid.GetCounter());
_BroadcastEvent(GE_REMOVED, ObjectGuid::Empty, name.c_str(), player->GetName().c_str());
}
@@ -1682,7 +1687,8 @@ void Guild::HandleUpdateMemberRank(WorldSession* session, std::string const& nam
}
uint32 newRankId = member->GetRankId() + (demote ? 1 : -1);
- member->ChangeRank(newRankId);
+ SQLTransaction trans(nullptr);
+ member->ChangeRank(trans, newRankId);
_LogEvent(demote ? GUILD_EVENT_LOG_DEMOTE_PLAYER : GUILD_EVENT_LOG_PROMOTE_PLAYER, player->GetGUID().GetCounter(), member->GetGUID().GetCounter(), newRankId);
_BroadcastEvent(demote ? GE_DEMOTION : GE_PROMOTION, ObjectGuid::Empty, player->GetName().c_str(), name.c_str(), _GetRankName(newRankId).c_str());
}
@@ -1696,12 +1702,11 @@ void Guild::HandleAddNewRank(WorldSession* session, std::string const& name)
// Only leader can add new rank
if (_IsLeader(session->GetPlayer()))
- if (_CreateRank(name, GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK))
- {
- char aux[2];
- sprintf(aux, "%u", size);
- _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, aux, name.c_str());
- }
+ {
+ SQLTransaction trans(nullptr);
+ if (_CreateRank(trans, name, GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK))
+ _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, std::to_string(size).c_str(), name.c_str());
+ }
}
void Guild::HandleRemoveLowestRank(WorldSession* session)
@@ -1973,10 +1978,11 @@ void Guild::LoadRankFromDB(Field* fields)
bool Guild::LoadMemberFromDB(Field* fields)
{
ObjectGuid::LowType lowguid = fields[1].GetUInt32();
- Member *member = new Member(m_id, ObjectGuid(HighGuid::Player, lowguid), fields[2].GetUInt8());
+ Member* member = new Member(m_id, ObjectGuid(HighGuid::Player, lowguid), fields[2].GetUInt8());
if (!member->LoadFromDB(fields))
{
- _DeleteMemberFromDB(lowguid);
+ SQLTransaction trans(nullptr);
+ _DeleteMemberFromDB(trans, lowguid);
delete member;
return false;
}
@@ -2080,6 +2086,8 @@ bool Guild::Validate()
// Min ranks count is 5 and max is 10.
bool broken_ranks = false;
uint8 ranks = _GetRanksSize();
+
+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
if (ranks < GUILD_RANKS_MIN_COUNT || ranks > GUILD_RANKS_MAX_COUNT)
{
TC_LOG_ERROR("guild", "Guild %u has invalid number of ranks, creating new...", m_id);
@@ -2096,24 +2104,20 @@ bool Guild::Validate()
broken_ranks = true;
}
else
- {
- SQLTransaction trans = CharacterDatabase.BeginTransaction();
rankInfo->CreateMissingTabsIfNeeded(_GetPurchasedTabsSize(), trans, true);
- CharacterDatabase.CommitTransaction(trans);
- }
}
}
if (broken_ranks)
{
m_ranks.clear();
- _CreateDefaultGuildRanks(DEFAULT_LOCALE);
+ _CreateDefaultGuildRanks(trans, DEFAULT_LOCALE);
}
// Validate members' data
- for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ for (auto itr = m_members.begin(); itr != m_members.end(); ++itr)
if (itr->second->GetRankId() > _GetRanksSize())
- itr->second->ChangeRank(_GetLowestRankId());
+ itr->second->ChangeRank(trans, _GetLowestRankId());
// Repair the structure of the guild.
// If the guildmaster doesn't exist or isn't member of the guild
@@ -2121,7 +2125,8 @@ bool Guild::Validate()
Member* pLeader = GetMember(m_leaderGuid);
if (!pLeader)
{
- DeleteMember(m_leaderGuid);
+ SQLTransaction trans(nullptr);
+ DeleteMember(trans, m_leaderGuid);
// If no more members left, disband guild
if (m_members.empty())
{
@@ -2134,10 +2139,12 @@ bool Guild::Validate()
// Check config if multiple guildmasters are allowed
if (!sConfigMgr->GetBoolDefault("Guild.AllowMultipleGuildMaster", 0))
- for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ for (auto itr = m_members.begin(); itr != m_members.end(); ++itr)
if (itr->second->GetRankId() == GR_GUILDMASTER && !itr->second->IsSamePlayer(m_leaderGuid))
- itr->second->ChangeRank(GR_OFFICER);
+ itr->second->ChangeRank(trans, GR_OFFICER);
+ if (trans->GetSize() > 0)
+ CharacterDatabase.CommitTransaction(trans);
_UpdateAccountsNumber();
return true;
}
@@ -2148,8 +2155,8 @@ void Guild::BroadcastToGuild(WorldSession* session, bool officerOnly, std::strin
if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK))
{
WorldPacket data;
- ChatHandler::BuildChatPacket(data, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), NULL, msg);
- for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ ChatHandler::BuildChatPacket(data, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), nullptr, msg);
+ for (auto itr = m_members.begin(); itr != m_members.end(); ++itr)
if (Player* player = itr->second->FindConnectedPlayer())
if (player->GetSession() && _HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) &&
!player->GetSocial()->HasIgnore(session->GetPlayer()->GetGUID().GetCounter()))
@@ -2159,7 +2166,7 @@ void Guild::BroadcastToGuild(WorldSession* session, bool officerOnly, std::strin
void Guild::BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const
{
- for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ for (auto itr = m_members.begin(); itr != m_members.end(); ++itr)
if (itr->second->IsRank(rankId))
if (Player* player = itr->second->FindConnectedPlayer())
player->GetSession()->SendPacket(packet);
@@ -2167,7 +2174,7 @@ void Guild::BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const
void Guild::BroadcastPacket(WorldPacket* packet) const
{
- for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ for (auto itr = m_members.begin(); itr != m_members.end(); ++itr)
if (Player* player = itr->second->FindPlayer())
player->GetSession()->SendPacket(packet);
}
@@ -2179,7 +2186,7 @@ void Guild::MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 max
WorldPacket data(SMSG_CALENDAR_FILTER_GUILD);
data << uint32(count); // count placeholder
- for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ for (auto itr = m_members.begin(); itr != m_members.end(); ++itr)
{
// not sure if needed, maybe client checks it as well
if (count >= CALENDAR_MAX_INVITES)
@@ -2206,7 +2213,7 @@ void Guild::MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 max
}
// Members handling
-bool Guild::AddMember(ObjectGuid guid, uint8 rankId)
+bool Guild::AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId)
{
Player* player = ObjectAccessor::FindConnectedPlayer(guid);
// Player cannot be in guild
@@ -2269,7 +2276,6 @@ bool Guild::AddMember(ObjectGuid guid, uint8 rankId)
m_members[lowguid] = member;
}
- SQLTransaction trans(NULL);
member->SaveToDB(trans);
_UpdateAccountsNumber();
@@ -2282,7 +2288,7 @@ bool Guild::AddMember(ObjectGuid guid, uint8 rankId)
return true;
}
-void Guild::DeleteMember(ObjectGuid guid, bool isDisbanding, bool isKicked, bool canDeleteGuild)
+void Guild::DeleteMember(SQLTransaction& trans, ObjectGuid guid, bool isDisbanding, bool isKicked, bool canDeleteGuild)
{
ObjectGuid::LowType lowguid = guid.GetCounter();
Player* player = ObjectAccessor::FindConnectedPlayer(guid);
@@ -2291,9 +2297,9 @@ void Guild::DeleteMember(ObjectGuid guid, bool isDisbanding, bool isKicked, bool
// or when he is removed from guild by gm command
if (m_leaderGuid == guid && !isDisbanding)
{
- Member* oldLeader = NULL;
- Member* newLeader = NULL;
- for (Guild::Members::iterator i = m_members.begin(); i != m_members.end(); ++i)
+ Member* oldLeader = nullptr;
+ Member* newLeader = nullptr;
+ for (auto i = m_members.begin(); i != m_members.end(); ++i)
{
if (i->first == lowguid)
oldLeader = i->second;
@@ -2336,19 +2342,22 @@ void Guild::DeleteMember(ObjectGuid guid, bool isDisbanding, bool isKicked, bool
player->SetRank(0);
}
- _DeleteMemberFromDB(lowguid);
+ _DeleteMemberFromDB(trans, lowguid);
if (!isDisbanding)
_UpdateAccountsNumber();
}
-bool Guild::ChangeMemberRank(ObjectGuid guid, uint8 newRank)
+bool Guild::ChangeMemberRank(SQLTransaction& trans, ObjectGuid guid, uint8 newRank)
{
if (newRank <= _GetLowestRankId()) // Validate rank (allow only existing ranks)
+ {
if (Member* member = GetMember(guid))
{
- member->ChangeRank(newRank);
+ member->ChangeRank(trans, newRank);
return true;
}
+ }
+
return false;
}
@@ -2386,7 +2395,7 @@ void Guild::SetBankTabText(uint8 tabId, std::string const& text)
if (BankTab* pTab = GetBankTab(tabId))
{
pTab->SetText(text);
- pTab->SendText(this, NULL);
+ pTab->SendText(this, nullptr);
}
}
@@ -2416,30 +2425,32 @@ void Guild::_CreateNewBankTab()
trans->Append(stmt);
++tabId;
- for (Ranks::iterator itr = m_ranks.begin(); itr != m_ranks.end(); ++itr)
+ for (auto itr = m_ranks.begin(); itr != m_ranks.end(); ++itr)
(*itr).CreateMissingTabsIfNeeded(tabId, trans, false);
CharacterDatabase.CommitTransaction(trans);
}
-void Guild::_CreateDefaultGuildRanks(LocaleConstant loc)
+void Guild::_CreateDefaultGuildRanks(SQLTransaction& trans, LocaleConstant loc)
{
+ ASSERT(trans);
+
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_RANKS);
stmt->setUInt32(0, m_id);
- CharacterDatabase.Execute(stmt);
+ trans->Append(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_RIGHTS);
stmt->setUInt32(0, m_id);
- CharacterDatabase.Execute(stmt);
+ trans->Append(stmt);
- _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_MASTER, loc), GR_RIGHT_ALL);
- _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_OFFICER, loc), GR_RIGHT_ALL);
- _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_VETERAN, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
- _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_MEMBER, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
- _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_INITIATE, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
+ _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_MASTER, loc), GR_RIGHT_ALL);
+ _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_OFFICER, loc), GR_RIGHT_ALL);
+ _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_VETERAN, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
+ _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_MEMBER, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
+ _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_INITIATE, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
}
-bool Guild::_CreateRank(std::string const& name, uint32 rights)
+bool Guild::_CreateRank(SQLTransaction& trans, std::string const& name, uint32 rights)
{
uint8 newRankId = _GetRanksSize();
if (newRankId >= GUILD_RANKS_MAX_COUNT)
@@ -2449,10 +2460,15 @@ bool Guild::_CreateRank(std::string const& name, uint32 rights)
RankInfo info(m_id, newRankId, name, rights, 0);
m_ranks.push_back(info);
- SQLTransaction trans = CharacterDatabase.BeginTransaction();
+ bool const isInTransaction = bool(trans);
+ if (!isInTransaction)
+ trans = CharacterDatabase.BeginTransaction();
+
info.CreateMissingTabsIfNeeded(_GetPurchasedTabsSize(), trans);
info.SaveToDB(trans);
- CharacterDatabase.CommitTransaction(trans);
+
+ if (!isInTransaction)
+ CharacterDatabase.CommitTransaction(trans);
return true;
}
@@ -2463,7 +2479,7 @@ void Guild::_UpdateAccountsNumber()
{
// We use a set to be sure each element will be unique
std::set<uint32> accountsIdSet;
- for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ for (auto itr = m_members.begin(); itr != m_members.end(); ++itr)
accountsIdSet.insert(itr->second->GetAccountId());
m_accountsNumber = accountsIdSet.size();
@@ -2487,7 +2503,7 @@ void Guild::_DeleteBankItems(SQLTransaction& trans, bool removeItemsFromDB)
{
m_bankTabs[tabId]->Delete(trans, removeItemsFromDB);
delete m_bankTabs[tabId];
- m_bankTabs[tabId] = NULL;
+ m_bankTabs[tabId] = nullptr;
}
m_bankTabs.clear();
}
@@ -2516,13 +2532,16 @@ void Guild::_SetLeaderGUID(Member* pLeader)
if (!pLeader)
return;
+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
m_leaderGuid = pLeader->GetGUID();
- pLeader->ChangeRank(GR_GUILDMASTER);
+ pLeader->ChangeRank(trans, GR_GUILDMASTER);
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_LEADER);
stmt->setUInt32(0, m_leaderGuid.GetCounter());
stmt->setUInt32(1, m_id);
- CharacterDatabase.Execute(stmt);
+ trans->Append(stmt);
+
+ CharacterDatabase.CommitTransaction(trans);
}
void Guild::_SetRankBankMoneyPerDay(uint8 rankId, uint32 moneyPerDay)
@@ -2670,13 +2689,13 @@ inline Item* Guild::_GetItem(uint8 tabId, uint8 slotId) const
{
if (const BankTab* tab = GetBankTab(tabId))
return tab->GetItem(slotId);
- return NULL;
+ return nullptr;
}
inline void Guild::_RemoveItem(SQLTransaction& trans, uint8 tabId, uint8 slotId)
{
if (BankTab* pTab = GetBankTab(tabId))
- pTab->SetItem(trans, slotId, NULL);
+ pTab->SetItem(trans, slotId, nullptr);
}
void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAmount)
@@ -2717,7 +2736,7 @@ void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAm
}
else // 6. No split
{
- // 6.1. Try to merge items in destination (pDest->GetItem() == NULL)
+ // 6.1. Try to merge items in destination (pDest->GetItem() == nullptr)
if (!_DoItemsMove(pSrc, pDest, false)) // Item could not be merged
{
// 6.2. Try to swap items
@@ -2732,7 +2751,7 @@ void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAm
if (!pDest->HasWithdrawRights(pSrc))
return; // Player has no rights to withdraw item from destination (opposite direction)
- // 6.2.3. Swap items (pDest->GetItem() != NULL)
+ // 6.2.3. Swap items (pDest->GetItem() != nullptr)
_DoItemsMove(pSrc, pDest, true);
}
}
@@ -2743,7 +2762,7 @@ void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAm
bool Guild::_DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError, uint32 splitedAmount)
{
Item* pDestItem = pDest->GetItem();
- bool swap = (pDestItem != NULL);
+ bool swap = (pDestItem != nullptr);
Item* pSrcItem = pSrc->GetItem(splitedAmount != 0);
// 1. Can store source item in destination
@@ -2832,7 +2851,7 @@ void Guild::_SendBankContentUpdate(MoveItemData* pSrc, MoveItemData* pDest) cons
void Guild::_SendBankContentUpdate(uint8 tabId, SlotIds slots) const
{
- _SendBankList(NULL, tabId, false, &slots);
+ _SendBankList(nullptr, tabId, false, &slots);
}
void Guild::_BroadcastEvent(GuildEvents guildEvent, ObjectGuid guid, const char* param1, const char* param2, const char* param3) const
@@ -2855,10 +2874,10 @@ void Guild::_BroadcastEvent(GuildEvents guildEvent, ObjectGuid guid, const char*
BroadcastPacket(&data);
- TC_LOG_DEBUG("guild", "SMSG_GUILD_EVENT [Broadcast] Event: %s (%u)", _GetGuildEventString(guildEvent).c_str(), guildEvent);
+ TC_LOG_DEBUG("guild", "SMSG_GUILD_EVENT [Broadcast] Event: %s (%u)", GetGuildEventString(guildEvent), guildEvent);
}
-void Guild::_SendBankList(WorldSession* session /* = NULL*/, uint8 tabId /*= 0*/, bool sendAllSlots /*= false*/, SlotIds *slots /*= NULL*/) const
+void Guild::_SendBankList(WorldSession* session /* = nullptr*/, uint8 tabId /*= 0*/, bool sendAllSlots /*= false*/, SlotIds *slots /*= nullptr*/) const
{
WorldPacket data(SMSG_GUILD_BANK_LIST, 500);
data << uint64(m_bankMoney);
@@ -2882,7 +2901,7 @@ void Guild::_SendBankList(WorldSession* session /* = NULL*/, uint8 tabId /*= 0*/
else if (slots && !slots->empty())
{
data << uint8(slots->size());
- for (SlotIds::const_iterator itr = slots->begin(); itr != slots->end(); ++itr)
+ for (auto itr = slots->begin(); itr != slots->end(); ++itr)
tab->WriteSlotPacket(data, *itr, false);
}
else
@@ -2900,7 +2919,7 @@ void Guild::_SendBankList(WorldSession* session /* = NULL*/, uint8 tabId /*= 0*/
}
else /// @todo - Probably this is just sent to session + those that have sent CMSG_GUILD_BANKER_ACTIVATE
{
- for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ for (auto itr = m_members.begin(); itr != m_members.end(); ++itr)
{
if (!_MemberHasTabRights(itr->second->GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB))
continue;
@@ -2919,7 +2938,7 @@ void Guild::_SendBankList(WorldSession* session /* = NULL*/, uint8 tabId /*= 0*/
void Guild::ResetTimes()
{
- for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
+ for (auto itr = m_members.begin(); itr != m_members.end(); ++itr)
itr->second->ResetValues();
_BroadcastEvent(GE_BANK_TAB_AND_MONEY_UPDATED, ObjectGuid::Empty);
diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h
index e25a3201957..742923f51a1 100644
--- a/src/server/game/Guilds/Guild.h
+++ b/src/server/game/Guilds/Guild.h
@@ -225,54 +225,54 @@ enum GuildMemberFlags
// Emblem info
class TC_GAME_API EmblemInfo
{
-public:
- EmblemInfo() : m_style(0), m_color(0), m_borderStyle(0), m_borderColor(0), m_backgroundColor(0) { }
-
- void LoadFromDB(Field* fields);
- void SaveToDB(ObjectGuid::LowType guildId) const;
- void ReadPacket(WorldPacket& recv);
- void WritePacket(WorldPacket& data) const;
-
- uint32 GetStyle() const { return m_style; }
- uint32 GetColor() const { return m_color; }
- uint32 GetBorderStyle() const { return m_borderStyle; }
- uint32 GetBorderColor() const { return m_borderColor; }
- uint32 GetBackgroundColor() const { return m_backgroundColor; }
-
-private:
- uint32 m_style;
- uint32 m_color;
- uint32 m_borderStyle;
- uint32 m_borderColor;
- uint32 m_backgroundColor;
+ public:
+ EmblemInfo() : m_style(0), m_color(0), m_borderStyle(0), m_borderColor(0), m_backgroundColor(0) { }
+
+ void LoadFromDB(Field* fields);
+ void SaveToDB(ObjectGuid::LowType guildId) const;
+ void ReadPacket(WorldPacket& recv);
+ void WritePacket(WorldPacket& data) const;
+
+ uint32 GetStyle() const { return m_style; }
+ uint32 GetColor() const { return m_color; }
+ uint32 GetBorderStyle() const { return m_borderStyle; }
+ uint32 GetBorderColor() const { return m_borderColor; }
+ uint32 GetBackgroundColor() const { return m_backgroundColor; }
+
+ private:
+ uint32 m_style;
+ uint32 m_color;
+ uint32 m_borderStyle;
+ uint32 m_borderColor;
+ uint32 m_backgroundColor;
};
// Structure for storing guild bank rights and remaining slots together.
class GuildBankRightsAndSlots
{
-public:
- GuildBankRightsAndSlots() : tabId(TAB_UNDEFINED), rights(0), slots(0) { }
- GuildBankRightsAndSlots(uint8 _tabId) : tabId(_tabId), rights(0), slots(0) { }
- GuildBankRightsAndSlots(uint8 _tabId, uint8 _rights, uint32 _slots) : tabId(_tabId), rights(_rights), slots(_slots) { }
-
- void SetGuildMasterValues()
- {
- rights = GUILD_BANK_RIGHT_FULL;
- slots = uint32(GUILD_WITHDRAW_SLOT_UNLIMITED);
- }
-
- void SetTabId(uint8 _tabId) { tabId = _tabId; }
- void SetSlots(uint32 _slots) { slots = _slots; }
- void SetRights(uint8 _rights) { rights = _rights; }
-
- int8 GetTabId() const { return tabId; }
- int32 GetSlots() const { return slots; }
- int8 GetRights() const { return rights; }
-
-private:
- uint8 tabId;
- uint8 rights;
- uint32 slots;
+ public:
+ GuildBankRightsAndSlots() : tabId(TAB_UNDEFINED), rights(0), slots(0) { }
+ GuildBankRightsAndSlots(uint8 _tabId) : tabId(_tabId), rights(0), slots(0) { }
+ GuildBankRightsAndSlots(uint8 _tabId, uint8 _rights, uint32 _slots) : tabId(_tabId), rights(_rights), slots(_slots) { }
+
+ void SetGuildMasterValues()
+ {
+ rights = GUILD_BANK_RIGHT_FULL;
+ slots = uint32(GUILD_WITHDRAW_SLOT_UNLIMITED);
+ }
+
+ void SetTabId(uint8 _tabId) { tabId = _tabId; }
+ void SetSlots(uint32 _slots) { slots = _slots; }
+ void SetRights(uint8 _rights) { rights = _rights; }
+
+ int8 GetTabId() const { return tabId; }
+ int32 GetSlots() const { return slots; }
+ int8 GetRights() const { return rights; }
+
+ private:
+ uint8 tabId;
+ uint8 rights;
+ uint32 slots;
};
typedef std::vector <GuildBankRightsAndSlots> GuildBankRightsAndSlotsVec;
@@ -281,577 +281,577 @@ typedef std::set <uint8> SlotIds;
class TC_GAME_API Guild
{
-private:
- // Class representing guild member
- class Member
- {
- public:
- Member(ObjectGuid::LowType guildId, ObjectGuid guid, uint8 rankId) :
- m_guildId(guildId),
- m_guid(guid),
- m_zoneId(0),
- m_level(0),
- m_class(0),
- m_flags(GUILDMEMBER_STATUS_NONE),
- m_logoutTime(::time(NULL)),
- m_accountId(0),
- m_rankId(rankId)
+ private:
+ // Class representing guild member
+ class Member
{
- memset(m_bankWithdraw, 0, (GUILD_BANK_MAX_TABS + 1) * sizeof(int32));
- }
-
- void SetStats(Player* player);
- void SetStats(std::string const& name, uint8 level, uint8 _class, uint32 zoneId, uint32 accountId);
- bool CheckStats() const;
+ public:
+ Member(ObjectGuid::LowType guildId, ObjectGuid guid, uint8 rankId) :
+ m_guildId(guildId),
+ m_guid(guid),
+ m_zoneId(0),
+ m_level(0),
+ m_class(0),
+ m_flags(GUILDMEMBER_STATUS_NONE),
+ m_logoutTime(::time(nullptr)),
+ m_accountId(0),
+ m_rankId(rankId)
+ {
+ memset(m_bankWithdraw, 0, (GUILD_BANK_MAX_TABS + 1) * sizeof(int32));
+ }
+
+ void SetStats(Player* player);
+ void SetStats(std::string const& name, uint8 level, uint8 _class, uint32 zoneId, uint32 accountId);
+ bool CheckStats() const;
+
+ void SetPublicNote(std::string const& publicNote);
+ void SetOfficerNote(std::string const& officerNote);
+ void SetZoneID(uint32 id) { m_zoneId = id; }
+ void SetLevel(uint8 var) { m_level = var; }
+
+ void AddFlag(uint8 var) { m_flags |= var; }
+ void RemFlag(uint8 var) { m_flags &= ~var; }
+ void ResetFlags() { m_flags = GUILDMEMBER_STATUS_NONE; }
+
+ bool LoadFromDB(Field* fields);
+ void SaveToDB(SQLTransaction& trans) const;
+ void WritePacket(WorldPacket& data, bool sendOfficerNote) const;
+
+ ObjectGuid GetGUID() const { return m_guid; }
+ std::string const& GetName() const { return m_name; }
+ uint32 GetAccountId() const { return m_accountId; }
+ uint8 GetRankId() const { return m_rankId; }
+ uint64 GetLogoutTime() const { return m_logoutTime; }
+ std::string GetPublicNote() const { return m_publicNote; }
+ std::string GetOfficerNote() const { return m_officerNote; }
+ uint8 GetClass() const { return m_class; }
+ uint8 GetLevel() const { return m_level; }
+ uint8 GetFlags() const { return m_flags; }
+ uint32 GetZoneId() const { return m_zoneId; }
+ bool IsOnline() const { return (m_flags & GUILDMEMBER_STATUS_ONLINE); }
+
+ void ChangeRank(SQLTransaction& trans, uint8 newRank);
+
+ inline void UpdateLogoutTime() { m_logoutTime = ::time(nullptr); }
+ inline bool IsRank(uint8 rankId) const { return m_rankId == rankId; }
+ inline bool IsRankNotLower(uint8 rankId) const { return m_rankId <= rankId; }
+ inline bool IsSamePlayer(ObjectGuid guid) const { return m_guid == guid; }
+
+ void UpdateBankWithdrawValue(SQLTransaction& trans, uint8 tabId, uint32 amount);
+ int32 GetBankWithdrawValue(uint8 tabId) const;
+ void ResetValues();
+
+ inline Player* FindPlayer() const { return ObjectAccessor::FindPlayer(m_guid); }
+ inline Player* FindConnectedPlayer() const { return ObjectAccessor::FindConnectedPlayer(m_guid); }
+
+ private:
+ ObjectGuid::LowType m_guildId;
+ // Fields from characters table
+ ObjectGuid m_guid;
+ std::string m_name;
+ uint32 m_zoneId;
+ uint8 m_level;
+ uint8 m_class;
+ uint8 m_flags;
+ uint64 m_logoutTime;
+ uint32 m_accountId;
+ // Fields from guild_member table
+ uint8 m_rankId;
+ std::string m_publicNote;
+ std::string m_officerNote;
+
+ int32 m_bankWithdraw[GUILD_BANK_MAX_TABS + 1];
+ };
+
+ // Base class for event entries
+ class LogEntry
+ {
+ public:
+ LogEntry(ObjectGuid::LowType guildId, uint32 guid) : m_guildId(guildId), m_guid(guid), m_timestamp(::time(nullptr)) { }
+ LogEntry(ObjectGuid::LowType guildId, uint32 guid, time_t timestamp) : m_guildId(guildId), m_guid(guid), m_timestamp(timestamp) { }
+ virtual ~LogEntry() { }
- void SetPublicNote(std::string const& publicNote);
- void SetOfficerNote(std::string const& officerNote);
- void SetZoneID(uint32 id) { m_zoneId = id; }
- void SetLevel(uint8 var) { m_level = var; }
+ uint32 GetGUID() const { return m_guid; }
+ uint64 GetTimestamp() const { return m_timestamp; }
- void AddFlag(uint8 var) { m_flags |= var; }
- void RemFlag(uint8 var) { m_flags &= ~var; }
- void ResetFlags() { m_flags = GUILDMEMBER_STATUS_NONE; }
+ virtual void SaveToDB(SQLTransaction& trans) const = 0;
+ virtual void WritePacket(WorldPacket& data) const = 0;
- bool LoadFromDB(Field* fields);
- void SaveToDB(SQLTransaction& trans) const;
- void WritePacket(WorldPacket& data, bool sendOfficerNote) const;
+ protected:
+ ObjectGuid::LowType m_guildId;
+ uint32 m_guid;
+ uint64 m_timestamp;
+ };
- ObjectGuid GetGUID() const { return m_guid; }
- std::string const& GetName() const { return m_name; }
- uint32 GetAccountId() const { return m_accountId; }
- uint8 GetRankId() const { return m_rankId; }
- uint64 GetLogoutTime() const { return m_logoutTime; }
- std::string GetPublicNote() const { return m_publicNote; }
- std::string GetOfficerNote() const { return m_officerNote; }
- uint8 GetClass() const { return m_class; }
- uint8 GetLevel() const { return m_level; }
- uint8 GetFlags() const { return m_flags; }
- uint32 GetZoneId() const { return m_zoneId; }
- bool IsOnline() const { return (m_flags & GUILDMEMBER_STATUS_ONLINE); }
-
- void ChangeRank(uint8 newRank);
-
- inline void UpdateLogoutTime() { m_logoutTime = ::time(NULL); }
- inline bool IsRank(uint8 rankId) const { return m_rankId == rankId; }
- inline bool IsRankNotLower(uint8 rankId) const { return m_rankId <= rankId; }
- inline bool IsSamePlayer(ObjectGuid guid) const { return m_guid == guid; }
-
- void UpdateBankWithdrawValue(SQLTransaction& trans, uint8 tabId, uint32 amount);
- int32 GetBankWithdrawValue(uint8 tabId) const;
- void ResetValues();
-
- inline Player* FindPlayer() const { return ObjectAccessor::FindPlayer(m_guid); }
- inline Player* FindConnectedPlayer() const { return ObjectAccessor::FindConnectedPlayer(m_guid); }
+ // Event log entry
+ class EventLogEntry : public LogEntry
+ {
+ public:
+ EventLogEntry(ObjectGuid::LowType guildId, uint32 guid, GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank) :
+ LogEntry(guildId, guid), m_eventType(eventType), m_playerGuid1(playerGuid1), m_playerGuid2(playerGuid2), m_newRank(newRank) { }
- private:
- ObjectGuid::LowType m_guildId;
- // Fields from characters table
- ObjectGuid m_guid;
- std::string m_name;
- uint32 m_zoneId;
- uint8 m_level;
- uint8 m_class;
- uint8 m_flags;
- uint64 m_logoutTime;
- uint32 m_accountId;
- // Fields from guild_member table
- uint8 m_rankId;
- std::string m_publicNote;
- std::string m_officerNote;
-
- int32 m_bankWithdraw[GUILD_BANK_MAX_TABS + 1];
- };
-
- // Base class for event entries
- class LogEntry
- {
- public:
- LogEntry(ObjectGuid::LowType guildId, uint32 guid) : m_guildId(guildId), m_guid(guid), m_timestamp(::time(NULL)) { }
- LogEntry(ObjectGuid::LowType guildId, uint32 guid, time_t timestamp) : m_guildId(guildId), m_guid(guid), m_timestamp(timestamp) { }
- virtual ~LogEntry() { }
+ EventLogEntry(ObjectGuid::LowType guildId, uint32 guid, time_t timestamp, GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank) :
+ LogEntry(guildId, guid, timestamp), m_eventType(eventType), m_playerGuid1(playerGuid1), m_playerGuid2(playerGuid2), m_newRank(newRank) { }
- uint32 GetGUID() const { return m_guid; }
- uint64 GetTimestamp() const { return m_timestamp; }
+ ~EventLogEntry() { }
- virtual void SaveToDB(SQLTransaction& trans) const = 0;
- virtual void WritePacket(WorldPacket& data) const = 0;
+ void SaveToDB(SQLTransaction& trans) const override;
+ void WritePacket(WorldPacket& data) const override;
- protected:
- ObjectGuid::LowType m_guildId;
- uint32 m_guid;
- uint64 m_timestamp;
- };
-
- // Event log entry
- class EventLogEntry : public LogEntry
- {
- public:
- EventLogEntry(ObjectGuid::LowType guildId, uint32 guid, GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank) :
- LogEntry(guildId, guid), m_eventType(eventType), m_playerGuid1(playerGuid1), m_playerGuid2(playerGuid2), m_newRank(newRank) { }
+ private:
+ GuildEventLogTypes m_eventType;
+ ObjectGuid::LowType m_playerGuid1;
+ ObjectGuid::LowType m_playerGuid2;
+ uint8 m_newRank;
+ };
- EventLogEntry(ObjectGuid::LowType guildId, uint32 guid, time_t timestamp, GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank) :
- LogEntry(guildId, guid, timestamp), m_eventType(eventType), m_playerGuid1(playerGuid1), m_playerGuid2(playerGuid2), m_newRank(newRank) { }
+ // Bank event log entry
+ class BankEventLogEntry : public LogEntry
+ {
+ public:
+ static bool IsMoneyEvent(GuildBankEventLogTypes eventType)
+ {
+ return
+ eventType == GUILD_BANK_LOG_DEPOSIT_MONEY ||
+ eventType == GUILD_BANK_LOG_WITHDRAW_MONEY ||
+ eventType == GUILD_BANK_LOG_REPAIR_MONEY;
+ }
+
+ BankEventLogEntry(ObjectGuid::LowType guildId, uint32 guid, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) :
+ LogEntry(guildId, guid), m_eventType(eventType), m_bankTabId(tabId), m_playerGuid(playerGuid),
+ m_itemOrMoney(itemOrMoney), m_itemStackCount(itemStackCount), m_destTabId(destTabId) { }
+
+ BankEventLogEntry(ObjectGuid::LowType guildId, uint32 guid, time_t timestamp, uint8 tabId, GuildBankEventLogTypes eventType, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) :
+ LogEntry(guildId, guid, timestamp), m_eventType(eventType), m_bankTabId(tabId), m_playerGuid(playerGuid),
+ m_itemOrMoney(itemOrMoney), m_itemStackCount(itemStackCount), m_destTabId(destTabId) { }
+
+ ~BankEventLogEntry() { }
+
+ void SaveToDB(SQLTransaction& trans) const override;
+ void WritePacket(WorldPacket& data) const override;
+
+ private:
+ GuildBankEventLogTypes m_eventType;
+ uint8 m_bankTabId;
+ ObjectGuid::LowType m_playerGuid;
+ uint32 m_itemOrMoney;
+ uint16 m_itemStackCount;
+ uint8 m_destTabId;
+ };
+
+ // Class encapsulating work with events collection
+ typedef std::list<LogEntry*> GuildLog;
+
+ class LogHolder
+ {
+ public:
+ LogHolder(uint32 maxRecords) : m_maxRecords(maxRecords), m_nextGUID(uint32(GUILD_EVENT_LOG_GUID_UNDEFINED)) { }
+ ~LogHolder();
+
+ uint8 GetSize() const { return uint8(m_log.size()); }
+ // Checks if new log entry can be added to holder when loading from DB
+ inline bool CanInsert() const { return m_log.size() < m_maxRecords; }
+ // Adds event from DB to collection
+ void LoadEvent(LogEntry* entry);
+ // Adds new event to collection and saves it to DB
+ void AddEvent(SQLTransaction& trans, LogEntry* entry);
+ // Writes information about all events to packet
+ void WritePacket(WorldPacket& data) const;
+ uint32 GetNextGUID();
+
+ private:
+ GuildLog m_log;
+ uint32 m_maxRecords;
+ uint32 m_nextGUID;
+ };
+
+ // Class encapsulating guild rank data
+ class RankInfo
+ {
+ public:
+ RankInfo(): m_guildId(0), m_rankId(GUILD_RANK_NONE), m_rights(GR_RIGHT_EMPTY), m_bankMoneyPerDay(0) { }
+ RankInfo(ObjectGuid::LowType guildId) : m_guildId(guildId), m_rankId(GUILD_RANK_NONE), m_rights(GR_RIGHT_EMPTY), m_bankMoneyPerDay(0) { }
+ RankInfo(ObjectGuid::LowType guildId, uint8 rankId, std::string const& name, uint32 rights, uint32 money) :
+ m_guildId(guildId), m_rankId(rankId), m_name(name), m_rights(rights),
+ m_bankMoneyPerDay(rankId != GR_GUILDMASTER ? money : GUILD_WITHDRAW_MONEY_UNLIMITED) { }
- ~EventLogEntry() { }
+ void LoadFromDB(Field* fields);
+ void SaveToDB(SQLTransaction& trans) const;
+ void WritePacket(WorldPacket& data) const;
- void SaveToDB(SQLTransaction& trans) const override;
- void WritePacket(WorldPacket& data) const override;
+ uint8 GetId() const { return m_rankId; }
- private:
- GuildEventLogTypes m_eventType;
- ObjectGuid::LowType m_playerGuid1;
- ObjectGuid::LowType m_playerGuid2;
- uint8 m_newRank;
- };
-
- // Bank event log entry
- class BankEventLogEntry : public LogEntry
- {
- public:
- static bool IsMoneyEvent(GuildBankEventLogTypes eventType)
- {
- return
- eventType == GUILD_BANK_LOG_DEPOSIT_MONEY ||
- eventType == GUILD_BANK_LOG_WITHDRAW_MONEY ||
- eventType == GUILD_BANK_LOG_REPAIR_MONEY;
- }
+ std::string const& GetName() const { return m_name; }
+ void SetName(std::string const& name);
- BankEventLogEntry(ObjectGuid::LowType guildId, uint32 guid, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) :
- LogEntry(guildId, guid), m_eventType(eventType), m_bankTabId(tabId), m_playerGuid(playerGuid),
- m_itemOrMoney(itemOrMoney), m_itemStackCount(itemStackCount), m_destTabId(destTabId) { }
+ uint32 GetRights() const { return m_rights; }
+ void SetRights(uint32 rights);
- BankEventLogEntry(ObjectGuid::LowType guildId, uint32 guid, time_t timestamp, uint8 tabId, GuildBankEventLogTypes eventType, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) :
- LogEntry(guildId, guid, timestamp), m_eventType(eventType), m_bankTabId(tabId), m_playerGuid(playerGuid),
- m_itemOrMoney(itemOrMoney), m_itemStackCount(itemStackCount), m_destTabId(destTabId) { }
+ int32 GetBankMoneyPerDay() const { return m_bankMoneyPerDay; }
- ~BankEventLogEntry() { }
+ void SetBankMoneyPerDay(uint32 money);
- void SaveToDB(SQLTransaction& trans) const override;
- void WritePacket(WorldPacket& data) const override;
+ inline int8 GetBankTabRights(uint8 tabId) const
+ {
+ return tabId < GUILD_BANK_MAX_TABS ? m_bankTabRightsAndSlots[tabId].GetRights() : 0;
+ }
- private:
- GuildBankEventLogTypes m_eventType;
- uint8 m_bankTabId;
- ObjectGuid::LowType m_playerGuid;
- uint32 m_itemOrMoney;
- uint16 m_itemStackCount;
- uint8 m_destTabId;
- };
-
- // Class encapsulating work with events collection
- typedef std::list<LogEntry*> GuildLog;
-
- class LogHolder
- {
- public:
- LogHolder(uint32 maxRecords) : m_maxRecords(maxRecords), m_nextGUID(uint32(GUILD_EVENT_LOG_GUID_UNDEFINED)) { }
- ~LogHolder();
-
- uint8 GetSize() const { return uint8(m_log.size()); }
- // Checks if new log entry can be added to holder when loading from DB
- inline bool CanInsert() const { return m_log.size() < m_maxRecords; }
- // Adds event from DB to collection
- void LoadEvent(LogEntry* entry);
- // Adds new event to collection and saves it to DB
- void AddEvent(SQLTransaction& trans, LogEntry* entry);
- // Writes information about all events to packet
- void WritePacket(WorldPacket& data) const;
- uint32 GetNextGUID();
+ inline int32 GetBankTabSlotsPerDay(uint8 tabId) const
+ {
+ return tabId < GUILD_BANK_MAX_TABS ? m_bankTabRightsAndSlots[tabId].GetSlots() : 0;
+ }
- private:
- GuildLog m_log;
- uint32 m_maxRecords;
- uint32 m_nextGUID;
- };
-
- // Class encapsulating guild rank data
- class RankInfo
- {
- public:
- RankInfo(): m_guildId(0), m_rankId(GUILD_RANK_NONE), m_rights(GR_RIGHT_EMPTY), m_bankMoneyPerDay(0) { }
- RankInfo(ObjectGuid::LowType guildId) : m_guildId(guildId), m_rankId(GUILD_RANK_NONE), m_rights(GR_RIGHT_EMPTY), m_bankMoneyPerDay(0) { }
- RankInfo(ObjectGuid::LowType guildId, uint8 rankId, std::string const& name, uint32 rights, uint32 money) :
- m_guildId(guildId), m_rankId(rankId), m_name(name), m_rights(rights),
- m_bankMoneyPerDay(rankId != GR_GUILDMASTER ? money : GUILD_WITHDRAW_MONEY_UNLIMITED) { }
+ void SetBankTabSlotsAndRights(GuildBankRightsAndSlots rightsAndSlots, bool saveToDB);
+ void CreateMissingTabsIfNeeded(uint8 ranks, SQLTransaction& trans, bool logOnCreate = false);
- void LoadFromDB(Field* fields);
- void SaveToDB(SQLTransaction& trans) const;
- void WritePacket(WorldPacket& data) const;
+ private:
+ ObjectGuid::LowType m_guildId;
- uint8 GetId() const { return m_rankId; }
+ uint8 m_rankId;
+ std::string m_name;
+ uint32 m_rights;
+ uint32 m_bankMoneyPerDay;
+ GuildBankRightsAndSlots m_bankTabRightsAndSlots[GUILD_BANK_MAX_TABS];
+ };
- std::string const& GetName() const { return m_name; }
- void SetName(std::string const& name);
+ class BankTab
+ {
+ public:
+ BankTab(ObjectGuid::LowType guildId, uint8 tabId) : m_guildId(guildId), m_tabId(tabId)
+ {
+ memset(m_items, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*));
+ }
+
+ void LoadFromDB(Field* fields);
+ bool LoadItemFromDB(Field* fields);
+ void Delete(SQLTransaction& trans, bool removeItemsFromDB = false);
+
+ void WritePacket(WorldPacket& data) const;
+ bool WriteSlotPacket(WorldPacket& data, uint8 slotId, bool ignoreEmpty = true) const;
+ void WriteInfoPacket(WorldPacket& data) const
+ {
+ data << m_name;
+ data << m_icon;
+ }
+
+ void SetInfo(std::string const& name, std::string const& icon);
+ void SetText(std::string const& text);
+ void SendText(const Guild* guild, WorldSession* session) const;
+
+ inline Item* GetItem(uint8 slotId) const { return slotId < GUILD_BANK_MAX_SLOTS ? m_items[slotId] : NULL; }
+ bool SetItem(SQLTransaction& trans, uint8 slotId, Item* pItem);
+
+ private:
+ ObjectGuid::LowType m_guildId;
+ uint8 m_tabId;
+
+ Item* m_items[GUILD_BANK_MAX_SLOTS];
+ std::string m_name;
+ std::string m_icon;
+ std::string m_text;
+ };
+
+ // Movement data
+ class MoveItemData
+ {
+ public:
+ MoveItemData(Guild* guild, Player* player, uint8 container, uint8 slotId) : m_pGuild(guild), m_pPlayer(player),
+ m_container(container), m_slotId(slotId), m_pItem(NULL), m_pClonedItem(NULL) { }
+ virtual ~MoveItemData() { }
+
+ virtual bool IsBank() const = 0;
+ // Initializes item pointer. Returns true, if item exists, false otherwise.
+ virtual bool InitItem() = 0;
+ // Checks splited amount against item. Splited amount cannot be more that number of items in stack.
+ virtual bool CheckItem(uint32& splitedAmount);
+ // Defines if player has rights to save item in container
+ virtual bool HasStoreRights(MoveItemData* /*pOther*/) const { return true; }
+ // Defines if player has rights to withdraw item from container
+ virtual bool HasWithdrawRights(MoveItemData* /*pOther*/) const { return true; }
+ // Checks if container can store specified item
+ bool CanStore(Item* pItem, bool swap, bool sendError);
+ // Clones stored item
+ bool CloneItem(uint32 count);
+ // Remove item from container (if splited update items fields)
+ virtual void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount = 0) = 0;
+ // Saves item to container
+ virtual Item* StoreItem(SQLTransaction& trans, Item* pItem) = 0;
+ // Log bank event
+ virtual void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const = 0;
+ // Log GM action
+ virtual void LogAction(MoveItemData* pFrom) const;
+ // Copy slots id from position vector
+ void CopySlots(SlotIds& ids) const;
+
+ Item* GetItem(bool isCloned = false) const { return isCloned ? m_pClonedItem : m_pItem; }
+ uint8 GetContainer() const { return m_container; }
+ uint8 GetSlotId() const { return m_slotId; }
+
+ protected:
+ virtual InventoryResult CanStore(Item* pItem, bool swap) = 0;
+
+ Guild* m_pGuild;
+ Player* m_pPlayer;
+ uint8 m_container;
+ uint8 m_slotId;
+ Item* m_pItem;
+ Item* m_pClonedItem;
+ ItemPosCountVec m_vec;
+ };
+
+ class PlayerMoveItemData : public MoveItemData
+ {
+ public:
+ PlayerMoveItemData(Guild* guild, Player* player, uint8 container, uint8 slotId) :
+ MoveItemData(guild, player, container, slotId) { }
+
+ bool IsBank() const override { return false; }
+ bool InitItem() override;
+ void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount = 0) override;
+ Item* StoreItem(SQLTransaction& trans, Item* pItem) override;
+ void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const override;
+ protected:
+ InventoryResult CanStore(Item* pItem, bool swap) override;
+ };
+
+ class BankMoveItemData : public MoveItemData
+ {
+ public:
+ BankMoveItemData(Guild* guild, Player* player, uint8 container, uint8 slotId) :
+ MoveItemData(guild, player, container, slotId) { }
+
+ bool IsBank() const override { return true; }
+ bool InitItem() override;
+ bool HasStoreRights(MoveItemData* pOther) const override;
+ bool HasWithdrawRights(MoveItemData* pOther) const override;
+ void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount) override;
+ Item* StoreItem(SQLTransaction& trans, Item* pItem) override;
+ void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const override;
+ void LogAction(MoveItemData* pFrom) const override;
+
+ protected:
+ InventoryResult CanStore(Item* pItem, bool swap) override;
+
+ private:
+ Item* _StoreItem(SQLTransaction& trans, BankTab* pTab, Item* pItem, ItemPosCount& pos, bool clone) const;
+ bool _ReserveSpace(uint8 slotId, Item* pItem, Item* pItemDest, uint32& count);
+ void CanStoreItemInTab(Item* pItem, uint8 skipSlotId, bool merge, uint32& count);
+ };
+
+ typedef std::unordered_map<uint32, Member*> Members;
+ typedef std::vector<RankInfo> Ranks;
+ typedef std::vector<BankTab*> BankTabs;
- uint32 GetRights() const { return m_rights; }
- void SetRights(uint32 rights);
+ public:
+ static void SendCommandResult(WorldSession* session, GuildCommandType type, GuildCommandError errCode, std::string const& param = "");
+ static void SendSaveEmblemResult(WorldSession* session, GuildEmblemError errCode);
- int32 GetBankMoneyPerDay() const { return m_bankMoneyPerDay; }
+ Guild();
+ ~Guild();
- void SetBankMoneyPerDay(uint32 money);
+ bool Create(Player* pLeader, std::string const& name);
+ void Disband();
- inline int8 GetBankTabRights(uint8 tabId) const
+ // Getters
+ ObjectGuid::LowType GetId() const { return m_id; }
+ ObjectGuid GetLeaderGUID() const { return m_leaderGuid; }
+ std::string const& GetName() const { return m_name; }
+ std::string const& GetMOTD() const { return m_motd; }
+ std::string const& GetInfo() const { return m_info; }
+ uint32 GetMemberCount() const { return m_members.size(); }
+ time_t GetCreatedDate() const { return m_createdDate; }
+ uint64 GetBankMoney() const { return m_bankMoney; }
+
+ bool SetName(std::string const& name);
+
+ // Handle client commands
+ void HandleRoster(WorldSession* session);
+ void HandleQuery(WorldSession* session);
+ void HandleSetMOTD(WorldSession* session, std::string const& motd);
+ void HandleSetInfo(WorldSession* session, std::string const& info);
+ void HandleSetEmblem(WorldSession* session, const EmblemInfo& emblemInfo);
+ void HandleSetLeader(WorldSession* session, std::string const& name);
+ void HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string const& name, std::string const& icon);
+ void HandleSetMemberNote(WorldSession* session, std::string const& name, std::string const& note, bool officer);
+ void HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string const& name, uint32 rights, uint32 moneyPerDay, const GuildBankRightsAndSlotsVec& rightsAndSlots);
+ void HandleBuyBankTab(WorldSession* session, uint8 tabId);
+ void HandleInviteMember(WorldSession* session, std::string const& name);
+ void HandleAcceptMember(WorldSession* session);
+ void HandleLeaveMember(WorldSession* session);
+ void HandleRemoveMember(WorldSession* session, std::string const& name);
+ void HandleUpdateMemberRank(WorldSession* session, std::string const& name, bool demote);
+ void HandleAddNewRank(WorldSession* session, std::string const& name);
+ void HandleRemoveRank(WorldSession* session, uint8 rankId);
+ void HandleRemoveLowestRank(WorldSession* session);
+ void HandleMemberDepositMoney(WorldSession* session, uint32 amount);
+ bool HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool repair = false);
+ void HandleMemberLogout(WorldSession* session);
+ void HandleDisband(WorldSession* session);
+
+ void UpdateMemberData(Player* player, uint8 dataid, uint32 value);
+ void OnPlayerStatusChange(Player* player, uint32 flag, bool state);
+
+ // Send info to client
+ void SendInfo(WorldSession* session) const;
+ void SendEventLog(WorldSession* session) const;
+ void SendBankLog(WorldSession* session, uint8 tabId) const;
+ void SendBankTabsInfo(WorldSession* session, bool showTabs = false) const;
+ void SendBankTabData(WorldSession* session, uint8 tabId) const;
+ void SendBankTabText(WorldSession* session, uint8 tabId) const;
+ void SendPermissions(WorldSession* session) const;
+ void SendMoneyInfo(WorldSession* session) const;
+ void SendLoginInfo(WorldSession* session);
+
+ // Load from DB
+ bool LoadFromDB(Field* fields);
+ void LoadRankFromDB(Field* fields);
+ bool LoadMemberFromDB(Field* fields);
+ bool LoadEventLogFromDB(Field* fields);
+ void LoadBankRightFromDB(Field* fields);
+ void LoadBankTabFromDB(Field* fields);
+ bool LoadBankEventLogFromDB(Field* fields);
+ bool LoadBankItemFromDB(Field* fields);
+ bool Validate();
+
+ // Broadcasts
+ void BroadcastToGuild(WorldSession* session, bool officerOnly, std::string const& msg, uint32 language = LANG_UNIVERSAL) const;
+ void BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const;
+ void BroadcastPacket(WorldPacket* packet) const;
+
+ void MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 maxLevel, uint32 minRank);
+
+ template<class Do>
+ void BroadcastWorker(Do& _do, Player* except = nullptr)
{
- return tabId < GUILD_BANK_MAX_TABS ? m_bankTabRightsAndSlots[tabId].GetRights() : 0;
+ for (auto itr = m_members.begin(); itr != m_members.end(); ++itr)
+ if (Player* player = itr->second->FindConnectedPlayer())
+ if (player != except)
+ _do(player);
}
- inline int32 GetBankTabSlotsPerDay(uint8 tabId) const
- {
- return tabId < GUILD_BANK_MAX_TABS ? m_bankTabRightsAndSlots[tabId].GetSlots() : 0;
- }
+ // Members
+ // Adds member to guild. If rankId == GUILD_RANK_NONE, lowest rank is assigned.
+ bool AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId = GUILD_RANK_NONE);
+ void DeleteMember(SQLTransaction& trans, ObjectGuid guid, bool isDisbanding = false, bool isKicked = false, bool canDeleteGuild = false);
+ bool ChangeMemberRank(SQLTransaction& trans, ObjectGuid guid, uint8 newRank);
- void SetBankTabSlotsAndRights(GuildBankRightsAndSlots rightsAndSlots, bool saveToDB);
- void CreateMissingTabsIfNeeded(uint8 ranks, SQLTransaction& trans, bool logOnCreate = false);
+ // Bank
+ void SwapItems(Player* player, uint8 tabId, uint8 slotId, uint8 destTabId, uint8 destSlotId, uint32 splitedAmount);
+ void SwapItemsWithInventory(Player* player, bool toChar, uint8 tabId, uint8 slotId, uint8 playerBag, uint8 playerSlotId, uint32 splitedAmount);
- private:
- ObjectGuid::LowType m_guildId;
+ // Bank tabs
+ void SetBankTabText(uint8 tabId, std::string const& text);
- uint8 m_rankId;
+ void ResetTimes();
+
+ protected:
+ ObjectGuid::LowType m_id;
std::string m_name;
- uint32 m_rights;
- uint32 m_bankMoneyPerDay;
- GuildBankRightsAndSlots m_bankTabRightsAndSlots[GUILD_BANK_MAX_TABS];
- };
+ ObjectGuid m_leaderGuid;
+ std::string m_motd;
+ std::string m_info;
+ time_t m_createdDate;
- class BankTab
- {
- public:
- BankTab(ObjectGuid::LowType guildId, uint8 tabId) : m_guildId(guildId), m_tabId(tabId)
- {
- memset(m_items, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*));
- }
+ EmblemInfo m_emblemInfo;
+ uint32 m_accountsNumber;
+ uint64 m_bankMoney;
- void LoadFromDB(Field* fields);
- bool LoadItemFromDB(Field* fields);
- void Delete(SQLTransaction& trans, bool removeItemsFromDB = false);
+ Ranks m_ranks;
+ Members m_members;
+ BankTabs m_bankTabs;
- void WritePacket(WorldPacket& data) const;
- bool WriteSlotPacket(WorldPacket& data, uint8 slotId, bool ignoreEmpty = true) const;
- void WriteInfoPacket(WorldPacket& data) const
+ // These are actually ordered lists. The first element is the oldest entry.
+ LogHolder* m_eventLog;
+ LogHolder* m_bankEventLog[GUILD_BANK_MAX_TABS + 1];
+
+ private:
+ inline uint8 _GetRanksSize() const { return uint8(m_ranks.size()); }
+ inline RankInfo const* GetRankInfo(uint8 rankId) const { return rankId < _GetRanksSize() ? &m_ranks[rankId] : nullptr; }
+ inline RankInfo* GetRankInfo(uint8 rankId) { return rankId < _GetRanksSize() ? &m_ranks[rankId] : nullptr; }
+ inline bool _HasRankRight(Player* player, uint32 right) const
{
- data << m_name;
- data << m_icon;
+ if (player)
+ if (Member const* member = GetMember(player->GetGUID()))
+ return (_GetRankRights(member->GetRankId()) & right) != GR_RIGHT_EMPTY;
+ return false;
}
- void SetInfo(std::string const& name, std::string const& icon);
- void SetText(std::string const& text);
- void SendText(const Guild* guild, WorldSession* session) const;
+ inline uint8 _GetLowestRankId() const { return uint8(m_ranks.size() - 1); }
- inline Item* GetItem(uint8 slotId) const { return slotId < GUILD_BANK_MAX_SLOTS ? m_items[slotId] : NULL; }
- bool SetItem(SQLTransaction& trans, uint8 slotId, Item* pItem);
+ inline uint8 _GetPurchasedTabsSize() const { return uint8(m_bankTabs.size()); }
+ inline BankTab* GetBankTab(uint8 tabId) { return tabId < m_bankTabs.size() ? m_bankTabs[tabId] : nullptr; }
+ inline BankTab const* GetBankTab(uint8 tabId) const { return tabId < m_bankTabs.size() ? m_bankTabs[tabId] : nullptr; }
- private:
- ObjectGuid::LowType m_guildId;
- uint8 m_tabId;
-
- Item* m_items[GUILD_BANK_MAX_SLOTS];
- std::string m_name;
- std::string m_icon;
- std::string m_text;
- };
+ inline Member const* GetMember(ObjectGuid guid) const
+ {
+ auto itr = m_members.find(guid.GetCounter());
+ return itr != m_members.end() ? itr->second : nullptr;
+ }
- // Movement data
- class MoveItemData
- {
- public:
- MoveItemData(Guild* guild, Player* player, uint8 container, uint8 slotId) : m_pGuild(guild), m_pPlayer(player),
- m_container(container), m_slotId(slotId), m_pItem(NULL), m_pClonedItem(NULL) { }
- virtual ~MoveItemData() { }
-
- virtual bool IsBank() const = 0;
- // Initializes item pointer. Returns true, if item exists, false otherwise.
- virtual bool InitItem() = 0;
- // Checks splited amount against item. Splited amount cannot be more that number of items in stack.
- virtual bool CheckItem(uint32& splitedAmount);
- // Defines if player has rights to save item in container
- virtual bool HasStoreRights(MoveItemData* /*pOther*/) const { return true; }
- // Defines if player has rights to withdraw item from container
- virtual bool HasWithdrawRights(MoveItemData* /*pOther*/) const { return true; }
- // Checks if container can store specified item
- bool CanStore(Item* pItem, bool swap, bool sendError);
- // Clones stored item
- bool CloneItem(uint32 count);
- // Remove item from container (if splited update items fields)
- virtual void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount = 0) = 0;
- // Saves item to container
- virtual Item* StoreItem(SQLTransaction& trans, Item* pItem) = 0;
- // Log bank event
- virtual void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const = 0;
- // Log GM action
- virtual void LogAction(MoveItemData* pFrom) const;
- // Copy slots id from position vector
- void CopySlots(SlotIds& ids) const;
-
- Item* GetItem(bool isCloned = false) const { return isCloned ? m_pClonedItem : m_pItem; }
- uint8 GetContainer() const { return m_container; }
- uint8 GetSlotId() const { return m_slotId; }
+ inline Member* GetMember(ObjectGuid guid)
+ {
+ auto itr = m_members.find(guid.GetCounter());
+ return itr != m_members.end() ? itr->second : nullptr;
+ }
- protected:
- virtual InventoryResult CanStore(Item* pItem, bool swap) = 0;
-
- Guild* m_pGuild;
- Player* m_pPlayer;
- uint8 m_container;
- uint8 m_slotId;
- Item* m_pItem;
- Item* m_pClonedItem;
- ItemPosCountVec m_vec;
- };
-
- class PlayerMoveItemData : public MoveItemData
- {
- public:
- PlayerMoveItemData(Guild* guild, Player* player, uint8 container, uint8 slotId) :
- MoveItemData(guild, player, container, slotId) { }
-
- bool IsBank() const override { return false; }
- bool InitItem() override;
- void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount = 0) override;
- Item* StoreItem(SQLTransaction& trans, Item* pItem) override;
- void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const override;
- protected:
- InventoryResult CanStore(Item* pItem, bool swap) override;
- };
+ inline Member* GetMember(std::string const& name)
+ {
+ for (auto itr = m_members.begin(); itr != m_members.end(); ++itr)
+ if (itr->second->GetName() == name)
+ return itr->second;
- class BankMoveItemData : public MoveItemData
- {
- public:
- BankMoveItemData(Guild* guild, Player* player, uint8 container, uint8 slotId) :
- MoveItemData(guild, player, container, slotId) { }
-
- bool IsBank() const override { return true; }
- bool InitItem() override;
- bool HasStoreRights(MoveItemData* pOther) const override;
- bool HasWithdrawRights(MoveItemData* pOther) const override;
- void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount) override;
- Item* StoreItem(SQLTransaction& trans, Item* pItem) override;
- void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const override;
- void LogAction(MoveItemData* pFrom) const override;
+ return nullptr;
+ }
- protected:
- InventoryResult CanStore(Item* pItem, bool swap) override;
+ inline void _DeleteMemberFromDB(SQLTransaction& trans, ObjectGuid::LowType lowguid) const
+ {
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_MEMBER);
+ stmt->setUInt32(0, lowguid);
+ CharacterDatabase.ExecuteOrAppend(trans, stmt);
+ }
- private:
- Item* _StoreItem(SQLTransaction& trans, BankTab* pTab, Item* pItem, ItemPosCount& pos, bool clone) const;
- bool _ReserveSpace(uint8 slotId, Item* pItem, Item* pItemDest, uint32& count);
- void CanStoreItemInTab(Item* pItem, uint8 skipSlotId, bool merge, uint32& count);
- };
-
- typedef std::unordered_map<uint32, Member*> Members;
- typedef std::vector<RankInfo> Ranks;
- typedef std::vector<BankTab*> BankTabs;
-
-public:
- static void SendCommandResult(WorldSession* session, GuildCommandType type, GuildCommandError errCode, std::string const& param = "");
- static void SendSaveEmblemResult(WorldSession* session, GuildEmblemError errCode);
-
- Guild();
- ~Guild();
-
- bool Create(Player* pLeader, std::string const& name);
- void Disband();
-
- // Getters
- ObjectGuid::LowType GetId() const { return m_id; }
- ObjectGuid GetLeaderGUID() const { return m_leaderGuid; }
- std::string const& GetName() const { return m_name; }
- std::string const& GetMOTD() const { return m_motd; }
- std::string const& GetInfo() const { return m_info; }
- uint32 GetMemberCount() const { return m_members.size(); }
- time_t GetCreatedDate() const { return m_createdDate; }
- uint64 GetBankMoney() const { return m_bankMoney; }
-
- bool SetName(std::string const& name);
-
- // Handle client commands
- void HandleRoster(WorldSession* session);
- void HandleQuery(WorldSession* session);
- void HandleSetMOTD(WorldSession* session, std::string const& motd);
- void HandleSetInfo(WorldSession* session, std::string const& info);
- void HandleSetEmblem(WorldSession* session, const EmblemInfo& emblemInfo);
- void HandleSetLeader(WorldSession* session, std::string const& name);
- void HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string const& name, std::string const& icon);
- void HandleSetMemberNote(WorldSession* session, std::string const& name, std::string const& note, bool officer);
- void HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string const& name, uint32 rights, uint32 moneyPerDay, const GuildBankRightsAndSlotsVec& rightsAndSlots);
- void HandleBuyBankTab(WorldSession* session, uint8 tabId);
- void HandleInviteMember(WorldSession* session, std::string const& name);
- void HandleAcceptMember(WorldSession* session);
- void HandleLeaveMember(WorldSession* session);
- void HandleRemoveMember(WorldSession* session, std::string const& name);
- void HandleUpdateMemberRank(WorldSession* session, std::string const& name, bool demote);
- void HandleAddNewRank(WorldSession* session, std::string const& name);
- void HandleRemoveRank(WorldSession* session, uint8 rankId);
- void HandleRemoveLowestRank(WorldSession* session);
- void HandleMemberDepositMoney(WorldSession* session, uint32 amount);
- bool HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool repair = false);
- void HandleMemberLogout(WorldSession* session);
- void HandleDisband(WorldSession* session);
-
- void UpdateMemberData(Player* player, uint8 dataid, uint32 value);
- void OnPlayerStatusChange(Player* player, uint32 flag, bool state);
-
- // Send info to client
- void SendInfo(WorldSession* session) const;
- void SendEventLog(WorldSession* session) const;
- void SendBankLog(WorldSession* session, uint8 tabId) const;
- void SendBankTabsInfo(WorldSession* session, bool showTabs = false) const;
- void SendBankTabData(WorldSession* session, uint8 tabId) const;
- void SendBankTabText(WorldSession* session, uint8 tabId) const;
- void SendPermissions(WorldSession* session) const;
- void SendMoneyInfo(WorldSession* session) const;
- void SendLoginInfo(WorldSession* session);
-
- // Load from DB
- bool LoadFromDB(Field* fields);
- void LoadRankFromDB(Field* fields);
- bool LoadMemberFromDB(Field* fields);
- bool LoadEventLogFromDB(Field* fields);
- void LoadBankRightFromDB(Field* fields);
- void LoadBankTabFromDB(Field* fields);
- bool LoadBankEventLogFromDB(Field* fields);
- bool LoadBankItemFromDB(Field* fields);
- bool Validate();
-
- // Broadcasts
- void BroadcastToGuild(WorldSession* session, bool officerOnly, std::string const& msg, uint32 language = LANG_UNIVERSAL) const;
- void BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const;
- void BroadcastPacket(WorldPacket* packet) const;
-
- void MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 maxLevel, uint32 minRank);
-
- template<class Do>
- void BroadcastWorker(Do& _do, Player* except = NULL)
- {
- for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
- if (Player* player = itr->second->FindConnectedPlayer())
- if (player != except)
- _do(player);
- }
-
- // Members
- // Adds member to guild. If rankId == GUILD_RANK_NONE, lowest rank is assigned.
- bool AddMember(ObjectGuid guid, uint8 rankId = GUILD_RANK_NONE);
- void DeleteMember(ObjectGuid guid, bool isDisbanding = false, bool isKicked = false, bool canDeleteGuild = false);
- bool ChangeMemberRank(ObjectGuid guid, uint8 newRank);
-
- // Bank
- void SwapItems(Player* player, uint8 tabId, uint8 slotId, uint8 destTabId, uint8 destSlotId, uint32 splitedAmount);
- void SwapItemsWithInventory(Player* player, bool toChar, uint8 tabId, uint8 slotId, uint8 playerBag, uint8 playerSlotId, uint32 splitedAmount);
-
- // Bank tabs
- void SetBankTabText(uint8 tabId, std::string const& text);
-
- void ResetTimes();
-
-protected:
- ObjectGuid::LowType m_id;
- std::string m_name;
- ObjectGuid m_leaderGuid;
- std::string m_motd;
- std::string m_info;
- time_t m_createdDate;
-
- EmblemInfo m_emblemInfo;
- uint32 m_accountsNumber;
- uint64 m_bankMoney;
-
- Ranks m_ranks;
- Members m_members;
- BankTabs m_bankTabs;
-
- // These are actually ordered lists. The first element is the oldest entry.
- LogHolder* m_eventLog;
- LogHolder* m_bankEventLog[GUILD_BANK_MAX_TABS + 1];
-
-private:
- inline uint8 _GetRanksSize() const { return uint8(m_ranks.size()); }
- inline const RankInfo* GetRankInfo(uint8 rankId) const { return rankId < _GetRanksSize() ? &m_ranks[rankId] : NULL; }
- inline RankInfo* GetRankInfo(uint8 rankId) { return rankId < _GetRanksSize() ? &m_ranks[rankId] : NULL; }
- inline bool _HasRankRight(Player* player, uint32 right) const
- {
- if (player)
- if (Member const* member = GetMember(player->GetGUID()))
- return (_GetRankRights(member->GetRankId()) & right) != GR_RIGHT_EMPTY;
- return false;
- }
-
- inline uint8 _GetLowestRankId() const { return uint8(m_ranks.size() - 1); }
-
- inline uint8 _GetPurchasedTabsSize() const { return uint8(m_bankTabs.size()); }
- inline BankTab* GetBankTab(uint8 tabId) { return tabId < m_bankTabs.size() ? m_bankTabs[tabId] : NULL; }
- inline const BankTab* GetBankTab(uint8 tabId) const { return tabId < m_bankTabs.size() ? m_bankTabs[tabId] : NULL; }
-
- inline const Member* GetMember(ObjectGuid guid) const
- {
- Members::const_iterator itr = m_members.find(guid.GetCounter());
- return itr != m_members.end() ? itr->second : NULL;
- }
-
- inline Member* GetMember(ObjectGuid guid)
- {
- Members::iterator itr = m_members.find(guid.GetCounter());
- return itr != m_members.end() ? itr->second : NULL;
- }
-
- inline Member* GetMember(std::string const& name)
- {
- for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
- if (itr->second->GetName() == name)
- return itr->second;
-
- return NULL;
- }
-
- inline void _DeleteMemberFromDB(ObjectGuid::LowType lowguid) const
- {
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_MEMBER);
- stmt->setUInt32(0, lowguid);
- CharacterDatabase.Execute(stmt);
- }
-
- // Creates log holders (either when loading or when creating guild)
- void _CreateLogHolders();
- // Tries to create new bank tab
- void _CreateNewBankTab();
- // Creates default guild ranks with names in given locale
- void _CreateDefaultGuildRanks(LocaleConstant loc);
- // Creates new rank
- bool _CreateRank(std::string const& name, uint32 rights);
- // Update account number when member added/removed from guild
- void _UpdateAccountsNumber();
- bool _IsLeader(Player* player) const;
- void _DeleteBankItems(SQLTransaction& trans, bool removeItemsFromDB = false);
- bool _ModifyBankMoney(SQLTransaction& trans, uint64 amount, bool add);
- void _SetLeaderGUID(Member* pLeader);
-
- void _SetRankBankMoneyPerDay(uint8 rankId, uint32 moneyPerDay);
- void _SetRankBankTabRightsAndSlots(uint8 rankId, GuildBankRightsAndSlots rightsAndSlots, bool saveToDB = true);
- int8 _GetRankBankTabRights(uint8 rankId, uint8 tabId) const;
- uint32 _GetRankRights(uint8 rankId) const;
- int32 _GetRankBankMoneyPerDay(uint8 rankId) const;
- int32 _GetRankBankTabSlotsPerDay(uint8 rankId, uint8 tabId) const;
- std::string _GetRankName(uint8 rankId) const;
-
- int32 _GetMemberRemainingSlots(Member const* member, uint8 tabId) const;
- int32 _GetMemberRemainingMoney(Member const* member) const;
- void _UpdateMemberWithdrawSlots(SQLTransaction& trans, ObjectGuid guid, uint8 tabId);
- bool _MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 rights) const;
-
- void _LogEvent(GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2 = 0, uint8 newRank = 0);
- void _LogBankEvent(SQLTransaction& trans, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount = 0, uint8 destTabId = 0);
-
- Item* _GetItem(uint8 tabId, uint8 slotId) const;
- void _RemoveItem(SQLTransaction& trans, uint8 tabId, uint8 slotId);
- void _MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAmount);
- bool _DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError, uint32 splitedAmount = 0);
-
- void _SendBankContent(WorldSession* session, uint8 tabId) const;
- void _SendBankMoneyUpdate(WorldSession* session) const;
- void _SendBankContentUpdate(MoveItemData* pSrc, MoveItemData* pDest) const;
- void _SendBankContentUpdate(uint8 tabId, SlotIds slots) const;
- void _SendBankList(WorldSession* session = NULL, uint8 tabId = 0, bool sendFullSlots = false, SlotIds *slots = NULL) const;
-
- void _BroadcastEvent(GuildEvents guildEvent, ObjectGuid guid, const char* param1 = NULL, const char* param2 = NULL, const char* param3 = NULL) const;
+ // Creates log holders (either when loading or when creating guild)
+ void _CreateLogHolders();
+ // Tries to create new bank tab
+ void _CreateNewBankTab();
+ // Creates default guild ranks with names in given locale
+ void _CreateDefaultGuildRanks(SQLTransaction& trans, LocaleConstant loc);
+ // Creates new rank
+ bool _CreateRank(SQLTransaction& trans, std::string const& name, uint32 rights);
+ // Update account number when member added/removed from guild
+ void _UpdateAccountsNumber();
+ bool _IsLeader(Player* player) const;
+ void _DeleteBankItems(SQLTransaction& trans, bool removeItemsFromDB = false);
+ bool _ModifyBankMoney(SQLTransaction& trans, uint64 amount, bool add);
+ void _SetLeaderGUID(Member* pLeader);
+
+ void _SetRankBankMoneyPerDay(uint8 rankId, uint32 moneyPerDay);
+ void _SetRankBankTabRightsAndSlots(uint8 rankId, GuildBankRightsAndSlots rightsAndSlots, bool saveToDB = true);
+ int8 _GetRankBankTabRights(uint8 rankId, uint8 tabId) const;
+ uint32 _GetRankRights(uint8 rankId) const;
+ int32 _GetRankBankMoneyPerDay(uint8 rankId) const;
+ int32 _GetRankBankTabSlotsPerDay(uint8 rankId, uint8 tabId) const;
+ std::string _GetRankName(uint8 rankId) const;
+
+ int32 _GetMemberRemainingSlots(Member const* member, uint8 tabId) const;
+ int32 _GetMemberRemainingMoney(Member const* member) const;
+ void _UpdateMemberWithdrawSlots(SQLTransaction& trans, ObjectGuid guid, uint8 tabId);
+ bool _MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 rights) const;
+
+ void _LogEvent(GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2 = 0, uint8 newRank = 0);
+ void _LogBankEvent(SQLTransaction& trans, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount = 0, uint8 destTabId = 0);
+
+ Item* _GetItem(uint8 tabId, uint8 slotId) const;
+ void _RemoveItem(SQLTransaction& trans, uint8 tabId, uint8 slotId);
+ void _MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAmount);
+ bool _DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError, uint32 splitedAmount = 0);
+
+ void _SendBankContent(WorldSession* session, uint8 tabId) const;
+ void _SendBankMoneyUpdate(WorldSession* session) const;
+ void _SendBankContentUpdate(MoveItemData* pSrc, MoveItemData* pDest) const;
+ void _SendBankContentUpdate(uint8 tabId, SlotIds slots) const;
+ void _SendBankList(WorldSession* session = NULL, uint8 tabId = 0, bool sendFullSlots = false, SlotIds *slots = NULL) const;
+
+ void _BroadcastEvent(GuildEvents guildEvent, ObjectGuid guid, const char* param1 = NULL, const char* param2 = NULL, const char* param3 = NULL) const;
};
#endif
diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp
index 71242d57f33..2c5eddcefdc 100644
--- a/src/server/game/Handlers/AuctionHouseHandler.cpp
+++ b/src/server/game/Handlers/AuctionHouseHandler.cpp
@@ -202,7 +202,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData)
itemEntry = item->GetTemplate()->ItemId;
if (sAuctionMgr->GetAItem(item->GetGUID().GetCounter()) || !item->CanBeTraded() || item->IsNotEmptyBag() ||
- item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION) ||
+ (item->GetTemplate()->Flags & ITEM_FLAG_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION) ||
item->GetCount() < count[i] || itemEntry != item->GetTemplate()->ItemId)
{
SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR);
diff --git a/src/server/game/Handlers/ChannelHandler.cpp b/src/server/game/Handlers/ChannelHandler.cpp
index 9285f4247b2..71cdddcebf5 100644
--- a/src/server/game/Handlers/ChannelHandler.cpp
+++ b/src/server/game/Handlers/ChannelHandler.cpp
@@ -17,11 +17,15 @@
*/
#include "ObjectMgr.h" // for normalizePlayerName
+#include "Channel.h"
#include "ChannelMgr.h"
#include "Player.h"
+#include "WorldSession.h"
#include <cctype>
+static size_t const MAX_CHANNEL_PASS_STR = 31;
+
void WorldSession::HandleJoinChannel(WorldPacket& recvPacket)
{
uint32 channelId;
@@ -33,13 +37,13 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket)
TC_LOG_DEBUG("chat.system", "CMSG_JOIN_CHANNEL %s Channel: %u, unk1: %u, unk2: %u, channel: %s, password: %s",
GetPlayerInfo().c_str(), channelId, unknown1, unknown2, channelName.c_str(), password.c_str());
+ AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetPlayer()->GetZoneId());
if (channelId)
{
ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(channelId);
if (!channel)
return;
- AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetPlayer()->GetZoneId());
if (!zone || !GetPlayer()->CanJoinConstantChannelInZone(channel, zone))
return;
}
@@ -51,30 +55,42 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket)
return;
if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
- {
- cMgr->setTeam(GetPlayer()->GetTeam());
- if (Channel* channel = cMgr->GetJoinChannel(channelName, channelId))
+ if (Channel* channel = cMgr->GetJoinChannel(channelId, channelName, zone))
channel->JoinChannel(GetPlayer(), password);
- }
}
void WorldSession::HandleLeaveChannel(WorldPacket& recvPacket)
{
- uint32 unk;
+ uint32 channelId;
std::string channelName;
- recvPacket >> unk >> channelName;
+ recvPacket >> channelId >> channelName;
- TC_LOG_DEBUG("chat.system", "CMSG_LEAVE_CHANNEL %s Channel: %s, unk1: %u",
- GetPlayerInfo().c_str(), channelName.c_str(), unk);
+ TC_LOG_DEBUG("chat.system", "CMSG_LEAVE_CHANNEL %s Channel: %s, channelId: %u",
+ GetPlayerInfo().c_str(), channelName.c_str(), channelId);
- if (channelName.empty())
+ if (channelName.empty() && !channelId)
return;
+ AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetPlayer()->GetZoneId());
+ if (channelId)
+ {
+ ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(channelId);
+ if (!channel)
+ return;
+
+ if (!zone || !GetPlayer()->CanJoinConstantChannelInZone(channel, zone))
+ return;
+ }
+
if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
{
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
+ if (Channel* channel = cMgr->GetChannel(channelId, channelName, GetPlayer(), true, zone))
channel->LeaveChannel(GetPlayer(), true);
- cMgr->LeftChannel(channelName);
+
+ if (channelId)
+ cMgr->LeftChannel(channelId, zone);
+ else
+ cMgr->LeftChannel(channelName);
}
}
@@ -87,9 +103,8 @@ void WorldSession::HandleChannelList(WorldPacket& recvPacket)
recvPacket.GetOpcode() == CMSG_CHANNEL_DISPLAY_LIST ? "CMSG_CHANNEL_DISPLAY_LIST" : "CMSG_CHANNEL_LIST",
GetPlayerInfo().c_str(), channelName.c_str());
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- channel->List(GetPlayer());
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
+ channel->List(GetPlayer());
}
void WorldSession::HandleChannelPassword(WorldPacket& recvPacket)
@@ -103,9 +118,8 @@ void WorldSession::HandleChannelPassword(WorldPacket& recvPacket)
if (password.length() > MAX_CHANNEL_PASS_STR)
return;
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- channel->Password(GetPlayer(), password);
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
+ channel->Password(GetPlayer(), password);
}
void WorldSession::HandleChannelSetOwner(WorldPacket& recvPacket)
@@ -119,9 +133,8 @@ void WorldSession::HandleChannelSetOwner(WorldPacket& recvPacket)
if (!normalizePlayerName(targetName))
return;
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- channel->SetOwner(GetPlayer(), targetName);
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
+ channel->SetOwner(GetPlayer(), targetName);
}
void WorldSession::HandleChannelOwner(WorldPacket& recvPacket)
@@ -132,9 +145,8 @@ void WorldSession::HandleChannelOwner(WorldPacket& recvPacket)
TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_OWNER %s Channel: %s",
GetPlayerInfo().c_str(), channelName.c_str());
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- channel->SendWhoOwner(GetPlayer()->GetGUID());
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
+ channel->SendWhoOwner(GetPlayer()->GetGUID());
}
void WorldSession::HandleChannelModerator(WorldPacket& recvPacket)
@@ -148,9 +160,8 @@ void WorldSession::HandleChannelModerator(WorldPacket& recvPacket)
if (!normalizePlayerName(targetName))
return;
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- channel->SetModerator(GetPlayer(), targetName);
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
+ channel->SetModerator(GetPlayer(), targetName);
}
void WorldSession::HandleChannelUnmoderator(WorldPacket& recvPacket)
@@ -164,9 +175,8 @@ void WorldSession::HandleChannelUnmoderator(WorldPacket& recvPacket)
if (!normalizePlayerName(targetName))
return;
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- channel->UnsetModerator(GetPlayer(), targetName);
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
+ channel->UnsetModerator(GetPlayer(), targetName);
}
void WorldSession::HandleChannelMute(WorldPacket& recvPacket)
@@ -180,9 +190,8 @@ void WorldSession::HandleChannelMute(WorldPacket& recvPacket)
if (!normalizePlayerName(targetName))
return;
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- channel->SetMute(GetPlayer(), targetName);
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
+ channel->SetMute(GetPlayer(), targetName);
}
void WorldSession::HandleChannelUnmute(WorldPacket& recvPacket)
@@ -196,9 +205,8 @@ void WorldSession::HandleChannelUnmute(WorldPacket& recvPacket)
if (!normalizePlayerName(targetName))
return;
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- channel->UnsetMute(GetPlayer(), targetName);
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
+ channel->UnsetMute(GetPlayer(), targetName);
}
void WorldSession::HandleChannelInvite(WorldPacket& recvPacket)
@@ -212,9 +220,8 @@ void WorldSession::HandleChannelInvite(WorldPacket& recvPacket)
if (!normalizePlayerName(targetName))
return;
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- channel->Invite(GetPlayer(), targetName);
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
+ channel->Invite(GetPlayer(), targetName);
}
void WorldSession::HandleChannelKick(WorldPacket& recvPacket)
@@ -228,9 +235,8 @@ void WorldSession::HandleChannelKick(WorldPacket& recvPacket)
if (!normalizePlayerName(targetName))
return;
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- channel->Kick(GetPlayer(), targetName);
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
+ channel->Kick(GetPlayer(), targetName);
}
void WorldSession::HandleChannelBan(WorldPacket& recvPacket)
@@ -244,9 +250,8 @@ void WorldSession::HandleChannelBan(WorldPacket& recvPacket)
if (!normalizePlayerName(targetName))
return;
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- channel->Ban(GetPlayer(), targetName);
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
+ channel->Ban(GetPlayer(), targetName);
}
void WorldSession::HandleChannelUnban(WorldPacket& recvPacket)
@@ -260,9 +265,8 @@ void WorldSession::HandleChannelUnban(WorldPacket& recvPacket)
if (!normalizePlayerName(targetName))
return;
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- channel->UnBan(GetPlayer(), targetName);
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
+ channel->UnBan(GetPlayer(), targetName);
}
void WorldSession::HandleChannelAnnouncements(WorldPacket& recvPacket)
@@ -273,9 +277,8 @@ void WorldSession::HandleChannelAnnouncements(WorldPacket& recvPacket)
TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_ANNOUNCEMENTS %s Channel: %s",
GetPlayerInfo().c_str(), channelName.c_str());
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- channel->Announce(GetPlayer());
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
+ channel->Announce(GetPlayer());
}
void WorldSession::HandleChannelDisplayListQuery(WorldPacket &recvPacket)
@@ -292,19 +295,17 @@ void WorldSession::HandleGetChannelMemberCount(WorldPacket &recvPacket)
TC_LOG_DEBUG("chat.system", "CMSG_GET_CHANNEL_MEMBER_COUNT %s Channel: %s",
GetPlayerInfo().c_str(), channelName.c_str());
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeam()))
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
{
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- {
- TC_LOG_DEBUG("chat.system", "SMSG_CHANNEL_MEMBER_COUNT %s Channel: %s Count: %u",
- GetPlayerInfo().c_str(), channelName.c_str(), channel->GetNumPlayers());
-
- WorldPacket data(SMSG_CHANNEL_MEMBER_COUNT, channel->GetName().size() + 1 + 4);
- data << channel->GetName();
- data << uint8(channel->GetFlags());
- data << uint32(channel->GetNumPlayers());
- SendPacket(&data);
- }
+ TC_LOG_DEBUG("chat.system", "SMSG_CHANNEL_MEMBER_COUNT %s Channel: %s Count: %u",
+ GetPlayerInfo().c_str(), channelName.c_str(), channel->GetNumPlayers());
+
+ std::string name = channel->GetName(GetSessionDbcLocale());
+ WorldPacket data(SMSG_CHANNEL_MEMBER_COUNT, name.size() + 1 + 4);
+ data << name;
+ data << uint8(channel->GetFlags());
+ data << uint32(channel->GetNumPlayers());
+ SendPacket(&data);
}
}
@@ -317,8 +318,7 @@ void WorldSession::HandleSetChannelWatch(WorldPacket &recvPacket)
GetPlayerInfo().c_str(), channelName.c_str());
/*
- if (ChannelMgr* cMgr = channelMgr(GetPlayer()->GetTeam()))
- if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
- channel->JoinNotify(GetPlayer());
+ if (Channel* channel = ChannelMgr::GetChannelForPlayerByNamePart(channelName, GetPlayer()))
+ channel->JoinNotify(GetPlayer());
*/
}
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 53c62858c04..157511afd96 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -1843,13 +1843,10 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData)
{
// Reset guild
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER);
-
stmt->setUInt32(0, lowGuid);
-
- PreparedQueryResult result = CharacterDatabase.Query(stmt);
- if (result)
+ if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
if (Guild* guild = sGuildMgr->GetGuildById((result->Fetch()[0]).GetUInt32()))
- guild->DeleteMember(factionChangeInfo.Guid, false, false, true);
+ guild->DeleteMember(trans, factionChangeInfo.Guid, false, false, true);
Player::LeaveAllArenaTeams(factionChangeInfo.Guid);
}
diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp
index 2b1660fef2b..ba5164f9be5 100644
--- a/src/server/game/Handlers/ChatHandler.cpp
+++ b/src/server/game/Handlers/ChatHandler.cpp
@@ -26,6 +26,7 @@
#include "DatabaseEnv.h"
#include "CellImpl.h"
#include "Chat.h"
+#include "Channel.h"
#include "ChannelMgr.h"
#include "GridNotifiersImpl.h"
#include "Group.h"
@@ -461,13 +462,10 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData)
}
}
- if (ChannelMgr* cMgr = ChannelMgr::forTeam(sender->GetTeam()))
+ if (Channel* chn = ChannelMgr::GetChannelForPlayerByNamePart(channel, sender))
{
- if (Channel* chn = cMgr->GetChannel(channel, sender))
- {
- sScriptMgr->OnPlayerChat(sender, type, lang, msg, chn);
- chn->Say(sender->GetGUID(), msg.c_str(), lang);
- }
+ sScriptMgr->OnPlayerChat(sender, type, lang, msg, chn);
+ chn->Say(sender->GetGUID(), msg.c_str(), lang);
}
break;
}
diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp
index bb188b08fbc..8f9a3ba6ffc 100644
--- a/src/server/game/Handlers/ItemHandler.cpp
+++ b/src/server/game/Handlers/ItemHandler.cpp
@@ -284,7 +284,7 @@ void WorldSession::HandleDestroyItemOpcode(WorldPacket& recvData)
return;
}
- if (pItem->GetTemplate()->Flags & ITEM_PROTO_FLAG_INDESTRUCTIBLE)
+ if (pItem->GetTemplate()->Flags & ITEM_FLAG_NO_USER_DESTROY)
{
_player->SendEquipError(EQUIP_ERR_CANT_DROP_SOULBOUND, NULL, NULL);
return;
@@ -542,7 +542,7 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
// prevent selling item for sellprice when the item is still refundable
// this probably happens when right clicking a refundable item, the client sends both
// CMSG_SELL_ITEM and CMSG_REFUND_ITEM (unverified)
- if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE))
+ if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE))
return; // Therefore, no feedback to client
// special case at auto sell (sell all)
@@ -776,7 +776,7 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid)
continue;
// Only display items in vendor lists for the team the
// player is on. If GM on, display all items.
- if (!_player->IsGameMaster() && ((itemTemplate->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY && _player->GetTeam() == ALLIANCE) || (itemTemplate->Flags2 == ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && _player->GetTeam() == HORDE)))
+ if (!_player->IsGameMaster() && ((itemTemplate->Flags2 & ITEM_FLAG2_FACTION_HORDE && _player->GetTeam() == ALLIANCE) || (itemTemplate->Flags2 == ITEM_FLAG2_FACTION_ALLIANCE && _player->GetTeam() == HORDE)))
continue;
// Items sold out are not displayed in list
@@ -1093,7 +1093,7 @@ void WorldSession::HandleWrapItemOpcode(WorldPacket& recvData)
return;
}
- if (!(gift->GetTemplate()->Flags & ITEM_PROTO_FLAG_IS_WRAPPER)) // cheating: non-wrapper wrapper
+ if (!(gift->GetTemplate()->Flags & ITEM_FLAG_IS_WRAPPER)) // cheating: non-wrapper wrapper
{
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL);
return;
@@ -1171,7 +1171,7 @@ void WorldSession::HandleWrapItemOpcode(WorldPacket& recvData)
case 21830: item->SetEntry(21831); break;
}
item->SetGuidValue(ITEM_FIELD_GIFTCREATOR, _player->GetGUID());
- item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED);
+ item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED);
item->SetState(ITEM_CHANGED, _player);
if (item->GetState() == ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance`
@@ -1272,7 +1272,7 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
ItemTemplate const* iGemProto = Gems[i]->GetTemplate();
// unique item (for new and already placed bit removed enchantments
- if (iGemProto->Flags & ITEM_PROTO_FLAG_UNIQUE_EQUIPPED)
+ if (iGemProto->Flags & ITEM_FLAG_UNIQUE_EQUIPPABLE)
{
for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
{
diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp
index d91dd6f495f..94e271465cd 100644
--- a/src/server/game/Handlers/LootHandler.cpp
+++ b/src/server/game/Handlers/LootHandler.cpp
@@ -322,7 +322,7 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
ItemTemplate const* proto = pItem->GetTemplate();
// destroy only 5 items from stack in case prospecting and milling
- if (proto->Flags & (ITEM_PROTO_FLAG_PROSPECTABLE | ITEM_PROTO_FLAG_MILLABLE))
+ if (proto->Flags & (ITEM_FLAG_IS_PROSPECTABLE | ITEM_FLAG_IS_MILLABLE))
{
pItem->m_lootGenerated = false;
pItem->loot.clear();
@@ -338,7 +338,7 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
else
{
// Only delete item if no loot or money (unlooted loot is saved to db) or if it isn't an openable item
- if (pItem->loot.isLooted() || !(proto->Flags & ITEM_PROTO_FLAG_HAS_LOOT))
+ if (pItem->loot.isLooted() || !(proto->Flags & ITEM_FLAG_HAS_LOOT))
player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true);
}
return; // item can be looted only single player
diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp
index 36df5b64f1b..a4dcd22c1f2 100644
--- a/src/server/game/Handlers/MailHandler.cpp
+++ b/src/server/game/Handlers/MailHandler.cpp
@@ -199,7 +199,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
if (Item* item = player->GetItemByGuid(itemGUIDs[i]))
{
ItemTemplate const* itemProto = item->GetTemplate();
- if (!itemProto || !(itemProto->Flags & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT))
+ if (!itemProto || !(itemProto->Flags & ITEM_FLAG_IS_BOUND_TO_ACCOUNT))
{
accountBound = false;
break;
@@ -250,13 +250,13 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
return;
}
- if (item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION))
+ if ((item->GetTemplate()->Flags & ITEM_FLAG_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION))
{
player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM);
return;
}
- if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))
+ if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED))
{
player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD);
return;
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index a0b3d46b38c..3ac638c246d 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -1408,7 +1408,7 @@ void WorldSession::HandleFarSightOpcode(WorldPacket& recvData)
if (WorldObject* target = _player->GetViewpoint())
_player->SetSeer(target);
else
- TC_LOG_ERROR("network", "Player %s (%s) requests non-existing seer %s", _player->GetName().c_str(), _player->GetGUID().ToString().c_str(), _player->GetGuidValue(PLAYER_FARSIGHT).ToString().c_str());
+ TC_LOG_DEBUG("network", "Player %s (%s) requests non-existing seer %s", _player->GetName().c_str(), _player->GetGUID().ToString().c_str(), _player->GetGuidValue(PLAYER_FARSIGHT).ToString().c_str());
}
else
{
@@ -1741,9 +1741,9 @@ void WorldSession::HandleHearthAndResurrect(WorldPacket& /*recvData*/)
if (_player->IsInFlight())
return;
- if (/*Battlefield* bf = */sBattlefieldMgr->GetBattlefieldToZoneId(_player->GetZoneId()))
+ if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(_player->GetZoneId()))
{
- // bf->PlayerAskToLeave(_player); FIXME
+ bf->PlayerAskToLeave(_player);
return;
}
diff --git a/src/server/game/Handlers/PetitionsHandler.cpp b/src/server/game/Handlers/PetitionsHandler.cpp
index c0b5db65d90..a4d41bbff1f 100644
--- a/src/server/game/Handlers/PetitionsHandler.cpp
+++ b/src/server/game/Handlers/PetitionsHandler.cpp
@@ -849,12 +849,18 @@ void WorldSession::HandleTurnInPetitionOpcode(WorldPacket& recvData)
Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_COMMAND_SUCCESS, name);
- // Add members from signatures
- for (uint8 i = 0; i < signatures; ++i)
{
- Field* fields = result->Fetch();
- guild->AddMember(ObjectGuid(HighGuid::Player, fields[0].GetUInt32()));
- result->NextRow();
+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
+
+ // Add members from signatures
+ for (uint8 i = 0; i < signatures; ++i)
+ {
+ Field* fields = result->Fetch();
+ guild->AddMember(trans, ObjectGuid(HighGuid::Player, fields[0].GetUInt32()));
+ result->NextRow();
+ }
+
+ CharacterDatabase.CommitTransaction(trans);
}
}
else
diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
index cbc9be3b140..728fda8d184 100644
--- a/src/server/game/Handlers/SpellHandler.cpp
+++ b/src/server/game/Handlers/SpellHandler.cpp
@@ -115,14 +115,14 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
}
// only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB)
- if (proto->Class == ITEM_CLASS_CONSUMABLE && !(proto->Flags & ITEM_PROTO_FLAG_USEABLE_IN_ARENA) && pUser->InArena())
+ if (proto->Class == ITEM_CLASS_CONSUMABLE && !(proto->Flags & ITEM_FLAG_IGNORE_DEFAULT_ARENA_RESTRICTIONS) && pUser->InArena())
{
pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH, pItem, NULL);
return;
}
// don't allow items banned in arena
- if (proto->Flags & ITEM_PROTO_FLAG_NOT_USEABLE_IN_ARENA && pUser->InArena())
+ if ((proto->Flags & ITEM_FLAG_NOT_USEABLE_IN_ARENA) && pUser->InArena())
{
pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH, pItem, NULL);
return;
@@ -196,7 +196,7 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket)
}
// Verify that the bag is an actual bag or wrapped item that can be used "normally"
- if (!(proto->Flags & ITEM_PROTO_FLAG_HAS_LOOT) && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))
+ if (!(proto->Flags & ITEM_FLAG_HAS_LOOT) && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED))
{
pUser->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, item, NULL);
TC_LOG_ERROR("entities.player.cheat", "Possible hacking attempt: Player %s [guid: %u] tried to open item [guid: %u, entry: %u] which is not openable!",
@@ -225,7 +225,7 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket)
}
}
- if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))// wrapped?
+ if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED))// wrapped?
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GIFT_BY_ITEM);
diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp
index e2743f8f456..6b4d16111ed 100644
--- a/src/server/game/Handlers/TradeHandler.cpp
+++ b/src/server/game/Handlers/TradeHandler.cpp
@@ -93,7 +93,7 @@ void WorldSession::SendUpdateTrade(bool trader_data /*= true*/)
data << uint32(item->GetTemplate()->DisplayInfoID);// display id
data << uint32(item->GetCount()); // stack count
// wrapped: hide stats but show giftcreator name
- data << uint32(item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED) ? 1 : 0);
+ data << uint32(item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED) ? 1 : 0);
data << uint64(item->GetGuidValue(ITEM_FIELD_GIFTCREATOR));
// perm. enchantment and gems
data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT));
@@ -152,7 +152,7 @@ void WorldSession::moveItems(Item* myItems[], Item* hisItems[])
}
// adjust time (depends on /played)
- if (myItems[i]->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE))
+ if (myItems[i]->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE))
myItems[i]->SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, trader->GetTotalPlayedTime()-(_player->GetTotalPlayedTime()-myItems[i]->GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME)));
// store
trader->MoveItemToInventory(traderDst, myItems[i], true, true);
@@ -170,7 +170,7 @@ void WorldSession::moveItems(Item* myItems[], Item* hisItems[])
}
// adjust time (depends on /played)
- if (hisItems[i]->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE))
+ if (hisItems[i]->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE))
hisItems[i]->SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, _player->GetTotalPlayedTime()-(trader->GetTotalPlayedTime()-hisItems[i]->GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME)));
// store
_player->MoveItemToInventory(playerDst, hisItems[i], true, true);
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index 260e7ff464f..b69bb41d3ad 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -353,7 +353,7 @@ LootItem::LootItem(LootStoreItem const& li)
conditions = li.conditions;
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemid);
- freeforall = proto && (proto->Flags & ITEM_PROTO_FLAG_MULTI_DROP);
+ freeforall = proto && (proto->Flags & ITEM_FLAG_MULTI_DROP);
follow_loot_rules = proto && (proto->FlagsCu & ITEM_FLAGS_CU_FOLLOW_LOOT_RULES);
needs_quest = li.needs_quest;
@@ -380,14 +380,14 @@ bool LootItem::AllowedForPlayer(Player const* player) const
return false;
// not show loot for players without profession or those who already know the recipe
- if ((pProto->Flags & ITEM_PROTO_FLAG_SMART_LOOT) && (!player->HasSkill(pProto->RequiredSkill) || player->HasSpell(pProto->Spells[1].SpellId)))
+ if ((pProto->Flags & ITEM_FLAG_HIDE_UNUSABLE_RECIPE) && (!player->HasSkill(pProto->RequiredSkill) || player->HasSpell(pProto->Spells[1].SpellId)))
return false;
// not show loot for not own team
- if ((pProto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && player->GetTeam() != HORDE)
+ if ((pProto->Flags2 & ITEM_FLAG2_FACTION_HORDE) && player->GetTeam() != HORDE)
return false;
- if ((pProto->Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) && player->GetTeam() != ALLIANCE)
+ if ((pProto->Flags2 & ITEM_FLAG2_FACTION_ALLIANCE) && player->GetTeam() != ALLIANCE)
return false;
// check quest requirements
@@ -429,7 +429,7 @@ void Loot::AddItem(LootStoreItem const& item)
// non-conditional one-player only items are counted here,
// free for all items are counted in FillFFALoot(),
// non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
- if (!item.needs_quest && item.conditions.empty() && !(proto->Flags & ITEM_PROTO_FLAG_MULTI_DROP))
+ if (!item.needs_quest && item.conditions.empty() && !(proto->Flags & ITEM_FLAG_MULTI_DROP))
++unlootedCount;
}
}
@@ -483,7 +483,7 @@ void Loot::FillNotNormalLootFor(Player* player, bool presentAtLooting)
{
ObjectGuid::LowType plguid = player->GetGUID().GetCounter();
- QuestItemMap::const_iterator qmapitr = PlayerQuestItems.find(plguid);
+ NotNormalLootItemMap::const_iterator qmapitr = PlayerQuestItems.find(plguid);
if (qmapitr == PlayerQuestItems.end())
FillQuestLoot(player);
@@ -517,16 +517,16 @@ void Loot::FillNotNormalLootFor(Player* player, bool presentAtLooting)
}
}
-QuestItemList* Loot::FillFFALoot(Player* player)
+NotNormalLootItemList* Loot::FillFFALoot(Player* player)
{
- QuestItemList* ql = new QuestItemList();
+ NotNormalLootItemList* ql = new NotNormalLootItemList();
for (uint8 i = 0; i < items.size(); ++i)
{
LootItem &item = items[i];
if (!item.is_looted && item.freeforall && item.AllowedForPlayer(player))
{
- ql->push_back(QuestItem(i));
+ ql->push_back(NotNormalLootItem(i));
++unlootedCount;
}
}
@@ -540,12 +540,12 @@ QuestItemList* Loot::FillFFALoot(Player* player)
return ql;
}
-QuestItemList* Loot::FillQuestLoot(Player* player)
+NotNormalLootItemList* Loot::FillQuestLoot(Player* player)
{
if (items.size() == MAX_NR_LOOT_ITEMS)
return NULL;
- QuestItemList* ql = new QuestItemList();
+ NotNormalLootItemList* ql = new NotNormalLootItemList();
for (uint8 i = 0; i < quest_items.size(); ++i)
{
@@ -553,7 +553,7 @@ QuestItemList* Loot::FillQuestLoot(Player* player)
if (!item.is_looted && (item.AllowedForPlayer(player) || (item.follow_loot_rules && player->GetGroup() && ((player->GetGroup()->GetLootMethod() == MASTER_LOOT && player->GetGroup()->GetMasterLooterGuid() == player->GetGUID()) || player->GetGroup()->GetLootMethod() != MASTER_LOOT))))
{
- ql->push_back(QuestItem(i));
+ ql->push_back(NotNormalLootItem(i));
// quest items get blocked when they first appear in a
// player's quest vector
@@ -578,20 +578,20 @@ QuestItemList* Loot::FillQuestLoot(Player* player)
return ql;
}
-QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting)
+NotNormalLootItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting)
{
- QuestItemList* ql = new QuestItemList();
+ NotNormalLootItemList* ql = new NotNormalLootItemList();
for (uint8 i = 0; i < items.size(); ++i)
{
LootItem &item = items[i];
- if (!item.is_looted && !item.freeforall && (item.AllowedForPlayer(player) || (item.follow_loot_rules && player->GetGroup() && ((player->GetGroup()->GetLootMethod() == MASTER_LOOT && player->GetGroup()->GetMasterLooterGuid() == player->GetGUID()) || player->GetGroup()->GetLootMethod() != MASTER_LOOT))))
+ if (!item.is_looted && !item.freeforall && (item.AllowedForPlayer(player)))
{
if (presentAtLooting)
item.AddAllowedLooter(player);
if (!item.conditions.empty())
{
- ql->push_back(QuestItem(i));
+ ql->push_back(NotNormalLootItem(i));
if (!item.is_counted)
{
++unlootedCount;
@@ -657,11 +657,11 @@ void Loot::NotifyQuestItemRemoved(uint8 questIndex)
++i_next;
if (Player* player = ObjectAccessor::FindPlayer(*i))
{
- QuestItemMap::const_iterator pq = PlayerQuestItems.find(player->GetGUID().GetCounter());
+ NotNormalLootItemMap::const_iterator pq = PlayerQuestItems.find(player->GetGUID().GetCounter());
if (pq != PlayerQuestItems.end() && pq->second)
{
// find where/if the player has the given item in it's vector
- QuestItemList& pql = *pq->second;
+ NotNormalLootItemList& pql = *pq->second;
uint8 j;
for (j = 0; j < pql.size(); ++j)
@@ -717,17 +717,17 @@ void Loot::DeleteLootMoneyFromContainerItemDB()
CharacterDatabase.Execute(stmt);
}
-LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem* *qitem, QuestItem* *ffaitem, QuestItem* *conditem)
+LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, NotNormalLootItem* *qitem, NotNormalLootItem* *ffaitem, NotNormalLootItem* *conditem)
{
LootItem* item = NULL;
bool is_looted = true;
if (lootSlot >= items.size())
{
uint32 questSlot = lootSlot - items.size();
- QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUID().GetCounter());
+ NotNormalLootItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUID().GetCounter());
if (itr != PlayerQuestItems.end() && questSlot < itr->second->size())
{
- QuestItem* qitem2 = &itr->second->at(questSlot);
+ NotNormalLootItem* qitem2 = &itr->second->at(questSlot);
if (qitem)
*qitem = qitem2;
item = &quest_items[qitem2->index];
@@ -740,13 +740,13 @@ LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem* *qite
is_looted = item->is_looted;
if (item->freeforall)
{
- QuestItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUID().GetCounter());
+ NotNormalLootItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUID().GetCounter());
if (itr != PlayerFFAItems.end())
{
- for (QuestItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
+ for (NotNormalLootItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
if (iter->index == lootSlot)
{
- QuestItem* ffaitem2 = (QuestItem*)&(*iter);
+ NotNormalLootItem* ffaitem2 = (NotNormalLootItem*)&(*iter);
if (ffaitem)
*ffaitem = ffaitem2;
is_looted = ffaitem2->is_looted;
@@ -756,14 +756,14 @@ LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem* *qite
}
else if (!item->conditions.empty())
{
- QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUID().GetCounter());
+ NotNormalLootItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUID().GetCounter());
if (itr != PlayerNonQuestNonFFAConditionalItems.end())
{
- for (QuestItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
+ for (NotNormalLootItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
{
if (iter->index == lootSlot)
{
- QuestItem* conditem2 = (QuestItem*)&(*iter);
+ NotNormalLootItem* conditem2 = (NotNormalLootItem*)&(*iter);
if (conditem)
*conditem = conditem2;
is_looted = conditem2->is_looted;
@@ -782,7 +782,7 @@ LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem* *qite
uint32 Loot::GetMaxSlotInLootFor(Player* player) const
{
- QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUID().GetCounter());
+ NotNormalLootItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUID().GetCounter());
return items.size() + (itr != PlayerQuestItems.end() ? itr->second->size() : 0);
}
@@ -802,12 +802,12 @@ bool Loot::hasItemForAll() const
// return true if there is any FFA, quest or conditional item for the player.
bool Loot::hasItemFor(Player* player) const
{
- QuestItemMap const& lootPlayerQuestItems = GetPlayerQuestItems();
- QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(player->GetGUID().GetCounter());
+ NotNormalLootItemMap const& lootPlayerQuestItems = GetPlayerQuestItems();
+ NotNormalLootItemMap::const_iterator q_itr = lootPlayerQuestItems.find(player->GetGUID().GetCounter());
if (q_itr != lootPlayerQuestItems.end())
{
- QuestItemList* q_list = q_itr->second;
- for (QuestItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi)
+ NotNormalLootItemList* q_list = q_itr->second;
+ for (NotNormalLootItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi)
{
const LootItem &item = quest_items[qi->index];
if (!qi->is_looted && !item.is_looted)
@@ -815,12 +815,12 @@ bool Loot::hasItemFor(Player* player) const
}
}
- QuestItemMap const& lootPlayerFFAItems = GetPlayerFFAItems();
- QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(player->GetGUID().GetCounter());
+ NotNormalLootItemMap const& lootPlayerFFAItems = GetPlayerFFAItems();
+ NotNormalLootItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(player->GetGUID().GetCounter());
if (ffa_itr != lootPlayerFFAItems.end())
{
- QuestItemList* ffa_list = ffa_itr->second;
- for (QuestItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi)
+ NotNormalLootItemList* ffa_list = ffa_itr->second;
+ for (NotNormalLootItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi)
{
const LootItem &item = items[fi->index];
if (!fi->is_looted && !item.is_looted)
@@ -828,12 +828,12 @@ bool Loot::hasItemFor(Player* player) const
}
}
- QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = GetPlayerNonQuestNonFFAConditionalItems();
- QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(player->GetGUID().GetCounter());
+ NotNormalLootItemMap const& lootPlayerNonQuestNonFFAConditionalItems = GetPlayerNonQuestNonFFAConditionalItems();
+ NotNormalLootItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(player->GetGUID().GetCounter());
if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
{
- QuestItemList* conditional_list = nn_itr->second;
- for (QuestItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci)
+ NotNormalLootItemList* conditional_list = nn_itr->second;
+ for (NotNormalLootItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci)
{
const LootItem &item = items[ci->index];
if (!ci->is_looted && !item.is_looted)
@@ -976,12 +976,12 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
}
LootSlotType slotType = lv.permission == OWNER_PERMISSION ? LOOT_SLOT_TYPE_OWNER : LOOT_SLOT_TYPE_ALLOW_LOOT;
- QuestItemMap const& lootPlayerQuestItems = l.GetPlayerQuestItems();
- QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(lv.viewer->GetGUID().GetCounter());
+ NotNormalLootItemMap const& lootPlayerQuestItems = l.GetPlayerQuestItems();
+ NotNormalLootItemMap::const_iterator q_itr = lootPlayerQuestItems.find(lv.viewer->GetGUID().GetCounter());
if (q_itr != lootPlayerQuestItems.end())
{
- QuestItemList* q_list = q_itr->second;
- for (QuestItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi)
+ NotNormalLootItemList* q_list = q_itr->second;
+ for (NotNormalLootItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi)
{
LootItem &item = l.quest_items[qi->index];
if (!qi->is_looted && !item.is_looted)
@@ -1017,12 +1017,12 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
}
}
- QuestItemMap const& lootPlayerFFAItems = l.GetPlayerFFAItems();
- QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(lv.viewer->GetGUID().GetCounter());
+ NotNormalLootItemMap const& lootPlayerFFAItems = l.GetPlayerFFAItems();
+ NotNormalLootItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(lv.viewer->GetGUID().GetCounter());
if (ffa_itr != lootPlayerFFAItems.end())
{
- QuestItemList* ffa_list = ffa_itr->second;
- for (QuestItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi)
+ NotNormalLootItemList* ffa_list = ffa_itr->second;
+ for (NotNormalLootItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi)
{
LootItem &item = l.items[fi->index];
if (!fi->is_looted && !item.is_looted)
@@ -1035,42 +1035,37 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
}
}
- QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFAConditionalItems();
- QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(lv.viewer->GetGUID().GetCounter());
+ NotNormalLootItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFAConditionalItems();
+ NotNormalLootItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(lv.viewer->GetGUID().GetCounter());
if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
{
- QuestItemList* conditional_list = nn_itr->second;
- for (QuestItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci)
+ NotNormalLootItemList* conditional_list = nn_itr->second;
+ for (NotNormalLootItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci)
{
LootItem &item = l.items[ci->index];
if (!ci->is_looted && !item.is_looted)
{
b << uint8(ci->index);
b << item;
- if (item.follow_loot_rules)
+ switch (lv.permission)
{
- switch (lv.permission)
- {
- case MASTER_PERMISSION:
- b << uint8(LOOT_SLOT_TYPE_MASTER);
- break;
- case RESTRICTED_PERMISSION:
- b << (item.is_blocked ? uint8(LOOT_SLOT_TYPE_LOCKED) : uint8(slotType));
- break;
- case GROUP_PERMISSION:
- case ROUND_ROBIN_PERMISSION:
- if (!item.is_blocked)
- b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT);
- else
- b << uint8(LOOT_SLOT_TYPE_ROLL_ONGOING);
- break;
- default:
- b << uint8(slotType);
- break;
- }
- }
- else
+ case MASTER_PERMISSION:
+ b << uint8(LOOT_SLOT_TYPE_MASTER);
+ break;
+ case RESTRICTED_PERMISSION:
+ b << (item.is_blocked ? uint8(LOOT_SLOT_TYPE_LOCKED) : uint8(slotType));
+ break;
+ case GROUP_PERMISSION:
+ case ROUND_ROBIN_PERMISSION:
+ if (!item.is_blocked)
+ b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT);
+ else
+ b << uint8(LOOT_SLOT_TYPE_ROLL_ONGOING);
+ break;
+ default:
b << uint8(slotType);
+ break;
+ }
++itemsShown;
}
}
@@ -1653,7 +1648,7 @@ void LoadLootTemplates_Item()
// remove real entries and check existence loot
ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore();
for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr)
- if (lootIdSet.find(itr->second.ItemId) != lootIdSet.end() && itr->second.Flags & ITEM_PROTO_FLAG_HAS_LOOT)
+ if (lootIdSet.find(itr->second.ItemId) != lootIdSet.end() && itr->second.Flags & ITEM_FLAG_HAS_LOOT)
lootIdSet.erase(itr->second.ItemId);
// output error for any still listed (not referenced from appropriate table) ids
@@ -1678,7 +1673,7 @@ void LoadLootTemplates_Milling()
ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore();
for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr)
{
- if (!(itr->second.Flags & ITEM_PROTO_FLAG_MILLABLE))
+ if (!(itr->second.Flags & ITEM_FLAG_IS_MILLABLE))
continue;
if (lootIdSet.find(itr->second.ItemId) != lootIdSet.end())
@@ -1741,7 +1736,7 @@ void LoadLootTemplates_Prospecting()
ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore();
for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr)
{
- if (!(itr->second.Flags & ITEM_PROTO_FLAG_PROSPECTABLE))
+ if (!(itr->second.Flags & ITEM_FLAG_IS_PROSPECTABLE))
continue;
if (lootIdSet.find(itr->second.ItemId) != lootIdSet.end())
diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h
index a66b8f0b4c5..ecfb864823f 100644
--- a/src/server/game/Loot/LootMgr.h
+++ b/src/server/game/Loot/LootMgr.h
@@ -180,24 +180,24 @@ struct TC_GAME_API LootItem
const AllowedLooterSet & GetAllowedLooters() const { return allowedGUIDs; }
};
-struct QuestItem
+struct NotNormalLootItem
{
- uint8 index; // position in quest_items;
+ uint8 index; // position in quest_items or items;
bool is_looted;
- QuestItem()
+ NotNormalLootItem()
: index(0), is_looted(false) { }
- QuestItem(uint8 _index, bool _islooted = false)
+ NotNormalLootItem(uint8 _index, bool _islooted = false)
: index(_index), is_looted(_islooted) { }
};
struct Loot;
class LootTemplate;
-typedef std::vector<QuestItem> QuestItemList;
+typedef std::vector<NotNormalLootItem> NotNormalLootItemList;
typedef std::vector<LootItem> LootItemList;
-typedef std::map<uint32, QuestItemList*> QuestItemMap;
+typedef std::map<uint32, NotNormalLootItemList*> NotNormalLootItemMap;
typedef std::list<LootStoreItem*> LootStoreItemList;
typedef std::unordered_map<uint32, LootTemplate*> LootTemplateMap;
@@ -271,13 +271,13 @@ class TC_GAME_API LootTemplate
LootGroups Groups; // groups have own (optimised) processing, grouped entries go there
// Objects of this class must never be copied, we are storing pointers in container
- LootTemplate(LootTemplate const&);
- LootTemplate& operator=(LootTemplate const&);
+ LootTemplate(LootTemplate const&) = delete;
+ LootTemplate& operator=(LootTemplate const&) = delete;
};
//=====================================================
-class LootValidatorRef : public Reference<Loot, LootValidatorRef>
+class LootValidatorRef : public Reference<Loot, LootValidatorRef>
{
public:
LootValidatorRef() { }
@@ -293,12 +293,9 @@ class LootValidatorRefManager : public RefManager<Loot, LootValidatorRef>
typedef LinkedListHead::Iterator< LootValidatorRef > iterator;
LootValidatorRef* getFirst() { return (LootValidatorRef*)RefManager<Loot, LootValidatorRef>::getFirst(); }
- LootValidatorRef* getLast() { return (LootValidatorRef*)RefManager<Loot, LootValidatorRef>::getLast(); }
iterator begin() { return iterator(getFirst()); }
- iterator end() { return iterator(NULL); }
- iterator rbegin() { return iterator(getLast()); }
- iterator rend() { return iterator(NULL); }
+ iterator end() { return iterator(nullptr); }
};
//=====================================================
@@ -311,9 +308,9 @@ struct TC_GAME_API Loot
{
friend ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv);
- QuestItemMap const& GetPlayerQuestItems() const { return PlayerQuestItems; }
- QuestItemMap const& GetPlayerFFAItems() const { return PlayerFFAItems; }
- QuestItemMap const& GetPlayerNonQuestNonFFAConditionalItems() const { return PlayerNonQuestNonFFAConditionalItems; }
+ NotNormalLootItemMap const& GetPlayerQuestItems() const { return PlayerQuestItems; }
+ NotNormalLootItemMap const& GetPlayerFFAItems() const { return PlayerFFAItems; }
+ NotNormalLootItemMap const& GetPlayerNonQuestNonFFAConditionalItems() const { return PlayerNonQuestNonFFAConditionalItems; }
std::vector<LootItem> items;
std::vector<LootItem> quest_items;
@@ -343,15 +340,15 @@ struct TC_GAME_API Loot
// void clear();
void clear()
{
- for (QuestItemMap::const_iterator itr = PlayerQuestItems.begin(); itr != PlayerQuestItems.end(); ++itr)
+ for (NotNormalLootItemMap::const_iterator itr = PlayerQuestItems.begin(); itr != PlayerQuestItems.end(); ++itr)
delete itr->second;
PlayerQuestItems.clear();
- for (QuestItemMap::const_iterator itr = PlayerFFAItems.begin(); itr != PlayerFFAItems.end(); ++itr)
+ for (NotNormalLootItemMap::const_iterator itr = PlayerFFAItems.begin(); itr != PlayerFFAItems.end(); ++itr)
delete itr->second;
PlayerFFAItems.clear();
- for (QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.begin(); itr != PlayerNonQuestNonFFAConditionalItems.end(); ++itr)
+ for (NotNormalLootItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.begin(); itr != PlayerNonQuestNonFFAConditionalItems.end(); ++itr)
delete itr->second;
PlayerNonQuestNonFFAConditionalItems.clear();
@@ -380,7 +377,7 @@ struct TC_GAME_API Loot
// Inserts the item into the loot (called by LootTemplate processors)
void AddItem(LootStoreItem const & item);
- LootItem* LootItemInSlot(uint32 lootslot, Player* player, QuestItem** qitem = NULL, QuestItem** ffaitem = NULL, QuestItem** conditem = NULL);
+ LootItem* LootItemInSlot(uint32 lootslot, Player* player, NotNormalLootItem** qitem = NULL, NotNormalLootItem** ffaitem = NULL, NotNormalLootItem** conditem = NULL);
uint32 GetMaxSlotInLootFor(Player* player) const;
bool hasItemForAll() const;
bool hasItemFor(Player* player) const;
@@ -388,14 +385,14 @@ struct TC_GAME_API Loot
private:
void FillNotNormalLootFor(Player* player, bool presentAtLooting);
- QuestItemList* FillFFALoot(Player* player);
- QuestItemList* FillQuestLoot(Player* player);
- QuestItemList* FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting);
+ NotNormalLootItemList* FillFFALoot(Player* player);
+ NotNormalLootItemList* FillQuestLoot(Player* player);
+ NotNormalLootItemList* FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting);
GuidSet PlayersLooting;
- QuestItemMap PlayerQuestItems;
- QuestItemMap PlayerFFAItems;
- QuestItemMap PlayerNonQuestNonFFAConditionalItems;
+ NotNormalLootItemMap PlayerQuestItems;
+ NotNormalLootItemMap PlayerFFAItems;
+ NotNormalLootItemMap PlayerNonQuestNonFFAConditionalItems;
// All rolls are registered here. They need to know, when the loot is not valid anymore
LootValidatorRefManager i_LootValidatorRefManager;
diff --git a/src/server/game/Maps/MapRefManager.h b/src/server/game/Maps/MapRefManager.h
index 09aa67d43eb..14d1d59bd36 100644
--- a/src/server/game/Maps/MapRefManager.h
+++ b/src/server/game/Maps/MapRefManager.h
@@ -26,20 +26,17 @@ class MapReference;
class MapRefManager : public RefManager<Map, Player>
{
public:
- typedef LinkedListHead::Iterator< MapReference > iterator;
- typedef LinkedListHead::Iterator< MapReference const > const_iterator;
+ typedef LinkedListHead::Iterator<MapReference> iterator;
+ typedef LinkedListHead::Iterator<MapReference const> const_iterator;
- MapReference* getFirst() { return (MapReference*)RefManager<Map, Player>::getFirst(); }
+ MapReference* getFirst() { return (MapReference*)RefManager<Map, Player>::getFirst(); }
MapReference const* getFirst() const { return (MapReference const*)RefManager<Map, Player>::getFirst(); }
- MapReference* getLast() { return (MapReference*)RefManager<Map, Player>::getLast(); }
- MapReference const* getLast() const { return (MapReference const*)RefManager<Map, Player>::getLast(); }
iterator begin() { return iterator(getFirst()); }
- iterator end() { return iterator(NULL); }
- iterator rbegin() { return iterator(getLast()); }
- iterator rend() { return iterator(NULL); }
+ iterator end() { return iterator(nullptr); }
+
const_iterator begin() const { return const_iterator(getFirst()); }
- const_iterator end() const { return const_iterator(NULL); }
+ const_iterator end() const { return const_iterator(nullptr); }
};
#endif
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 7f77453d00b..bf913081fef 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -374,9 +374,9 @@ enum SpellAttr2
SPELL_ATTR2_IS_ARCANE_CONCENTRATION = 0x00800000, // 23 Only mage Arcane Concentration have this flag
SPELL_ATTR2_UNK24 = 0x01000000, // 24
SPELL_ATTR2_UNK25 = 0x02000000, // 25
- SPELL_ATTR2_UNK26 = 0x04000000, // 26 unaffected by school immunity
+ SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE = 0x04000000, // 26 unaffected by school immunity
SPELL_ATTR2_UNK27 = 0x08000000, // 27
- SPELL_ATTR2_UNK28 = 0x10000000, // 28
+ SPELL_ATTR2_IGNORE_ITEM_CHECK = 0x10000000, // 28 Spell is cast without checking item requirements (charges/reagents/totem)
SPELL_ATTR2_CANT_CRIT = 0x20000000, // 29 Spell can't crit
SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC = 0x40000000, // 30 spell can trigger even if triggered
SPELL_ATTR2_FOOD_BUFF = 0x80000000 // 31 Food or Drink Buff (like Well Fed)
@@ -472,7 +472,7 @@ enum SpellAttr5
SPELL_ATTR5_HASTE_AFFECT_DURATION = 0x00002000, // 13 haste effects decrease duration of this
SPELL_ATTR5_UNK14 = 0x00004000, // 14
SPELL_ATTR5_UNK15 = 0x00008000, // 15 Inflits on multiple targets?
- SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK = 0x00010000, // 16 this allows spells with EquippedItemClass to affect spells from other items if the required item is equipped
+ SPELL_ATTR5_UNK16 = 0x00010000, // 16
SPELL_ATTR5_USABLE_WHILE_FEARED = 0x00020000, // 17 usable while feared
SPELL_ATTR5_USABLE_WHILE_CONFUSED = 0x00040000, // 18 usable while confused
SPELL_ATTR5_DONT_TURN_DURING_CAST = 0x00080000, // 19 Blocks caster's turning when casting (client does not automatically turn caster's model to face UNIT_FIELD_TARGET)
@@ -517,7 +517,7 @@ enum SpellAttr6
SPELL_ATTR6_UNK22 = 0x00400000, // 22 only 72054
SPELL_ATTR6_UNK23 = 0x00800000, // 23
SPELL_ATTR6_CAN_TARGET_UNTARGETABLE = 0x01000000, // 24
- SPELL_ATTR6_UNK25 = 0x02000000, // 25 Exorcism, Flash of Light
+ SPELL_ATTR6_NOT_RESET_SWING_IF_INSTANT = 0x02000000, // 25 Exorcism, Flash of Light
SPELL_ATTR6_UNK26 = 0x04000000, // 26 related to player castable positive buff
SPELL_ATTR6_UNK27 = 0x08000000, // 27
SPELL_ATTR6_UNK28 = 0x10000000, // 28 Death Grip
@@ -548,7 +548,7 @@ enum SpellAttr7
SPELL_ATTR7_UNK17 = 0x00020000, // 17 Only 27965 (Suicide) spell.
SPELL_ATTR7_HAS_CHARGE_EFFECT = 0x00040000, // 18 Only spells that have Charge among effects.
SPELL_ATTR7_ZONE_TELEPORT = 0x00080000, // 19 Teleports to specific zones.
- SPELL_ATTR7_UNK20 = 0x00100000, // 20 Blink, Divine Shield, Ice Block
+ SPELL_ATTR7_USABLE_IN_STUN_FEAR_CONFUSION = 0x00100000, // 20 Blink, Divine Shield, Ice Block
SPELL_ATTR7_UNK21 = 0x00200000, // 21 Not set
SPELL_ATTR7_UNK22 = 0x00400000, // 22
SPELL_ATTR7_UNK23 = 0x00800000, // 23 Motivate, Mutilate, Shattering Throw
@@ -1286,10 +1286,11 @@ enum SpellImmunity
IMMUNITY_DAMAGE = 3, // enum SpellSchoolMask
IMMUNITY_DISPEL = 4, // enum DispelType
IMMUNITY_MECHANIC = 5, // enum Mechanics
- IMMUNITY_ID = 6
+ IMMUNITY_ID = 6,
+
+ MAX_SPELL_IMMUNITY
};
-#define MAX_SPELL_IMMUNITY 7
// target enum name consist of:
// TARGET_[OBJECT_TYPE]_[REFERENCE_TYPE(skipped for caster)]_[SELECTION_TYPE(skipped for default)]_[additional specifiers(friendly, BACK_LEFT, etc.]
@@ -3114,7 +3115,7 @@ enum DiminishingReturnsType
};
// Diminishing Return Groups
-enum DiminishingGroup
+enum DiminishingGroup : uint16
{
DIMINISHING_NONE = 0,
DIMINISHING_BANISH = 1,
@@ -3136,7 +3137,9 @@ enum DiminishingGroup
DIMINISHING_SLEEP = 17,
DIMINISHING_TAUNT = 18,
DIMINISHING_LIMITONLY = 19,
- DIMINISHING_DRAGONS_BREATH = 20
+ DIMINISHING_DRAGONS_BREATH = 20,
+
+ DIMINISHING_MAX
};
enum SummonCategory
diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
index bae8e541ddc..61916504758 100644
--- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
@@ -34,8 +34,8 @@ void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner)
owner->ClearUnitState(UNIT_STATE_EVADE);
owner->SetWalk(true);
owner->LoadCreaturesAddon();
- owner->SetSpawnHealth();
owner->AI()->JustReachedHome();
+ owner->SetSpawnHealth();
}
}
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index d0079ad1524..b9357d60967 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -1202,12 +1202,11 @@ void ScriptMgr::FillSpellSummary()
}
}
-template<typename T, typename F>
-void CreateSpellOrAuraScripts(uint32 spellId, std::list<T*>& scriptVector, F&& extractor)
+template<typename T, typename F, typename O>
+void CreateSpellOrAuraScripts(uint32 spellId, std::vector<T*>& scriptVector, F&& extractor, O* objectInvoker)
{
SpellScriptsBounds bounds = sObjectMgr->GetSpellScriptsBounds(spellId);
-
- for (SpellScriptsContainer::iterator itr = bounds.first; itr != bounds.second; ++itr)
+ for (auto itr = bounds.first; itr != bounds.second; ++itr)
{
// When the script is disabled continue with the next one
if (!itr->second.second)
@@ -1218,24 +1217,28 @@ void CreateSpellOrAuraScripts(uint32 spellId, std::list<T*>& scriptVector, F&& e
continue;
T* script = (*tmpscript.*extractor)();
-
if (!script)
continue;
script->_Init(&tmpscript->GetName(), spellId);
+ if (!script->_Load(objectInvoker))
+ {
+ delete script;
+ continue;
+ }
scriptVector.push_back(script);
}
}
-void ScriptMgr::CreateSpellScripts(uint32 spellId, std::list<SpellScript*>& scriptVector)
+void ScriptMgr::CreateSpellScripts(uint32 spellId, std::vector<SpellScript*>& scriptVector, Spell* invoker) const
{
- CreateSpellOrAuraScripts(spellId, scriptVector, &SpellScriptLoader::GetSpellScript);
+ CreateSpellOrAuraScripts(spellId, scriptVector, &SpellScriptLoader::GetSpellScript, invoker);
}
-void ScriptMgr::CreateAuraScripts(uint32 spellId, std::list<AuraScript*>& scriptVector)
+void ScriptMgr::CreateAuraScripts(uint32 spellId, std::vector<AuraScript*>& scriptVector, Aura* invoker) const
{
- CreateSpellOrAuraScripts(spellId, scriptVector, &SpellScriptLoader::GetAuraScript);
+ CreateSpellOrAuraScripts(spellId, scriptVector, &SpellScriptLoader::GetAuraScript, invoker);
}
SpellScriptLoader* ScriptMgr::GetSpellScriptLoader(uint32 scriptId)
@@ -1641,6 +1644,8 @@ bool ScriptMgr::CanSpawn(ObjectGuid::LowType spawnId, uint32 entry, CreatureTemp
ASSERT(actTemplate);
CreatureTemplate const* baseTemplate = sObjectMgr->GetCreatureTemplate(entry);
+ if (!baseTemplate)
+ baseTemplate = actTemplate;
GET_SCRIPT_RET(CreatureScript, baseTemplate->ScriptID, tmpscript, true);
return tmpscript->CanSpawn(spawnId, entry, baseTemplate, actTemplate, cData, map);
}
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index a6cce299645..22a84804089 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -29,6 +29,7 @@
class AccountMgr;
class AuctionHouseObject;
+class Aura;
class AuraScript;
class Battleground;
class BattlegroundMap;
@@ -896,8 +897,8 @@ class TC_GAME_API ScriptMgr
public: /* SpellScriptLoader */
- void CreateSpellScripts(uint32 spellId, std::list<SpellScript*>& scriptVector);
- void CreateAuraScripts(uint32 spellId, std::list<AuraScript*>& scriptVector);
+ void CreateSpellScripts(uint32 spellId, std::vector<SpellScript*>& scriptVector, Spell* invoker) const;
+ void CreateAuraScripts(uint32 spellId, std::vector<AuraScript*>& scriptVector, Aura* invoker) const;
SpellScriptLoader* GetSpellScriptLoader(uint32 scriptId);
public: /* ServerScript */
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 980926a476c..2b4e2e4177d 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -99,8 +99,8 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleAuraModSchoolImmunity, // 39 SPELL_AURA_SCHOOL_IMMUNITY
&AuraEffect::HandleAuraModDmgImmunity, // 40 SPELL_AURA_DAMAGE_IMMUNITY
&AuraEffect::HandleAuraModDispelImmunity, // 41 SPELL_AURA_DISPEL_IMMUNITY
- &AuraEffect::HandleNoImmediateEffect, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in Unit::ProcDamageAndSpellFor and Unit::HandleProcTriggerSpell
- &AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in Unit::ProcDamageAndSpellFor
+ &AuraEffect::HandleNoImmediateEffect, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in AuraEffect::HandleProc
+ &AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in AuraEffect::HandleProc
&AuraEffect::HandleAuraTrackCreatures, // 44 SPELL_AURA_TRACK_CREATURES
&AuraEffect::HandleAuraTrackResources, // 45 SPELL_AURA_TRACK_RESOURCES
&AuraEffect::HandleNULL, // 46 SPELL_AURA_46 (used in test spells 54054 and 54058, and spell 48050) (3.0.8a)
@@ -204,7 +204,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleNoImmediateEffect, //144 SPELL_AURA_SAFE_FALL implemented in WorldSession::HandleMovementOpcodes
&AuraEffect::HandleAuraModPetTalentsPoints, //145 SPELL_AURA_MOD_PET_TALENT_POINTS
&AuraEffect::HandleNoImmediateEffect, //146 SPELL_AURA_ALLOW_TAME_PET_TYPE
- &AuraEffect::HandleModStateImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK
+ &AuraEffect::HandleModMechanicImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK
&AuraEffect::HandleAuraRetainComboPoints, //148 SPELL_AURA_RETAIN_COMBO_POINTS
&AuraEffect::HandleNoImmediateEffect, //149 SPELL_AURA_REDUCE_PUSHBACK
&AuraEffect::HandleShieldBlockValue, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT
@@ -308,7 +308,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleNoImmediateEffect, //248 SPELL_AURA_MOD_COMBAT_RESULT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
&AuraEffect::HandleAuraConvertRune, //249 SPELL_AURA_CONVERT_RUNE
&AuraEffect::HandleAuraModIncreaseHealth, //250 SPELL_AURA_MOD_INCREASE_HEALTH_2
- &AuraEffect::HandleNoImmediateEffect, //251 SPELL_AURA_MOD_ENEMY_DODGE
+ &AuraEffect::HandleNoImmediateEffect, //251 SPELL_AURA_MOD_ENEMY_DODGE implemented in Unit::GetUnitDodgeChance
&AuraEffect::HandleModCombatSpeedPct, //252 SPELL_AURA_252 Is there any difference between this and SPELL_AURA_MELEE_SLOW ? maybe not stacking mod?
&AuraEffect::HandleNoImmediateEffect, //253 SPELL_AURA_MOD_BLOCK_CRIT_CHANCE implemented in Unit::isBlockCritical
&AuraEffect::HandleAuraModDisarm, //254 SPELL_AURA_MOD_DISARM_OFFHAND
@@ -319,7 +319,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleNoImmediateEffect, //259 SPELL_AURA_MOD_HOT_PCT implemented in Unit::SpellHealingBonus
&AuraEffect::HandleNoImmediateEffect, //260 SPELL_AURA_SCREEN_EFFECT (miscvalue = id in ScreenEffect.dbc) not required any code
&AuraEffect::HandlePhase, //261 SPELL_AURA_PHASE
- &AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in spell::cancast
+ &AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in Spell::CheckCast
&AuraEffect::HandleAuraAllowOnlyAbility, //263 SPELL_AURA_ALLOW_ONLY_ABILITY player can use only abilities set in SpellClassMask
&AuraEffect::HandleUnused, //264 unused (3.2.0)
&AuraEffect::HandleUnused, //265 unused (3.2.0)
@@ -494,7 +494,7 @@ int32 AuraEffect::CalculateAmount(Unit* caster)
return amount;
}
-void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load)
+void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer /*= true*/, bool load /*= false*/)
{
m_amplitude = m_spellInfo->Effects[m_effIndex].Amplitude;
@@ -528,14 +528,13 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load)
if (!m_isPeriodic)
return;
- Player* modOwner = caster ? caster->GetSpellModOwner() : NULL;
-
+ Player* modOwner = caster ? caster->GetSpellModOwner() : nullptr;
// Apply casting time mods
if (m_amplitude)
{
// Apply periodic time mod
if (modOwner)
- modOwner->ApplySpellMod(GetId(), SPELLMOD_ACTIVATION_TIME, m_amplitude);
+ modOwner->ApplySpellMod<SPELLMOD_ACTIVATION_TIME>(GetId(), m_amplitude);
if (caster)
{
@@ -558,12 +557,9 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load)
else // aura just created or reapplied
{
m_tickNumber = 0;
- // reset periodic timer on aura create or on reapply when aura isn't dot
- // possibly we should not reset periodic timers only when aura is triggered by proc
- // or maybe there's a spell attribute somewhere
- bool resetPeriodicTimer = create
- || ((GetAuraType() != SPELL_AURA_PERIODIC_DAMAGE) && (GetAuraType() != SPELL_AURA_PERIODIC_DAMAGE_PERCENT));
+ // reset periodic timer on aura create or reapply
+ // we don't reset periodic timers when aura is triggered by proc
if (resetPeriodicTimer)
{
m_periodicTimer = 0;
@@ -588,7 +584,6 @@ void AuraEffect::CalculateSpellMod()
m_spellmod->type = SpellModType(uint32(GetAuraType())); // SpellModType value == spell aura types
m_spellmod->spellId = GetId();
m_spellmod->mask = GetSpellInfo()->Effects[GetEffIndex()].SpellClassMask;
- m_spellmod->charges = GetBase()->GetCharges();
}
m_spellmod->value = GetAmount();
break;
@@ -895,14 +890,12 @@ bool AuraEffect::IsAffectedOnSpell(SpellInfo const* spell) const
{
if (!spell)
return false;
- // Check family name
- if (spell->SpellFamilyName != m_spellInfo->SpellFamilyName)
+
+ // Check family name and EffectClassMask
+ if (!spell->IsAffected(m_spellInfo->SpellFamilyName, m_spellInfo->Effects[m_effIndex].SpellClassMask))
return false;
- // Check EffectClassMask
- if (m_spellInfo->Effects[m_effIndex].SpellClassMask & spell->SpellFamilyFlags)
- return true;
- return false;
+ return true;
}
void AuraEffect::SendTickImmune(Unit* target, Unit* caster) const
@@ -961,6 +954,80 @@ void AuraEffect::PeriodicTick(AuraApplication * aurApp, Unit* caster) const
}
}
+bool AuraEffect::CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) const
+{
+ bool result = GetBase()->CallScriptCheckEffectProcHandlers(this, aurApp, eventInfo);
+ if (!result)
+ return false;
+
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ switch (GetAuraType())
+ {
+ case SPELL_AURA_MOD_CONFUSE:
+ case SPELL_AURA_MOD_FEAR:
+ case SPELL_AURA_MOD_STUN:
+ case SPELL_AURA_MOD_ROOT:
+ case SPELL_AURA_TRANSFORM:
+ {
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return false;
+
+ // Spell own damage at apply won't break CC
+ if (spellInfo && spellInfo == GetSpellInfo())
+ {
+ Aura* aura = GetBase();
+ // called from spellcast, should not have ticked yet
+ if (aura->GetDuration() == aura->GetMaxDuration())
+ return false;
+ }
+ break;
+ }
+ case SPELL_AURA_MECHANIC_IMMUNITY:
+ case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
+ // compare mechanic
+ if (!spellInfo || static_cast<int32>(spellInfo->Mechanic) != GetMiscValue())
+ return false;
+ break;
+ case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK:
+ // skip melee hits and instant cast spells
+ if (!spellInfo || !spellInfo->CalcCastTime())
+ return false;
+ break;
+ case SPELL_AURA_MOD_DAMAGE_FROM_CASTER:
+ // Compare casters
+ if (GetCasterGUID() != eventInfo.GetActor()->GetGUID())
+ return false;
+ break;
+ case SPELL_AURA_MOD_POWER_COST_SCHOOL:
+ case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT:
+ // Skip melee hits and spells with wrong school or zero cost
+ if (!spellInfo || (!spellInfo->ManaCost && !spellInfo->ManaCostPercentage) || // Cost Check
+ !(spellInfo->GetSchoolMask() & GetMiscValue())) // School Check
+ return false;
+ break;
+ case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
+ // Skip melee hits and spells with wrong school
+ if (!spellInfo || !(spellInfo->GetSchoolMask() & GetMiscValue()))
+ return false;
+ break;
+ case SPELL_AURA_PROC_TRIGGER_SPELL:
+ case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE:
+ {
+ // Don't proc extra attacks while already processing extra attack spell
+ uint32 triggerSpellId = GetSpellInfo()->Effects[GetEffIndex()].TriggerSpell;
+ if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId))
+ if (aurApp->GetTarget()->m_extraAttacks && triggeredSpellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
+ return false;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return result;
+}
+
void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
bool prevented = GetBase()->CallScriptEffectProcHandlers(this, aurApp, eventInfo);
@@ -969,6 +1036,16 @@ void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
switch (GetAuraType())
{
+ // CC Auras which use their amount to drop
+ // Are there any more auras which need this?
+ case SPELL_AURA_MOD_CONFUSE:
+ case SPELL_AURA_MOD_FEAR:
+ case SPELL_AURA_MOD_STUN:
+ case SPELL_AURA_MOD_ROOT:
+ case SPELL_AURA_TRANSFORM:
+ HandleBreakableCCAuraProc(aurApp, eventInfo);
+ break;
+ case SPELL_AURA_DUMMY:
case SPELL_AURA_PROC_TRIGGER_SPELL:
HandleProcTriggerSpellAuraProc(aurApp, eventInfo);
break;
@@ -1094,15 +1171,15 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
if (apply)
{
if (spellId)
- target->CastSpell(target, spellId, true, NULL, this);
+ target->CastSpell(target, spellId, true, nullptr, this);
if (spellId2)
- target->CastSpell(target, spellId2, true, NULL, this);
+ target->CastSpell(target, spellId2, true, nullptr, this);
if (target->GetTypeId() == TYPEID_PLAYER)
{
- const PlayerSpellMap& sp_list = target->ToPlayer()->GetSpellMap();
- for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
+ PlayerSpellMap const& sp_list = target->ToPlayer()->GetSpellMap();
+ for (auto itr = sp_list.begin(); itr != sp_list.end(); ++itr)
{
if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled)
continue;
@@ -1111,11 +1188,11 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
continue;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
- if (!spellInfo || !(spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE) || spellInfo->HasAttribute(SPELL_ATTR0_HIDDEN_CLIENTSIDE)))
+ if (!spellInfo || !(spellInfo->IsPassive() || spellInfo->HasAttribute(SPELL_ATTR0_HIDDEN_CLIENTSIDE)))
continue;
if (spellInfo->Stances & (UI64LIT(1) << (GetMiscValue() - 1)))
- target->CastSpell(target, itr->first, true, NULL, this);
+ target->CastSpell(target, itr->first, true, nullptr, this);
}
// Also do it for Glyphs
@@ -1130,7 +1207,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
continue;
if (spellInfo->Stances & (UI64LIT(1) << (GetMiscValue() - 1)))
- target->CastSpell(target, glyph->SpellId, true, NULL, this);
+ target->CastSpell(target, glyph->SpellId, true, nullptr, this);
}
}
}
@@ -1140,7 +1217,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(24932);
if (spellInfo && spellInfo->Stances & (UI64LIT(1) << (GetMiscValue() - 1)))
- target->CastSpell(target, 24932, true, NULL, this);
+ target->CastSpell(target, 24932, true, nullptr, this);
}
// Improved Barkskin - apply/remove armor bonus due to shapeshift
if (target->ToPlayer()->HasSpell(63410) || target->ToPlayer()->HasSpell(63411))
@@ -1153,14 +1230,14 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
if (HotWSpellId)
{ // hacky, but the only way as spell family is not SPELLFAMILY_DRUID
Unit::AuraEffectList const& mModTotalStatPct = target->GetAuraEffectsByType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE);
- for (Unit::AuraEffectList::const_iterator i = mModTotalStatPct.begin(); i != mModTotalStatPct.end(); ++i)
+ for (AuraEffect const* aurEff : mModTotalStatPct)
{
// Heart of the Wild
- if ((*i)->GetSpellInfo()->SpellIconID == 240 && (*i)->GetMiscValue() == 3)
+ if (aurEff->GetSpellInfo()->SpellIconID == 240 && aurEff->GetMiscValue() == 3)
{
- int32 HotWMod = (*i)->GetAmount() / 2; // For each 2% Intelligence, you get 1% stamina and 1% attack power.
+ int32 HotWMod = aurEff->GetAmount() / 2; // For each 2% Intelligence, you get 1% stamina and 1% attack power.
- target->CastCustomSpell(target, HotWSpellId, &HotWMod, NULL, NULL, true, NULL, this);
+ target->CastCustomSpell(HotWSpellId, SPELLVALUE_BASE_POINT0, HotWMod, target, true, nullptr, this);
break;
}
}
@@ -1184,13 +1261,13 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
spellId3 = 47180;
break;
}
- target->CastSpell(target, spellId3, true, NULL, this);
+ target->CastSpell(target, spellId3, true, nullptr, this);
}
// Master Shapeshifter - Cat
if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0))
{
int32 bp = aurEff->GetAmount();
- target->CastCustomSpell(target, 48420, &bp, NULL, NULL, true);
+ target->CastCustomSpell(48420, SPELLVALUE_BASE_POINT0, bp, target, true);
}
break;
case FORM_DIREBEAR:
@@ -1199,13 +1276,13 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0))
{
int32 bp = aurEff->GetAmount();
- target->CastCustomSpell(target, 48418, &bp, NULL, NULL, true);
+ target->CastCustomSpell(48418, SPELLVALUE_BASE_POINT0, bp, target, true);
}
// Survival of the Fittest
if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, SPELLFAMILY_DRUID, 961, 0))
{
int32 bp = aurEff->GetSpellInfo()->Effects[EFFECT_2].CalcValue();
- target->CastCustomSpell(target, 62069, &bp, NULL, NULL, true, 0, this);
+ target->CastCustomSpell(62069, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, this);
}
break;
case FORM_MOONKIN:
@@ -1213,7 +1290,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0))
{
int32 bp = aurEff->GetAmount();
- target->CastCustomSpell(target, 48421, &bp, NULL, NULL, true);
+ target->CastCustomSpell(48421, SPELLVALUE_BASE_POINT0, bp, target, true);
}
break;
// Master Shapeshifter - Tree of Life
@@ -1221,7 +1298,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0))
{
int32 bp = aurEff->GetAmount();
- target->CastCustomSpell(target, 48422, &bp, NULL, NULL, true);
+ target->CastCustomSpell(48422, SPELLVALUE_BASE_POINT0, bp, target, true);
}
break;
}
@@ -1235,7 +1312,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
target->RemoveOwnedAura(spellId2, target->GetGUID());
// Improved Barkskin - apply/remove armor bonus due to shapeshift
- if (Player* player=target->ToPlayer())
+ if (Player* player = target->ToPlayer())
{
if (player->HasSpell(63410) || player->HasSpell(63411))
{
@@ -1244,19 +1321,20 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
}
}
- const Unit::AuraEffectList& shapeshifts = target->GetAuraEffectsByType(SPELL_AURA_MOD_SHAPESHIFT);
- AuraEffect* newAura = NULL;
+ Unit::AuraEffectList const& shapeshifts = target->GetAuraEffectsByType(SPELL_AURA_MOD_SHAPESHIFT);
+ AuraEffect const* newAura = nullptr;
// Iterate through all the shapeshift auras that the target has, if there is another aura with SPELL_AURA_MOD_SHAPESHIFT, then this aura is being removed due to that one being applied
- for (Unit::AuraEffectList::const_iterator itr = shapeshifts.begin(); itr != shapeshifts.end(); ++itr)
+ for (AuraEffect const* aurEff : shapeshifts)
{
- if ((*itr) != this)
+ if (aurEff != this)
{
- newAura = *itr;
+ newAura = aurEff;
break;
}
}
+
Unit::AuraApplicationMap& tAuras = target->GetAppliedAuras();
- for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
+ for (auto itr = tAuras.begin(); itr != tAuras.end();)
{
// Use the new aura to see on what stance the target will be
uint64 newStance = newAura ? (UI64LIT(1) << (newAura->GetMiscValue() - 1)) : 0;
@@ -1697,7 +1775,12 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
if (aurApp->GetRemoveMode())
return;
+ ShapeshiftForm prevForm = target->GetShapeshiftForm();
target->SetShapeshiftForm(form);
+ // add the shapeshift aura's boosts
+ if (prevForm != form)
+ HandleShapeshiftBoosts(target, true);
+
if (modelid > 0)
{
SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(target->getTransForm());
@@ -1769,11 +1852,10 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
default:
break;
}
- }
- // adding/removing linked auras
- // add/remove the shapeshift aura's boosts
- HandleShapeshiftBoosts(target, apply);
+ // remove the shapeshift aura's boosts
+ HandleShapeshiftBoosts(target, false);
+ }
if (target->GetTypeId() == TYPEID_PLAYER)
target->ToPlayer()->InitDataForForm();
@@ -2225,11 +2307,9 @@ void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode,
{
uint8 attacktype = Player::GetAttackBySlot(slot);
+ player->ApplyItemDependentAuras(item, !apply);
if (attacktype < MAX_ATTACK)
- {
player->_ApplyWeaponDamage(slot, item->GetTemplate(), NULL, !apply);
- player->_ApplyWeaponDependentAuraMods(item, WeaponAttackType(attacktype), !apply);
- }
}
}
@@ -2987,249 +3067,13 @@ void AuraEffect::HandleAuraModUseNormalSpeed(AuraApplication const* aurApp, uint
/*** IMMUNITY ***/
/*********************************************************/
-void AuraEffect::HandleModStateImmunityMask(AuraApplication const* aurApp, uint8 mode, bool apply) const
+void AuraEffect::HandleModMechanicImmunityMask(AuraApplication const* aurApp, uint8 mode, bool apply) const
{
if (!(mode & AURA_EFFECT_HANDLE_REAL))
return;
Unit* target = aurApp->GetTarget();
- std::list <AuraType> aura_immunity_list;
- uint32 mechanic_immunity_list = 0;
- int32 miscVal = GetMiscValue();
-
- switch (miscVal)
- {
- case 27:
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SILENCE, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_SILENCE);
- break;
- case 96:
- case 1615:
- {
- if (GetAmount())
- {
- mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT)
- | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN)
- | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM)
- | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR)
- | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED)
- | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN);
-
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT);
- aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE);
- aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR);
- }
- break;
- }
- case 679:
- {
- if (GetId() == 57742)
- {
- mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT)
- | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN)
- | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM)
- | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR)
- | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED)
- | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN);
-
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT);
- aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE);
- aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR);
- }
- break;
- }
- case 1557:
- {
- if (GetId() == 64187)
- {
- mechanic_immunity_list = (1 << MECHANIC_STUN);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- }
- else
- {
- mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT)
- | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN)
- | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM)
- | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR)
- | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED)
- | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN);
-
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT);
- aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE);
- aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR);
- }
- break;
- }
- case 1614:
- case 1694:
- {
- target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_TAUNT);
- break;
- }
- case 1630:
- {
- if (!GetAmount())
- {
- target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_TAUNT);
- }
- else
- {
- mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT)
- | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN)
- | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM)
- | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR)
- | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED)
- | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN);
-
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT);
- aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE);
- aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR);
- }
- break;
- }
- case 477:
- case 1733:
- {
- if (!GetAmount())
- {
- mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT)
- | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN)
- | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM)
- | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR)
- | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED)
- | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN);
-
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT);
- aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE);
- aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR);
- }
- break;
- }
- case 878:
- {
- if (GetAmount() == 1)
- {
- mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_STUN)
- | (1 << MECHANIC_DISORIENTED) | (1 << MECHANIC_FREEZE);
-
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
- }
- break;
- }
- default:
- break;
- }
-
- if (aura_immunity_list.empty())
- {
- if (miscVal & (1<<10))
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- if (miscVal & (1<<1))
- aura_immunity_list.push_back(SPELL_AURA_TRANSFORM);
-
- // These flag can be recognized wrong:
- if (miscVal & (1<<6))
- aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
- if (miscVal & (1<<0))
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT);
- if (miscVal & (1<<2))
- aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE);
- if (miscVal & (1<<9))
- aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR);
- if (miscVal & (1<<7))
- aura_immunity_list.push_back(SPELL_AURA_MOD_DISARM);
- }
-
- // apply immunities
- for (std::list <AuraType>::iterator iter = aura_immunity_list.begin(); iter != aura_immunity_list.end(); ++iter)
- target->ApplySpellImmune(GetId(), IMMUNITY_STATE, *iter, apply);
-
- if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
- {
- target->RemoveAurasWithMechanic(mechanic_immunity_list, AURA_REMOVE_BY_DEFAULT, GetId());
- for (std::list <AuraType>::iterator iter = aura_immunity_list.begin(); iter != aura_immunity_list.end(); ++iter)
- target->RemoveAurasByType(*iter);
- }
+ m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetEffIndex(), apply);
}
void AuraEffect::HandleModMechanicImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -3238,52 +3082,7 @@ void AuraEffect::HandleModMechanicImmunity(AuraApplication const* aurApp, uint8
return;
Unit* target = aurApp->GetTarget();
- uint32 mechanic;
-
- switch (GetId())
- {
- case 34471: // The Beast Within
- case 19574: // Bestial Wrath
- mechanic = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_KNOCKOUT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_BANISH, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SHACKLE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DAZE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
- break;
- case 42292: // PvP trinket
- case 59752: // Every Man for Himself
- case 53490: // Bullheaded
- mechanic = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
- // Actually we should apply immunities here, too, but the aura has only 100 ms duration, so there is practically no point
- break;
- case 54508: // Demonic Empowerment
- mechanic = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- break;
- default:
- if (GetMiscValue() < 1)
- return;
- mechanic = 1 << GetMiscValue();
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, GetMiscValue(), apply);
- break;
- }
-
- if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
- target->RemoveAurasWithMechanic(mechanic, AURA_REMOVE_BY_DEFAULT, GetId());
+ m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetEffIndex(), apply);
}
void AuraEffect::HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -3292,8 +3091,7 @@ void AuraEffect::HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint
return;
Unit* target = aurApp->GetTarget();
-
- target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, GetMiscValue(), apply);
+ m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetEffIndex(), apply);
// when removing flag aura, handle flag drop
Player* player = target->ToPlayer();
@@ -3315,11 +3113,7 @@ void AuraEffect::HandleAuraModStateImmunity(AuraApplication const* aurApp, uint8
return;
Unit* target = aurApp->GetTarget();
-
- target->ApplySpellImmune(GetId(), IMMUNITY_STATE, GetMiscValue(), apply);
-
- if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
- target->RemoveAurasByType(AuraType(GetMiscValue()), ObjectGuid::Empty, GetBase());
+ m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetEffIndex(), apply);
}
void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -3328,8 +3122,7 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint
return;
Unit* target = aurApp->GetTarget();
-
- target->ApplySpellImmune(GetId(), IMMUNITY_SCHOOL, GetMiscValue(), (apply));
+ m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetEffIndex(), apply);
if (GetSpellInfo()->Mechanic == MECHANIC_BANISH)
{
@@ -3339,12 +3132,15 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint
{
bool banishFound = false;
Unit::AuraEffectList const& banishAuras = target->GetAuraEffectsByType(GetAuraType());
- for (Unit::AuraEffectList::const_iterator i = banishAuras.begin(); i != banishAuras.end(); ++i)
- if ((*i)->GetSpellInfo()->Mechanic == MECHANIC_BANISH)
+ for (AuraEffect const* aurEff : banishAuras)
+ {
+ if (aurEff->GetSpellInfo()->Mechanic == MECHANIC_BANISH)
{
banishFound = true;
break;
}
+ }
+
if (!banishFound)
target->ClearUnitState(UNIT_STATE_ISOLATED);
}
@@ -3357,28 +3153,6 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint
if (GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
&& GetSpellInfo()->HasAttribute(SPELL_ATTR2_DAMAGE_REDUCED_SHIELD))
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
-
- /// @todo optimalize this cycle - use RemoveAurasWithInterruptFlags call or something else
- if ((apply)
- && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
- && GetSpellInfo()->IsPositive()) //Only positive immunity removes auras
- {
- uint32 school_mask = GetMiscValue();
- Unit::AuraApplicationMap& Auras = target->GetAppliedAuras();
- for (Unit::AuraApplicationMap::iterator iter = Auras.begin(); iter != Auras.end();)
- {
- SpellInfo const* spell = iter->second->GetBase()->GetSpellInfo();
- if ((spell->GetSchoolMask() & school_mask)//Check for school mask
- && GetSpellInfo()->CanDispelAura(spell)
- && !iter->second->IsPositive() //Don't remove positive spells
- && spell->Id != GetId()) //Don't remove self
- {
- target->RemoveAura(iter);
- }
- else
- ++iter;
- }
- }
}
void AuraEffect::HandleAuraModDmgImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -3387,8 +3161,7 @@ void AuraEffect::HandleAuraModDmgImmunity(AuraApplication const* aurApp, uint8 m
return;
Unit* target = aurApp->GetTarget();
-
- target->ApplySpellImmune(GetId(), IMMUNITY_DAMAGE, GetMiscValue(), apply);
+ m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetEffIndex(), apply);
}
void AuraEffect::HandleAuraModDispelImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -3397,8 +3170,7 @@ void AuraEffect::HandleAuraModDispelImmunity(AuraApplication const* aurApp, uint
return;
Unit* target = aurApp->GetTarget();
-
- target->ApplySpellDispelImmunity(m_spellInfo, DispelType(GetMiscValue()), (apply));
+ m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetEffIndex(), apply);
}
/*********************************************************/
@@ -3994,29 +3766,14 @@ void AuraEffect::HandleAuraModWeaponCritPercent(AuraApplication const* aurApp, u
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
- Unit* target = aurApp->GetTarget();
+ Player* target = aurApp->GetTarget()->ToPlayer();
- if (target->GetTypeId() != TYPEID_PLAYER)
+ if (!target)
return;
- for (int i = 0; i < MAX_ATTACK; ++i)
- if (Item* pItem = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true))
- target->ToPlayer()->_ApplyWeaponDependentAuraCritMod(pItem, WeaponAttackType(i), this, apply);
-
- // mods must be applied base at equipped weapon class and subclass comparison
- // with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask
- // GetMiscValue() comparison with item generated damage types
-
- if (GetSpellInfo()->EquippedItemClass == -1)
- {
- target->ToPlayer()->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
- target->ToPlayer()->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
- target->ToPlayer()->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
- }
- else
- {
- // done in Player::_ApplyWeaponDependentAuraMods
- }
+ target->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float(GetAmount()), apply);
+ target->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float(GetAmount()), apply);
+ target->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float(GetAmount()), apply);
}
void AuraEffect::HandleModHitChance(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -4317,6 +4074,7 @@ void AuraEffect::HandleAuraModAttackPowerOfArmor(AuraApplication const* aurApp,
if (target->GetTypeId() == TYPEID_PLAYER)
target->ToPlayer()->UpdateAttackPowerAndDamage(false);
}
+
/********************************/
/*** DAMAGE BONUS ***/
/********************************/
@@ -4327,79 +4085,22 @@ void AuraEffect::HandleModDamageDone(AuraApplication const* aurApp, uint8 mode,
Unit* target = aurApp->GetTarget();
- // apply item specific bonuses for already equipped weapon
- if (target->GetTypeId() == TYPEID_PLAYER)
- {
- for (int i = 0; i < MAX_ATTACK; ++i)
- if (Item* pItem = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true))
- target->ToPlayer()->_ApplyWeaponDependentAuraDamageMod(pItem, WeaponAttackType(i), this, apply);
- }
-
- // GetMiscValue() is bitmask of spell schools
- // 1 (0-bit) - normal school damage (SPELL_SCHOOL_MASK_NORMAL)
- // 126 - full bitmask all magic damages (SPELL_SCHOOL_MASK_MAGIC) including wands
- // 127 - full bitmask any damages
- //
- // mods must be applied base at equipped weapon class and subclass comparison
- // with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask
- // GetMiscValue() comparison with item generated damage types
-
- if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0)
- {
- // apply generic physical damage bonuses including wand case
- if (GetSpellInfo()->EquippedItemClass == -1 || target->GetTypeId() != TYPEID_PLAYER)
- {
- target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(GetAmount()), apply);
- target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(GetAmount()), apply);
- target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(GetAmount()), apply);
-
- if (target->GetTypeId() == TYPEID_PLAYER)
- {
- if (GetAmount() > 0)
- target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, GetAmount(), apply);
- else
- target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, GetAmount(), apply);
- }
- }
- else
- {
- // done in Player::_ApplyWeaponDependentAuraMods
- }
- }
-
- // Skip non magic case for speedup
- if ((GetMiscValue() & SPELL_SCHOOL_MASK_MAGIC) == 0)
- return;
-
- if (GetSpellInfo()->EquippedItemClass != -1 || GetSpellInfo()->EquippedItemInventoryTypeMask != 0)
+ if (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
{
- // wand magic case (skip generic to all item spell bonuses)
- // done in Player::_ApplyWeaponDependentAuraMods
-
- // Skip item specific requirements for not wand magic damage
- return;
+ target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(GetAmount()), apply);
+ target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(GetAmount()), apply);
+ target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(GetAmount()), apply);
}
- // Magic damage modifiers implemented in Unit::SpellDamageBonus
+ // Magic damage modifiers implemented in Unit::SpellBaseDamageBonusDone
// This information for client side use only
if (target->GetTypeId() == TYPEID_PLAYER)
{
- if (GetAmount() > 0)
- {
- for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
- {
- if ((GetMiscValue() & (1<<i)) != 0)
- target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, GetAmount(), apply);
- }
- }
- else
- {
- for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
- {
- if ((GetMiscValue() & (1<<i)) != 0)
- target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG+i, GetAmount(), apply);
- }
- }
+ uint16 baseField = GetAmount() >= 0 ? PLAYER_FIELD_MOD_DAMAGE_DONE_POS : PLAYER_FIELD_MOD_DAMAGE_DONE_NEG;
+ for (uint16 i = 0; i < MAX_SPELL_SCHOOL; ++i)
+ if (GetMiscValue() & (1 << i))
+ target->ApplyModUInt32Value(baseField + i, GetAmount(), apply);
+
if (Guardian* pet = target->ToPlayer()->GetGuardianPet())
pet->UpdateAttackPowerAndDamage();
}
@@ -4415,14 +4116,7 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8
if (abs(spellGroupVal) >= abs(GetAmount()))
return;
- if (target->GetTypeId() == TYPEID_PLAYER)
- {
- for (int i = 0; i < MAX_ATTACK; ++i)
- if (Item* item = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), false))
- target->ToPlayer()->_ApplyWeaponDependentAuraDamageMod(item, WeaponAttackType(i), this, apply);
- }
-
- if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) && (GetSpellInfo()->EquippedItemClass == -1 || target->GetTypeId() != TYPEID_PLAYER))
+ if (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
{
if (spellGroupVal)
{
@@ -4430,22 +4124,25 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8
target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(spellGroupVal), !apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(spellGroupVal), !apply);
}
+
target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(GetAmount()), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(GetAmount()), apply);
+ }
- if (Player* player = target->ToPlayer())
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ {
+ for (uint16 i = 0; i < MAX_SPELL_SCHOOL; ++i)
{
- if (spellGroupVal)
- player->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float(spellGroupVal), !apply);
+ if (GetMiscValue() & (1 << i))
+ {
+ if (spellGroupVal)
+ target->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i, float(spellGroupVal), !apply);
- player->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float(GetAmount()), apply);
+ target->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i, float(GetAmount()), apply);
+ }
}
}
- else
- {
- // done in Player::_ApplyWeaponDependentAuraMods for SPELL_SCHOOL_MASK_NORMAL && EquippedItemClass != -1 and also for wand case
- }
}
void AuraEffect::HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -4672,10 +4369,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
if (target->GetTypeId() == TYPEID_PLAYER)
target->ToPlayer()->RemoveAmmo(); // not use ammo and not allow use
break;
- case 71563:
- if (Aura* newAura = target->AddAura(71564, target))
- newAura->SetStackAmount(newAura->GetSpellInfo()->StackAmount);
- break;
}
}
// AT REMOVE
@@ -5373,13 +5066,11 @@ void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const
{
// Master of Subtlety
case 31666:
- if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH))
- target->RemoveAurasDueToSpell(31665);
+ target->RemoveAurasDueToSpell(31665);
break;
// Overkill
case 58428:
- if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH))
- target->RemoveAurasDueToSpell(58427);
+ target->RemoveAurasDueToSpell(58427);
break;
}
break;
@@ -5475,8 +5166,10 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster)
if (caster)
{
int32 heal = caster->CountPctFromMaxHealth(10);
- caster->HealBySpell(target, auraSpellInfo, heal);
+ HealInfo healInfo(caster, target, heal, auraSpellInfo, auraSpellInfo->GetSchoolMask());
+ caster->HealBySpell(healInfo);
+ /// @todo: should proc other auras?
if (int32 mana = caster->GetMaxPower(POWER_MANA))
{
mana /= 10;
@@ -5774,8 +5467,6 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
}
}
- uint32 absorb = 0;
- uint32 resist = 0;
CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
// AOE spells are not affected by the new periodic system.
@@ -5794,7 +5485,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
damage = std::max(int32(damage * GetDonePct()), 0);
if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage);
+ modOwner->ApplySpellMod<SPELLMOD_DOT>(GetSpellInfo()->Id, damage);
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
@@ -5852,12 +5543,14 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
damage = uint32(target->CountPctFromMaxHealth(damage));
if (!m_spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
+ {
if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura)
{
damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
if (caster->GetTypeId() != TYPEID_PLAYER)
damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
}
+ }
bool crit = false;
@@ -5869,11 +5562,15 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
int32 dmg = damage;
if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
- caster->ApplyResilience(target, NULL, &dmg, crit, CR_CRIT_TAKEN_SPELL);
+ caster->ApplyResilience(target, nullptr, &dmg, crit, CR_CRIT_TAKEN_SPELL);
damage = dmg;
- caster->CalcAbsorbResist(target, GetSpellInfo()->GetSchoolMask(), DOT, damage, &absorb, &resist, GetSpellInfo());
+ DamageInfo damageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK);
+ caster->CalcAbsorbResist(damageInfo);
+ damage = damageInfo.GetDamage();
+ uint32 absorb = damageInfo.GetAbsorb();
+ uint32 resist = damageInfo.GetResist();
TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s attacked %s for %u dmg inflicted by %u absorb is %u",
GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId(), absorb);
@@ -5882,10 +5579,12 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
// Set trigger flag
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
- uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT;
- damage = (damage <= absorb+resist) ? 0 : (damage-absorb-resist);
+ uint32 hitMask = damageInfo.GetHitMask();
if (damage)
+ {
+ hitMask |= crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
+ }
int32 overkill = damage - target->GetHealth();
if (overkill < 0)
@@ -5894,7 +5593,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
SpellPeriodicAuraLogInfo pInfo(this, damage, overkill, absorb, resist, 0.0f, crit);
target->SendPeriodicAuraLog(&pInfo);
- caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo());
+ caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &damageInfo, nullptr);
caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true);
}
@@ -5914,8 +5613,6 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
caster->SpellHitResult(target, GetSpellInfo(), false) != SPELL_MISS_NONE)
return;
- uint32 absorb = 0;
- uint32 resist = 0;
CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA);
@@ -5930,6 +5627,9 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
else
damage = std::max(int32(damage * GetDonePct()), 0);
+ if (Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod<SPELLMOD_DOT>(GetSpellInfo()->Id, damage);
+
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
// Calculate armor mitigation
@@ -5941,12 +5641,14 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
}
if (!m_spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
+ {
if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura)
{
damage = uint32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
if (caster->GetTypeId() != TYPEID_PLAYER)
damage = uint32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
}
+ }
bool crit = false;
@@ -5958,25 +5660,34 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
int32 dmg = damage;
if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
- caster->ApplyResilience(target, NULL, &dmg, crit, CR_CRIT_TAKEN_SPELL);
+ caster->ApplyResilience(target, nullptr, &dmg, crit, CR_CRIT_TAKEN_SPELL);
damage = dmg;
- caster->CalcAbsorbResist(target, GetSpellInfo()->GetSchoolMask(), DOT, damage, &absorb, &resist, m_spellInfo);
+ DamageInfo damageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK);
+ caster->CalcAbsorbResist(damageInfo);
+ uint32 absorb = damageInfo.GetAbsorb();
+ uint32 resist = damageInfo.GetResist();
TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s health leech of %s for %u dmg inflicted by %u abs is %u",
GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId(), absorb);
+ // SendSpellNonMeleeDamageLog expects non-absorbed/non-resisted damage
caster->SendSpellNonMeleeDamageLog(target, GetId(), damage, GetSpellInfo()->GetSchoolMask(), absorb, resist, false, 0, crit);
+ damage = damageInfo.GetDamage();
// Set trigger flag
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
- uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT;
- damage = (damage <= absorb+resist) ? 0 : (damage-absorb-resist);
+ uint32 hitMask = damageInfo.GetHitMask();
if (damage)
+ {
+ hitMask |= crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
+ }
+
if (caster->IsAlive())
- caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo());
+ caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &damageInfo, nullptr);
+
int32 new_damage = caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false);
if (caster->IsAlive())
{
@@ -5985,8 +5696,11 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
uint32 heal = uint32(caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, GetBase()->GetStackAmount()));
heal = uint32(caster->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT, GetBase()->GetStackAmount()));
- int32 gain = caster->HealBySpell(caster, GetSpellInfo(), heal);
- caster->getHostileRefManager().threatAssist(caster, gain * 0.5f, GetSpellInfo());
+ HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
+ caster->HealBySpell(healInfo);
+
+ caster->getHostileRefManager().threatAssist(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo());
+ caster->ProcSkillsAndAuras(caster, PROC_FLAG_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo);
}
}
@@ -6015,7 +5729,9 @@ void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster)
damage = int32(damage * gainMultiplier);
- caster->HealBySpell(target, GetSpellInfo(), damage);
+ HealInfo healInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
+ caster->HealBySpell(healInfo);
+ caster->ProcSkillsAndAuras(target, PROC_FLAG_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, PROC_HIT_NORMAL, nullptr, nullptr, &healInfo);
}
void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
@@ -6097,7 +5813,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
damage = std::max(int32(damage * GetDonePct()), 0);
if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage);
+ modOwner->ApplySpellMod<SPELLMOD_DOT>(GetSpellInfo()->Id, damage);
damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
}
@@ -6113,15 +5829,16 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s heal of %s for %u health inflicted by %u",
GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId());
- uint32 absorb = 0;
uint32 heal = damage;
- caster->CalcHealAbsorb(target, GetSpellInfo(), heal, absorb);
- int32 gain = caster->DealHeal(target, heal);
- SpellPeriodicAuraLogInfo pInfo(this, heal, heal - gain, absorb, 0, 0.0f, crit);
+ HealInfo healInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
+ caster->CalcHealAbsorb(healInfo);
+ caster->DealHeal(healInfo);
+
+ SpellPeriodicAuraLogInfo pInfo(this, heal, heal - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit);
target->SendPeriodicAuraLog(&pInfo);
- target->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, GetSpellInfo());
+ target->getHostileRefManager().threatAssist(caster, float(healInfo.GetEffectiveHeal()) * 0.5f, GetSpellInfo());
bool haveCastItem = !GetBase()->GetCastItemGUID().IsEmpty();
@@ -6131,8 +5848,8 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
{
uint32 funnelDamage = GetSpellInfo()->ManaPerSecond; // damage is not affected by spell power
- if ((int32)funnelDamage > gain && gain > 0)
- funnelDamage = gain;
+ if (funnelDamage > healInfo.GetEffectiveHeal() && healInfo.GetEffectiveHeal())
+ funnelDamage = healInfo.GetEffectiveHeal();
uint32 funnelAbsorb = 0;
caster->DealDamageMods(caster, funnelDamage, &funnelAbsorb);
@@ -6144,10 +5861,10 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
- uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_HOT;
+ uint32 hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
// ignore item heals
if (!haveCastItem)
- caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo());
+ caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo);
}
void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const
@@ -6326,15 +6043,30 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con
// Set trigger flag
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
- uint32 procEx = createProcExtendMask(&damageInfo, SPELL_MISS_NONE) | PROC_EX_INTERNAL_DOT;
+ uint32 hitMask = createProcHitMask(&damageInfo, SPELL_MISS_NONE);
+ uint32 spellTypeMask = PROC_SPELL_TYPE_NO_DMG_HEAL;
if (damageInfo.damage)
+ {
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
+ spellTypeMask |= PROC_SPELL_TYPE_DAMAGE;
+ }
- caster->ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto);
+ DamageInfo dotDamageInfo(damageInfo, DOT, BASE_ATTACK, hitMask);
+ caster->ProcSkillsAndAuras(target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dotDamageInfo, nullptr);
caster->DealSpellDamage(&damageInfo, true);
}
+void AuraEffect::HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
+{
+ int32 const damageLeft = GetAmount() - static_cast<int32>(eventInfo.GetDamageInfo()->GetDamage());
+
+ if (damageLeft <= 0)
+ aurApp->GetTarget()->RemoveAura(aurApp);
+ else
+ SetAmount(damageLeft);
+}
+
void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
Unit* triggerCaster = aurApp->GetTarget();
@@ -6347,7 +6079,7 @@ void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEve
triggerCaster->CastSpell(triggerTarget, triggeredSpellInfo, true, NULL, this);
}
else
- TC_LOG_DEBUG("spells","AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
+ TC_LOG_ERROR("spells","AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
}
void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
@@ -6363,7 +6095,7 @@ void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp
triggerCaster->CastCustomSpell(triggerTarget, triggerSpellId, &basepoints0, NULL, NULL, true, NULL, this);
}
else
- TC_LOG_DEBUG("spells","AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
+ TC_LOG_ERROR("spells","AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
}
void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
@@ -6373,6 +6105,12 @@ void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEv
Unit* target = aurApp->GetTarget();
Unit* triggerTarget = eventInfo.GetProcTarget();
+ if (triggerTarget->HasUnitState(UNIT_STATE_ISOLATED) || triggerTarget->IsImmunedToDamage(GetSpellInfo()))
+ {
+ SendTickImmune(triggerTarget, target);
+ return;
+ }
+
SpellNonMeleeDamage damageInfo(target, triggerTarget, GetId(), GetSpellInfo()->SchoolMask);
uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE);
damage = triggerTarget->SpellDamageBonusTaken(target, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE);
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h
index 32a7b97fff2..05bfe7c0534 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.h
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.h
@@ -29,8 +29,8 @@ typedef void(AuraEffect::*pAuraEffectHandler)(AuraApplication const* aurApp, uin
class TC_GAME_API AuraEffect
{
- friend void Aura::_InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount);
- friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID);
+ friend void Aura::_InitEffects(uint8 effMask, Unit* caster, int32* baseAmount);
+ friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID, bool resetPeriodicTimer);
friend Aura::~Aura();
private:
~AuraEffect();
@@ -41,7 +41,6 @@ class TC_GAME_API AuraEffect
Aura* GetBase() const { return m_base; }
void GetTargetList(std::list<Unit*> & targetList) const;
void GetApplicationList(std::list<AuraApplication*> & applicationList) const;
- SpellModifier* GetSpellModifier() const { return m_spellmod; }
SpellInfo const* GetSpellInfo() const { return m_spellInfo; }
uint32 GetId() const { return m_spellInfo->Id; }
@@ -59,7 +58,7 @@ class TC_GAME_API AuraEffect
void SetPeriodicTimer(int32 periodicTimer) { m_periodicTimer = periodicTimer; }
int32 CalculateAmount(Unit* caster);
- void CalculatePeriodic(Unit* caster, bool create = false, bool load = false);
+ void CalculatePeriodic(Unit* caster, bool resetPeriodicTimer = true, bool load = false);
void CalculateSpellMod();
void ChangeAmount(int32 newAmount, bool mark = true, bool onStackOrReapply = false);
void RecalculateAmount() { if (!CanBeRecalculated()) return; ChangeAmount(CalculateAmount(GetCaster()), false); }
@@ -90,8 +89,9 @@ class TC_GAME_API AuraEffect
bool HasSpellClassMask() const { return m_spellInfo->Effects[m_effIndex].SpellClassMask; }
void SendTickImmune(Unit* target, Unit* caster) const;
- void PeriodicTick(AuraApplication * aurApp, Unit* caster) const;
+ void PeriodicTick(AuraApplication* aurApp, Unit* caster) const;
+ bool CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) const;
void HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
void CleanupTriggeredSpells(Unit* target);
@@ -198,7 +198,7 @@ class TC_GAME_API AuraEffect
void HandleAuraModDecreaseSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleAuraModUseNormalSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const;
// immunity
- void HandleModStateImmunityMask(AuraApplication const* aurApp, uint8 mode, bool apply) const;
+ void HandleModMechanicImmunityMask(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleModMechanicImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleAuraModStateImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const;
@@ -305,6 +305,7 @@ class TC_GAME_API AuraEffect
void HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) const;
// aura effect proc handlers
+ void HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
void HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
void HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
void HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 23ebc741b37..45ea44f1dfb 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -221,7 +221,7 @@ void AuraApplication::ClientUpdate(bool remove)
_target->SendMessageToSet(&data, true);
}
-uint8 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 avalibleEffectMask, WorldObject* owner)
+uint8 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 availableEffectMask, WorldObject* owner)
{
ASSERT(spellProto);
ASSERT(owner);
@@ -230,26 +230,28 @@ uint8 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 avalibleE
{
case TYPEID_UNIT:
case TYPEID_PLAYER:
- for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i)
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (spellProto->Effects[i].IsUnitOwnedAuraEffect())
effMask |= 1 << i;
}
break;
case TYPEID_DYNAMICOBJECT:
- for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i)
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (spellProto->Effects[i].Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA)
effMask |= 1 << i;
}
break;
default:
+ ABORT();
break;
}
- return effMask & avalibleEffectMask;
+
+ return effMask & availableEffectMask;
}
-Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, bool* refresh /*= NULL*/)
+Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, bool* refresh /*= nullptr*/, bool resetPeriodicTimer /*= true*/)
{
ASSERT(spellproto);
ASSERT(owner);
@@ -257,25 +259,28 @@ Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMas
ASSERT(tryEffMask <= MAX_EFFECT_MASK);
if (refresh)
*refresh = false;
+
uint8 effMask = Aura::BuildEffectMaskForOwner(spellproto, tryEffMask, owner);
if (!effMask)
- return NULL;
- if (Aura* foundAura = owner->ToUnit()->_TryStackingOrRefreshingExistingAura(spellproto, effMask, caster, baseAmount, castItem, casterGUID))
+ return nullptr;
+
+ if (Aura* foundAura = owner->ToUnit()->_TryStackingOrRefreshingExistingAura(spellproto, effMask, caster, baseAmount, castItem, casterGUID, resetPeriodicTimer))
{
// we've here aura, which script triggered removal after modding stack amount
// check the state here, so we won't create new Aura object
if (foundAura->IsRemoved())
- return NULL;
+ return nullptr;
if (refresh)
*refresh = true;
+
return foundAura;
}
else
return Create(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID);
}
-Aura* Aura::TryCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/)
+Aura* Aura::TryCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/)
{
ASSERT(spellproto);
ASSERT(owner);
@@ -283,7 +288,8 @@ Aura* Aura::TryCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject
ASSERT(tryEffMask <= MAX_EFFECT_MASK);
uint8 effMask = Aura::BuildEffectMaskForOwner(spellproto, tryEffMask, owner);
if (!effMask)
- return NULL;
+ return nullptr;
+
return Create(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID);
}
@@ -310,9 +316,9 @@ Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owne
if (!owner->IsInWorld() || ((Unit*)owner)->IsDuringRemoveFromWorld())
// owner not in world so don't allow to own not self cast single target auras
if (casterGUID != owner->GetGUID() && spellproto->IsSingleTarget())
- return NULL;
+ return nullptr;
- Aura* aura = NULL;
+ Aura* aura = nullptr;
switch (owner->GetTypeId())
{
case TYPEID_UNIT:
@@ -324,11 +330,12 @@ Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owne
break;
default:
ABORT();
- return NULL;
+ return nullptr;
}
+
// aura can be removed in Unit::_AddAura call
if (aura->IsRemoved())
- return NULL;
+ return nullptr;
return aura;
}
@@ -353,7 +360,7 @@ m_procCooldown(std::chrono::steady_clock::time_point::min())
AuraScript* Aura::GetScriptByName(std::string const& scriptName) const
{
- for (std::list<AuraScript*>::const_iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
+ for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
if ((*itr)->_GetScriptName()->compare(scriptName) == 0)
return *itr;
return NULL;
@@ -374,12 +381,10 @@ void Aura::_InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount)
Aura::~Aura()
{
// unload scripts
- while (!m_loadedScripts.empty())
+ for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
{
- std::list<AuraScript*>::iterator itr = m_loadedScripts.begin();
(*itr)->_Unload();
delete (*itr);
- m_loadedScripts.erase(itr);
}
// free effects memory
@@ -483,37 +488,36 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
m_updateTargetMapInterval = UPDATE_TARGET_MAP_INTERVAL;
// fill up to date target list
- // target, effMask
- std::map<Unit*, uint8> targets;
-
+ // target, effMask
+ std::unordered_map<Unit*, uint8> targets;
FillTargetMap(targets, caster);
- UnitList targetsToRemove;
+ std::deque<Unit*> targetsToRemove;
// mark all auras as ready to remove
for (ApplicationMap::iterator appIter = m_applications.begin(); appIter != m_applications.end();++appIter)
{
- std::map<Unit*, uint8>::iterator existing = targets.find(appIter->second->GetTarget());
+ auto itr = targets.find(appIter->second->GetTarget());
// not found in current area - remove the aura
- if (existing == targets.end())
+ if (itr == targets.end())
targetsToRemove.push_back(appIter->second->GetTarget());
else
{
// needs readding - remove now, will be applied in next update cycle
// (dbcs do not have auras which apply on same type of targets but have different radius, so this is not really needed)
- if (appIter->second->GetEffectMask() != existing->second || !CanBeAppliedOn(existing->first))
+ if (appIter->second->GetEffectMask() != itr->second || !CanBeAppliedOn(itr->first))
targetsToRemove.push_back(appIter->second->GetTarget());
// nothing todo - aura already applied
// remove from auras to register list
- targets.erase(existing);
+ targets.erase(itr);
}
}
// register auras for units
- for (std::map<Unit*, uint8>::iterator itr = targets.begin(); itr!= targets.end();)
+ for (auto itr = targets.begin(); itr!= targets.end();)
{
// aura mustn't be already applied on target
- if (AuraApplication * aurApp = GetApplicationOfTarget(itr->first->GetGUID()))
+ if (AuraApplication* aurApp = GetApplicationOfTarget(itr->first->GetGUID()))
{
// the core created 2 different units with same guid
// this is a major failue, which i can't fix right now
@@ -523,7 +527,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
if (aurApp->GetTarget() != itr->first)
{
// remove from auras to register list
- targets.erase(itr++);
+ itr = targets.erase(itr);
continue;
}
else
@@ -577,7 +581,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
}
}
if (!addUnit)
- targets.erase(itr++);
+ itr = targets.erase(itr);
else
{
// owner has to be in world, or effect has to be applied to self
@@ -595,17 +599,17 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
}
// remove auras from units no longer needing them
- for (UnitList::iterator itr = targetsToRemove.begin(); itr != targetsToRemove.end();++itr)
- if (AuraApplication * aurApp = GetApplicationOfTarget((*itr)->GetGUID()))
- (*itr)->_UnapplyAura(aurApp, AURA_REMOVE_BY_DEFAULT);
+ for (Unit* unit : targetsToRemove)
+ if (AuraApplication* aurApp = GetApplicationOfTarget(unit->GetGUID()))
+ unit->_UnapplyAura(aurApp, AURA_REMOVE_BY_DEFAULT);
if (!apply)
return;
// apply aura effects for units
- for (std::map<Unit*, uint8>::iterator itr = targets.begin(); itr!= targets.end();++itr)
+ for (auto itr = targets.begin(); itr!= targets.end(); ++itr)
{
- if (AuraApplication * aurApp = GetApplicationOfTarget(itr->first->GetGUID()))
+ if (AuraApplication* aurApp = GetApplicationOfTarget(itr->first->GetGUID()))
{
// owner has to be in world, or effect has to be applied to self
ASSERT((!GetOwner()->IsInWorld() && GetOwner() == itr->first) || GetOwner()->IsInMap(itr->first));
@@ -730,7 +734,7 @@ int32 Aura::CalcMaxDuration(Unit* caster) const
// IsPermanent() checks max duration (which we are supposed to calculate here)
if (maxDuration != -1 && modOwner)
- modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, maxDuration);
+ modOwner->ApplySpellMod<SPELLMOD_DURATION>(GetId(), maxDuration);
return maxDuration;
}
@@ -740,7 +744,7 @@ void Aura::SetDuration(int32 duration, bool withMods)
if (withMods)
if (Unit* caster = GetCaster())
if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, duration);
+ modOwner->ApplySpellMod<SPELLMOD_DURATION>(GetId(), duration);
m_duration = duration;
SetNeedClientUpdateForTargets();
@@ -766,14 +770,15 @@ void Aura::RefreshDuration(bool withMods)
m_timeCla = 1 * IN_MILLISECONDS;
}
-void Aura::RefreshTimers()
+void Aura::RefreshTimers(bool resetPeriodicTimer)
{
m_maxDuration = CalcMaxDuration();
RefreshDuration();
+
Unit* caster = GetCaster();
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- if (HasEffect(i))
- GetEffect(i)->CalculatePeriodic(caster, false, false);
+ if (AuraEffect* aurEff = m_effects[i])
+ aurEff->CalculatePeriodic(caster, resetPeriodicTimer, false);
}
void Aura::SetCharges(uint8 charges)
@@ -794,7 +799,7 @@ uint8 Aura::CalcMaxCharges(Unit* caster) const
if (caster)
if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, maxProcCharges);
+ modOwner->ApplySpellMod<SPELLMOD_CHARGES>(GetId(), maxProcCharges);
return maxProcCharges;
}
@@ -868,7 +873,7 @@ void Aura::SetStackAmount(uint8 stackAmount)
SetNeedClientUpdateForTargets();
}
-bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode)
+bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/, bool resetPeriodicTimer /*= true*/)
{
int32 stackAmount = m_stackAmount + num;
@@ -896,16 +901,10 @@ bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode)
if (refresh)
{
RefreshSpellMods();
- RefreshTimers();
+ RefreshTimers(resetPeriodicTimer);
// reset charges
SetCharges(CalcMaxCharges());
- // FIXME: not a best way to synchronize charges, but works
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- if (AuraEffect* aurEff = GetEffect(i))
- if (aurEff->GetAuraType() == SPELL_AURA_ADD_FLAT_MODIFIER || aurEff->GetAuraType() == SPELL_AURA_ADD_PCT_MODIFIER)
- if (SpellModifier* mod = aurEff->GetSpellModifier())
- mod->charges = GetCharges();
}
SetNeedClientUpdateForTargets();
@@ -986,6 +985,10 @@ bool Aura::CanBeSaved() const
if (IsUsingCharges() && !GetCharges())
return false;
+ // don't save permanent auras triggered by items, they'll be recasted on login if necessary
+ if (GetCastItemGUID() && IsPermanent())
+ return false;
+
return true;
}
@@ -1037,7 +1040,7 @@ int32 Aura::CalcDispelChance(Unit* auraTarget, bool offensive) const
// Apply dispel mod from aura caster
if (Unit* caster = GetCaster())
if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(GetId(), SPELLMOD_RESIST_DISPEL_CHANCE, resistChance);
+ modOwner->ApplySpellMod<SPELLMOD_RESIST_DISPEL_CHANCE>(GetId(), resistChance);
// Dispel resistance from target SPELL_AURA_MOD_DISPEL_RESIST
// Only affects offensive dispels
@@ -1057,14 +1060,16 @@ void Aura::SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint
m_stackAmount = stackamount;
Unit* caster = GetCaster();
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- if (m_effects[i])
+ {
+ if (AuraEffect* aurEff = m_effects[i])
{
- m_effects[i]->SetAmount(amount[i]);
- m_effects[i]->SetCanBeRecalculated((recalculateMask & (1 << i)) != 0);
- m_effects[i]->CalculatePeriodic(caster, false, true);
- m_effects[i]->CalculateSpellMod();
- m_effects[i]->RecalculateAmount(caster);
+ aurEff->SetAmount(amount[i]);
+ aurEff->SetCanBeRecalculated((recalculateMask & (1 << i)) != 0);
+ aurEff->CalculatePeriodic(caster, false, true);
+ aurEff->CalculateSpellMod();
+ aurEff->RecalculateAmount(caster);
}
+ }
}
bool Aura::HasEffectType(AuraType type) const
@@ -1094,7 +1099,7 @@ void Aura::HandleAllEffects(AuraApplication * aurApp, uint8 mode, bool apply)
m_effects[i]->HandleEffect(aurApp, mode, apply);
}
-void Aura::GetApplicationList(std::list<AuraApplication*> & applicationList) const
+void Aura::GetApplicationList(Unit::AuraApplicationList& applicationList) const
{
for (Aura::ApplicationMap::const_iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter)
{
@@ -1278,17 +1283,9 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
}
break;
case 44544: // Fingers of Frost
- {
- // See if we already have the indicator aura. If not, create one.
- if (Aura* aur = target->GetAura(74396))
- {
- // Aura already there. Refresh duration and set original charges
- aur->SetCharges(2);
- aur->RefreshDuration();
- }
- else
- target->AddAura(74396, target);
- }
+ // Refresh or add visual aura
+ target->CastCustomSpell(74396, SPELLVALUE_AURA_STACK, sSpellMgr->AssertSpellInfo(74396)->StackAmount, (Unit*)nullptr, true);
+ break;
default:
break;
}
@@ -1296,20 +1293,27 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
case SPELLFAMILY_PRIEST:
if (!caster)
break;
+
// Devouring Plague
- if (GetSpellInfo()->SpellFamilyFlags[0] & 0x02000000 && GetEffect(0))
+ if (GetSpellInfo()->SpellFamilyFlags[0] & 0x02000000)
{
+ AuraEffect const* devouringPlague = GetEffect(EFFECT_0);
+ if (!devouringPlague)
+ break;
+
// Improved Devouring Plague
if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 3790, 1))
{
- uint32 damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), GetEffect(0)->GetAmount(), DOT);
- damage *= caster->SpellDamagePctDone(target, GetSpellInfo(), SPELL_DIRECT_DAMAGE);
+ int32 damage = (devouringPlague->GetAmount() + devouringPlague->GetBonusAmount()) * devouringPlague->GetDonePct();
+ if (Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod<SPELLMOD_DOT>(GetSpellInfo()->Id, damage);
+
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT);
- int32 basepoints0 = aurEff->GetAmount() * GetEffect(0)->GetTotalTicks() * int32(damage) / 100;
- int32 heal = int32(CalculatePct(basepoints0, 15));
- caster->CastCustomSpell(target, 63675, &basepoints0, NULL, NULL, true, NULL, GetEffect(0));
- caster->CastCustomSpell(caster, 75999, &heal, NULL, NULL, true, NULL, GetEffect(0));
+ int32 basepoints0 = CalculatePct(devouringPlague->GetTotalTicks() * static_cast<int32>(damage), aurEff->GetAmount());
+ int32 heal = CalculatePct(basepoints0, 15);
+ caster->CastCustomSpell(63675, SPELLVALUE_BASE_POINT0, basepoints0, target, true, nullptr, devouringPlague);
+ caster->CastCustomSpell(75999, SPELLVALUE_BASE_POINT0, heal, (Unit*)nullptr, true, nullptr, devouringPlague);
}
}
// Power Word: Shield
@@ -1402,10 +1406,6 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
target->CastSpell(target, 32612, true, NULL, GetEffect(1));
target->CombatStop();
break;
- case 74396: // Fingers of Frost
- // Remove the IGNORE_AURASTATE aura
- target->RemoveAurasDueToSpell(44544);
- break;
default:
break;
}
@@ -1600,6 +1600,9 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
target->CastSpell(target, 31666, true);
else
{
+ // Remove counter aura
+ target->RemoveAurasDueToSpell(31666);
+
int32 basepoints0 = aurEff->GetAmount();
target->CastCustomSpell(target, 31665, &basepoints0, NULL, NULL, true);
}
@@ -1610,7 +1613,12 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
if (!apply)
target->CastSpell(target, 58428, true);
else
+ {
+ // Remove counter aura
+ target->RemoveAurasDueToSpell(58428);
+
target->CastSpell(target, 58427, true);
+ }
}
break;
}
@@ -1868,49 +1876,90 @@ void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInf
}
SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId());
-
ASSERT(procEntry);
// cooldowns should be added to the whole aura (see 51698 area aura)
AddProcCooldown(now + procEntry->Cooldown);
}
-bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const
+uint8 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const
{
SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId());
// only auras with spell proc entry can trigger proc
if (!procEntry)
- return false;
+ return 0;
+
+ // check spell triggering us
+ if (Spell const* spell = eventInfo.GetProcSpell())
+ {
+ // Do not allow auras to proc from effect triggered from itself
+ if (spell->IsTriggeredByAura(m_spellInfo))
+ return 0;
+
+ // check if aura can proc when spell is triggered (exception for hunter auto shot & wands)
+ if (spell->IsTriggered() && !(procEntry->AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC) && !(eventInfo.GetTypeMask() & AUTO_ATTACK_PROC_FLAG_MASK))
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED))
+ return 0;
+ }
+
+ // check don't break stealth attr present
+ if (m_spellInfo->HasAura(SPELL_AURA_MOD_STEALTH))
+ {
+ if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
+ if (spellInfo->HasAttribute(SPELL_ATTR0_CU_DONT_BREAK_STEALTH))
+ return 0;
+ }
// check if we have charges to proc with
- if (IsUsingCharges() && !GetCharges())
- return false;
+ if (IsUsingCharges())
+ {
+ if (!GetCharges())
+ return 0;
+
+ if (procEntry->AttributesMask & PROC_ATTR_REQ_SPELLMOD)
+ if (Spell const* spell = eventInfo.GetProcSpell())
+ if (!spell->m_appliedMods.count(const_cast<Aura*>(this)))
+ return 0;
+ }
// check proc cooldown
if (IsProcOnCooldown(now))
- return false;
-
- /// @todo
- // something about triggered spells triggering, and add extra attack effect
+ return 0;
// do checks against db data
- if (!sSpellMgr->CanSpellTriggerProcOnEvent(*procEntry, eventInfo))
- return false;
+ if (!SpellMgr::CanSpellTriggerProcOnEvent(*procEntry, eventInfo))
+ return 0;
// do checks using conditions table
if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_SPELL_PROC, GetId(), eventInfo.GetActor(), eventInfo.GetActionTarget()))
- return false;
+ return 0;
// AuraScript Hook
bool check = const_cast<Aura*>(this)->CallScriptCheckProcHandlers(aurApp, eventInfo);
if (!check)
- return false;
+ return 0;
+
+ // At least one effect has to pass checks to proc aura
+ uint8 procEffectMask = aurApp->GetEffectMask();
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (procEffectMask & (1 << i))
+ if ((procEntry->AttributesMask & (PROC_ATTR_DISABLE_EFF_0 << i)) || !GetEffect(i)->CheckEffectProc(aurApp, eventInfo))
+ procEffectMask &= ~(1 << i);
+
+ if (!procEffectMask)
+ return 0;
/// @todo
// do allow additional requirements for procs
// this is needed because this is the last moment in which you can prevent aura charge drop on proc
// and possibly a way to prevent default checks (if there're going to be any)
+ // Aura added by spell can't trigger from self (prevent drop charges/do triggers)
+ // But except periodic and kill triggers (can triggered from self)
+ if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
+ if (spellInfo->Id == GetId() && !(eventInfo.GetTypeMask() & (PROC_FLAG_TAKEN_PERIODIC | PROC_FLAG_KILL)))
+ return 0;
+
// Check if current equipment meets aura requirements
// do that only for passive spells
/// @todo this needs to be unified for all kinds of auras
@@ -1920,12 +1969,12 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI
if (GetSpellInfo()->EquippedItemClass == ITEM_CLASS_WEAPON)
{
if (target->ToPlayer()->IsInFeralForm())
- return false;
+ return 0;
- if (eventInfo.GetDamageInfo())
+ if (DamageInfo* damageInfo = eventInfo.GetDamageInfo())
{
- WeaponAttackType attType = eventInfo.GetDamageInfo()->GetAttackType();
- Item* item = NULL;
+ WeaponAttackType attType = damageInfo->GetAttackType();
+ Item* item = nullptr;
if (attType == BASE_ATTACK)
item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
else if (attType == OFF_ATTACK)
@@ -1933,20 +1982,23 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI
else
item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
- if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_WEAPON || !((1<<item->GetTemplate()->SubClass) & GetSpellInfo()->EquippedItemSubClassMask))
- return false;
+ if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_WEAPON || !((1 << item->GetTemplate()->SubClass) & GetSpellInfo()->EquippedItemSubClassMask))
+ return 0;
}
}
else if (GetSpellInfo()->EquippedItemClass == ITEM_CLASS_ARMOR)
{
// Check if player is wearing shield
Item* item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
- if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_ARMOR || !((1<<item->GetTemplate()->SubClass) & GetSpellInfo()->EquippedItemSubClassMask))
- return false;
+ if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_ARMOR || !((1 << item->GetTemplate()->SubClass) & GetSpellInfo()->EquippedItemSubClassMask))
+ return 0;
}
}
- return roll_chance_f(CalcProcChance(*procEntry, eventInfo));
+ if (roll_chance_f(CalcProcChance(*procEntry, eventInfo)))
+ return procEffectMask;
+
+ return 0;
}
float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const
@@ -1964,21 +2016,28 @@ float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& event
}
// apply chance modifer aura, applies also to ppm chance (see improved judgement of light spell)
if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(GetId(), SPELLMOD_CHANCE_OF_SUCCESS, chance);
+ modOwner->ApplySpellMod<SPELLMOD_CHANCE_OF_SUCCESS>(GetId(), chance);
}
return chance;
}
-void Aura::TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo)
+void Aura::TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
- CallScriptProcHandlers(aurApp, eventInfo);
+ bool prevented = CallScriptProcHandlers(aurApp, eventInfo);
+ if (!prevented)
+ {
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (!(procEffectMask & (1 << i)))
+ continue;
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- if (aurApp->HasEffect(i))
// OnEffectProc / AfterEffectProc hooks handled in AuraEffect::HandleProc()
- GetEffect(i)->HandleProc(aurApp, eventInfo);
+ if (aurApp->HasEffect(i))
+ GetEffect(i)->HandleProc(aurApp, eventInfo);
+ }
- CallScriptAfterProcHandlers(aurApp, eventInfo);
+ CallScriptAfterProcHandlers(aurApp, eventInfo);
+ }
// Remove aura if we've used last charge to proc
if (IsUsingCharges() && !GetCharges())
@@ -1996,30 +2055,21 @@ void Aura::_DeleteRemovedApplications()
void Aura::LoadScripts()
{
- sScriptMgr->CreateAuraScripts(m_spellInfo->Id, m_loadedScripts);
- for (std::list<AuraScript*>::iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end();)
+ sScriptMgr->CreateAuraScripts(m_spellInfo->Id, m_loadedScripts, this);
+ for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
{
- if (!(*itr)->_Load(this))
- {
- std::list<AuraScript*>::iterator bitr = itr;
- ++itr;
- delete (*bitr);
- m_loadedScripts.erase(bitr);
- continue;
- }
TC_LOG_DEBUG("spells", "Aura::LoadScripts: Script `%s` for aura `%u` is loaded now", (*itr)->_GetScriptName()->c_str(), m_spellInfo->Id);
(*itr)->Register();
- ++itr;
}
}
bool Aura::CallScriptCheckAreaTargetHandlers(Unit* target)
{
bool result = true;
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_AREA_TARGET);
- std::list<AuraScript::CheckAreaTargetHandler>::iterator hookItrEnd = (*scritr)->DoCheckAreaTarget.end(), hookItr = (*scritr)->DoCheckAreaTarget.begin();
+ auto hookItrEnd = (*scritr)->DoCheckAreaTarget.end(), hookItr = (*scritr)->DoCheckAreaTarget.begin();
for (; hookItr != hookItrEnd; ++hookItr)
result &= hookItr->Call(*scritr, target);
@@ -2030,10 +2080,10 @@ bool Aura::CallScriptCheckAreaTargetHandlers(Unit* target)
void Aura::CallScriptDispel(DispelInfo* dispelInfo)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_DISPEL);
- std::list<AuraScript::AuraDispelHandler>::iterator hookItrEnd = (*scritr)->OnDispel.end(), hookItr = (*scritr)->OnDispel.begin();
+ auto hookItrEnd = (*scritr)->OnDispel.end(), hookItr = (*scritr)->OnDispel.begin();
for (; hookItr != hookItrEnd; ++hookItr)
hookItr->Call(*scritr, dispelInfo);
@@ -2043,10 +2093,10 @@ void Aura::CallScriptDispel(DispelInfo* dispelInfo)
void Aura::CallScriptAfterDispel(DispelInfo* dispelInfo)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_AFTER_DISPEL);
- std::list<AuraScript::AuraDispelHandler>::iterator hookItrEnd = (*scritr)->AfterDispel.end(), hookItr = (*scritr)->AfterDispel.begin();
+ auto hookItrEnd = (*scritr)->AfterDispel.end(), hookItr = (*scritr)->AfterDispel.begin();
for (; hookItr != hookItrEnd; ++hookItr)
hookItr->Call(*scritr, dispelInfo);
@@ -2057,10 +2107,10 @@ void Aura::CallScriptAfterDispel(DispelInfo* dispelInfo)
bool Aura::CallScriptEffectApplyHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, AuraEffectHandleModes mode)
{
bool preventDefault = false;
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_APPLY, aurApp);
- std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectApply.end(), effItr = (*scritr)->OnEffectApply.begin();
+ auto effEndItr = (*scritr)->OnEffectApply.end(), effItr = (*scritr)->OnEffectApply.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff, mode);
@@ -2077,10 +2127,10 @@ bool Aura::CallScriptEffectApplyHandlers(AuraEffect const* aurEff, AuraApplicati
bool Aura::CallScriptEffectRemoveHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, AuraEffectHandleModes mode)
{
bool preventDefault = false;
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_REMOVE, aurApp);
- std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectRemove.end(), effItr = (*scritr)->OnEffectRemove.begin();
+ auto effEndItr = (*scritr)->OnEffectRemove.end(), effItr = (*scritr)->OnEffectRemove.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff, mode);
@@ -2095,10 +2145,10 @@ bool Aura::CallScriptEffectRemoveHandlers(AuraEffect const* aurEff, AuraApplicat
void Aura::CallScriptAfterEffectApplyHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, AuraEffectHandleModes mode)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_APPLY, aurApp);
- std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->AfterEffectApply.end(), effItr = (*scritr)->AfterEffectApply.begin();
+ auto effEndItr = (*scritr)->AfterEffectApply.end(), effItr = (*scritr)->AfterEffectApply.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff, mode);
@@ -2109,10 +2159,10 @@ void Aura::CallScriptAfterEffectApplyHandlers(AuraEffect const* aurEff, AuraAppl
void Aura::CallScriptAfterEffectRemoveHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, AuraEffectHandleModes mode)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_REMOVE, aurApp);
- std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->AfterEffectRemove.end(), effItr = (*scritr)->AfterEffectRemove.begin();
+ auto effEndItr = (*scritr)->AfterEffectRemove.end(), effItr = (*scritr)->AfterEffectRemove.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff, mode);
@@ -2124,10 +2174,10 @@ void Aura::CallScriptAfterEffectRemoveHandlers(AuraEffect const* aurEff, AuraApp
bool Aura::CallScriptEffectPeriodicHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp)
{
bool preventDefault = false;
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_PERIODIC, aurApp);
- std::list<AuraScript::EffectPeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectPeriodic.end(), effItr = (*scritr)->OnEffectPeriodic.begin();
+ auto effEndItr = (*scritr)->OnEffectPeriodic.end(), effItr = (*scritr)->OnEffectPeriodic.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff);
@@ -2143,10 +2193,10 @@ bool Aura::CallScriptEffectPeriodicHandlers(AuraEffect const* aurEff, AuraApplic
void Aura::CallScriptEffectUpdatePeriodicHandlers(AuraEffect* aurEff)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_UPDATE_PERIODIC);
- std::list<AuraScript::EffectUpdatePeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectUpdatePeriodic.end(), effItr = (*scritr)->OnEffectUpdatePeriodic.begin();
+ auto effEndItr = (*scritr)->OnEffectUpdatePeriodic.end(), effItr = (*scritr)->OnEffectUpdatePeriodic.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff);
@@ -2157,10 +2207,10 @@ void Aura::CallScriptEffectUpdatePeriodicHandlers(AuraEffect* aurEff)
void Aura::CallScriptEffectCalcAmountHandlers(AuraEffect const* aurEff, int32 & amount, bool & canBeRecalculated)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_AMOUNT);
- std::list<AuraScript::EffectCalcAmountHandler>::iterator effEndItr = (*scritr)->DoEffectCalcAmount.end(), effItr = (*scritr)->DoEffectCalcAmount.begin();
+ auto effEndItr = (*scritr)->DoEffectCalcAmount.end(), effItr = (*scritr)->DoEffectCalcAmount.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff, amount, canBeRecalculated);
@@ -2171,10 +2221,10 @@ void Aura::CallScriptEffectCalcAmountHandlers(AuraEffect const* aurEff, int32 &
void Aura::CallScriptEffectCalcPeriodicHandlers(AuraEffect const* aurEff, bool & isPeriodic, int32 & amplitude)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_PERIODIC);
- std::list<AuraScript::EffectCalcPeriodicHandler>::iterator effEndItr = (*scritr)->DoEffectCalcPeriodic.end(), effItr = (*scritr)->DoEffectCalcPeriodic.begin();
+ auto effEndItr = (*scritr)->DoEffectCalcPeriodic.end(), effItr = (*scritr)->DoEffectCalcPeriodic.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff, isPeriodic, amplitude);
@@ -2185,10 +2235,10 @@ void Aura::CallScriptEffectCalcPeriodicHandlers(AuraEffect const* aurEff, bool &
void Aura::CallScriptEffectCalcSpellModHandlers(AuraEffect const* aurEff, SpellModifier* & spellMod)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_SPELLMOD);
- std::list<AuraScript::EffectCalcSpellModHandler>::iterator effEndItr = (*scritr)->DoEffectCalcSpellMod.end(), effItr = (*scritr)->DoEffectCalcSpellMod.begin();
+ auto effEndItr = (*scritr)->DoEffectCalcSpellMod.end(), effItr = (*scritr)->DoEffectCalcSpellMod.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff, spellMod);
@@ -2199,10 +2249,10 @@ void Aura::CallScriptEffectCalcSpellModHandlers(AuraEffect const* aurEff, SpellM
void Aura::CallScriptEffectAbsorbHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount, bool& defaultPrevented)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_ABSORB, aurApp);
- std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->OnEffectAbsorb.end(), effItr = (*scritr)->OnEffectAbsorb.begin();
+ auto effEndItr = (*scritr)->OnEffectAbsorb.end(), effItr = (*scritr)->OnEffectAbsorb.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
@@ -2217,10 +2267,10 @@ void Aura::CallScriptEffectAbsorbHandlers(AuraEffect* aurEff, AuraApplication co
void Aura::CallScriptEffectAfterAbsorbHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_ABSORB, aurApp);
- std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->AfterEffectAbsorb.end(), effItr = (*scritr)->AfterEffectAbsorb.begin();
+ auto effEndItr = (*scritr)->AfterEffectAbsorb.end(), effItr = (*scritr)->AfterEffectAbsorb.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
@@ -2231,10 +2281,10 @@ void Aura::CallScriptEffectAfterAbsorbHandlers(AuraEffect* aurEff, AuraApplicati
void Aura::CallScriptEffectManaShieldHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount, bool & /*defaultPrevented*/)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_MANASHIELD, aurApp);
- std::list<AuraScript::EffectManaShieldHandler>::iterator effEndItr = (*scritr)->OnEffectManaShield.end(), effItr = (*scritr)->OnEffectManaShield.begin();
+ auto effEndItr = (*scritr)->OnEffectManaShield.end(), effItr = (*scritr)->OnEffectManaShield.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
@@ -2245,10 +2295,10 @@ void Aura::CallScriptEffectManaShieldHandlers(AuraEffect* aurEff, AuraApplicatio
void Aura::CallScriptEffectAfterManaShieldHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD, aurApp);
- std::list<AuraScript::EffectManaShieldHandler>::iterator effEndItr = (*scritr)->AfterEffectManaShield.end(), effItr = (*scritr)->AfterEffectManaShield.begin();
+ auto effEndItr = (*scritr)->AfterEffectManaShield.end(), effItr = (*scritr)->AfterEffectManaShield.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
@@ -2259,10 +2309,10 @@ void Aura::CallScriptEffectAfterManaShieldHandlers(AuraEffect* aurEff, AuraAppli
void Aura::CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & splitAmount)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_SPLIT, aurApp);
- std::list<AuraScript::EffectSplitHandler>::iterator effEndItr = (*scritr)->OnEffectSplit.end(), effItr = (*scritr)->OnEffectSplit.begin();
+ auto effEndItr = (*scritr)->OnEffectSplit.end(), effItr = (*scritr)->OnEffectSplit.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff, dmgInfo, splitAmount);
@@ -2274,10 +2324,10 @@ void Aura::CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication con
bool Aura::CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
bool result = true;
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_PROC, aurApp);
- std::list<AuraScript::CheckProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckProc.end(), hookItr = (*scritr)->DoCheckProc.begin();
+ auto hookItrEnd = (*scritr)->DoCheckProc.end(), hookItr = (*scritr)->DoCheckProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
result &= hookItr->Call(*scritr, eventInfo);
@@ -2290,10 +2340,10 @@ bool Aura::CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventI
bool Aura::CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
bool prepare = true;
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_PREPARE_PROC, aurApp);
- std::list<AuraScript::AuraProcHandler>::iterator effEndItr = (*scritr)->DoPrepareProc.end(), effItr = (*scritr)->DoPrepareProc.begin();
+ auto effEndItr = (*scritr)->DoPrepareProc.end(), effItr = (*scritr)->DoPrepareProc.begin();
for (; effItr != effEndItr; ++effItr)
effItr->Call(*scritr, eventInfo);
@@ -2309,10 +2359,10 @@ bool Aura::CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEven
bool Aura::CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
bool handled = false;
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_PROC, aurApp);
- std::list<AuraScript::AuraProcHandler>::iterator hookItrEnd = (*scritr)->OnProc.end(), hookItr = (*scritr)->OnProc.begin();
+ auto hookItrEnd = (*scritr)->OnProc.end(), hookItr = (*scritr)->OnProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
hookItr->Call(*scritr, eventInfo);
@@ -2325,10 +2375,10 @@ bool Aura::CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo&
void Aura::CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_AFTER_PROC, aurApp);
- std::list<AuraScript::AuraProcHandler>::iterator hookItrEnd = (*scritr)->AfterProc.end(), hookItr = (*scritr)->AfterProc.begin();
+ auto hookItrEnd = (*scritr)->AfterProc.end(), hookItr = (*scritr)->AfterProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
hookItr->Call(*scritr, eventInfo);
@@ -2336,13 +2386,30 @@ void Aura::CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventI
}
}
+bool Aura::CallScriptCheckEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo)
+{
+ bool result = true;
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ {
+ (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC, aurApp);
+ auto hookItrEnd = (*scritr)->DoCheckEffectProc.end(), hookItr = (*scritr)->DoCheckEffectProc.begin();
+ for (; hookItr != hookItrEnd; ++hookItr)
+ if (hookItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ result &= hookItr->Call(*scritr, aurEff, eventInfo);
+
+ (*scritr)->_FinishScriptCall();
+ }
+
+ return result;
+}
+
bool Aura::CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
bool preventDefault = false;
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_PROC, aurApp);
- std::list<AuraScript::EffectProcHandler>::iterator effEndItr = (*scritr)->OnEffectProc.end(), effItr = (*scritr)->OnEffectProc.begin();
+ auto effEndItr = (*scritr)->OnEffectProc.end(), effItr = (*scritr)->OnEffectProc.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff, eventInfo);
@@ -2357,10 +2424,10 @@ bool Aura::CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplicatio
void Aura::CallScriptAfterEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
- for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_PROC, aurApp);
- std::list<AuraScript::EffectProcHandler>::iterator effEndItr = (*scritr)->AfterEffectProc.end(), effItr = (*scritr)->AfterEffectProc.begin();
+ auto effEndItr = (*scritr)->AfterEffectProc.end(), effItr = (*scritr)->AfterEffectProc.begin();
for (; effItr != effEndItr; ++effItr)
if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
effItr->Call(*scritr, aurEff, eventInfo);
@@ -2403,18 +2470,17 @@ void UnitAura::Remove(AuraRemoveMode removeMode)
GetUnitOwner()->RemoveOwnedAura(this, removeMode);
}
-void UnitAura::FillTargetMap(std::map<Unit*, uint8> & targets, Unit* caster)
+void UnitAura::FillTargetMap(std::unordered_map<Unit*, uint8>& targets, Unit* caster)
{
for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
{
if (!HasEffect(effIndex))
continue;
- UnitList targetList;
+
+ std::deque<Unit*> units;
// non-area aura
if (GetSpellInfo()->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AURA)
- {
- targetList.push_back(GetUnitOwner());
- }
+ units.push_back(GetUnitOwner());
else
{
float radius = GetSpellInfo()->Effects[effIndex].CalcRadius(caster);
@@ -2426,48 +2492,48 @@ void UnitAura::FillTargetMap(std::map<Unit*, uint8> & targets, Unit* caster)
case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
case SPELL_EFFECT_APPLY_AREA_AURA_RAID:
{
- targetList.push_back(GetUnitOwner());
- Trinity::AnyGroupedUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, GetSpellInfo()->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID);
- Trinity::UnitListSearcher<Trinity::AnyGroupedUnitInObjectRangeCheck> searcher(GetUnitOwner(), targetList, u_check);
+ units.push_back(GetUnitOwner());
+ Trinity::AnyGroupedUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS));
+ Trinity::UnitListSearcher<Trinity::AnyGroupedUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check);
GetUnitOwner()->VisitNearbyObject(radius, searcher);
break;
}
case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
{
- targetList.push_back(GetUnitOwner());
- Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius);
- Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(GetUnitOwner(), targetList, u_check);
+ units.push_back(GetUnitOwner());
+ Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS));
+ Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check);
GetUnitOwner()->VisitNearbyObject(radius, searcher);
break;
}
case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY:
{
- Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius); // No GetCharmer in searcher
- Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(GetUnitOwner(), targetList, u_check);
+ Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo); // No GetCharmer in searcher
+ Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check);
GetUnitOwner()->VisitNearbyObject(radius, searcher);
break;
}
case SPELL_EFFECT_APPLY_AREA_AURA_PET:
- targetList.push_back(GetUnitOwner());
+ units.push_back(GetUnitOwner());
// no break
case SPELL_EFFECT_APPLY_AREA_AURA_OWNER:
{
if (Unit* owner = GetUnitOwner()->GetCharmerOrOwner())
if (GetUnitOwner()->IsWithinDistInMap(owner, radius))
- targetList.push_back(owner);
+ units.push_back(owner);
break;
}
}
}
}
- for (UnitList::iterator itr = targetList.begin(); itr!= targetList.end();++itr)
+ for (Unit* unit : units)
{
- std::map<Unit*, uint8>::iterator existing = targets.find(*itr);
- if (existing != targets.end())
- existing->second |= 1<<effIndex;
+ auto itr = targets.find(unit);
+ if (itr != targets.end())
+ itr->second |= 1 << effIndex;
else
- targets[*itr] = 1<<effIndex;
+ targets[unit] = 1 << effIndex;
}
}
}
@@ -2490,7 +2556,7 @@ void DynObjAura::Remove(AuraRemoveMode removeMode)
_Remove(removeMode);
}
-void DynObjAura::FillTargetMap(std::map<Unit*, uint8> & targets, Unit* /*caster*/)
+void DynObjAura::FillTargetMap(std::unordered_map<Unit*, uint8>& targets, Unit* /*caster*/)
{
Unit* dynObjOwnerCaster = GetDynobjOwner()->GetCaster();
float radius = GetDynobjOwner()->GetRadius();
@@ -2499,28 +2565,29 @@ void DynObjAura::FillTargetMap(std::map<Unit*, uint8> & targets, Unit* /*caster*
{
if (!HasEffect(effIndex))
continue;
- UnitList targetList;
+
+ std::deque<Unit*> units;
if (GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_ALLY
|| GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ALLY)
{
- Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
- Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
+ Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS));
+ Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), units, u_check);
GetDynobjOwner()->VisitNearbyObject(radius, searcher);
}
else
{
Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
- Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
+ Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(GetDynobjOwner(), units, u_check);
GetDynobjOwner()->VisitNearbyObject(radius, searcher);
}
- for (UnitList::iterator itr = targetList.begin(); itr!= targetList.end();++itr)
+ for (Unit* unit : units)
{
- std::map<Unit*, uint8>::iterator existing = targets.find(*itr);
- if (existing != targets.end())
- existing->second |= 1<<effIndex;
+ auto itr = targets.find(unit);
+ if (itr != targets.end())
+ itr->second |= 1 << effIndex;
else
- targets[*itr] = 1<<effIndex;
+ targets[unit] = 1 << effIndex;
}
}
}
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index a147957f258..1533746893a 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -84,13 +84,13 @@ class TC_GAME_API AuraApplication
class TC_GAME_API Aura
{
- friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID);
+ friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, bool resetPeriodicTimer);
public:
typedef std::map<ObjectGuid, AuraApplication*> ApplicationMap;
- static uint8 BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 avalibleEffectMask, WorldObject* owner);
- static Aura* TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount = NULL, Item* castItem = NULL, ObjectGuid casterGUID = ObjectGuid::Empty, bool* refresh = NULL);
- static Aura* TryCreate(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount = NULL, Item* castItem = NULL, ObjectGuid casterGUID = ObjectGuid::Empty);
+ static uint8 BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 availableEffectMask, WorldObject* owner);
+ static Aura* TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount = nullptr, Item* castItem = nullptr, ObjectGuid casterGUID = ObjectGuid::Empty, bool* refresh = nullptr, bool resetPeriodicTimer = true);
+ static Aura* TryCreate(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32* baseAmount = nullptr, Item* castItem = nullptr, ObjectGuid casterGUID = ObjectGuid::Empty);
static Aura* Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID);
explicit Aura(SpellInfo const* spellproto, WorldObject* owner, Unit* caster, Item* castItem, ObjectGuid casterGUID);
void _InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount);
@@ -113,7 +113,7 @@ class TC_GAME_API Aura
void _Remove(AuraRemoveMode removeMode);
virtual void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) = 0;
- virtual void FillTargetMap(std::map<Unit*, uint8> & targets, Unit* caster) = 0;
+ virtual void FillTargetMap(std::unordered_map<Unit*, uint8>& targets, Unit* caster) = 0;
void UpdateTargetMap(Unit* caster, bool apply = true);
void _RegisterForTargets() {Unit* caster = GetCaster(); UpdateTargetMap(caster, false);}
@@ -131,7 +131,7 @@ class TC_GAME_API Aura
int32 GetDuration() const { return m_duration; }
void SetDuration(int32 duration, bool withMods = false);
void RefreshDuration(bool withMods = false);
- void RefreshTimers();
+ void RefreshTimers(bool resetPeriodicTimer);
bool IsExpired() const { return !GetDuration() && !m_dropEvent; }
bool IsPermanent() const { return GetMaxDuration() == -1; }
@@ -146,7 +146,7 @@ class TC_GAME_API Aura
uint8 GetStackAmount() const { return m_stackAmount; }
void SetStackAmount(uint8 num);
- bool ModStackAmount(int32 num, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
+ bool ModStackAmount(int32 num, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT, bool resetPeriodicTimer = true);
void RefreshSpellMods();
@@ -199,18 +199,14 @@ class TC_GAME_API Aura
bool CheckAreaTarget(Unit* target);
bool CanStackWith(Aura const* existingAura) const;
- // Proc system
- // this subsystem is not yet in use - the core of it is functional, but still some research has to be done
- // and some dependant problems fixed before it can replace old proc system (for example cooldown handling)
- // currently proc system functionality is implemented in Unit::ProcDamageAndSpell
bool IsProcOnCooldown(std::chrono::steady_clock::time_point now) const;
void AddProcCooldown(std::chrono::steady_clock::time_point cooldownEnd);
bool IsUsingCharges() const { return m_isUsingCharges; }
void SetUsingCharges(bool val) { m_isUsingCharges = val; }
void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now);
- bool IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const;
+ uint8 GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const;
float CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const;
- void TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo);
+ void TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo);
// AuraScript
void LoadScripts();
@@ -233,6 +229,7 @@ class TC_GAME_API Aura
void CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & splitAmount);
// Spell Proc Hooks
bool CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
+ bool CallScriptCheckEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo);
bool CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
bool CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
void CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
@@ -241,9 +238,11 @@ class TC_GAME_API Aura
AuraScript* GetScriptByName(std::string const& scriptName) const;
- std::list<AuraScript*> m_loadedScripts;
+ std::vector<AuraScript*> m_loadedScripts;
+
private:
void _DeleteRemovedApplications();
+
protected:
SpellInfo const* const m_spellInfo;
ObjectGuid const m_casterGuid;
@@ -286,14 +285,14 @@ class TC_GAME_API UnitAura : public Aura
void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) override;
- void FillTargetMap(std::map<Unit*, uint8> & targets, Unit* caster) override;
+ void FillTargetMap(std::unordered_map<Unit*, uint8>& targets, Unit* caster) override;
// Allow Apply Aura Handler to modify and access m_AuraDRGroup
void SetDiminishGroup(DiminishingGroup group) { m_AuraDRGroup = group; }
DiminishingGroup GetDiminishGroup() const { return m_AuraDRGroup; }
private:
- DiminishingGroup m_AuraDRGroup:8; // Diminishing
+ DiminishingGroup m_AuraDRGroup; // Diminishing
};
class TC_GAME_API DynObjAura : public Aura
@@ -304,7 +303,7 @@ class TC_GAME_API DynObjAura : public Aura
public:
void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) override;
- void FillTargetMap(std::map<Unit*, uint8> & targets, Unit* caster) override;
+ void FillTargetMap(std::unordered_map<Unit*, uint8>& targets, Unit* caster) override;
};
class TC_GAME_API ChargeDropEvent : public BasicEvent
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 8332219cff1..c082c0a7584 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -586,13 +586,11 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO
destTarget = NULL;
damage = 0;
effectHandleMode = SPELL_EFFECT_HANDLE_LAUNCH;
- m_diminishLevel = DIMINISHING_LEVEL_1;
- m_diminishGroup = DIMINISHING_NONE;
m_damage = 0;
m_healing = 0;
m_procAttacker = 0;
m_procVictim = 0;
- m_procEx = 0;
+ m_hitMask = 0;
focusObject = NULL;
m_cast_count = 0;
m_glyphIndex = 0;
@@ -628,12 +626,10 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO
Spell::~Spell()
{
// unload scripts
- while (!m_loadedScripts.empty())
+ for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
{
- std::list<SpellScript*>::iterator itr = m_loadedScripts.begin();
(*itr)->_Unload();
delete (*itr);
- m_loadedScripts.erase(itr);
}
if (m_referencedFromCurrentSpell && m_selfContainer && *m_selfContainer == this)
@@ -649,7 +645,8 @@ Spell::~Spell()
delete m_spellValue;
- CheckEffectExecuteData();
+ // missing cleanup somewhere, mem leaks so let's crash
+ AssertEffectExecuteData();
}
void Spell::InitExplicitTargets(SpellCastTargets const& targets)
@@ -1121,8 +1118,14 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge
SpellTargetObjectTypes objectType = targetType.GetObjectType();
SpellTargetCheckTypes selectionType = targetType.GetCheckType();
ConditionContainer* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions;
- float coneAngle = float(M_PI) / 2;
- float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod;
+ float coneAngle = float(M_PI) / 2.f;
+
+ float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster);
+ // Workaround for some spells that don't have RadiusEntry set in dbc (but SpellRange instead)
+ if (G3D::fuzzyEq(radius, 0.f))
+ radius = m_spellInfo->GetMaxRange(m_spellInfo->IsPositiveEffect(effIndex), m_caster, this);
+
+ radius *= m_spellValue->RadiusMod;
if (uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList))
{
@@ -1208,7 +1211,13 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge
return;
}
std::list<WorldObject*> targets;
- float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod;
+ float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster);
+ // Workaround for some spells that don't have RadiusEntry set in dbc (but SpellRange instead)
+ if (G3D::fuzzyEq(radius, 0.f))
+ radius = m_spellInfo->GetMaxRange(m_spellInfo->IsPositiveEffect(effIndex), m_caster, this);
+
+ radius *= m_spellValue->RadiusMod;
+
SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), m_spellInfo->Effects[effIndex].ImplicitTargetConditions);
CallScriptObjectAreaTargetSelectHandlers(targets, effIndex, targetType);
@@ -1481,7 +1490,7 @@ void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTarg
{
uint32 maxTargets = m_spellInfo->Effects[effIndex].ChainTarget;
if (Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, maxTargets, this);
+ modOwner->ApplySpellMod<SPELLMOD_JUMP_TARGETS>(m_spellInfo->Id, maxTargets, this);
if (maxTargets > 1)
{
@@ -1947,12 +1956,11 @@ GameObject* Spell::SearchSpellFocus()
return focus;
}
-void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
+void Spell::prepareDataForTriggerSystem()
{
//==========================================================================================
// Now fill data for trigger system, need know:
- // can spell trigger another or not (m_canTrigger)
- // Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_procEx)
+ // Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_hitMask)
//==========================================================================================
m_procVictim = m_procAttacker = 0;
@@ -1982,7 +1990,7 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
break;
default:
if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON &&
- m_spellInfo->EquippedItemSubClassMask & (1<<ITEM_SUBCLASS_WEAPON_WAND)
+ m_spellInfo->EquippedItemSubClassMask & (1 << ITEM_SUBCLASS_WEAPON_WAND)
&& m_spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG)) // Wands auto attack
{
m_procAttacker = PROC_FLAG_DONE_RANGED_AUTO_ATTACK;
@@ -1991,17 +1999,20 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
// For other spells trigger procflags are set in Spell::DoAllEffectOnTarget
// Because spell positivity is dependant on target
}
- m_procEx = PROC_EX_NONE;
+ m_hitMask = PROC_HIT_NONE;
// Hunter trap spells - activation proc for Lock and Load, Entrapment and Misdirection
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER &&
- (m_spellInfo->SpellFamilyFlags[0] & 0x18 || // Freezing and Frost Trap, Freezing Arrow
- m_spellInfo->Id == 57879 || // Snake Trap - done this way to avoid double proc
- m_spellInfo->SpellFamilyFlags[2] & 0x00024000)) // Explosive and Immolation Trap
+ (m_spellInfo->SpellFamilyFlags[0] & 0x18 || // Freezing and Frost Trap, Freezing Arrow
+ m_spellInfo->Id == 57879 || // Snake Trap - done this way to avoid double proc
+ m_spellInfo->SpellFamilyFlags[2] & 0x00024000)) // Explosive and Immolation Trap
+ {
m_procAttacker |= PROC_FLAG_DONE_TRAP_ACTIVATION;
- /* Effects which are result of aura proc from triggered spell cannot proc
- to prevent chain proc of these spells */
+ // also fill up other flags (DoAllEffectOnTarget only fills up flag if both are not set)
+ m_procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
+ m_procVictim |= PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG;
+ }
// Hellfire Effect - trigger as DOT
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags[0] & 0x00000040)
@@ -2009,20 +2020,6 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
m_procAttacker = PROC_FLAG_DONE_PERIODIC;
m_procVictim = PROC_FLAG_TAKEN_PERIODIC;
}
-
- // Ranged autorepeat attack is set as triggered spell - ignore it
- if (!(m_procAttacker & PROC_FLAG_DONE_RANGED_AUTO_ATTACK))
- {
- if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS &&
- (m_spellInfo->HasAttribute(SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC) ||
- m_spellInfo->HasAttribute(SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2)))
- m_procEx |= PROC_EX_INTERNAL_CANT_PROC;
- else if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS)
- m_procEx |= PROC_EX_INTERNAL_TRIGGERED;
- }
- // Totem casts require spellfamilymask defined in spell_proc_event to proc
- if (m_originalCaster && m_caster != m_originalCaster && m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsTotem() && m_caster->IsControlledByPlayer())
- m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY;
}
void Spell::CleanupTargetList()
@@ -2033,6 +2030,32 @@ void Spell::CleanupTargetList()
m_delayMoment = 0;
}
+class ProcReflectDelayed : public BasicEvent
+{
+ public:
+ ProcReflectDelayed(Unit* owner, ObjectGuid casterGuid) : _victim(owner), _casterGuid(casterGuid) { }
+
+ bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
+ {
+ Unit* caster = ObjectAccessor::GetUnit(*_victim, _casterGuid);
+ if (!caster)
+ return true;
+
+ uint32 const typeMaskActor = PROC_FLAG_NONE;
+ uint32 const typeMaskActionTarget = PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG;
+ uint32 const spellTypeMask = PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL;
+ uint32 const spellPhaseMask = PROC_SPELL_PHASE_NONE;
+ uint32 const hitMask = PROC_HIT_REFLECT;
+
+ caster->ProcSkillsAndAuras(_victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr);
+ return true;
+ }
+
+ private:
+ Unit* _victim;
+ ObjectGuid _casterGuid;
+};
+
void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/, Position const* losPosition /*= nullptr*/)
{
for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
@@ -2044,7 +2067,7 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
return;
if (checkIfValid)
- if (m_spellInfo->CheckTarget(m_caster, target, implicit) != SPELL_CAST_OK)
+ if (m_spellInfo->CheckTarget(m_caster, target, implicit || m_caster->GetEntry() == WORLD_TRIGGER) != SPELL_CAST_OK) // skip stealth checks for GO casts
return;
// Check for effect immune skip if immuned
@@ -2112,20 +2135,20 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
targetInfo.timeDelay = (uint64)std::floor(dist / m_spellInfo->Speed * 1000.0f);
// Calculate minimum incoming time
- if (m_delayMoment == 0 || m_delayMoment > targetInfo.timeDelay)
+ if (!m_delayMoment || m_delayMoment > targetInfo.timeDelay)
m_delayMoment = targetInfo.timeDelay;
}
else
- targetInfo.timeDelay = 0LL;
+ targetInfo.timeDelay = 0ULL;
// If target reflect spell back to caster
if (targetInfo.missCondition == SPELL_MISS_REFLECT)
{
// Calculate reflected spell result on caster
- targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, m_canReflect);
+ targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, false); // can't reflect twice
- if (targetInfo.reflectResult == SPELL_MISS_REFLECT) // Impossible reflect again, so simply deflect spell
- targetInfo.reflectResult = SPELL_MISS_PARRY;
+ // Proc spell reflect aura when missile hits the original target
+ target->m_Events.AddEvent(new ProcReflectDelayed(target, m_originalCasterGUID), target->m_Events.CalculateTime(targetInfo.timeDelay));
// Increase time interval for reflected spells by 1.5
targetInfo.timeDelay += targetInfo.timeDelay >> 1;
@@ -2147,14 +2170,14 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask)
{
switch (m_spellInfo->Effects[effIndex].Effect)
{
- case SPELL_EFFECT_GAMEOBJECT_DAMAGE:
- case SPELL_EFFECT_GAMEOBJECT_REPAIR:
- case SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE:
- if (go->GetGoType() != GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
- effectMask &= ~(1 << effIndex);
- break;
- default:
- break;
+ case SPELL_EFFECT_GAMEOBJECT_DAMAGE:
+ case SPELL_EFFECT_GAMEOBJECT_REPAIR:
+ case SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE:
+ if (go->GetGoType() != GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
+ effectMask &= ~(1 << effIndex);
+ break;
+ default:
+ break;
}
}
}
@@ -2189,7 +2212,7 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask)
if (dist < 5.0f)
dist = 5.0f;
target.timeDelay = uint64(floor(dist / m_spellInfo->Speed * 1000.0f));
- if (m_delayMoment == 0 || m_delayMoment > target.timeDelay)
+ if (!m_delayMoment || m_delayMoment > target.timeDelay)
m_delayMoment = target.timeDelay;
}
else
@@ -2297,13 +2320,13 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// Fill base trigger info
uint32 procAttacker = m_procAttacker;
uint32 procVictim = m_procVictim;
- uint32 procEx = m_procEx;
+ uint32 hitMask = m_hitMask;
- m_spellAura = NULL; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied
+ m_spellAura = nullptr; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied
- //Spells with this flag cannot trigger if effect is cast on self
- bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2);
- Unit* spellHitTarget = NULL;
+ // Spells with this flag cannot trigger if effect is cast on self
+ bool const canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2);
+ Unit* spellHitTarget = nullptr;
if (missInfo == SPELL_MISS_NONE) // In case spell hit target, do all effect on that target
spellHitTarget = unit;
@@ -2331,30 +2354,34 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (missInfo2 != SPELL_MISS_MISS)
m_caster->SendSpellMiss(unit, m_spellInfo->Id, missInfo2);
m_damage = 0;
- spellHitTarget = NULL;
+ spellHitTarget = nullptr;
}
}
// Do not take combo points on dodge and miss
- if (missInfo != SPELL_MISS_NONE && m_needComboPoints &&
- m_targets.GetUnitTargetGUID() == target->targetGUID)
- {
+ if (missInfo != SPELL_MISS_NONE && m_needComboPoints && m_targets.GetUnitTargetGUID() == target->targetGUID)
m_needComboPoints = false;
- // Restore spell mods for a miss/dodge/parry Cold Blood
- /// @todo check how broad this rule should be
- if (m_caster->GetTypeId() == TYPEID_PLAYER && (missInfo == SPELL_MISS_MISS ||
- missInfo == SPELL_MISS_DODGE || missInfo == SPELL_MISS_PARRY))
- m_caster->ToPlayer()->RestoreSpellMods(this, 14177);
- }
- // Trigger info was not filled in spell::preparedatafortriggersystem - we do it now
+ // Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now
if (canEffectTrigger && !procAttacker && !procVictim)
{
bool positive = true;
if (m_damage > 0)
positive = false;
else if (!m_healing)
- positive = m_spellInfo->IsPositive();
+ {
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (!(target->effectMask & (1 << i)))
+ continue;
+
+ if (!m_spellInfo->IsPositiveEffect(i))
+ {
+ positive = false;
+ break;
+ }
+ }
+ }
switch (m_spellInfo->DmgClass)
{
@@ -2394,19 +2421,20 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
uint32 addhealth = m_healing;
if (crit)
{
- procEx |= PROC_EX_CRITICAL_HIT;
- addhealth = caster->SpellCriticalHealingBonus(m_spellInfo, addhealth, NULL);
+ hitMask |= PROC_HIT_CRITICAL;
+ addhealth = caster->SpellCriticalHealingBonus(m_spellInfo, addhealth, nullptr);
}
else
- procEx |= PROC_EX_NORMAL_HIT;
+ hitMask |= PROC_HIT_NORMAL;
- int32 gain = caster->HealBySpell(unitTarget, m_spellInfo, addhealth, crit);
- unitTarget->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, m_spellInfo);
- m_healing = gain;
+ HealInfo healInfo(caster, unitTarget, addhealth, m_spellInfo, m_spellInfo->GetSchoolMask());
+ caster->HealBySpell(healInfo, crit);
+ unitTarget->getHostileRefManager().threatAssist(caster, float(healInfo.GetEffectiveHeal()) * 0.5f, m_spellInfo);
+ m_healing = healInfo.GetEffectiveHeal();
- // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
- if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
- caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
+ // Do triggers for unit
+ if (canEffectTrigger)
+ caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, nullptr, &healInfo);
}
// Do damage and triggers
else if (m_damage > 0)
@@ -2414,38 +2442,57 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask);
- // Add bonuses and fill damageInfo struct
- caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo, m_attackType, target->crit);
- caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
+ // Check damage immunity
+ if (unitTarget->IsImmunedToDamage(m_spellInfo))
+ {
+ hitMask = PROC_HIT_IMMUNE;
+ m_damage = 0;
- // Send log damage message to client
- caster->SendSpellNonMeleeDamageLog(&damageInfo);
+ // no packet found in sniffs
+ }
+ else
+ {
+ // Add bonuses and fill damageInfo struct
+ caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo, m_attackType, target->crit);
+ caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
- procEx |= createProcExtendMask(&damageInfo, missInfo);
- procVictim |= PROC_FLAG_TAKEN_DAMAGE;
+ // Send log damage message to client
+ caster->SendSpellNonMeleeDamageLog(&damageInfo);
- // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
- if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
- {
- caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
- if (caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) == 0 &&
- (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
- caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx);
+ hitMask |= createProcHitMask(&damageInfo, missInfo);
+ procVictim |= PROC_FLAG_TAKEN_DAMAGE;
+
+ m_damage = damageInfo.damage;
+ caster->DealSpellDamage(&damageInfo, true);
}
- m_damage = damageInfo.damage;
+ // Do triggers for unit
+ if (canEffectTrigger)
+ {
+ DamageInfo spellDamageInfo(damageInfo, SPELL_DIRECT_DAMAGE, m_attackType, hitMask);
+ caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, this, &spellDamageInfo, nullptr);
- caster->DealSpellDamage(&damageInfo, true);
+ if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) &&
+ (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
+ caster->ToPlayer()->CastItemCombatSpell(spellDamageInfo);
+ }
}
// Passive spell hits/misses or active spells only misses (only triggers)
else
{
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask);
- procEx |= createProcExtendMask(&damageInfo, missInfo);
- // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
- if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
- caster->ProcDamageAndSpell(unit, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
+ hitMask |= createProcHitMask(&damageInfo, missInfo);
+ // Do triggers for unit
+ if (canEffectTrigger)
+ {
+ DamageInfo spellNoDamageInfo(damageInfo, NODAMAGE, m_attackType, hitMask);
+ caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_NO_DMG_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, &spellNoDamageInfo, nullptr);
+
+ if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) &&
+ (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
+ caster->ToPlayer()->CastItemCombatSpell(spellNoDamageInfo);
+ }
// Failed Pickpocket, reveal rogue
if (missInfo == SPELL_MISS_RESIST && m_spellInfo->HasAttribute(SPELL_ATTR0_CU_PICKPOCKET) && unitTarget->GetTypeId() == TYPEID_UNIT)
@@ -2494,7 +2541,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
return SPELL_MISS_EVADE;
// For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
- if (m_spellInfo->Speed && (unit->IsImmunedToDamage(m_spellInfo) || unit->IsImmunedToSpell(m_spellInfo)))
+ if (m_spellInfo->Speed && unit->IsImmunedToSpell(m_spellInfo))
return SPELL_MISS_IMMUNE;
// disable effects to which unit is immune
@@ -2507,15 +2554,12 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
effectMask &= ~(1 << effectNumber);
else if (m_spellInfo->Effects[effectNumber].IsAura() && !m_spellInfo->IsPositiveEffect(effectNumber))
{
- int32 debuff_resist_chance = unit->GetMaxPositiveAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(m_spellInfo->Dispel));
- debuff_resist_chance += unit->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(m_spellInfo->Dispel));
-
- if (debuff_resist_chance > 0)
- if (irand(0, 10000) <= (debuff_resist_chance * 100))
- {
- effectMask &= ~(1 << effectNumber);
- returnVal = SPELL_MISS_RESIST;
- }
+ int32 debuff_resist_chance = unit->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, static_cast<int32>(m_spellInfo->Dispel));
+ if (debuff_resist_chance > 0 && roll_chance_i(debuff_resist_chance))
+ {
+ effectMask &= ~(1 << effectNumber);
+ returnVal = SPELL_MISS_RESIST;
+ }
}
}
}
@@ -2546,12 +2590,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
return SPELL_MISS_EVADE;
if (m_caster->_IsValidAttackTarget(unit, m_spellInfo))
- {
unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_HITBYSPELL);
-
- if (!m_spellInfo->HasAttribute(SPELL_ATTR0_CU_DONT_BREAK_STEALTH))
- unit->RemoveAurasByType(SPELL_AURA_MOD_STEALTH);
- }
else if (m_caster->IsFriendlyTo(unit))
{
// for delayed spells ignore negative spells (after duel end) for friendly targets
@@ -2581,16 +2620,19 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
aura_effmask |= 1 << i;
// Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add
- m_diminishGroup = GetDiminishingReturnsGroupForSpell(m_spellInfo, m_triggeredByAuraSpell != nullptr);
- if (m_diminishGroup && aura_effmask)
+ bool const triggered = m_triggeredByAuraSpell != nullptr;
+ DiminishingGroup const diminishGroup = m_spellInfo->GetDiminishingReturnsGroupForSpell(triggered);
+
+ DiminishingLevels diminishLevel = DIMINISHING_LEVEL_1;
+ if (diminishGroup && aura_effmask)
{
- m_diminishLevel = unit->GetDiminishing(m_diminishGroup);
- DiminishingReturnsType type = GetDiminishingReturnsGroupType(m_diminishGroup);
+ diminishLevel = unit->GetDiminishing(diminishGroup);
+ DiminishingReturnsType type = m_spellInfo->GetDiminishingReturnsGroupType(triggered);
// Increase Diminishing on unit, current informations for actually casts will use values above
if ((type == DRTYPE_PLAYER &&
(unit->GetCharmerOrOwnerPlayerOrPlayerItself() || (unit->GetTypeId() == TYPEID_UNIT && unit->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_ALL_DIMINISH))) ||
type == DRTYPE_ALL)
- unit->IncrDiminishing(m_diminishGroup);
+ unit->IncrDiminishing(m_spellInfo, triggered);
}
if (aura_effmask)
@@ -2617,8 +2659,9 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
if (m_originalCaster)
{
bool refresh = false;
+ bool const resetPeriodicTimer = !(_triggeredCastFlags & TRIGGERED_DONT_RESET_PERIODIC_TIMER);
m_spellAura = Aura::TryRefreshStackOrCreate(aurSpellInfo, effectMask, unit,
- m_originalCaster, (aurSpellInfo == m_spellInfo) ? &m_spellValue->EffectBasePoints[0] : &basePoints[0], m_CastItem, ObjectGuid::Empty, &refresh);
+ m_originalCaster, (aurSpellInfo == m_spellInfo) ? &m_spellValue->EffectBasePoints[0] : &basePoints[0], m_CastItem, ObjectGuid::Empty, &refresh, resetPeriodicTimer);
if (m_spellAura)
{
// Set aura stack amount to desired value
@@ -2632,8 +2675,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
// Now Reduce spell duration using data received at spell hit
int32 duration = m_spellAura->GetMaxDuration();
- int32 limitduration = GetDiminishingReturnsLimitDuration(m_diminishGroup, aurSpellInfo);
- float diminishMod = unit->ApplyDiminishingToDuration(m_diminishGroup, duration, m_originalCaster, m_diminishLevel, limitduration);
+ float diminishMod = unit->ApplyDiminishingToDuration(aurSpellInfo, triggered, duration, m_originalCaster, diminishLevel);
// unit is immune to aura if it was diminished to 0 duration
if (diminishMod == 0.0f)
@@ -2648,7 +2690,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
}
else
{
- ((UnitAura*)m_spellAura)->SetDiminishGroup(m_diminishGroup);
+ ((UnitAura*)m_spellAura)->SetDiminishGroup(diminishGroup);
bool positive = m_spellAura->GetSpellInfo()->IsPositive();
if (AuraApplication* aurApp = m_spellAura->GetApplicationOfTarget(m_originalCaster->GetGUID()))
@@ -2712,8 +2754,8 @@ void Spell::DoTriggersOnSpellHit(Unit* unit, uint8 effMask)
// info confirmed with retail sniffs of permafrost and shadow weaving
if (!m_hitTriggerSpells.empty())
{
- int _duration = 0;
- for (HitTriggerSpellList::const_iterator i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i)
+ int32 _duration = 0;
+ for (auto i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i)
{
if (CanExecuteTriggersOnHit(effMask, i->triggeredByAura) && roll_chance_i(i->chance))
{
@@ -2815,7 +2857,7 @@ bool Spell::UpdateChanneledTargetList()
{
range = m_spellInfo->GetMaxRange(m_spellInfo->IsPositive());
if (Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
+ modOwner->ApplySpellMod<SPELLMOD_RANGE>(m_spellInfo->Id, range, this);
}
for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
@@ -2925,7 +2967,8 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
if ((_triggeredCastFlags & TRIGGERED_IGNORE_COMBO_POINTS) || m_CastItem || !m_caster->m_playerMovingMe)
m_needComboPoints = false;
- SpellCastResult result = CheckCast(true);
+ uint32 param1 = 0, param2 = 0;
+ SpellCastResult result = CheckCast(true, &param1, &param2);
if (result != SPELL_CAST_OK && !IsAutoRepeat()) //always cast autorepeat dummy for triggering
{
// Periodic auras should be interrupted when aura triggers a spell which can't be cast
@@ -2946,14 +2989,17 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
m_caster->ToPlayer()->SetSpellModTakingSpell(this, false);
}
- SendCastResult(result);
+ if (param1 || param2)
+ SendCastResult(result, &param1, &param2);
+ else
+ SendCastResult(result);
finish(false);
return;
}
// Prepare data for triggers
- prepareDataForTriggerSystem(triggeredByAura);
+ prepareDataForTriggerSystem();
if (Player* player = m_caster->ToPlayer())
{
@@ -2971,7 +3017,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
m_casttime = m_spellInfo->CalcCastTime(this);
if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED)) // _UNIT actually means creature. for some reason.
- if (!(IsNextMeleeSwingSpell() || IsAutoRepeat() || _triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING))
+ if (!(m_spellInfo->IsNextMeleeSwingSpell() || IsAutoRepeat() || (_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING)))
{
if (m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
m_caster->ToCreature()->FocusTarget(this, m_targets.GetObjectTarget());
@@ -2984,8 +3030,8 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
// (even if they are interrupted on moving, spells with almost immediate effect get to have their effect processed before movement interrupter kicks in)
if ((m_spellInfo->IsChanneled() || m_casttime) && m_caster->GetTypeId() == TYPEID_PLAYER && !(m_caster->IsCharmed() && m_caster->GetCharmerGUID().IsCreature()) && m_caster->isMoving() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT))
{
- // 1. Is a channel spell, 2. Has no casttime, 3. And has flag to allow movement during channel
- if (!(m_spellInfo->IsChanneled() && !m_casttime && m_spellInfo->HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING)))
+ // 1. Has casttime, 2. Or doesn't have flag to allow movement during channel
+ if (m_casttime || !m_spellInfo->IsMoveAllowedChannel())
{
SendCastResult(SPELL_FAILED_MOVING);
finish(false);
@@ -3061,10 +3107,6 @@ void Spell::cancel()
SendInterrupted(0);
SendCastResult(SPELL_FAILED_INTERRUPTED);
- // spell is canceled-take mods and clear list
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->RemoveSpellMods(this);
-
m_appliedMods.clear();
break;
@@ -3137,10 +3179,11 @@ void Spell::cast(bool skipCheck)
// skip check if done already (for instant cast spells for example)
if (!skipCheck)
{
- SpellCastResult castResult = CheckCast(false);
+ uint32 param1 = 0, param2 = 0;
+ SpellCastResult castResult = CheckCast(false, &param1, &param2);
if (castResult != SPELL_CAST_OK)
{
- SendCastResult(castResult);
+ SendCastResult(castResult, &param1, &param2);
SendInterrupted(0);
//restore spell mods
if (m_caster->GetTypeId() == TYPEID_PLAYER)
@@ -3299,6 +3342,25 @@ void Spell::cast(bool skipCheck)
if (Creature* creatureCaster = m_caster->ToCreature())
creatureCaster->ReleaseFocus(this);
+
+ if (!m_originalCaster)
+ return;
+
+ // Handle procs on cast
+ uint32 procAttacker = m_procAttacker;
+ if (!procAttacker)
+ {
+ if (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC)
+ procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
+ else
+ procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG;
+ }
+
+ uint32 hitMask = m_hitMask;
+ if (!(hitMask & PROC_HIT_CRITICAL))
+ hitMask |= PROC_HIT_NORMAL;
+
+ m_originalCaster->ProcSkillsAndAuras(nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr);
}
void Spell::handle_immediate()
@@ -3312,7 +3374,7 @@ void Spell::handle_immediate()
// First mod_duration then haste - see Missile Barrage
// Apply duration mod
if (Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
+ modOwner->ApplySpellMod<SPELLMOD_DURATION>(m_spellInfo->Id, duration);
// Apply haste mods
m_caster->ModSpellDurationTime(m_spellInfo, duration, this);
@@ -3434,9 +3496,6 @@ uint64 Spell::handle_delayed(uint64 t_offset)
void Spell::_handle_immediate_phase()
{
m_spellAura = NULL;
- // initialize Diminishing Returns Data
- m_diminishLevel = DIMINISHING_LEVEL_1;
- m_diminishGroup = DIMINISHING_NONE;
// handle some immediate features of the spell here
HandleThreatSpells();
@@ -3455,22 +3514,8 @@ void Spell::_handle_immediate_phase()
}
// process items
- for (std::list<ItemTargetInfo>::iterator ihit= m_UniqueItemInfo.begin(); ihit != m_UniqueItemInfo.end(); ++ihit)
+ for (std::list<ItemTargetInfo>::iterator ihit = m_UniqueItemInfo.begin(); ihit != m_UniqueItemInfo.end(); ++ihit)
DoAllEffectOnTarget(&(*ihit));
-
- if (!m_originalCaster)
- return;
- // Handle procs on cast
- /// @todo finish new proc system:P
- if (m_UniqueTargetInfo.empty() && m_targets.HasDst())
- {
- uint32 procAttacker = m_procAttacker;
- if (!procAttacker)
- procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS;
-
- // Proc the spells that have DEST target
- m_originalCaster->ProcDamageAndSpell(NULL, procAttacker, 0, m_procEx | PROC_EX_NORMAL_HIT, 0, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell);
- }
}
void Spell::_handle_finish_phase()
@@ -3494,7 +3539,24 @@ void Spell::_handle_finish_phase()
m_caster->m_extraAttacks = 0;
}
- /// @todo trigger proc phase finish here
+ // Handle procs on finish
+ if (!m_originalCaster)
+ return;
+
+ uint32 procAttacker = m_procAttacker;
+ if (!procAttacker)
+ {
+ if (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC)
+ procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
+ else
+ procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG;
+ }
+
+ uint32 hitMask = m_hitMask;
+ if (!(hitMask & PROC_HIT_CRITICAL))
+ hitMask |= PROC_HIT_NORMAL;
+
+ m_originalCaster->ProcSkillsAndAuras(nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_FINISH, hitMask, this, nullptr, nullptr);
}
void Spell::SendSpellCooldown()
@@ -3525,7 +3587,7 @@ void Spell::update(uint32 difftime)
(m_spellInfo->Effects[0].Effect != SPELL_EFFECT_STUCK || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR))))
{
// don't cancel for melee, autorepeat, triggered and instant spells
- if (!IsNextMeleeSwingSpell() && !IsAutoRepeat() && !IsTriggered() && !(IsChannelActive() && m_spellInfo->HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING)))
+ if (!m_spellInfo->IsNextMeleeSwingSpell() && !IsAutoRepeat() && !IsTriggered() && !(IsChannelActive() && m_spellInfo->IsMoveAllowedChannel()))
{
// if charmed by creature, trust the AI not to cheat and allow the cast to proceed
// @todo this is a hack, "creature" movesplines don't differentiate turning/moving right now
@@ -3547,7 +3609,7 @@ void Spell::update(uint32 difftime)
m_timer -= difftime;
}
- if (m_timer == 0 && !IsNextMeleeSwingSpell() && !IsAutoRepeat())
+ if (m_timer == 0 && !m_spellInfo->IsNextMeleeSwingSpell() && !IsAutoRepeat())
// don't CheckCast for instant spells - done in spell::prepare, skip duplicate checks, needed for range checks for example
cast(!m_casttime);
break;
@@ -3560,8 +3622,12 @@ void Spell::update(uint32 difftime)
if (!UpdateChanneledTargetList())
{
TC_LOG_DEBUG("spells", "Channeled spell %d is removed due to lack of targets", m_spellInfo->Id);
- SendChannelUpdate(0);
- finish();
+ m_timer = 0;
+
+ // Also remove applied auras
+ for (TargetInfo const& target : m_UniqueTargetInfo)
+ if (Unit* unit = m_caster->GetGUID() == target.targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, target.targetGUID))
+ unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL);
}
if (m_timer > 0)
@@ -3641,6 +3707,7 @@ void Spell::finish(bool ok)
break;
}
}
+
if (!found && !m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
{
m_caster->resetAttackTimer(BASE_ATTACK);
@@ -3657,24 +3724,12 @@ void Spell::finish(bool ok)
m_caster->ToPlayer()->UpdatePotionCooldown(this);
}
- if (Player* modOwner = m_caster->GetSpellModOwner())
- {
- // triggered spell pointer can be not set in some cases
- // this is needed for proper apply of triggered spell mods
- modOwner->SetSpellModTakingSpell(this, true);
-
- // Take mods after trigger spell (needed for 14177 to affect 48664)
- // mods are taken only on succesfull cast and independantly from targets of the spell
- modOwner->RemoveSpellMods(this);
- modOwner->SetSpellModTakingSpell(this, false);
- }
-
// Stop Attack for some spells
if (m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET))
m_caster->AttackStop();
}
-void Spell::WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError)
+void Spell::WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
{
data << uint8(castCount); // single cast or multi 2.3 (0/1)
data << uint32(spellInfo->Id);
@@ -3682,115 +3737,185 @@ void Spell::WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo con
switch (result)
{
case SPELL_FAILED_REQUIRES_SPELL_FOCUS:
- data << uint32(spellInfo->RequiresSpellFocus); // SpellFocusObject.dbc id
+ if (param1)
+ data << uint32(*param1);
+ else
+ data << uint32(spellInfo->RequiresSpellFocus); // SpellFocusObject.dbc id
break;
case SPELL_FAILED_REQUIRES_AREA: // AreaTable.dbc id
- // hardcode areas limitation case
- switch (spellInfo->Id)
+ if (param1)
+ data << uint32(*param1);
+ else
{
- case 41617: // Cenarion Mana Salve
- case 41619: // Cenarion Healing Salve
- data << uint32(3905);
- break;
- case 41618: // Bottled Nethergon Energy
- case 41620: // Bottled Nethergon Vapor
- data << uint32(3842);
- break;
- case 45373: // Bloodberry Elixir
- data << uint32(4075);
- break;
- default: // default case (don't must be)
- data << uint32(0);
- break;
+ // hardcode areas limitation case
+ switch (spellInfo->Id)
+ {
+ case 41617: // Cenarion Mana Salve
+ case 41619: // Cenarion Healing Salve
+ data << uint32(3905);
+ break;
+ case 41618: // Bottled Nethergon Energy
+ case 41620: // Bottled Nethergon Vapor
+ data << uint32(3842);
+ break;
+ case 45373: // Bloodberry Elixir
+ data << uint32(4075);
+ break;
+ default: // default case (don't must be)
+ data << uint32(0);
+ break;
+ }
}
break;
case SPELL_FAILED_TOTEMS:
- if (spellInfo->Totem[0])
- data << uint32(spellInfo->Totem[0]);
- if (spellInfo->Totem[1])
- data << uint32(spellInfo->Totem[1]);
+ if (param1)
+ {
+ data << uint32(*param1);
+ if (param2)
+ data << uint32(*param2);
+ }
+ else
+ {
+ if (spellInfo->Totem[0])
+ data << uint32(spellInfo->Totem[0]);
+ if (spellInfo->Totem[1])
+ data << uint32(spellInfo->Totem[1]);
+ }
break;
case SPELL_FAILED_TOTEM_CATEGORY:
- if (spellInfo->TotemCategory[0])
- data << uint32(spellInfo->TotemCategory[0]);
- if (spellInfo->TotemCategory[1])
- data << uint32(spellInfo->TotemCategory[1]);
+ if (param1)
+ {
+ data << uint32(*param1);
+ if (param2)
+ data << uint32(*param2);
+ }
+ else
+ {
+ if (spellInfo->TotemCategory[0])
+ data << uint32(spellInfo->TotemCategory[0]);
+ if (spellInfo->TotemCategory[1])
+ data << uint32(spellInfo->TotemCategory[1]);
+ }
break;
case SPELL_FAILED_EQUIPPED_ITEM_CLASS:
case SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND:
case SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND:
- data << uint32(spellInfo->EquippedItemClass);
- data << uint32(spellInfo->EquippedItemSubClassMask);
+ if (param1 && param2)
+ {
+ data << uint32(*param1);
+ data << uint32(*param2);
+ }
+ else
+ {
+ data << uint32(spellInfo->EquippedItemClass);
+ data << uint32(spellInfo->EquippedItemSubClassMask);
+ }
break;
case SPELL_FAILED_TOO_MANY_OF_ITEM:
{
- uint32 item = 0;
- for (int8 eff = 0; eff < MAX_SPELL_EFFECTS; eff++)
- if (spellInfo->Effects[eff].ItemType)
- item = spellInfo->Effects[eff].ItemType;
- ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item);
- if (proto && proto->ItemLimitCategory)
- data << uint32(proto->ItemLimitCategory);
- break;
+ if (param1)
+ data << uint32(*param1);
+ else
+ {
+ uint32 item = 0;
+ for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS && !item; ++effIndex)
+ if (uint32 itemType = spellInfo->Effects[effIndex].ItemType)
+ item = itemType;
+
+ ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item);
+ if (proto && proto->ItemLimitCategory)
+ data << uint32(proto->ItemLimitCategory);
+ }
+ break;
}
case SPELL_FAILED_CUSTOM_ERROR:
data << uint32(customError);
break;
case SPELL_FAILED_REAGENTS:
{
- uint32 missingItem = 0;
- for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
+ if (param1)
+ data << uint32(*param1);
+ else
{
- if (spellInfo->Reagent[i] <= 0)
- continue;
+ uint32 missingItem = 0;
+ for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
+ {
+ if (spellInfo->Reagent[i] <= 0)
+ continue;
- uint32 itemid = spellInfo->Reagent[i];
- uint32 itemcount = spellInfo->ReagentCount[i];
+ uint32 itemid = spellInfo->Reagent[i];
+ uint32 itemcount = spellInfo->ReagentCount[i];
- if (!caster->HasItemCount(itemid, itemcount))
- {
- missingItem = itemid;
- break;
+ if (!caster->HasItemCount(itemid, itemcount))
+ {
+ missingItem = itemid;
+ break;
+ }
}
- }
- data << uint32(missingItem); // first missing item
+ data << uint32(missingItem); // first missing item
+ }
break;
}
case SPELL_FAILED_PREVENTED_BY_MECHANIC:
- data << uint32(spellInfo->Mechanic);
+ if (param1)
+ data << uint32(*param1);
+ else
+ data << uint32(spellInfo->Mechanic);
break;
case SPELL_FAILED_NEED_EXOTIC_AMMO:
- data << uint32(spellInfo->EquippedItemSubClassMask);
+ if (param1)
+ data << uint32(*param1);
+ else
+ data << uint32(spellInfo->EquippedItemSubClassMask);
break;
case SPELL_FAILED_NEED_MORE_ITEMS:
- data << uint32(0); // Item entry
- data << uint32(0); // Count
+ if (param1 && param2)
+ {
+ data << uint32(*param1);
+ data << uint32(*param2);
+ }
+ else
+ {
+ data << uint32(0); // Item entry
+ data << uint32(0); // Count
+ }
break;
case SPELL_FAILED_MIN_SKILL:
- data << uint32(0); // SkillLine.dbc Id
- data << uint32(0); // Amount
+ if (param1 && param2)
+ {
+ data << uint32(*param1);
+ data << uint32(*param2);
+ }
+ else
+ {
+ data << uint32(0); // SkillLine.dbc Id
+ data << uint32(0); // Amount
+ }
break;
case SPELL_FAILED_FISHING_TOO_LOW:
- data << uint32(0); // Skill level
+ if (param1)
+ data << uint32(*param1);
+ else
+ data << uint32(0); // Skill level
break;
default:
break;
}
}
-void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/)
+void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
{
if (result == SPELL_CAST_OK)
return;
WorldPacket data(SMSG_CAST_FAILED, 1 + 4 + 1);
- WriteCastResultInfo(data, caster, spellInfo, castCount, result, customError);
+ WriteCastResultInfo(data, caster, spellInfo, castCount, result, customError, param1, param2);
- caster->GetSession()->SendPacket(&data);
+ caster->SendDirectMessage(&data);
}
-void Spell::SendCastResult(SpellCastResult result)
+void Spell::SendCastResult(SpellCastResult result, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) const
{
if (result == SPELL_CAST_OK)
return;
@@ -3798,13 +3923,13 @@ void Spell::SendCastResult(SpellCastResult result)
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
- if (m_caster->ToPlayer()->GetSession()->PlayerLoading()) // don't send cast results at loading time
+ if (m_caster->ToPlayer()->IsLoading()) // don't send cast results at loading time
return;
if (_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR)
result = SPELL_FAILED_DONT_REPORT;
- SendCastResult(m_caster->ToPlayer(), m_spellInfo, m_cast_count, result, m_customError);
+ SendCastResult(m_caster->ToPlayer(), m_spellInfo, m_cast_count, result, m_customError, param1, param2);
}
void Spell::SendPetCastResult(SpellCastResult result)
@@ -4386,7 +4511,7 @@ void Spell::TakePower()
hit = false;
//lower spell cost on fail (by talent aura)
if (Player* modOwner = m_caster->ToPlayer()->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_SPELL_COST_REFUND_ON_FAIL, m_powerCost);
+ modOwner->ApplySpellMod<SPELLMOD_SPELL_COST_REFUND_ON_FAIL>(m_spellInfo->Id, m_powerCost);
}
break;
}
@@ -4453,7 +4578,7 @@ void Spell::TakeAmmo()
}
}
-SpellCastResult Spell::CheckRuneCost(uint32 runeCostID)
+SpellCastResult Spell::CheckRuneCost(uint32 runeCostID) const
{
if (m_spellInfo->PowerType != POWER_RUNE || !runeCostID)
return SPELL_CAST_OK;
@@ -4478,7 +4603,7 @@ SpellCastResult Spell::CheckRuneCost(uint32 runeCostID)
{
runeCost[i] = src->RuneCost[i];
if (Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this);
+ modOwner->ApplySpellMod<SPELLMOD_COST>(m_spellInfo->Id, runeCost[i], const_cast<Spell*>(this));
}
runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later
@@ -4518,7 +4643,7 @@ void Spell::TakeRunePower(bool didHit)
{
runeCost[i] = runeCostData->RuneCost[i];
if (Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this);
+ modOwner->ApplySpellMod<SPELLMOD_COST>(m_spellInfo->Id, runeCost[i], this);
}
// Let's say we use a skill that requires a Frost rune. This is the order:
@@ -4598,7 +4723,7 @@ void Spell::TakeReagents()
ItemTemplate const* castItemTemplate = m_CastItem ? m_CastItem->GetTemplate() : NULL;
// do not take reagents for these item casts
- if (castItemTemplate && castItemTemplate->Flags & ITEM_PROTO_FLAG_TRIGGERED_CAST)
+ if (castItemTemplate && castItemTemplate->Flags & ITEM_FLAG_NO_REAGENT_COST)
return;
Player* p_caster = m_caster->ToPlayer();
@@ -4677,7 +4802,7 @@ void Spell::HandleThreatSpells()
continue;
// positive spells distribute threat among all units that are in combat with target, like healing
- if (m_spellInfo->_IsPositiveSpell())
+ if (m_spellInfo->IsPositive())
target->getHostileRefManager().threatAssist(m_caster, threatToAdd, m_spellInfo);
// for negative spells threat gets distributed among affected targets
else
@@ -4688,7 +4813,7 @@ void Spell::HandleThreatSpells()
target->AddThreat(m_caster, threatToAdd, m_spellInfo->GetSchoolMask(), m_spellInfo);
}
}
- TC_LOG_DEBUG("spells", "Spell %u, added an additional %f threat for %s %u target(s)", m_spellInfo->Id, threat, m_spellInfo->_IsPositiveSpell() ? "assisting" : "harming", uint32(m_UniqueTargetInfo.size()));
+ TC_LOG_DEBUG("spells", "Spell %u, added an additional %f threat for %s %u target(s)", m_spellInfo->Id, threat, m_spellInfo->IsPositive() ? "assisting" : "harming", uint32(m_UniqueTargetInfo.size()));
}
void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOTarget, uint32 i, SpellEffectHandleMode mode)
@@ -4714,10 +4839,10 @@ void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOT
}
}
-SpellCastResult Spell::CheckCast(bool strict)
+SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
{
// check death state
- if (!m_caster->IsAlive() && !m_spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE) && !(m_spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD) || (IsTriggered() && !m_triggeredByAuraSpell)))
+ if (!m_caster->IsAlive() && !m_spellInfo->IsPassive() && !(m_spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD) || (IsTriggered() && !m_triggeredByAuraSpell)))
return SPELL_FAILED_CASTER_DEAD;
// check cooldowns to prevent cheating
@@ -4777,13 +4902,15 @@ SpellCastResult Spell::CheckCast(bool strict)
bool checkForm = true;
// Ignore form req aura
Unit::AuraEffectList const& ignore = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT);
- for (Unit::AuraEffectList::const_iterator i = ignore.begin(); i != ignore.end(); ++i)
+ for (AuraEffect const* aurEff : ignore)
{
- if (!(*i)->IsAffectedOnSpell(m_spellInfo))
+ if (!aurEff->IsAffectedOnSpell(m_spellInfo))
continue;
+
checkForm = false;
break;
}
+
if (checkForm)
{
// Cannot be used in this stance/form
@@ -4876,17 +5003,21 @@ SpellCastResult Spell::CheckCast(bool strict)
// those spells may have incorrect target entries or not filled at all (for example 15332)
// such spells when learned are not targeting anyone using targeting system, they should apply directly to caster instead
// also, such casts shouldn't be sent to client
- if (!(m_spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE) && (!m_targets.GetUnitTarget() || m_targets.GetUnitTarget() == m_caster)))
+ if (!(m_spellInfo->IsPassive() && (!m_targets.GetUnitTarget() || m_targets.GetUnitTarget() == m_caster)))
{
// Check explicit target for m_originalCaster - todo: get rid of such workarounds
- SpellCastResult castResult = m_spellInfo->CheckExplicitTarget(m_originalCaster ? m_originalCaster : m_caster, m_targets.GetObjectTarget(), m_targets.GetItemTarget());
+ Unit* caster = m_caster;
+ if (m_originalCaster && m_caster->GetEntry() != WORLD_TRIGGER) // Do a simplified check for gameobject casts
+ caster = m_originalCaster;
+
+ SpellCastResult castResult = m_spellInfo->CheckExplicitTarget(caster, m_targets.GetObjectTarget(), m_targets.GetItemTarget());
if (castResult != SPELL_CAST_OK)
return castResult;
}
if (Unit* target = m_targets.GetUnitTarget())
{
- SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, false);
+ SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, m_caster->GetEntry() == WORLD_TRIGGER); // skip stealth checks for GO casts
if (castResult != SPELL_CAST_OK)
return castResult;
@@ -4987,7 +5118,7 @@ SpellCastResult Spell::CheckCast(bool strict)
// always (except passive spells) check items (only player related checks)
if (!m_spellInfo->IsPassive())
{
- castResult = CheckItems();
+ castResult = CheckItems(param1, param2);
if (castResult != SPELL_CAST_OK)
return castResult;
}
@@ -5007,7 +5138,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURAS))
{
- castResult = CheckCasterAuras();
+ castResult = CheckCasterAuras(param1);
if (castResult != SPELL_CAST_OK)
return castResult;
}
@@ -5021,6 +5152,7 @@ SpellCastResult Spell::CheckCast(bool strict)
bool hasNonDispelEffect = false;
uint32 dispelMask = 0;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_DISPEL)
{
if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->HasAttribute(SPELL_ATTR1_MELEE_COMBAT_START))
@@ -5036,6 +5168,7 @@ SpellCastResult Spell::CheckCast(bool strict)
hasNonDispelEffect = true;
break;
}
+ }
if (!hasNonDispelEffect && !hasDispellableAura && dispelMask && !IsTriggered())
{
@@ -5150,7 +5283,7 @@ SpellCastResult Spell::CheckCast(bool strict)
m_caster->RemoveMovementImpairingAuras();
}
- if (m_caster->HasUnitState(UNIT_STATE_ROOT))
+ if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURAS) && m_caster->HasUnitState(UNIT_STATE_ROOT))
return SPELL_FAILED_ROOTED;
if (GetSpellInfo()->NeedsExplicitUnitTarget())
@@ -5619,132 +5752,114 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
return CheckCast(true);
}
-SpellCastResult Spell::CheckCasterAuras() const
+SpellCastResult Spell::CheckCasterAuras(uint32* param1) const
{
// spells totally immuned to caster auras (wsg flag drop, give marks etc)
if (m_spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CASTER_AURAS))
return SPELL_CAST_OK;
- uint8 school_immune = 0;
- uint32 mechanic_immune = 0;
- uint32 dispel_immune = 0;
-
- // Check if the spell grants school or mechanic immunity.
- // We use bitmasks so the loop is done only once and not on every aura check below.
- if (m_spellInfo->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ bool usableWhileStunned = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED);
+ bool usableWhileFeared = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED);
+ bool usableWhileConfused = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED);
+ if (m_spellInfo->HasAttribute(SPELL_ATTR7_USABLE_IN_STUN_FEAR_CONFUSION))
{
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
- if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_SCHOOL_IMMUNITY)
- school_immune |= uint32(m_spellInfo->Effects[i].MiscValue);
- else if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MECHANIC_IMMUNITY)
- mechanic_immune |= 1 << uint32(m_spellInfo->Effects[i].MiscValue);
- else if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_DISPEL_IMMUNITY)
- dispel_immune |= SpellInfo::GetDispelMask(DispelType(m_spellInfo->Effects[i].MiscValue));
- }
- // immune movement impairment and loss of control
- if (m_spellInfo->Id == 42292 || m_spellInfo->Id == 59752 || m_spellInfo->Id == 19574 || m_spellInfo->Id == 53490)
- mechanic_immune = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+ usableWhileStunned = true;
+ usableWhileFeared = true;
+ usableWhileConfused = true;
}
- bool usableInStun = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED);
-
// Glyph of Pain Suppression
// there is no other way to handle it
if (m_spellInfo->Id == 33206 && !m_caster->HasAura(63248))
- usableInStun = false;
+ usableWhileStunned = false;
// Check whether the cast should be prevented by any state you might have.
- SpellCastResult prevented_reason = SPELL_CAST_OK;
- // Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out
- uint32 unitflag = m_caster->GetUInt32Value(UNIT_FIELD_FLAGS); // Get unit state
- if (unitflag & UNIT_FLAG_STUNNED)
- {
- // spell is usable while stunned, check if caster has only mechanic stun auras, another stun types must prevent cast spell
- if (usableInStun)
- {
- bool foundNotStun = false;
- Unit::AuraEffectList const& stunAuras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_STUN);
- for (Unit::AuraEffectList::const_iterator i = stunAuras.begin(); i != stunAuras.end(); ++i)
- {
- if ((*i)->GetSpellInfo()->GetAllEffectsMechanicMask() && !((*i)->GetSpellInfo()->GetAllEffectsMechanicMask() & (1<<MECHANIC_STUN)))
- {
- foundNotStun = true;
- break;
- }
- }
- if (foundNotStun && m_spellInfo->Id != 22812)
- prevented_reason = SPELL_FAILED_STUNNED;
- }
- else
- prevented_reason = SPELL_FAILED_STUNNED;
- }
- else if (unitflag & UNIT_FLAG_CONFUSED && !m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED))
- prevented_reason = SPELL_FAILED_CONFUSED;
- else if (unitflag & UNIT_FLAG_FLEEING && !m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED))
- prevented_reason = SPELL_FAILED_FLEEING;
- else if (unitflag & UNIT_FLAG_SILENCED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
- prevented_reason = SPELL_FAILED_SILENCED;
- else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY)
- prevented_reason = SPELL_FAILED_PACIFIED;
+ SpellCastResult result = SPELL_CAST_OK;
+
+ // Get unit state
+ uint32 const unitflag = m_caster->GetUInt32Value(UNIT_FIELD_FLAGS);
+ if (m_caster->GetCharmerGUID())
+ {
+ if (Unit* charmer = m_caster->GetCharmer())
+ if (charmer->GetUnitBeingMoved() != m_caster && CheckCasterNotImmunedCharmAuras(param1))
+ result = SPELL_FAILED_CHARMED;
+ }
+ else if (unitflag & UNIT_FLAG_STUNNED && !usableWhileStunned && CheckCasterNotImmunedStunAuras(param1))
+ result = SPELL_FAILED_STUNNED;
+ else if (unitflag & UNIT_FLAG_SILENCED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && CheckCasterNotImmunedSilenceAuras(param1))
+ result = SPELL_FAILED_SILENCED;
+ else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && CheckCasterNotImmunedPacifyAuras(param1))
+ result = SPELL_FAILED_PACIFIED;
+ else if (unitflag & UNIT_FLAG_FLEEING && !usableWhileFeared && CheckCasterNotImmunedFearAuras(param1))
+ result = SPELL_FAILED_FLEEING;
+ else if (unitflag & UNIT_FLAG_CONFUSED && !usableWhileConfused && CheckCasterNotImmunedDisorientAuras(param1))
+ result = SPELL_FAILED_CONFUSED;
// Attr must make flag drop spell totally immune from all effects
- if (prevented_reason != SPELL_CAST_OK)
+ if (result != SPELL_CAST_OK)
+ return (param1 && *param1) ? SPELL_FAILED_PREVENTED_BY_MECHANIC : result;
+
+ return SPELL_CAST_OK;
+}
+
+// based on sub_00804430 from 12340 client
+bool Spell::CheckCasterHasNotImmunedAuraType(AuraType auraType, uint32* param1) const
+{
+ // Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
+ Unit::AuraEffectList const& auraEffects = m_caster->GetAuraEffectsByType(auraType);
+ if (auraEffects.empty())
+ return false;
+
+ for (AuraEffect const* aurEff : auraEffects)
{
- if (school_immune || mechanic_immune || dispel_immune)
- {
- //Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
- Unit::AuraApplicationMap const& auras = m_caster->GetAppliedAuras();
- for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- {
- Aura const* aura = itr->second->GetBase();
- SpellInfo const* auraInfo = aura->GetSpellInfo();
- if (auraInfo->GetAllEffectsMechanicMask() & mechanic_immune)
- continue;
- if (auraInfo->GetSchoolMask() & school_immune && !auraInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE))
- continue;
- if (auraInfo->GetDispelMask() & dispel_immune)
- continue;
+ SpellInfo const* auraInfo = aurEff->GetSpellInfo();
+ if (m_spellInfo->CanSpellCastOverrideAuraEffect(auraInfo, aurEff->GetEffIndex()))
+ continue;
- //Make a second check for spell failed so the right SPELL_FAILED message is returned.
- //That is needed when your casting is prevented by multiple states and you are only immune to some of them.
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
- if (AuraEffect* part = aura->GetEffect(i))
- {
- switch (part->GetAuraType())
- {
- case SPELL_AURA_MOD_STUN:
- if (!usableInStun || !(auraInfo->GetAllEffectsMechanicMask() & (1<<MECHANIC_STUN)))
- return SPELL_FAILED_STUNNED;
- break;
- case SPELL_AURA_MOD_CONFUSE:
- if (!m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED))
- return SPELL_FAILED_CONFUSED;
- break;
- case SPELL_AURA_MOD_FEAR:
- if (!m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED))
- return SPELL_FAILED_FLEEING;
- break;
- case SPELL_AURA_MOD_SILENCE:
- case SPELL_AURA_MOD_PACIFY:
- case SPELL_AURA_MOD_PACIFY_SILENCE:
- if (m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY)
- return SPELL_FAILED_PACIFIED;
- else if (m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
- return SPELL_FAILED_SILENCED;
- break;
- default: break;
- }
- }
- }
- }
+ if (param1)
+ {
+ *param1 = auraInfo->Effects[aurEff->GetEffIndex()].Mechanic;
+ if (!*param1)
+ *param1 = auraInfo->Mechanic;
}
- // You are prevented from casting and the spell cast does not grant immunity. Return a failed error.
- else
- return prevented_reason;
+ return true;
}
- return SPELL_CAST_OK;
+
+ return false;
+}
+
+bool Spell::CheckCasterNotImmunedCharmAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_CHARM, param1) ||
+ CheckCasterHasNotImmunedAuraType(SPELL_AURA_AOE_CHARM, param1) ||
+ CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_POSSESS, param1);
+}
+
+bool Spell::CheckCasterNotImmunedStunAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_STUN, param1);
+}
+
+bool Spell::CheckCasterNotImmunedSilenceAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_SILENCE, param1) ||
+ CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_PACIFY_SILENCE, param1);
+}
+
+bool Spell::CheckCasterNotImmunedPacifyAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_PACIFY, param1) ||
+ CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_PACIFY_SILENCE, param1);
+}
+
+bool Spell::CheckCasterNotImmunedFearAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_FEAR, param1);
+}
+
+bool Spell::CheckCasterNotImmunedDisorientAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_CONFUSE, param1);
}
bool Spell::CanAutoCast(Unit* target)
@@ -5803,7 +5918,7 @@ bool Spell::CanAutoCast(Unit* target)
return false;
}
-SpellCastResult Spell::CheckRange(bool strict)
+SpellCastResult Spell::CheckRange(bool strict) const
{
// Don't check for instant cast spells
if (!strict && m_casttime == 0)
@@ -5833,20 +5948,20 @@ SpellCastResult Spell::CheckRange(bool strict)
if (m_targets.HasDst() && !m_targets.HasTraj())
{
if (m_caster->GetExactDistSq(m_targets.GetDstPos()) > maxRange)
- return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT;
+ return SPELL_FAILED_OUT_OF_RANGE;
if (minRange > 0.0f && m_caster->GetExactDistSq(m_targets.GetDstPos()) < minRange)
- return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT;
+ return SPELL_FAILED_OUT_OF_RANGE;
}
return SPELL_CAST_OK;
}
-std::pair<float, float> Spell::GetMinMaxRange(bool strict)
+std::pair<float, float> Spell::GetMinMaxRange(bool strict) const
{
float rangeMod = 0.0f;
float minRange = 0.0f;
float maxRange = 0.0f;
- if (strict && IsNextMeleeSwingSpell())
+ if (strict && m_spellInfo->IsNextMeleeSwingSpell())
{
maxRange = 100.0f;
return std::pair<float, float>(minRange, maxRange);
@@ -5888,14 +6003,14 @@ std::pair<float, float> Spell::GetMinMaxRange(bool strict)
maxRange *= ranged->GetTemplate()->RangedModRange * 0.01f;
if (Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, maxRange, this);
+ modOwner->ApplySpellMod<SPELLMOD_RANGE>(m_spellInfo->Id, maxRange, const_cast<Spell*>(this));
maxRange += rangeMod;
return std::pair<float, float>(minRange, maxRange);
}
-SpellCastResult Spell::CheckPower()
+SpellCastResult Spell::CheckPower() const
{
// item cast not used power
if (m_CastItem)
@@ -5931,12 +6046,15 @@ SpellCastResult Spell::CheckPower()
return SPELL_CAST_OK;
}
-SpellCastResult Spell::CheckItems()
+SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) const
{
Player* player = m_caster->ToPlayer();
if (!player)
return SPELL_CAST_OK;
+ if (m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_ITEM_CHECK))
+ return SPELL_CAST_OK;
+
if (!m_CastItem)
{
if (m_castItemGUID)
@@ -6012,10 +6130,11 @@ SpellCastResult Spell::CheckItems()
// check target item
if (m_targets.GetItemTargetGUID())
{
- if (!m_targets.GetItemTarget())
+ Item* item = m_targets.GetItemTarget();
+ if (!item)
return SPELL_FAILED_ITEM_GONE;
- if (!m_targets.GetItemTarget()->IsFitToSpellRequirements(m_spellInfo))
+ if (!item->IsFitToSpellRequirements(m_spellInfo))
return SPELL_FAILED_EQUIPPED_ITEM_CLASS;
}
// if not item target then required item must be equipped
@@ -6027,7 +6146,7 @@ SpellCastResult Spell::CheckItems()
}
// do not take reagents for these item casts
- if (!(m_CastItem && m_CastItem->GetTemplate()->Flags & ITEM_PROTO_FLAG_TRIGGERED_CAST))
+ if (!(m_CastItem && m_CastItem->GetTemplate()->Flags & ITEM_FLAG_NO_REAGENT_COST))
{
bool checkReagents = !(_triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST) && !player->CanNoReagentCast(m_spellInfo);
// Not own traded item (in trader trade slot) requires reagents even if triggered spell
@@ -6065,7 +6184,11 @@ SpellCastResult Spell::CheckItems()
}
}
if (!player->HasItemCount(itemid, itemcount))
+ {
+ if (param1)
+ *param1 = itemid;
return SPELL_FAILED_REAGENTS;
+ }
}
}
@@ -6149,7 +6272,7 @@ SpellCastResult Spell::CheckItems()
if (m_targets.GetItemTarget()->GetOwner() != m_caster)
return SPELL_FAILED_NOT_TRADEABLE;
// do not allow to enchant vellum from scroll made by vellum-prevent exploit
- if (m_CastItem && m_CastItem->GetTemplate()->Flags & ITEM_PROTO_FLAG_TRIGGERED_CAST)
+ if (m_CastItem && m_CastItem->GetTemplate()->Flags & ITEM_FLAG_NO_REAGENT_COST)
return SPELL_FAILED_TOTEM_CATEGORY;
ItemPosCountVec dest;
InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->Effects[i].ItemType, 1);
@@ -6269,21 +6392,29 @@ SpellCastResult Spell::CheckItems()
}
case SPELL_EFFECT_PROSPECTING:
{
- if (!m_targets.GetItemTarget())
+ Item* item = m_targets.GetItemTarget();
+ if (!item)
return SPELL_FAILED_CANT_BE_PROSPECTED;
//ensure item is a prospectable ore
- if (!(m_targets.GetItemTarget()->GetTemplate()->Flags & ITEM_PROTO_FLAG_PROSPECTABLE))
+ if (!(item->GetTemplate()->Flags & ITEM_FLAG_IS_PROSPECTABLE))
return SPELL_FAILED_CANT_BE_PROSPECTED;
//prevent prospecting in trade slot
- if (m_targets.GetItemTarget()->GetOwnerGUID() != m_caster->GetGUID())
+ if (item->GetOwnerGUID() != m_caster->GetGUID())
return SPELL_FAILED_CANT_BE_PROSPECTED;
//Check for enough skill in jewelcrafting
- uint32 item_prospectingskilllevel = m_targets.GetItemTarget()->GetTemplate()->RequiredSkillRank;
- if (item_prospectingskilllevel >player->GetSkillValue(SKILL_JEWELCRAFTING))
+ uint32 item_prospectingskilllevel = item->GetTemplate()->RequiredSkillRank;
+ if (item_prospectingskilllevel > player->GetSkillValue(SKILL_JEWELCRAFTING))
return SPELL_FAILED_LOW_CASTLEVEL;
//make sure the player has the required ores in inventory
- if (m_targets.GetItemTarget()->GetCount() < 5)
+ if (item->GetCount() < 5)
+ {
+ if (param1 && param2)
+ {
+ *param1 = item->GetEntry();
+ *param2 = 5;
+ }
return SPELL_FAILED_NEED_MORE_ITEMS;
+ }
if (!LootTemplates_Prospecting.HaveLootFor(m_targets.GetItemTargetEntry()))
return SPELL_FAILED_CANT_BE_PROSPECTED;
@@ -6292,21 +6423,29 @@ SpellCastResult Spell::CheckItems()
}
case SPELL_EFFECT_MILLING:
{
- if (!m_targets.GetItemTarget())
+ Item* item = m_targets.GetItemTarget();
+ if (!item)
return SPELL_FAILED_CANT_BE_MILLED;
//ensure item is a millable herb
- if (!(m_targets.GetItemTarget()->GetTemplate()->Flags & ITEM_PROTO_FLAG_MILLABLE))
+ if (!(item->GetTemplate()->Flags & ITEM_FLAG_IS_MILLABLE))
return SPELL_FAILED_CANT_BE_MILLED;
//prevent milling in trade slot
- if (m_targets.GetItemTarget()->GetOwnerGUID() != m_caster->GetGUID())
+ if (item->GetOwnerGUID() != m_caster->GetGUID())
return SPELL_FAILED_CANT_BE_MILLED;
//Check for enough skill in inscription
- uint32 item_millingskilllevel = m_targets.GetItemTarget()->GetTemplate()->RequiredSkillRank;
+ uint32 item_millingskilllevel = item->GetTemplate()->RequiredSkillRank;
if (item_millingskilllevel > player->GetSkillValue(SKILL_INSCRIPTION))
return SPELL_FAILED_LOW_CASTLEVEL;
//make sure the player has the required herbs in inventory
- if (m_targets.GetItemTarget()->GetCount() < 5)
+ if (item->GetCount() < 5)
+ {
+ if (param1 && param2)
+ {
+ *param1 = item->GetEntry();
+ *param2 = 5;
+ }
return SPELL_FAILED_NEED_MORE_ITEMS;
+ }
if (!LootTemplates_Milling.HaveLootFor(m_targets.GetItemTargetEntry()))
return SPELL_FAILED_CANT_BE_MILLED;
@@ -6457,7 +6596,7 @@ void Spell::Delayed() // only called in DealDamage()
//check pushback reduce
int32 delaytime = 500; // spellcasting delay is normally 500ms
int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
- m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
+ m_caster->ToPlayer()->ApplySpellMod<SPELLMOD_NOT_LOSE_CASTING_TIME>(m_spellInfo->Id, delayReduce, this);
delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
if (delayReduce >= 100)
return;
@@ -6495,7 +6634,7 @@ void Spell::DelayedChannel()
int32 delaytime = CalculatePct(duration, 25); // channeling delay is normally 25% of its time per hit
int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
- m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
+ m_caster->ToPlayer()->ApplySpellMod<SPELLMOD_NOT_LOSE_CASTING_TIME>(m_spellInfo->Id, delayReduce, this);
delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
if (delayReduce >= 100)
return;
@@ -6578,14 +6717,14 @@ bool Spell::UpdatePointers()
CurrentSpellTypes Spell::GetCurrentContainer() const
{
- if (IsNextMeleeSwingSpell())
- return(CURRENT_MELEE_SPELL);
+ if (m_spellInfo->IsNextMeleeSwingSpell())
+ return CURRENT_MELEE_SPELL;
else if (IsAutoRepeat())
- return(CURRENT_AUTOREPEAT_SPELL);
+ return CURRENT_AUTOREPEAT_SPELL;
else if (m_spellInfo->IsChanneled())
- return(CURRENT_CHANNELED_SPELL);
- else
- return(CURRENT_GENERIC_SPELL);
+ return CURRENT_CHANNELED_SPELL;
+
+ return CURRENT_GENERIC_SPELL;
}
bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* losPosition) const
@@ -6664,15 +6803,16 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* lo
return true;
}
-bool Spell::IsNextMeleeSwingSpell() const
-{
- return m_spellInfo->HasAttribute(SPELL_ATTR0_ON_NEXT_SWING);
-}
-
bool Spell::IsAutoActionResetSpell() const
{
/// @todo changed SPELL_INTERRUPT_FLAG_AUTOATTACK -> SPELL_INTERRUPT_FLAG_INTERRUPT to fix compile - is this check correct at all?
- return !IsTriggered() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT);
+ if (IsTriggered() || !(m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT))
+ return false;
+
+ if (!m_casttime && m_spellInfo->HasAttribute(SPELL_ATTR6_NOT_RESET_SWING_IF_INSTANT))
+ return false;
+
+ return true;
}
bool Spell::IsNeedSendToClient() const
@@ -6850,9 +6990,11 @@ void Spell::HandleLaunchPhase()
for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
{
if ((*j)->IsAffectedOnSpell(m_spellInfo))
- usesAmmo=false;
+ usesAmmo = false;
}
+ PrepareTargetProcessing();
+
for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
{
TargetInfo& target = *ihit;
@@ -6886,8 +7028,11 @@ void Spell::HandleLaunchPhase()
break;
}
}
+
DoAllEffectOnLaunchTarget(target, multiplier);
}
+
+ FinishTargetProcessing();
}
void Spell::DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier)
@@ -7035,7 +7180,7 @@ void Spell::SetSpellValue(SpellValueMod mod, int32 value)
void Spell::PrepareTargetProcessing()
{
- CheckEffectExecuteData();
+ AssertEffectExecuteData();
}
void Spell::FinishTargetProcessing()
@@ -7060,7 +7205,7 @@ void Spell::InitEffectExecuteData(uint8 effIndex)
}
}
-void Spell::CheckEffectExecuteData()
+void Spell::AssertEffectExecuteData() const
{
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
ASSERT(!m_effectExecuteData[i]);
@@ -7068,29 +7213,20 @@ void Spell::CheckEffectExecuteData()
void Spell::LoadScripts()
{
- sScriptMgr->CreateSpellScripts(m_spellInfo->Id, m_loadedScripts);
- for (std::list<SpellScript*>::iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end();)
+ sScriptMgr->CreateSpellScripts(m_spellInfo->Id, m_loadedScripts, this);
+ for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
{
- if (!(*itr)->_Load(this))
- {
- std::list<SpellScript*>::iterator bitr = itr;
- ++itr;
- delete (*bitr);
- m_loadedScripts.erase(bitr);
- continue;
- }
TC_LOG_DEBUG("spells", "Spell::LoadScripts: Script `%s` for spell `%u` is loaded now", (*itr)->_GetScriptName()->c_str(), m_spellInfo->Id);
(*itr)->Register();
- ++itr;
}
}
void Spell::CallScriptBeforeCastHandlers()
{
- for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_CAST);
- std::list<SpellScript::CastHandler>::iterator hookItrEnd = (*scritr)->BeforeCast.end(), hookItr = (*scritr)->BeforeCast.begin();
+ auto hookItrEnd = (*scritr)->BeforeCast.end(), hookItr = (*scritr)->BeforeCast.begin();
for (; hookItr != hookItrEnd; ++hookItr)
(*hookItr).Call(*scritr);
@@ -7100,10 +7236,10 @@ void Spell::CallScriptBeforeCastHandlers()
void Spell::CallScriptOnCastHandlers()
{
- for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_CAST);
- std::list<SpellScript::CastHandler>::iterator hookItrEnd = (*scritr)->OnCast.end(), hookItr = (*scritr)->OnCast.begin();
+ auto hookItrEnd = (*scritr)->OnCast.end(), hookItr = (*scritr)->OnCast.begin();
for (; hookItr != hookItrEnd; ++hookItr)
(*hookItr).Call(*scritr);
@@ -7113,10 +7249,10 @@ void Spell::CallScriptOnCastHandlers()
void Spell::CallScriptAfterCastHandlers()
{
- for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_CAST);
- std::list<SpellScript::CastHandler>::iterator hookItrEnd = (*scritr)->AfterCast.end(), hookItr = (*scritr)->AfterCast.begin();
+ auto hookItrEnd = (*scritr)->AfterCast.end(), hookItr = (*scritr)->AfterCast.begin();
for (; hookItr != hookItrEnd; ++hookItr)
(*hookItr).Call(*scritr);
@@ -7127,10 +7263,10 @@ void Spell::CallScriptAfterCastHandlers()
SpellCastResult Spell::CallScriptCheckCastHandlers()
{
SpellCastResult retVal = SPELL_CAST_OK;
- for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CHECK_CAST);
- std::list<SpellScript::CheckCastHandler>::iterator hookItrEnd = (*scritr)->OnCheckCast.end(), hookItr = (*scritr)->OnCheckCast.begin();
+ auto hookItrEnd = (*scritr)->OnCheckCast.end(), hookItr = (*scritr)->OnCheckCast.begin();
for (; hookItr != hookItrEnd; ++hookItr)
{
SpellCastResult tempResult = (*hookItr).Call(*scritr);
@@ -7145,7 +7281,7 @@ SpellCastResult Spell::CallScriptCheckCastHandlers()
void Spell::PrepareScriptHitHandlers()
{
- for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
(*scritr)->_InitHit();
}
@@ -7153,9 +7289,9 @@ bool Spell::CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMo
{
// execute script effect handler hooks and check if effects was prevented
bool preventDefault = false;
- for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
- std::list<SpellScript::EffectHandler>::iterator effItr, effEndItr;
+ HookList<SpellScript::EffectHandler>::iterator effItr, effEndItr;
SpellScriptHookType hookType;
switch (mode)
{
@@ -7199,10 +7335,10 @@ bool Spell::CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMo
void Spell::CallScriptSuccessfulDispel(SpellEffIndex effIndex)
{
- for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_EFFECT_SUCCESSFUL_DISPEL);
- std::list<SpellScript::EffectHandler>::iterator hookItrEnd = (*scritr)->OnEffectSuccessfulDispel.end(), hookItr = (*scritr)->OnEffectSuccessfulDispel.begin();
+ auto hookItrEnd = (*scritr)->OnEffectSuccessfulDispel.end(), hookItr = (*scritr)->OnEffectSuccessfulDispel.begin();
for (; hookItr != hookItrEnd; ++hookItr)
hookItr->Call(*scritr, effIndex);
@@ -7212,10 +7348,10 @@ void Spell::CallScriptSuccessfulDispel(SpellEffIndex effIndex)
void Spell::CallScriptBeforeHitHandlers()
{
- for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_HIT);
- std::list<SpellScript::HitHandler>::iterator hookItrEnd = (*scritr)->BeforeHit.end(), hookItr = (*scritr)->BeforeHit.begin();
+ auto hookItrEnd = (*scritr)->BeforeHit.end(), hookItr = (*scritr)->BeforeHit.begin();
for (; hookItr != hookItrEnd; ++hookItr)
(*hookItr).Call(*scritr);
@@ -7225,10 +7361,10 @@ void Spell::CallScriptBeforeHitHandlers()
void Spell::CallScriptOnHitHandlers()
{
- for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_HIT);
- std::list<SpellScript::HitHandler>::iterator hookItrEnd = (*scritr)->OnHit.end(), hookItr = (*scritr)->OnHit.begin();
+ auto hookItrEnd = (*scritr)->OnHit.end(), hookItr = (*scritr)->OnHit.begin();
for (; hookItr != hookItrEnd; ++hookItr)
(*hookItr).Call(*scritr);
@@ -7238,10 +7374,10 @@ void Spell::CallScriptOnHitHandlers()
void Spell::CallScriptAfterHitHandlers()
{
- for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_HIT);
- std::list<SpellScript::HitHandler>::iterator hookItrEnd = (*scritr)->AfterHit.end(), hookItr = (*scritr)->AfterHit.begin();
+ auto hookItrEnd = (*scritr)->AfterHit.end(), hookItr = (*scritr)->AfterHit.begin();
for (; hookItr != hookItrEnd; ++hookItr)
(*hookItr).Call(*scritr);
@@ -7251,10 +7387,10 @@ void Spell::CallScriptAfterHitHandlers()
void Spell::CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
{
- for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_AREA_TARGET_SELECT);
- std::list<SpellScript::ObjectAreaTargetSelectHandler>::iterator hookItrEnd = (*scritr)->OnObjectAreaTargetSelect.end(), hookItr = (*scritr)->OnObjectAreaTargetSelect.begin();
+ auto hookItrEnd = (*scritr)->OnObjectAreaTargetSelect.end(), hookItr = (*scritr)->OnObjectAreaTargetSelect.begin();
for (; hookItr != hookItrEnd; ++hookItr)
if (hookItr->IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == hookItr->GetTarget())
hookItr->Call(*scritr, targets);
@@ -7265,10 +7401,10 @@ void Spell::CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& ta
void Spell::CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
{
- for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT);
- std::list<SpellScript::ObjectTargetSelectHandler>::iterator hookItrEnd = (*scritr)->OnObjectTargetSelect.end(), hookItr = (*scritr)->OnObjectTargetSelect.begin();
+ auto hookItrEnd = (*scritr)->OnObjectTargetSelect.end(), hookItr = (*scritr)->OnObjectTargetSelect.begin();
for (; hookItr != hookItrEnd; ++hookItr)
if (hookItr->IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == hookItr->GetTarget())
hookItr->Call(*scritr, target);
@@ -7279,10 +7415,10 @@ void Spell::CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffI
void Spell::CallScriptDestinationTargetSelectHandlers(SpellDestination& target, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
{
- for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_DESTINATION_TARGET_SELECT);
- std::list<SpellScript::DestinationTargetSelectHandler>::iterator hookItrEnd = (*scritr)->OnDestinationTargetSelect.end(), hookItr = (*scritr)->OnDestinationTargetSelect.begin();
+ auto hookItrEnd = (*scritr)->OnDestinationTargetSelect.end(), hookItr = (*scritr)->OnDestinationTargetSelect.begin();
for (; hookItr != hookItrEnd; ++hookItr)
if (hookItr->IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == hookItr->GetTarget())
hookItr->Call(*scritr, target);
@@ -7297,15 +7433,15 @@ bool Spell::CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToC
if (m_loadedScripts.empty())
return true;
- for (std::list<SpellScript*>::iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
+ for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
{
- std::list<SpellScript::ObjectTargetSelectHandler>::iterator targetSelectHookEnd = (*itr)->OnObjectTargetSelect.end(), targetSelectHookItr = (*itr)->OnObjectTargetSelect.begin();
+ auto targetSelectHookEnd = (*itr)->OnObjectTargetSelect.end(), targetSelectHookItr = (*itr)->OnObjectTargetSelect.begin();
for (; targetSelectHookItr != targetSelectHookEnd; ++targetSelectHookItr)
if (((*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && !(*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck)) ||
(!(*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && (*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck)))
return false;
- std::list<SpellScript::ObjectAreaTargetSelectHandler>::iterator areaTargetSelectHookEnd = (*itr)->OnObjectAreaTargetSelect.end(), areaTargetSelectHookItr = (*itr)->OnObjectAreaTargetSelect.begin();
+ auto areaTargetSelectHookEnd = (*itr)->OnObjectAreaTargetSelect.end(), areaTargetSelectHookItr = (*itr)->OnObjectAreaTargetSelect.begin();
for (; areaTargetSelectHookItr != areaTargetSelectHookEnd; ++areaTargetSelectHookItr)
if (((*areaTargetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && !(*areaTargetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck)) ||
(!(*areaTargetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && (*areaTargetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck)))
@@ -7355,25 +7491,24 @@ void Spell::PrepareTriggersExecutedOnHit()
// save auras which were present on spell caster on cast, to prevent triggered auras from affecting caster
// and to correctly calculate proc chance when combopoints are present
Unit::AuraEffectList const& targetTriggers = m_caster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER);
- for (Unit::AuraEffectList::const_iterator i = targetTriggers.begin(); i != targetTriggers.end(); ++i)
+ for (AuraEffect const* aurEff : targetTriggers)
{
- if (!(*i)->IsAffectedOnSpell(m_spellInfo))
+ if (!aurEff->IsAffectedOnSpell(m_spellInfo))
continue;
- SpellInfo const* auraSpellInfo = (*i)->GetSpellInfo();
- uint32 auraSpellIdx = (*i)->GetEffIndex();
+
+ SpellInfo const* auraSpellInfo = aurEff->GetSpellInfo();
+ uint32 auraSpellIdx = aurEff->GetEffIndex();
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(auraSpellInfo->Effects[auraSpellIdx].TriggerSpell))
{
// calculate the chance using spell base amount, because aura amount is not updated on combo-points change
// this possibly needs fixing
- int32 auraBaseAmount = (*i)->GetBaseAmount();
+ int32 auraBaseAmount = aurEff->GetBaseAmount();
// proc chance is stored in effect amount
- int32 chance = m_caster->CalculateSpellDamage(NULL, auraSpellInfo, auraSpellIdx, &auraBaseAmount);
+ int32 chance = m_caster->CalculateSpellDamage(nullptr, auraSpellInfo, auraSpellIdx, &auraBaseAmount);
+ chance *= aurEff->GetBase()->GetStackAmount();
+
// build trigger and add to the list
- HitTriggerSpell spellTriggerInfo;
- spellTriggerInfo.triggeredSpell = spellInfo;
- spellTriggerInfo.triggeredByAura = auraSpellInfo;
- spellTriggerInfo.chance = chance * (*i)->GetBase()->GetStackAmount();
- m_hitTriggerSpells.push_back(spellTriggerInfo);
+ m_hitTriggerSpells.emplace_back(spellInfo, auraSpellInfo, chance);
}
}
}
@@ -7414,15 +7549,12 @@ void Spell::TriggerGlobalCooldown()
if (m_spellInfo->StartRecoveryTime >= MIN_GCD && m_spellInfo->StartRecoveryTime <= MAX_GCD)
{
// gcd modifier auras are applied only to own spells and only players have such mods
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_GLOBAL_COOLDOWN, gcd, this);
+ if (Player* modOwner = m_caster->GetSpellModOwner())
+ modOwner->ApplySpellMod<SPELLMOD_GLOBAL_COOLDOWN>(m_spellInfo->Id, gcd, this);
// Apply haste rating
gcd = int32(float(gcd) * m_caster->GetFloatValue(UNIT_MOD_CAST_SPEED));
- if (gcd < MIN_GCD)
- gcd = MIN_GCD;
- else if (gcd > MAX_GCD)
- gcd = MAX_GCD;
+ RoundToInterval<int32>(gcd, MIN_GCD, MAX_GCD);
}
m_caster->GetSpellHistory()->AddGlobalCooldown(m_spellInfo, gcd);
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 016af275141..aa3b6ca358a 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -352,7 +352,7 @@ class TC_GAME_API Spell
void EffectCastButtons(SpellEffIndex effIndex);
void EffectRechargeManaGem(SpellEffIndex effIndex);
- typedef std::set<Aura*> UsedSpellMods;
+ typedef std::unordered_set<Aura*> UsedSpellMods;
Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID = ObjectGuid::Empty, bool skipCheck = false);
~Spell();
@@ -397,7 +397,7 @@ class TC_GAME_API Spell
void TakeReagents();
void TakeCastItem();
- SpellCastResult CheckCast(bool strict);
+ SpellCastResult CheckCast(bool strict, uint32* param1 = nullptr, uint32* param2 = nullptr);
SpellCastResult CheckPetCast(Unit* target);
// handlers
@@ -407,11 +407,19 @@ class TC_GAME_API Spell
void _handle_immediate_phase();
void _handle_finish_phase();
- SpellCastResult CheckItems();
- SpellCastResult CheckRange(bool strict);
- SpellCastResult CheckPower();
- SpellCastResult CheckRuneCost(uint32 runeCostID);
- SpellCastResult CheckCasterAuras() const;
+ SpellCastResult CheckItems(uint32* param1, uint32* param2) const;
+ SpellCastResult CheckRange(bool strict) const;
+ SpellCastResult CheckPower() const;
+ SpellCastResult CheckRuneCost(uint32 runeCostID) const;
+ SpellCastResult CheckCasterAuras(uint32* param1) const;
+
+ bool CheckCasterHasNotImmunedAuraType(AuraType auraType, uint32* param1) const;
+ bool CheckCasterNotImmunedCharmAuras(uint32* param1) const;
+ bool CheckCasterNotImmunedStunAuras(uint32* param1) const;
+ bool CheckCasterNotImmunedSilenceAuras(uint32* param1) const;
+ bool CheckCasterNotImmunedPacifyAuras(uint32* param1) const;
+ bool CheckCasterNotImmunedFearAuras(uint32* param1) const;
+ bool CheckCasterNotImmunedDisorientAuras(uint32* param1) const;
int32 CalculateDamage(uint8 i, Unit const* target) const { return m_caster->CalculateSpellDamage(target, m_spellInfo, i, &m_spellValue->EffectBasePoints[i]); }
@@ -430,9 +438,9 @@ class TC_GAME_API Spell
void CheckSrc() { if (!m_targets.HasSrc()) m_targets.SetSrc(*m_caster); }
void CheckDst() { if (!m_targets.HasDst()) m_targets.SetDst(*m_caster); }
- static void WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError);
- static void SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE);
- void SendCastResult(SpellCastResult result);
+ static void WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError, uint32* param1 = nullptr, uint32* param2 = nullptr);
+ static void SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE, uint32* param1 = nullptr, uint32* param2 = nullptr);
+ void SendCastResult(SpellCastResult result, uint32* param1 = nullptr, uint32* param2 = nullptr) const;
void SendPetCastResult(SpellCastResult result);
void SendSpellStart();
void SendSpellGo();
@@ -473,12 +481,14 @@ class TC_GAME_API Spell
bool IsAutoRepeat() const { return m_autoRepeat; }
void SetAutoRepeat(bool rep) { m_autoRepeat = rep; }
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 IsProcDisabled() const { return (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS) != 0; }
bool IsChannelActive() const { return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0; }
bool IsAutoActionResetSpell() const;
+ bool IsTriggeredByAura(SpellInfo const* auraSpellInfo) const { return (auraSpellInfo == m_triggeredByAuraSpell); }
+
bool IsDeletable() const { return !m_referencedFromCurrentSpell && !m_executedCurrently; }
void SetReferencedFromCurrent(bool yes) { m_referencedFromCurrentSpell = yes; }
bool IsInterruptable() const { return !m_executedCurrently; }
@@ -507,7 +517,7 @@ class TC_GAME_API Spell
void CancelGlobalCooldown();
void SendLoot(ObjectGuid guid, LootType loottype);
- std::pair<float, float> GetMinMaxRange(bool strict);
+ std::pair<float, float> GetMinMaxRange(bool strict) const;
Unit* const m_caster;
@@ -561,10 +571,6 @@ class TC_GAME_API Spell
// used in effects handlers
Aura* m_spellAura;
- // this is set in Spell Hit, but used in Apply Aura handler
- DiminishingLevels m_diminishLevel;
- DiminishingGroup m_diminishGroup;
-
// -------------------------------------------
GameObject* focusObject;
@@ -577,8 +583,8 @@ class TC_GAME_API Spell
// ******************************************
uint32 m_procAttacker; // Attacker trigger flags
uint32 m_procVictim; // Victim trigger flags
- uint32 m_procEx;
- void prepareDataForTriggerSystem(AuraEffect const* triggeredByAura);
+ uint32 m_hitMask;
+ void prepareDataForTriggerSystem();
// *****************************************
// Spell target subsystem
@@ -640,7 +646,7 @@ class TC_GAME_API Spell
// spell execution log
void InitEffectExecuteData(uint8 effIndex);
- void CheckEffectExecuteData();
+ void AssertEffectExecuteData() const;
// Scripting system
void LoadScripts();
@@ -658,10 +664,13 @@ class TC_GAME_API Spell
void CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType);
void CallScriptDestinationTargetSelectHandlers(SpellDestination& target, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType);
bool CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToCheck);
- std::list<SpellScript*> m_loadedScripts;
+ std::vector<SpellScript*> m_loadedScripts;
struct HitTriggerSpell
{
+ HitTriggerSpell(SpellInfo const* spellInfo, SpellInfo const* auraSpellInfo, int32 procChance) :
+ triggeredSpell(spellInfo), triggeredByAura(auraSpellInfo), chance(procChance) { }
+
SpellInfo const* triggeredSpell;
SpellInfo const* triggeredByAura;
// uint8 triggeredByEffIdx This might be needed at a later stage - No need known for now
@@ -670,7 +679,7 @@ class TC_GAME_API Spell
bool CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura = NULL) const;
void PrepareTriggersExecutedOnHit();
- typedef std::list<HitTriggerSpell> HitTriggerSpellList;
+ typedef std::vector<HitTriggerSpell> HitTriggerSpellList;
HitTriggerSpellList m_hitTriggerSpells;
// effect helpers
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index d8feaf22c6f..7afcf52172a 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -292,14 +292,18 @@ void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/)
if (!unitTarget || !unitTarget->IsAlive())
return;
- uint32 absorb = 0;
- uint32 resist = 0;
-
- m_caster->CalcAbsorbResist(unitTarget, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist, m_spellInfo);
-
- m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_spellInfo->GetSchoolMask(), absorb, resist, false, 0, false);
+ // CalcAbsorbResist already in Player::EnvironmentalDamage
if (unitTarget->GetTypeId() == TYPEID_PLAYER)
unitTarget->ToPlayer()->EnvironmentalDamage(DAMAGE_FIRE, damage);
+ else
+ {
+ DamageInfo damageInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK);
+ m_caster->CalcAbsorbResist(damageInfo);
+
+ uint32 absorb = damageInfo.GetAbsorb();
+ uint32 resist = damageInfo.GetResist();
+ m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_spellInfo->GetSchoolMask(), absorb, resist, false, 0, false);
+ }
}
void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
@@ -395,9 +399,9 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
// Conflagrate - consumes Immolate or Shadowflame
else if (m_spellInfo->TargetAuraState == AURA_STATE_CONFLAGRATE)
{
- AuraEffect const* aura = NULL; // found req. aura for damage calculation
+ AuraEffect const* aura = nullptr; // found req. aura for damage calculation
- Unit::AuraEffectList const &mPeriodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE);
+ Unit::AuraEffectList const& mPeriodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE);
for (Unit::AuraEffectList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i)
{
// for caster applied auras only
@@ -420,15 +424,22 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
// found Immolate or Shadowflame
if (aura)
{
- uint32 pdamage = uint32(std::max(aura->GetAmount(), 0));
- pdamage = m_caster->SpellDamageBonusDone(unitTarget, aura->GetSpellInfo(), pdamage, DOT, aura->GetBase()->GetStackAmount());
- pdamage = unitTarget->SpellDamageBonusTaken(m_caster, aura->GetSpellInfo(), pdamage, DOT, aura->GetBase()->GetStackAmount());
- uint32 pct_dir = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, (effIndex + 1));
- uint8 baseTotalTicks = uint8(m_caster->CalcSpellDuration(aura->GetSpellInfo()) / aura->GetSpellInfo()->Effects[EFFECT_0].Amplitude);
- damage += int32(CalculatePct(pdamage * baseTotalTicks, pct_dir));
+ // Calculate damage of Immolate/Shadowflame tick
+ int32 pdamage = (aura->GetAmount() + aura->GetBonusAmount()) * aura->GetDonePct();
+ if (Player* modOwner = m_caster->GetSpellModOwner())
+ modOwner->ApplySpellMod<SPELLMOD_DOT>(GetSpellInfo()->Id, pdamage);
+
+ pdamage = unitTarget->SpellDamageBonusTaken(m_caster, aura->GetSpellInfo(), pdamage, DOT);
+
+ // And multiply by amount of ticks to get damage potential
+ pdamage *= aura->GetSpellInfo()->GetMaxTicks();
- uint32 pct_dot = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, (effIndex + 2)) / 3;
- m_spellValue->EffectBasePoints[1] = m_spellInfo->Effects[EFFECT_1].CalcBaseValue(int32(CalculatePct(pdamage * baseTotalTicks, pct_dot)));
+ int32 pct_dir = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, EFFECT_1);
+ damage += CalculatePct(pdamage, pct_dir);
+
+ int32 pct_dot = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, EFFECT_2);
+ int32 const dotBasePoints = CalculatePct(pdamage, pct_dot);
+ m_spellValue->EffectBasePoints[EFFECT_1] = dotBasePoints / m_spellInfo->GetMaxTicks();
apply_direct_bonus = false;
// Glyph of Conflagrate
@@ -1393,9 +1404,12 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/)
return;
}
- int32 tickheal = targetAura->GetAmount();
- if (Unit* auraCaster = targetAura->GetCaster())
- tickheal = auraCaster->SpellHealingBonusDone(unitTarget, targetAura->GetSpellInfo(), tickheal, DOT);
+ int32 tickheal = (targetAura->GetAmount() + targetAura->GetBonusAmount()) * targetAura->GetDonePct();
+ if (Player* modOwner = m_caster->GetSpellModOwner())
+ modOwner->ApplySpellMod<SPELLMOD_DOT>(targetAura->GetId(), tickheal);
+
+ unitTarget->SpellHealingBonusTaken(m_caster, targetAura->GetSpellInfo(), tickheal, DOT);
+
//int32 tickheal = targetAura->GetSpellInfo()->EffectBasePoints[idx] + 1;
//It is said that talent bonus should not be included
@@ -1507,7 +1521,8 @@ void Spell::EffectHealthLeech(SpellEffIndex effIndex)
healthGain = m_caster->SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, HEAL);
healthGain = m_caster->SpellHealingBonusTaken(m_caster, m_spellInfo, healthGain, HEAL);
- m_caster->HealBySpell(m_caster, m_spellInfo, uint32(healthGain));
+ HealInfo healInfo(m_caster, m_caster, healthGain, m_spellInfo, m_spellSchoolMask);
+ m_caster->HealBySpell(healInfo);
}
}
@@ -2022,7 +2037,7 @@ void Spell::EffectOpenLock(SpellEffIndex effIndex)
if (gameObjTarget)
SendLoot(guid, LOOT_SKINNING);
else if (itemTarget)
- itemTarget->SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_UNLOCKED);
+ itemTarget->SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_UNLOCKED);
// not allow use skill grow at item base open
if (!m_CastItem && skillId != SKILL_NONE)
@@ -2102,6 +2117,8 @@ void Spell::EffectSummonChangeItem(SpellEffIndex effIndex)
m_castItemEntry = 0;
player->StoreItem(dest, pNewItem, true);
+ player->SendNewItem(pNewItem, 1, true, false);
+ player->ItemAddedQuestCheck(newitemid, 1);
return;
}
}
@@ -2146,6 +2163,8 @@ void Spell::EffectSummonChangeItem(SpellEffIndex effIndex)
player->EquipItem(dest, pNewItem, true);
player->AutoUnequipOffhandIfNeed();
+ player->SendNewItem(pNewItem, 1, true, false);
+ player->ItemAddedQuestCheck(newitemid, 1);
return;
}
}
@@ -2197,7 +2216,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
int32 duration = m_spellInfo->GetDuration();
if (Player* modOwner = m_originalCaster->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
+ modOwner->ApplySpellMod<SPELLMOD_DURATION>(m_spellInfo->Id, duration);
TempSummon* summon = NULL;
@@ -2685,7 +2704,7 @@ void Spell::EffectEnchantItemPerm(SpellEffIndex effIndex)
else
{
// do not increase skill if vellum used
- if (!(m_CastItem && m_CastItem->GetTemplate()->Flags & ITEM_PROTO_FLAG_TRIGGERED_CAST))
+ if (!(m_CastItem && m_CastItem->GetTemplate()->Flags & ITEM_FLAG_NO_REAGENT_COST))
player->UpdateCraftSkill(m_spellInfo->Id);
uint32 enchant_id = m_spellInfo->Effects[effIndex].MiscValue;
@@ -3361,8 +3380,10 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
}
}
- // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
- if (fixed_bonus || spell_bonus)
+ // if (addPctMods) { percent mods are added in Unit::CalculateDamage } else { percent mods are added in Unit::MeleeDamageBonusDone }
+ // this distinction is neccessary to properly inform the client about his autoattack damage values from Script_UnitDamage
+ bool addPctMods = !m_spellInfo->HasAttribute(SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS) && (m_spellSchoolMask & SPELL_SCHOOL_MASK_NORMAL);
+ if (addPctMods)
{
UnitMods unitMod;
switch (m_attackType)
@@ -3373,17 +3394,14 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
}
- float weapon_total_pct = 1.0f;
- if (m_spellInfo->SchoolMask & SPELL_SCHOOL_MASK_NORMAL)
- weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
-
+ float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
if (fixed_bonus)
fixed_bonus = int32(fixed_bonus * weapon_total_pct);
if (spell_bonus)
spell_bonus = int32(spell_bonus * weapon_total_pct);
}
- int32 weaponDamage = m_caster->CalculateDamage(m_attackType, normalized, true);
+ int32 weaponDamage = m_caster->CalculateDamage(m_attackType, normalized, addPctMods);
// Sequence is important
for (int j = 0; j < MAX_SPELL_EFFECTS; ++j)
@@ -3398,17 +3416,14 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
weaponDamage += fixed_bonus;
break;
case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
- weaponDamage = int32(weaponDamage* weaponDamagePercentMod);
+ weaponDamage = int32(weaponDamage * weaponDamagePercentMod);
default:
break; // not weapon damage effect, just skip
}
}
- if (spell_bonus)
- weaponDamage += spell_bonus;
-
- if (totalDamagePercentMod != 1.0f)
- weaponDamage = int32(weaponDamage* totalDamagePercentMod);
+ weaponDamage += spell_bonus;
+ weaponDamage = int32(weaponDamage * totalDamagePercentMod);
// prevent negative damage
uint32 eff_damage(std::max(weaponDamage, 0));
@@ -3454,7 +3469,7 @@ void Spell::EffectHealMaxHealth(SpellEffIndex /*effIndex*/)
void Spell::EffectInterruptCast(SpellEffIndex effIndex)
{
- if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
+ if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
return;
if (!unitTarget || !unitTarget->IsAlive())
@@ -3530,21 +3545,12 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex)
if (Battleground* bg = player->GetBattleground())
bg->SetDroppedFlagGUID(pGameObj->GetGUID(), player->GetTeam() == ALLIANCE ? TEAM_HORDE: TEAM_ALLIANCE);
- if (uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry())
+ if (GameObject* linkedTrap = pGameObj->GetLinkedTrap())
{
- GameObject* linkedGO = new GameObject();
- if (linkedGO->Create(map->GenerateLowGuid<HighGuid::GameObject>(), linkedEntry, map, m_caster->GetPhaseMask(), Position(x, y, z, target->GetOrientation()), rot, 255, GO_STATE_READY))
- {
- linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
- linkedGO->SetSpellId(m_spellInfo->Id);
-
- ExecuteLogEffectSummonObject(effIndex, linkedGO);
+ linkedTrap->SetRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0);
+ linkedTrap->SetSpellId(m_spellInfo->Id);
- // Wild object not have owner and check clickable by players
- map->AddToMap(linkedGO);
- }
- else
- delete linkedGO;
+ ExecuteLogEffectSummonObject(effIndex, linkedTrap);
}
}
@@ -4578,8 +4584,8 @@ void Spell::EffectQuestComplete(SpellEffIndex effIndex)
uint16 logSlot = player->FindQuestSlot(questId);
if (logSlot < MAX_QUEST_LOG_SIZE)
player->AreaExploredOrEventHappens(questId);
- else if (player->CanTakeQuest(quest, false)) // never rewarded before
- player->CompleteQuest(questId); // quest not in log - for internal use
+ else if (quest->HasFlag(QUEST_FLAGS_TRACKING)) // Check if the quest is used as a serverside flag.
+ player->SetRewardedQuest(questId); // If so, set status to rewarded without broadcasting it to client.
}
}
@@ -4756,7 +4762,7 @@ void Spell::EffectLeapBack(SpellEffIndex effIndex)
float speedxy = m_spellInfo->Effects[effIndex].MiscValue / 10.f;
float speedz = damage/ 10.f;
//1891: Disengage
- m_caster->JumpTo(speedxy, speedz, m_spellInfo->SpellIconID != 1891);
+ unitTarget->JumpTo(speedxy, speedz, m_spellInfo->SpellIconID != 1891);
}
void Spell::EffectQuestClear(SpellEffIndex effIndex)
@@ -5136,26 +5142,14 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex)
cMap->AddToMap(pGameObj);
- if (uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry())
+ if (GameObject* linkedTrap = pGameObj->GetLinkedTrap())
{
- GameObject* linkedGO = new GameObject;
- if (linkedGO->Create(cMap->GenerateLowGuid<HighGuid::GameObject>(), linkedEntry, cMap, m_caster->GetPhaseMask(), pos, rot, 255, GO_STATE_READY))
- {
- linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
- //linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
- linkedGO->SetSpellId(m_spellInfo->Id);
- linkedGO->SetOwnerGUID(m_caster->GetGUID());
+ linkedTrap->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
+ //linkedTrap->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
+ linkedTrap->SetSpellId(m_spellInfo->Id);
+ linkedTrap->SetOwnerGUID(m_caster->GetGUID());
- ExecuteLogEffectSummonObject(effIndex, linkedGO);
-
- linkedGO->GetMap()->AddToMap(linkedGO);
- }
- else
- {
- delete linkedGO;
- linkedGO = NULL;
- return;
- }
+ ExecuteLogEffectSummonObject(effIndex, linkedTrap);
}
}
@@ -5168,7 +5162,7 @@ void Spell::EffectProspecting(SpellEffIndex /*effIndex*/)
if (!player)
return;
- if (!itemTarget || !(itemTarget->GetTemplate()->Flags & ITEM_PROTO_FLAG_PROSPECTABLE))
+ if (!itemTarget || !(itemTarget->GetTemplate()->Flags & ITEM_FLAG_IS_PROSPECTABLE))
return;
if (itemTarget->GetCount() < 5)
@@ -5193,7 +5187,7 @@ void Spell::EffectMilling(SpellEffIndex /*effIndex*/)
if (!player)
return;
- if (!itemTarget || !(itemTarget->GetTemplate()->Flags & ITEM_PROTO_FLAG_MILLABLE))
+ if (!itemTarget || !(itemTarget->GetTemplate()->Flags & ITEM_FLAG_IS_MILLABLE))
return;
if (itemTarget->GetCount() < 5)
@@ -5286,8 +5280,8 @@ void Spell::EffectStealBeneficialBuff(SpellEffIndex effIndex)
// The charges / stack amounts don't count towards the total number of auras that can be dispelled.
// Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
// Polymorph instead of 1 / (5 + 1) -> 16%.
- bool dispel_charges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
- uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount();
+ bool dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
+ uint8 charges = dispelCharges ? aura->GetCharges() : aura->GetStackAmount();
if (charges > 0)
steal_list.push_back(std::make_pair(aura, charges));
}
@@ -5442,18 +5436,8 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
m_runesState = m_caster->ToPlayer()->GetRunesState();
uint32 count = damage;
- if (count == 0) count = 1;
- for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j)
- {
- if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(m_spellInfo->Effects[effIndex].MiscValue))
- {
- if (m_spellInfo->Id == 45529)
- if (player->GetBaseRune(j) != RuneType(m_spellInfo->Effects[effIndex].MiscValueB))
- continue;
- player->SetRuneCooldown(j, 0);
- --count;
- }
- }
+ if (count == 0)
+ count = 1;
// Blood Tap
if (m_spellInfo->Id == 45529 && count > 0)
@@ -5461,11 +5445,12 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
for (uint32 l = 0; l + 1 < MAX_RUNES && count > 0; ++l)
{
// Check if both runes are on cd as that is the only time when this needs to come into effect
- if ((player->GetRuneCooldown(l) && player->GetBaseRune(l) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB)) && (player->GetRuneCooldown(l+1) && player->GetBaseRune(l+1) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB)))
+ if ((player->GetRuneCooldown(l) && player->GetBaseRune(l) == RUNE_BLOOD) && (player->GetRuneCooldown(l + 1) && player->GetBaseRune(l + 1) == RUNE_BLOOD))
{
// Should always update the rune with the lowest cd
- if (l + 1 < MAX_RUNES && player->GetRuneCooldown(l) >= player->GetRuneCooldown(l+1))
- l++;
+ if (l + 1 < MAX_RUNES && player->GetRuneCooldown(l) >= player->GetRuneCooldown(l + 1))
+ ++l;
+
player->SetRuneCooldown(l, 0);
--count;
// is needed to push through to the client that the rune is active
@@ -5476,6 +5461,15 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
}
}
+ for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j)
+ {
+ if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(m_spellInfo->Effects[effIndex].MiscValue))
+ {
+ player->SetRuneCooldown(j, 0);
+ --count;
+ }
+ }
+
// Empower rune weapon
if (m_spellInfo->Id == 47568)
{
@@ -5485,7 +5479,7 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex)
for (uint32 i = 0; i < MAX_RUNES; ++i)
{
- if (player->GetRuneCooldown(i) && (player->GetCurrentRune(i) == RUNE_FROST || player->GetCurrentRune(i) == RUNE_DEATH))
+ if (player->GetRuneCooldown(i) && (player->GetBaseRune(i) == RUNE_FROST))
player->SetRuneCooldown(i, 0);
}
}
@@ -5531,13 +5525,13 @@ void Spell::EffectDiscoverTaxi(SpellEffIndex effIndex)
unitTarget->ToPlayer()->GetSession()->SendDiscoverNewTaxiNode(nodeid);
}
-void Spell::EffectTitanGrip(SpellEffIndex /*effIndex*/)
+void Spell::EffectTitanGrip(SpellEffIndex effIndex)
{
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
return;
if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->SetCanTitanGrip(true);
+ m_caster->ToPlayer()->SetCanTitanGrip(true, m_spellInfo->Effects[effIndex].MiscValue);
}
void Spell::EffectRedirectThreat(SpellEffIndex /*effIndex*/)
@@ -5614,7 +5608,7 @@ void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const*
int32 duration = m_spellInfo->GetDuration();
if (Player* modOwner = m_originalCaster->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
+ modOwner->ApplySpellMod<SPELLMOD_DURATION>(m_spellInfo->Id, duration);
//TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
Map* map = caster->GetMap();
diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp
index 31490bea29b..3925ffe552e 100644
--- a/src/server/game/Spells/SpellHistory.cpp
+++ b/src/server/game/Spells/SpellHistory.cpp
@@ -307,10 +307,10 @@ void SpellHistory::StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spel
if (Player* modOwner = _owner->GetSpellModOwner())
{
if (cooldown > 0)
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, cooldown, spell);
+ modOwner->ApplySpellMod<SPELLMOD_COOLDOWN>(spellInfo->Id, cooldown, spell);
if (categoryCooldown > 0 && !spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS))
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, categoryCooldown, spell);
+ modOwner->ApplySpellMod<SPELLMOD_COOLDOWN>(spellInfo->Id, categoryCooldown, spell);
}
if (int32 cooldownMod = _owner->GetTotalAuraModifier(SPELL_AURA_MOD_COOLDOWN))
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index eba950a3233..c0fbdf51889 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -16,6 +16,7 @@
*/
#include "SpellAuraDefines.h"
+#include "SpellAuras.h"
#include "SpellInfo.h"
#include "SpellMgr.h"
#include "Spell.h"
@@ -519,7 +520,7 @@ float SpellEffectInfo::CalcValueMultiplier(Unit* caster, Spell* spell) const
{
float multiplier = ValueMultiplier;
if (Player* modOwner = (caster ? caster->GetSpellModOwner() : NULL))
- modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_VALUE_MULTIPLIER, multiplier, spell);
+ modOwner->ApplySpellMod<SPELLMOD_VALUE_MULTIPLIER>(_spellInfo->Id, multiplier, spell);
return multiplier;
}
@@ -527,7 +528,7 @@ float SpellEffectInfo::CalcDamageMultiplier(Unit* caster, Spell* spell) const
{
float multiplierPercent = DamageMultiplier * 100.0f;
if (Player* modOwner = (caster ? caster->GetSpellModOwner() : NULL))
- modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_DAMAGE_MULTIPLIER, multiplierPercent, spell);
+ modOwner->ApplySpellMod<SPELLMOD_DAMAGE_MULTIPLIER>(_spellInfo->Id, multiplierPercent, spell);
return multiplierPercent / 100.0f;
}
@@ -547,7 +548,7 @@ float SpellEffectInfo::CalcRadius(Unit* caster, Spell* spell) const
radius += RadiusEntry->RadiusPerLevel * caster->getLevel();
radius = std::min(radius, RadiusEntry->RadiusMax);
if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_RADIUS, radius, spell);
+ modOwner->ApplySpellMod<SPELLMOD_RADIUS>(_spellInfo->Id, radius, spell);
}
return radius;
@@ -855,6 +856,9 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry)
ChainEntry = NULL;
ExplicitTargetMask = 0;
+
+ _spellSpecific = SPELL_SPECIFIC_NORMAL;
+ _auraState = AURA_STATE_NONE;
}
SpellInfo::~SpellInfo()
@@ -891,6 +895,31 @@ bool SpellInfo::HasAreaAuraEffect() const
return false;
}
+bool SpellInfo::HasOnlyDamageEffects() const
+{
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (Effects[i].IsEffect())
+ {
+ switch (Effects[i].Effect)
+ {
+ case SPELL_EFFECT_WEAPON_DAMAGE:
+ case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
+ case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
+ case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
+ case SPELL_EFFECT_SCHOOL_DAMAGE:
+ case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE:
+ case SPELL_EFFECT_HEALTH_LEECH:
+ continue;
+ default:
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
bool SpellInfo::IsExplicitDiscovery() const
{
return ((Effects[0].Effect == SPELL_EFFECT_CREATE_RANDOM_ITEM
@@ -1055,7 +1084,7 @@ bool SpellInfo::IsPassive() const
bool SpellInfo::IsAutocastable() const
{
- if (HasAttribute(SPELL_ATTR0_PASSIVE))
+ if (IsPassive())
return false;
if (HasAttribute(SPELL_ATTR1_UNAUTOCASTABLE_BY_PET))
return false;
@@ -1113,7 +1142,10 @@ bool SpellInfo::IsStackableOnOneSlotWithDifferentCasters() const
bool SpellInfo::IsCooldownStartedOnEvent() const
{
- return HasAttribute(SPELL_ATTR0_DISABLED_WHILE_ACTIVE) || (CategoryEntry && CategoryEntry->Flags & SPELL_CATEGORY_FLAG_COOLDOWN_STARTS_ON_EVENT);
+ if (HasAttribute(SPELL_ATTR0_DISABLED_WHILE_ACTIVE))
+ return true;
+
+ return CategoryEntry && CategoryEntry->Flags & SPELL_CATEGORY_FLAG_COOLDOWN_STARTS_ON_EVENT;
}
bool SpellInfo::IsDeathPersistent() const
@@ -1175,12 +1207,22 @@ bool SpellInfo::IsPositiveEffect(uint8 effIndex) const
bool SpellInfo::IsChanneled() const
{
- return HasAttribute(SPELL_ATTR1_CHANNELED_1) || HasAttribute(SPELL_ATTR1_CHANNELED_2);
+ return HasAttribute(SpellAttr1(SPELL_ATTR1_CHANNELED_1 | SPELL_ATTR1_CHANNELED_2));
+}
+
+bool SpellInfo::IsMoveAllowedChannel() const
+{
+ return IsChanneled() && HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING);
}
bool SpellInfo::NeedsComboPoints() const
{
- return HasAttribute(SPELL_ATTR1_REQ_COMBO_POINTS1) || HasAttribute(SPELL_ATTR1_REQ_COMBO_POINTS2);
+ return HasAttribute(SpellAttr1(SPELL_ATTR1_REQ_COMBO_POINTS1 | SPELL_ATTR1_REQ_COMBO_POINTS2));
+}
+
+bool SpellInfo::IsNextMeleeSwingSpell() const
+{
+ return HasAttribute(SpellAttr0(SPELL_ATTR0_ON_NEXT_SWING | SPELL_ATTR0_ON_NEXT_SWING_2));
}
bool SpellInfo::IsBreakingStealth() const
@@ -1204,6 +1246,20 @@ bool SpellInfo::HasInitialAggro() const
return !(HasAttribute(SPELL_ATTR1_NO_THREAT) || HasAttribute(SPELL_ATTR3_NO_INITIAL_AGGRO));
}
+bool SpellInfo::IsAffected(uint32 familyName, flag96 const& familyFlags) const
+{
+ if (!familyName)
+ return true;
+
+ if (familyName != SpellFamilyName)
+ return false;
+
+ if (familyFlags && !(familyFlags & SpellFamilyFlags))
+ return false;
+
+ return true;
+}
+
bool SpellInfo::IsAffectedBySpellMods() const
{
return !HasAttribute(SPELL_ATTR3_NO_DONE_BONUS);
@@ -1215,42 +1271,41 @@ bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const
return false;
SpellInfo const* affectSpell = sSpellMgr->GetSpellInfo(mod->spellId);
- // False if affect_spell == NULL or spellFamily not equal
- if (!affectSpell || affectSpell->SpellFamilyName != SpellFamilyName)
+ if (!affectSpell)
return false;
- // true
- if (mod->mask & SpellFamilyFlags)
- return true;
-
- return false;
+ return IsAffected(affectSpell->SpellFamilyName, mod->mask);
}
-bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const
+bool SpellInfo::CanPierceImmuneAura(SpellInfo const* auraSpellInfo) const
{
- // these spells pierce all avalible spells (Resurrection Sickness for example)
+ // aura can't be pierced
+ if (!auraSpellInfo || auraSpellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
+ return false;
+
+ // these spells pierce all available spells (Resurrection Sickness for example)
if (HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return true;
- // these spells (Cyclone for example) can pierce all... // ...but not these (Divine shield, Ice block, Cyclone and Banish for example)
- if ((HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE)) && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY || aura->Mechanic == MECHANIC_BANISH)))
+ // Dispels other auras on immunity, check if this spell makes the unit immune to aura
+ if (HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) && CanSpellProvideImmunityAgainstAura(auraSpellInfo))
return true;
return false;
}
-bool SpellInfo::CanDispelAura(SpellInfo const* aura) const
+bool SpellInfo::CanDispelAura(SpellInfo const* auraSpellInfo) const
{
- // These spells (like Mass Dispel) can dispell all auras, except death persistent ones (like Dungeon and Battleground Deserter)
- if (HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) && !aura->IsDeathPersistent())
- return true;
-
// These auras (like Divine Shield) can't be dispelled
- if (aura->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
+ if (auraSpellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return false;
+ // These spells (like Mass Dispel) can dispel all auras
+ if (HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
+ return true;
+
// These auras (Cyclone for example) are not dispelable
- if (aura->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE))
+ if (auraSpellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) || auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
return false;
return true;
@@ -1405,9 +1460,11 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
// continent limitation (virtual continent)
if (HasAttribute(SPELL_ATTR4_CAST_ONLY_IN_OUTLAND))
{
- uint32 v_map = GetVirtualMapForMapAndZone(map_id, zone_id);
- MapEntry const* mapEntry = sMapStore.LookupEntry(v_map);
- if (!mapEntry || mapEntry->addon < 1 || !mapEntry->IsContinent())
+ AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(area_id);
+ if (!areaEntry)
+ areaEntry = sAreaTableStore.LookupEntry(zone_id);
+
+ if (!areaEntry || !areaEntry->IsFlyable() || !player->CanFlyInZone(map_id, zone_id))
return SPELL_FAILED_INCORRECT_AREA;
}
@@ -1604,7 +1661,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
else return SPELL_CAST_OK;
// corpseOwner and unit specific target checks
- if (HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS) && !unitTarget->ToPlayer())
+ if (HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS) && unitTarget->GetTypeId() != TYPEID_PLAYER)
return SPELL_FAILED_TARGET_NOT_PLAYER;
if (!IsAllowingDeadTarget() && !unitTarget->IsAlive())
@@ -1618,7 +1675,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
//if (!HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
// return SPELL_FAILED_BAD_TARGETS;
- //if (!HasAttribute(SPELL_ATTR6_CAN_TARGET_POSSESSED_FRIENDS)
+ //if (!HasAttribute(SPELL_ATTR6_CAN_TARGET_POSSESSED_FRIENDS))
if (!CheckTargetCreatureType(unitTarget))
{
@@ -1639,7 +1696,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
}
// not allow casting on flying player
- if (unitTarget->HasUnitState(UNIT_STATE_IN_FLIGHT) && !(AttributesCu & SPELL_ATTR0_CU_ALLOW_INFLIGHT_TARGET))
+ if (unitTarget->HasUnitState(UNIT_STATE_IN_FLIGHT) && !HasAttribute(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
@@ -1851,239 +1908,1037 @@ uint32 SpellInfo::GetExplicitTargetMask() const
AuraStateType SpellInfo::GetAuraState() const
{
- // Seals
- if (GetSpellSpecific() == SPELL_SPECIFIC_SEAL)
- return AURA_STATE_JUDGEMENT;
-
- // Conflagrate aura state on Immolate and Shadowflame
- if (SpellFamilyName == SPELLFAMILY_WARLOCK &&
- // Immolate
- ((SpellFamilyFlags[0] & 4) ||
- // Shadowflame
- (SpellFamilyFlags[2] & 2)))
- return AURA_STATE_CONFLAGRATE;
-
- // Faerie Fire (druid versions)
- if (SpellFamilyName == SPELLFAMILY_DRUID && SpellFamilyFlags[0] & 0x400)
- return AURA_STATE_FAERIE_FIRE;
-
- // Sting (hunter's pet ability)
- if (GetCategory() == 1133)
- return AURA_STATE_FAERIE_FIRE;
-
- // Victorious
- if (SpellFamilyName == SPELLFAMILY_WARRIOR && SpellFamilyFlags[1] & 0x00040000)
- return AURA_STATE_WARRIOR_VICTORY_RUSH;
-
- // Swiftmend state on Regrowth & Rejuvenation
- if (SpellFamilyName == SPELLFAMILY_DRUID && SpellFamilyFlags[0] & 0x50)
- return AURA_STATE_SWIFTMEND;
-
- // Deadly poison aura state
- if (SpellFamilyName == SPELLFAMILY_ROGUE && SpellFamilyFlags[0] & 0x10000)
- return AURA_STATE_DEADLY_POISON;
-
- // Enrage aura state
- if (Dispel == DISPEL_ENRAGE)
- return AURA_STATE_ENRAGE;
-
- // Bleeding aura state
- if (GetAllEffectsMechanicMask() & 1<<MECHANIC_BLEED)
- return AURA_STATE_BLEEDING;
-
- if (GetSchoolMask() & SPELL_SCHOOL_MASK_FROST)
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- if (Effects[i].IsAura() && (Effects[i].ApplyAuraName == SPELL_AURA_MOD_STUN
- || Effects[i].ApplyAuraName == SPELL_AURA_MOD_ROOT))
- return AURA_STATE_FROZEN;
+ return _auraState;
+}
- switch (Id)
+void SpellInfo::_LoadAuraState()
+{
+ _auraState = [this]() -> AuraStateType
{
- case 71465: // Divine Surge
- case 50241: // Evasive Charges
- return AURA_STATE_UNKNOWN22;
- default:
- break;
- }
+ // Seals
+ if (GetSpellSpecific() == SPELL_SPECIFIC_SEAL)
+ return AURA_STATE_JUDGEMENT;
+
+ // Conflagrate aura state on Immolate and Shadowflame
+ if (SpellFamilyName == SPELLFAMILY_WARLOCK &&
+ // Immolate
+ ((SpellFamilyFlags[0] & 4) ||
+ // Shadowflame
+ (SpellFamilyFlags[2] & 2)))
+ return AURA_STATE_CONFLAGRATE;
+
+ // Faerie Fire (druid versions)
+ if (SpellFamilyName == SPELLFAMILY_DRUID && SpellFamilyFlags[0] & 0x400)
+ return AURA_STATE_FAERIE_FIRE;
+
+ // Sting (hunter's pet ability)
+ if (GetCategory() == 1133)
+ return AURA_STATE_FAERIE_FIRE;
+
+ // Victorious
+ if (SpellFamilyName == SPELLFAMILY_WARRIOR && SpellFamilyFlags[1] & 0x00040000)
+ return AURA_STATE_WARRIOR_VICTORY_RUSH;
+
+ // Swiftmend state on Regrowth & Rejuvenation
+ if (SpellFamilyName == SPELLFAMILY_DRUID && SpellFamilyFlags[0] & 0x50)
+ return AURA_STATE_SWIFTMEND;
+
+ // Deadly poison aura state
+ if (SpellFamilyName == SPELLFAMILY_ROGUE && SpellFamilyFlags[0] & 0x10000)
+ return AURA_STATE_DEADLY_POISON;
+
+ // Enrage aura state
+ if (Dispel == DISPEL_ENRAGE)
+ return AURA_STATE_ENRAGE;
+
+ // Bleeding aura state
+ if (GetAllEffectsMechanicMask() & 1 << MECHANIC_BLEED)
+ return AURA_STATE_BLEEDING;
+
+ if (GetSchoolMask() & SPELL_SCHOOL_MASK_FROST)
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (Effects[i].IsAura() && (Effects[i].ApplyAuraName == SPELL_AURA_MOD_STUN
+ || Effects[i].ApplyAuraName == SPELL_AURA_MOD_ROOT))
+ return AURA_STATE_FROZEN;
+
+ switch (Id)
+ {
+ case 71465: // Divine Surge
+ case 50241: // Evasive Charges
+ return AURA_STATE_UNKNOWN22;
+ default:
+ break;
+ }
- return AURA_STATE_NONE;
+ return AURA_STATE_NONE;
+ }();
}
SpellSpecificType SpellInfo::GetSpellSpecific() const
{
- switch (SpellFamilyName)
+ return _spellSpecific;
+}
+
+void SpellInfo::_LoadSpellSpecific()
+{
+ _spellSpecific = [this]() -> SpellSpecificType
{
- case SPELLFAMILY_GENERIC:
+ switch (SpellFamilyName)
{
- // Food / Drinks (mostly)
- if (AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED)
+ case SPELLFAMILY_GENERIC:
{
- bool food = false;
- bool drink = false;
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ // Food / Drinks (mostly)
+ if (AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED)
{
- if (!Effects[i].IsAura())
- continue;
- switch (Effects[i].ApplyAuraName)
+ bool food = false;
+ bool drink = false;
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- // Food
- case SPELL_AURA_MOD_REGEN:
- case SPELL_AURA_OBS_MOD_HEALTH:
- food = true;
- break;
- // Drink
- case SPELL_AURA_MOD_POWER_REGEN:
- case SPELL_AURA_OBS_MOD_POWER:
- drink = true;
+ if (!Effects[i].IsAura())
+ continue;
+ switch (Effects[i].ApplyAuraName)
+ {
+ // Food
+ case SPELL_AURA_MOD_REGEN:
+ case SPELL_AURA_OBS_MOD_HEALTH:
+ food = true;
+ break;
+ // Drink
+ case SPELL_AURA_MOD_POWER_REGEN:
+ case SPELL_AURA_OBS_MOD_POWER:
+ drink = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (food && drink)
+ return SPELL_SPECIFIC_FOOD_AND_DRINK;
+ else if (food)
+ return SPELL_SPECIFIC_FOOD;
+ else if (drink)
+ return SPELL_SPECIFIC_DRINK;
+ }
+ // scrolls effects
+ else
+ {
+ SpellInfo const* firstRankSpellInfo = GetFirstRankSpell();
+ switch (firstRankSpellInfo->Id)
+ {
+ case 8118: // Strength
+ case 8099: // Stamina
+ case 8112: // Spirit
+ case 8096: // Intellect
+ case 8115: // Agility
+ case 8091: // Armor
+ return SPELL_SPECIFIC_SCROLL;
+ default:
break;
+ }
+
+ switch (Id)
+ {
+ case 12880: // Enrage (Enrage)
+ case 14201:
+ case 14202:
+ case 14203:
+ case 14204:
+ case 57518: // Enrage (Wrecking Crew)
+ case 57519:
+ case 57520:
+ case 57521:
+ case 57522:
+ case 57514: // Enrage (Imp. Defensive Stance)
+ case 57516:
+ return SPELL_SPECIFIC_WARRIOR_ENRAGE;
default:
break;
}
}
+ break;
+ }
+ case SPELLFAMILY_MAGE:
+ {
+ // family flags 18(Molten), 25(Frost/Ice), 28(Mage)
+ if (SpellFamilyFlags[0] & 0x12040000)
+ return SPELL_SPECIFIC_MAGE_ARMOR;
- if (food && drink)
- return SPELL_SPECIFIC_FOOD_AND_DRINK;
- else if (food)
- return SPELL_SPECIFIC_FOOD;
- else if (drink)
- return SPELL_SPECIFIC_DRINK;
+ // Arcane brillance and Arcane intelect (normal check fails because of flags difference)
+ if (SpellFamilyFlags[0] & 0x400)
+ return SPELL_SPECIFIC_MAGE_ARCANE_BRILLANCE;
+
+ if ((SpellFamilyFlags[0] & 0x1000000) && Effects[0].ApplyAuraName == SPELL_AURA_MOD_CONFUSE)
+ return SPELL_SPECIFIC_MAGE_POLYMORPH;
+
+ break;
}
- // scrolls effects
- else
+ case SPELLFAMILY_WARRIOR:
+ {
+ if (Id == 12292) // Death Wish
+ return SPELL_SPECIFIC_WARRIOR_ENRAGE;
+
+ break;
+ }
+ case SPELLFAMILY_WARLOCK:
+ {
+ // only warlock curses have this
+ if (Dispel == DISPEL_CURSE)
+ return SPELL_SPECIFIC_CURSE;
+
+ // Warlock (Demon Armor | Demon Skin | Fel Armor)
+ if (SpellFamilyFlags[1] & 0x20000020 || SpellFamilyFlags[2] & 0x00000010)
+ return SPELL_SPECIFIC_WARLOCK_ARMOR;
+
+ //seed of corruption and corruption
+ if (SpellFamilyFlags[1] & 0x10 || SpellFamilyFlags[0] & 0x2)
+ return SPELL_SPECIFIC_WARLOCK_CORRUPTION;
+ break;
+ }
+ case SPELLFAMILY_PRIEST:
{
- SpellInfo const* firstRankSpellInfo = GetFirstRankSpell();
- switch (firstRankSpellInfo->Id)
+ // Divine Spirit and Prayer of Spirit
+ if (SpellFamilyFlags[0] & 0x20)
+ return SPELL_SPECIFIC_PRIEST_DIVINE_SPIRIT;
+
+ break;
+ }
+ case SPELLFAMILY_HUNTER:
+ {
+ // only hunter stings have this
+ if (Dispel == DISPEL_POISON)
+ return SPELL_SPECIFIC_STING;
+
+ // only hunter aspects have this (but not all aspects in hunter family)
+ if (SpellFamilyFlags.HasFlag(0x00380000, 0x00440000, 0x00001010))
+ return SPELL_SPECIFIC_ASPECT;
+
+ break;
+ }
+ case SPELLFAMILY_PALADIN:
+ {
+ // Collection of all the seal family flags. No other paladin spell has any of those.
+ if (SpellFamilyFlags[1] & 0x26000C00
+ || SpellFamilyFlags[0] & 0x0A000000)
+ return SPELL_SPECIFIC_SEAL;
+
+ if (SpellFamilyFlags[0] & 0x00002190)
+ return SPELL_SPECIFIC_HAND;
+
+ // Judgement of Wisdom, Judgement of Light, Judgement of Justice
+ if (Id == 20184 || Id == 20185 || Id == 20186)
+ return SPELL_SPECIFIC_JUDGEMENT;
+
+ // only paladin auras have this (for palaldin class family)
+ if (SpellFamilyFlags[2] & 0x00000020)
+ return SPELL_SPECIFIC_AURA;
+
+ break;
+ }
+ case SPELLFAMILY_SHAMAN:
+ {
+ // family flags 10 (Lightning), 42 (Earth), 37 (Water), proc shield from T2 8 pieces bonus
+ if (SpellFamilyFlags[1] & 0x420
+ || SpellFamilyFlags[0] & 0x00000400
+ || Id == 23552)
+ return SPELL_SPECIFIC_ELEMENTAL_SHIELD;
+
+ break;
+ }
+ case SPELLFAMILY_DEATHKNIGHT:
+ if (Id == 48266 || Id == 48263 || Id == 48265)
+ return SPELL_SPECIFIC_PRESENCE;
+ break;
+ }
+
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (Effects[i].Effect == SPELL_EFFECT_APPLY_AURA)
+ {
+ switch (Effects[i].ApplyAuraName)
{
- case 8118: // Strength
- case 8099: // Stamina
- case 8112: // Spirit
- case 8096: // Intellect
- case 8115: // Agility
- case 8091: // Armor
- return SPELL_SPECIFIC_SCROLL;
- case 12880: // Enrage (Enrage)
- case 57518: // Enrage (Wrecking Crew)
- return SPELL_SPECIFIC_WARRIOR_ENRAGE;
+ case SPELL_AURA_MOD_CHARM:
+ case SPELL_AURA_MOD_POSSESS_PET:
+ case SPELL_AURA_MOD_POSSESS:
+ case SPELL_AURA_AOE_CHARM:
+ return SPELL_SPECIFIC_CHARM;
+ case SPELL_AURA_TRACK_CREATURES:
+ /// @workaround For non-stacking tracking spells (We need generic solution)
+ if (Id == 30645) // Gas Cloud Tracking
+ return SPELL_SPECIFIC_NORMAL;
+ case SPELL_AURA_TRACK_RESOURCES:
+ case SPELL_AURA_TRACK_STEALTHED:
+ return SPELL_SPECIFIC_TRACKER;
}
}
- break;
}
- case SPELLFAMILY_MAGE:
- {
- // family flags 18(Molten), 25(Frost/Ice), 28(Mage)
- if (SpellFamilyFlags[0] & 0x12040000)
- return SPELL_SPECIFIC_MAGE_ARMOR;
- // Arcane brillance and Arcane intelect (normal check fails because of flags difference)
- if (SpellFamilyFlags[0] & 0x400)
- return SPELL_SPECIFIC_MAGE_ARCANE_BRILLANCE;
+ return SPELL_SPECIFIC_NORMAL;
+ }();
+}
- if ((SpellFamilyFlags[0] & 0x1000000) && Effects[0].ApplyAuraName == SPELL_AURA_MOD_CONFUSE)
- return SPELL_SPECIFIC_MAGE_POLYMORPH;
+void SpellInfo::_LoadSpellDiminishInfo()
+{
+ auto diminishingGroupCompute = [this](bool triggered) -> DiminishingGroup
+ {
+ if (IsPositive())
+ return DIMINISHING_NONE;
- break;
- }
- case SPELLFAMILY_WARRIOR:
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- if (Id == 12292) // Death Wish
- return SPELL_SPECIFIC_WARRIOR_ENRAGE;
-
- break;
+ if (Effects[i].ApplyAuraName == SPELL_AURA_MOD_TAUNT)
+ return DIMINISHING_TAUNT;
}
- case SPELLFAMILY_WARLOCK:
+
+ // Explicit Diminishing Groups
+ switch (SpellFamilyName)
{
- // only warlock curses have this
- if (Dispel == DISPEL_CURSE)
- return SPELL_SPECIFIC_CURSE;
+ case SPELLFAMILY_GENERIC:
+ {
+ // Pet charge effects (Infernal Awakening, Demon Charge)
+ if (SpellVisual[0] == 2816 && SpellIconID == 15)
+ return DIMINISHING_CONTROLLED_STUN;
+ // Frost Tomb
+ else if (Id == 48400)
+ return DIMINISHING_NONE;
+ // Gnaw
+ else if (Id == 47481)
+ return DIMINISHING_CONTROLLED_STUN;
+ // ToC Icehowl Arctic Breath
+ else if (SpellVisual[0] == 14153)
+ return DIMINISHING_NONE;
+ // Black Plague
+ else if (Id == 64155)
+ return DIMINISHING_NONE;
+ // Screams of the Dead (King Ymiron)
+ else if (Id == 51750)
+ return DIMINISHING_NONE;
+ break;
+ }
+ // Event spells
+ case SPELLFAMILY_UNK1:
+ return DIMINISHING_NONE;
+ case SPELLFAMILY_MAGE:
+ {
+ // Frostbite
+ if (SpellFamilyFlags[1] & 0x80000000)
+ return DIMINISHING_ROOT;
+ // Shattered Barrier
+ else if (SpellVisual[0] == 12297)
+ return DIMINISHING_ROOT;
+ // Deep Freeze
+ else if (SpellIconID == 2939 && SpellVisual[0] == 9963)
+ return DIMINISHING_CONTROLLED_STUN;
+ // Frost Nova / Freeze (Water Elemental)
+ else if (SpellIconID == 193)
+ return DIMINISHING_CONTROLLED_ROOT;
+ // Dragon's Breath
+ else if (SpellFamilyFlags[0] & 0x800000)
+ return DIMINISHING_DRAGONS_BREATH;
+ break;
+ }
+ case SPELLFAMILY_WARRIOR:
+ {
+ // Hamstring - limit duration to 10s in PvP
+ if (SpellFamilyFlags[0] & 0x2)
+ return DIMINISHING_LIMITONLY;
+ // Charge Stun (own diminishing)
+ else if (SpellFamilyFlags[0] & 0x01000000)
+ return DIMINISHING_CHARGE;
+ break;
+ }
+ case SPELLFAMILY_WARLOCK:
+ {
+ // Curses/etc
+ if ((SpellFamilyFlags[0] & 0x80000000) || (SpellFamilyFlags[1] & 0x200))
+ return DIMINISHING_LIMITONLY;
+ // Seduction
+ else if (SpellFamilyFlags[1] & 0x10000000)
+ return DIMINISHING_FEAR;
+ break;
+ }
+ case SPELLFAMILY_DRUID:
+ {
+ // Pounce
+ if (SpellFamilyFlags[0] & 0x20000)
+ return DIMINISHING_OPENING_STUN;
+ // Cyclone
+ else if (SpellFamilyFlags[1] & 0x20)
+ return DIMINISHING_CYCLONE;
+ // Entangling Roots
+ // Nature's Grasp
+ else if (SpellFamilyFlags[0] & 0x00000200)
+ return DIMINISHING_CONTROLLED_ROOT;
+ // Faerie Fire
+ else if (SpellFamilyFlags[0] & 0x400)
+ return DIMINISHING_LIMITONLY;
+ break;
+ }
+ case SPELLFAMILY_ROGUE:
+ {
+ // Gouge
+ if (SpellFamilyFlags[0] & 0x8)
+ return DIMINISHING_DISORIENT;
+ // Blind
+ else if (SpellFamilyFlags[0] & 0x1000000)
+ return DIMINISHING_FEAR;
+ // Cheap Shot
+ else if (SpellFamilyFlags[0] & 0x400)
+ return DIMINISHING_OPENING_STUN;
+ // Crippling poison - Limit to 10 seconds in PvP (No SpellFamilyFlags)
+ else if (SpellIconID == 163)
+ return DIMINISHING_LIMITONLY;
+ break;
+ }
+ case SPELLFAMILY_HUNTER:
+ {
+ // Hunter's Mark
+ if ((SpellFamilyFlags[0] & 0x400) && SpellIconID == 538)
+ return DIMINISHING_LIMITONLY;
+ // Scatter Shot (own diminishing)
+ else if ((SpellFamilyFlags[0] & 0x40000) && SpellIconID == 132)
+ return DIMINISHING_SCATTER_SHOT;
+ // Entrapment (own diminishing)
+ else if (SpellVisual[0] == 7484 && SpellIconID == 20)
+ return DIMINISHING_ENTRAPMENT;
+ // Wyvern Sting mechanic is MECHANIC_SLEEP but the diminishing is DIMINISHING_DISORIENT
+ else if ((SpellFamilyFlags[1] & 0x1000) && SpellIconID == 1721)
+ return DIMINISHING_DISORIENT;
+ // Freezing Arrow
+ else if (SpellFamilyFlags[0] & 0x8)
+ return DIMINISHING_DISORIENT;
+ break;
+ }
+ case SPELLFAMILY_PALADIN:
+ {
+ // Judgement of Justice - limit duration to 10s in PvP
+ if (SpellFamilyFlags[0] & 0x100000)
+ return DIMINISHING_LIMITONLY;
+ // Turn Evil
+ else if ((SpellFamilyFlags[1] & 0x804000) && SpellIconID == 309)
+ return DIMINISHING_FEAR;
+ break;
+ }
+ case SPELLFAMILY_SHAMAN:
+ {
+ // Storm, Earth and Fire - Earthgrab
+ if (SpellFamilyFlags[2] & 0x4000)
+ return DIMINISHING_NONE;
+ break;
+ }
+ case SPELLFAMILY_DEATHKNIGHT:
+ {
+ // Hungering Cold (no flags)
+ if (SpellIconID == 2797)
+ return DIMINISHING_DISORIENT;
+ // Mark of Blood
+ else if ((SpellFamilyFlags[0] & 0x10000000) && SpellIconID == 2285)
+ return DIMINISHING_LIMITONLY;
+ break;
+ }
+ default:
+ break;
+ }
- // Warlock (Demon Armor | Demon Skin | Fel Armor)
- if (SpellFamilyFlags[1] & 0x20000020 || SpellFamilyFlags[2] & 0x00000010)
- return SPELL_SPECIFIC_WARLOCK_ARMOR;
+ // Lastly - Set diminishing depending on mechanic
+ uint32 mechanic = GetAllEffectsMechanicMask();
+ if (mechanic & (1 << MECHANIC_CHARM))
+ return DIMINISHING_MIND_CONTROL;
+ if (mechanic & (1 << MECHANIC_SILENCE))
+ return DIMINISHING_SILENCE;
+ if (mechanic & (1 << MECHANIC_SLEEP))
+ return DIMINISHING_SLEEP;
+ if (mechanic & ((1 << MECHANIC_SAPPED) | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_SHACKLE)))
+ return DIMINISHING_DISORIENT;
+ // Mechanic Knockout, except Blast Wave
+ if (mechanic & (1 << MECHANIC_KNOCKOUT) && SpellIconID != 292)
+ return DIMINISHING_DISORIENT;
+ if (mechanic & (1 << MECHANIC_DISARM))
+ return DIMINISHING_DISARM;
+ if (mechanic & (1 << MECHANIC_FEAR))
+ return DIMINISHING_FEAR;
+ if (mechanic & (1 << MECHANIC_STUN))
+ return triggered ? DIMINISHING_STUN : DIMINISHING_CONTROLLED_STUN;
+ if (mechanic & (1 << MECHANIC_BANISH))
+ return DIMINISHING_BANISH;
+ if (mechanic & (1 << MECHANIC_ROOT))
+ return triggered ? DIMINISHING_ROOT : DIMINISHING_CONTROLLED_ROOT;
+ if (mechanic & (1 << MECHANIC_HORROR))
+ return DIMINISHING_HORROR;
+
+ return DIMINISHING_NONE;
+ };
+
+ auto diminishingTypeCompute = [](DiminishingGroup group) -> DiminishingReturnsType
+ {
+ switch (group)
+ {
+ case DIMINISHING_TAUNT:
+ case DIMINISHING_CONTROLLED_STUN:
+ case DIMINISHING_STUN:
+ case DIMINISHING_OPENING_STUN:
+ case DIMINISHING_CYCLONE:
+ case DIMINISHING_CHARGE:
+ return DRTYPE_ALL;
+ case DIMINISHING_LIMITONLY:
+ case DIMINISHING_NONE:
+ return DRTYPE_NONE;
+ default:
+ return DRTYPE_PLAYER;
+ }
+ };
- //seed of corruption and corruption
- if (SpellFamilyFlags[1] & 0x10 || SpellFamilyFlags[0] & 0x2)
- return SPELL_SPECIFIC_WARLOCK_CORRUPTION;
- break;
+ auto diminishingMaxLevelCompute = [](DiminishingGroup group) -> DiminishingLevels
+ {
+ switch (group)
+ {
+ case DIMINISHING_TAUNT:
+ return DIMINISHING_LEVEL_TAUNT_IMMUNE;
+ default:
+ return DIMINISHING_LEVEL_IMMUNE;
}
- case SPELLFAMILY_PRIEST:
+ };
+
+ auto diminishingLimitDurationCompute = [this](DiminishingGroup group) -> int32
+ {
+ auto isGroupDurationLimited = [group]() -> bool
{
- // Divine Spirit and Prayer of Spirit
- if (SpellFamilyFlags[0] & 0x20)
- return SPELL_SPECIFIC_PRIEST_DIVINE_SPIRIT;
+ switch (group)
+ {
+ case DIMINISHING_BANISH:
+ case DIMINISHING_CONTROLLED_STUN:
+ case DIMINISHING_CONTROLLED_ROOT:
+ case DIMINISHING_CYCLONE:
+ case DIMINISHING_DISORIENT:
+ case DIMINISHING_ENTRAPMENT:
+ case DIMINISHING_FEAR:
+ case DIMINISHING_HORROR:
+ case DIMINISHING_MIND_CONTROL:
+ case DIMINISHING_OPENING_STUN:
+ case DIMINISHING_ROOT:
+ case DIMINISHING_STUN:
+ case DIMINISHING_SLEEP:
+ case DIMINISHING_LIMITONLY:
+ return true;
+ default:
+ return false;
+ }
+ };
- break;
+ if (!isGroupDurationLimited())
+ return 0;
+
+ // Explicit diminishing duration
+ switch (SpellFamilyName)
+ {
+ case SPELLFAMILY_DRUID:
+ {
+ // Faerie Fire - limit to 40 seconds in PvP (3.1)
+ if (SpellFamilyFlags[0] & 0x400)
+ return 40 * IN_MILLISECONDS;
+ break;
+ }
+ case SPELLFAMILY_HUNTER:
+ {
+ // Wyvern Sting
+ if (SpellFamilyFlags[1] & 0x1000)
+ return 6 * IN_MILLISECONDS;
+ // Hunter's Mark
+ if (SpellFamilyFlags[0] & 0x400)
+ return 120 * IN_MILLISECONDS;
+ break;
+ }
+ case SPELLFAMILY_PALADIN:
+ {
+ // Repentance - limit to 6 seconds in PvP
+ if (SpellFamilyFlags[0] & 0x4)
+ return 6 * IN_MILLISECONDS;
+ break;
+ }
+ case SPELLFAMILY_WARLOCK:
+ {
+ // Banish - limit to 6 seconds in PvP
+ if (SpellFamilyFlags[1] & 0x8000000)
+ return 6 * IN_MILLISECONDS;
+ // Curse of Tongues - limit to 12 seconds in PvP
+ else if (SpellFamilyFlags[2] & 0x800)
+ return 12 * IN_MILLISECONDS;
+ // Curse of Elements - limit to 120 seconds in PvP
+ else if (SpellFamilyFlags[1] & 0x200)
+ return 120 * IN_MILLISECONDS;
+ break;
+ }
+ default:
+ break;
}
- case SPELLFAMILY_HUNTER:
+
+ return 10 * IN_MILLISECONDS;
+ };
+
+ SpellDiminishInfo triggeredInfo, normalInfo;
+ triggeredInfo.DiminishGroup = diminishingGroupCompute(true);
+ triggeredInfo.DiminishReturnType = diminishingTypeCompute(triggeredInfo.DiminishGroup);
+ triggeredInfo.DiminishMaxLevel = diminishingMaxLevelCompute(triggeredInfo.DiminishGroup);
+ triggeredInfo.DiminishDurationLimit = diminishingLimitDurationCompute(triggeredInfo.DiminishGroup);
+
+ normalInfo.DiminishGroup = diminishingGroupCompute(false);
+ normalInfo.DiminishReturnType = diminishingTypeCompute(normalInfo.DiminishGroup);
+ normalInfo.DiminishMaxLevel = diminishingMaxLevelCompute(normalInfo.DiminishGroup);
+ normalInfo.DiminishDurationLimit = diminishingLimitDurationCompute(normalInfo.DiminishGroup);
+
+ _diminishInfoTriggered = triggeredInfo;
+ _diminishInfoNonTriggered = normalInfo;
+}
+
+DiminishingGroup SpellInfo::GetDiminishingReturnsGroupForSpell(bool triggered) const
+{
+ return triggered ? _diminishInfoTriggered.DiminishGroup : _diminishInfoNonTriggered.DiminishGroup;
+}
+
+DiminishingReturnsType SpellInfo::GetDiminishingReturnsGroupType(bool triggered) const
+{
+ return triggered ? _diminishInfoTriggered.DiminishReturnType : _diminishInfoNonTriggered.DiminishReturnType;
+}
+
+DiminishingLevels SpellInfo::GetDiminishingReturnsMaxLevel(bool triggered) const
+{
+ return triggered ? _diminishInfoTriggered.DiminishMaxLevel : _diminishInfoNonTriggered.DiminishMaxLevel;
+}
+
+int32 SpellInfo::GetDiminishingReturnsLimitDuration(bool triggered) const
+{
+ return triggered ? _diminishInfoTriggered.DiminishDurationLimit : _diminishInfoNonTriggered.DiminishDurationLimit;
+}
+
+void SpellInfo::_LoadImmunityInfo()
+{
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ uint32 schoolImmunityMask = 0;
+ uint32 applyHarmfulAuraImmunityMask = 0;
+ uint32 mechanicImmunityMask = 0;
+ uint32 dispelImmunity = 0;
+ uint32 damageImmunityMask = 0;
+
+ int32 miscVal = Effects[i].MiscValue;
+ int32 amount = Effects[i].CalcValue();
+
+ ImmunityInfo& immuneInfo = _immunityInfo[i];
+
+ switch (Effects[i].ApplyAuraName)
{
- // only hunter stings have this
- if (Dispel == DISPEL_POISON)
- return SPELL_SPECIFIC_STING;
+ case SPELL_AURA_MECHANIC_IMMUNITY_MASK:
+ {
+ switch (miscVal)
+ {
+ case 96: // Free Friend, Uncontrollable Frenzy, Warlord's Presence
+ {
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
- // only hunter aspects have this (but not all aspects in hunter family)
- if (SpellFamilyFlags.HasFlag(0x00380000, 0x00440000, 0x00001010))
- return SPELL_SPECIFIC_ASPECT;
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_CONFUSE);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_FEAR);
+ break;
+ }
+ case 1615: // Incite Rage, Wolf Spirit, Overload, Lightning Tendrils
+ {
+ switch (Id)
+ {
+ case 43292: // Incite Rage
+ case 49172: // Wolf Spirit
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_CONFUSE);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_FEAR);
+ // no break intended
+ case 61869: // Overload
+ case 63481:
+ case 61887: // Lightning Tendrils
+ case 63486:
+ mechanicImmunityMask |= (1 << MECHANIC_INTERRUPT) | (1 << MECHANIC_SILENCE);
+
+ immuneInfo.SpellEffectImmune.insert(SPELL_EFFECT_KNOCK_BACK);
+ immuneInfo.SpellEffectImmune.insert(SPELL_EFFECT_KNOCK_BACK_DEST);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case 679: // Mind Control, Avenging Fury
+ {
+ if (Id == 57742) // Avenging Fury
+ {
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
- break;
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_CONFUSE);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_FEAR);
+ }
+ break;
+ }
+ case 1557: // Startling Roar, Warlord Roar, Break Bonds, Stormshield
+ {
+ if (Id == 64187) // Stormshield
+ {
+ mechanicImmunityMask |= (1 << MECHANIC_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ }
+ else
+ {
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_CONFUSE);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_FEAR);
+ }
+ break;
+ }
+ case 1614: // Fixate
+ case 1694: // Fixated, Lightning Tendrils
+ {
+ immuneInfo.SpellEffectImmune.insert(SPELL_EFFECT_ATTACK_ME);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_TAUNT);
+ break;
+ }
+ case 1630: // Fervor, Berserk
+ {
+ if (Id == 64112) // Berserk
+ {
+ immuneInfo.SpellEffectImmune.insert(SPELL_EFFECT_ATTACK_ME);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_TAUNT);
+ }
+ else
+ {
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_CONFUSE);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_FEAR);
+ }
+ break;
+ }
+ case 477: // Bladestorm
+ case 1733: // Bladestorm, Killing Spree
+ {
+ if (!amount)
+ {
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+
+ immuneInfo.SpellEffectImmune.insert(SPELL_EFFECT_KNOCK_BACK);
+ immuneInfo.SpellEffectImmune.insert(SPELL_EFFECT_KNOCK_BACK_DEST);
+
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_CONFUSE);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_FEAR);
+ }
+ break;
+ }
+ case 878: // Whirlwind, Fog of Corruption, Determination
+ {
+ if (Id == 66092) // Determination
+ {
+ mechanicImmunityMask |= (1 << MECHANIC_SNARE) | (1 << MECHANIC_STUN)
+ | (1 << MECHANIC_DISORIENTED) | (1 << MECHANIC_FREEZE);
+
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (immuneInfo.AuraTypeImmune.empty())
+ {
+ if (miscVal & (1 << 10))
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ if (miscVal & (1 << 1))
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_TRANSFORM);
+
+ // These flag can be recognized wrong:
+ if (miscVal & (1 << 6))
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ if (miscVal & (1 << 0))
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT);
+ if (miscVal & (1 << 2))
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_CONFUSE);
+ if (miscVal & (1 << 9))
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_FEAR);
+ if (miscVal & (1 << 7))
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DISARM);
+ }
+ break;
+ }
+ case SPELL_AURA_MECHANIC_IMMUNITY:
+ {
+ switch (Id)
+ {
+ case 34471: // The Beast Within
+ case 19574: // Bestial Wrath
+ case 42292: // PvP trinket
+ case 59752: // Every Man for Himself
+ case 53490: // Bullheaded
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+ break;
+ case 54508: // Demonic Empowerment
+ mechanicImmunityMask |= (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN);
+ break;
+ default:
+ if (miscVal < 1)
+ continue;
+
+ mechanicImmunityMask |= 1 << miscVal;
+ break;
+ }
+ break;
+ }
+ case SPELL_AURA_EFFECT_IMMUNITY:
+ {
+ immuneInfo.SpellEffectImmune.insert(static_cast<SpellEffects>(miscVal));
+ break;
+ }
+ case SPELL_AURA_STATE_IMMUNITY:
+ {
+ immuneInfo.AuraTypeImmune.insert(static_cast<AuraType>(miscVal));
+ break;
+ }
+ case SPELL_AURA_SCHOOL_IMMUNITY:
+ {
+ schoolImmunityMask |= uint32(miscVal);
+ break;
+ }
+ case SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL:
+ {
+ applyHarmfulAuraImmunityMask |= uint32(miscVal);
+ break;
+ }
+ case SPELL_AURA_DAMAGE_IMMUNITY:
+ {
+ damageImmunityMask |= uint32(miscVal);
+ break;
+ }
+ case SPELL_AURA_DISPEL_IMMUNITY:
+ {
+ dispelImmunity = uint32(miscVal);
+ break;
+ }
+ default:
+ break;
}
- case SPELLFAMILY_PALADIN:
- {
- // Collection of all the seal family flags. No other paladin spell has any of those.
- if (SpellFamilyFlags[1] & 0x26000C00
- || SpellFamilyFlags[0] & 0x0A000000)
- return SPELL_SPECIFIC_SEAL;
- if (SpellFamilyFlags[0] & 0x00002190)
- return SPELL_SPECIFIC_HAND;
+ immuneInfo.SchoolImmuneMask = schoolImmunityMask;
+ immuneInfo.ApplyHarmfulAuraImmuneMask = applyHarmfulAuraImmunityMask;
+ immuneInfo.MechanicImmuneMask = mechanicImmunityMask;
+ immuneInfo.DispelImmune = dispelImmunity;
+ immuneInfo.DamageSchoolMask = damageImmunityMask;
+
+ immuneInfo.AuraTypeImmune.shrink_to_fit();
+ immuneInfo.SpellEffectImmune.shrink_to_fit();
+ }
+}
- // Judgement of Wisdom, Judgement of Light, Judgement of Justice
- if (Id == 20184 || Id == 20185 || Id == 20186)
- return SPELL_SPECIFIC_JUDGEMENT;
+void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, uint8 effIndex, bool apply) const
+{
+ ImmunityInfo const* immuneInfo = _immunityInfo + effIndex;
- // only paladin auras have this (for palaldin class family)
- if (SpellFamilyFlags[2] & 0x00000020)
- return SPELL_SPECIFIC_AURA;
+ if (uint32 schoolImmunity = immuneInfo->SchoolImmuneMask)
+ {
+ target->ApplySpellImmune(Id, IMMUNITY_SCHOOL, schoolImmunity, apply);
- break;
+ if (apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ {
+ target->RemoveAppliedAuras([this, schoolImmunity](AuraApplication const* aurApp) -> bool
+ {
+ SpellInfo const* auraSpellInfo = aurApp->GetBase()->GetSpellInfo();
+ return ((auraSpellInfo->GetSchoolMask() & schoolImmunity) != 0 && // Check for school mask
+ CanDispelAura(auraSpellInfo) &&
+ (IsPositive() != aurApp->IsPositive()) && // Check spell vs aura possitivity
+ !auraSpellInfo->IsPassive() && // Don't remove passive auras
+ auraSpellInfo->Id != Id); // Don't remove self
+ });
}
- case SPELLFAMILY_SHAMAN:
+ }
+
+ if (uint32 mechanicImmunity = immuneInfo->MechanicImmuneMask)
+ {
+ for (uint32 i = 0; i < MAX_MECHANIC; ++i)
+ if (mechanicImmunity & (1 << i))
+ target->ApplySpellImmune(Id, IMMUNITY_MECHANIC, i, apply);
+
+ if (apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ target->RemoveAurasWithMechanic(mechanicImmunity, AURA_REMOVE_BY_DEFAULT, Id);
+ }
+
+ if (uint32 dispelImmunity = immuneInfo->DispelImmune)
+ {
+ target->ApplySpellImmune(Id, IMMUNITY_DISPEL, dispelImmunity, apply);
+
+ if (apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
{
- // family flags 10 (Lightning), 42 (Earth), 37 (Water), proc shield from T2 8 pieces bonus
- if (SpellFamilyFlags[1] & 0x420
- || SpellFamilyFlags[0] & 0x00000400
- || Id == 23552)
- return SPELL_SPECIFIC_ELEMENTAL_SHIELD;
+ target->RemoveAppliedAuras([dispelImmunity](AuraApplication const* aurApp) -> bool
+ {
+ SpellInfo const* spellInfo = aurApp->GetBase()->GetSpellInfo();
+ if (spellInfo->Dispel == dispelImmunity)
+ return true;
- break;
+ return false;
+ });
}
- case SPELLFAMILY_DEATHKNIGHT:
- if (Id == 48266 || Id == 48263 || Id == 48265)
- return SPELL_SPECIFIC_PRESENCE;
- break;
}
+ if (uint32 damageImmunity = immuneInfo->DamageSchoolMask)
+ target->ApplySpellImmune(Id, IMMUNITY_DAMAGE, damageImmunity, apply);
+
+ for (AuraType auraType : immuneInfo->AuraTypeImmune)
+ {
+ target->ApplySpellImmune(Id, IMMUNITY_STATE, auraType, apply);
+ if (apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ target->RemoveAurasByType(auraType);
+ }
+
+ for (SpellEffects effectType : immuneInfo->SpellEffectImmune)
+ target->ApplySpellImmune(Id, IMMUNITY_EFFECT, effectType, apply);
+}
+
+bool SpellInfo::CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInfo) const
+{
+ if (!auraSpellInfo)
+ return false;
+
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- if (Effects[i].Effect == SPELL_EFFECT_APPLY_AURA)
+ ImmunityInfo const* immuneInfo = _immunityInfo + i;
+
+ if (!auraSpellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
{
- switch (Effects[i].ApplyAuraName)
+ if (uint32 schoolImmunity = immuneInfo->SchoolImmuneMask)
+ if ((auraSpellInfo->SchoolMask & schoolImmunity) != 0)
+ return true;
+ }
+
+ if (uint32 mechanicImmunity = immuneInfo->MechanicImmuneMask)
+ if ((mechanicImmunity & (1 << auraSpellInfo->Mechanic)) != 0)
+ return true;
+
+ if (uint32 dispelImmunity = immuneInfo->DispelImmune)
+ if (auraSpellInfo->Dispel == dispelImmunity)
+ return true;
+
+ bool immuneToAllEffects = true;
+ for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
+ {
+ uint32 effectName = auraSpellInfo->Effects[effIndex].Effect;
+ if (!effectName)
+ continue;
+
+ auto spellImmuneItr = immuneInfo->SpellEffectImmune.find(static_cast<SpellEffects>(effectName));
+ if (spellImmuneItr == immuneInfo->SpellEffectImmune.cend())
{
- case SPELL_AURA_MOD_CHARM:
- case SPELL_AURA_MOD_POSSESS_PET:
- case SPELL_AURA_MOD_POSSESS:
- case SPELL_AURA_AOE_CHARM:
- return SPELL_SPECIFIC_CHARM;
- case SPELL_AURA_TRACK_CREATURES:
- /// @workaround For non-stacking tracking spells (We need generic solution)
- if (Id == 30645) // Gas Cloud Tracking
- return SPELL_SPECIFIC_NORMAL;
- case SPELL_AURA_TRACK_RESOURCES:
- case SPELL_AURA_TRACK_STEALTHED:
- return SPELL_SPECIFIC_TRACKER;
+ immuneToAllEffects = false;
+ break;
+ }
+
+ if (uint32 mechanic = auraSpellInfo->Effects[effIndex].Mechanic)
+ {
+ if (!(immuneInfo->MechanicImmuneMask & (1 << mechanic)))
+ {
+ immuneToAllEffects = false;
+ break;
+ }
}
+
+ if (!auraSpellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
+ {
+ if (uint32 auraName = auraSpellInfo->Effects[effIndex].ApplyAuraName)
+ {
+ bool isImmuneToAuraEffectApply = false;
+ auto auraImmuneItr = immuneInfo->AuraTypeImmune.find(static_cast<AuraType>(auraName));
+ if (auraImmuneItr != immuneInfo->AuraTypeImmune.cend())
+ isImmuneToAuraEffectApply = true;
+
+ if (!isImmuneToAuraEffectApply && !auraSpellInfo->IsPositiveEffect(effIndex) && !auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
+ {
+ if (uint32 applyHarmfulAuraImmunityMask = immuneInfo->ApplyHarmfulAuraImmuneMask)
+ if ((auraSpellInfo->GetSchoolMask() & applyHarmfulAuraImmunityMask) != 0)
+ isImmuneToAuraEffectApply = true;
+ }
+
+ if (!isImmuneToAuraEffectApply)
+ {
+ immuneToAllEffects = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if (immuneToAllEffects)
+ return true;
+ }
+
+ return false;
+}
+
+// based on client sub_007FDFA0
+bool SpellInfo::CanSpellCastOverrideAuraEffect(SpellInfo const* auraSpellInfo, uint8 auraEffIndex) const
+{
+ if (!HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ return false;
+
+ if (auraSpellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
+ return false;
+
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (Effects[i].Effect != SPELL_EFFECT_APPLY_AURA)
+ continue;
+
+ uint32 const miscValue = static_cast<uint32>(Effects[i].MiscValue);
+ switch (Effects[i].ApplyAuraName)
+ {
+ case SPELL_AURA_STATE_IMMUNITY:
+ if (miscValue != auraSpellInfo->Effects[auraEffIndex].ApplyAuraName)
+ continue;
+ break;
+ case SPELL_AURA_SCHOOL_IMMUNITY:
+ case SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL:
+ if (auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE) || !(auraSpellInfo->SchoolMask & miscValue))
+ continue;
+ break;
+ case SPELL_AURA_DISPEL_IMMUNITY:
+ if (miscValue != auraSpellInfo->Dispel)
+ continue;
+ break;
+ case SPELL_AURA_MECHANIC_IMMUNITY:
+ if (miscValue != auraSpellInfo->Mechanic)
+ {
+ if (miscValue != auraSpellInfo->Effects[auraEffIndex].Mechanic)
+ continue;
+ }
+ break;
+ default:
+ continue;
}
+
+ return true;
}
- return SPELL_SPECIFIC_NORMAL;
+ return false;
}
float SpellInfo::GetMinRange(bool positive) const
@@ -2106,7 +2961,7 @@ float SpellInfo::GetMaxRange(bool positive, Unit* caster, Spell* spell) const
range = RangeEntry->maxRangeHostile;
if (caster)
if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(Id, SPELLMOD_RANGE, range, spell);
+ modOwner->ApplySpellMod<SPELLMOD_RANGE>(Id, range, spell);
return range;
}
@@ -2252,7 +3107,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) c
// Apply cost mod by spell
if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(Id, SPELLMOD_COST, powerCost);
+ modOwner->ApplySpellMod<SPELLMOD_COST>(Id, powerCost);
if (!caster->IsControlledByPlayer())
{
@@ -2430,9 +3285,12 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const
// Amplify Magic, Dampen Magic
if (SpellFamilyFlags[0] == 0x00002000)
return true;
- // Ignite
+ // Impact
if (SpellIconID == 45)
return true;
+ // Arcane Missiles
+ if (SpellFamilyFlags[0] == 0x00000800)
+ return false;
break;
case SPELLFAMILY_PRIEST:
switch (Id)
@@ -2462,6 +3320,9 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const
case 32684: // Envenom (Rank 2)
case 57992: // Envenom (Rank 3)
case 57993: // Envenom (Rank 4)
+ // Slice and Dice. Prevents breaking Stealth
+ case 5171: // Slice and Dice (Rank 1)
+ case 6774: // Slice and Dice (Rank 2)
return true;
default:
break;
@@ -2482,8 +3343,16 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const
// Special case: effects which determine positivity of whole spell
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- if (Effects[i].IsAura() && Effects[i].ApplyAuraName == SPELL_AURA_MOD_STEALTH)
- return true;
+ if (Effects[i].IsAura())
+ {
+ switch (Effects[i].ApplyAuraName)
+ {
+ case SPELL_AURA_MOD_STEALTH:
+ return true;
+ case SPELL_AURA_CHANNEL_DEATH_ITEM:
+ return false;
+ }
+ }
}
switch (Effects[effIndex].Effect)
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 589ed16e409..d7b48ddb4d2 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -24,10 +24,13 @@
#include "Object.h"
#include "SpellAuraDefines.h"
+#include <boost/container/flat_set.hpp>
+
class Unit;
class Player;
class Item;
class Spell;
+class SpellMgr;
class SpellInfo;
struct SpellChainNode;
struct SpellTargetPosition;
@@ -291,201 +294,252 @@ private:
static StaticData _data[TOTAL_SPELL_EFFECTS];
};
+struct TC_GAME_API SpellDiminishInfo
+{
+ DiminishingGroup DiminishGroup = DIMINISHING_NONE;
+ DiminishingReturnsType DiminishReturnType = DRTYPE_NONE;
+ DiminishingLevels DiminishMaxLevel = DIMINISHING_LEVEL_IMMUNE;
+ int32 DiminishDurationLimit = 0;
+};
+
+struct TC_GAME_API ImmunityInfo
+{
+ uint32 SchoolImmuneMask = 0;
+ uint32 ApplyHarmfulAuraImmuneMask = 0;
+ uint32 MechanicImmuneMask = 0;
+ uint32 DispelImmune = 0;
+ uint32 DamageSchoolMask = 0;
+
+ boost::container::flat_set<AuraType> AuraTypeImmune;
+ boost::container::flat_set<SpellEffects> SpellEffectImmune;
+};
+
class TC_GAME_API SpellInfo
{
-public:
- uint32 Id;
- SpellCategoryEntry const* CategoryEntry;
- uint32 Dispel;
- uint32 Mechanic;
- uint32 Attributes;
- uint32 AttributesEx;
- uint32 AttributesEx2;
- uint32 AttributesEx3;
- uint32 AttributesEx4;
- uint32 AttributesEx5;
- uint32 AttributesEx6;
- uint32 AttributesEx7;
- uint32 AttributesCu;
- uint64 Stances;
- uint64 StancesNot;
- uint32 Targets;
- uint32 TargetCreatureType;
- uint32 RequiresSpellFocus;
- uint32 FacingCasterFlags;
- uint32 CasterAuraState;
- uint32 TargetAuraState;
- uint32 CasterAuraStateNot;
- uint32 TargetAuraStateNot;
- uint32 CasterAuraSpell;
- uint32 TargetAuraSpell;
- uint32 ExcludeCasterAuraSpell;
- uint32 ExcludeTargetAuraSpell;
- SpellCastTimesEntry const* CastTimeEntry;
- uint32 RecoveryTime;
- uint32 CategoryRecoveryTime;
- uint32 StartRecoveryCategory;
- uint32 StartRecoveryTime;
- uint32 InterruptFlags;
- uint32 AuraInterruptFlags;
- uint32 ChannelInterruptFlags;
- uint32 ProcFlags;
- uint32 ProcChance;
- uint32 ProcCharges;
- uint32 MaxLevel;
- uint32 BaseLevel;
- uint32 SpellLevel;
- SpellDurationEntry const* DurationEntry;
- uint32 PowerType;
- uint32 ManaCost;
- uint32 ManaCostPerlevel;
- uint32 ManaPerSecond;
- uint32 ManaPerSecondPerLevel;
- uint32 ManaCostPercentage;
- uint32 RuneCostID;
- SpellRangeEntry const* RangeEntry;
- float Speed;
- uint32 StackAmount;
- uint32 Totem[2];
- int32 Reagent[MAX_SPELL_REAGENTS];
- uint32 ReagentCount[MAX_SPELL_REAGENTS];
- int32 EquippedItemClass;
- int32 EquippedItemSubClassMask;
- int32 EquippedItemInventoryTypeMask;
- uint32 TotemCategory[2];
- uint32 SpellVisual[2];
- uint32 SpellIconID;
- uint32 ActiveIconID;
- char* SpellName[16];
- char* Rank[16];
- uint32 MaxTargetLevel;
- uint32 MaxAffectedTargets;
- uint32 SpellFamilyName;
- flag96 SpellFamilyFlags;
- uint32 DmgClass;
- uint32 PreventionType;
- int32 AreaGroupId;
- uint32 SchoolMask;
- SpellEffectInfo Effects[MAX_SPELL_EFFECTS];
- uint32 ExplicitTargetMask;
- SpellChainNode const* ChainEntry;
-
- SpellInfo(SpellEntry const* spellEntry);
- ~SpellInfo();
-
- uint32 GetCategory() const;
- bool HasEffect(SpellEffects effect) const;
- bool HasAura(AuraType aura) const;
- bool HasAreaAuraEffect() const;
-
- inline bool HasAttribute(SpellAttr0 attribute) const { return !!(Attributes & attribute); }
- inline bool HasAttribute(SpellAttr1 attribute) const { return !!(AttributesEx & attribute); }
- inline bool HasAttribute(SpellAttr2 attribute) const { return !!(AttributesEx2 & attribute); }
- inline bool HasAttribute(SpellAttr3 attribute) const { return !!(AttributesEx3 & attribute); }
- inline bool HasAttribute(SpellAttr4 attribute) const { return !!(AttributesEx4 & attribute); }
- inline bool HasAttribute(SpellAttr5 attribute) const { return !!(AttributesEx5 & attribute); }
- inline bool HasAttribute(SpellAttr6 attribute) const { return !!(AttributesEx6 & attribute); }
- inline bool HasAttribute(SpellAttr7 attribute) const { return !!(AttributesEx7 & attribute); }
- inline bool HasAttribute(SpellCustomAttributes customAttribute) const { return !!(AttributesCu & customAttribute); }
-
- bool IsExplicitDiscovery() const;
- bool IsLootCrafting() const;
- bool IsQuestTame() const;
- bool IsProfessionOrRiding() const;
- bool IsProfession() const;
- bool IsPrimaryProfession() const;
- bool IsPrimaryProfessionFirstRank() const;
- bool IsAbilityLearnedWithProfession() const;
- bool IsAbilityOfSkillType(uint32 skillType) const;
-
- bool IsAffectingArea() const;
- bool IsTargetingArea() const;
- bool NeedsExplicitUnitTarget() const;
- bool NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell) const;
-
- bool IsPassive() const;
- bool IsAutocastable() const;
- bool IsStackableWithRanks() const;
- bool IsPassiveStackableWithRanks() const;
- bool IsMultiSlotAura() const;
- bool IsStackableOnOneSlotWithDifferentCasters() const;
- bool IsCooldownStartedOnEvent() const;
- bool IsDeathPersistent() const;
- bool IsRequiringDeadTarget() const;
- bool IsAllowingDeadTarget() const;
- bool IsGroupBuff() const;
- bool CanBeUsedInCombat() const;
- bool IsPositive() const;
- bool IsPositiveEffect(uint8 effIndex) const;
- bool IsChanneled() const;
- bool NeedsComboPoints() const;
- bool IsBreakingStealth() const;
- bool IsRangedWeaponSpell() const;
- bool IsAutoRepeatRangedSpell() const;
- bool HasInitialAggro() const;
-
- bool IsAffectedBySpellMods() const;
- bool IsAffectedBySpellMod(SpellModifier const* mod) const;
-
- bool CanPierceImmuneAura(SpellInfo const* aura) const;
- bool CanDispelAura(SpellInfo const* aura) const;
-
- bool IsSingleTarget() const;
- bool IsAuraExclusiveBySpecificWith(SpellInfo const* spellInfo) const;
- bool IsAuraExclusiveBySpecificPerCasterWith(SpellInfo const* spellInfo) const;
-
- SpellCastResult CheckShapeshift(uint32 form) const;
- SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL) const;
- SpellCastResult CheckTarget(Unit const* caster, WorldObject const* target, bool implicit = true) const;
- SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = NULL) const;
- SpellCastResult CheckVehicle(Unit const* caster) const;
- bool CheckTargetCreatureType(Unit const* target) const;
-
- SpellSchoolMask GetSchoolMask() const;
- uint32 GetAllEffectsMechanicMask() const;
- uint32 GetEffectMechanicMask(uint8 effIndex) const;
- uint32 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const;
- Mechanics GetEffectMechanic(uint8 effIndex) const;
- bool HasAnyEffectMechanic() const;
- uint32 GetDispelMask() const;
- static uint32 GetDispelMask(DispelType type);
- uint32 GetExplicitTargetMask() const;
-
- AuraStateType GetAuraState() const;
- SpellSpecificType GetSpellSpecific() const;
-
- float GetMinRange(bool positive = false) const;
- float GetMaxRange(bool positive = false, Unit* caster = NULL, Spell* spell = NULL) const;
-
- int32 GetDuration() const;
- int32 GetMaxDuration() const;
-
- uint32 GetMaxTicks() const;
-
- uint32 CalcCastTime(Spell* spell = NULL) const;
- uint32 GetRecoveryTime() const;
-
- int32 CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const;
-
- bool IsRanked() const;
- uint8 GetRank() const;
- SpellInfo const* GetFirstRankSpell() const;
- SpellInfo const* GetLastRankSpell() const;
- SpellInfo const* GetNextRankSpell() const;
- SpellInfo const* GetPrevRankSpell() const;
- SpellInfo const* GetAuraRankForLevel(uint8 level) const;
- bool IsRankOf(SpellInfo const* spellInfo) const;
- bool IsDifferentRankOf(SpellInfo const* spellInfo) const;
- bool IsHighRankOf(SpellInfo const* spellInfo) const;
-
- // loading helpers
- void _InitializeExplicitTargetMask();
- bool _IsPositiveEffect(uint8 effIndex, bool deep) const;
- bool _IsPositiveSpell() const;
- static bool _IsPositiveTarget(uint32 targetA, uint32 targetB);
-
- // unloading helpers
- void _UnloadImplicitTargetConditionLists();
+ friend class SpellMgr;
+
+ public:
+ uint32 Id;
+ SpellCategoryEntry const* CategoryEntry;
+ uint32 Dispel;
+ uint32 Mechanic;
+ uint32 Attributes;
+ uint32 AttributesEx;
+ uint32 AttributesEx2;
+ uint32 AttributesEx3;
+ uint32 AttributesEx4;
+ uint32 AttributesEx5;
+ uint32 AttributesEx6;
+ uint32 AttributesEx7;
+ uint32 AttributesCu;
+ uint64 Stances;
+ uint64 StancesNot;
+ uint32 Targets;
+ uint32 TargetCreatureType;
+ uint32 RequiresSpellFocus;
+ uint32 FacingCasterFlags;
+ uint32 CasterAuraState;
+ uint32 TargetAuraState;
+ uint32 CasterAuraStateNot;
+ uint32 TargetAuraStateNot;
+ uint32 CasterAuraSpell;
+ uint32 TargetAuraSpell;
+ uint32 ExcludeCasterAuraSpell;
+ uint32 ExcludeTargetAuraSpell;
+ SpellCastTimesEntry const* CastTimeEntry;
+ uint32 RecoveryTime;
+ uint32 CategoryRecoveryTime;
+ uint32 StartRecoveryCategory;
+ uint32 StartRecoveryTime;
+ uint32 InterruptFlags;
+ uint32 AuraInterruptFlags;
+ uint32 ChannelInterruptFlags;
+ uint32 ProcFlags;
+ uint32 ProcChance;
+ uint32 ProcCharges;
+ uint32 MaxLevel;
+ uint32 BaseLevel;
+ uint32 SpellLevel;
+ SpellDurationEntry const* DurationEntry;
+ uint32 PowerType;
+ uint32 ManaCost;
+ uint32 ManaCostPerlevel;
+ uint32 ManaPerSecond;
+ uint32 ManaPerSecondPerLevel;
+ uint32 ManaCostPercentage;
+ uint32 RuneCostID;
+ SpellRangeEntry const* RangeEntry;
+ float Speed;
+ uint32 StackAmount;
+ uint32 Totem[2];
+ int32 Reagent[MAX_SPELL_REAGENTS];
+ uint32 ReagentCount[MAX_SPELL_REAGENTS];
+ int32 EquippedItemClass;
+ int32 EquippedItemSubClassMask;
+ int32 EquippedItemInventoryTypeMask;
+ uint32 TotemCategory[2];
+ uint32 SpellVisual[2];
+ uint32 SpellIconID;
+ uint32 ActiveIconID;
+ char* SpellName[16];
+ char* Rank[16];
+ uint32 MaxTargetLevel;
+ uint32 MaxAffectedTargets;
+ uint32 SpellFamilyName;
+ flag96 SpellFamilyFlags;
+ uint32 DmgClass;
+ uint32 PreventionType;
+ int32 AreaGroupId;
+ uint32 SchoolMask;
+ SpellEffectInfo Effects[MAX_SPELL_EFFECTS];
+ uint32 ExplicitTargetMask;
+ SpellChainNode const* ChainEntry;
+
+ SpellInfo(SpellEntry const* spellEntry);
+ ~SpellInfo();
+
+ uint32 GetCategory() const;
+ bool HasEffect(SpellEffects effect) const;
+ bool HasAura(AuraType aura) const;
+ bool HasAreaAuraEffect() const;
+ bool HasOnlyDamageEffects() const;
+
+ inline bool HasAttribute(SpellAttr0 attribute) const { return !!(Attributes & attribute); }
+ inline bool HasAttribute(SpellAttr1 attribute) const { return !!(AttributesEx & attribute); }
+ inline bool HasAttribute(SpellAttr2 attribute) const { return !!(AttributesEx2 & attribute); }
+ inline bool HasAttribute(SpellAttr3 attribute) const { return !!(AttributesEx3 & attribute); }
+ inline bool HasAttribute(SpellAttr4 attribute) const { return !!(AttributesEx4 & attribute); }
+ inline bool HasAttribute(SpellAttr5 attribute) const { return !!(AttributesEx5 & attribute); }
+ inline bool HasAttribute(SpellAttr6 attribute) const { return !!(AttributesEx6 & attribute); }
+ inline bool HasAttribute(SpellAttr7 attribute) const { return !!(AttributesEx7 & attribute); }
+ inline bool HasAttribute(SpellCustomAttributes customAttribute) const { return !!(AttributesCu & customAttribute); }
+
+ bool IsExplicitDiscovery() const;
+ bool IsLootCrafting() const;
+ bool IsQuestTame() const;
+ bool IsProfessionOrRiding() const;
+ bool IsProfession() const;
+ bool IsPrimaryProfession() const;
+ bool IsPrimaryProfessionFirstRank() const;
+ bool IsAbilityLearnedWithProfession() const;
+ bool IsAbilityOfSkillType(uint32 skillType) const;
+
+ bool IsAffectingArea() const;
+ bool IsTargetingArea() const;
+ bool NeedsExplicitUnitTarget() const;
+ bool NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell) const;
+
+ bool IsPassive() const;
+ bool IsAutocastable() const;
+ bool IsStackableWithRanks() const;
+ bool IsPassiveStackableWithRanks() const;
+ bool IsMultiSlotAura() const;
+ bool IsStackableOnOneSlotWithDifferentCasters() const;
+ bool IsCooldownStartedOnEvent() const;
+ bool IsDeathPersistent() const;
+ bool IsRequiringDeadTarget() const;
+ bool IsAllowingDeadTarget() const;
+ bool IsGroupBuff() const;
+ bool CanBeUsedInCombat() const;
+ bool IsPositive() const;
+ bool IsPositiveEffect(uint8 effIndex) const;
+ bool IsChanneled() const;
+ bool IsMoveAllowedChannel() const;
+ bool NeedsComboPoints() const;
+ bool IsNextMeleeSwingSpell() const;
+ bool IsBreakingStealth() const;
+ bool IsRangedWeaponSpell() const;
+ bool IsAutoRepeatRangedSpell() const;
+ bool HasInitialAggro() const;
+
+ bool IsAffected(uint32 familyName, flag96 const& familyFlags) const;
+
+ bool IsAffectedBySpellMods() const;
+ bool IsAffectedBySpellMod(SpellModifier const* mod) const;
+
+ bool CanPierceImmuneAura(SpellInfo const* auraSpellInfo) const;
+ bool CanDispelAura(SpellInfo const* auraSpellInfo) const;
+
+ bool IsSingleTarget() const;
+ bool IsAuraExclusiveBySpecificWith(SpellInfo const* spellInfo) const;
+ bool IsAuraExclusiveBySpecificPerCasterWith(SpellInfo const* spellInfo) const;
+
+ SpellCastResult CheckShapeshift(uint32 form) const;
+ SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL) const;
+ SpellCastResult CheckTarget(Unit const* caster, WorldObject const* target, bool implicit = true) const;
+ SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = NULL) const;
+ SpellCastResult CheckVehicle(Unit const* caster) const;
+ bool CheckTargetCreatureType(Unit const* target) const;
+
+ SpellSchoolMask GetSchoolMask() const;
+ uint32 GetAllEffectsMechanicMask() const;
+ uint32 GetEffectMechanicMask(uint8 effIndex) const;
+ uint32 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const;
+ Mechanics GetEffectMechanic(uint8 effIndex) const;
+ bool HasAnyEffectMechanic() const;
+ uint32 GetDispelMask() const;
+ static uint32 GetDispelMask(DispelType type);
+ uint32 GetExplicitTargetMask() const;
+
+ AuraStateType GetAuraState() const;
+ SpellSpecificType GetSpellSpecific() const;
+
+ float GetMinRange(bool positive = false) const;
+ float GetMaxRange(bool positive = false, Unit* caster = NULL, Spell* spell = NULL) const;
+
+ int32 GetDuration() const;
+ int32 GetMaxDuration() const;
+
+ uint32 GetMaxTicks() const;
+
+ uint32 CalcCastTime(Spell* spell = NULL) const;
+ uint32 GetRecoveryTime() const;
+
+ int32 CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const;
+
+ bool IsRanked() const;
+ uint8 GetRank() const;
+ SpellInfo const* GetFirstRankSpell() const;
+ SpellInfo const* GetLastRankSpell() const;
+ SpellInfo const* GetNextRankSpell() const;
+ SpellInfo const* GetPrevRankSpell() const;
+ SpellInfo const* GetAuraRankForLevel(uint8 level) const;
+ bool IsRankOf(SpellInfo const* spellInfo) const;
+ bool IsDifferentRankOf(SpellInfo const* spellInfo) const;
+ bool IsHighRankOf(SpellInfo const* spellInfo) const;
+
+ // spell diminishing returns
+ DiminishingGroup GetDiminishingReturnsGroupForSpell(bool triggered) const;
+ DiminishingReturnsType GetDiminishingReturnsGroupType(bool triggered) const;
+ DiminishingLevels GetDiminishingReturnsMaxLevel(bool triggered) const;
+ int32 GetDiminishingReturnsLimitDuration(bool triggered) const;
+
+ // spell immunities
+ void ApplyAllSpellImmunitiesTo(Unit* target, uint8 effIndex, bool apply) const;
+ bool CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInfo) const;
+ bool CanSpellCastOverrideAuraEffect(SpellInfo const* auraSpellInfo, uint8 auraEffIndex) const;
+
+ private:
+ // loading helpers
+ void _InitializeExplicitTargetMask();
+ bool _IsPositiveEffect(uint8 effIndex, bool deep) const;
+ bool _IsPositiveSpell() const;
+ static bool _IsPositiveTarget(uint32 targetA, uint32 targetB);
+ void _LoadSpellSpecific();
+ void _LoadAuraState();
+ void _LoadSpellDiminishInfo();
+ void _LoadImmunityInfo();
+
+ // unloading helpers
+ void _UnloadImplicitTargetConditionLists();
+
+ SpellSpecificType _spellSpecific;
+ AuraStateType _auraState;
+
+ SpellDiminishInfo _diminishInfoNonTriggered;
+ SpellDiminishInfo _diminishInfoTriggered;
+
+ ImmunityInfo _immunityInfo[MAX_SPELL_EFFECTS];
};
#endif // _SPELLINFO_H
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index ccdda800bc0..bd13f1b2c7b 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -18,6 +18,7 @@
#include "SpellMgr.h"
#include "SpellInfo.h"
+#include "Spell.h"
#include "ObjectMgr.h"
#include "SpellAuraDefines.h"
#include "SharedDefines.h"
@@ -50,302 +51,6 @@ bool IsPartOfSkillLine(uint32 skillId, uint32 spellId)
return false;
}
-DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto, bool triggered)
-{
- if (spellproto->IsPositive())
- return DIMINISHING_NONE;
-
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
- if (spellproto->Effects[i].ApplyAuraName == SPELL_AURA_MOD_TAUNT)
- return DIMINISHING_TAUNT;
- }
-
- // Explicit Diminishing Groups
- switch (spellproto->SpellFamilyName)
- {
- case SPELLFAMILY_GENERIC:
- {
- // Pet charge effects (Infernal Awakening, Demon Charge)
- if (spellproto->SpellVisual[0] == 2816 && spellproto->SpellIconID == 15)
- return DIMINISHING_CONTROLLED_STUN;
- // Frost Tomb
- else if (spellproto->Id == 48400)
- return DIMINISHING_NONE;
- // Gnaw
- else if (spellproto->Id == 47481)
- return DIMINISHING_CONTROLLED_STUN;
- // ToC Icehowl Arctic Breath
- else if (spellproto->SpellVisual[0] == 14153)
- return DIMINISHING_NONE;
- // Black Plague
- else if (spellproto->Id == 64155)
- return DIMINISHING_NONE;
- // Screams of the Dead (King Ymiron)
- else if (spellproto->Id == 51750)
- return DIMINISHING_NONE;
- break;
- }
- // Event spells
- case SPELLFAMILY_UNK1:
- return DIMINISHING_NONE;
- case SPELLFAMILY_MAGE:
- {
- // Frostbite
- if (spellproto->SpellFamilyFlags[1] & 0x80000000)
- return DIMINISHING_ROOT;
- // Shattered Barrier
- else if (spellproto->SpellVisual[0] == 12297)
- return DIMINISHING_ROOT;
- // Deep Freeze
- else if (spellproto->SpellIconID == 2939 && spellproto->SpellVisual[0] == 9963)
- return DIMINISHING_CONTROLLED_STUN;
- // Frost Nova / Freeze (Water Elemental)
- else if (spellproto->SpellIconID == 193)
- return DIMINISHING_CONTROLLED_ROOT;
- // Dragon's Breath
- else if (spellproto->SpellFamilyFlags[0] & 0x800000)
- return DIMINISHING_DRAGONS_BREATH;
- break;
- }
- case SPELLFAMILY_WARRIOR:
- {
- // Hamstring - limit duration to 10s in PvP
- if (spellproto->SpellFamilyFlags[0] & 0x2)
- return DIMINISHING_LIMITONLY;
- // Charge Stun (own diminishing)
- else if (spellproto->SpellFamilyFlags[0] & 0x01000000)
- return DIMINISHING_CHARGE;
- break;
- }
- case SPELLFAMILY_WARLOCK:
- {
- // Curses/etc
- if ((spellproto->SpellFamilyFlags[0] & 0x80000000) || (spellproto->SpellFamilyFlags[1] & 0x200))
- return DIMINISHING_LIMITONLY;
- // Seduction
- else if (spellproto->SpellFamilyFlags[1] & 0x10000000)
- return DIMINISHING_FEAR;
- break;
- }
- case SPELLFAMILY_DRUID:
- {
- // Pounce
- if (spellproto->SpellFamilyFlags[0] & 0x20000)
- return DIMINISHING_OPENING_STUN;
- // Cyclone
- else if (spellproto->SpellFamilyFlags[1] & 0x20)
- return DIMINISHING_CYCLONE;
- // Entangling Roots
- // Nature's Grasp
- else if (spellproto->SpellFamilyFlags[0] & 0x00000200)
- return DIMINISHING_CONTROLLED_ROOT;
- // Faerie Fire
- else if (spellproto->SpellFamilyFlags[0] & 0x400)
- return DIMINISHING_LIMITONLY;
- break;
- }
- case SPELLFAMILY_ROGUE:
- {
- // Gouge
- if (spellproto->SpellFamilyFlags[0] & 0x8)
- return DIMINISHING_DISORIENT;
- // Blind
- else if (spellproto->SpellFamilyFlags[0] & 0x1000000)
- return DIMINISHING_FEAR;
- // Cheap Shot
- else if (spellproto->SpellFamilyFlags[0] & 0x400)
- return DIMINISHING_OPENING_STUN;
- // Crippling poison - Limit to 10 seconds in PvP (No SpellFamilyFlags)
- else if (spellproto->SpellIconID == 163)
- return DIMINISHING_LIMITONLY;
- break;
- }
- case SPELLFAMILY_HUNTER:
- {
- // Hunter's Mark
- if ((spellproto->SpellFamilyFlags[0] & 0x400) && spellproto->SpellIconID == 538)
- return DIMINISHING_LIMITONLY;
- // Scatter Shot (own diminishing)
- else if ((spellproto->SpellFamilyFlags[0] & 0x40000) && spellproto->SpellIconID == 132)
- return DIMINISHING_SCATTER_SHOT;
- // Entrapment (own diminishing)
- else if (spellproto->SpellVisual[0] == 7484 && spellproto->SpellIconID == 20)
- return DIMINISHING_ENTRAPMENT;
- // Wyvern Sting mechanic is MECHANIC_SLEEP but the diminishing is DIMINISHING_DISORIENT
- else if ((spellproto->SpellFamilyFlags[1] & 0x1000) && spellproto->SpellIconID == 1721)
- return DIMINISHING_DISORIENT;
- // Freezing Arrow
- else if (spellproto->SpellFamilyFlags[0] & 0x8)
- return DIMINISHING_DISORIENT;
- break;
- }
- case SPELLFAMILY_PALADIN:
- {
- // Judgement of Justice - limit duration to 10s in PvP
- if (spellproto->SpellFamilyFlags[0] & 0x100000)
- return DIMINISHING_LIMITONLY;
- // Turn Evil
- else if ((spellproto->SpellFamilyFlags[1] & 0x804000) && spellproto->SpellIconID == 309)
- return DIMINISHING_FEAR;
- break;
- }
- case SPELLFAMILY_SHAMAN:
- {
- // Storm, Earth and Fire - Earthgrab
- if (spellproto->SpellFamilyFlags[2] & 0x4000)
- return DIMINISHING_NONE;
- break;
- }
- case SPELLFAMILY_DEATHKNIGHT:
- {
- // Hungering Cold (no flags)
- if (spellproto->SpellIconID == 2797)
- return DIMINISHING_DISORIENT;
- // Mark of Blood
- else if ((spellproto->SpellFamilyFlags[0] & 0x10000000) && spellproto->SpellIconID == 2285)
- return DIMINISHING_LIMITONLY;
- break;
- }
- default:
- break;
- }
-
- // Lastly - Set diminishing depending on mechanic
- uint32 mechanic = spellproto->GetAllEffectsMechanicMask();
- if (mechanic & (1 << MECHANIC_CHARM))
- return DIMINISHING_MIND_CONTROL;
- if (mechanic & (1 << MECHANIC_SILENCE))
- return DIMINISHING_SILENCE;
- if (mechanic & (1 << MECHANIC_SLEEP))
- return DIMINISHING_SLEEP;
- if (mechanic & ((1 << MECHANIC_SAPPED) | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_SHACKLE)))
- return DIMINISHING_DISORIENT;
- // Mechanic Knockout, except Blast Wave
- if (mechanic & (1 << MECHANIC_KNOCKOUT) && spellproto->SpellIconID != 292)
- return DIMINISHING_DISORIENT;
- if (mechanic & (1 << MECHANIC_DISARM))
- return DIMINISHING_DISARM;
- if (mechanic & (1 << MECHANIC_FEAR))
- return DIMINISHING_FEAR;
- if (mechanic & (1 << MECHANIC_STUN))
- return triggered ? DIMINISHING_STUN : DIMINISHING_CONTROLLED_STUN;
- if (mechanic & (1 << MECHANIC_BANISH))
- return DIMINISHING_BANISH;
- if (mechanic & (1 << MECHANIC_ROOT))
- return triggered ? DIMINISHING_ROOT : DIMINISHING_CONTROLLED_ROOT;
- if (mechanic & (1 << MECHANIC_HORROR))
- return DIMINISHING_HORROR;
-
- return DIMINISHING_NONE;
-}
-
-DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group)
-{
- switch (group)
- {
- case DIMINISHING_TAUNT:
- case DIMINISHING_CONTROLLED_STUN:
- case DIMINISHING_STUN:
- case DIMINISHING_OPENING_STUN:
- case DIMINISHING_CYCLONE:
- case DIMINISHING_CHARGE:
- return DRTYPE_ALL;
- case DIMINISHING_LIMITONLY:
- case DIMINISHING_NONE:
- return DRTYPE_NONE;
- default:
- return DRTYPE_PLAYER;
- }
-}
-
-DiminishingLevels GetDiminishingReturnsMaxLevel(DiminishingGroup group)
-{
- switch (group)
- {
- case DIMINISHING_TAUNT:
- return DIMINISHING_LEVEL_TAUNT_IMMUNE;
- default:
- return DIMINISHING_LEVEL_IMMUNE;
- }
-}
-
-int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellInfo const* spellproto)
-{
- if (!IsDiminishingReturnsGroupDurationLimited(group))
- return 0;
-
- // Explicit diminishing duration
- switch (spellproto->SpellFamilyName)
- {
- case SPELLFAMILY_DRUID:
- {
- // Faerie Fire - limit to 40 seconds in PvP (3.1)
- if (spellproto->SpellFamilyFlags[0] & 0x400)
- return 40 * IN_MILLISECONDS;
- break;
- }
- case SPELLFAMILY_HUNTER:
- {
- // Wyvern Sting
- if (spellproto->SpellFamilyFlags[1] & 0x1000)
- return 6 * IN_MILLISECONDS;
- // Hunter's Mark
- if (spellproto->SpellFamilyFlags[0] & 0x400)
- return 120 * IN_MILLISECONDS;
- break;
- }
- case SPELLFAMILY_PALADIN:
- {
- // Repentance - limit to 6 seconds in PvP
- if (spellproto->SpellFamilyFlags[0] & 0x4)
- return 6 * IN_MILLISECONDS;
- break;
- }
- case SPELLFAMILY_WARLOCK:
- {
- // Banish - limit to 6 seconds in PvP
- if (spellproto->SpellFamilyFlags[1] & 0x8000000)
- return 6 * IN_MILLISECONDS;
- // Curse of Tongues - limit to 12 seconds in PvP
- else if (spellproto->SpellFamilyFlags[2] & 0x800)
- return 12 * IN_MILLISECONDS;
- // Curse of Elements - limit to 120 seconds in PvP
- else if (spellproto->SpellFamilyFlags[1] & 0x200)
- return 120 * IN_MILLISECONDS;
- break;
- }
- default:
- break;
- }
-
- return 10 * IN_MILLISECONDS;
-}
-
-bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group)
-{
- switch (group)
- {
- case DIMINISHING_BANISH:
- case DIMINISHING_CONTROLLED_STUN:
- case DIMINISHING_CONTROLLED_ROOT:
- case DIMINISHING_CYCLONE:
- case DIMINISHING_DISORIENT:
- case DIMINISHING_ENTRAPMENT:
- case DIMINISHING_FEAR:
- case DIMINISHING_HORROR:
- case DIMINISHING_MIND_CONTROL:
- case DIMINISHING_OPENING_STUN:
- case DIMINISHING_ROOT:
- case DIMINISHING_STUN:
- case DIMINISHING_SLEEP:
- case DIMINISHING_LIMITONLY:
- return true;
- default:
- return false;
- }
-}
-
SpellMgr::SpellMgr() { }
SpellMgr::~SpellMgr()
@@ -779,172 +484,6 @@ SpellGroupStackRule SpellMgr::GetSpellGroupStackRule(SpellGroup group) const
return SPELL_GROUP_STACK_RULE_DEFAULT;
}
-SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const
-{
- SpellProcEventMap::const_iterator itr = mSpellProcEventMap.find(spellId);
- if (itr != mSpellProcEventMap.end())
- return &itr->second;
- return NULL;
-}
-
-bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellInfo const* procSpell, uint32 procFlags, uint32 procExtra, bool active) const
-{
- // No extra req need
- uint32 procEvent_procEx = PROC_EX_NONE;
-
- // check prockFlags for condition
- if ((procFlags & EventProcFlag) == 0)
- return false;
-
- bool hasFamilyMask = false;
-
- /**
-
- * @brief Check auras procced by periodics
-
- *Only damaging Dots can proc auras with PROC_FLAG_TAKEN_DAMAGE
-
- *Only Dots can proc if ONLY has PROC_FLAG_DONE_PERIODIC or PROC_FLAG_TAKEN_PERIODIC.
-
- *Hots can proc if ONLY has PROC_FLAG_DONE_PERIODIC and spellfamily != 0
-
- *Only Dots can proc auras with PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG or PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG
-
- *Only Hots can proc auras with PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS or PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS
-
- *Only Dots can proc auras with PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG or PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG
-
- *Only Hots can proc auras with PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS or PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS
-
- * @param procSpell the spell proccing the aura
- * @param procFlags proc_flags of spellProc
- * @param procExtra proc_EX of procSpell
- * @param EventProcFlag proc_flags of aura to be procced
- * @param spellProto SpellInfo of aura to be procced
-
- */
-
- /// Quick Check - If PROC_FLAG_TAKEN_DAMAGE is set for aura and procSpell dealt damage, proc no matter what kind of spell that deals the damage.
- if (procFlags & PROC_FLAG_TAKEN_DAMAGE && EventProcFlag & PROC_FLAG_TAKEN_DAMAGE)
- return true;
-
- if (procFlags & PROC_FLAG_DONE_PERIODIC && EventProcFlag & PROC_FLAG_DONE_PERIODIC)
- {
- if (procExtra & PROC_EX_INTERNAL_HOT)
- {
- if (EventProcFlag == PROC_FLAG_DONE_PERIODIC)
- {
- /// no aura with only PROC_FLAG_DONE_PERIODIC and spellFamilyName == 0 can proc from a HOT.
- if (!spellProto->SpellFamilyName)
- return false;
- }
- /// Aura must have positive procflags for a HOT to proc
- else if (!(EventProcFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS)))
- return false;
- }
- /// Aura must have negative or neutral(PROC_FLAG_DONE_PERIODIC only) procflags for a DOT to proc
- /// Traps are negative spells but not always do damage (only hunter traps set PROC_FLAG_DONE_TRAP_ACTIVATION)
- else if (EventProcFlag != PROC_FLAG_DONE_PERIODIC)
- if (!(EventProcFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_DONE_TRAP_ACTIVATION)))
- return false;
- }
-
- if (procFlags & PROC_FLAG_TAKEN_PERIODIC && EventProcFlag & PROC_FLAG_TAKEN_PERIODIC)
- {
- if (procExtra & PROC_EX_INTERNAL_HOT)
- {
- /// No aura that only has PROC_FLAG_TAKEN_PERIODIC can proc from a HOT.
- if (EventProcFlag == PROC_FLAG_TAKEN_PERIODIC)
- return false;
- /// Aura must have positive procflags for a HOT to proc
- if (!(EventProcFlag & (PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS)))
- return false;
- }
- /// Aura must have negative or neutral(PROC_FLAG_TAKEN_PERIODIC only) procflags for a DOT to proc
- else if (EventProcFlag != PROC_FLAG_TAKEN_PERIODIC)
- if (!(EventProcFlag & (PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG)))
- return false;
- }
- // Trap casts are active by default
- if (procFlags & PROC_FLAG_DONE_TRAP_ACTIVATION)
- active = true;
-
- // Always trigger for this
- if (procFlags & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH))
- return true;
-
- if (spellProcEvent) // Exist event data
- {
- // Store extra req
- procEvent_procEx = spellProcEvent->procEx;
-
- // For melee triggers
- if (procSpell == NULL)
- {
- // Check (if set) for school (melee attack has Normal school)
- if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
- return false;
- }
- else // For spells need check school/spell family/family mask
- {
- // Check (if set) for school
- if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & procSpell->SchoolMask) == 0)
- return false;
-
- // Check (if set) for spellFamilyName
- if (spellProcEvent->spellFamilyName && (spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
- return false;
-
- // spellFamilyName is Ok need check for spellFamilyMask if present
- if (spellProcEvent->spellFamilyMask)
- {
- if (!(spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags))
- return false;
- hasFamilyMask = true;
- // Some spells are not considered as active even with spellfamilyflags set
- if (!(procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL))
- active = true;
- }
- }
- }
-
- if (procExtra & (PROC_EX_INTERNAL_REQ_FAMILY))
- {
- if (!hasFamilyMask)
- return false;
- }
-
- // Check for extra req (if none) and hit/crit
- if (procEvent_procEx == PROC_EX_NONE)
- {
- // No extra req, so can trigger only for hit/crit - spell has to be active
- if ((procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) && active)
- return true;
- }
- else // Passive spells hits here only if resist/reflect/immune/evade
- {
- if (procExtra & AURA_SPELL_PROC_EX_MASK)
- {
- // if spell marked as procing only from not active spells
- if (active && procEvent_procEx & PROC_EX_NOT_ACTIVE_SPELL)
- return false;
- // if spell marked as procing only from active spells
- if (!active && procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL)
- return false;
- // Exist req for PROC_EX_EX_TRIGGER_ALWAYS
- if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS)
- return true;
- // PROC_EX_NOT_ACTIVE_SPELL and PROC_EX_ONLY_ACTIVE_SPELL flags handle: if passed checks before
- if ((procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) && ((procEvent_procEx & (AURA_SPELL_PROC_EX_MASK)) == 0))
- return true;
- }
- // Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other)
- if (procEvent_procEx & procExtra)
- return true;
- }
- return false;
-}
-
SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const
{
SpellProcMap::const_iterator itr = mSpellProcMap.find(spellId);
@@ -953,7 +492,7 @@ SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const
return NULL;
}
-bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const
+bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo)
{
// proc type doesn't match
if (!(eventInfo.GetTypeMask() & procEntry.ProcFlags))
@@ -965,29 +504,44 @@ bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcE
if (eventInfo.GetActionTarget() && !actor->isHonorOrXPTarget(eventInfo.GetActionTarget()))
return false;
+ // check mana requirement
+ if (procEntry.AttributesMask & PROC_ATTR_REQ_MANA_COST)
+ if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo())
+ if (!eventSpellInfo->ManaCost && !eventSpellInfo->ManaCostPercentage)
+ return false;
+
// always trigger for these types
if (eventInfo.GetTypeMask() & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH))
return true;
+ // do triggered cast checks
+ // Do not consider autoattacks as triggered spells
+ if (!(procEntry.AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC) && !(eventInfo.GetTypeMask() & AUTO_ATTACK_PROC_FLAG_MASK))
+ {
+ if (Spell const* spell = eventInfo.GetProcSpell())
+ {
+ if (spell->IsTriggered())
+ {
+ SpellInfo const* spellInfo = spell->GetSpellInfo();
+ if (!spellInfo->HasAttribute(SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2) &&
+ !spellInfo->HasAttribute(SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC))
+ return false;
+ }
+ }
+ }
+
// check school mask (if set) for other trigger types
if (procEntry.SchoolMask && !(eventInfo.GetSchoolMask() & procEntry.SchoolMask))
return false;
// check spell family name/flags (if set) for spells
- if (eventInfo.GetTypeMask() & (PERIODIC_PROC_FLAG_MASK | SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION))
+ if (eventInfo.GetTypeMask() & (PERIODIC_PROC_FLAG_MASK | SPELL_PROC_FLAG_MASK))
{
- SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo();
-
- if (procEntry.SpellFamilyName && eventSpellInfo && (procEntry.SpellFamilyName != eventSpellInfo->SpellFamilyName))
- return false;
-
- if (procEntry.SpellFamilyMask && eventSpellInfo && !(procEntry.SpellFamilyMask & eventSpellInfo->SpellFamilyFlags))
- return false;
- }
+ if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo())
+ if (!eventSpellInfo->IsAffected(procEntry.SpellFamilyName, procEntry.SpellFamilyMask))
+ return false;
- // check spell type mask (if set)
- if (eventInfo.GetTypeMask() & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))
- {
+ // check spell type mask (if set)
if (procEntry.SpellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.SpellTypeMask))
return false;
}
@@ -1487,29 +1041,38 @@ void SpellMgr::LoadSpellLearnSkills()
// search auto-learned skills and add its to map also for use in unlearn spells/talents
uint32 dbc_count = 0;
- for (uint32 spell = 0; spell < GetSpellInfoStoreSize(); ++spell)
+ for (SpellInfo const* entry : mSpellInfoMap)
{
- SpellInfo const* entry = GetSpellInfo(spell);
-
if (!entry)
continue;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- if (entry->Effects[i].Effect == SPELL_EFFECT_SKILL)
+ SpellLearnSkillNode dbc_node;
+ switch (entry->Effects[i].Effect)
{
- SpellLearnSkillNode dbc_node;
- dbc_node.skill = entry->Effects[i].MiscValue;
- dbc_node.step = entry->Effects[i].CalcValue();
- if (dbc_node.skill != SKILL_RIDING)
+ case SPELL_EFFECT_SKILL:
+ dbc_node.skill = entry->Effects[i].MiscValue;
+ dbc_node.step = entry->Effects[i].CalcValue();
+ if (dbc_node.skill != SKILL_RIDING)
+ dbc_node.value = 1;
+ else
+ dbc_node.value = dbc_node.step * 75;
+ dbc_node.maxvalue = dbc_node.step * 75;
+ break;
+ case SPELL_EFFECT_DUAL_WIELD:
+ dbc_node.skill = SKILL_DUAL_WIELD;
+ dbc_node.step = 1;
dbc_node.value = 1;
- else
- dbc_node.value = dbc_node.step * 75;
- dbc_node.maxvalue = dbc_node.step * 75;
- mSpellLearnSkills[spell] = dbc_node;
- ++dbc_count;
- break;
+ dbc_node.maxvalue = 1;
+ break;
+ default:
+ continue;
}
+
+ mSpellLearnSkills[entry->Id] = dbc_node;
+ ++dbc_count;
+ break;
}
}
@@ -1842,224 +1405,301 @@ void SpellMgr::LoadSpellGroupStackRules()
TC_LOG_INFO("server.loading", ">> Loaded %u spell group stack rules in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
-void SpellMgr::LoadSpellProcEvents()
+void SpellMgr::LoadSpellProcs()
{
uint32 oldMSTime = getMSTime();
- mSpellProcEventMap.clear(); // need for reload case
+ mSpellProcMap.clear(); // need for reload case
- // 0 1 2 3 4 5 6 7 8 9 10
- QueryResult result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
- if (!result)
- {
- TC_LOG_INFO("server.loading", ">> Loaded 0 spell proc event conditions. DB table `spell_proc_event` is empty.");
- return;
- }
+ // 0 1 2 3 4 5
+ QueryResult result = WorldDatabase.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, "
+ // 6 7 8 9 10 11 12 13 14
+ "ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc");
uint32 count = 0;
-
- do
+ if (result)
{
- Field* fields = result->Fetch();
-
- int32 spellId = fields[0].GetInt32();
-
- bool allRanks = false;
- if (spellId < 0)
- {
- allRanks = true;
- spellId = -spellId;
- }
-
- SpellInfo const* spellInfo = GetSpellInfo(spellId);
- if (!spellInfo)
+ do
{
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` does not exist.", spellId);
- continue;
- }
+ Field* fields = result->Fetch();
- if (allRanks)
- {
- if (!spellInfo->IsRanked())
- TC_LOG_ERROR("sql.sql", "The spell %u is listed in `spell_proc_event` with all ranks, but spell has no ranks.", spellId);
+ int32 spellId = fields[0].GetInt32();
- if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
+ bool allRanks = false;
+ if (spellId < 0)
{
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` is not first rank of spell.", spellId);
- continue;
+ allRanks = true;
+ spellId = -spellId;
}
- }
-
- SpellProcEventEntry spellProcEvent;
- spellProcEvent.schoolMask = fields[1].GetInt8();
- spellProcEvent.spellFamilyName = fields[2].GetUInt16();
- spellProcEvent.spellFamilyMask[0] = fields[3].GetUInt32();
- spellProcEvent.spellFamilyMask[1] = fields[4].GetUInt32();
- spellProcEvent.spellFamilyMask[2] = fields[5].GetUInt32();
- spellProcEvent.procFlags = fields[6].GetUInt32();
- spellProcEvent.procEx = fields[7].GetUInt32();
- spellProcEvent.ppmRate = fields[8].GetFloat();
- spellProcEvent.customChance = fields[9].GetFloat();
- spellProcEvent.cooldown = fields[10].GetUInt32();
-
- while (spellInfo)
- {
- if (mSpellProcEventMap.find(spellInfo->Id) != mSpellProcEventMap.end())
+ SpellInfo const* spellInfo = GetSpellInfo(spellId);
+ if (!spellInfo)
{
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` already has its first rank in table.", spellInfo->Id);
- break;
+ TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` does not exist", spellId);
+ continue;
}
- if (!spellInfo->ProcFlags && !spellProcEvent.procFlags)
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` is probably not a triggered spell.", spellInfo->Id);
-
- mSpellProcEventMap[spellInfo->Id] = spellProcEvent;
-
if (allRanks)
- spellInfo = spellInfo->GetNextRankSpell();
- else
- break;
- }
+ {
+ if (!spellInfo->IsRanked())
+ TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` with all ranks, but spell has no ranks.", spellId);
- ++count;
- }
- while (result->NextRow());
+ if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
+ {
+ TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` is not the first rank of the spell.", spellId);
+ continue;
+ }
+ }
- TC_LOG_INFO("server.loading", ">> Loaded %u extra spell proc event conditions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
-}
+ SpellProcEntry baseProcEntry;
+
+ baseProcEntry.SchoolMask = fields[1].GetInt8();
+ baseProcEntry.SpellFamilyName = fields[2].GetUInt16();
+ baseProcEntry.SpellFamilyMask[0] = fields[3].GetUInt32();
+ baseProcEntry.SpellFamilyMask[1] = fields[4].GetUInt32();
+ baseProcEntry.SpellFamilyMask[2] = fields[5].GetUInt32();
+ baseProcEntry.ProcFlags = fields[6].GetUInt32();
+ baseProcEntry.SpellTypeMask = fields[7].GetUInt32();
+ baseProcEntry.SpellPhaseMask = fields[8].GetUInt32();
+ baseProcEntry.HitMask = fields[9].GetUInt32();
+ baseProcEntry.AttributesMask = fields[10].GetUInt32();
+ baseProcEntry.ProcsPerMinute = fields[11].GetFloat();
+ baseProcEntry.Chance = fields[12].GetFloat();
+ baseProcEntry.Cooldown = Milliseconds(fields[13].GetUInt32());
+ baseProcEntry.Charges = fields[14].GetUInt8();
+
+ while (spellInfo)
+ {
+ if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
+ {
+ TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` already has its first rank in the table.", spellInfo->Id);
+ break;
+ }
-void SpellMgr::LoadSpellProcs()
-{
- uint32 oldMSTime = getMSTime();
+ SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);
+
+ // take defaults from dbcs
+ if (!procEntry.ProcFlags)
+ procEntry.ProcFlags = spellInfo->ProcFlags;
+ if (!procEntry.Charges)
+ procEntry.Charges = spellInfo->ProcCharges;
+ if (!procEntry.Chance && !procEntry.ProcsPerMinute)
+ procEntry.Chance = float(spellInfo->ProcChance);
+
+ // validate data
+ if (procEntry.SchoolMask & ~SPELL_SCHOOL_MASK_ALL)
+ TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SchoolMask` set: %u", spellInfo->Id, procEntry.SchoolMask);
+ if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName < SPELLFAMILY_MAGE || procEntry.SpellFamilyName > SPELLFAMILY_PET || procEntry.SpellFamilyName == 14 || procEntry.SpellFamilyName == 16))
+ TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SpellFamilyName` set: %u", spellInfo->Id, procEntry.SpellFamilyName);
+ if (procEntry.Chance < 0)
+ {
+ TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `Chance` field", spellInfo->Id);
+ procEntry.Chance = 0;
+ }
+ if (procEntry.ProcsPerMinute < 0)
+ {
+ TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `ProcsPerMinute` field", spellInfo->Id);
+ procEntry.ProcsPerMinute = 0;
+ }
+ if (!procEntry.ProcFlags)
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `ProcFlags` value defined, proc will not be triggered.", spellInfo->Id);
+ if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
+ TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SpellTypeMask` set: %u", spellInfo->Id, procEntry.SpellTypeMask);
+ if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `SpellTypeMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id);
+ if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `SpellPhaseMask` value defined, but it is required for the defined `ProcFlags` value. Proc will not be triggered.", spellInfo->Id);
+ if (procEntry.SpellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL)
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `SpellPhaseMask` set: %u", spellInfo->Id, procEntry.SpellPhaseMask);
+ if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK))
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has a `SpellPhaseMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id);
+ if (procEntry.HitMask & ~PROC_HIT_MASK_ALL)
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `HitMask` set: %u", spellInfo->Id, procEntry.HitMask);
+ if (procEntry.HitMask && !(procEntry.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.ProcFlags & DONE_HIT_PROC_FLAG_MASK && (!procEntry.SpellPhaseMask || procEntry.SpellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH)))))
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `HitMask` value defined, but it will not be used for defined `ProcFlags` and `SpellPhaseMask` values.", spellInfo->Id);
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if ((procEntry.AttributesMask & (PROC_ATTR_DISABLE_EFF_0 << i)) && !spellInfo->Effects[i].IsAura())
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has Attribute PROC_ATTR_DISABLE_EFF_%u, but effect %u is not an aura effect", spellInfo->Id, static_cast<uint32>(i), static_cast<uint32>(i));
+
+ mSpellProcMap[spellInfo->Id] = procEntry;
+
+ if (allRanks)
+ spellInfo = spellInfo->GetNextRankSpell();
+ else
+ break;
+ }
+ ++count;
+ } while (result->NextRow());
+ }
+ else
+ TC_LOG_INFO("server.loading", ">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty.");
- mSpellProcMap.clear(); // need for reload case
+ TC_LOG_INFO("server.loading", ">> Loaded %u spell proc conditions and data in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
- // 0 1 2 3 4 5
- QueryResult result = WorldDatabase.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, "
- // 6 7 8 9 10 11 12 13 14
- "ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc");
+ // Define can trigger auras
+ bool isTriggerAura[TOTAL_AURAS];
+ // Triggered always, even from triggered spells
+ bool isAlwaysTriggeredAura[TOTAL_AURAS];
+ // SpellTypeMask to add to the proc
+ uint32 spellTypeMask[TOTAL_AURAS];
+
+ // List of auras that CAN trigger but may not exist in spell_proc
+ // in most cases needed to drop charges
+
+ // some aura types need additional checks (eg SPELL_AURA_MECHANIC_IMMUNITY needs mechanic check)
+ // see AuraEffect::CheckEffectProc
+ for (uint16 i = 0; i < TOTAL_AURAS; ++i)
+ {
+ isTriggerAura[i] = false;
+ isAlwaysTriggeredAura[i] = false;
+ spellTypeMask[i] = PROC_SPELL_TYPE_MASK_ALL;
+ }
+
+ isTriggerAura[SPELL_AURA_DUMMY] = true; // Most dummy auras should require scripting, but there are some exceptions (ie 12311)
+ isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true; // "Any direct damaging attack will revive targets"
+ isTriggerAura[SPELL_AURA_MOD_THREAT] = true; // Only one spell: 28762 part of Mage T3 8p bonus
+ isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura does not have charges but needs to be removed on trigger
+ isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
+ isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
+ isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
+ isTriggerAura[SPELL_AURA_MOD_STEALTH] = true;
+ isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura does not have charges but needs to be removed on trigger
+ isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
+ isTriggerAura[SPELL_AURA_TRANSFORM] = true;
+ isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
+ isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
+ isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
+ isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true;
+ isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true;
+ isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true;
+ isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true;
+ isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true;
+ isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true;
+ isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true;
+ isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true;
+ isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
+ isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE] = true;
+ isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE] = true;
+ isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE] = true;
+ isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE] = true;
+ isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true;
+ isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true;
+ isTriggerAura[SPELL_AURA_ADD_FLAT_MODIFIER] = true;
+ isTriggerAura[SPELL_AURA_ADD_PCT_MODIFIER] = true;
+ isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true;
+
+ isAlwaysTriggeredAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_MOD_CONFUSE] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_MOD_FEAR] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true;
+
+ spellTypeMask[SPELL_AURA_MOD_STEALTH] = PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL;
+ spellTypeMask[SPELL_AURA_MOD_CONFUSE] = PROC_SPELL_TYPE_DAMAGE;
+ spellTypeMask[SPELL_AURA_MOD_FEAR] = PROC_SPELL_TYPE_DAMAGE;
+ spellTypeMask[SPELL_AURA_MOD_ROOT] = PROC_SPELL_TYPE_DAMAGE;
+ spellTypeMask[SPELL_AURA_MOD_STUN] = PROC_SPELL_TYPE_DAMAGE;
+ spellTypeMask[SPELL_AURA_TRANSFORM] = PROC_SPELL_TYPE_DAMAGE;
+
+ // This generates default procs to retain compatibility with previous proc system
+ TC_LOG_INFO("server.loading", "Generating spell proc data from SpellMap...");
+ count = 0;
+ oldMSTime = getMSTime();
- if (!result)
+ for (SpellInfo const* spellInfo : mSpellInfoMap)
{
- TC_LOG_INFO("server.loading", ">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty.");
- return;
- }
+ if (!spellInfo)
+ continue;
- uint32 count = 0;
- do
- {
- Field* fields = result->Fetch();
+ // Data already present in DB, overwrites default proc
+ if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
+ continue;
- int32 spellId = fields[0].GetInt32();
+ // Nothing to do if no flags set
+ if (!spellInfo->ProcFlags)
+ continue;
- bool allRanks = false;
- if (spellId < 0)
+ bool addTriggerFlag = false;
+ uint32 procSpellTypeMask = PROC_SPELL_TYPE_NONE;
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- allRanks = true;
- spellId = -spellId;
- }
+ if (!spellInfo->Effects[i].IsEffect())
+ continue;
- SpellInfo const* spellInfo = GetSpellInfo(spellId);
- if (!spellInfo)
- {
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` does not exist", spellId);
- continue;
- }
+ uint32 auraName = spellInfo->Effects[i].ApplyAuraName;
+ if (!auraName)
+ continue;
- if (allRanks)
- {
- if (!spellInfo->IsRanked())
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` with all ranks, but spell has no ranks.", spellId);
+ if (!isTriggerAura[auraName])
+ continue;
+
+ procSpellTypeMask |= spellTypeMask[auraName];
+ if (isAlwaysTriggeredAura[auraName])
+ addTriggerFlag = true;
- if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
+ // many proc auras with taken procFlag mask don't have attribute "can proc with triggered"
+ // they should proc nevertheless (example mage armor spells with judgement)
+ if (!addTriggerFlag && (spellInfo->ProcFlags & TAKEN_HIT_PROC_FLAG_MASK) != 0)
{
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` is not the first rank of the spell.", spellId);
- continue;
+ switch (auraName)
+ {
+ case SPELL_AURA_PROC_TRIGGER_SPELL:
+ case SPELL_AURA_PROC_TRIGGER_DAMAGE:
+ addTriggerFlag = true;
+ break;
+ default:
+ break;
+ }
}
+ break;
}
- SpellProcEntry baseProcEntry;
+ if (!procSpellTypeMask)
+ continue;
+
+ SpellProcEntry procEntry;
+ procEntry.SchoolMask = 0;
+ procEntry.ProcFlags = spellInfo->ProcFlags;
+ procEntry.SpellFamilyName = 0;
+ for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (spellInfo->Effects[i].IsEffect() && isTriggerAura[spellInfo->Effects[i].ApplyAuraName])
+ procEntry.SpellFamilyMask |= spellInfo->Effects[i].SpellClassMask;
+
+ if (procEntry.SpellFamilyMask)
+ procEntry.SpellFamilyName = spellInfo->SpellFamilyName;
- baseProcEntry.SchoolMask = fields[1].GetInt8();
- baseProcEntry.SpellFamilyName = fields[2].GetUInt16();
- baseProcEntry.SpellFamilyMask[0] = fields[3].GetUInt32();
- baseProcEntry.SpellFamilyMask[1] = fields[4].GetUInt32();
- baseProcEntry.SpellFamilyMask[2] = fields[5].GetUInt32();
- baseProcEntry.ProcFlags = fields[6].GetUInt32();
- baseProcEntry.SpellTypeMask = fields[7].GetUInt32();
- baseProcEntry.SpellPhaseMask = fields[8].GetUInt32();
- baseProcEntry.HitMask = fields[9].GetUInt32();
- baseProcEntry.AttributesMask = fields[10].GetUInt32();
- baseProcEntry.ProcsPerMinute = fields[11].GetFloat();
- baseProcEntry.Chance = fields[12].GetFloat();
- baseProcEntry.Cooldown = Milliseconds(fields[13].GetUInt32());
- baseProcEntry.Charges = fields[14].GetUInt8();
+ procEntry.SpellTypeMask = procSpellTypeMask;
+ procEntry.SpellPhaseMask = PROC_SPELL_PHASE_HIT;
+ procEntry.HitMask = PROC_HIT_NONE; // uses default proc @see SpellMgr::CanSpellTriggerProcOnEvent
- while (spellInfo)
+ // Reflect auras should only proc off reflects
+ for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
+ if (spellInfo->Effects[i].IsAura(SPELL_AURA_REFLECT_SPELLS) || spellInfo->Effects[i].IsAura(SPELL_AURA_REFLECT_SPELLS_SCHOOL))
{
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` already has its first rank in the table.", spellInfo->Id);
+ procEntry.HitMask = PROC_HIT_REFLECT;
break;
}
+ }
- SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);
-
- // take defaults from dbcs
- if (!procEntry.ProcFlags)
- procEntry.ProcFlags = spellInfo->ProcFlags;
- if (!procEntry.Charges)
- procEntry.Charges = spellInfo->ProcCharges;
- if (!procEntry.Chance && !procEntry.ProcsPerMinute)
- procEntry.Chance = float(spellInfo->ProcChance);
-
- // validate data
- if (procEntry.SchoolMask & ~SPELL_SCHOOL_MASK_ALL)
- TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SchoolMask` set: %u", spellInfo->Id, procEntry.SchoolMask);
- if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName < 3 || procEntry.SpellFamilyName > 17 || procEntry.SpellFamilyName == 14 || procEntry.SpellFamilyName == 16))
- TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SpellFamilyName` set: %u", spellInfo->Id, procEntry.SpellFamilyName);
- if (procEntry.Chance < 0)
- {
- TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `Chance` field", spellInfo->Id);
- procEntry.Chance = 0;
- }
- if (procEntry.ProcsPerMinute < 0)
- {
- TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `ProcsPerMinute` field", spellInfo->Id);
- procEntry.ProcsPerMinute = 0;
- }
- if (procEntry.Chance == 0 && procEntry.ProcsPerMinute == 0)
- TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u doesn't have any `Chance` and `ProcsPerMinute` values defined, proc will not be triggered", spellInfo->Id);
- if (!procEntry.ProcFlags)
- TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `ProcFlags` value defined, proc will not be triggered.", spellInfo->Id);
- if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
- TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SpellTypeMask` set: %u", spellInfo->Id, procEntry.SpellTypeMask);
- if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
- TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `SpellTypeMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id);
- if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)
- TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `SpellPhaseMask` value defined, but it is required for the defined `ProcFlags` value. Proc will not be triggered.", spellInfo->Id);
- if (procEntry.SpellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL)
- TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `SpellPhaseMask` set: %u", spellInfo->Id, procEntry.SpellPhaseMask);
- if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK))
- TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has a `SpellPhaseMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id);
- if (procEntry.HitMask & ~PROC_HIT_MASK_ALL)
- TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `HitMask` set: %u", spellInfo->Id, procEntry.HitMask);
- if (procEntry.HitMask && !(procEntry.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.ProcFlags & DONE_HIT_PROC_FLAG_MASK && (!procEntry.SpellPhaseMask || procEntry.SpellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH)))))
- TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `HitMask` value defined, but it will not be used for defined `ProcFlags` and `SpellPhaseMask` values.", spellInfo->Id);
-
- mSpellProcMap[spellInfo->Id] = procEntry;
+ procEntry.AttributesMask = 0;
+ if (spellInfo->ProcFlags & PROC_FLAG_KILL)
+ procEntry.AttributesMask |= PROC_ATTR_REQ_EXP_OR_HONOR;
+ if (addTriggerFlag)
+ procEntry.AttributesMask |= PROC_ATTR_TRIGGERED_CAN_PROC;
- if (allRanks)
- spellInfo = spellInfo->GetNextRankSpell();
- else
- break;
- }
+ procEntry.ProcsPerMinute = 0;
+ procEntry.Chance = spellInfo->ProcChance;
+ procEntry.Cooldown = Milliseconds::zero();
+ procEntry.Charges = spellInfo->ProcCharges;
+
+ mSpellProcMap[spellInfo->Id] = procEntry;
++count;
}
- while (result->NextRow());
- TC_LOG_INFO("server.loading", ">> Loaded %u spell proc conditions and data in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ TC_LOG_INFO("server.loading", ">> Generated spell proc data for %u spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void SpellMgr::LoadSpellBonusess()
@@ -2951,12 +2591,6 @@ void SpellMgr::LoadSpellInfoCorrections()
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
- case 4020: // Safirdrang's Chill
- spellInfo->MaxAffectedTargets = 1;
- break;
case 42436: // Drink! (Brewfest)
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY);
break;
@@ -2984,6 +2618,8 @@ void SpellMgr::LoadSpellInfoCorrections()
case 2895: // Wrath of Air Totem rank 1 (Aura)
case 68933: // Wrath of Air Totem rank 2 (Aura)
case 29200: // Purify Helboar Meat
+ case 10872: // Abolish Disease Effect
+ case 3137: // Abolish Poison Effect
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo();
break;
@@ -3011,6 +2647,15 @@ void SpellMgr::LoadSpellInfoCorrections()
// because of bug in dbc
spellInfo->ProcChance = 0;
break;
+ case 51528: // Maelstrom Weapon (Rank 1)
+ case 51529: // Maelstrom Weapon (Rank 2)
+ case 51530: // Maelstrom Weapon (Rank 3)
+ case 51531: // Maelstrom Weapon (Rank 4)
+ case 51532: // Maelstrom Weapon (Rank 5)
+ // due to discrepancies between ranks
+ spellInfo->EquippedItemSubClassMask = 0x0000FC33;
+ spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED;
+ break;
case 20335: // Heart of the Crusader
case 20336:
case 20337:
@@ -3034,7 +2679,7 @@ void SpellMgr::LoadSpellInfoCorrections()
case 59725: // Improved Spell Reflection - aoe aura
// Target entry seems to be wrong for this spell :/
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER_AREA_PARTY);
- spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS_2);
+ spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_20_YARDS);
break;
case 44978: // Wild Magic
case 45001:
@@ -3061,6 +2706,14 @@ void SpellMgr::LoadSpellInfoCorrections()
case 36327: // Shoot Arcane Explosion Arrow
case 55479: // Force Obedience
case 28560: // Summon Blizzard (Sapphiron)
+ case 53096: // Quetz'lun's Judgment
+ case 70743: // AoD Special
+ case 70614: // AoD Special - Vegard
+ case 4020: // Safirdrang's Chill
+ case 52438: // Summon Skittering Swarmer (Force Cast)
+ case 52449: // Summon Skittering Infector (Force Cast)
+ case 53609: // Summon Anub'ar Assassin (Force Cast)
+ case 53457: // Summon Impale Trigger (AoE)
spellInfo->MaxAffectedTargets = 1;
break;
case 36384: // Skartax Purple Beam
@@ -3085,6 +2738,12 @@ void SpellMgr::LoadSpellInfoCorrections()
case 53385: // Divine Storm (Damage)
spellInfo->MaxAffectedTargets = 4;
break;
+ case 56342: // Lock and Load (Rank 1)
+ // @workaround: Delete dummy effect from rank 1,
+ // effect apply aura has TargetA == TargetB == 0 but core still applies it to caster
+ // core bug?
+ spellInfo->Effects[EFFECT_2].Effect = 0;
+ break;
case 53480: // Roar of Sacrifice
// missing spell effect 2 data, taken from 4.3.4
spellInfo->Effects[EFFECT_1].Effect = SPELL_EFFECT_APPLY_AURA;
@@ -3119,36 +2778,17 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->MaxAffectedTargets = 1;
spellInfo->Effects[EFFECT_0].TriggerSpell = 33760;
break;
- case 17941: // Shadow Trance
- case 22008: // Netherwind Focus
- case 31834: // Light's Grace
- case 34936: // Backlash
- case 48108: // Hot Streak
- case 51124: // Killing Machine
- case 54741: // Firestarter
- case 57761: // Fireball!
- 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
spellInfo->Effects[EFFECT_0].SpellClassMask = flag96(685904631, 1151048, 0);
break;
- case 74396: // Fingers of Frost visual buff
- case 53257: // Cobra Strikes
- spellInfo->ProcCharges = 2;
- spellInfo->StackAmount = 0;
- break;
- case 28200: // Ascendance (Talisman of Ascendance trinket)
- spellInfo->ProcCharges = 6;
- break;
case 49224: // Magic Suppression - DK
case 49610: // Magic Suppression - DK
case 49611: // Magic Suppression - DK
spellInfo->ProcCharges = 0;
break;
+ case 52212: // Death and Decay
+ spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE;
+ break;
case 37408: // Oscillation Field
spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
break;
@@ -3228,6 +2868,19 @@ void SpellMgr::LoadSpellInfoCorrections()
case 27915: // Anchor to Skulls
case 27931: // Anchor to Skulls
case 27937: // Anchor to Skulls
+ case 16177: // Ancestral Fortitude (Rank 1)
+ case 16236: // Ancestral Fortitude (Rank 2)
+ case 16237: // Ancestral Fortitude (Rank 3)
+ case 47930: // Grace
+ case 45145: // Snake Trap Effect (Rank 1)
+ case 13812: // Explosive Trap Effect (Rank 1)
+ case 14314: // Explosive Trap Effect (Rank 2)
+ case 14315: // Explosive Trap Effect (Rank 3)
+ case 27026: // Explosive Trap Effect (Rank 4)
+ case 49064: // Explosive Trap Effect (Rank 5)
+ case 49065: // Explosive Trap Effect (Rank 6)
+ case 43446: // Explosive Trap Effect (Hexlord Malacrass)
+ case 68979: // Unleashed Souls
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13);
break;
// target allys instead of enemies, target A is src_caster, spells with effect like that have ally target
@@ -3335,9 +2988,6 @@ void SpellMgr::LoadSpellInfoCorrections()
case 71839: // Drain Life - Bryntroll Heroic
spellInfo->AttributesEx2 |= SPELL_ATTR2_CANT_CRIT;
break;
- case 34471: // The Beast Within
- spellInfo->AttributesEx5 |= SPELL_ATTR5_USABLE_WHILE_CONFUSED | SPELL_ATTR5_USABLE_WHILE_FEARED | SPELL_ATTR5_USABLE_WHILE_STUNNED;
- break;
case 56606: // Ride Jokkum
case 61791: // Ride Vehicle (Yogg-Saron)
/// @todo: remove this when basepoints of all Ride Vehicle auras are calculated correctly
@@ -3375,6 +3025,24 @@ void SpellMgr::LoadSpellInfoCorrections()
case 29726: // Test Ribbon Pole Channel
spellInfo->InterruptFlags &= ~AURA_INTERRUPT_FLAG_CAST;
break;
+ case 42767: // Sic'em
+ case 43092: // Stop the Ascension!: Halfdan's Soul Destruction
+ spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_NEARBY_ENTRY);
+ break;
+ case 14621: // Polymorph (Six Demon Bag)
+ spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(4); // Medium Range
+ break;
+ case 35101: // Concussive Barrage
+ spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(155); // Hunter Range (Long)
+ break;
+ case 55741: // Desecration (Rank 1)
+ case 68766: // Desecration (Rank 2)
+ spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(2); // Melee Range
+ break;
+ case 46946: // Safeguard (Rank 1)
+ case 46947: // Safeguard (Rank 2)
+ spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(34); // Twenty-Five yards
+ break;
// VIOLET HOLD SPELLS
//
case 54258: // Water Globule (Ichoron)
@@ -3822,6 +3490,55 @@ void SpellMgr::LoadSpellInfoCorrections()
properties->Type = SUMMON_TYPE_TOTEM;
if (SummonPropertiesEntry* properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(647))) // 52893
properties->Type = SUMMON_TYPE_TOTEM;
+ if (SummonPropertiesEntry* properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(628))) // Hungry Plaguehound
+ properties->Category = SUMMON_CATEGORY_PET;
TC_LOG_INFO("server.loading", ">> Loaded SpellInfo corrections in %u ms", GetMSTimeDiffToNow(oldMSTime));
}
+
+void SpellMgr::LoadSpellInfoSpellSpecificAndAuraState()
+{
+ uint32 oldMSTime = getMSTime();
+
+ for (SpellInfo* spellInfo : mSpellInfoMap)
+ {
+ if (!spellInfo)
+ continue;
+
+ // AuraState depends on SpellSpecific
+ spellInfo->_LoadSpellSpecific();
+ spellInfo->_LoadAuraState();
+ }
+
+ TC_LOG_INFO("server.loading", ">> Loaded SpellInfo SpellSpecific and AuraState in %u ms", GetMSTimeDiffToNow(oldMSTime));
+}
+
+void SpellMgr::LoadSpellInfoDiminishing()
+{
+ uint32 oldMSTime = getMSTime();
+
+ for (SpellInfo* spellInfo : mSpellInfoMap)
+ {
+ if (!spellInfo)
+ continue;
+
+ spellInfo->_LoadSpellDiminishInfo();
+ }
+
+ TC_LOG_INFO("server.loading", ">> Loaded SpellInfo diminishing infos in %u ms", GetMSTimeDiffToNow(oldMSTime));
+}
+
+void SpellMgr::LoadSpellInfoImmunities()
+{
+ uint32 oldMSTime = getMSTime();
+
+ for (SpellInfo* spellInfo : mSpellInfoMap)
+ {
+ if (!spellInfo)
+ continue;
+
+ spellInfo->_LoadImmunityInfo();
+ }
+
+ TC_LOG_INFO("server.loading", ">> Loaded SpellInfo immunity infos in %u ms", GetMSTimeDiffToNow(oldMSTime));
+}
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index 23329c1ff1e..a08ff921a2e 100644
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -160,13 +160,13 @@ enum ProcFlags
| PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS,
SPELL_PROC_FLAG_MASK = PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS
+ | PROC_FLAG_DONE_RANGED_AUTO_ATTACK | PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK
| PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS
| PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS
| PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG
| PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS
- | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG,
-
- SPELL_CAST_PROC_FLAG_MASK = SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION | RANGED_PROC_FLAG_MASK,
+ | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG
+ | PROC_FLAG_DONE_TRAP_ACTIVATION,
PERIODIC_PROC_FLAG_MASK = PROC_FLAG_DONE_PERIODIC | PROC_FLAG_TAKEN_PERIODIC,
@@ -174,7 +174,8 @@ enum ProcFlags
| PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS
| PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG
| PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG
- | PROC_FLAG_DONE_PERIODIC | PROC_FLAG_DONE_MAINHAND_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK,
+ | PROC_FLAG_DONE_PERIODIC | PROC_FLAG_DONE_TRAP_ACTIVATION
+ | PROC_FLAG_DONE_MAINHAND_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK,
TAKEN_HIT_PROC_FLAG_MASK = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK | PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK
| PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS
@@ -194,43 +195,6 @@ enum ProcFlags
PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | \
PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS)
-enum ProcFlagsExLegacy
-{
- PROC_EX_NONE = 0x0000000, // If none can tigger on Hit/Crit only (passive spells MUST defined by SpellFamily flag)
- PROC_EX_NORMAL_HIT = 0x0000001, // If set only from normal hit (only damage spells)
- PROC_EX_CRITICAL_HIT = 0x0000002,
- PROC_EX_MISS = 0x0000004,
- PROC_EX_RESIST = 0x0000008,
- PROC_EX_DODGE = 0x0000010,
- PROC_EX_PARRY = 0x0000020,
- PROC_EX_BLOCK = 0x0000040,
- PROC_EX_EVADE = 0x0000080,
- PROC_EX_IMMUNE = 0x0000100,
- PROC_EX_DEFLECT = 0x0000200,
- PROC_EX_ABSORB = 0x0000400,
- PROC_EX_REFLECT = 0x0000800,
- PROC_EX_INTERRUPT = 0x0001000, // Melee hit result can be Interrupt (not used)
- PROC_EX_FULL_BLOCK = 0x0002000, // block al attack damage
- PROC_EX_RESERVED2 = 0x0004000,
- PROC_EX_NOT_ACTIVE_SPELL = 0x0008000, // Spell mustn't do damage/heal to proc
- PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always no matter of hit result
- PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000, // If set trigger always but only one time (not implemented yet)
- PROC_EX_ONLY_ACTIVE_SPELL = 0x0040000, // Spell has to do damage/heal to proc
-
- // Flags for internal use - do not use these in db!
- PROC_EX_INTERNAL_CANT_PROC = 0x0800000,
- PROC_EX_INTERNAL_DOT = 0x1000000,
- PROC_EX_INTERNAL_HOT = 0x2000000,
- PROC_EX_INTERNAL_TRIGGERED = 0x4000000,
- PROC_EX_INTERNAL_REQ_FAMILY = 0x8000000
-};
-
-#define AURA_SPELL_PROC_EX_MASK \
- (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT | PROC_EX_MISS | \
- PROC_EX_RESIST | PROC_EX_DODGE | PROC_EX_PARRY | PROC_EX_BLOCK | \
- PROC_EX_EVADE | PROC_EX_IMMUNE | PROC_EX_DEFLECT | \
- PROC_EX_ABSORB | PROC_EX_REFLECT | PROC_EX_INTERRUPT)
-
enum ProcFlagsSpellType
{
PROC_SPELL_TYPE_NONE = 0x0000000,
@@ -271,23 +235,16 @@ enum ProcFlagsHit
enum ProcAttributes
{
- PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000010
+ PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000001, // requires proc target to give exp or honor for aura proc
+ PROC_ATTR_TRIGGERED_CAN_PROC = 0x0000002, // aura can proc even with triggered spells
+ PROC_ATTR_REQ_MANA_COST = 0x0000004, // requires triggering spell to have a mana cost for aura proc
+ PROC_ATTR_REQ_SPELLMOD = 0x0000008, // requires triggering spell to be affected by proccing aura to drop charges
+
+ PROC_ATTR_DISABLE_EFF_0 = 0x0000010, // explicitly disables aura proc from effects, USE ONLY IF 100% SURE AURA SHOULDN'T PROC
+ PROC_ATTR_DISABLE_EFF_1 = 0x0000020, // used to avoid a console error if the spell has invalid trigger spell and handled elsewhere
+ PROC_ATTR_DISABLE_EFF_2 = 0x0000040 // or handling not needed
};
-struct SpellProcEventEntry
-{
- uint32 schoolMask; // if nonzero - bit mask for matching proc condition based on spell candidate's school: Fire=2, Mask=1<<(2-1)=2
- uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyNamer value
- flag96 spellFamilyMask; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyFlags (like auras 107 and 108 do)
- uint32 procFlags; // bitmask for matching proc event
- uint32 procEx; // proc Extend info (see ProcFlagsEx)
- float ppmRate; // for melee (ranged?) damage spells - proc rate per minute. if zero, falls back to flat chance from Spell.dbc
- float customChance; // Owerride chance (in most cases for debug only)
- uint32 cooldown; // hidden cooldown used for some spell proc events, applied to _triggered_spell_
-};
-
-typedef std::unordered_map<uint32, SpellProcEventEntry> SpellProcEventMap;
-
struct SpellProcEntry
{
uint32 SchoolMask; // if nonzero - bitmask for matching proc condition based on spell's school
@@ -545,7 +502,7 @@ struct SpellLearnSkillNode
uint16 maxvalue; // 0 - max skill value for player level
};
-typedef std::map<uint32, SpellLearnSkillNode> SpellLearnSkillMap;
+typedef std::unordered_map<uint32, SpellLearnSkillNode> SpellLearnSkillMap;
struct SpellLearnSpellNode
{
@@ -594,13 +551,6 @@ inline bool IsProfessionOrRidingSkill(uint32 skill)
bool IsPartOfSkillLine(uint32 skillId, uint32 spellId);
-// spell diminishing returns
-TC_GAME_API DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto, bool triggered);
-TC_GAME_API DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group);
-TC_GAME_API DiminishingLevels GetDiminishingReturnsMaxLevel(DiminishingGroup group);
-TC_GAME_API int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellInfo const* spellproto);
-TC_GAME_API bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group);
-
class TC_GAME_API SpellMgr
{
// Constructors
@@ -658,13 +608,9 @@ class TC_GAME_API SpellMgr
SpellGroupStackRule CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const;
SpellGroupStackRule GetSpellGroupStackRule(SpellGroup groupid) const;
- // Spell proc event table
- SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const;
- bool IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellInfo const* procSpell, uint32 procFlags, uint32 procExtra, bool active) const;
-
// Spell proc table
SpellProcEntry const* GetSpellProcEntry(uint32 spellId) const;
- bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const;
+ static bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo);
// Spell bonus data table
SpellBonusEntry const* GetSpellBonusData(uint32 spellId) const;
@@ -720,7 +666,6 @@ class TC_GAME_API SpellMgr
void LoadSpellTargetPositions();
void LoadSpellGroups();
void LoadSpellGroupStackRules();
- void LoadSpellProcEvents();
void LoadSpellProcs();
void LoadSpellBonusess();
void LoadSpellThreats();
@@ -737,6 +682,9 @@ class TC_GAME_API SpellMgr
void UnloadSpellInfoImplicitTargetConditionLists();
void LoadSpellInfoCustomAttributes();
void LoadSpellInfoCorrections();
+ void LoadSpellInfoSpellSpecificAndAuraState();
+ void LoadSpellInfoDiminishing();
+ void LoadSpellInfoImmunities();
private:
SpellDifficultySearcherMap mSpellDifficultySearcherMap;
@@ -749,7 +697,6 @@ class TC_GAME_API SpellMgr
SpellSpellGroupMap mSpellSpellGroup;
SpellGroupSpellMap mSpellGroupSpell;
SpellGroupStackMap mSpellGroupStack;
- SpellProcEventMap mSpellProcEventMap;
SpellProcMap mSpellProcMap;
SpellBonusMap mSpellBonusMap;
SpellThreatMap mSpellThreatMap;
diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp
index e2598386466..950456394d8 100644
--- a/src/server/game/Spells/SpellScript.cpp
+++ b/src/server/game/Spells/SpellScript.cpp
@@ -301,35 +301,35 @@ void SpellScript::DestinationTargetSelectHandler::Call(SpellScript* spellScript,
bool SpellScript::_Validate(SpellInfo const* entry)
{
- for (std::list<EffectHandler>::iterator itr = OnEffectLaunch.begin(); itr != OnEffectLaunch.end(); ++itr)
+ for (auto itr = OnEffectLaunch.begin(); itr != OnEffectLaunch.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectLaunch` of SpellScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectHandler>::iterator itr = OnEffectLaunchTarget.begin(); itr != OnEffectLaunchTarget.end(); ++itr)
+ for (auto itr = OnEffectLaunchTarget.begin(); itr != OnEffectLaunchTarget.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectLaunchTarget` of SpellScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectHandler>::iterator itr = OnEffectHit.begin(); itr != OnEffectHit.end(); ++itr)
+ for (auto itr = OnEffectHit.begin(); itr != OnEffectHit.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectHit` of SpellScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectHandler>::iterator itr = OnEffectHitTarget.begin(); itr != OnEffectHitTarget.end(); ++itr)
+ for (auto itr = OnEffectHitTarget.begin(); itr != OnEffectHitTarget.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectHitTarget` of SpellScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectHandler>::iterator itr = OnEffectSuccessfulDispel.begin(); itr != OnEffectSuccessfulDispel.end(); ++itr)
+ for (auto itr = OnEffectSuccessfulDispel.begin(); itr != OnEffectSuccessfulDispel.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectSuccessfulDispel` of SpellScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<ObjectAreaTargetSelectHandler>::iterator itr = OnObjectAreaTargetSelect.begin(); itr != OnObjectAreaTargetSelect.end(); ++itr)
+ for (auto itr = OnObjectAreaTargetSelect.begin(); itr != OnObjectAreaTargetSelect.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnObjectAreaTargetSelect` of SpellScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<ObjectTargetSelectHandler>::iterator itr = OnObjectTargetSelect.begin(); itr != OnObjectTargetSelect.end(); ++itr)
+ for (auto itr = OnObjectTargetSelect.begin(); itr != OnObjectTargetSelect.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnObjectTargetSelect` of SpellScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<DestinationTargetSelectHandler>::iterator itr = OnDestinationTargetSelect.begin(); itr != OnDestinationTargetSelect.end(); ++itr)
+ for (auto itr = OnDestinationTargetSelect.begin(); itr != OnDestinationTargetSelect.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnDestinationTargetSelect` of SpellScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
@@ -624,9 +624,9 @@ SpellInfo const* SpellScript::GetTriggeringSpell()
return m_spell->m_triggeredByAuraSpell;
}
-void SpellScript::FinishCast(SpellCastResult result)
+void SpellScript::FinishCast(SpellCastResult result, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
{
- m_spell->SendCastResult(result);
+ m_spell->SendCastResult(result, param1, param2);
m_spell->finish(result == SPELL_CAST_OK);
}
@@ -648,95 +648,99 @@ SpellValue const* SpellScript::GetSpellValue()
bool AuraScript::_Validate(SpellInfo const* entry)
{
- for (std::list<CheckAreaTargetHandler>::iterator itr = DoCheckAreaTarget.begin(); itr != DoCheckAreaTarget.end(); ++itr)
+ for (auto itr = DoCheckAreaTarget.begin(); itr != DoCheckAreaTarget.end(); ++itr)
if (!entry->HasAreaAuraEffect() && !entry->HasEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) && !entry->HasEffect(SPELL_EFFECT_APPLY_AURA))
TC_LOG_ERROR("scripts", "Spell `%u` of script `%s` does not have apply aura effect - handler bound to hook `DoCheckAreaTarget` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
- for (std::list<AuraDispelHandler>::iterator itr = OnDispel.begin(); itr != OnDispel.end(); ++itr)
+ for (auto itr = OnDispel.begin(); itr != OnDispel.end(); ++itr)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
TC_LOG_ERROR("scripts", "Spell `%u` of script `%s` does not have apply aura effect - handler bound to hook `OnDispel` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
- for (std::list<AuraDispelHandler>::iterator itr = AfterDispel.begin(); itr != AfterDispel.end(); ++itr)
+ for (auto itr = AfterDispel.begin(); itr != AfterDispel.end(); ++itr)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
TC_LOG_ERROR("scripts", "Spell `%u` of script `%s` does not have apply aura effect - handler bound to hook `AfterDispel` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
- for (std::list<EffectApplyHandler>::iterator itr = OnEffectApply.begin(); itr != OnEffectApply.end(); ++itr)
+ for (auto itr = OnEffectApply.begin(); itr != OnEffectApply.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectApply` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectApplyHandler>::iterator itr = OnEffectRemove.begin(); itr != OnEffectRemove.end(); ++itr)
+ for (auto itr = OnEffectRemove.begin(); itr != OnEffectRemove.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectRemove` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectApplyHandler>::iterator itr = AfterEffectApply.begin(); itr != AfterEffectApply.end(); ++itr)
+ for (auto itr = AfterEffectApply.begin(); itr != AfterEffectApply.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `AfterEffectApply` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectApplyHandler>::iterator itr = AfterEffectRemove.begin(); itr != AfterEffectRemove.end(); ++itr)
+ for (auto itr = AfterEffectRemove.begin(); itr != AfterEffectRemove.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `AfterEffectRemove` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectPeriodicHandler>::iterator itr = OnEffectPeriodic.begin(); itr != OnEffectPeriodic.end(); ++itr)
+ for (auto itr = OnEffectPeriodic.begin(); itr != OnEffectPeriodic.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectPeriodic` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectUpdatePeriodicHandler>::iterator itr = OnEffectUpdatePeriodic.begin(); itr != OnEffectUpdatePeriodic.end(); ++itr)
+ for (auto itr = OnEffectUpdatePeriodic.begin(); itr != OnEffectUpdatePeriodic.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectUpdatePeriodic` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectCalcAmountHandler>::iterator itr = DoEffectCalcAmount.begin(); itr != DoEffectCalcAmount.end(); ++itr)
+ for (auto itr = DoEffectCalcAmount.begin(); itr != DoEffectCalcAmount.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `DoEffectCalcAmount` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectCalcPeriodicHandler>::iterator itr = DoEffectCalcPeriodic.begin(); itr != DoEffectCalcPeriodic.end(); ++itr)
+ for (auto itr = DoEffectCalcPeriodic.begin(); itr != DoEffectCalcPeriodic.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `DoEffectCalcPeriodic` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectCalcSpellModHandler>::iterator itr = DoEffectCalcSpellMod.begin(); itr != DoEffectCalcSpellMod.end(); ++itr)
+ for (auto itr = DoEffectCalcSpellMod.begin(); itr != DoEffectCalcSpellMod.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `DoEffectCalcSpellMod` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectAbsorbHandler>::iterator itr = OnEffectAbsorb.begin(); itr != OnEffectAbsorb.end(); ++itr)
+ for (auto itr = OnEffectAbsorb.begin(); itr != OnEffectAbsorb.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectAbsorb` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectAbsorbHandler>::iterator itr = AfterEffectAbsorb.begin(); itr != AfterEffectAbsorb.end(); ++itr)
+ for (auto itr = AfterEffectAbsorb.begin(); itr != AfterEffectAbsorb.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `AfterEffectAbsorb` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectManaShieldHandler>::iterator itr = OnEffectManaShield.begin(); itr != OnEffectManaShield.end(); ++itr)
+ for (auto itr = OnEffectManaShield.begin(); itr != OnEffectManaShield.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectManaShield` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectManaShieldHandler>::iterator itr = AfterEffectManaShield.begin(); itr != AfterEffectManaShield.end(); ++itr)
+ for (auto itr = AfterEffectManaShield.begin(); itr != AfterEffectManaShield.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `AfterEffectManaShield` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectSplitHandler>::iterator itr = OnEffectSplit.begin(); itr != OnEffectSplit.end(); ++itr)
+ for (auto itr = OnEffectSplit.begin(); itr != OnEffectSplit.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectSplit` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<CheckProcHandler>::iterator itr = DoCheckProc.begin(); itr != DoCheckProc.end(); ++itr)
+ for (auto itr = DoCheckProc.begin(); itr != DoCheckProc.end(); ++itr)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
TC_LOG_ERROR("scripts", "Spell `%u` of script `%s` does not have apply aura effect - handler bound to hook `DoCheckProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
- for (std::list<AuraProcHandler>::iterator itr = DoPrepareProc.begin(); itr != DoPrepareProc.end(); ++itr)
+ for (auto itr = DoCheckEffectProc.begin(); itr != DoCheckEffectProc.end(); ++itr)
+ if (!itr->GetAffectedEffectsMask(entry))
+ TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `DoCheckEffectProc` of AuraScript won't be executed", entry->Id, itr->ToString().c_str(), m_scriptName->c_str());
+
+ for (auto itr = DoPrepareProc.begin(); itr != DoPrepareProc.end(); ++itr)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
TC_LOG_ERROR("scripts", "Spell `%u` of script `%s` does not have apply aura effect - handler bound to hook `DoPrepareProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
- for (std::list<AuraProcHandler>::iterator itr = OnProc.begin(); itr != OnProc.end(); ++itr)
+ for (auto itr = OnProc.begin(); itr != OnProc.end(); ++itr)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
TC_LOG_ERROR("scripts", "Spell `%u` of script `%s` does not have apply aura effect - handler bound to hook `OnProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
- for (std::list<AuraProcHandler>::iterator itr = AfterProc.begin(); itr != AfterProc.end(); ++itr)
+ for (auto itr = AfterProc.begin(); itr != AfterProc.end(); ++itr)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
TC_LOG_ERROR("scripts", "Spell `%u` of script `%s` does not have apply aura effect - handler bound to hook `AfterProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
- for (std::list<EffectProcHandler>::iterator itr = OnEffectProc.begin(); itr != OnEffectProc.end(); ++itr)
+ for (auto itr = OnEffectProc.begin(); itr != OnEffectProc.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectProc` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- for (std::list<EffectProcHandler>::iterator itr = AfterEffectProc.begin(); itr != AfterEffectProc.end(); ++itr)
+ for (auto itr = AfterEffectProc.begin(); itr != AfterEffectProc.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `AfterEffectProc` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
@@ -887,6 +891,17 @@ bool AuraScript::CheckProcHandler::Call(AuraScript* auraScript, ProcEventInfo& e
return (auraScript->*_HandlerScript)(eventInfo);
}
+AuraScript::CheckEffectProcHandler::CheckEffectProcHandler(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName)
+ : AuraScript::EffectBase(effIndex, effName)
+{
+ _HandlerScript = handlerScript;
+}
+
+bool AuraScript::CheckEffectProcHandler::Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+{
+ return (auraScript->*_HandlerScript)(aurEff, eventInfo);
+}
+
AuraScript::AuraProcHandler::AuraProcHandler(AuraProcFnType handlerScript)
{
_HandlerScript = handlerScript;
@@ -1148,6 +1163,7 @@ Unit* AuraScript::GetTarget() const
case AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD:
case AURA_SCRIPT_HOOK_EFFECT_SPLIT:
case AURA_SCRIPT_HOOK_CHECK_PROC:
+ case AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC:
case AURA_SCRIPT_HOOK_PREPARE_PROC:
case AURA_SCRIPT_HOOK_PROC:
case AURA_SCRIPT_HOOK_AFTER_PROC:
diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h
index 539bc54cc94..af30b6a7879 100644
--- a/src/server/game/Spells/SpellScript.h
+++ b/src/server/game/Spells/SpellScript.h
@@ -63,9 +63,9 @@ class TC_GAME_API _SpellScript
public:
_SpellScript() : m_currentScriptState(SPELL_SCRIPT_STATE_NONE), m_scriptName(NULL), m_scriptSpellId(0) {}
virtual ~_SpellScript() { }
- virtual void _Register();
- virtual void _Unload();
- virtual void _Init(std::string const* scriptname, uint32 spellId);
+ void _Register();
+ void _Unload();
+ void _Init(std::string const* scriptname, uint32 spellId);
std::string const* _GetScriptName() const;
protected:
@@ -441,7 +441,7 @@ class TC_GAME_API SpellScript : public _SpellScript
SpellInfo const* GetTriggeringSpell();
// finishes spellcast prematurely with selected error message
- void FinishCast(SpellCastResult result);
+ void FinishCast(SpellCastResult result, uint32* param1 = nullptr, uint32* param2 = nullptr);
void SetCustomCastResultMessage(SpellCustomErrors result);
};
@@ -468,6 +468,7 @@ enum AuraScriptHookType
AURA_SCRIPT_HOOK_AFTER_DISPEL,
// Spell Proc Hooks
AURA_SCRIPT_HOOK_CHECK_PROC,
+ AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC,
AURA_SCRIPT_HOOK_PREPARE_PROC,
AURA_SCRIPT_HOOK_PROC,
AURA_SCRIPT_HOOK_EFFECT_PROC,
@@ -499,6 +500,7 @@ class TC_GAME_API AuraScript : public _SpellScript
typedef void(CLASSNAME::*AuraEffectAbsorbFnType)(AuraEffect*, DamageInfo &, uint32 &); \
typedef void(CLASSNAME::*AuraEffectSplitFnType)(AuraEffect*, DamageInfo &, uint32 &); \
typedef bool(CLASSNAME::*AuraCheckProcFnType)(ProcEventInfo&); \
+ typedef bool(CLASSNAME::*AuraCheckEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \
typedef void(CLASSNAME::*AuraProcFnType)(ProcEventInfo&); \
typedef void(CLASSNAME::*AuraEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \
@@ -608,6 +610,14 @@ class TC_GAME_API AuraScript : public _SpellScript
private:
AuraCheckProcFnType _HandlerScript;
};
+ class TC_GAME_API CheckEffectProcHandler : public EffectBase
+ {
+ public:
+ CheckEffectProcHandler(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName);
+ bool Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo);
+ private:
+ AuraCheckEffectProcFnType _HandlerScript;
+ };
class TC_GAME_API AuraProcHandler
{
public:
@@ -638,6 +648,7 @@ class TC_GAME_API AuraScript : public _SpellScript
class EffectManaShieldFunction : public AuraScript::EffectManaShieldHandler { public: EffectManaShieldFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectManaShieldHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) { } }; \
class EffectSplitFunction : public AuraScript::EffectSplitHandler { public: EffectSplitFunction(AuraEffectSplitFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectSplitHandler((AuraScript::AuraEffectSplitFnType)_pEffectHandlerScript, _effIndex) { } }; \
class CheckProcHandlerFunction : public AuraScript::CheckProcHandler { public: CheckProcHandlerFunction(AuraCheckProcFnType handlerScript) : AuraScript::CheckProcHandler((AuraScript::AuraCheckProcFnType)handlerScript) { } }; \
+ class CheckEffectProcHandlerFunction : public AuraScript::CheckEffectProcHandler { public: CheckEffectProcHandlerFunction(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName) : AuraScript::CheckEffectProcHandler((AuraScript::AuraCheckEffectProcFnType)handlerScript, effIndex, effName) { } }; \
class AuraProcHandlerFunction : public AuraScript::AuraProcHandler { public: AuraProcHandlerFunction(AuraProcFnType handlerScript) : AuraScript::AuraProcHandler((AuraScript::AuraProcFnType)handlerScript) { } }; \
class EffectProcHandlerFunction : public AuraScript::EffectProcHandler { public: EffectProcHandlerFunction(AuraEffectProcFnType effectHandlerScript, uint8 effIndex, uint16 effName) : AuraScript::EffectProcHandler((AuraScript::AuraEffectProcFnType)effectHandlerScript, effIndex, effName) { } }
@@ -776,6 +787,12 @@ class TC_GAME_API AuraScript : public _SpellScript
HookList<CheckProcHandler> DoCheckProc;
#define AuraCheckProcFn(F) CheckProcHandlerFunction(&F)
+ // executed when aura effect checks if it can proc the aura
+ // example: DoCheckEffectProc += AuraCheckEffectProcFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier);
+ // where function is bool function (AuraEffect const* aurEff, ProcEventInfo& eventInfo);
+ HookList<CheckEffectProcHandler> DoCheckEffectProc;
+ #define AuraCheckEffectProcFn(F, I, N) CheckEffectProcHandlerFunction(&F, I, N)
+
// executed before aura procs (possibility to prevent charge drop/cooldown)
// example: DoPrepareProc += AuraProcFn(class::function);
// where function is: void function (ProcEventInfo& eventInfo);
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index de605ee9f2d..7bbf73d028d 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -872,6 +872,7 @@ void World::LoadConfigSettings(bool reload)
m_bool_configs[CONFIG_CAST_UNSTUCK] = sConfigMgr->GetBoolDefault("CastUnstuck", true);
m_int_configs[CONFIG_INSTANCE_RESET_TIME_HOUR] = sConfigMgr->GetIntDefault("Instance.ResetTimeHour", 4);
m_int_configs[CONFIG_INSTANCE_UNLOAD_DELAY] = sConfigMgr->GetIntDefault("Instance.UnloadDelay", 30 * MINUTE * IN_MILLISECONDS);
+ m_int_configs[CONFIG_DAILY_QUEST_RESET_TIME_HOUR] = sConfigMgr->GetIntDefault("Quests.DailyResetTime", 3);
m_int_configs[CONFIG_MAX_PRIMARY_TRADE_SKILL] = sConfigMgr->GetIntDefault("MaxPrimaryTradeSkill", 2);
m_int_configs[CONFIG_MIN_PETITION_SIGNS] = sConfigMgr->GetIntDefault("MinPetitionSigns", 9);
@@ -1448,6 +1449,12 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading SpellInfo custom attributes...");
sSpellMgr->LoadSpellInfoCustomAttributes();
+ TC_LOG_INFO("server.loading", "Loading SpellInfo diminishing infos...");
+ sSpellMgr->LoadSpellInfoDiminishing();
+
+ TC_LOG_INFO("server.loading", "Loading SpellInfo immunity infos...");
+ sSpellMgr->LoadSpellInfoImmunities();
+
TC_LOG_INFO("server.loading", "Loading GameObject models...");
LoadGameObjectModelList(m_dataPath);
@@ -1507,12 +1514,12 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Spell Learn Skills...");
sSpellMgr->LoadSpellLearnSkills(); // must be after LoadSpellRanks
+ TC_LOG_INFO("server.loading", "Loading SpellInfo SpellSpecific and AuraState...");
+ sSpellMgr->LoadSpellInfoSpellSpecificAndAuraState(); // must be after LoadSpellRanks
+
TC_LOG_INFO("server.loading", "Loading Spell Learn Spells...");
sSpellMgr->LoadSpellLearnSpells();
- TC_LOG_INFO("server.loading", "Loading Spell Proc Event conditions...");
- sSpellMgr->LoadSpellProcEvents();
-
TC_LOG_INFO("server.loading", "Loading Spell Proc conditions and data...");
sSpellMgr->LoadSpellProcs();
@@ -2103,7 +2110,7 @@ void World::Update(uint32 diff)
if (m_gameTime > m_NextDailyQuestReset)
{
ResetDailyQuests();
- m_NextDailyQuestReset += DAY;
+ InitDailyQuestResetTime(false);
}
/// Handle weekly quests reset time
@@ -2934,25 +2941,25 @@ void World::InitWeeklyQuestResetTime()
m_NextWeeklyQuestReset = wstime < curtime ? curtime : time_t(wstime);
}
-void World::InitDailyQuestResetTime()
+void World::InitDailyQuestResetTime(bool loading)
{
- time_t mostRecentQuestTime;
+ time_t mostRecentQuestTime = 0;
- QueryResult result = CharacterDatabase.Query("SELECT MAX(time) FROM character_queststatus_daily");
- if (result)
+ if (loading)
{
- Field* fields = result->Fetch();
- mostRecentQuestTime = time_t(fields[0].GetUInt32());
+ QueryResult result = CharacterDatabase.Query("SELECT MAX(time) FROM character_queststatus_daily");
+ if (result)
+ {
+ Field* fields = result->Fetch();
+ mostRecentQuestTime = time_t(fields[0].GetUInt32());
+ }
}
- else
- mostRecentQuestTime = 0;
- // client built-in time for reset is 6:00 AM
// FIX ME: client not show day start time
time_t curTime = time(NULL);
tm localTm;
localtime_r(&curTime, &localTm);
- localTm.tm_hour = 6;
+ localTm.tm_hour = getIntConfig(CONFIG_DAILY_QUEST_RESET_TIME_HOUR);
localTm.tm_min = 0;
localTm.tm_sec = 0;
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 4dcb07e2f9c..8d6182887c0 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -242,6 +242,7 @@ enum WorldIntConfigs
CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL_DIFFERENCE,
CONFIG_INSTANCE_RESET_TIME_HOUR,
CONFIG_INSTANCE_UNLOAD_DELAY,
+ CONFIG_DAILY_QUEST_RESET_TIME_HOUR,
CONFIG_MAX_PRIMARY_TRADE_SKILL,
CONFIG_MIN_PETITION_SIGNS,
CONFIG_GM_LOGIN_STATE,
@@ -783,7 +784,7 @@ class TC_GAME_API World
// callback for UpdateRealmCharacters
void _UpdateRealmCharCount(PreparedQueryResult resultCharCount);
- void InitDailyQuestResetTime();
+ void InitDailyQuestResetTime(bool loading = true);
void InitWeeklyQuestResetTime();
void InitMonthlyQuestResetTime();
void InitRandomBGResetTime();
diff --git a/src/server/scripts/Commands/cs_cast.cpp b/src/server/scripts/Commands/cs_cast.cpp
index 44c606a360f..45e6c65cc6b 100644
--- a/src/server/scripts/Commands/cs_cast.cpp
+++ b/src/server/scripts/Commands/cs_cast.cpp
@@ -99,8 +99,7 @@ public:
return false;
}
- bool triggered = (triggeredStr != NULL);
-
+ TriggerCastFlags triggered = (triggeredStr != NULL) ? TRIGGERED_FULL_DEBUG_MASK : TRIGGERED_NONE;
handler->GetSession()->GetPlayer()->CastSpell(target, spellId, triggered);
return true;
@@ -132,8 +131,7 @@ public:
return false;
}
- bool triggered = (triggeredStr != NULL);
-
+ TriggerCastFlags triggered = (triggeredStr != NULL) ? TRIGGERED_FULL_DEBUG_MASK : TRIGGERED_NONE;
caster->CastSpell(handler->GetSession()->GetPlayer(), spellId, triggered);
return true;
@@ -167,8 +165,7 @@ public:
return false;
}
- bool triggered = (triggeredStr != NULL);
-
+ TriggerCastFlags triggered = (triggeredStr != NULL) ? TRIGGERED_FULL_DEBUG_MASK : TRIGGERED_NONE;
float x, y, z;
handler->GetSession()->GetPlayer()->GetClosePoint(x, y, z, dist);
@@ -230,8 +227,7 @@ public:
return false;
}
- bool triggered = (triggeredStr != NULL);
-
+ TriggerCastFlags triggered = (triggeredStr != NULL) ? TRIGGERED_FULL_DEBUG_MASK : TRIGGERED_NONE;
caster->CastSpell(caster->GetVictim(), spellId, triggered);
return true;
@@ -274,8 +270,7 @@ public:
return false;
}
- bool triggered = (triggeredStr != NULL);
-
+ TriggerCastFlags triggered = (triggeredStr != NULL) ? TRIGGERED_FULL_DEBUG_MASK : TRIGGERED_NONE;
caster->CastSpell(x, y, z, spellId, triggered);
return true;
diff --git a/src/server/scripts/Commands/cs_guild.cpp b/src/server/scripts/Commands/cs_guild.cpp
index 98fc852b573..8c4bf73395d 100644
--- a/src/server/scripts/Commands/cs_guild.cpp
+++ b/src/server/scripts/Commands/cs_guild.cpp
@@ -146,7 +146,8 @@ public:
return false;
// player's guild membership checked in AddMember before add
- return targetGuild->AddMember(targetGuid);
+ SQLTransaction trans(nullptr);
+ return targetGuild->AddMember(trans, targetGuid);
}
static bool HandleGuildUninviteCommand(ChatHandler* handler, char const* args)
@@ -164,7 +165,8 @@ public:
if (!targetGuild)
return false;
- targetGuild->DeleteMember(targetGuid, false, true, true);
+ SQLTransaction trans(nullptr);
+ targetGuild->DeleteMember(trans, targetGuid, false, true, true);
return true;
}
@@ -191,7 +193,8 @@ public:
return false;
uint8 newRank = uint8(atoi(rankStr));
- return targetGuild->ChangeMemberRank(targetGuid, newRank);
+ SQLTransaction trans(nullptr);
+ return targetGuild->ChangeMemberRank(trans, targetGuid, newRank);
}
static bool HandleGuildRenameCommand(ChatHandler* handler, char const* _args)
diff --git a/src/server/scripts/Commands/cs_message.cpp b/src/server/scripts/Commands/cs_message.cpp
index 69ff04ffb46..4b3caae686b 100644
--- a/src/server/scripts/Commands/cs_message.cpp
+++ b/src/server/scripts/Commands/cs_message.cpp
@@ -24,6 +24,7 @@ EndScriptData */
#include "ScriptMgr.h"
#include "Chat.h"
+#include "Channel.h"
#include "ChannelMgr.h"
#include "Language.h"
#include "Player.h"
@@ -63,21 +64,49 @@ public:
if (!*args)
return false;
char const* channelStr = strtok((char*)args, " ");
- char const* argStr = strtok(NULL, "");
+ char const* argStr = strtok(nullptr, "");
if (!channelStr || !argStr)
return false;
+ uint32 channelId = 0;
+ for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i)
+ {
+ ChatChannelsEntry const* entry = sChatChannelsStore.LookupEntry(i);
+ if (!entry)
+ continue;
+
+ if (strstr(entry->pattern[handler->GetSessionDbcLocale()], channelStr))
+ {
+ channelId = i;
+ break;
+ }
+ }
+
+ AreaTableEntry const* zoneEntry = nullptr;
+ for (uint32 i = 0; i < sAreaTableStore.GetNumRows(); ++i)
+ {
+ AreaTableEntry const* entry = sAreaTableStore.LookupEntry(i);
+ if (!entry)
+ continue;
+
+ if (strstr(entry->area_name[handler->GetSessionDbcLocale()], channelStr))
+ {
+ zoneEntry = entry;
+ break;
+ }
+ }
+
Player* player = handler->GetSession()->GetPlayer();
- Channel* channcel = NULL;
+ Channel* channel = nullptr;
if (ChannelMgr* cMgr = ChannelMgr::forTeam(player->GetTeam()))
- channcel = cMgr->GetChannel(channelStr, player);
+ channel = cMgr->GetChannel(channelId, channelStr, player, false, zoneEntry);
if (strcmp(argStr, "on") == 0)
{
- if (channcel)
- channcel->SetOwnership(true);
+ if (channel)
+ channel->SetOwnership(true);
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHANNEL_OWNERSHIP);
stmt->setUInt8 (0, 1);
stmt->setString(1, channelStr);
@@ -86,8 +115,8 @@ public:
}
else if (strcmp(argStr, "off") == 0)
{
- if (channcel)
- channcel->SetOwnership(false);
+ if (channel)
+ channel->SetOwnership(false);
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHANNEL_OWNERSHIP);
stmt->setUInt8 (0, 0);
stmt->setString(1, channelStr);
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 16217fbaea6..5487b9c7b2f 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -2268,19 +2268,20 @@ public:
// melee damage by specific school
if (!spellStr)
{
- uint32 absorb = 0;
- uint32 resist = 0;
+ Player* attacker = handler->GetSession()->GetPlayer();
+ DamageInfo dmgInfo(attacker, target, damage, nullptr, schoolmask, SPELL_DIRECT_DAMAGE, BASE_ATTACK);
+ attacker->CalcAbsorbResist(dmgInfo);
- handler->GetSession()->GetPlayer()->CalcAbsorbResist(target, schoolmask, SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
-
- if (damage <= absorb + resist)
+ if (!dmgInfo.GetDamage())
return true;
- damage -= absorb + resist;
+ damage = dmgInfo.GetDamage();
- handler->GetSession()->GetPlayer()->DealDamageMods(target, damage, &absorb);
- handler->GetSession()->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, schoolmask, NULL, false);
- handler->GetSession()->GetPlayer()->SendAttackStateUpdate (HITINFO_AFFECTS_VICTIM, target, 1, schoolmask, damage, absorb, resist, VICTIMSTATE_HIT, 0);
+ uint32 absorb = dmgInfo.GetAbsorb();
+ uint32 resist = dmgInfo.GetResist();
+ attacker->DealDamageMods(target, damage, &absorb);
+ attacker->DealDamage(target, damage, nullptr, DIRECT_DAMAGE, schoolmask, nullptr, false);
+ attacker->SendAttackStateUpdate(HITINFO_AFFECTS_VICTIM, target, 0, schoolmask, damage, absorb, resist, VICTIMSTATE_HIT, 0);
return true;
}
@@ -2288,10 +2289,22 @@ public:
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form
uint32 spellid = handler->extractSpellIdFromLink((char*)args);
- if (!spellid || !sSpellMgr->GetSpellInfo(spellid))
+ if (!spellid)
+ return false;
+
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid);
+ if (!spellInfo)
return false;
- handler->GetSession()->GetPlayer()->SpellNonMeleeDamageLog(target, spellid, damage);
+ Player* attacker = handler->GetSession()->GetPlayer();
+ SpellNonMeleeDamage dmgInfo(attacker, target, spellid, spellInfo->GetSchoolMask());
+ damage = attacker->SpellDamageBonusDone(target, spellInfo, damage, SPELL_DIRECT_DAMAGE);
+ damage = target->SpellDamageBonusTaken(attacker, spellInfo, damage, SPELL_DIRECT_DAMAGE);
+
+ attacker->CalculateSpellDamageTaken(&dmgInfo, damage, spellInfo);
+ attacker->DealDamageMods(dmgInfo.target, dmgInfo.damage, &dmgInfo.absorb);
+ attacker->SendSpellNonMeleeDamageLog(&dmgInfo);
+ attacker->DealSpellDamage(&dmgInfo, true);
return true;
}
diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp
index 4470fa7de42..f44b66c7498 100644
--- a/src/server/scripts/Commands/cs_reload.cpp
+++ b/src/server/scripts/Commands/cs_reload.cpp
@@ -144,7 +144,6 @@ public:
{ "spell_loot_template", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_LOOT_TEMPLATE, true, &HandleReloadLootTemplatesSpellCommand, "" },
{ "spell_linked_spell", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_LINKED_SPELL, true, &HandleReloadSpellLinkedSpellCommand, "" },
{ "spell_pet_auras", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_PET_AURAS, true, &HandleReloadSpellPetAurasCommand, "" },
- { "spell_proc_event", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_PROC_EVENT, true, &HandleReloadSpellProcEventCommand, "" },
{ "spell_proc", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_PROC, true, &HandleReloadSpellProcsCommand, "" },
{ "spell_scripts", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_SCRIPTS, true, &HandleReloadSpellScriptsCommand, "" },
{ "spell_target_position", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION, true, &HandleReloadSpellTargetPositionCommand, "" },
@@ -276,7 +275,6 @@ public:
HandleReloadSpellGroupsCommand(handler, "a");
HandleReloadSpellLearnSpellCommand(handler, "a");
HandleReloadSpellLinkedSpellCommand(handler, "a");
- HandleReloadSpellProcEventCommand(handler, "a");
HandleReloadSpellProcsCommand(handler, "a");
HandleReloadSpellBonusesCommand(handler, "a");
HandleReloadSpellTargetPositionCommand(handler, "a");
@@ -811,14 +809,6 @@ public:
return true;
}
- static bool HandleReloadSpellProcEventCommand(ChatHandler* handler, const char* /*args*/)
- {
- TC_LOG_INFO("misc", "Re-Loading Spell Proc Event conditions...");
- sSpellMgr->LoadSpellProcEvents();
- handler->SendGlobalGMSysMessage("DB table `spell_proc_event` (spell proc trigger requirements) reloaded.");
- return true;
- }
-
static bool HandleReloadSpellProcsCommand(ChatHandler* handler, const char* /*args*/)
{
TC_LOG_INFO("misc", "Re-Loading Spell Proc conditions and data...");
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h
index 446cc48d2f7..2c0f16c4ff2 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h
@@ -48,7 +48,8 @@ enum DataTypes
DATA_HALL_RUNE_4 = 19,
DATA_HALL_RUNE_5 = 20,
DATA_HALL_RUNE_6 = 21,
- DATA_HALL_RUNE_7 = 22
+ DATA_HALL_RUNE_7 = 22,
+ DATA_SCARSHIELD_INFILTRATOR = 23
};
enum CreaturesIds
@@ -71,7 +72,8 @@ enum CreaturesIds
NPC_BLACKHAND_SUMMONER = 9818,
NPC_BLACKHAND_VETERAN = 9819,
NPC_BLACKHAND_INCARCERATOR = 10316,
- NPC_LORD_VICTOR_NEFARIUS = 10162
+ NPC_LORD_VICTOR_NEFARIUS = 10162,
+ NPC_SCARSHIELD_INFILTRATOR = 10299
};
enum AdditionalData
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp
index bbe8fda37eb..89617a9f4ef 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp
@@ -109,6 +109,9 @@ public:
if (GetBossState(DATA_GYTH) == DONE)
creature->DisappearAndDie();
break;
+ case NPC_SCARSHIELD_INFILTRATOR:
+ ScarshieldInfiltrator = creature->GetGUID();
+ break;
}
}
@@ -318,6 +321,8 @@ public:
return TheBeast;
case DATA_GENERAL_DRAKKISATH:
return GeneralDrakkisath;
+ case DATA_SCARSHIELD_INFILTRATOR:
+ return ScarshieldInfiltrator;
case GO_EMBERSEER_IN:
return go_emberseerin;
case GO_DOORS:
@@ -496,6 +501,7 @@ public:
ObjectGuid LordVictorNefarius;
ObjectGuid TheBeast;
ObjectGuid GeneralDrakkisath;
+ ObjectGuid ScarshieldInfiltrator;
ObjectGuid go_emberseerin;
ObjectGuid go_doors;
ObjectGuid go_emberseerout;
@@ -565,9 +571,33 @@ public:
}
};
+class at_nearby_scarshield_infiltrator : public AreaTriggerScript
+{
+public:
+ at_nearby_scarshield_infiltrator() : AreaTriggerScript("at_nearby_scarshield_infiltrator") { }
+
+ bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/) override
+ {
+ if (player->IsAlive())
+ if (InstanceScript* instance = player->GetInstanceScript())
+ if (Creature* infiltrator = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_SCARSHIELD_INFILTRATOR)))
+ {
+ if (player->getLevel() >= 57)
+ infiltrator->AI()->SetData(1, 1);
+ else if (infiltrator->GetEntry() == NPC_SCARSHIELD_INFILTRATOR)
+ infiltrator->AI()->Talk(0, player);
+
+ return true;
+ }
+
+ return false;
+ }
+};
+
void AddSC_instance_blackrock_spire()
{
new instance_blackrock_spire();
new at_dragonspire_hall();
new at_blackrock_stadium();
+ new at_nearby_scarshield_infiltrator();
}
diff --git a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp
index d0430ebb3e5..67bda699643 100644
--- a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp
+++ b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp
@@ -54,7 +54,6 @@ enum Yells
enum Spells
{
SPELL_UNLOCK = 6421,
-
SPELL_DARK_OFFERING = 7154
};
@@ -205,6 +204,123 @@ public:
};
+enum ArugalSpells
+{
+ SPELL_TELE_UPPER = 7587,
+ SPELL_TELE_SPAWN = 7586,
+ SPELL_TELE_STAIRS = 7136,
+ NUM_TELEPORT_SPELLS = 3,
+ SPELL_ARUGAL_CURSE = 7621,
+ SPELL_THUNDERSHOCK = 7803,
+ SPELL_VOIDBOLT = 7588
+};
+
+enum ArugalTexts
+{
+ SAY_AGGRO = 1, // You, too, shall serve!
+ SAY_TRANSFORM = 2, // Release your rage!
+ SAY_SLAY = 3 // Another falls!
+};
+
+enum ArugalEvents
+{
+ EVENT_VOID_BOLT = 1,
+ EVENT_TELEPORT,
+ EVENT_THUNDERSHOCK,
+ EVENT_CURSE
+};
+
+class boss_archmage_arugal : public CreatureScript
+{
+ public:
+ boss_archmage_arugal() : CreatureScript("boss_archmage_arugal") { }
+
+ struct boss_archmage_arugalAI : public BossAI
+ {
+ boss_archmage_arugalAI(Creature* creature) : BossAI(creature, BOSS_ARUGAL) { }
+
+ uint32 teleportSpells[NUM_TELEPORT_SPELLS] =
+ {
+ SPELL_TELE_SPAWN,
+ SPELL_TELE_UPPER,
+ SPELL_TELE_STAIRS
+ };
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
+ }
+
+ void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) override
+ {
+ if (spell->Id == SPELL_ARUGAL_CURSE)
+ Talk(SAY_TRANSFORM);
+ }
+
+ void EnterCombat(Unit* /*who*/) override
+ {
+ _EnterCombat();
+ Talk(SAY_AGGRO);
+ events.ScheduleEvent(EVENT_CURSE, Seconds(7));
+ events.ScheduleEvent(EVENT_TELEPORT, Seconds(15));
+ events.ScheduleEvent(EVENT_VOID_BOLT, Seconds(1));
+ events.ScheduleEvent(EVENT_THUNDERSHOCK, Seconds(10));
+ }
+
+ void AttackStart(Unit* who) override
+ {
+ AttackStartCaster(who, 100.0f); // void bolt range is 100.f
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_CURSE:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 30.0f, true))
+ DoCast(target, SPELL_ARUGAL_CURSE);
+ events.Repeat(Seconds(15));
+ break;
+ case EVENT_TELEPORT:
+ {
+ // ensure we never cast the same teleport twice in a row
+ uint8 spellIndex = urand(1, NUM_TELEPORT_SPELLS-1);
+ std::swap(teleportSpells[0], teleportSpells[spellIndex]);
+ DoCast(teleportSpells[0]);
+ events.Repeat(Seconds(20));
+ break;
+ }
+ case EVENT_THUNDERSHOCK:
+ DoCastAOE(SPELL_THUNDERSHOCK);
+ events.Repeat(Seconds(30));
+ break;
+ case EVENT_VOID_BOLT:
+ DoCastVictim(SPELL_VOIDBOLT);
+ events.Repeat(Seconds(5));
+ break;
+ }
+ }
+ DoMeleeAttackIfReady();
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_archmage_arugalAI>(creature);
+ }
+};
+
class spell_shadowfang_keep_haunting_spirits : public SpellScriptLoader
{
public:
@@ -248,5 +364,6 @@ void AddSC_shadowfang_keep()
{
new npc_shadowfang_prisoner();
new npc_arugal_voidwalker();
+ new boss_archmage_arugal();
new spell_shadowfang_keep_haunting_spirits();
}
diff --git a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.h b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.h
index 88edc3f1ee1..7e508191f69 100644
--- a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.h
+++ b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.h
@@ -26,8 +26,8 @@ enum DataTypes
TYPE_FREE_NPC = 1,
TYPE_RETHILGORE = 2,
TYPE_FENRUS = 3,
- TYPE_NANDOS = 4
+ TYPE_NANDOS = 4,
+ BOSS_ARUGAL = 5
};
#endif
-
diff --git a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp
index adcb4f9fc9a..d9c929794cc 100644
--- a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp
+++ b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp
@@ -175,7 +175,7 @@ void AddSC_arathi_highlands();
void AddSC_blasted_lands();
void AddSC_burning_steppes();
void AddSC_duskwood();
-void AddSC_eastern_plaguelands();
+//void AddSC_eastern_plaguelands();
void AddSC_ghostlands();
void AddSC_hinterlands();
void AddSC_isle_of_queldanas();
@@ -352,7 +352,7 @@ void AddEasternKingdomsScripts()
AddSC_blasted_lands();
AddSC_burning_steppes();
AddSC_duskwood();
- AddSC_eastern_plaguelands();
+ //AddSC_eastern_plaguelands();
AddSC_ghostlands();
AddSC_hinterlands();
AddSC_isle_of_queldanas();
diff --git a/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp
deleted file mode 100644
index c35c8629cef..00000000000
--- a/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
- *
- * 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/>.
- */
-
-/* ScriptData
-SDName: Eastern_Plaguelands
-SD%Complete: 100
-SDComment: Quest support: 5211. Special vendor Augustus the Touched
-SDCategory: Eastern Plaguelands
-EndScriptData */
-
-/* ContentData
-npc_ghoul_flayer
-npc_augustus_the_touched
-npc_darrowshire_spirit
-EndContentData */
-
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-#include "ScriptedGossip.h"
-#include "Player.h"
-#include "WorldSession.h"
-
-class npc_ghoul_flayer : public CreatureScript
-{
-public:
- npc_ghoul_flayer() : CreatureScript("npc_ghoul_flayer") { }
-
- struct npc_ghoul_flayerAI : public ScriptedAI
- {
- npc_ghoul_flayerAI(Creature* creature) : ScriptedAI(creature) { }
-
- void Reset() override { }
-
- void EnterCombat(Unit* /*who*/) override { }
-
- void JustDied(Unit* killer) override
- {
- if (killer->GetTypeId() == TYPEID_PLAYER)
- me->SummonCreature(11064, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000);
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_ghoul_flayerAI(creature);
- }
-};
-
-/*######
-## npc_augustus_the_touched
-######*/
-
-class npc_augustus_the_touched : public CreatureScript
-{
-public:
- npc_augustus_the_touched() : CreatureScript("npc_augustus_the_touched") { }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- ClearGossipMenuFor(player);
- if (action == GOSSIP_ACTION_TRADE)
- player->GetSession()->SendListInventory(creature->GetGUID());
- return true;
- }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (creature->IsQuestGiver())
- player->PrepareQuestMenu(creature->GetGUID());
-
- if (creature->IsVendor() && player->GetQuestRewardStatus(6164))
- AddGossipItemFor(player, GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE);
-
- SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
- return true;
- }
-};
-
-/*######
-## npc_darrowshire_spirit
-######*/
-
-enum DarrowshireSpirit
-{
- SPELL_SPIRIT_SPAWNIN = 17321
-};
-
-class npc_darrowshire_spirit : public CreatureScript
-{
-public:
- npc_darrowshire_spirit() : CreatureScript("npc_darrowshire_spirit") { }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- SendGossipMenuFor(player, 3873, creature->GetGUID());
- player->TalkedToCreature(creature->GetEntry(), creature->GetGUID());
- creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- return true;
- }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_darrowshire_spiritAI(creature);
- }
-
- struct npc_darrowshire_spiritAI : public ScriptedAI
- {
- npc_darrowshire_spiritAI(Creature* creature) : ScriptedAI(creature) { }
-
- void Reset() override
- {
- DoCast(me, SPELL_SPIRIT_SPAWNIN);
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- }
-
- void EnterCombat(Unit* /*who*/) override { }
- };
-};
-
-void AddSC_eastern_plaguelands()
-{
- new npc_ghoul_flayer();
- new npc_augustus_the_touched();
- new npc_darrowshire_spirit();
-}
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp
index 5009cce48f4..722b7768617 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp
@@ -17,17 +17,19 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellScript.h"
#include "hyjal.h"
#include "hyjal_trash.h"
enum Spells
{
- SPELL_CARRION_SWARM = 31306,
- SPELL_SLEEP = 31298,
- SPELL_VAMPIRIC_AURA = 38196,
- SPELL_INFERNO = 31299,
- SPELL_IMMOLATION = 31303,
- SPELL_INFERNO_EFFECT = 31302,
+ SPELL_CARRION_SWARM = 31306,
+ SPELL_SLEEP = 31298,
+ SPELL_VAMPIRIC_AURA = 38196,
+ SPELL_VAMPIRIC_AURA_HEAL = 31285,
+ SPELL_INFERNO = 31299,
+ SPELL_IMMOLATION = 31303,
+ SPELL_INFERNO_EFFECT = 31302
};
enum Texts
@@ -261,8 +263,48 @@ public:
};
+class spell_anetheron_vampiric_aura : public SpellScriptLoader
+{
+ public:
+ spell_anetheron_vampiric_aura() : SpellScriptLoader("spell_anetheron_vampiric_aura") { }
+
+ class spell_anetheron_vampiric_aura_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_anetheron_vampiric_aura_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_VAMPIRIC_AURA_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 bp = damageInfo->GetDamage() * 3;
+ eventInfo.GetActor()->CastCustomSpell(SPELL_VAMPIRIC_AURA_HEAL, SPELLVALUE_BASE_POINT0, bp, eventInfo.GetActor(), true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_anetheron_vampiric_aura_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_anetheron_vampiric_aura_AuraScript();
+ }
+};
+
void AddSC_boss_anetheron()
{
new boss_anetheron();
new npc_towering_infernal();
+ new spell_anetheron_vampiric_aura();
}
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp
index 137da1002af..34a456ae502 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp
@@ -16,19 +16,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/*
-Name: The_Black_Morass
-%Complete: 30
-Comment: Misc NPC's and mobs for instance. Most here far from complete.
-Category: Caverns of Time, The Black Morass
-*/
-
-/* ContentData
-npc_medivh_bm
-npc_time_rift
-npc_saat
-EndContentData */
-
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
@@ -365,57 +352,8 @@ public:
};
-enum Saat
-{
- SPELL_CHRONO_BEACON = 34975,
- ITEM_CHRONO_BEACON = 24289
-};
-
-#define GOSSIP_ITEM_OBTAIN "[PH] Obtain Chrono-Beacon"
-
-class npc_saat : public CreatureScript
-{
-public:
- npc_saat() : CreatureScript("npc_saat") { }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- ClearGossipMenuFor(player);
- if (action == GOSSIP_ACTION_INFO_DEF+1)
- {
- CloseGossipMenuFor(player);
- creature->CastSpell(player, SPELL_CHRONO_BEACON, false);
- }
- return true;
- }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (creature->IsQuestGiver())
- player->PrepareQuestMenu(creature->GetGUID());
-
- if (player->GetQuestStatus(QUEST_OPENING_PORTAL) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(ITEM_CHRONO_BEACON))
- {
- AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM_OBTAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
- SendGossipMenuFor(player, 10000, creature->GetGUID());
- return true;
- }
- else if (player->GetQuestRewardStatus(QUEST_OPENING_PORTAL) && !player->HasItemCount(ITEM_CHRONO_BEACON))
- {
- AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM_OBTAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
- SendGossipMenuFor(player, 10001, creature->GetGUID());
- return true;
- }
-
- SendGossipMenuFor(player, 10002, creature->GetGUID());
- return true;
- }
-
-};
-
void AddSC_the_black_morass()
{
new npc_medivh_bm();
new npc_time_rift();
- new npc_saat();
}
diff --git a/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp b/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp
index c47971836ac..fdc9b0c12ff 100644
--- a/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp
+++ b/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp
@@ -331,7 +331,14 @@ enum Magwin
SAY_END1 = 3,
SAY_END2 = 4,
EMOTE_HUG = 5,
- QUEST_A_CRY_FOR_SAY_HELP = 9528,
+ NPC_COWLEN = 17311,
+ SAY_COWLEN = 0,
+ EVENT_ACCEPT_QUEST = 1,
+ EVENT_START_ESCORT = 2,
+ EVENT_STAND = 3,
+ EVENT_TALK_END = 4,
+ EVENT_COWLEN_TALK = 5,
+ QUEST_A_CRY_FOR_HELP = 9528,
FACTION_QUEST = 113
};
@@ -344,7 +351,10 @@ public:
{
npc_magwinAI(Creature* creature) : npc_escortAI(creature) { }
- void Reset() override { }
+ void Reset() override
+ {
+ _events.Reset();
+ }
void EnterCombat(Unit* who) override
{
@@ -353,10 +363,10 @@ public:
void sQuestAccept(Player* player, Quest const* quest) override
{
- if (quest->GetQuestId() == QUEST_A_CRY_FOR_SAY_HELP)
+ if (quest->GetQuestId() == QUEST_A_CRY_FOR_HELP)
{
- me->setFaction(FACTION_QUEST);
- npc_escortAI::Start(true, false, player->GetGUID());
+ _player = player->GetGUID();
+ _events.ScheduleEvent(EVENT_ACCEPT_QUEST, Seconds(2));
}
}
@@ -366,23 +376,63 @@ public:
{
switch (waypointId)
{
- case 0:
- Talk(SAY_START, player);
- break;
case 17:
Talk(SAY_PROGRESS, player);
break;
case 28:
- Talk(SAY_END1, player);
+ player->GroupEventHappens(QUEST_A_CRY_FOR_HELP, me);
+ _events.ScheduleEvent(EVENT_TALK_END, Seconds(2));
+ SetRun(true);
break;
case 29:
- Talk(EMOTE_HUG, player);
+ if (Creature* cowlen = me->FindNearestCreature(NPC_COWLEN, 50.0f, true))
+ Talk(EMOTE_HUG, cowlen);
Talk(SAY_END2, player);
- player->GroupEventHappens(QUEST_A_CRY_FOR_SAY_HELP, me);
break;
}
}
}
+
+ void UpdateEscortAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ if (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_ACCEPT_QUEST:
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _player))
+ Talk(SAY_START, player);
+ me->setFaction(FACTION_QUEST);
+ _events.ScheduleEvent(EVENT_START_ESCORT, Seconds(1));
+ break;
+ case EVENT_START_ESCORT:
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _player))
+ npc_escortAI::Start(true, false, player->GetGUID());
+ _events.ScheduleEvent(EVENT_STAND, Seconds(2));
+ break;
+ case EVENT_STAND: // Remove kneel standstate. Using a separate delayed event because it causes unwanted delay before starting waypoint movement.
+ me->SetByteValue(UNIT_FIELD_BYTES_1, 0, 0);
+ break;
+ case EVENT_TALK_END:
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _player))
+ Talk(SAY_END1, player);
+ _events.ScheduleEvent(EVENT_COWLEN_TALK, Seconds(2));
+ break;
+ case EVENT_COWLEN_TALK:
+ if (Creature* cowlen = me->FindNearestCreature(NPC_COWLEN, 50.0f, true))
+ cowlen->AI()->Talk(SAY_COWLEN);
+ break;
+ }
+ }
+
+ npc_escortAI::UpdateEscortAI(diff);
+ }
+
+ private:
+ EventMap _events;
+ ObjectGuid _player;
};
CreatureAI* GetAI(Creature* creature) const override
diff --git a/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp b/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
index a7b2b156128..3ca7954cd87 100644
--- a/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
+++ b/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
@@ -41,7 +41,7 @@ EndContentData */
######*/
//possible creatures to be spawned
-uint32 const possibleSpawns[32] = {17322, 17661, 17496, 17522, 17340, 17352, 17333, 17524, 17654, 17348, 17339, 17345, 17359, 17353, 17336, 17550, 17330, 17701, 17321, 17680, 17325, 17320, 17683, 17342, 17715, 17334, 17341, 17338, 17337, 17346, 17344, 17327};
+uint32 const possibleSpawns[31] = {17322, 17661, 17496, 17522, 17340, 17352, 17333, 17524, 17654, 17348, 17339, 17345, 17359, 17353, 17336, 17550, 17330, 17701, 17321, 17325, 17320, 17683, 17342, 17715, 17334, 17341, 17338, 17337, 17346, 17344, 17327};
enum WebbedCreature
{
@@ -74,6 +74,7 @@ public:
case 0:
if (Player* player = killer->ToPlayer())
player->KilledMonsterCredit(NPC_EXPEDITION_RESEARCHER);
+ spawnCreatureID = NPC_EXPEDITION_RESEARCHER;
break;
case 1:
case 2:
@@ -81,8 +82,7 @@ public:
break;
}
- if (spawnCreatureID)
- me->SummonCreature(spawnCreatureID, 0.0f, 0.0f, 0.0f, me->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000);
+ me->SummonCreature(spawnCreatureID, 0.0f, 0.0f, 0.0f, me->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000);
}
};
diff --git a/src/server/scripts/Kalimdor/zone_darkshore.cpp b/src/server/scripts/Kalimdor/zone_darkshore.cpp
index 230e4e2aca5..de98addd7b0 100644
--- a/src/server/scripts/Kalimdor/zone_darkshore.cpp
+++ b/src/server/scripts/Kalimdor/zone_darkshore.cpp
@@ -316,7 +316,7 @@ public:
enum Threshwackonator
{
EMOTE_START = 0,
- SAY_AT_CLOSE = 1,
+ SAY_AT_CLOSE = 0,
QUEST_GYROMAST_REV = 2078,
NPC_GELKAK = 6667,
FACTION_HOSTILE = 14
@@ -344,7 +344,7 @@ public:
{
if (me->IsWithinDistInMap(who, 10.0f))
{
- Talk(SAY_AT_CLOSE, who);
+ who->ToCreature()->AI()->Talk(SAY_AT_CLOSE, who);
DoAtEnd();
}
}
diff --git a/src/server/scripts/Kalimdor/zone_feralas.cpp b/src/server/scripts/Kalimdor/zone_feralas.cpp
index 3c6ab633f66..c35081bfdcb 100644
--- a/src/server/scripts/Kalimdor/zone_feralas.cpp
+++ b/src/server/scripts/Kalimdor/zone_feralas.cpp
@@ -156,7 +156,8 @@ public:
enum GordunniTrap
{
- GO_GORDUNNI_DIRT_MOUND = 144064,
+ GO_GORDUNNI_DIRT_MOUND_1 = 144064,
+ GO_GORDUNNI_DIRT_MOUND_2 = 177681
};
class spell_gordunni_trap : public SpellScriptLoader
@@ -171,7 +172,7 @@ class spell_gordunni_trap : public SpellScriptLoader
void HandleDummy()
{
Unit* caster = GetCaster();
- if (GameObject* chest = caster->SummonGameObject(GO_GORDUNNI_DIRT_MOUND, *caster, G3D::Quat(), 0))
+ if (GameObject* chest = caster->SummonGameObject(urand(0, 1) ? GO_GORDUNNI_DIRT_MOUND_1 : GO_GORDUNNI_DIRT_MOUND_2, *caster, G3D::Quat(), 0))
{
chest->SetSpellId(GetSpellInfo()->Id);
caster->RemoveGameObject(chest, false);
diff --git a/src/server/scripts/Kalimdor/zone_stonetalon_mountains.cpp b/src/server/scripts/Kalimdor/zone_stonetalon_mountains.cpp
index b7f88200077..7a7c104bdba 100644
--- a/src/server/scripts/Kalimdor/zone_stonetalon_mountains.cpp
+++ b/src/server/scripts/Kalimdor/zone_stonetalon_mountains.cpp
@@ -16,18 +16,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: Stonetalon_Mountains
-SD%Complete: 95
-SDComment: Quest support: 6627, 6523
-SDCategory: Stonetalon Mountains
-EndScriptData */
-
-/* ContentData
-npc_braug_dimspirit
-npc_kaya_flathoof
-EndContentData */
-
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
@@ -35,61 +23,6 @@ EndContentData */
#include "Player.h"
/*######
-## npc_braug_dimspirit
-######*/
-
-#define GOSSIP_HBD1 "Ysera"
-#define GOSSIP_HBD2 "Neltharion"
-#define GOSSIP_HBD3 "Nozdormu"
-#define GOSSIP_HBD4 "Alexstrasza"
-#define GOSSIP_HBD5 "Malygos"
-
-class npc_braug_dimspirit : public CreatureScript
-{
-public:
- npc_braug_dimspirit() : CreatureScript("npc_braug_dimspirit") { }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- ClearGossipMenuFor(player);
- if (action == GOSSIP_ACTION_INFO_DEF+1)
- {
- CloseGossipMenuFor(player);
- creature->CastSpell(player, 6766, false);
-
- }
- if (action == GOSSIP_ACTION_INFO_DEF+2)
- {
- CloseGossipMenuFor(player);
- player->AreaExploredOrEventHappens(6627);
- }
- return true;
- }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (creature->IsQuestGiver())
- player->PrepareQuestMenu(creature->GetGUID());
-
- if (player->GetQuestStatus(6627) == QUEST_STATUS_INCOMPLETE)
- {
- AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_HBD1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
- AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_HBD2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2);
- AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_HBD3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
- AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_HBD4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
- AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_HBD5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
-
- SendGossipMenuFor(player, 5820, creature->GetGUID());
- }
- else
- SendGossipMenuFor(player, 5819, creature->GetGUID());
-
- return true;
- }
-
-};
-
-/*######
## npc_kaya_flathoof
######*/
@@ -174,6 +107,5 @@ public:
void AddSC_stonetalon_mountains()
{
- new npc_braug_dimspirit();
new npc_kaya_flathoof();
}
diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h
index cc454882154..2eda9509bb8 100644
--- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h
+++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h
@@ -18,7 +18,6 @@
#ifndef AZJOL_NERUB_H_
#define AZJOL_NERUB_H_
-#define AzjolNerubScriptName "instance_azjol_nerub"
#define DataHeader "AN"
uint32 const EncounterCount = 3;
@@ -26,14 +25,16 @@ uint32 const EncounterCount = 3;
enum DataTypes
{
// Encounter States/Boss GUIDs
- DATA_KRIKTHIR_THE_GATEWATCHER = 0,
+ DATA_KRIKTHIR = 0,
DATA_HADRONOX = 1,
DATA_ANUBARAK = 2,
// Additional Data
- DATA_WATCHER_GASHRA = 3,
- DATA_WATCHER_SILTHIK = 4,
- DATA_WATCHER_NARJIL = 5
+ DATA_WATCHER_NARJIL,
+ DATA_WATCHER_GASHRA,
+ DATA_WATCHER_SILTHIK,
+ DATA_ANUBARAK_WALL,
+ DATA_ANUBARAK_WALL_2
};
enum CreatureIds
@@ -47,6 +48,12 @@ enum CreatureIds
NPC_WATCHER_SILTHIK = 28731
};
+// These are passed as -action to AI's DoAction to differentiate between them and boss scripts' own actions
+enum InstanceActions
+{
+ ACTION_GATEWATCHER_GREET = 1
+};
+
enum GameObjectIds
{
GO_KRIKTHIR_DOOR = 192395,
@@ -55,10 +62,4 @@ enum GameObjectIds
GO_ANUBARAK_DOOR_3 = 192398
};
-template<class AI>
-AI* GetAzjolNerubAI(Creature* creature)
-{
- return GetInstanceAI<AI>(creature, AzjolNerubScriptName);
-}
-
#endif // AZJOL_NERUB_H_
diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp
index 95335393942..2860698a8b2 100644
--- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp
@@ -17,65 +17,90 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "PassiveAI.h"
#include "azjol_nerub.h"
enum Spells
{
- SPELL_CARRION_BEETLES = 53520,
- SPELL_SUMMON_CARRION_BEETLES = 53521,
- SPELL_LEECHING_SWARM = 53467,
- SPELL_POUND = 53472,
- SPELL_SUBMERGE = 53421,
- SPELL_IMPALE_DMG = 53454,
- SPELL_IMPALE_SHAKEGROUND = 53455,
- SPELL_IMPALE_SPIKE = 53539, //this is not the correct visual effect
- //SPELL_IMPALE_TARGET = 53458,
+ SPELL_EMERGE = 53500,
+ SPELL_SUBMERGE = 53421,
+ SPELL_IMPALE_AURA = 53456,
+ SPELL_IMPALE_VISUAL = 53455,
+ SPELL_IMPALE_DAMAGE = 53454,
+ SPELL_LEECHING_SWARM = 53467,
+ SPELL_POUND = 59433,
+ SPELL_POUND_DAMAGE = 59432,
+ SPELL_CARRION_BEETLES = 53520,
+ SPELL_CARRION_BEETLE = 53521,
+
+ SPELL_SUMMON_DARTER = 53599,
+ SPELL_SUMMON_ASSASSIN = 53609,
+ SPELL_SUMMON_GUARDIAN = 53614,
+ SPELL_SUMMON_VENOMANCER = 53615,
+
+ SPELL_DART = 59349,
+ SPELL_BACKSTAB = 52540,
+ SPELL_ASSASSIN_VISUAL = 53611,
+ SPELL_SUNDER_ARMOR = 53618,
+ SPELL_POISON_BOLT = 53617
};
enum Creatures
{
- CREATURE_GUARDIAN = 29216,
- CREATURE_VENOMANCER = 29217,
- CREATURE_DATTER = 29213,
- CREATURE_IMPALE_TARGET = 89,
- DISPLAY_INVISIBLE = 11686
+ NPC_WORLD_TRIGGER = 22515,
};
-// not in db
enum Yells
{
- SAY_AGGRO = 0,
- SAY_SLAY = 1,
- SAY_DEATH = 2,
- SAY_LOCUST = 3,
- SAY_SUBMERGE = 4,
- SAY_INTRO = 5
+ SAY_AGGRO = 0,
+ SAY_SLAY = 1,
+ SAY_DEATH = 2,
+ SAY_LOCUST = 3,
+ SAY_SUBMERGE = 4,
+ SAY_INTRO = 5
+};
+
+enum Events
+{
+ EVENT_POUND = 1,
+ EVENT_IMPALE,
+ EVENT_LEECHING_SWARM,
+ EVENT_CARRION_BEETLES,
+ EVENT_SUBMERGE, // use event for this so we don't submerge mid-cast
+ EVENT_DARTER,
+ EVENT_ASSASSIN,
+ EVENT_GUARDIAN,
+ EVENT_VENOMANCER,
+ EVENT_CLOSE_DOOR
+};
+
+enum Actions
+{
+ ACTION_PET_DIED = 1,
+ ACTION_PET_EVADE
};
enum Misc
{
- ACHIEV_TIMED_START_EVENT = 20381,
+ ACHIEV_GOTTA_GO_START_EVENT = 20381,
};
enum Phases
{
- PHASE_MELEE = 0,
- PHASE_UNDERGROUND = 1,
- IMPALE_PHASE_TARGET = 0,
- IMPALE_PHASE_ATTACK = 1,
- IMPALE_PHASE_DMG = 2
+ PHASE_EMERGE = 1,
+ PHASE_SUBMERGE
};
-const Position SpawnPoint[2] =
+enum GUIDTypes
{
- { 550.7f, 282.8f, 224.3f, 0.0f },
- { 551.1f, 229.4f, 224.3f, 0.0f },
+ GUID_TYPE_PET = 0,
+ GUID_TYPE_IMPALE
};
-const Position SpawnPointGuardian[2] =
+enum SummonGroups
{
- { 550.348633f, 316.006805f, 234.2947f, 0.0f },
- { 550.188660f, 324.264557f, 237.7412f, 0.0f },
+ SUMMON_GROUP_WORLD_TRIGGER_GUARDIAN = 1
};
class boss_anub_arak : public CreatureScript
@@ -83,97 +108,62 @@ class boss_anub_arak : public CreatureScript
public:
boss_anub_arak() : CreatureScript("boss_anub_arak") { }
- struct boss_anub_arakAI : public ScriptedAI
+ struct boss_anub_arakAI : public BossAI
{
- boss_anub_arakAI(Creature* creature) : ScriptedAI(creature), Summons(me)
- {
- Initialize();
- instance = creature->GetInstanceScript();
- GuardianSummoned = false;
- VenomancerSummoned = false;
- DatterSummoned = false;
- UndergroundTimer = 0;
- VenomancerTimer = 0;
- DatterTimer = 0;
- DelayTimer = 0;
- }
+ boss_anub_arakAI(Creature* creature) : BossAI(creature, DATA_ANUBARAK), _nextSubmerge(0), _petCount(0), _assassinCount(0), _guardianCount(0), _venomancerCount(0) { }
- void Initialize()
+ void Reset() override
{
- CarrionBeetlesTimer = 8 * IN_MILLISECONDS;
- LeechingSwarmTimer = 20 * IN_MILLISECONDS;
- ImpaleTimer = 9 * IN_MILLISECONDS;
- PoundTimer = 15 * IN_MILLISECONDS;
-
- Phase = PHASE_MELEE;
- UndergroundPhase = 0;
- Channeling = false;
- ImpalePhase = IMPALE_PHASE_TARGET;
- ImpaleTarget.Clear();
+ BossAI::Reset();
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+ instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_GOTTA_GO_START_EVENT);
+ _nextSubmerge = 75;
+ _petCount = 0;
}
- InstanceScript* instance;
-
- bool Channeling;
- bool GuardianSummoned;
- bool VenomancerSummoned;
- bool DatterSummoned;
- uint8 Phase;
- uint32 UndergroundPhase;
- uint32 CarrionBeetlesTimer;
- uint32 LeechingSwarmTimer;
- uint32 PoundTimer;
- uint32 UndergroundTimer;
- uint32 VenomancerTimer;
- uint32 DatterTimer;
- uint32 DelayTimer;
-
- uint32 ImpaleTimer;
- uint32 ImpalePhase;
- ObjectGuid ImpaleTarget;
-
- SummonList Summons;
+ bool CanAIAttack(Unit const* /*who*/) const override { return true; } // do not check boundary here
- void Reset() override
+ void EnterCombat(Unit* who) override
{
- Initialize();
-
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE);
- me->RemoveAura(SPELL_SUBMERGE);
+ BossAI::EnterCombat(who);
- Summons.DespawnAll();
+ if (GameObject* door = instance->GetGameObject(DATA_ANUBARAK_WALL))
+ door->SetGoState(GO_STATE_ACTIVE); // open door for now
+ if (GameObject* door2 = instance->GetGameObject(DATA_ANUBARAK_WALL_2))
+ door2->SetGoState(GO_STATE_ACTIVE);
- instance->SetBossState(DATA_ANUBARAK, NOT_STARTED);
- instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
- }
-
- Creature* DoSummonImpaleTarget(Unit* target)
- {
- Position targetPos = target->GetPosition();
-
- if (TempSummon* impaleTarget = me->SummonCreature(CREATURE_IMPALE_TARGET, targetPos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 6*IN_MILLISECONDS))
+ Talk(SAY_AGGRO);
+ instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_GOTTA_GO_START_EVENT);
+
+ events.SetPhase(PHASE_EMERGE);
+ events.ScheduleEvent(EVENT_CLOSE_DOOR, Seconds(5));
+ events.ScheduleEvent(EVENT_POUND, randtime(Seconds(2), Seconds(4)), 0, PHASE_EMERGE);
+ events.ScheduleEvent(EVENT_LEECHING_SWARM, randtime(Seconds(5), Seconds(7)), 0, PHASE_EMERGE);
+ events.ScheduleEvent(EVENT_CARRION_BEETLES, randtime(Seconds(14), Seconds(17)), 0, PHASE_EMERGE);
+
+ // set up world triggers
+ std::list<TempSummon*> summoned;
+ me->SummonCreatureGroup(SUMMON_GROUP_WORLD_TRIGGER_GUARDIAN, &summoned);
+ if (summoned.empty()) // something went wrong
{
- ImpaleTarget = impaleTarget->GetGUID();
- impaleTarget->SetReactState(REACT_PASSIVE);
- impaleTarget->SetDisplayId(DISPLAY_INVISIBLE);
- impaleTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
- impaleTarget->SetControlled(true, UNIT_STATE_ROOT);
- return impaleTarget;
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
+ }
+ _guardianTrigger = (*summoned.begin())->GetGUID();
+
+ if (Creature* trigger = DoSummon(NPC_WORLD_TRIGGER, me->GetPosition(), 0u, TEMPSUMMON_MANUAL_DESPAWN))
+ _assassinTrigger = trigger->GetGUID();
+ else
+ {
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
}
-
- return NULL;
- }
-
- void EnterCombat(Unit* /*who*/) override
- {
- Talk(SAY_AGGRO);
- DelayTimer = 0;
- instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
}
- void DelayEventStart()
+ void EnterEvadeMode(EvadeReason /*why*/) override
{
- instance->SetBossState(DATA_ANUBARAK, IN_PROGRESS);
+ summons.DespawnAll();
+ _DespawnAtEvade();
}
void UpdateAI(uint32 diff) override
@@ -181,192 +171,551 @@ public:
if (!UpdateVictim())
return;
- if (DelayTimer && DelayTimer > 5000)
- DelayEventStart();
- else DelayTimer+=diff;
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- switch (Phase)
+ while (uint32 eventId = events.ExecuteEvent())
{
- case PHASE_UNDERGROUND:
- if (ImpaleTimer <= diff)
+ switch (eventId)
{
- switch (ImpalePhase)
+ case EVENT_CLOSE_DOOR:
+ if (GameObject* door = instance->GetGameObject(DATA_ANUBARAK_WALL))
+ door->SetGoState(GO_STATE_READY);
+ if (GameObject* door2 = instance->GetGameObject(DATA_ANUBARAK_WALL_2))
+ door2->SetGoState(GO_STATE_READY);
+ break;
+ case EVENT_POUND:
+ DoCastVictim(SPELL_POUND);
+ events.Repeat(randtime(Seconds(26), Seconds(32)));
+ break;
+ case EVENT_LEECHING_SWARM:
+ Talk(SAY_LOCUST);
+ DoCastAOE(SPELL_LEECHING_SWARM);
+ events.Repeat(randtime(Seconds(25), Seconds(28)));
+ break;
+ case EVENT_CARRION_BEETLES:
+ DoCastAOE(SPELL_CARRION_BEETLES);
+ events.Repeat(randtime(Seconds(24), Seconds(27)));
+ break;
+ case EVENT_IMPALE:
+ if (Creature* impaleTarget = ObjectAccessor::GetCreature(*me, _impaleTarget))
+ DoCast(impaleTarget, SPELL_IMPALE_DAMAGE, true);
+ break;
+ case EVENT_SUBMERGE:
+ Talk(SAY_SUBMERGE);
+ DoCastSelf(SPELL_SUBMERGE);
+ break;
+ case EVENT_DARTER:
{
- case IMPALE_PHASE_TARGET:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
+ std::list<Creature*> triggers;
+ me->GetCreatureListWithEntryInGrid(triggers, NPC_WORLD_TRIGGER);
+ if (!triggers.empty())
{
- if (Creature* impaleTarget = DoSummonImpaleTarget(target))
- impaleTarget->CastSpell(impaleTarget, SPELL_IMPALE_SHAKEGROUND, true);
- ImpaleTimer = 3*IN_MILLISECONDS;
- ImpalePhase = IMPALE_PHASE_ATTACK;
+ std::list<Creature*>::iterator it = triggers.begin();
+ std::advance(it, urand(0, triggers.size()-1));
+ (*it)->CastSpell(*it, SPELL_SUMMON_DARTER, true);
+ events.Repeat(Seconds(11));
}
+ else
+ EnterEvadeMode(EVADE_REASON_OTHER);
break;
- case IMPALE_PHASE_ATTACK:
- if (Creature* impaleTarget = ObjectAccessor::GetCreature(*me, ImpaleTarget))
+ }
+ case EVENT_ASSASSIN:
+ if (Creature* trigger = ObjectAccessor::GetCreature(*me, _assassinTrigger))
{
- impaleTarget->CastSpell(impaleTarget, SPELL_IMPALE_SPIKE, false);
- impaleTarget->RemoveAurasDueToSpell(SPELL_IMPALE_SHAKEGROUND);
+ trigger->CastSpell(trigger, SPELL_SUMMON_ASSASSIN, true);
+ trigger->CastSpell(trigger, SPELL_SUMMON_ASSASSIN, true);
+ if (_assassinCount > 2)
+ {
+ _assassinCount -= 2;
+ events.Repeat(Seconds(20));
+ }
+ else
+ _assassinCount = 0;
}
- ImpalePhase = IMPALE_PHASE_DMG;
- ImpaleTimer = 1*IN_MILLISECONDS;
+ else // something went wrong
+ EnterEvadeMode(EVADE_REASON_OTHER);
break;
- case IMPALE_PHASE_DMG:
- if (Creature* impaleTarget = ObjectAccessor::GetCreature(*me, ImpaleTarget))
- me->CastSpell(impaleTarget, SPELL_IMPALE_DMG, true);
- ImpalePhase = IMPALE_PHASE_TARGET;
- ImpaleTimer = 9*IN_MILLISECONDS;
- break;
- }
- } else ImpaleTimer -= diff;
-
- if (!GuardianSummoned)
- {
- for (uint8 i = 0; i < 2; ++i)
- {
- if (Creature* Guardian = me->SummonCreature(CREATURE_GUARDIAN, SpawnPointGuardian[i], TEMPSUMMON_CORPSE_DESPAWN, 0))
+ case EVENT_GUARDIAN:
+ if (Creature* trigger = ObjectAccessor::GetCreature(*me, _guardianTrigger))
{
- Guardian->AddThreat(me->GetVictim(), 0.0f);
- DoZoneInCombat(Guardian);
+ trigger->CastSpell(trigger, SPELL_SUMMON_GUARDIAN, true);
+ trigger->CastSpell(trigger, SPELL_SUMMON_GUARDIAN, true);
+ if (_guardianCount > 2)
+ {
+ _guardianCount -= 2;
+ events.Repeat(Seconds(20));
+ }
+ else
+ _guardianCount = 0;
}
- }
- GuardianSummoned = true;
- }
-
- if (!VenomancerSummoned)
- {
- if (VenomancerTimer <= diff)
- {
- if (UndergroundPhase > 1)
+ else
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ case EVENT_VENOMANCER:
+ if (Creature* trigger = ObjectAccessor::GetCreature(*me, _guardianTrigger))
{
- for (uint8 i = 0; i < 2; ++i)
+ trigger->CastSpell(trigger, SPELL_SUMMON_VENOMANCER, true);
+ trigger->CastSpell(trigger, SPELL_SUMMON_VENOMANCER, true);
+ if (_venomancerCount > 2)
{
- if (Creature* Venomancer = me->SummonCreature(CREATURE_VENOMANCER, SpawnPoint[i], TEMPSUMMON_CORPSE_DESPAWN, 0))
- {
- Venomancer->AddThreat(me->GetVictim(), 0.0f);
- DoZoneInCombat(Venomancer);
- }
+ _venomancerCount -= 2;
+ events.Repeat(Seconds(20));
}
- VenomancerSummoned = true;
+ else
+ _venomancerCount = 0;
}
- } else VenomancerTimer -= diff;
+ else
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ default:
+ break;
}
- if (!DatterSummoned)
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
+
+ DoMeleeAttackIfReady();
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ Talk(SAY_DEATH);
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
+ }
+
+ void SetGUID(ObjectGuid guid, int32 type) override
+ {
+ switch (type)
+ {
+ case GUID_TYPE_PET:
{
- if (DatterTimer <= diff)
+ if (Creature* creature = ObjectAccessor::GetCreature(*me, guid))
+ JustSummoned(creature);
+ else // something has gone horribly wrong
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ }
+ case GUID_TYPE_IMPALE:
+ _impaleTarget = guid;
+ events.ScheduleEvent(EVENT_IMPALE, Seconds(4));
+ break;
+ }
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_PET_DIED:
+ if (!_petCount) // underflow check - something has gone horribly wrong
{
- if (UndergroundPhase > 2)
- {
- for (uint8 i = 0; i < 2; ++i)
- {
- if (Creature* Datter = me->SummonCreature(CREATURE_DATTER, SpawnPoint[i], TEMPSUMMON_CORPSE_DESPAWN, 0))
- {
- Datter->AddThreat(me->GetVictim(), 0.0f);
- DoZoneInCombat(Datter);
- }
- }
- DatterSummoned = true;
- }
- } else DatterTimer -= diff;
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
+ }
+ if (!--_petCount) // last pet died, emerge
+ {
+ me->RemoveAurasDueToSpell(SPELL_SUBMERGE);
+ me->RemoveAurasDueToSpell(SPELL_IMPALE_AURA);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+ DoCastSelf(SPELL_EMERGE);
+ events.SetPhase(PHASE_EMERGE);
+ events.ScheduleEvent(EVENT_POUND, randtime(Seconds(13), Seconds(18)), 0, PHASE_EMERGE);
+ events.ScheduleEvent(EVENT_LEECHING_SWARM, randtime(Seconds(3), Seconds(7)), 0, PHASE_EMERGE);
+ events.ScheduleEvent(EVENT_CARRION_BEETLES, randtime(Seconds(10), Seconds(15)), 0, PHASE_EMERGE);
+ }
+ break;
+ case ACTION_PET_EVADE:
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ }
+ }
- if (me->HasAura(SPELL_LEECHING_SWARM))
- me->RemoveAurasDueToSpell(SPELL_LEECHING_SWARM);
+ void DamageTaken(Unit* /*source*/, uint32& damage) override
+ {
+ if (me->HasAura(SPELL_SUBMERGE))
+ damage = 0;
+ else
+ if (_nextSubmerge && me->HealthBelowPctDamaged(_nextSubmerge, damage))
+ {
+ events.CancelEvent(EVENT_SUBMERGE);
+ events.ScheduleEvent(EVENT_SUBMERGE, 0, 0, PHASE_EMERGE);
+ _nextSubmerge = _nextSubmerge-25;
}
+ }
- if (UndergroundTimer <= diff)
- {
- me->RemoveAura(SPELL_SUBMERGE);
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE);
- Phase = PHASE_MELEE;
- } else UndergroundTimer -= diff;
- break;
-
- case PHASE_MELEE:
- if (((UndergroundPhase == 0 && HealthBelowPct(75))
- || (UndergroundPhase == 1 && HealthBelowPct(50))
- || (UndergroundPhase == 2 && HealthBelowPct(25)))
- && !me->HasUnitState(UNIT_STATE_CASTING))
+ void SpellHit(Unit* /*whose*/, SpellInfo const* spell) override
+ {
+ if (spell->Id == SPELL_SUBMERGE)
+ {
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+ me->RemoveAurasDueToSpell(SPELL_LEECHING_SWARM);
+ DoCastSelf(SPELL_IMPALE_AURA, true);
+
+ events.SetPhase(PHASE_SUBMERGE);
+ switch (_nextSubmerge)
{
- GuardianSummoned = false;
- VenomancerSummoned = false;
- DatterSummoned = false;
+ case 50: // first submerge phase
+ _assassinCount = 4;
+ _guardianCount = 2;
+ _venomancerCount = 0;
+ break;
+ case 25: // second submerge phase
+ _assassinCount = 6;
+ _guardianCount = 2;
+ _venomancerCount = 2;
+ break;
+ case 0: // third submerge phase
+ _assassinCount = 6;
+ _guardianCount = 2;
+ _venomancerCount = 2;
+ events.ScheduleEvent(EVENT_DARTER, Seconds(0), 0, PHASE_SUBMERGE);
+ break;
+ }
+ _petCount = _guardianCount + _venomancerCount;
+ if (_assassinCount)
+ events.ScheduleEvent(EVENT_ASSASSIN, Seconds(0), 0, PHASE_SUBMERGE);
+ if (_guardianCount)
+ events.ScheduleEvent(EVENT_GUARDIAN, Seconds(4), 0, PHASE_SUBMERGE);
+ if (_venomancerCount)
+ events.ScheduleEvent(EVENT_VENOMANCER, Seconds(20), 0, PHASE_SUBMERGE);
+ }
+ }
- UndergroundTimer = 40*IN_MILLISECONDS;
- VenomancerTimer = 25*IN_MILLISECONDS;
- DatterTimer = 32*IN_MILLISECONDS;
+ private:
+ ObjectGuid _impaleTarget;
+ uint32 _nextSubmerge;
+ uint32 _petCount;
+ ObjectGuid _guardianTrigger;
+ ObjectGuid _assassinTrigger;
+ uint8 _assassinCount;
+ uint8 _guardianCount;
+ uint8 _venomancerCount;
+ };
- ImpalePhase = 0;
- ImpaleTimer = 9*IN_MILLISECONDS;
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_anub_arakAI>(creature);
+ }
+};
- DoCast(me, SPELL_SUBMERGE, false);
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE);
+class npc_anubarak_pet_template : public ScriptedAI
+{
+ public:
+ npc_anubarak_pet_template(Creature* creature, bool isLarge) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _isLarge(isLarge) { }
- Phase = PHASE_UNDERGROUND;
- ++UndergroundPhase;
- }
+ void InitializeAI() override
+ {
+ ScriptedAI::InitializeAI();
+ if (Creature* anubarak = _instance->GetCreature(DATA_ANUBARAK))
+ anubarak->AI()->SetGUID(me->GetGUID(), GUID_TYPE_PET);
+ else
+ me->DespawnOrUnsummon();
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ ScriptedAI::JustDied(killer);
+ if (_isLarge)
+ if (Creature* anubarak = _instance->GetCreature(DATA_ANUBARAK))
+ anubarak->AI()->DoAction(ACTION_PET_DIED);
+ }
+
+ void EnterEvadeMode(EvadeReason /*why*/) override
+ {
+ if (Creature* anubarak = _instance->GetCreature(DATA_ANUBARAK))
+ anubarak->AI()->DoAction(ACTION_PET_EVADE);
+ else
+ me->DespawnOrUnsummon();
+ }
- if (Channeling == true)
+ protected:
+ InstanceScript* _instance;
+ private:
+ bool const _isLarge;
+};
+
+class npc_anubarak_anub_ar_darter : public CreatureScript
+{
+ public:
+ npc_anubarak_anub_ar_darter() : CreatureScript("npc_anubarak_anub_ar_darter") { }
+
+ struct npc_anubarak_anub_ar_darterAI : public npc_anubarak_pet_template
+ {
+ npc_anubarak_anub_ar_darterAI(Creature* creature) : npc_anubarak_pet_template(creature, false) { }
+
+ void InitializeAI() override
+ {
+ npc_anubarak_pet_template::InitializeAI();
+ DoCastAOE(SPELL_DART);
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_anubarak_anub_ar_darterAI>(creature);
+ }
+};
+
+class npc_anubarak_anub_ar_assassin : public CreatureScript
+{
+ public:
+ npc_anubarak_anub_ar_assassin() : CreatureScript("npc_anubarak_anub_ar_assassin") { }
+
+ struct npc_anubarak_anub_ar_assassinAI : public npc_anubarak_pet_template
+ {
+ npc_anubarak_anub_ar_assassinAI(Creature* creature) : npc_anubarak_pet_template(creature, false), _backstabTimer(6 * IN_MILLISECONDS) { }
+
+ bool IsInBounds(Position const& jumpTo, CreatureBoundary const* boundary)
+ {
+ if (!boundary)
+ return true;
+ for (CreatureBoundary::const_iterator it = boundary->cbegin(); it != boundary->cend(); ++it)
+ if (!(*it)->IsWithinBoundary(&jumpTo))
+ return false;
+ return true;
+ }
+ Position GetRandomPositionAround(Creature* anubarak)
+ {
+ static float DISTANCE_MIN = 10.0f;
+ static float DISTANCE_MAX = 30.0f;
+ double angle = rand_norm() * 2.0 * M_PI;
+ return { anubarak->GetPositionX() + (float)(frand(DISTANCE_MIN, DISTANCE_MAX)*std::sin(angle)), anubarak->GetPositionY() + (float)(frand(DISTANCE_MIN, DISTANCE_MAX)*std::cos(angle)), anubarak->GetPositionZ() };
+ }
+ void InitializeAI() override
+ {
+ npc_anubarak_pet_template::InitializeAI();
+ CreatureBoundary const* boundary = _instance->GetBossBoundary(DATA_ANUBARAK);
+ if (Creature* anubarak = _instance->GetCreature(DATA_ANUBARAK))
{
- for (uint8 i = 0; i < 8; ++i)
- DoCastVictim(SPELL_SUMMON_CARRION_BEETLES, true);
- Channeling = false;
+ Position jumpTo;
+ do
+ jumpTo = GetRandomPositionAround(anubarak);
+ while (!IsInBounds(jumpTo, boundary));
+ me->GetMotionMaster()->MoveJump(jumpTo, 40.0f, 40.0f);
+ DoCastSelf(SPELL_ASSASSIN_VISUAL, true);
}
- else if (CarrionBeetlesTimer <= diff)
- {
- Channeling = true;
- DoCastVictim(SPELL_CARRION_BEETLES);
- CarrionBeetlesTimer = 25*IN_MILLISECONDS;
- } else CarrionBeetlesTimer -= diff;
+ }
- if (LeechingSwarmTimer <= diff)
- {
- DoCast(me, SPELL_LEECHING_SWARM, true);
- LeechingSwarmTimer = 19*IN_MILLISECONDS;
- } else LeechingSwarmTimer -= diff;
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
- if (PoundTimer <= diff)
+ if (diff >= _backstabTimer)
{
- if (Unit* target = me->GetVictim())
- {
- if (Creature* pImpaleTarget = DoSummonImpaleTarget(target))
- me->CastSpell(pImpaleTarget, SPELL_POUND, false);
- }
- PoundTimer = 16500;
- } else PoundTimer -= diff;
+ if (me->GetVictim() && me->GetVictim()->isInBack(me))
+ DoCastVictim(SPELL_BACKSTAB);
+ _backstabTimer = 6 * IN_MILLISECONDS;
+ }
+ else
+ _backstabTimer -= diff;
DoMeleeAttackIfReady();
- break;
}
- }
- void JustDied(Unit* /*killer*/) override
+ void MovementInform(uint32 /*type*/, uint32 id) override
+ {
+ if (id == EVENT_JUMP)
+ {
+ me->RemoveAurasDueToSpell(SPELL_ASSASSIN_VISUAL);
+ DoZoneInCombat();
+ }
+ }
+
+ private:
+ uint32 _backstabTimer;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
{
- Talk(SAY_DEATH);
- Summons.DespawnAll();
- instance->SetBossState(DATA_ANUBARAK, DONE);
+ return GetInstanceAI<npc_anubarak_anub_ar_assassinAI>(creature);
}
+};
- void KilledUnit(Unit* victim) override
+class npc_anubarak_anub_ar_guardian : public CreatureScript
+{
+ public:
+ npc_anubarak_anub_ar_guardian() : CreatureScript("npc_anubarak_anub_ar_guardian") { }
+
+ struct npc_anubarak_anub_ar_guardianAI : public npc_anubarak_pet_template
+ {
+ npc_anubarak_anub_ar_guardianAI(Creature* creature) : npc_anubarak_pet_template(creature, true), _sunderTimer(6 * IN_MILLISECONDS) { }
+
+ void UpdateAI(uint32 diff) override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
+ if (!UpdateVictim())
return;
- Talk(SAY_SLAY);
+ if (diff >= _sunderTimer)
+ {
+ DoCastVictim(SPELL_SUNDER_ARMOR);
+ _sunderTimer = 12 * IN_MILLISECONDS;
+ }
+ else
+ _sunderTimer -= diff;
+
+ DoMeleeAttackIfReady();
}
- void JustSummoned(Creature* summon) override
+ private:
+ uint32 _sunderTimer;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_anubarak_anub_ar_guardianAI>(creature);
+ }
+};
+
+class npc_anubarak_anub_ar_venomancer : public CreatureScript
+{
+ public:
+ npc_anubarak_anub_ar_venomancer() : CreatureScript("npc_anubarak_anub_ar_venomancer") { }
+
+ struct npc_anubarak_anub_ar_venomancerAI : public npc_anubarak_pet_template
+ {
+ npc_anubarak_anub_ar_venomancerAI(Creature* creature) : npc_anubarak_pet_template(creature, true), _boltTimer(5 * IN_MILLISECONDS) { }
+
+ void UpdateAI(uint32 diff) override
{
- Summons.Summon(summon);
+ if (!UpdateVictim())
+ return;
+
+ if (diff >= _boltTimer)
+ {
+ DoCastVictim(SPELL_POISON_BOLT);
+ _boltTimer = urandms(2, 3);
+ }
+ else
+ _boltTimer -= diff;
+
+ DoMeleeAttackIfReady();
}
+
+ private:
+ uint32 _boltTimer;
};
CreatureAI* GetAI(Creature* creature) const override
{
- return GetInstanceAI<boss_anub_arakAI>(creature);
+ return GetInstanceAI<npc_anubarak_anub_ar_venomancerAI>(creature);
}
};
+class npc_anubarak_impale_target : public CreatureScript
+{
+ public:
+ npc_anubarak_impale_target() : CreatureScript("npc_anubarak_impale_target") { }
+
+ struct npc_anubarak_impale_targetAI : public NullCreatureAI
+ {
+ npc_anubarak_impale_targetAI(Creature* creature) : NullCreatureAI(creature) { }
+
+ void InitializeAI() override
+ {
+ if (Creature* anubarak = me->GetInstanceScript()->GetCreature(DATA_ANUBARAK))
+ {
+ DoCastSelf(SPELL_IMPALE_VISUAL);
+ me->DespawnOrUnsummon(Seconds(6));
+ anubarak->AI()->SetGUID(me->GetGUID(), GUID_TYPE_IMPALE);
+ }
+ else
+ me->DespawnOrUnsummon();
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_anubarak_impale_targetAI>(creature);
+ }
+};
+
+class spell_anubarak_pound : public SpellScriptLoader
+{
+ public:
+ spell_anubarak_pound() : SpellScriptLoader("spell_anubarak_pound") { }
+
+ class spell_anubarak_pound_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_anubarak_pound_SpellScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return sSpellMgr->GetSpellInfo(SPELL_POUND_DAMAGE) != nullptr;
+ }
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* target = GetHitUnit())
+ GetCaster()->CastSpell(target, SPELL_POUND_DAMAGE, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_anubarak_pound_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_anubarak_pound_SpellScript();
+ }
+};
+
+class spell_anubarak_carrion_beetles : public SpellScriptLoader
+{
+ public:
+ spell_anubarak_carrion_beetles() : SpellScriptLoader("spell_anubarak_carrion_beetles") { }
+
+ class spell_anubarak_carrion_beetles_AuraScript : public AuraScript
+ {
+ public:
+ PrepareAuraScript(spell_anubarak_carrion_beetles_AuraScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return (sSpellMgr->GetSpellInfo(SPELL_CARRION_BEETLE) != nullptr);
+ }
+
+ void HandlePeriodic(AuraEffect const* /*eff*/)
+ {
+ GetCaster()->CastSpell(GetCaster(), SPELL_CARRION_BEETLE, true);
+ GetCaster()->CastSpell(GetCaster(), SPELL_CARRION_BEETLE, true);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_anubarak_carrion_beetles_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_anubarak_carrion_beetles_AuraScript();
+ }
+};
+
void AddSC_boss_anub_arak()
{
new boss_anub_arak();
+
+ new npc_anubarak_anub_ar_darter();
+ new npc_anubarak_anub_ar_assassin();
+ new npc_anubarak_anub_ar_guardian();
+ new npc_anubarak_anub_ar_venomancer();
+ new npc_anubarak_impale_target();
+
+ new spell_anubarak_pound();
+ new spell_anubarak_carrion_beetles();
}
diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp
index ff2588d204e..c41ec1c488d 100644
--- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp
@@ -15,34 +15,136 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/*
-* Comment: No Waves atm and the doors spells are crazy...
-*
-* When your group enters the main room (the one after the bridge), you will notice a group of 3 Nerubians.
-* When you engage them, 2 more groups like this one spawn behind the first one - it is important to pull the first group back,
-* so you don't aggro all 3. Hadronox will be under you, fighting Nerubians.
-*
-* This is the timed gauntlet - waves of non-elite spiders
-* will spawn from the 3 doors located a little above the main room, and will then head down to fight Hadronox. After clearing the
-* main room, it is recommended to just stay in it, kill the occasional non-elites that will attack you instead of the boss, and wait for
-* Hadronox to make his way to you. When Hadronox enters the main room, she will web the doors, and no more non-elites will spawn.
-*/
-
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "SpellAuras.h"
+#include "SpellAuraEffects.h"
#include "azjol_nerub.h"
+enum Events
+{
+ // Hadronox
+ EVENT_LEECH_POISON = 1,
+ EVENT_ACID_CLOUD,
+ EVENT_WEB_GRAB,
+ EVENT_PIERCE_ARMOR,
+ EVENT_PLAYER_CHECK,
+
+ // Anub'ar Crusher
+ EVENT_SMASH,
+
+ // Anub'ar foes - Shared
+ EVENT_TAUNT,
+
+ // Anub'ar Champion
+ EVENT_REND,
+ EVENT_PUMMEL,
+
+ // Anub'ar Crypt Guard
+ EVENT_CRUSHING_WEBS,
+ EVENT_INFECTED_WOUND,
+
+ // Anub'ar Necromancer
+ EVENT_SHADOW_BOLT,
+ EVENT_ANIMATE_BONES
+};
+
enum Spells
{
- SPELL_ACID_CLOUD = 53400, // Victim
- SPELL_LEECH_POISON = 53030, // Victim
- SPELL_PIERCE_ARMOR = 53418, // Victim
- SPELL_WEB_GRAB = 57731, // Victim
- SPELL_WEB_FRONT_DOORS = 53177, // Self
- SPELL_WEB_SIDE_DOORS = 53185, // Self
- H_SPELL_ACID_CLOUD = 59419,
- H_SPELL_LEECH_POISON = 59417,
- H_SPELL_WEB_GRAB = 59421
+ // Hadronox
+ SPELL_WEB_FRONT_DOORS = 53177,
+ SPELL_WEB_SIDE_DOORS = 53185,
+ SPELL_LEECH_POISON = 53030,
+ SPELL_LEECH_POISON_HEAL = 53800,
+ SPELL_ACID_CLOUD = 53400,
+ SPELL_WEB_GRAB = 57731,
+ SPELL_PIERCE_ARMOR = 53418,
+
+ // Anub'ar opponent summoning spells
+ SPELL_SUMMON_CHAMPION_PERIODIC = 53035,
+ SPELL_SUMMON_CRYPT_FIEND_PERIODIC = 53037,
+ SPELL_SUMMON_NECROMANCER_PERIODIC = 53036,
+ SPELL_SUMMON_CHAMPION_TOP = 53064,
+ SPELL_SUMMON_CRYPT_FIEND_TOP = 53065,
+ SPELL_SUMMON_NECROMANCER_TOP = 53066,
+ SPELL_SUMMON_CHAMPION_BOTTOM = 53090,
+ SPELL_SUMMON_CRYPT_FIEND_BOTTOM = 53091,
+ SPELL_SUMMON_NECROMANCER_BOTTOM = 53092,
+
+ // Anub'ar Crusher
+ SPELL_SMASH = 53318,
+ SPELL_FRENZY = 53801,
+
+ // Anub'ar foes - Shared
+ SPELL_TAUNT = 53798,
+
+ // Anub'ar Champion
+ SPELL_REND = 59343,
+ SPELL_PUMMEL = 59344,
+
+ // Anub'ar Crypt Guard
+ SPELL_CRUSHING_WEBS = 59347,
+ SPELL_INFECTED_WOUND = 59348,
+
+ // Anub'ar Necromancer
+ SPELL_SHADOW_BOLT = 53333,
+ SPELL_ANIMATE_BONES_1 = 53334,
+ SPELL_ANIMATE_BONES_2 = 53336,
+};
+
+enum SummonGroups
+{
+ SUMMON_GROUP_CRUSHER_1 = 1,
+ SUMMON_GROUP_CRUSHER_2 = 2,
+ SUMMON_GROUP_CRUSHER_3 = 3
+};
+
+enum Actions
+{
+ ACTION_HADRONOX_MOVE = 1,
+ ACTION_CRUSHER_ENGAGED,
+ ACTION_PACK_WALK
+};
+
+enum Data
+{
+ DATA_CRUSHER_PACK_ID = 1,
+ DATA_HADRONOX_ENTERED_COMBAT,
+ DATA_HADRONOX_WEBBED_DOORS
+};
+
+enum Creatures
+{
+ NPC_CRUSHER = 28922,
+ NPC_WORLDTRIGGER_LARGE = 23472
+};
+
+enum Talk
+{
+ CRUSHER_SAY_AGGRO = 1,
+ CRUSHER_EMOTE_FRENZY = 2,
+ HADRONOX_EMOTE_MOVE = 1
+};
+
+// Movement IDs used by the permanently spawning Anub'ar opponents - they are done in sequence, as one finishes, the next one starts
+enum Movements
+{
+ MOVE_NONE = 0,
+ MOVE_OUTSIDE,
+ MOVE_DOWNSTAIRS,
+ MOVE_DOWNSTAIRS_2,
+ MOVE_HADRONOX, // this one might have us take a detour to avoid pathfinding "through" the floor...
+ MOVE_HADRONOX_REAL // while this one will always make us movechase
+};
+
+static const uint8 NUM_STEPS = 4;
+static const Position hadronoxStep[NUM_STEPS] =
+{
+ { 515.5848f, 544.2007f, 673.6272f },
+ { 562.191f , 514.068f , 696.4448f },
+ { 610.3828f, 518.6407f, 695.9385f },
+ { 530.42f , 560.003f, 733.0308f }
};
class boss_hadronox : public CreatureScript
@@ -50,157 +152,1014 @@ class boss_hadronox : public CreatureScript
public:
boss_hadronox() : CreatureScript("boss_hadronox") { }
- struct boss_hadronoxAI : public ScriptedAI
+ struct boss_hadronoxAI : public BossAI
{
- boss_hadronoxAI(Creature* creature) : ScriptedAI(creature)
+ boss_hadronoxAI(Creature* creature) : BossAI(creature, DATA_HADRONOX), _enteredCombat(false), _doorsWebbed(false), _lastPlayerCombatState(false), _step(0) { }
+
+ bool IsInCombatWithPlayer() const
{
- Initialize();
- instance = creature->GetInstanceScript();
- fMaxDistance = 50.0f;
- bFirstTime = true;
+ std::list<HostileReference*> const& refs = me->getThreatManager().getThreatList();
+ for (HostileReference const* hostileRef : refs)
+ {
+ if (Unit const* target = hostileRef->getTarget())
+ if (target->IsControlledByPlayer())
+ return true;
+ }
+ return false;
}
- void Initialize()
+ void SetStep(uint8 step)
+ {
+ if (_lastPlayerCombatState)
+ return;
+
+ _step = step;
+ me->SetHomePosition(hadronoxStep[step]);
+ me->GetMotionMaster()->Clear();
+ me->AttackStop();
+ SetCombatMovement(false);
+ me->GetMotionMaster()->MovePoint(0, hadronoxStep[step]);
+ }
+
+ void SummonCrusherPack(SummonGroups group)
{
- uiAcidTimer = urand(10 * IN_MILLISECONDS, 14 * IN_MILLISECONDS);
- uiLeechTimer = urand(3 * IN_MILLISECONDS, 9 * IN_MILLISECONDS);
- uiPierceTimer = urand(1 * IN_MILLISECONDS, 3 * IN_MILLISECONDS);
- uiGrabTimer = urand(15 * IN_MILLISECONDS, 19 * IN_MILLISECONDS);
- uiDoorsTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS);
- uiCheckDistanceTimer = 2 * IN_MILLISECONDS;
+ std::list<TempSummon*> summoned;
+ me->SummonCreatureGroup(group, &summoned);
+ for (TempSummon* summon : summoned)
+ {
+ summon->AI()->SetData(DATA_CRUSHER_PACK_ID, group);
+ summon->AI()->DoAction(ACTION_PACK_WALK);
+ }
+ }
+
+ void MovementInform(uint32 type, uint32 /*id*/) override
+ {
+ if (type != POINT_MOTION_TYPE)
+ return;
+ SetCombatMovement(true);
+ AttackStart(me->GetVictim());
+ if (_step < NUM_STEPS-1)
+ return;
+ DoCastAOE(SPELL_WEB_FRONT_DOORS);
+ DoCastAOE(SPELL_WEB_SIDE_DOORS);
+ _doorsWebbed = true;
+ DoZoneInCombat();
+ }
+
+ uint32 GetData(uint32 data) const override
+ {
+ if (data == DATA_HADRONOX_ENTERED_COMBAT)
+ return _enteredCombat ? 1 : 0;
+ if (data == DATA_HADRONOX_WEBBED_DOORS)
+ return _doorsWebbed ? 1 : 0;
+ return 0;
}
- InstanceScript* instance;
+ bool CanAIAttack(Unit const* target) const override
+ {
+ // Prevent Hadronox from going too far from her current home position
+ if (!target->IsControlledByPlayer() && target->GetDistance(me->GetHomePosition()) > 20.0f)
+ return false;
+ return BossAI::CanAIAttack(target);
+ }
- uint32 uiAcidTimer;
- uint32 uiLeechTimer;
- uint32 uiPierceTimer;
- uint32 uiGrabTimer;
- uint32 uiDoorsTimer;
- uint32 uiCheckDistanceTimer;
+ void EnterCombat(Unit* /*who*/) override
+ {
+ events.ScheduleEvent(EVENT_LEECH_POISON, randtime(Seconds(5), Seconds(7)));
+ events.ScheduleEvent(EVENT_ACID_CLOUD, randtime(Seconds(7), Seconds(13)));
+ events.ScheduleEvent(EVENT_WEB_GRAB, randtime(Seconds(13), Seconds(19)));
+ events.ScheduleEvent(EVENT_PIERCE_ARMOR, randtime(Seconds(4), Seconds(7)));
+ events.ScheduleEvent(EVENT_PLAYER_CHECK, Seconds(1));
+ me->setActive(true);
+ }
- bool bFirstTime;
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_CRUSHER_ENGAGED:
+ if (_enteredCombat)
+ break;
+ instance->SetBossState(DATA_HADRONOX, IN_PROGRESS);
+ _enteredCombat = true;
+ SummonCrusherPack(SUMMON_GROUP_CRUSHER_2);
+ SummonCrusherPack(SUMMON_GROUP_CRUSHER_3);
+ break;
+ case ACTION_HADRONOX_MOVE:
+ if (_step < NUM_STEPS-1)
+ {
+ SetStep(_step + 1);
+ Talk(HADRONOX_EMOTE_MOVE);
+ }
+ break;
+ }
+ }
- float fMaxDistance;
+ void EnterEvadeMode(EvadeReason /*why*/) override
+ {
+ std::list<Creature*> triggers;
+ me->GetCreatureListWithEntryInGrid(triggers, NPC_WORLDTRIGGER_LARGE);
+ for (Creature* trigger : triggers)
+ if (trigger->HasAura(SPELL_SUMMON_CHAMPION_PERIODIC) || trigger->HasAura(SPELL_WEB_FRONT_DOORS) || trigger->HasAura(SPELL_WEB_SIDE_DOORS))
+ _DespawnAtEvade(25, trigger);
+ _DespawnAtEvade(25);
+ summons.DespawnAll();
+ for (ObjectGuid gNerubian : _anubar)
+ if (Creature* nerubian = ObjectAccessor::GetCreature(*me, gNerubian))
+ nerubian->DespawnOrUnsummon();
+ }
- void Reset() override
+ void SetGUID(ObjectGuid guid, int32 /*what*/) override
+ {
+ _anubar.push_back(guid);
+ }
+
+ void Initialize()
{
me->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, 9.0f);
me->SetFloatValue(UNIT_FIELD_COMBATREACH, 9.0f);
+ _enteredCombat = false;
+ _doorsWebbed = false;
+ _lastPlayerCombatState = false;
+ SetStep(0);
+ SetCombatMovement(true);
+ SummonCrusherPack(SUMMON_GROUP_CRUSHER_1);
+ }
+
+ void InitializeAI() override
+ {
+ BossAI::InitializeAI();
+ if (me->IsAlive())
+ Initialize();
+ }
+ void JustRespawned() override
+ {
+ BossAI::JustRespawned();
Initialize();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
- if (instance->GetBossState(DATA_HADRONOX) != DONE && !bFirstTime)
- instance->SetBossState(DATA_HADRONOX, FAIL);
+ events.Update(diff);
- bFirstTime = false;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_LEECH_POISON:
+ DoCastAOE(SPELL_LEECH_POISON);
+ events.Repeat(randtime(Seconds(7), Seconds(9)));
+ break;
+ case EVENT_ACID_CLOUD:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f))
+ DoCast(target, SPELL_ACID_CLOUD);
+ events.Repeat(randtime(Seconds(16), Seconds(23)));
+ break;
+ case EVENT_WEB_GRAB:
+ DoCastAOE(SPELL_WEB_GRAB);
+ events.Repeat(randtime(Seconds(20), Seconds(25)));
+ break;
+ case EVENT_PIERCE_ARMOR:
+ DoCastVictim(SPELL_PIERCE_ARMOR);
+ events.Repeat(randtime(Seconds(10), Seconds(15)));
+ break;
+ case EVENT_PLAYER_CHECK:
+ if (IsInCombatWithPlayer() != _lastPlayerCombatState)
+ {
+ _lastPlayerCombatState = !_lastPlayerCombatState;
+ if (_lastPlayerCombatState) // we are now in combat with players
+ {
+ if (!instance->CheckRequiredBosses(DATA_HADRONOX))
+ {
+ EnterEvadeMode(EVADE_REASON_SEQUENCE_BREAK);
+ return;
+ }
+ // cancel current point movement if engaged by players
+ if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
+ {
+ me->GetMotionMaster()->Clear();
+ SetCombatMovement(true);
+ AttackStart(me->GetVictim());
+ }
+ }
+ else // we are no longer in combat with players - reset the encounter
+ EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
+ }
+ events.Repeat(Seconds(1));
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
+ DoMeleeAttackIfReady();
}
- //when Hadronox kills any enemy (that includes a party member) she will regain 10% of her HP if the target had Leech Poison on
- void KilledUnit(Unit* Victim) override
+ // Safeguard to prevent Hadronox dying to NPCs
+ void DamageTaken(Unit* who, uint32& damage) override
{
- // not sure if this aura check is correct, I think it is though
- if (!Victim || !Victim->HasAura(DUNGEON_MODE(SPELL_LEECH_POISON, H_SPELL_LEECH_POISON)) || !me->IsAlive())
- return;
+ if (!who->IsControlledByPlayer() && me->HealthBelowPct(70))
+ {
+ if (me->HealthBelowPctDamaged(5, damage))
+ damage = 0;
+ else
+ damage *= (me->GetHealthPct()-5.0f)/ 65.0f;
+ }
+ }
- me->ModifyHealth(int32(me->CountPctFromMaxHealth(10)));
+ void JustSummoned(Creature* summon) override
+ {
+ summons.Summon(summon);
+ // Do not enter combat with zone
}
+
+ private:
+ bool _enteredCombat; // has a player entered combat with the first crusher pack? (talk and spawn two more packs)
+ bool _doorsWebbed; // obvious - have we reached the top and webbed the doors shut? (trigger for hadronox denied achievement)
+ bool _lastPlayerCombatState; // was there a player in our threat list the last time we checked (we check every second)
+ uint8 _step;
+ std::list<ObjectGuid> _anubar;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_hadronoxAI>(creature);
+ }
+};
+
+struct npc_hadronox_crusherPackAI : public ScriptedAI
+{
+ npc_hadronox_crusherPackAI(Creature* creature, Position const* positions) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _positions(positions), _myPack(SummonGroups(0)), _doFacing(false) { }
- void JustDied(Unit* /*killer*/) override
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_PACK_WALK)
{
- instance->SetBossState(DATA_HADRONOX, DONE);
+ switch (_myPack)
+ {
+ case SUMMON_GROUP_CRUSHER_1:
+ case SUMMON_GROUP_CRUSHER_2:
+ case SUMMON_GROUP_CRUSHER_3:
+ me->GetMotionMaster()->MovePoint(ACTION_PACK_WALK, _positions[_myPack - SUMMON_GROUP_CRUSHER_1]);
+ break;
+ default:
+ break;
+ }
}
+ }
- void EnterCombat(Unit* /*who*/) override
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type == POINT_MOTION_TYPE && id == ACTION_PACK_WALK)
+ _doFacing = true;
+ }
+
+ void EnterEvadeMode(EvadeReason /*why*/) override
+ {
+ if (Creature* hadronox = _instance->GetCreature(DATA_HADRONOX))
+ hadronox->AI()->EnterEvadeMode(EVADE_REASON_OTHER);
+ }
+
+ uint32 GetData(uint32 data) const override
+ {
+ if (data == DATA_CRUSHER_PACK_ID)
+ return _myPack;
+ return 0;
+ }
+
+ void SetData(uint32 data, uint32 value) override
+ {
+ if (data == DATA_CRUSHER_PACK_ID)
{
- instance->SetBossState(DATA_HADRONOX, IN_PROGRESS);
- me->SetInCombatWithZone();
+ _myPack = SummonGroups(value);
+ me->SetReactState(_myPack ? REACT_PASSIVE : REACT_AGGRESSIVE);
}
+ }
- void CheckDistance(float dist, const uint32 uiDiff)
+ void EnterCombat(Unit* who) override
+ {
+ if (me->HasReactState(REACT_PASSIVE))
{
- if (!me->IsInCombat())
- return;
+ std::list<Creature*> others;
+ me->GetCreatureListWithEntryInGrid(others, 0, 40.0f);
+ for (Creature* other : others)
+ if (other->AI()->GetData(DATA_CRUSHER_PACK_ID) == _myPack)
+ {
+ other->SetReactState(REACT_AGGRESSIVE);
+ other->AI()->AttackStart(who);
+ }
+ }
+ _EnterCombat();
+ ScriptedAI::EnterCombat(who);
+ }
- float x=0.0f, y=0.0f, z=0.0f;
- me->GetRespawnPosition(x, y, z);
+ virtual void _EnterCombat() = 0;
+ virtual void DoEvent(uint32 /*eventId*/) = 0;
- if (uiCheckDistanceTimer <= uiDiff)
- uiCheckDistanceTimer = 5*IN_MILLISECONDS;
- else
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (!me->HasReactState(REACT_PASSIVE))
+ {
+ ScriptedAI::MoveInLineOfSight(who);
+ return;
+ }
+
+ if (me->CanStartAttack(who, false) && me->IsWithinDistInMap(who, me->GetAttackDistance(who) + me->m_CombatDistance))
+ EnterCombat(who);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_doFacing)
+ {
+ _doFacing = false;
+ me->SetFacingTo(_positions[_myPack - SUMMON_GROUP_CRUSHER_1].GetOrientation());
+ }
+
+ if (!UpdateVictim())
+ return;
+
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ DoEvent(eventId);
+
+ DoMeleeAttackIfReady();
+ }
+
+ protected:
+ InstanceScript* const _instance;
+ EventMap _events;
+ Position const* const _positions;
+ SummonGroups _myPack;
+ bool _doFacing;
+
+};
+
+static const Position crusherWaypoints[] =
+{
+ { 529.6913f, 547.1257f, 731.9155f, 4.799650f },
+ { 517.51f , 561.439f , 734.0306f, 4.520403f },
+ { 543.414f , 551.728f , 732.0522f, 3.996804f }
+};
+class npc_anub_ar_crusher : public CreatureScript
+{
+ public:
+ npc_anub_ar_crusher() : CreatureScript("npc_anub_ar_crusher") { }
+
+ struct npc_anub_ar_crusherAI : public npc_hadronox_crusherPackAI
+ {
+ npc_anub_ar_crusherAI(Creature* creature) : npc_hadronox_crusherPackAI(creature, crusherWaypoints), _hadFrenzy(false) { }
+
+ void _EnterCombat() override
{
- uiCheckDistanceTimer -= uiDiff;
- return;
+ _events.ScheduleEvent(EVENT_SMASH, randtime(Seconds(8), Seconds(12)));
+
+ if (_myPack != SUMMON_GROUP_CRUSHER_1)
+ return;
+
+ if (Creature* hadronox = _instance->GetCreature(DATA_HADRONOX))
+ {
+ if (hadronox->AI()->GetData(DATA_HADRONOX_ENTERED_COMBAT))
+ return;
+ hadronox->AI()->DoAction(ACTION_CRUSHER_ENGAGED);
+ }
+
+ Talk(CRUSHER_SAY_AGGRO);
}
- if (me->IsInEvadeMode() || !me->GetVictim())
- return;
- if (me->GetDistance(x, y, z) > dist)
- EnterEvadeMode();
+
+ void DamageTaken(Unit* /*source*/, uint32& damage) override
+ {
+ if (_hadFrenzy || !me->HealthBelowPctDamaged(25, damage))
+ return;
+ _hadFrenzy = true;
+ Talk(CRUSHER_EMOTE_FRENZY);
+ DoCastSelf(SPELL_FRENZY);
+ }
+
+ void DoEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_SMASH:
+ DoCastVictim(SPELL_SMASH);
+ _events.Repeat(randtime(Seconds(13), Seconds(21)));
+ break;
+ }
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ if (Creature* hadronox = _instance->GetCreature(DATA_HADRONOX))
+ hadronox->AI()->DoAction(ACTION_HADRONOX_MOVE);
+ ScriptedAI::JustDied(killer);
+ }
+
+ private:
+ bool _hadFrenzy;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_anub_ar_crusherAI>(creature);
}
+};
- void UpdateAI(uint32 diff) override
+static const Position championWaypoints[] =
+{
+ { 539.2076f, 549.7539f, 732.8668f, 4.55531f },
+ { 527.3098f, 559.5197f, 732.9407f, 4.742493f },
+ { }
+};
+class npc_anub_ar_crusher_champion : public CreatureScript
+{
+ public:
+ npc_anub_ar_crusher_champion() : CreatureScript("npc_anub_ar_crusher_champion") { }
+
+ struct npc_anub_ar_crusher_championAI : public npc_hadronox_crusherPackAI
{
- //Return since we have no target
- if (!UpdateVictim())
- return;
+ npc_anub_ar_crusher_championAI(Creature* creature) : npc_hadronox_crusherPackAI(creature, championWaypoints) { }
+
+ void DoEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_REND:
+ DoCastVictim(SPELL_REND);
+ _events.Repeat(randtime(Seconds(12), Seconds(16)));
+ break;
+ case EVENT_PUMMEL:
+ DoCastVictim(SPELL_PUMMEL);
+ _events.Repeat(randtime(Seconds(12), Seconds(17)));
+ break;
+ }
+ }
+
+ void _EnterCombat() override
+ {
+ _events.ScheduleEvent(EVENT_REND, randtime(Seconds(4), Seconds(8)));
+ _events.ScheduleEvent(EVENT_PUMMEL, randtime(Seconds(15), Seconds(19)));
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_anub_ar_crusher_championAI>(creature);
+ }
+};
+
+static const Position cryptFiendWaypoints[] =
+{
+ { 520.3911f, 548.7895f, 732.0118f, 5.0091f },
+ { },
+ { 550.9611f, 545.1674f, 731.9031f, 3.996804f }
+};
+class npc_anub_ar_crusher_crypt_fiend : public CreatureScript
+{
+ public:
+ npc_anub_ar_crusher_crypt_fiend() : CreatureScript("npc_anub_ar_crusher_crypt_fiend") { }
+
+ struct npc_anub_ar_crusher_crypt_fiendAI : public npc_hadronox_crusherPackAI
+ {
+ npc_anub_ar_crusher_crypt_fiendAI(Creature* creature) : npc_hadronox_crusherPackAI(creature, cryptFiendWaypoints) { }
- // Without he comes up through the air to players on the bridge after krikthir if players crossing this bridge!
- CheckDistance(fMaxDistance, diff);
+ void DoEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_CRUSHING_WEBS:
+ DoCastVictim(SPELL_CRUSHING_WEBS);
+ _events.Repeat(randtime(Seconds(12), Seconds(16)));
+ break;
+ case EVENT_INFECTED_WOUND:
+ DoCastVictim(SPELL_INFECTED_WOUND);
+ _events.Repeat(randtime(Seconds(16), Seconds(25)));
+ break;
+ }
+ }
- if (me->HasAura(SPELL_WEB_FRONT_DOORS) || me->HasAura(SPELL_WEB_SIDE_DOORS))
+ void _EnterCombat() override
{
- if (IsCombatMovementAllowed())
- SetCombatMovement(false);
+ _events.ScheduleEvent(EVENT_CRUSHING_WEBS, randtime(Seconds(4), Seconds(8)));
+ _events.ScheduleEvent(EVENT_INFECTED_WOUND, randtime(Seconds(15), Seconds(19)));
}
- else if (!IsCombatMovementAllowed())
- SetCombatMovement(true);
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_anub_ar_crusher_crypt_fiendAI>(creature);
+ }
+};
+
+static const Position necromancerWaypoints[] =
+{
+ { },
+ { 507.6937f, 563.3471f, 734.8986f, 4.520403f },
+ { 535.1049f, 552.8961f, 732.8441f, 3.996804f },
+};
+class npc_anub_ar_crusher_necromancer : public CreatureScript
+{
+ public:
+ npc_anub_ar_crusher_necromancer() : CreatureScript("npc_anub_ar_crusher_necromancer") { }
+
+ struct npc_anub_ar_crusher_necromancerAI : public npc_hadronox_crusherPackAI
+ {
+ npc_anub_ar_crusher_necromancerAI(Creature* creature) : npc_hadronox_crusherPackAI(creature, necromancerWaypoints) { }
- if (uiPierceTimer <= diff)
+ void DoEvent(uint32 eventId) override
{
- DoCastVictim(SPELL_PIERCE_ARMOR);
- uiPierceTimer = 8*IN_MILLISECONDS;
- } else uiPierceTimer -= diff;
+ switch (eventId)
+ {
+ case EVENT_SHADOW_BOLT:
+ DoCastVictim(SPELL_SHADOW_BOLT);
+ _events.Repeat(randtime(Seconds(2), Seconds(5)));
+ break;
+ case EVENT_ANIMATE_BONES:
+ DoCastVictim(urand(0, 1) ? SPELL_ANIMATE_BONES_2 : SPELL_ANIMATE_BONES_1);
+ _events.Repeat(randtime(Seconds(35), Seconds(50)));
+ break;
+ }
+ }
- if (uiAcidTimer <= diff)
+ void _EnterCombat() override
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- DoCast(target, SPELL_ACID_CLOUD);
+ _events.ScheduleEvent(EVENT_SHADOW_BOLT, randtime(Seconds(2), Seconds(4)));
+ _events.ScheduleEvent(EVENT_ANIMATE_BONES, randtime(Seconds(37), Seconds(45)));
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_anub_ar_crusher_necromancerAI>(creature);
+ }
+};
+
+static const uint8 NUM_SPAWNS = 3;
+static const Position initialMoves[NUM_SPAWNS] =
+{
+ { 485.314606f, 611.418640f, 771.428406f },
+ { 575.760437f, 611.516418f, 771.427368f },
+ { 588.930725f, 598.233276f, 739.142151f }
+};
+static const Position downstairsMoves[NUM_SPAWNS] =
+{
+ { 513.574341f, 587.022156f, 736.229065f },
+ { 537.920410f, 580.436157f, 732.796692f },
+ { 601.289246f, 583.259644f, 725.443054f },
+};
+static const Position downstairsMoves2[NUM_SPAWNS] =
+{
+ { 571.498718f, 576.978333f, 727.582947f },
+ { 571.498718f, 576.978333f, 727.582947f },
+ { }
+};
+struct npc_hadronox_foeAI : public ScriptedAI
+{
+ npc_hadronox_foeAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _nextMovement(MOVE_OUTSIDE), _mySpawn(0) { }
+
+ void InitializeAI() override
+ {
+ ScriptedAI::InitializeAI();
+ if (Creature* hadronox = _instance->GetCreature(DATA_HADRONOX))
+ hadronox->AI()->SetGUID(me->GetGUID());
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type == POINT_MOTION_TYPE)
+ _nextMovement = Movements(id+1);
+ }
+
+ void EnterEvadeMode(EvadeReason /*why*/) override
+ {
+ me->DespawnOrUnsummon();
+ }
+
+ virtual void DoEvent(uint32 /*eventId*/) = 0;
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_nextMovement)
+ {
+ switch (_nextMovement)
+ {
+ case MOVE_OUTSIDE:
+ {
+ float dist = HUGE_VALF;
+ for (uint8 spawn = 0; spawn < NUM_SPAWNS; ++spawn)
+ {
+ float thisDist = initialMoves[spawn].GetExactDistSq(me);
+ if (thisDist < dist)
+ {
+ _mySpawn = spawn;
+ dist = thisDist;
+ }
+ }
+ me->GetMotionMaster()->MovePoint(MOVE_OUTSIDE, initialMoves[_mySpawn], false); // do not pathfind here, we have to pass through a "wall" of webbing
+ break;
+ }
+ case MOVE_DOWNSTAIRS:
+ me->GetMotionMaster()->MovePoint(MOVE_DOWNSTAIRS, downstairsMoves[_mySpawn]);
+ break;
+ case MOVE_DOWNSTAIRS_2:
+ if (downstairsMoves2[_mySpawn].GetPositionX() > 0.0f) // might be unset for this spawn - if yes, skip
+ {
+ me->GetMotionMaster()->MovePoint(MOVE_DOWNSTAIRS_2, downstairsMoves2[_mySpawn]);
+ break;
+ }
+ // intentional missing break
+ case MOVE_HADRONOX:
+ case MOVE_HADRONOX_REAL:
+ {
+ static const float zCutoff = 702.0f;
+ Creature* hadronox = _instance->GetCreature(DATA_HADRONOX);
+ if (hadronox && hadronox->IsAlive())
+ {
+ if (_nextMovement != MOVE_HADRONOX_REAL)
+ if (hadronox->GetPositionZ() < zCutoff)
+ {
+ me->GetMotionMaster()->MovePoint(MOVE_HADRONOX, hadronoxStep[2]);
+ break;
+ }
+ AttackStart(hadronox);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ _nextMovement = MOVE_NONE;
+ }
+
+ if (!UpdateVictim())
+ return;
+
+ _events.Update(diff);
- uiAcidTimer = urand(20*IN_MILLISECONDS, 30*IN_MILLISECONDS);
- } else uiAcidTimer -= diff;
+ while (uint32 eventId = _events.ExecuteEvent())
+ DoEvent(eventId);
- if (uiLeechTimer <= diff)
+ DoMeleeAttackIfReady();
+ }
+
+ protected:
+ EventMap _events;
+ InstanceScript* const _instance;
+
+ private:
+ Movements _nextMovement;
+ uint8 _mySpawn;
+};
+
+class npc_anub_ar_champion : public CreatureScript
+{
+ public:
+ npc_anub_ar_champion() : CreatureScript("npc_anub_ar_champion") { }
+
+ struct npc_anub_ar_championAI : public npc_hadronox_foeAI
+ {
+ npc_anub_ar_championAI(Creature* creature) : npc_hadronox_foeAI(creature) { }
+
+ void DoEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_REND:
+ DoCastVictim(SPELL_REND);
+ _events.Repeat(randtime(Seconds(12), Seconds(16)));
+ break;
+ case EVENT_PUMMEL:
+ DoCastVictim(SPELL_PUMMEL);
+ _events.Repeat(randtime(Seconds(12), Seconds(17)));
+ break;
+ case EVENT_TAUNT:
+ DoCastVictim(SPELL_TAUNT);
+ _events.Repeat(randtime(Seconds(15), Seconds(50)));
+ break;
+ }
+ }
+
+ void EnterCombat(Unit* /*who*/) override
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- DoCast(target, SPELL_LEECH_POISON);
+ _events.ScheduleEvent(EVENT_REND, randtime(Seconds(4), Seconds(8)));
+ _events.ScheduleEvent(EVENT_PUMMEL, randtime(Seconds(15), Seconds(19)));
+ _events.ScheduleEvent(EVENT_TAUNT, randtime(Seconds(15), Seconds(50)));
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_anub_ar_championAI>(creature);
+ }
+};
+
+class npc_anub_ar_crypt_fiend : public CreatureScript
+{
+ public:
+ npc_anub_ar_crypt_fiend() : CreatureScript("npc_anub_ar_crypt_fiend") { }
- uiLeechTimer = urand(11*IN_MILLISECONDS, 14*IN_MILLISECONDS);
- } else uiLeechTimer -= diff;
+ struct npc_anub_ar_crypt_fiendAI : public npc_hadronox_foeAI
+ {
+ npc_anub_ar_crypt_fiendAI(Creature* creature) : npc_hadronox_foeAI(creature) { }
- if (uiGrabTimer <= diff)
+ void DoEvent(uint32 eventId) override
+ {
+ switch (eventId)
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) // Draws all players (and attacking Mobs) to itself.
- DoCast(target, SPELL_WEB_GRAB);
+ case EVENT_CRUSHING_WEBS:
+ DoCastVictim(SPELL_CRUSHING_WEBS);
+ _events.Repeat(randtime(Seconds(12), Seconds(16)));
+ break;
+ case EVENT_INFECTED_WOUND:
+ DoCastVictim(SPELL_INFECTED_WOUND);
+ _events.Repeat(randtime(Seconds(16), Seconds(25)));
+ break;
+ case EVENT_TAUNT:
+ DoCastVictim(SPELL_TAUNT);
+ _events.Repeat(randtime(Seconds(15), Seconds(50)));
+ break;
+ }
+ }
- uiGrabTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS);
- } else uiGrabTimer -= diff;
+ void EnterCombat(Unit* /*who*/) override
+ {
+ _events.ScheduleEvent(EVENT_CRUSHING_WEBS, randtime(Seconds(4), Seconds(8)));
+ _events.ScheduleEvent(EVENT_INFECTED_WOUND, randtime(Seconds(15), Seconds(19)));
+ _events.ScheduleEvent(EVENT_TAUNT, randtime(Seconds(15), Seconds(50)));
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_anub_ar_crypt_fiendAI>(creature);
+ }
+};
+
+class npc_anub_ar_necromancer : public CreatureScript
+{
+ public:
+ npc_anub_ar_necromancer() : CreatureScript("npc_anub_ar_necromancer") { }
+
+ struct npc_anub_ar_necromancerAI : public npc_hadronox_foeAI
+ {
+ npc_anub_ar_necromancerAI(Creature* creature) : npc_hadronox_foeAI(creature) { }
- if (uiDoorsTimer <= diff)
+ void DoEvent(uint32 eventId) override
+ {
+ switch (eventId)
{
- uiDoorsTimer = urand(30*IN_MILLISECONDS, 60*IN_MILLISECONDS);
- } else uiDoorsTimer -= diff;
+ case EVENT_SHADOW_BOLT:
+ DoCastVictim(SPELL_SHADOW_BOLT);
+ _events.Repeat(randtime(Seconds(2), Seconds(5)));
+ break;
+ case EVENT_ANIMATE_BONES:
+ DoCastVictim(urand(0,1) ? SPELL_ANIMATE_BONES_2 : SPELL_ANIMATE_BONES_1);
+ _events.Repeat(randtime(Seconds(35), Seconds(50)));
+ break;
+ case EVENT_TAUNT:
+ DoCastVictim(SPELL_TAUNT);
+ _events.Repeat(randtime(Seconds(15), Seconds(50)));
+ break;
+ }
+ }
- DoMeleeAttackIfReady();
+ void EnterCombat(Unit* /*who*/) override
+ {
+ _events.ScheduleEvent(EVENT_SHADOW_BOLT, randtime(Seconds(2), Seconds(4)));
+ _events.ScheduleEvent(EVENT_ANIMATE_BONES, randtime(Seconds(37), Seconds(45)));
+ _events.ScheduleEvent(EVENT_TAUNT, randtime(Seconds(15), Seconds(50)));
}
};
CreatureAI* GetAI(Creature* creature) const override
{
- return GetInstanceAI<boss_hadronoxAI>(creature);
+ return GetInstanceAI<npc_anub_ar_necromancerAI>(creature);
}
};
+class spell_hadronox_periodic_summon_template_AuraScript : public AuraScript
+{
+ public:
+ spell_hadronox_periodic_summon_template_AuraScript(uint32 topSpellId, uint32 bottomSpellId) : AuraScript(), _topSpellId(topSpellId), _bottomSpellId(bottomSpellId) { }
+ PrepareAuraScript(spell_hadronox_periodic_summon_template_AuraScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return
+ (sSpellMgr->GetSpellInfo(_topSpellId) != nullptr) &&
+ (sSpellMgr->GetSpellInfo(_bottomSpellId) != nullptr);
+ }
+
+ void HandleApply(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (AuraEffect* effect = GetAura()->GetEffect(EFFECT_0))
+ effect->SetPeriodicTimer(urandms(2, 17));
+ }
+
+ void HandlePeriodic(AuraEffect const* /*eff*/)
+ {
+ Unit* caster = GetCaster();
+ if (!caster)
+ return;
+ InstanceScript* instance = caster->GetInstanceScript();
+ if (!instance)
+ return;
+ if (instance->GetBossState(DATA_HADRONOX) == DONE)
+ GetAura()->Remove();
+ else
+ {
+ if (caster->GetPositionZ() >= 750.0f)
+ caster->CastSpell(caster, _topSpellId, true);
+ else
+ caster->CastSpell(caster, _bottomSpellId, true);
+ }
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_hadronox_periodic_summon_template_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_hadronox_periodic_summon_template_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ }
+
+ private:
+ uint32 _topSpellId;
+ uint32 _bottomSpellId;
+};
+
+class spell_hadronox_periodic_summon_champion : public SpellScriptLoader
+{
+ public:
+ spell_hadronox_periodic_summon_champion() : SpellScriptLoader("spell_hadronox_periodic_summon_champion") { }
+
+ class spell_hadronox_periodic_summon_champion_AuraScript : public spell_hadronox_periodic_summon_template_AuraScript
+ {
+ public:
+ spell_hadronox_periodic_summon_champion_AuraScript() : spell_hadronox_periodic_summon_template_AuraScript(SPELL_SUMMON_CHAMPION_TOP, SPELL_SUMMON_CHAMPION_BOTTOM) { }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hadronox_periodic_summon_champion_AuraScript();
+ }
+};
+
+class spell_hadronox_periodic_summon_crypt_fiend : public SpellScriptLoader
+{
+ public:
+ spell_hadronox_periodic_summon_crypt_fiend() : SpellScriptLoader("spell_hadronox_periodic_summon_crypt_fiend") { }
+
+ class spell_hadronox_periodic_summon_crypt_fiend_AuraScript : public spell_hadronox_periodic_summon_template_AuraScript
+ {
+ public:
+ spell_hadronox_periodic_summon_crypt_fiend_AuraScript() : spell_hadronox_periodic_summon_template_AuraScript(SPELL_SUMMON_CRYPT_FIEND_TOP, SPELL_SUMMON_CRYPT_FIEND_BOTTOM) { }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hadronox_periodic_summon_crypt_fiend_AuraScript();
+ }
+};
+
+class spell_hadronox_periodic_summon_necromancer : public SpellScriptLoader
+{
+ public:
+ spell_hadronox_periodic_summon_necromancer() : SpellScriptLoader("spell_hadronox_periodic_summon_necromancer") { }
+
+ class spell_hadronox_periodic_summon_necromancer_AuraScript : public spell_hadronox_periodic_summon_template_AuraScript
+ {
+ public:
+ spell_hadronox_periodic_summon_necromancer_AuraScript() : spell_hadronox_periodic_summon_template_AuraScript(SPELL_SUMMON_NECROMANCER_TOP, SPELL_SUMMON_NECROMANCER_BOTTOM) { }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hadronox_periodic_summon_necromancer_AuraScript();
+ }
+};
+
+class spell_hadronox_leeching_poison : public SpellScriptLoader
+{
+ public:
+ spell_hadronox_leeching_poison() : SpellScriptLoader("spell_hadronox_leeching_poison") { }
+
+ class spell_hadronox_leeching_poison_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hadronox_leeching_poison_AuraScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return sSpellMgr->GetSpellInfo(SPELL_LEECH_POISON_HEAL) != nullptr;
+ }
+
+ void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH)
+ return;
+
+ if (GetTarget()->IsGuardian())
+ return;
+
+ if (Unit* caster = GetCaster())
+ caster->CastSpell(caster, SPELL_LEECH_POISON_HEAL, true);
+ }
+
+ void Register() override
+ {
+ OnEffectRemove += AuraEffectRemoveFn(spell_hadronox_leeching_poison_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_PERIODIC_LEECH, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hadronox_leeching_poison_AuraScript();
+ }
+};
+
+class spell_hadronox_web_doors : public SpellScriptLoader
+{
+ public:
+ spell_hadronox_web_doors() : SpellScriptLoader("spell_hadronox_web_doors") { }
+
+ class spell_hadronox_web_doors_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_hadronox_web_doors_SpellScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return (
+ sSpellMgr->GetSpellInfo(SPELL_SUMMON_CHAMPION_PERIODIC) &&
+ sSpellMgr->GetSpellInfo(SPELL_SUMMON_CRYPT_FIEND_PERIODIC) &&
+ sSpellMgr->GetSpellInfo(SPELL_SUMMON_NECROMANCER_PERIODIC)
+ );
+ }
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* target = GetHitUnit())
+ {
+ target->RemoveAurasDueToSpell(SPELL_SUMMON_CHAMPION_PERIODIC);
+ target->RemoveAurasDueToSpell(SPELL_SUMMON_CRYPT_FIEND_PERIODIC);
+ target->RemoveAurasDueToSpell(SPELL_SUMMON_NECROMANCER_PERIODIC);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_hadronox_web_doors_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_hadronox_web_doors_SpellScript();
+ }
+};
+
+class achievement_hadronox_denied : public AchievementCriteriaScript
+{
+ public:
+ achievement_hadronox_denied() : AchievementCriteriaScript("achievement_hadronox_denied") { }
+
+ bool OnCheck(Player* /*player*/, Unit* target) override
+ {
+ if (!target)
+ return false;
+
+ if (Creature* cTarget = target->ToCreature())
+ if (!cTarget->AI()->GetData(DATA_HADRONOX_WEBBED_DOORS))
+ return true;
+
+ return false;
+ }
+};
+
void AddSC_boss_hadronox()
{
new boss_hadronox();
+
+ new npc_anub_ar_crusher();
+ new npc_anub_ar_crusher_champion();
+ new npc_anub_ar_crusher_crypt_fiend();
+ new npc_anub_ar_crusher_necromancer();
+
+ new npc_anub_ar_champion();
+ new npc_anub_ar_crypt_fiend();
+ new npc_anub_ar_necromancer();
+
+ new spell_hadronox_periodic_summon_champion();
+ new spell_hadronox_periodic_summon_crypt_fiend();
+ new spell_hadronox_periodic_summon_necromancer();
+
+ new spell_hadronox_leeching_poison();
+ new spell_hadronox_web_doors();
+
+ new achievement_hadronox_denied();
}
diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp
index 8c977e892df..0d52a09bbdc 100644
--- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp
@@ -21,63 +21,105 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "PassiveAI.h"
+#include "SpellAuras.h"
#include "azjol_nerub.h"
-enum Spells
+enum Events
{
- SPELL_MIND_FLAY = 52586,
- SPELL_CURSE_OF_FATIGUE = 52592,
- SPELL_FRENZY = 28747, //maybe 53361
- SPELL_SUMMON_SKITTERING_SWARMER = 52438, //AOE Effect 140, maybe 52439
- SPELL_SUMMON_SKITTERING_SWARMER_1 = 52439, //Summon 3x 28735
- SPELL_ACID_SPLASH = 52446,
- SPELL_CHARGE = 16979, //maybe is another spell
- SPELL_BACKSTAB = 52540,
- SPELL_SHADOW_BOLT = 52534,
- SPELL_SHADOW_NOVA = 52535,
- SPELL_STRIKE = 52532,
- SPELL_CLEAVE = 49806,
- SPELL_ENRAGE = 52470,
- SPELL_INFECTED_BITE = 52469,
- SPELL_WEB_WRAP = 52086, //the spell is not working properly
- SPELL_BLINDING_WEBS = 52524,
- SPELL_POSION_SPRAY = 52493
+ // Krik'thir the Gatewatcher
+ EVENT_SEND_GROUP = 1,
+ EVENT_SWARM,
+ EVENT_MIND_FLAY,
+ EVENT_FRENZY,
+
+ // Watchers - Shared
+ EVENT_WEB_WRAP,
+ EVENT_INFECTED_BITE,
+
+ // Watcher Gashra
+ EVENT_ENRAGE,
+ // Watcher Narjil
+ EVENT_BLINDING_WEBS,
+ // Watcher Silthik
+ EVENT_POISON_SPRAY,
+
+ // Anubar Skirmisher
+ EVENT_ANUBAR_CHARGE,
+ EVENT_BACKSTAB,
+
+ // Anubar Shadowcaster
+ EVENT_SHADOW_BOLT,
+ EVENT_SHADOW_NOVA,
+
+ // Anubar Warrior
+ EVENT_STRIKE,
+ EVENT_CLEAVE
};
-enum Mobs
+enum Spells
{
- NPC_SKITTERING_SWARMER = 28735,
- NPC_SKITTERING_SWARMER_CONTROLLER = 32593,
- NPC_SKITTERING_INFECTIOR = 28736
+ // Krik'thir the Gatewatcher
+ SPELL_SUBBOSS_AGGRO_TRIGGER = 52343,
+ SPELL_SWARM = 52440,
+ SPELL_MIND_FLAY = 52586,
+ SPELL_CURSE_OF_FATIGUE = 52592,
+ SPELL_FRENZY = 28747,
+
+ // Watchers - Shared
+ SPELL_WEB_WRAP = 52086,
+ SPELL_WEB_WRAP_WRAPPED = 52087,
+ SPELL_INFECTED_BITE = 52469,
+
+ // Watcher Gashra
+ SPELL_ENRAGE = 52470,
+ // Watcher Narjil
+ SPELL_BLINDING_WEBS = 52524,
+ // Watcher Silthik
+ SPELL_POISON_SPRAY = 52493,
+
+ // Anub'ar Warrior
+ SPELL_CLEAVE = 49806,
+ SPELL_STRIKE = 52532,
+
+ // Anub'ar Skirmisher
+ SPELL_CHARGE = 52538,
+ SPELL_BACKSTAB = 52540,
+ SPELL_FIXTATE_TRIGGER = 52536,
+ SPELL_FIXTATE_TRIGGERED = 52537,
+
+ // Anub'ar Shadowcaster
+ SPELL_SHADOW_BOLT = 52534,
+ SPELL_SHADOW_NOVA = 52535,
+
+ // Skittering Infector
+ SPELL_ACID_SPLASH = 52446
};
-enum Yells
+enum Data
{
- SAY_AGGRO = 0,
- SAY_SLAY = 1,
- SAY_DEATH = 2,
- SAY_SWARM = 3,
- SAY_PREFIGHT = 4,
- SAY_SEND_GROUP = 5
+ DATA_PET_GROUP
};
-Position const SpawnPoint[] =
+enum Actions
{
- { 566.164f, 682.087f, 769.079f, 2.21657f },
- { 529.042f, 706.941f, 777.298f, 1.0821f },
- { 489.975f, 671.239f, 772.131f, 0.261799f },
- { 488.556f, 692.95f, 771.764f, 4.88692f },
- { 553.34f, 640.387f, 777.419f, 1.20428f },
- { 517.486f, 706.398f, 777.335f, 5.35816f },
- { 504.01f, 637.693f, 777.479f, 0.506145f },
- { 552.625f, 706.408f, 777.177f, 3.4383f }
+ ACTION_GASHRA_DIED,
+ ACTION_NARJIL_DIED,
+ ACTION_SILTHIK_DIED,
+ ACTION_WATCHER_ENGAGED,
+ ACTION_PET_ENGAGED,
+ ACTION_PET_EVADE
};
-enum Events
+enum Yells
{
- EVENT_SUMMON = 1,
- EVENT_MIND_FLAY,
- EVENT_CURSE_FATIGUE
+ SAY_AGGRO = 0,
+ SAY_SLAY = 1,
+ SAY_DEATH = 2,
+ SAY_SWARM = 3,
+ SAY_PREFIGHT = 4,
+ SAY_SEND_GROUP = 5
};
class boss_krik_thir : public CreatureScript
@@ -87,37 +129,128 @@ class boss_krik_thir : public CreatureScript
struct boss_krik_thirAI : public BossAI
{
- boss_krik_thirAI(Creature* creature) : BossAI(creature, DATA_KRIKTHIR_THE_GATEWATCHER) { }
+ boss_krik_thirAI(Creature* creature) : BossAI(creature, DATA_KRIKTHIR), _hadGreet(false), _hadFrenzy(false), _petsInCombat(false), _watchersActive(0) { }
+
+ void SummonAdds()
+ {
+ if (instance->GetBossState(DATA_KRIKTHIR) == DONE)
+ return;
+
+ for (uint8 i = 1; i <= 3; ++i)
+ {
+ std::list<TempSummon*> adds;
+ me->SummonCreatureGroup(i, &adds);
+ for (TempSummon* add : adds)
+ add->AI()->SetData(DATA_PET_GROUP, i);
+ }
+ }
void Reset() override
{
- _Reset();
+ BossAI::Reset();
+ _hadFrenzy = false;
+ _petsInCombat = false;
+ _watchersActive = 0;
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ void InitializeAI() override
+ {
+ BossAI::InitializeAI();
+ SummonAdds();
+ }
+
+ void JustRespawned() override
+ {
+ BossAI::JustRespawned();
+ SummonAdds();
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ summons.clear();
+ BossAI::JustDied(killer);
+ Talk(SAY_DEATH);
}
- void EnterCombat(Unit* /*who*/) override
+ void EnterCombat(Unit* who) override
{
- Talk(SAY_AGGRO);
- _EnterCombat();
- Summon();
+ _petsInCombat = false;
+ me->SetReactState(REACT_AGGRESSIVE);
+ summons.DoZoneInCombat();
+
+ events.CancelEvent(EVENT_SEND_GROUP);
+ events.ScheduleEvent(EVENT_SWARM, Seconds(5));
+ events.ScheduleEvent(EVENT_MIND_FLAY, randtime(Seconds(1), Seconds(3)));
- events.ScheduleEvent(EVENT_SUMMON, 15000);
- events.ScheduleEvent(EVENT_MIND_FLAY, 15000);
- events.ScheduleEvent(EVENT_CURSE_FATIGUE, 12000);
+ BossAI::EnterCombat(who);
}
- void Summon()
+ void MoveInLineOfSight(Unit* who) override
{
- for (uint8 i = 0; i < 8; i++)
+ if (!me->HasReactState(REACT_PASSIVE))
{
- me->SummonCreature(NPC_SKITTERING_SWARMER, SpawnPoint[i], TEMPSUMMON_TIMED_DESPAWN, 25000);
- uint32 summon_entry = (i == 4 || i == 5 || i == 6) ? NPC_SKITTERING_INFECTIOR : NPC_SKITTERING_SWARMER;
- me->SummonCreature(summon_entry, SpawnPoint[i], TEMPSUMMON_TIMED_DESPAWN, 25000);
+ ScriptedAI::MoveInLineOfSight(who);
+ return;
+ }
+
+ if (me->CanStartAttack(who, false) && me->IsWithinDistInMap(who, me->GetAttackDistance(who) + me->m_CombatDistance))
+ EnterCombat(who);
+ }
+
+ void EnterEvadeMode(EvadeReason /*why*/) override
+ {
+ summons.DespawnAll();
+ _DespawnAtEvade();
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case -ACTION_GATEWATCHER_GREET:
+ if (!_hadGreet && me->IsAlive() && !me->IsInCombat() && !_petsInCombat)
+ {
+ _hadGreet = true;
+ Talk(SAY_PREFIGHT);
+ }
+ break;
+ case ACTION_GASHRA_DIED:
+ case ACTION_NARJIL_DIED:
+ case ACTION_SILTHIK_DIED:
+ if (!_watchersActive) // something is wrong
+ {
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
+ }
+ if (!--_watchersActive) // if there are no watchers currently in combat...
+ events.RescheduleEvent(EVENT_SEND_GROUP, Seconds(5)); // ...send the next watcher after the targets sooner
+ break;
+ case ACTION_WATCHER_ENGAGED:
+ ++_watchersActive;
+ break;
+ case ACTION_PET_ENGAGED:
+ if (_petsInCombat || me->IsInCombat())
+ break;
+ _petsInCombat = true;
+ Talk(SAY_AGGRO);
+ events.ScheduleEvent(EVENT_SEND_GROUP, Seconds(70));
+ break;
+ case ACTION_PET_EVADE:
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
}
}
void UpdateAI(uint32 diff) override
{
- if (!UpdateVictim())
+ if (!UpdateVictim() && !_petsInCombat)
return;
events.Update(diff);
@@ -125,128 +258,183 @@ class boss_krik_thir : public CreatureScript
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
+ if (me->HealthBelowPct(10) && !_hadFrenzy)
+ {
+ _hadFrenzy = true;
+ events.ScheduleEvent(EVENT_FRENZY, Seconds(1));
+ }
+
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
- case EVENT_SUMMON:
- Summon();
- events.ScheduleEvent(EVENT_SUMMON, 15000);
+ case EVENT_SEND_GROUP:
+ DoCastAOE(SPELL_SUBBOSS_AGGRO_TRIGGER, true);
+ events.Repeat(Seconds(70));
+ break;
+
+ case EVENT_SWARM:
+ DoCastAOE(SPELL_SWARM);
+ Talk(SAY_SWARM);
break;
+
case EVENT_MIND_FLAY:
DoCastVictim(SPELL_MIND_FLAY);
- events.ScheduleEvent(EVENT_MIND_FLAY, 15000);
- break;
- case EVENT_CURSE_FATIGUE:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- DoCast(target, SPELL_CURSE_OF_FATIGUE);
- events.ScheduleEvent(EVENT_CURSE_FATIGUE, 10000);
+ events.Repeat(randtime(Seconds(9), Seconds(11)));
break;
- default:
+
+ case EVENT_FRENZY:
+ DoCastSelf(SPELL_FRENZY);
+ DoCastAOE(SPELL_CURSE_OF_FATIGUE);
+ events.Repeat(Seconds(15));
break;
}
- }
- if (!me->HasAura(SPELL_FRENZY) && HealthBelowPct(10))
- DoCast(me, SPELL_FRENZY, true);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
DoMeleeAttackIfReady();
}
- void JustDied(Unit* /*killer*/) override
+ void SpellHit(Unit* /*whose*/, SpellInfo const* spell) override
{
- Talk(SAY_DEATH);
- _JustDied();
+ if (spell->Id == SPELL_SUBBOSS_AGGRO_TRIGGER)
+ DoZoneInCombat();
}
- void KilledUnit(Unit* victim) override
+ void SpellHitTarget(Unit* /*who*/, SpellInfo const* spell) override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_SLAY);
+ if (spell->Id == SPELL_SUBBOSS_AGGRO_TRIGGER)
+ Talk(SAY_SEND_GROUP);
}
- void JustSummoned(Creature* summoned) override
- {
- summoned->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ());
- }
+ private:
+ bool _hadGreet;
+ bool _hadFrenzy;
+ bool _petsInCombat;
+ uint8 _watchersActive;
};
CreatureAI* GetAI(Creature* creature) const override
{
- return GetAzjolNerubAI<boss_krik_thirAI>(creature);
+ return GetInstanceAI<boss_krik_thirAI>(creature);
}
};
-class npc_skittering_infector : public CreatureScript
+struct npc_gatewatcher_petAI : public ScriptedAI
{
- public:
- npc_skittering_infector() : CreatureScript("npc_skittering_infector") { }
+ npc_gatewatcher_petAI(Creature* creature, bool isWatcher) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _petGroup(0), _isWatcher(isWatcher) { }
- struct npc_skittering_infectorAI : public ScriptedAI
+ virtual void _EnterCombat() = 0;
+ void EnterCombat(Unit* who) override
+ {
+ if (_isWatcher)
{
- npc_skittering_infectorAI(Creature* creature) : ScriptedAI(creature) { }
-
- void JustDied(Unit* /*killer*/) override
- {
- DoCastAOE(SPELL_ACID_SPLASH);
- }
- };
+ _isWatcher = false;
+ if (TempSummon* meSummon = me->ToTempSummon())
+ if (Creature* summoner = meSummon->GetSummonerCreatureBase())
+ summoner->AI()->DoAction(ACTION_WATCHER_ENGAGED);
+ }
- CreatureAI* GetAI(Creature* creature) const override
+ if (me->HasReactState(REACT_PASSIVE))
{
- return GetAzjolNerubAI<npc_skittering_infectorAI>(creature);
- }
-};
+ std::list<Creature*> others;
+ me->GetCreatureListWithEntryInGrid(others, 0, 40.0f);
+ for (Creature* other : others)
+ if (other->AI()->GetData(DATA_PET_GROUP) == _petGroup)
+ {
+ other->SetReactState(REACT_AGGRESSIVE);
+ other->AI()->AttackStart(who);
+ }
-enum TrashEvents
-{
- // Anubar Skrimisher
- EVENT_ANUBAR_CHARGE = 1,
- EVENT_BACKSTAB,
+ if (TempSummon* meSummon = me->ToTempSummon())
+ if (Creature* summoner = meSummon->GetSummonerCreatureBase())
+ summoner->AI()->DoAction(ACTION_PET_ENGAGED);
+ }
+ _EnterCombat();
+ ScriptedAI::EnterCombat(who);
+ }
- // Anubar Shadowcaster
- EVENT_SHADOW_BOLT,
- EVENT_SHADOW_NOVA,
+ void SetData(uint32 data, uint32 value) override
+ {
+ if (data == DATA_PET_GROUP)
+ {
+ _petGroup = value;
+ me->SetReactState(_petGroup ? REACT_PASSIVE : REACT_AGGRESSIVE);
+ }
+ }
+
+ uint32 GetData(uint32 data) const override
+ {
+ if (data == DATA_PET_GROUP)
+ return _petGroup;
+ return 0;
+ }
+
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (!me->HasReactState(REACT_PASSIVE))
+ {
+ ScriptedAI::MoveInLineOfSight(who);
+ return;
+ }
- // Anubar Warrior
- EVENT_STRIKE,
- EVENT_CLEAVE,
+ if (me->CanStartAttack(who, false) && me->IsWithinDistInMap(who, me->GetAttackDistance(who) + me->m_CombatDistance))
+ EnterCombat(who);
+ }
- // Watcher Gashra
- EVENT_WEB_WRAP_GASHRA,
- EVENT_INFECTED_BITE_GASHRA,
+ void SpellHit(Unit* /*whose*/, SpellInfo const* spell) override
+ {
+ if (spell->Id == SPELL_SUBBOSS_AGGRO_TRIGGER)
+ DoZoneInCombat();
+ }
- // Watcher Narjil
- EVENT_WEB_WRAP_NARJIL,
- EVENT_INFECTED_BITE_NARJIL,
- EVENT_BINDING_WEBS,
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ if (TempSummon* meSummon = me->ToTempSummon())
+ {
+ if (Creature* summoner = meSummon->GetSummonerCreatureBase())
+ summoner->AI()->DoAction(ACTION_PET_EVADE);
+ else
+ me->DespawnOrUnsummon();
+ return;
+ }
+ ScriptedAI::EnterEvadeMode(why);
+ }
- // Watcher Silthik
- EVENT_WEB_WRAP_SILTHIK,
- EVENT_INFECTED_BITE_SILTHIK,
- EVENT_POISON_SPRAY
+ EventMap _events;
+ InstanceScript* _instance;
+ uint32 _petGroup;
+ bool _isWatcher;
};
-class npc_anub_ar_skirmisher : public CreatureScript
+class npc_watcher_gashra : public CreatureScript
{
public:
- npc_anub_ar_skirmisher() : CreatureScript("npc_anub_ar_skirmisher") { }
+ npc_watcher_gashra() : CreatureScript("npc_watcher_gashra") { }
- struct npc_anub_ar_skirmisherAI : public ScriptedAI
+ struct npc_watcher_gashraAI : public npc_gatewatcher_petAI
{
- npc_anub_ar_skirmisherAI(Creature* creature) : ScriptedAI(creature) { }
+ npc_watcher_gashraAI(Creature* creature) : npc_gatewatcher_petAI(creature, true) { }
void Reset() override
{
- events.Reset();
+ _events.Reset();
}
- void EnterCombat(Unit* /*who*/) override
+ void _EnterCombat() override
{
- events.ScheduleEvent(EVENT_ANUBAR_CHARGE, 11000);
- events.ScheduleEvent(EVENT_BACKSTAB, 7000);
+ _events.ScheduleEvent(EVENT_ENRAGE, randtime(Seconds(3), Seconds(5)));
+ _events.ScheduleEvent(EVENT_WEB_WRAP, randtime(Seconds(16), Seconds(19)));
+ _events.ScheduleEvent(EVENT_INFECTED_BITE, randtime(Seconds(7),Seconds(11)));
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ Creature* krikthir = _instance->GetCreature(DATA_KRIKTHIR);
+ if (krikthir && krikthir->IsAlive())
+ krikthir->AI()->DoAction(ACTION_GASHRA_DIED);
}
void UpdateAI(uint32 diff) override
@@ -254,64 +442,77 @@ class npc_anub_ar_skirmisher : public CreatureScript
if (!UpdateVictim())
return;
- events.Update(diff);
+ _events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
- while (uint32 eventId = events.ExecuteEvent())
+ while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
- case EVENT_ANUBAR_CHARGE:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- {
- DoResetThreat();
- me->AddThreat(target, 1.0f);
- DoCast(target, SPELL_CHARGE, true);
- }
- events.ScheduleEvent(EVENT_ANUBAR_CHARGE, 15000);
+ case EVENT_ENRAGE:
+ DoCastSelf(SPELL_ENRAGE);
+ _events.Repeat(randtime(Seconds(12), Seconds(20)));
break;
- case EVENT_BACKSTAB:
- DoCastVictim(SPELL_BACKSTAB);
- events.ScheduleEvent(EVENT_BACKSTAB, 12000);
+ case EVENT_WEB_WRAP:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f))
+ DoCast(target, SPELL_WEB_WRAP);
+ _events.Repeat(randtime(Seconds(13), Seconds(19)));
+ break;
+ case EVENT_INFECTED_BITE:
+ DoCastVictim(SPELL_INFECTED_BITE);
+ _events.Repeat(randtime(Seconds(23), Seconds(27)));
break;
default:
break;
}
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
}
DoMeleeAttackIfReady();
}
private:
- EventMap events;
+ EventMap _events;
};
CreatureAI* GetAI(Creature* creature) const override
{
- return GetAzjolNerubAI<npc_anub_ar_skirmisherAI>(creature);
+ return GetInstanceAI<npc_watcher_gashraAI>(creature);
}
};
-class npc_anub_ar_shadowcaster : public CreatureScript
+class npc_watcher_narjil : public CreatureScript
{
public:
- npc_anub_ar_shadowcaster() : CreatureScript("npc_anub_ar_shadowcaster") { }
+ npc_watcher_narjil() : CreatureScript("npc_watcher_narjil") { }
- struct npc_anub_ar_shadowcasterAI : public ScriptedAI
+ struct npc_watcher_narjilAI : public npc_gatewatcher_petAI
{
- npc_anub_ar_shadowcasterAI(Creature* creature) : ScriptedAI(creature) { }
+ npc_watcher_narjilAI(Creature* creature) : npc_gatewatcher_petAI(creature, true)
+ {
+ }
void Reset() override
{
- events.Reset();
+ _events.Reset();
+ }
+
+ void _EnterCombat() override
+ {
+ _events.ScheduleEvent(EVENT_BLINDING_WEBS, randtime(Seconds(13), Seconds(18)));
+ _events.ScheduleEvent(EVENT_WEB_WRAP, randtime(Seconds(3), Seconds(5)));
+ _events.ScheduleEvent(EVENT_INFECTED_BITE, randtime(Seconds(7), Seconds(11)));
}
- void EnterCombat(Unit* /*who*/) override
+ void JustDied(Unit* /*killer*/) override
{
- events.ScheduleEvent(EVENT_SHADOW_BOLT, 6000);
- events.ScheduleEvent(EVENT_SHADOW_NOVA, 15000);
+ Creature* krikthir = _instance->GetCreature(DATA_KRIKTHIR);
+ if (krikthir && krikthir->IsAlive())
+ krikthir->AI()->DoAction(ACTION_NARJIL_DIED);
}
void UpdateAI(uint32 diff) override
@@ -319,60 +520,77 @@ class npc_anub_ar_shadowcaster : public CreatureScript
if (!UpdateVictim())
return;
- events.Update(diff);
+ _events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
- while (uint32 eventId = events.ExecuteEvent())
+ while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
- case EVENT_SHADOW_BOLT:
+ case EVENT_BLINDING_WEBS:
+ DoCastVictim(SPELL_BLINDING_WEBS);
+ _events.Repeat(randtime(Seconds(23), Seconds(27)));
+ break;
+ case EVENT_WEB_WRAP:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- DoCast(target, SPELL_SHADOW_BOLT, true);
- events.ScheduleEvent(EVENT_SHADOW_BOLT, 15000);
+ DoCast(target, SPELL_WEB_WRAP);
+ _events.Repeat(randtime(Seconds(13), Seconds(19)));
break;
- case EVENT_SHADOW_NOVA:
- DoCastVictim(SPELL_SHADOW_NOVA, true);
- events.ScheduleEvent(EVENT_SHADOW_NOVA, 17000);
+ case EVENT_INFECTED_BITE:
+ DoCastVictim(SPELL_INFECTED_BITE);
+ _events.Repeat(randtime(Seconds(20), Seconds(25)));
break;
default:
break;
}
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
}
DoMeleeAttackIfReady();
}
private:
- EventMap events;
+ EventMap _events;
};
CreatureAI* GetAI(Creature* creature) const override
{
- return GetAzjolNerubAI<npc_anub_ar_shadowcasterAI>(creature);
+ return GetInstanceAI<npc_watcher_narjilAI>(creature);
}
};
-class npc_anub_ar_warrior : public CreatureScript
+class npc_watcher_silthik : public CreatureScript
{
public:
- npc_anub_ar_warrior() : CreatureScript("npc_anub_ar_warrior") { }
+ npc_watcher_silthik() : CreatureScript("npc_watcher_silthik") { }
- struct npc_anub_ar_warriorAI : public ScriptedAI
+ struct npc_watcher_silthikAI : public npc_gatewatcher_petAI
{
- npc_anub_ar_warriorAI(Creature* creature) : ScriptedAI(creature) { }
+ npc_watcher_silthikAI(Creature* creature) : npc_gatewatcher_petAI(creature, true)
+ {
+ }
void Reset() override
{
- events.Reset();
+ _events.Reset();
+ }
+
+ void _EnterCombat() override
+ {
+ _events.ScheduleEvent(EVENT_POISON_SPRAY, randtime(Seconds(16), Seconds(19)));
+ _events.ScheduleEvent(EVENT_WEB_WRAP, randtime(Seconds(7), Seconds(11)));
+ _events.ScheduleEvent(EVENT_INFECTED_BITE, randtime(Seconds(3), Seconds(5)));
}
- void EnterCombat(Unit* /*who*/) override
+ void JustDied(Unit* /*killer*/) override
{
- events.ScheduleEvent(EVENT_CLEAVE, 11000);
- events.ScheduleEvent(EVENT_STRIKE, 6000);
+ Creature* krikthir = _instance->GetCreature(DATA_KRIKTHIR);
+ if (krikthir && krikthir->IsAlive())
+ krikthir->AI()->DoAction(ACTION_SILTHIK_DIED);
}
void UpdateAI(uint32 diff) override
@@ -380,70 +598,67 @@ class npc_anub_ar_warrior : public CreatureScript
if (!UpdateVictim())
return;
- events.Update(diff);
+ _events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
- while (uint32 eventId = events.ExecuteEvent())
+ while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
- case EVENT_CLEAVE:
- DoCastVictim(SPELL_STRIKE, true);
- events.ScheduleEvent(EVENT_CLEAVE, 15000);
+ case EVENT_POISON_SPRAY:
+ DoCastVictim(SPELL_POISON_SPRAY);
+ _events.Repeat(randtime(Seconds(13), Seconds(19)));
break;
- case EVENT_STRIKE:
- DoCastVictim(SPELL_CLEAVE, true);
- events.ScheduleEvent(EVENT_STRIKE, 17000);
+ case EVENT_WEB_WRAP:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
+ DoCast(target, SPELL_WEB_WRAP);
+ _events.Repeat(randtime(Seconds(13), Seconds(17)));
+ break;
+ case EVENT_INFECTED_BITE:
+ DoCastVictim(SPELL_INFECTED_BITE);
+ _events.Repeat(randtime(Seconds(20), Seconds(24)));
break;
default:
break;
}
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
}
DoMeleeAttackIfReady();
}
private:
- EventMap events;
+ EventMap _events;
};
CreatureAI* GetAI(Creature* creature) const override
{
- return GetAzjolNerubAI<npc_anub_ar_warriorAI>(creature);
+ return GetInstanceAI<npc_watcher_silthikAI>(creature);
}
};
-class npc_watcher_gashra : public CreatureScript
+class npc_anub_ar_warrior : public CreatureScript
{
public:
- npc_watcher_gashra() : CreatureScript("npc_watcher_gashra") { }
+ npc_anub_ar_warrior() : CreatureScript("npc_anub_ar_warrior") { }
- struct npc_watcher_gashraAI : public ScriptedAI
+ struct npc_anub_ar_warriorAI : public npc_gatewatcher_petAI
{
- npc_watcher_gashraAI(Creature* creature) : ScriptedAI(creature)
- {
- _instance = creature->GetInstanceScript();
- }
+ npc_anub_ar_warriorAI(Creature* creature) : npc_gatewatcher_petAI(creature, false) { }
void Reset() override
{
_events.Reset();
}
- void EnterCombat(Unit* /*who*/) override
- {
- DoCast(me, SPELL_ENRAGE, true);
- _events.ScheduleEvent(EVENT_WEB_WRAP_GASHRA, 11000);
- _events.ScheduleEvent(EVENT_INFECTED_BITE_GASHRA, 4000);
- }
-
- void JustDied(Unit* /*killer*/) override
+ void _EnterCombat() override
{
- Creature* krikthir = _instance->GetCreature(DATA_KRIKTHIR_THE_GATEWATCHER);
- if (krikthir && krikthir->IsAlive())
- krikthir->AI()->Talk(SAY_PREFIGHT);
+ _events.ScheduleEvent(EVENT_CLEAVE, randtime(Seconds(7), Seconds(9)));
+ _events.ScheduleEvent(EVENT_STRIKE, randtime(Seconds(5), Seconds(10)));
}
void UpdateAI(uint32 diff) override
@@ -460,63 +675,50 @@ class npc_watcher_gashra : public CreatureScript
{
switch (eventId)
{
- case EVENT_WEB_WRAP_GASHRA:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- DoCast(target, SPELL_WEB_WRAP, true);
- _events.ScheduleEvent(EVENT_WEB_WRAP_GASHRA, 17000);
+ case EVENT_CLEAVE:
+ DoCastVictim(SPELL_CLEAVE);
+ _events.Repeat(randtime(Seconds(10), Seconds(16)));
break;
- case EVENT_INFECTED_BITE_GASHRA:
- DoCastVictim(SPELL_INFECTED_BITE, true);
- _events.ScheduleEvent(EVENT_INFECTED_BITE_GASHRA, 15000);
+ case EVENT_STRIKE:
+ DoCastVictim(SPELL_STRIKE);
+ _events.Repeat(randtime(Seconds(15), Seconds(19)));
break;
default:
break;
}
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
}
DoMeleeAttackIfReady();
}
-
- private:
- EventMap _events;
- InstanceScript* _instance;
};
CreatureAI* GetAI(Creature* creature) const override
{
- return GetAzjolNerubAI<npc_watcher_gashraAI>(creature);
+ return GetInstanceAI<npc_anub_ar_warriorAI>(creature);
}
};
-class npc_watcher_narjil : public CreatureScript
+class npc_anub_ar_skirmisher : public CreatureScript
{
public:
- npc_watcher_narjil() : CreatureScript("npc_watcher_narjil") { }
+ npc_anub_ar_skirmisher() : CreatureScript("npc_anub_ar_skirmisher") { }
- struct npc_watcher_narjilAI : public ScriptedAI
+ struct npc_anub_ar_skirmisherAI : public npc_gatewatcher_petAI
{
- npc_watcher_narjilAI(Creature* creature) : ScriptedAI(creature)
- {
- _instance = creature->GetInstanceScript();
- }
+ npc_anub_ar_skirmisherAI(Creature* creature) : npc_gatewatcher_petAI(creature, false) { }
void Reset() override
{
_events.Reset();
}
- void EnterCombat(Unit* /*who*/) override
- {
- _events.ScheduleEvent(EVENT_WEB_WRAP_NARJIL, 11000);
- _events.ScheduleEvent(EVENT_INFECTED_BITE_NARJIL, 4000);
- _events.ScheduleEvent(EVENT_BINDING_WEBS, 17000);
- }
-
- void JustDied(Unit* /*killer*/) override
+ void _EnterCombat() override
{
- Creature* krikthir = _instance->GetCreature(DATA_KRIKTHIR_THE_GATEWATCHER);
- if (krikthir && krikthir->IsAlive())
- krikthir->AI()->Talk(SAY_PREFIGHT);
+ _events.ScheduleEvent(EVENT_ANUBAR_CHARGE, randtime(Seconds(6), Seconds(8)));
+ _events.ScheduleEvent(EVENT_BACKSTAB, randtime(Seconds(7), Seconds(9)));
}
void UpdateAI(uint32 diff) override
@@ -533,67 +735,58 @@ class npc_watcher_narjil : public CreatureScript
{
switch (eventId)
{
- case EVENT_WEB_WRAP_NARJIL:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- DoCast(target, SPELL_WEB_WRAP, true);
- _events.ScheduleEvent(EVENT_WEB_WRAP_NARJIL, 15000);
- break;
- case EVENT_INFECTED_BITE_NARJIL:
- DoCastVictim(SPELL_INFECTED_BITE, true);
- _events.ScheduleEvent(EVENT_INFECTED_BITE_NARJIL, 11000);
+ case EVENT_ANUBAR_CHARGE:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_CHARGE);
+ _events.Repeat(randtime(Seconds(20), Seconds(25)));
break;
- case EVENT_BINDING_WEBS:
- DoCastVictim(SPELL_BLINDING_WEBS, true);
- _events.ScheduleEvent(EVENT_BINDING_WEBS, 17000);
+ case EVENT_BACKSTAB:
+ if (me->GetVictim() && me->GetVictim()->isInBack(me))
+ DoCastVictim(SPELL_BACKSTAB);
+ _events.Repeat(randtime(Seconds(10), Seconds(13)));
break;
default:
break;
}
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
}
DoMeleeAttackIfReady();
}
- private:
- EventMap _events;
- InstanceScript* _instance;
+ void SpellHitTarget(Unit* target, SpellInfo const* spell) override
+ {
+ if (spell->Id == SPELL_CHARGE && target)
+ DoCast(target, SPELL_FIXTATE_TRIGGER);
+ }
};
CreatureAI* GetAI(Creature* creature) const override
{
- return GetAzjolNerubAI<npc_watcher_narjilAI>(creature);
+ return GetInstanceAI<npc_anub_ar_skirmisherAI>(creature);
}
};
-class npc_watcher_silthik : public CreatureScript
+class npc_anub_ar_shadowcaster : public CreatureScript
{
public:
- npc_watcher_silthik() : CreatureScript("npc_watcher_silthik") { }
+ npc_anub_ar_shadowcaster() : CreatureScript("npc_anub_ar_shadowcaster") { }
- struct npc_watcher_silthikAI : public ScriptedAI
+ struct npc_anub_ar_shadowcasterAI : public npc_gatewatcher_petAI
{
- npc_watcher_silthikAI(Creature* creature) : ScriptedAI(creature)
- {
- _instance = creature->GetInstanceScript();
- }
+ npc_anub_ar_shadowcasterAI(Creature* creature) : npc_gatewatcher_petAI(creature, false) { }
void Reset() override
{
_events.Reset();
}
- void EnterCombat(Unit* /*who*/) override
- {
- _events.ScheduleEvent(EVENT_WEB_WRAP_SILTHIK, 11000);
- _events.ScheduleEvent(EVENT_INFECTED_BITE_SILTHIK, 4000);
- _events.ScheduleEvent(EVENT_POISON_SPRAY, 15000);
- }
-
- void JustDied(Unit* /*killer*/) override
+ void _EnterCombat() override
{
- Creature* krikthir = _instance->GetCreature(DATA_KRIKTHIR_THE_GATEWATCHER);
- if (krikthir && krikthir->IsAlive())
- krikthir->AI()->Talk(SAY_PREFIGHT);
+ _events.ScheduleEvent(EVENT_SHADOW_BOLT, Seconds(4));
+ _events.ScheduleEvent(EVENT_SHADOW_NOVA, randtime(Seconds(10), Seconds(14)));
}
void UpdateAI(uint32 diff) override
@@ -610,35 +803,234 @@ class npc_watcher_silthik : public CreatureScript
{
switch (eventId)
{
- case EVENT_WEB_WRAP_SILTHIK:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- DoCast(target, SPELL_WEB_WRAP, true);
- _events.ScheduleEvent(EVENT_WEB_WRAP_SILTHIK, 15000);
- break;
- case EVENT_INFECTED_BITE_SILTHIK:
- DoCastVictim(SPELL_INFECTED_BITE, true);
- _events.ScheduleEvent(EVENT_INFECTED_BITE_SILTHIK, 11000);
+ case EVENT_SHADOW_BOLT:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_SHADOW_BOLT);
+ _events.Repeat(randtime(Seconds(2), Seconds(4)));
break;
- case EVENT_POISON_SPRAY:
- DoCastVictim(SPELL_POSION_SPRAY, true);
- _events.ScheduleEvent(EVENT_POISON_SPRAY, 17000);
+ case EVENT_SHADOW_NOVA:
+ DoCastVictim(SPELL_SHADOW_NOVA);
+ _events.Repeat(randtime(Seconds(10), Seconds(16)));
break;
default:
break;
}
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
}
DoMeleeAttackIfReady();
}
+ };
- private:
- EventMap _events;
- InstanceScript* _instance;
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_anub_ar_shadowcasterAI>(creature);
+ }
+};
+
+class npc_skittering_swarmer : public CreatureScript
+{
+ public:
+ npc_skittering_swarmer() : CreatureScript("npc_skittering_swarmer") { }
+
+ struct npc_skittering_swarmerAI : public ScriptedAI
+ {
+ npc_skittering_swarmerAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void InitializeAI() override
+ {
+ ScriptedAI::InitializeAI();
+ if (Creature* gatewatcher = me->GetInstanceScript()->GetCreature(DATA_KRIKTHIR))
+ {
+ if (Unit* target = gatewatcher->getAttackerForHelper())
+ AttackStart(target);
+ gatewatcher->AI()->JustSummoned(me);
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_skittering_swarmerAI>(creature);
+ }
+};
+
+class npc_skittering_infector : public CreatureScript
+{
+ public:
+ npc_skittering_infector() : CreatureScript("npc_skittering_infector") { }
+
+ struct npc_skittering_infectorAI : public ScriptedAI
+ {
+ npc_skittering_infectorAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void InitializeAI() override
+ {
+ ScriptedAI::InitializeAI();
+ if (Creature* gatewatcher = me->GetInstanceScript()->GetCreature(DATA_KRIKTHIR))
+ {
+ if (Unit* target = gatewatcher->getAttackerForHelper())
+ AttackStart(target);
+ gatewatcher->AI()->JustSummoned(me);
+ }
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ DoCastAOE(SPELL_ACID_SPLASH);
+ ScriptedAI::JustDied(killer);
+ }
};
CreatureAI* GetAI(Creature* creature) const override
{
- return GetAzjolNerubAI<npc_watcher_silthikAI>(creature);
+ return GetInstanceAI<npc_skittering_infectorAI>(creature);
+ }
+};
+
+class npc_gatewatcher_web_wrap : public CreatureScript
+{
+ public:
+ npc_gatewatcher_web_wrap() : CreatureScript("npc_gatewatcher_web_wrap") { }
+
+ struct npc_gatewatcher_web_wrapAI : public NullCreatureAI
+ {
+ npc_gatewatcher_web_wrapAI(Creature* creature) : NullCreatureAI(creature) { }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (TempSummon* meSummon = me->ToTempSummon())
+ if (Unit* summoner = meSummon->GetSummoner())
+ summoner->RemoveAurasDueToSpell(SPELL_WEB_WRAP_WRAPPED);
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_gatewatcher_web_wrapAI>(creature);
+ }
+};
+
+class spell_gatewatcher_subboss_trigger : public SpellScriptLoader
+{
+ public:
+ spell_gatewatcher_subboss_trigger() : SpellScriptLoader("spell_gatewatcher_subboss_trigger") { }
+
+ class spell_gatewatcher_subboss_trigger_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_gatewatcher_subboss_trigger_SpellScript);
+
+ void HandleTargets(std::list<WorldObject*>& targetList)
+ {
+ // Remove any Watchers that are already in combat
+ auto it = targetList.begin();
+ while (it != targetList.end())
+ {
+ if (Creature* creature = (*it)->ToCreature())
+ if (creature->IsAlive() && !creature->IsInCombat())
+ {
+ ++it;
+ continue;
+ }
+ it = targetList.erase(it);
+ }
+
+ // Default to Krik'thir himself if he isn't engaged
+ WorldObject* target = nullptr;
+ if (GetCaster() && !GetCaster()->IsInCombat())
+ target = GetCaster();
+ // Unless there are Watchers that aren't engaged yet
+ if (!targetList.empty())
+ {
+ // If there are, pick one of them at random
+ std::list<WorldObject*>::iterator it = targetList.begin();
+ std::advance(it, urand(0, targetList.size() - 1));
+ target = *it;
+ }
+ // And hit only that one
+ targetList.clear();
+ if (target)
+ targetList.push_back(target);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gatewatcher_subboss_trigger_SpellScript::HandleTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_gatewatcher_subboss_trigger_SpellScript();
+ }
+};
+
+class spell_anub_ar_skirmisher_fixtate : public SpellScriptLoader
+{
+ public:
+ spell_anub_ar_skirmisher_fixtate() : SpellScriptLoader("spell_anub_ar_skirmisher_fixtate") { }
+
+ class spell_anub_ar_skirmisher_fixtate_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_anub_ar_skirmisher_fixtate_SpellScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return sSpellMgr->GetSpellInfo(SPELL_FIXTATE_TRIGGERED) != nullptr;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* target = GetHitUnit())
+ target->CastSpell(GetCaster(), SPELL_FIXTATE_TRIGGERED, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_anub_ar_skirmisher_fixtate_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_anub_ar_skirmisher_fixtate_SpellScript();
+ }
+};
+
+class spell_gatewatcher_web_wrap : public SpellScriptLoader
+{
+ public:
+ spell_gatewatcher_web_wrap() : SpellScriptLoader("spell_gatewatcher_web_wrap") { }
+
+ class spell_gatewatcher_web_wrap_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_gatewatcher_web_wrap_AuraScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return sSpellMgr->GetSpellInfo(SPELL_WEB_WRAP_WRAPPED) != nullptr;
+ }
+
+ void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
+ return;
+
+ if (Unit* target = GetTarget())
+ target->CastSpell(target, SPELL_WEB_WRAP_WRAPPED, true);
+ }
+
+ void Register() override
+ {
+ OnEffectRemove += AuraEffectRemoveFn(spell_gatewatcher_web_wrap_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_MOD_ROOT, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_gatewatcher_web_wrap_AuraScript();
}
};
@@ -656,11 +1048,12 @@ class achievement_watch_him_die : public AchievementCriteriaScript
if (!instance)
return false;
- for (uint8 n = 0; n < 3; ++n)
+ for (DataTypes watcherData : {DATA_WATCHER_GASHRA, DATA_WATCHER_NARJIL, DATA_WATCHER_SILTHIK})
{
- if (Creature* watcher = instance->GetCreature(DATA_WATCHER_GASHRA + n))
- if (!watcher->IsAlive())
- return false;
+ if (Creature* watcher = instance->GetCreature(watcherData))
+ if (watcher->IsAlive())
+ continue;
+ return false;
}
return true;
@@ -670,12 +1063,22 @@ class achievement_watch_him_die : public AchievementCriteriaScript
void AddSC_boss_krik_thir()
{
new boss_krik_thir();
- new npc_skittering_infector();
- new npc_anub_ar_skirmisher();
- new npc_anub_ar_shadowcaster();
+
new npc_watcher_gashra();
- new npc_anub_ar_warrior();
- new npc_watcher_silthik();
new npc_watcher_narjil();
+ new npc_watcher_silthik();
+
+ new npc_anub_ar_warrior();
+ new npc_anub_ar_skirmisher();
+ new npc_anub_ar_shadowcaster();
+
+ new npc_skittering_swarmer();
+ new npc_skittering_infector();
+ new npc_gatewatcher_web_wrap();
+
+ new spell_gatewatcher_subboss_trigger();
+ new spell_anub_ar_skirmisher_fixtate();
+ new spell_gatewatcher_web_wrap();
+
new achievement_watch_him_die();
}
diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp
index 88003680ec7..7f0ce5c369e 100644
--- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp
@@ -21,7 +21,7 @@
DoorData const doorData[] =
{
- { GO_KRIKTHIR_DOOR, DATA_KRIKTHIR_THE_GATEWATCHER, DOOR_TYPE_PASSAGE },
+ { GO_KRIKTHIR_DOOR, DATA_KRIKTHIR, DOOR_TYPE_PASSAGE },
{ GO_ANUBARAK_DOOR_1, DATA_ANUBARAK, DOOR_TYPE_ROOM },
{ GO_ANUBARAK_DOOR_2, DATA_ANUBARAK, DOOR_TYPE_ROOM },
{ GO_ANUBARAK_DOOR_3, DATA_ANUBARAK, DOOR_TYPE_ROOM },
@@ -30,17 +30,33 @@ DoorData const doorData[] =
ObjectData const creatureData[] =
{
- { NPC_KRIKTHIR, DATA_KRIKTHIR_THE_GATEWATCHER },
+ { NPC_KRIKTHIR, DATA_KRIKTHIR },
+ { NPC_HADRONOX, DATA_HADRONOX },
+ { NPC_ANUBARAK, DATA_ANUBARAK },
{ NPC_WATCHER_NARJIL, DATA_WATCHER_GASHRA },
{ NPC_WATCHER_GASHRA, DATA_WATCHER_SILTHIK },
{ NPC_WATCHER_SILTHIK, DATA_WATCHER_NARJIL },
{ 0, 0 } // END
};
+ObjectData const gameobjectData[] =
+{
+ { GO_ANUBARAK_DOOR_1, DATA_ANUBARAK_WALL },
+ { GO_ANUBARAK_DOOR_3, DATA_ANUBARAK_WALL_2 },
+ { 0, 0 } // END
+};
+
+BossBoundaryData const boundaries =
+{
+ { DATA_KRIKTHIR, new RectangleBoundary(400.0f, 580.0f, 623.5f, 810.0f) },
+ { DATA_HADRONOX, new ZRangeBoundary(666.0f, 776.0f) },
+ { DATA_ANUBARAK, new CircleBoundary(Position(550.6178f, 253.5917f), 26.0f) }
+};
+
class instance_azjol_nerub : public InstanceMapScript
{
public:
- instance_azjol_nerub() : InstanceMapScript(AzjolNerubScriptName, 601) { }
+ instance_azjol_nerub() : InstanceMapScript("instance_azjol_nerub", 601) { }
struct instance_azjol_nerub_InstanceScript : public InstanceScript
{
@@ -48,8 +64,30 @@ class instance_azjol_nerub : public InstanceMapScript
{
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
+ LoadBossBoundaries(boundaries);
LoadDoorData(doorData);
- LoadObjectData(creatureData, nullptr);
+ LoadObjectData(creatureData, gameobjectData);
+ }
+
+ void OnUnitDeath(Unit* who) override
+ {
+ InstanceScript::OnUnitDeath(who);
+ Creature* creature = who->ToCreature();
+ if (!creature || creature->IsCritter() || creature->IsControlledByPlayer())
+ return;
+ if (Creature* gatewatcher = GetCreature(DATA_KRIKTHIR))
+ gatewatcher->AI()->DoAction(-ACTION_GATEWATCHER_GREET);
+ }
+
+ bool CheckRequiredBosses(uint32 bossId, Player const* player) const override
+ {
+ if (_SkipCheckRequiredBosses(player))
+ return true;
+
+ if (bossId > DATA_KRIKTHIR && GetBossState(DATA_KRIKTHIR) != DONE)
+ return false;
+
+ return true;
}
};
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp
index d9200fbb2f5..ee44e1391b4 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp
@@ -829,9 +829,6 @@ class npc_toc_druid : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
}
};
@@ -925,9 +922,6 @@ class npc_toc_shaman : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
}
};
@@ -1032,9 +1026,6 @@ class npc_toc_paladin : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
}
};
@@ -1120,9 +1111,6 @@ class npc_toc_priest : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
}
};
@@ -1220,9 +1208,6 @@ class npc_toc_shadow_priest : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
DoSpellAttackIfReady(SPELL_MIND_FLAY);
}
@@ -1314,9 +1299,6 @@ class npc_toc_warlock : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
DoSpellAttackIfReady(SPELL_SHADOW_BOLT);
}
@@ -1411,9 +1393,6 @@ class npc_toc_mage : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
DoSpellAttackIfReady(SPELL_FROSTBOLT);
}
@@ -1516,9 +1495,6 @@ class npc_toc_hunter : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
DoSpellAttackIfReady(SPELL_SHOOT);
}
@@ -1611,9 +1587,6 @@ class npc_toc_boomkin : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
DoSpellAttackIfReady(SPELL_WRATH);
}
@@ -1719,9 +1692,6 @@ class npc_toc_warrior : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
}
};
@@ -1818,9 +1788,6 @@ class npc_toc_dk : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
}
};
@@ -1926,9 +1893,6 @@ class npc_toc_rogue : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
}
};
@@ -2060,9 +2024,6 @@ class npc_toc_enh_shaman : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
}
private:
@@ -2172,9 +2133,6 @@ class npc_toc_retro_paladin : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
}
};
@@ -2227,9 +2185,6 @@ class npc_toc_pet_warlock : public CreatureScript
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
}
};
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 64299da79e6..976ef3e34db 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp
@@ -16,9 +16,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-// Known bugs:
-// Gormok - Snobolled (creature at back)
-
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "trial_of_the_crusader.h"
@@ -71,14 +68,16 @@ enum BossSpells
//Gormok
SPELL_IMPALE = 66331,
SPELL_STAGGERING_STOMP = 67648,
- SPELL_RISING_ANGER = 66636,
//Snobold
+ SPELL_RISING_ANGER = 66636,
SPELL_SNOBOLLED = 66406,
SPELL_BATTER = 66408,
SPELL_FIRE_BOMB = 66313,
SPELL_FIRE_BOMB_1 = 66317,
SPELL_FIRE_BOMB_DOT = 66318,
SPELL_HEAD_CRACK = 66407,
+ SPELL_JUMP_TO_HAND = 66342,
+ SPELL_RIDE_PLAYER = 66245,
//Acidmaw & Dreadscale Generic
SPELL_SWEEP = 66794,
@@ -117,38 +116,41 @@ enum BossSpells
enum MyActions
{
ACTION_ENABLE_FIRE_BOMB = 1,
- ACTION_DISABLE_FIRE_BOMB = 2
+ ACTION_DISABLE_FIRE_BOMB = 2,
+ ACTION_ACTIVE_SNOBOLD = 3
};
enum Events
{
// Gormok
EVENT_IMPALE = 1,
- EVENT_STAGGERING_STOMP = 2,
- EVENT_THROW = 3,
+ EVENT_STAGGERING_STOMP,
+ EVENT_THROW,
// Snobold
- EVENT_FIRE_BOMB = 4,
- EVENT_BATTER = 5,
- EVENT_HEAD_CRACK = 6,
+ EVENT_FIRE_BOMB,
+ EVENT_BATTER,
+ EVENT_HEAD_CRACK,
+ EVENT_SNOBOLLED,
+ EVENT_CHECK_MOUNT,
// Acidmaw & Dreadscale
- EVENT_BITE = 7,
- EVENT_SPEW = 8,
- EVENT_SLIME_POOL = 9,
- EVENT_SPIT = 10,
- EVENT_SPRAY = 11,
- EVENT_SWEEP = 12,
- EVENT_SUBMERGE = 13,
- EVENT_EMERGE = 14,
- EVENT_SUMMON_ACIDMAW = 15,
+ EVENT_BITE,
+ EVENT_SPEW,
+ EVENT_SLIME_POOL,
+ EVENT_SPIT,
+ EVENT_SPRAY,
+ EVENT_SWEEP,
+ EVENT_SUBMERGE,
+ EVENT_EMERGE,
+ EVENT_SUMMON_ACIDMAW,
// Icehowl
- EVENT_FEROCIOUS_BUTT = 16,
- EVENT_MASSIVE_CRASH = 17,
- EVENT_WHIRL = 18,
- EVENT_ARCTIC_BREATH = 19,
- EVENT_TRAMPLE = 20
+ EVENT_FEROCIOUS_BUTT,
+ EVENT_MASSIVE_CRASH,
+ EVENT_WHIRL,
+ EVENT_ARCTIC_BREATH,
+ EVENT_TRAMPLE
};
enum Phases
@@ -158,6 +160,13 @@ enum Phases
PHASE_SUBMERGED = 3
};
+enum GormokMisc
+{
+ DATA_NEW_TARGET = 1,
+ GORMOK_HAND_SEAT = 4,
+ PLAYER_VEHICLE_ID = 444,
+};
+
class boss_gormok : public CreatureScript
{
public:
@@ -169,9 +178,9 @@ class boss_gormok : public CreatureScript
void Reset() override
{
- events.ScheduleEvent(EVENT_IMPALE, urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS));
- events.ScheduleEvent(EVENT_STAGGERING_STOMP, 15*IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_THROW, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS));
+ events.ScheduleEvent(EVENT_IMPALE, Seconds(8), Seconds(10));
+ events.ScheduleEvent(EVENT_STAGGERING_STOMP, Seconds(15));
+ events.ScheduleEvent(EVENT_THROW, Seconds(15), Seconds(30));
summons.DespawnAll();
}
@@ -216,18 +225,7 @@ class boss_gormok : public CreatureScript
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
- me->SetInCombatWithZone();
instance->SetData(TYPE_NORTHREND_BEASTS, GORMOK_IN_PROGRESS);
-
- for (uint8 i = 0; i < MAX_SNOBOLDS; i++)
- {
- if (Creature* pSnobold = DoSpawnCreature(NPC_SNOBOLD_VASSAL, 0, 0, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0))
- {
- pSnobold->EnterVehicle(me, i);
- pSnobold->SetInCombatWithZone();
- pSnobold->AI()->DoAction(ACTION_ENABLE_FIRE_BOMB);
- }
- }
}
void DamageTaken(Unit* /*who*/, uint32& damage) override
@@ -235,8 +233,14 @@ class boss_gormok : public CreatureScript
// despawn the remaining passengers on death
if (damage >= me->GetHealth())
for (uint8 i = 0; i < MAX_SNOBOLDS; ++i)
- if (Unit* pSnobold = me->GetVehicleKit()->GetPassenger(i))
- pSnobold->ToCreature()->DespawnOrUnsummon();
+ if (Unit* snobold = me->GetVehicleKit()->GetPassenger(i))
+ snobold->ToCreature()->DespawnOrUnsummon();
+ }
+
+ void PassengerBoarded(Unit* who, int8 seatId, bool apply) override
+ {
+ if (apply && seatId == GORMOK_HAND_SEAT)
+ who->CastSpell(me, SPELL_RISING_ANGER, true);
}
void UpdateAI(uint32 diff) override
@@ -255,34 +259,29 @@ class boss_gormok : public CreatureScript
{
case EVENT_IMPALE:
DoCastVictim(SPELL_IMPALE);
- events.ScheduleEvent(EVENT_IMPALE, urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS));
- return;
+ events.Repeat(Seconds(8), Seconds(10));
+ break;
case EVENT_STAGGERING_STOMP:
DoCastVictim(SPELL_STAGGERING_STOMP);
- events.ScheduleEvent(EVENT_STAGGERING_STOMP, 15*IN_MILLISECONDS);
- return;
+ events.Repeat(Seconds(15));
+ break;
case EVENT_THROW:
for (uint8 i = 0; i < MAX_SNOBOLDS; ++i)
{
- if (Unit* pSnobold = me->GetVehicleKit()->GetPassenger(i))
+ if (Unit* snobold = me->GetVehicleKit()->GetPassenger(i))
{
- pSnobold->ExitVehicle();
- pSnobold->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
- pSnobold->ToCreature()->SetReactState(REACT_AGGRESSIVE);
- pSnobold->ToCreature()->AI()->DoAction(ACTION_DISABLE_FIRE_BOMB);
- pSnobold->CastSpell(me, SPELL_RISING_ANGER, true);
- Talk(EMOTE_SNOBOLLED);
+ snobold->ExitVehicle();
+ snobold->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+ snobold->GetAI()->DoAction(ACTION_DISABLE_FIRE_BOMB);
+ snobold->CastSpell(me, SPELL_JUMP_TO_HAND, true);
break;
}
}
- events.ScheduleEvent(EVENT_THROW, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS));
- return;
+ events.Repeat(Seconds(15), Seconds(30));
+ break;
default:
- return;
+ break;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
DoMeleeAttackIfReady();
@@ -295,6 +294,23 @@ class boss_gormok : public CreatureScript
}
};
+class SnobolledTargetSelector : public std::unary_function<Unit*, bool>
+{
+public:
+ SnobolledTargetSelector(Unit const* /*unit*/) { }
+
+ bool operator()(Unit* unit) const
+ {
+ if (unit->GetTypeId() != TYPEID_PLAYER)
+ return false;
+
+ if (unit->HasAura(SPELL_RIDE_PLAYER) || unit->HasAura(SPELL_SNOBOLLED))
+ return false;
+
+ return true;
+ }
+};
+
class npc_snobold_vassal : public CreatureScript
{
public:
@@ -302,59 +318,24 @@ class npc_snobold_vassal : public CreatureScript
struct npc_snobold_vassalAI : public ScriptedAI
{
- npc_snobold_vassalAI(Creature* creature) : ScriptedAI(creature)
+ npc_snobold_vassalAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _isActive(false)
{
- _targetDied = false;
- _instance = creature->GetInstanceScript();
_instance->SetData(DATA_SNOBOLD_COUNT, INCREASE);
+ SetCombatMovement(false);
}
void Reset() override
{
- _events.ScheduleEvent(EVENT_BATTER, 5*IN_MILLISECONDS);
- _events.ScheduleEvent(EVENT_HEAD_CRACK, 25*IN_MILLISECONDS);
-
- _targetGUID.Clear();
- _targetDied = false;
-
- //Workaround for Snobold
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
- }
-
- void EnterCombat(Unit* who) override
- {
- _targetGUID = who->GetGUID();
- me->TauntApply(who);
- DoCast(who, SPELL_SNOBOLLED);
- }
-
- void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) override
- {
- if (pDoneBy->GetGUID() == _targetGUID)
- uiDamage = 0;
- }
-
- void MovementInform(uint32 type, uint32 pointId) override
- {
- if (type != POINT_MOTION_TYPE)
- return;
-
- switch (pointId)
- {
- case 0:
- if (_targetDied)
- me->DespawnOrUnsummon();
- break;
- default:
- break;
- }
+ me->SetInCombatWithZone();
+ _events.ScheduleEvent(EVENT_CHECK_MOUNT, Seconds(1));
+ _events.ScheduleEvent(EVENT_FIRE_BOMB, Seconds(5), Seconds(30));
}
void JustDied(Unit* /*killer*/) override
{
if (Unit* target = ObjectAccessor::GetPlayer(*me, _targetGUID))
- if (target->IsAlive())
- target->RemoveAurasDueToSpell(SPELL_SNOBOLLED);
+ target->RemoveAurasDueToSpell(SPELL_SNOBOLLED);
_instance->SetData(DATA_SNOBOLD_COUNT, DECREASE);
}
@@ -363,50 +344,69 @@ class npc_snobold_vassal : public CreatureScript
switch (action)
{
case ACTION_ENABLE_FIRE_BOMB:
- _events.ScheduleEvent(EVENT_FIRE_BOMB, urand(5*IN_MILLISECONDS, 30*IN_MILLISECONDS));
+ _events.ScheduleEvent(EVENT_FIRE_BOMB, Seconds(5), Seconds(30));
break;
case ACTION_DISABLE_FIRE_BOMB:
_events.CancelEvent(EVENT_FIRE_BOMB);
break;
+ case ACTION_ACTIVE_SNOBOLD:
+ _isActive = true;
+ break;
default:
break;
}
}
- void UpdateAI(uint32 diff) override
+ void SetGUID(ObjectGuid guid, int32 id) override
{
- if (!UpdateVictim() || _targetDied)
+ if (id == DATA_NEW_TARGET)
+ if (Unit* target = ObjectAccessor::GetPlayer(*me, guid))
+ {
+ _targetGUID = guid;
+ AttackStart(target);
+ _events.ScheduleEvent(EVENT_BATTER, Seconds(5));
+ _events.ScheduleEvent(EVENT_HEAD_CRACK, Seconds(25));
+ _events.ScheduleEvent(EVENT_SNOBOLLED, Milliseconds(500));
+ }
+ }
+
+ void AttackStart(Unit* who) override
+ {
+ //Snobold only melee attack players that is your vehicle
+ if (!_isActive || who->GetGUID() != _targetGUID)
return;
- if (Unit* target = ObjectAccessor::GetPlayer(*me, _targetGUID))
+ ScriptedAI::AttackStart(who);
+ }
+
+ void MountOnBoss()
+ {
+ Unit* gormok = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(NPC_GORMOK));
+ if (gormok && gormok->IsAlive())
{
- if (!target->IsAlive())
- {
- Unit* gormok = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(NPC_GORMOK));
- if (gormok && gormok->IsAlive())
- {
- SetCombatMovement(false);
- _targetDied = true;
+ me->AttackStop();
+ _targetGUID.Clear();
+ _isActive = false;
+ _events.CancelEvent(EVENT_BATTER);
+ _events.CancelEvent(EVENT_HEAD_CRACK);
- // looping through Gormoks seats
- for (uint8 i = 0; i < MAX_SNOBOLDS; i++)
- {
- if (!gormok->GetVehicleKit()->GetPassenger(i))
- {
- me->EnterVehicle(gormok, i);
- DoAction(ACTION_ENABLE_FIRE_BOMB);
- break;
- }
- }
- }
- else if (Unit* target2 = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
+ for (uint8 i = 0; i < MAX_SNOBOLDS; i++)
+ {
+ if (!gormok->GetVehicleKit()->GetPassenger(i))
{
- _targetGUID = target2->GetGUID();
- me->GetMotionMaster()->MoveJump(*target2, 15.0f, 15.0f);
+ me->EnterVehicle(gormok, i);
+ DoAction(ACTION_ENABLE_FIRE_BOMB);
+ break;
}
}
}
+ //Without Boss, snobolds should jump in another players
+ else if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, SnobolledTargetSelector(me)))
+ me->CastSpell(target, SPELL_RIDE_PLAYER, true);
+ }
+ void UpdateAI(uint32 diff) override
+ {
_events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
@@ -419,35 +419,46 @@ class npc_snobold_vassal : public CreatureScript
case EVENT_FIRE_BOMB:
if (me->GetVehicleBase())
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, -me->GetVehicleBase()->GetCombatReach(), true))
- me->CastSpell(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), SPELL_FIRE_BOMB, true);
- _events.ScheduleEvent(EVENT_FIRE_BOMB, 20*IN_MILLISECONDS);
- return;
+ me->CastSpell(target, SPELL_FIRE_BOMB);
+ _events.Repeat(Seconds(20));
+ break;
case EVENT_HEAD_CRACK:
- // commented out while SPELL_SNOBOLLED gets fixed
- //if (Unit* target = ObjectAccessor::GetPlayer(*me, m_uiTargetGUID))
- DoCastVictim(SPELL_HEAD_CRACK);
- _events.ScheduleEvent(EVENT_HEAD_CRACK, 30*IN_MILLISECONDS);
- return;
+ DoCast(me->GetVehicleBase(), SPELL_HEAD_CRACK);
+ _events.Repeat(Seconds(30));
+ break;
case EVENT_BATTER:
- // commented out while SPELL_SNOBOLLED gets fixed
- //if (Unit* target = ObjectAccessor::GetPlayer(*me, m_uiTargetGUID))
- DoCastVictim(SPELL_BATTER);
- _events.ScheduleEvent(EVENT_BATTER, 10*IN_MILLISECONDS);
- return;
+ DoCast(me->GetVehicleBase(), SPELL_BATTER);
+ _events.Repeat(Seconds(10));
+ break;
+ case EVENT_SNOBOLLED:
+ DoCastAOE(SPELL_SNOBOLLED);
+ break;
+ case EVENT_CHECK_MOUNT:
+ if (!me->GetVehicleBase())
+ MountOnBoss();
+ _events.Repeat(Seconds(1));
+ break;
default:
- return;
+ break;
}
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
}
- // do melee attack only when not on Gormoks back
- if (!me->GetVehicleBase())
+ if (!UpdateVictim())
+ return;
+
+ // do melee attack only if is in player back.
+ if (_isActive)
DoMeleeAttackIfReady();
}
+
private:
EventMap _events;
InstanceScript* _instance;
ObjectGuid _targetGUID;
- bool _targetDied;
+ bool _isActive;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -617,9 +628,6 @@ struct boss_jormungarAI : public BossAI
default:
return;
}
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
}
if (events.IsInPhase(PHASE_MOBILE))
DoMeleeAttackIfReady();
@@ -1151,6 +1159,138 @@ class boss_icehowl : public CreatureScript
}
};
+class spell_gormok_jump_to_hand : public SpellScriptLoader
+{
+public:
+ spell_gormok_jump_to_hand() : SpellScriptLoader("spell_gormok_jump_to_hand") { }
+
+ class spell_gormok_jump_to_hand_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_gormok_jump_to_hand_AuraScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_RIDE_PLAYER))
+ return false;
+ return true;
+ }
+
+ bool Load() override
+ {
+ if (GetCaster() && GetCaster()->GetEntry() == NPC_SNOBOLD_VASSAL)
+ return true;
+ return false;
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* caster = GetCaster())
+ {
+ if (CreatureAI* gormokAI = GetTarget()->ToCreature()->AI())
+ {
+ if (Unit* target = gormokAI->SelectTarget(SELECT_TARGET_RANDOM, 0, SnobolledTargetSelector(GetTarget())))
+ {
+ gormokAI->Talk(EMOTE_SNOBOLLED);
+ caster->GetAI()->DoAction(ACTION_ACTIVE_SNOBOLD);
+ caster->CastSpell(target, SPELL_RIDE_PLAYER, true);
+ }
+ }
+ }
+ }
+
+ void Register() override
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_gormok_jump_to_hand_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_gormok_jump_to_hand_AuraScript();
+ }
+};
+
+class spell_gormok_ride_player : public SpellScriptLoader
+{
+public:
+ spell_gormok_ride_player() : SpellScriptLoader("spell_gormok_ride_player") { }
+
+ class spell_gormok_ride_player_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_gormok_ride_player_AuraScript);
+
+ bool Load() override
+ {
+ if (GetCaster() && GetCaster()->GetEntry() == NPC_SNOBOLD_VASSAL)
+ return true;
+ return false;
+ }
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ if (target->GetTypeId() != TYPEID_PLAYER || !target->IsInWorld())
+ return;
+
+ if (!target->CreateVehicleKit(PLAYER_VEHICLE_ID, 0))
+ return;
+
+ if (Unit *caster = GetCaster())
+ caster->GetAI()->SetGUID(target->GetGUID(), DATA_NEW_TARGET);
+ }
+
+ void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ GetTarget()->RemoveVehicleKit();
+ }
+
+ void Register() override
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_gormok_ride_player_AuraScript::OnApply, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_gormok_ride_player_AuraScript::AfterRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_gormok_ride_player_AuraScript();
+ }
+};
+
+class spell_gormok_snobolled : public SpellScriptLoader
+{
+public:
+ spell_gormok_snobolled() : SpellScriptLoader("spell_gormok_snobolled") { }
+
+ class spell_gormok_snobolled_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_gormok_snobolled_AuraScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_RIDE_PLAYER))
+ return false;
+ return true;
+ }
+
+ void OnPeriodic(AuraEffect const* /*aurEff*/)
+ {
+ if (!GetTarget()->HasAura(SPELL_RIDE_PLAYER))
+ Remove();
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_gormok_snobolled_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_gormok_snobolled_AuraScript();
+ }
+};
+
class spell_jormungars_paralytic_toxin : public SpellScriptLoader
{
public:
@@ -1299,6 +1439,9 @@ void AddSC_boss_northrend_beasts()
new npc_snobold_vassal();
new npc_firebomb();
new spell_gormok_fire_bomb();
+ new spell_gormok_jump_to_hand();
+ new spell_gormok_ride_player();
+ new spell_gormok_snobolled();
new boss_acidmaw();
new boss_dreadscale();
diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp
index 8998b77d8b5..25e2c045af9 100644
--- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp
@@ -406,7 +406,11 @@ class spell_devourer_of_souls_mirrored_soul_proc : public SpellScriptLoader
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- int32 damage = int32(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), 45));
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 damage = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), 45);
GetTarget()->CastCustomSpell(SPELL_MIRRORED_SOUL_DAMAGE, SPELLVALUE_BASE_POINT0, damage, GetCaster(), true);
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp
index 28484280ada..707bbd4eb02 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp
@@ -1498,6 +1498,26 @@ class spell_taldaram_ball_of_inferno_flame : public SpellScriptLoader
{
return new spell_taldaram_ball_of_inferno_flame_SpellScript();
}
+
+ class spell_taldaram_ball_of_inferno_flame_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_taldaram_ball_of_inferno_flame_AuraScript);
+
+ void HandleStackDrop(ProcEventInfo& /*eventInfo*/)
+ {
+ ModStackAmount(-1);
+ }
+
+ void Register() override
+ {
+ OnProc += AuraProcFn(spell_taldaram_ball_of_inferno_flame_AuraScript::HandleStackDrop);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_taldaram_ball_of_inferno_flame_AuraScript();
+ }
};
// 72080 - Kinetic Bomb (Valanar)
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp
index a5d6d27724c..dd34f501e61 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp
@@ -729,8 +729,12 @@ class spell_blood_queen_essence_of_the_blood_queen : public SpellScriptLoader
void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- int32 heal = CalculatePct(int32(eventInfo.GetDamageInfo()->GetDamage()), aurEff->GetAmount());
- GetTarget()->CastCustomSpell(SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_HEAL, SPELLVALUE_BASE_POINT0, heal, GetTarget(), TRIGGERED_FULL_MASK, NULL, aurEff);
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 heal = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
+ GetTarget()->CastCustomSpell(SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_HEAL, SPELLVALUE_BASE_POINT0, heal, GetTarget(), TRIGGERED_FULL_MASK, nullptr, aurEff);
}
void Register() override
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
index 23049e82d5e..137cdb28fb5 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
@@ -431,7 +431,7 @@ class boss_deathbringer_saurfang : public CreatureScript
case 72445:
case 72446:
if (me->GetPower(POWER_ENERGY) != me->GetMaxPower(POWER_ENERGY))
- target->CastCustomSpell(SPELL_BLOOD_LINK_DUMMY, SPELLVALUE_BASE_POINT0, 1, me, true);
+ target->CastCustomSpell(SPELL_BLOOD_LINK_DUMMY, SPELLVALUE_BASE_POINT0, 1, (Unit*)nullptr, true);
break;
default:
break;
@@ -1135,8 +1135,7 @@ class spell_deathbringer_rune_of_blood : public SpellScriptLoader
void HandleScript(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex); // make this the default handler
- if (GetCaster()->GetPower(POWER_ENERGY) != GetCaster()->GetMaxPower(POWER_ENERGY))
- GetHitUnit()->CastCustomSpell(SPELL_BLOOD_LINK_DUMMY, SPELLVALUE_BASE_POINT0, 1, GetCaster(), true);
+ GetHitUnit()->CastCustomSpell(SPELL_BLOOD_LINK_DUMMY, SPELLVALUE_BASE_POINT0, 1, (Unit*)nullptr, true);
}
void Register() override
@@ -1151,6 +1150,41 @@ class spell_deathbringer_rune_of_blood : public SpellScriptLoader
}
};
+// 72176 - Blood Beast's Blood Link
+class spell_deathbringer_blood_beast_blood_link : public SpellScriptLoader
+{
+ public:
+ spell_deathbringer_blood_beast_blood_link() : SpellScriptLoader("spell_deathbringer_blood_beast_blood_link") { }
+
+ class spell_deathbringer_blood_beast_blood_link_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_deathbringer_blood_beast_blood_link_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_BLOOD_LINK_DUMMY))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetProcTarget()->CastCustomSpell(SPELL_BLOOD_LINK_DUMMY, SPELLVALUE_BASE_POINT0, 3, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_deathbringer_blood_beast_blood_link_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_deathbringer_blood_beast_blood_link_AuraScript();
+ }
+};
+
class spell_deathbringer_blood_nova : public SpellScriptLoader
{
public:
@@ -1170,8 +1204,7 @@ class spell_deathbringer_blood_nova : public SpellScriptLoader
void HandleScript(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex); // make this the default handler
- if (GetCaster()->GetPower(POWER_ENERGY) != GetCaster()->GetMaxPower(POWER_ENERGY))
- GetHitUnit()->CastCustomSpell(SPELL_BLOOD_LINK_DUMMY, SPELLVALUE_BASE_POINT0, 2, GetCaster(), true);
+ GetHitUnit()->CastCustomSpell(SPELL_BLOOD_LINK_DUMMY, SPELLVALUE_BASE_POINT0, 2, (Unit*)nullptr, true);
}
void Register() override
@@ -1349,6 +1382,7 @@ void AddSC_boss_deathbringer_saurfang()
new spell_deathbringer_blood_link_aura();
new spell_deathbringer_blood_power();
new spell_deathbringer_rune_of_blood();
+ new spell_deathbringer_blood_beast_blood_link();
new spell_deathbringer_blood_nova();
new spell_deathbringer_blood_nova_targeting();
new spell_deathbringer_boiling_blood();
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 73a7de36580..88fd65baec4 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp
@@ -1721,10 +1721,7 @@ class npc_gunship_mage : public CreatureScript
me->SetReactState(REACT_PASSIVE);
}
- void EnterEvadeMode(EvadeReason why) override
- {
- ScriptedAI::EnterEvadeMode(why);
- }
+ void EnterEvadeMode(EvadeReason /*why*/) override { }
void MovementInform(uint32 type, uint32 pointId) override
{
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
index 5f884ccee9e..85126b35cdb 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
@@ -56,21 +56,26 @@ enum Spells
SPELL_MANA_BARRIER = 70842,
SPELL_SHADOW_BOLT = 71254,
SPELL_DEATH_AND_DECAY = 71001,
- SPELL_DOMINATE_MIND_H = 71289,
+ SPELL_DOMINATE_MIND = 71289,
+ SPELL_DOMINATE_MIND_SCALE = 71290,
SPELL_FROSTBOLT = 71420,
SPELL_FROSTBOLT_VOLLEY = 72905,
SPELL_TOUCH_OF_INSIGNIFICANCE = 71204,
SPELL_SUMMON_SHADE = 71363,
- SPELL_SHADOW_CHANNELING = 43897, // Prefight, during intro
+ SPELL_SHADOW_CHANNELING = 43897,
SPELL_DARK_TRANSFORMATION_T = 70895,
SPELL_DARK_EMPOWERMENT_T = 70896,
SPELL_DARK_MARTYRDOM_T = 70897,
+ SPELL_SUMMON_SPIRITS = 72478,
// Achievement
SPELL_FULL_HOUSE = 72827, // does not exist in dbc but still can be used for criteria check
// Both Adds
SPELL_TELEPORT_VISUAL = 41236,
+ SPELL_CLEAR_ALL_DEBUFFS = 34098,
+ SPELL_FULL_HEAL = 17683,
+ SPELL_PERMANENT_FEIGN_DEATH = 70628,
// Fanatics
SPELL_DARK_TRANSFORMATION = 70900,
@@ -86,7 +91,7 @@ enum Spells
SPELL_DEATHCHILL_BOLT = 70594,
SPELL_DEATHCHILL_BLAST = 70906,
SPELL_CURSE_OF_TORPOR = 71237,
- SPELL_SHORUD_OF_THE_OCCULT = 70768,
+ SPELL_SHROUD_OF_THE_OCCULT = 70768,
SPELL_ADHERENT_S_DETERMINATION = 71234,
SPELL_DARK_MARTYRDOM_ADHERENT = 70903,
@@ -108,44 +113,6 @@ enum Spells
enum EventTypes
{
- // Lady Deathwhisper
- EVENT_INTRO_2 = 1,
- EVENT_INTRO_3 = 2,
- EVENT_INTRO_4 = 3,
- EVENT_INTRO_5 = 4,
- EVENT_INTRO_6 = 5,
- EVENT_INTRO_7 = 6,
- EVENT_BERSERK = 7,
- EVENT_DEATH_AND_DECAY = 8,
- EVENT_DOMINATE_MIND_H = 9,
-
- // Phase 1 only
- EVENT_P1_SUMMON_WAVE = 10,
- EVENT_P1_SHADOW_BOLT = 11,
- EVENT_P1_EMPOWER_CULTIST = 12,
- EVENT_P1_REANIMATE_CULTIST = 13,
-
- // Phase 2 only
- EVENT_P2_SUMMON_WAVE = 14,
- EVENT_P2_FROSTBOLT = 15,
- EVENT_P2_FROSTBOLT_VOLLEY = 16,
- EVENT_P2_TOUCH_OF_INSIGNIFICANCE = 17,
- EVENT_P2_SUMMON_SHADE = 18,
-
- // Shared adds events
- EVENT_CULTIST_DARK_MARTYRDOM = 19,
-
- // Cult Fanatic
- EVENT_FANATIC_NECROTIC_STRIKE = 20,
- EVENT_FANATIC_SHADOW_CLEAVE = 21,
- EVENT_FANATIC_VAMPIRIC_MIGHT = 22,
-
- // Cult Adherent
- EVENT_ADHERENT_FROST_FEVER = 23,
- EVENT_ADHERENT_DEATHCHILL = 24,
- EVENT_ADHERENT_CURSE_OF_TORPOR = 25,
- EVENT_ADHERENT_SHORUD_OF_THE_OCCULT = 26,
-
// Darnavan
EVENT_DARNAVAN_BLADESTORM = 27,
EVENT_DARNAVAN_CHARGE = 28,
@@ -163,6 +130,13 @@ enum Phases
PHASE_TWO = 3
};
+enum Groups
+{
+ GROUP_INTRO = 0,
+ GROUP_ONE = 1,
+ GROUP_TWO = 2
+};
+
enum DeprogrammingData
{
NPC_DARNAVAN_10 = 38472,
@@ -185,8 +159,6 @@ enum Actions
uint32 const SummonEntries[2] = {NPC_CULT_FANATIC, NPC_CULT_ADHERENT};
-#define GUID_CULTIST 1
-
Position const SummonPositions[7] =
{
{-578.7066f, 2154.167f, 51.01529f, 1.692969f}, // 1 Left Door 1 (Cult Fanatic)
@@ -229,43 +201,67 @@ class boss_lady_deathwhisper : public CreatureScript
void Initialize()
{
_waveCounter = 0;
- _nextVengefulShadeTargetGUID.Clear();
+ _nextVengefulShadeTargetGUID.clear();
+ _cultistQueue.clear();
_darnavanGUID.Clear();
+ _phase = PHASE_ALL;
+ scheduler.SetValidator([this]
+ {
+ return !(me->HasUnitState(UNIT_STATE_CASTING) && _phase != PHASE_INTRO);
+ });
}
void Reset() override
{
- _Reset();
- me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA));
- events.SetPhase(PHASE_ONE);
Initialize();
- DoCast(me, SPELL_SHADOW_CHANNELING);
- me->RemoveAurasDueToSpell(SPELL_BERSERK);
- me->RemoveAurasDueToSpell(SPELL_MANA_BARRIER);
+ _phase = PHASE_ONE;
+ DoCastSelf(SPELL_SHADOW_CHANNELING);
+ me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA));
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false);
}
void DoAction(int32 action) override
{
- switch (action)
+ if (action != ACTION_START_INTRO)
+ return;
+
+ if (!_introDone)
{
- case ACTION_START_INTRO:
- if (!_introDone)
+ _introDone = true;
+ Talk(SAY_INTRO_1);
+ _phase = PHASE_INTRO;
+ scheduler.Schedule(Seconds(10), GROUP_INTRO, [this](TaskContext context)
+ {
+ switch (context.GetRepeatCounter())
{
- _introDone = true;
- Talk(SAY_INTRO_1);
- events.SetPhase(PHASE_INTRO);
- events.ScheduleEvent(EVENT_INTRO_2, 11000, 0, PHASE_INTRO);
- events.ScheduleEvent(EVENT_INTRO_3, 21000, 0, PHASE_INTRO);
- events.ScheduleEvent(EVENT_INTRO_4, 31500, 0, PHASE_INTRO);
- events.ScheduleEvent(EVENT_INTRO_5, 39500, 0, PHASE_INTRO);
- events.ScheduleEvent(EVENT_INTRO_6, 48500, 0, PHASE_INTRO);
- events.ScheduleEvent(EVENT_INTRO_7, 58000, 0, PHASE_INTRO);
+ case 0:
+ Talk(SAY_INTRO_2);
+ context.Repeat(Seconds(21));
+ break;
+ case 1:
+ Talk(SAY_INTRO_3);
+ context.Repeat(Seconds(11));
+ break;
+ case 2:
+ Talk(SAY_INTRO_4);
+ context.Repeat(Seconds(9));
+ break;
+ case 3:
+ Talk(SAY_INTRO_5);
+ context.Repeat(Seconds(21));
+ break;
+ case 4:
+ Talk(SAY_INTRO_6);
+ context.Repeat(Seconds(10));
+ break;
+ case 5:
+ Talk(SAY_INTRO_7);
+ return;
+ default:
+ break;
}
- break;
- default:
- break;
+ });
}
}
@@ -274,7 +270,7 @@ class boss_lady_deathwhisper : public CreatureScript
if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
return;
- if (victim && me->Attack(victim, true) && !events.IsInPhase(PHASE_ONE))
+ if (victim && me->Attack(victim, true) && _phase != PHASE_ONE)
me->GetMotionMaster()->MoveChase(victim);
}
@@ -282,31 +278,61 @@ class boss_lady_deathwhisper : public CreatureScript
{
if (!instance->CheckRequiredBosses(DATA_LADY_DEATHWHISPER, who->ToPlayer()))
{
- EnterEvadeMode();
+ EnterEvadeMode(EVADE_REASON_SEQUENCE_BREAK);
instance->DoCastSpellOnPlayers(LIGHT_S_HAMMER_TELEPORT);
return;
}
+ me->SetCombatPulseDelay(5);
me->setActive(true);
DoZoneInCombat();
-
- events.Reset();
- events.SetPhase(PHASE_ONE);
+ _phase = PHASE_ONE;
+ scheduler.CancelGroup(GROUP_INTRO);
// phase-independent events
- events.ScheduleEvent(EVENT_BERSERK, 600000);
- events.ScheduleEvent(EVENT_DEATH_AND_DECAY, 10000);
+ scheduler
+ .Schedule(Minutes(10), [this](TaskContext /*context*/)
+ {
+ DoCastSelf(SPELL_BERSERK);
+ Talk(SAY_BERSERK);
+ })
+ .Schedule(Seconds(17), [this](TaskContext death_and_decay)
+ {
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(target, SPELL_DEATH_AND_DECAY);
+ death_and_decay.Repeat(Seconds(22), Seconds(30));
+ });
+ if (GetDifficulty() != RAID_DIFFICULTY_10MAN_NORMAL)
+ scheduler.Schedule(Seconds(27), [this](TaskContext dominate_mind)
+ {
+ Talk(SAY_DOMINATE_MIND);
+ for (uint8 i = 0; i < _dominateMindCount; i++)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_DOMINATE_MIND))
+ DoCast(target, SPELL_DOMINATE_MIND);
+ dominate_mind.Repeat(Seconds(40), Seconds(45));
+ });
// phase one only
- events.ScheduleEvent(EVENT_P1_SUMMON_WAVE, 5000, 0, PHASE_ONE);
- events.ScheduleEvent(EVENT_P1_SHADOW_BOLT, urand(5500, 6000), 0, PHASE_ONE);
- events.ScheduleEvent(EVENT_P1_EMPOWER_CULTIST, urand(20000, 30000), 0, PHASE_ONE);
- if (GetDifficulty() != RAID_DIFFICULTY_10MAN_NORMAL)
- events.ScheduleEvent(EVENT_DOMINATE_MIND_H, 27000);
+ scheduler
+ .Schedule(Seconds(5), GROUP_ONE, [this](TaskContext wave)
+ {
+ SummonWaveP1();
+ wave.Repeat(Seconds(IsHeroic() ? 45 : 60));
+ })
+ .Schedule(Seconds(2), GROUP_ONE, [this](TaskContext shadow_bolt)
+ {
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(target, SPELL_SHADOW_BOLT);
+ shadow_bolt.Repeat(Milliseconds(2450), Milliseconds(3600));
+ })
+ .Schedule(Seconds(15), GROUP_ONE, [this](TaskContext context)
+ {
+ DoImproveCultist();
+ context.Repeat(Seconds(25));
+ });
Talk(SAY_AGGRO);
DoStartNoMovement(who);
me->RemoveAurasDueToSpell(SPELL_SHADOW_CHANNELING);
- DoCast(me, SPELL_MANA_BARRIER, true);
-
+ DoCastSelf(SPELL_MANA_BARRIER, true);
instance->SetBossState(DATA_LADY_DEATHWHISPER, IN_PROGRESS);
}
@@ -338,7 +364,7 @@ class boss_lady_deathwhisper : public CreatureScript
{
if (Group* group = owner->GetGroup())
{
- for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
+ for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
if (Player* member = itr->GetSource())
member->KilledMonsterCredit(NPC_DARNAVAN_CREDIT);
}
@@ -351,17 +377,14 @@ class boss_lady_deathwhisper : public CreatureScript
_JustDied();
}
- void JustReachedHome() override
+ void EnterEvadeMode(EvadeReason /*why*/) override
{
- _JustReachedHome();
- instance->SetBossState(DATA_LADY_DEATHWHISPER, FAIL);
-
+ scheduler.CancelAll();
summons.DespawnAll();
if (Creature* darnavan = ObjectAccessor::GetCreature(*me, _darnavanGUID))
- {
darnavan->DespawnOrUnsummon();
- _darnavanGUID.Clear();
- }
+
+ _DespawnAtEvade();
}
void KilledUnit(Unit* victim) override
@@ -373,151 +396,98 @@ class boss_lady_deathwhisper : public CreatureScript
void DamageTaken(Unit* /*damageDealer*/, uint32& damage) override
{
// phase transition
- if (events.IsInPhase(PHASE_ONE) && damage > me->GetPower(POWER_MANA))
+ if (_phase == PHASE_ONE && damage > me->GetPower(POWER_MANA))
{
+ _phase = PHASE_TWO;
Talk(SAY_PHASE_2);
Talk(EMOTE_PHASE_2);
DoStartMovement(me->GetVictim());
+ DoResetThreat();
damage -= me->GetPower(POWER_MANA);
me->SetPower(POWER_MANA, 0);
me->RemoveAurasDueToSpell(SPELL_MANA_BARRIER);
- events.SetPhase(PHASE_TWO);
- events.ScheduleEvent(EVENT_P2_FROSTBOLT, urand(10000, 12000), 0, PHASE_TWO);
- events.ScheduleEvent(EVENT_P2_FROSTBOLT_VOLLEY, urand(19000, 21000), 0, PHASE_TWO);
- events.ScheduleEvent(EVENT_P2_TOUCH_OF_INSIGNIFICANCE, urand(6000, 9000), 0, PHASE_TWO);
- events.ScheduleEvent(EVENT_P2_SUMMON_SHADE, urand(12000, 15000), 0, PHASE_TWO);
+ scheduler.CancelGroup(GROUP_ONE);
+
+ scheduler
+ .Schedule(Seconds(12), GROUP_TWO, [this](TaskContext frostbolt)
+ {
+ DoCastVictim(SPELL_FROSTBOLT);
+ frostbolt.Repeat();
+ })
+ .Schedule(Seconds(20), GROUP_TWO, [this](TaskContext frostboldVolley)
+ {
+ DoCastAOE(SPELL_FROSTBOLT_VOLLEY);
+ frostboldVolley.Repeat();
+ })
+ .Schedule(Seconds(6), Seconds(9), GROUP_TWO, [this](TaskContext touch)
+ {
+ if (me->GetVictim())
+ me->AddAura(SPELL_TOUCH_OF_INSIGNIFICANCE, me->EnsureVictim());
+ touch.Repeat();
+ })
+ .Schedule(Seconds(12), GROUP_TWO, [this](TaskContext summonShade)
+ {
+ me->CastCustomSpell(SPELL_SUMMON_SPIRITS, SPELLVALUE_MAX_TARGETS, Is25ManRaid() ? 2 : 1);
+ summonShade.Repeat();
+ });
+
// on heroic mode Lady Deathwhisper is immune to taunt effects in phase 2 and continues summoning adds
if (IsHeroic())
{
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true);
- events.ScheduleEvent(EVENT_P2_SUMMON_WAVE, 45000, 0, PHASE_TWO);
+ scheduler.Schedule(Seconds(), GROUP_TWO, [this](TaskContext context)
+ {
+ SummonWaveP2();
+ context.Repeat(Seconds(45));
+ });
}
}
}
- void JustSummoned(Creature* summon) override
+ void SpellHitTarget(Unit* target, const SpellInfo* spell) override
{
- if (summon->GetEntry() == NPC_DARNAVAN)
- _darnavanGUID = summon->GetGUID();
- else
- summons.Summon(summon);
+ if (spell->Id == SPELL_SUMMON_SPIRITS)
+ _nextVengefulShadeTargetGUID.push_back(target->GetGUID());
+ }
- Unit* target = NULL;
- if (summon->GetEntry() == NPC_VENGEFUL_SHADE)
+ void JustSummoned(Creature* summon) override
+ {
+ switch (summon->GetEntry())
{
- target = ObjectAccessor::GetUnit(*me, _nextVengefulShadeTargetGUID); // Vengeful Shade
- _nextVengefulShadeTargetGUID.Clear();
+ case NPC_DARNAVAN_10:
+ case NPC_DARNAVAN_25:
+ _darnavanGUID = summon->GetGUID();
+ summon->AI()->AttackStart(SelectTarget(SELECT_TARGET_RANDOM));
+ return;
+ case NPC_VENGEFUL_SHADE:
+ if (_nextVengefulShadeTargetGUID.empty())
+ break;
+ summon->AI()->SetGUID(_nextVengefulShadeTargetGUID.front());
+ _nextVengefulShadeTargetGUID.pop_front();
+ break;
+ case NPC_CULT_ADHERENT:
+ case NPC_CULT_FANATIC:
+ _cultistQueue.push_back(summon->GetGUID());
+ summon->AI()->AttackStart(SelectTarget(SELECT_TARGET_RANDOM));
+ break;
+ default:
+ break;
}
- else
- target = SelectTarget(SELECT_TARGET_RANDOM); // Wave adds
-
- summon->AI()->AttackStart(target); // CAN be NULL
- if (summon->GetEntry() == NPC_REANIMATED_FANATIC)
- summon->CastSpell(summon, SPELL_FANATIC_S_DETERMINATION, true);
- else if (summon->GetEntry() == NPC_REANIMATED_ADHERENT)
- summon->CastSpell(summon, SPELL_ADHERENT_S_DETERMINATION, true);
+ summons.Summon(summon);
}
void UpdateAI(uint32 diff) override
{
- if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO))
+ if (!UpdateVictim() && _phase != PHASE_INTRO)
return;
- events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_CASTING) && !events.IsInPhase(PHASE_INTRO))
- return;
-
- while (uint32 eventId = events.ExecuteEvent())
+ scheduler.Update(diff, [this]
{
- switch (eventId)
- {
- case EVENT_INTRO_2:
- Talk(SAY_INTRO_2);
- break;
- case EVENT_INTRO_3:
- Talk(SAY_INTRO_3);
- break;
- case EVENT_INTRO_4:
- Talk(SAY_INTRO_4);
- break;
- case EVENT_INTRO_5:
- Talk(SAY_INTRO_5);
- break;
- case EVENT_INTRO_6:
- Talk(SAY_INTRO_6);
- break;
- case EVENT_INTRO_7:
- Talk(SAY_INTRO_7);
- break;
- case EVENT_DEATH_AND_DECAY:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
- DoCast(target, SPELL_DEATH_AND_DECAY);
- events.ScheduleEvent(EVENT_DEATH_AND_DECAY, urand(22000, 30000));
- break;
- case EVENT_DOMINATE_MIND_H:
- Talk(SAY_DOMINATE_MIND);
- for (uint8 i = 0; i < _dominateMindCount; i++)
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_DOMINATE_MIND_H))
- DoCast(target, SPELL_DOMINATE_MIND_H);
- events.ScheduleEvent(EVENT_DOMINATE_MIND_H, urand(40000, 45000));
- break;
- case EVENT_P1_SUMMON_WAVE:
- SummonWaveP1();
- events.ScheduleEvent(EVENT_P1_SUMMON_WAVE, IsHeroic() ? 45000 : 60000, 0, PHASE_ONE);
- break;
- case EVENT_P1_SHADOW_BOLT:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
- DoCast(target, SPELL_SHADOW_BOLT);
- events.ScheduleEvent(EVENT_P1_SHADOW_BOLT, urand(5000, 8000), 0, PHASE_ONE);
- break;
- case EVENT_P1_REANIMATE_CULTIST:
- ReanimateCultist();
- break;
- case EVENT_P1_EMPOWER_CULTIST:
- EmpowerCultist();
- events.ScheduleEvent(EVENT_P1_EMPOWER_CULTIST, urand(18000, 25000));
- break;
- case EVENT_P2_FROSTBOLT:
- DoCastVictim(SPELL_FROSTBOLT);
- events.ScheduleEvent(EVENT_P2_FROSTBOLT, urand(10000, 11000), 0, PHASE_TWO);
- break;
- case EVENT_P2_FROSTBOLT_VOLLEY:
- DoCastAOE(SPELL_FROSTBOLT_VOLLEY);
- events.ScheduleEvent(EVENT_P2_FROSTBOLT_VOLLEY, urand(13000, 15000), 0, PHASE_TWO);
- break;
- case EVENT_P2_TOUCH_OF_INSIGNIFICANCE:
- DoCastVictim(SPELL_TOUCH_OF_INSIGNIFICANCE);
- events.ScheduleEvent(EVENT_P2_TOUCH_OF_INSIGNIFICANCE, urand(9000, 13000), 0, PHASE_TWO);
- break;
- case EVENT_P2_SUMMON_SHADE:
- if (Unit* shadeTarget = SelectTarget(SELECT_TARGET_RANDOM, 1))
- {
- _nextVengefulShadeTargetGUID = shadeTarget->GetGUID();
- DoCast(shadeTarget, SPELL_SUMMON_SHADE);
- }
- events.ScheduleEvent(EVENT_P2_SUMMON_SHADE, urand(18000, 23000), 0, PHASE_TWO);
- break;
- case EVENT_P2_SUMMON_WAVE:
- SummonWaveP2();
- events.ScheduleEvent(EVENT_P2_SUMMON_WAVE, 45000, 0, PHASE_TWO);
- break;
- case EVENT_BERSERK:
- DoCast(me, SPELL_BERSERK);
- Talk(SAY_BERSERK);
- break;
- }
-
- if (me->HasUnitState(UNIT_STATE_CASTING) && !events.IsInPhase(PHASE_INTRO))
- return;
- }
-
- // We should not melee attack when barrier is up
- if (me->HasAura(SPELL_MANA_BARRIER))
- return;
-
- DoMeleeAttackIfReady();
+ // We should not melee attack when barrier is up
+ if (!me->HasAura(SPELL_MANA_BARRIER))
+ DoMeleeAttackIfReady();
+ });
}
// summoning function for first phase
@@ -568,72 +538,40 @@ class boss_lady_deathwhisper : public CreatureScript
summon->CastSpell(summon, SPELL_TELEPORT_VISUAL);
}
- void SetGUID(ObjectGuid guid, int32 id/* = 0*/) override
+ void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
- if (id != GUID_CULTIST)
- return;
-
- _reanimationQueue.push_back(guid);
- events.ScheduleEvent(EVENT_P1_REANIMATE_CULTIST, 3000, 0, PHASE_ONE);
+ if (summon->GetEntry() == NPC_CULT_ADHERENT || summon->GetEntry() == NPC_CULT_FANATIC)
+ _cultistQueue.remove(summon->GetGUID());
}
- void ReanimateCultist()
+ void DoImproveCultist()
{
- if (_reanimationQueue.empty())
+ if (_cultistQueue.empty())
return;
- ObjectGuid cultistGUID = _reanimationQueue.front();
- Creature* cultist = ObjectAccessor::GetCreature(*me, cultistGUID);
- _reanimationQueue.pop_front();
+ _cultistGUID = Trinity::Containers::SelectRandomContainerElement(_cultistQueue);
+ _cultistQueue.remove(_cultistGUID);
+ Creature* cultist = ObjectAccessor::GetCreature(*me, _cultistGUID);
if (!cultist)
return;
- Talk(SAY_ANIMATE_DEAD);
- DoCast(cultist, SPELL_DARK_MARTYRDOM_T);
- }
-
- void SpellHitTarget(Unit* target, SpellInfo const* spell) override
- {
- if (spell->Id == SPELL_DARK_MARTYRDOM_T)
+ if (RAND(0,1))
+ me->CastSpell(cultist, SPELL_DARK_MARTYRDOM_T);
+ else
{
- Position pos = target->GetPosition();
- if (target->GetEntry() == NPC_CULT_FANATIC)
- me->SummonCreature(NPC_REANIMATED_FANATIC, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000);
- else
- me->SummonCreature(NPC_REANIMATED_ADHERENT, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000);
-
- if (TempSummon* summon = target->ToTempSummon())
- summon->UnSummon();
+ me->CastSpell(cultist, cultist->GetEntry() == NPC_CULT_FANATIC ? SPELL_DARK_TRANSFORMATION_T : SPELL_DARK_EMPOWERMENT_T, true);
+ Talk(uint8(cultist->GetEntry() == NPC_CULT_FANATIC ? SAY_DARK_TRANSFORMATION : SAY_DARK_EMPOWERMENT));
}
}
- void EmpowerCultist()
- {
- if (summons.empty())
- return;
-
- std::list<Creature*> temp;
- for (SummonList::iterator itr = summons.begin(); itr != summons.end(); ++itr)
- if (Creature* cre = ObjectAccessor::GetCreature(*me, *itr))
- if (cre->IsAlive() && (cre->GetEntry() == NPC_CULT_FANATIC || cre->GetEntry() == NPC_CULT_ADHERENT))
- temp.push_back(cre);
-
- // noone to empower
- if (temp.empty())
- return;
-
- // select random cultist
- Creature* cultist = Trinity::Containers::SelectRandomContainerElement(temp);
- DoCast(cultist, cultist->GetEntry() == NPC_CULT_FANATIC ? SPELL_DARK_TRANSFORMATION_T : SPELL_DARK_EMPOWERMENT_T, true);
- Talk(uint8(cultist->GetEntry() == NPC_CULT_FANATIC ? SAY_DARK_TRANSFORMATION : SAY_DARK_EMPOWERMENT));
- }
-
private:
- ObjectGuid _nextVengefulShadeTargetGUID;
ObjectGuid _darnavanGUID;
- GuidDeque _reanimationQueue;
+ ObjectGuid _cultistGUID;
+ GuidList _cultistQueue;
+ GuidList _nextVengefulShadeTargetGUID;
uint32 _waveCounter;
uint8 const _dominateMindCount;
+ uint8 _phase;
bool _introDone;
};
@@ -643,8 +581,6 @@ class boss_lady_deathwhisper : public CreatureScript
}
};
-typedef boss_lady_deathwhisper::boss_lady_deathwhisperAI DeathwisperAI;
-
class npc_cult_fanatic : public CreatureScript
{
public:
@@ -652,71 +588,91 @@ class npc_cult_fanatic : public CreatureScript
struct npc_cult_fanaticAI : public ScriptedAI
{
- npc_cult_fanaticAI(Creature* creature) : ScriptedAI(creature) { }
+ npc_cult_fanaticAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void Reset() override
{
- Events.Reset();
- Events.ScheduleEvent(EVENT_FANATIC_NECROTIC_STRIKE, urand(10000, 12000));
- Events.ScheduleEvent(EVENT_FANATIC_SHADOW_CLEAVE, urand(14000, 16000));
- Events.ScheduleEvent(EVENT_FANATIC_VAMPIRIC_MIGHT, urand(20000, 27000));
- if (me->GetEntry() == NPC_CULT_FANATIC)
- Events.ScheduleEvent(EVENT_CULTIST_DARK_MARTYRDOM, urand(18000, 32000));
+ _scheduler.CancelAll();
+ _scheduler
+ .SetValidator([this]
+ {
+ return !me->HasUnitState(UNIT_STATE_CASTING);
+ })
+ .Schedule(Seconds(17), [this](TaskContext vampiric_might)
+ {
+ DoCastSelf(SPELL_VAMPIRIC_MIGHT);
+ vampiric_might.Repeat(Seconds(25));
+ })
+ .Schedule(Seconds(12), [this](TaskContext shadow_cleave)
+ {
+ DoCastVictim(SPELL_SHADOW_CLEAVE);
+ shadow_cleave.Repeat(Seconds(14));
+ })
+ .Schedule(Seconds(10), [this](TaskContext necrotic_strike)
+ {
+ DoCastVictim(SPELL_NECROTIC_STRIKE);
+ necrotic_strike.Repeat(Seconds(17));
+ });
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
{
- if (spell->Id == SPELL_DARK_TRANSFORMATION)
- me->UpdateEntry(NPC_DEFORMED_FANATIC);
- else if (spell->Id == SPELL_DARK_TRANSFORMATION_T)
+ switch (spell->Id)
{
- Events.CancelEvent(EVENT_CULTIST_DARK_MARTYRDOM);
- me->InterruptNonMeleeSpells(true);
- DoCast(me, SPELL_DARK_TRANSFORMATION);
+ case SPELL_DARK_TRANSFORMATION_T:
+ me->InterruptNonMeleeSpells(true);
+ DoCastSelf(SPELL_DARK_TRANSFORMATION);
+ break;
+ case SPELL_DARK_TRANSFORMATION:
+ DoCastSelf(SPELL_FULL_HEAL);
+ me->UpdateEntry(NPC_DEFORMED_FANATIC);
+ break;
+ case SPELL_DARK_MARTYRDOM_T:
+ me->SetReactState(REACT_PASSIVE);
+ me->InterruptNonMeleeSpells(true);
+ me->AttackStop();
+ DoCastSelf(SPELL_DARK_MARTYRDOM_FANATIC);
+ break;
+ case SPELL_DARK_MARTYRDOM_FANATIC:
+ _scheduler
+ .Schedule(Seconds(2), [this](TaskContext /*context*/)
+ {
+ me->UpdateEntry(NPC_REANIMATED_FANATIC);
+ DoCastSelf(SPELL_PERMANENT_FEIGN_DEATH);
+ DoCastSelf(SPELL_CLEAR_ALL_DEBUFFS);
+ DoCastSelf(SPELL_FULL_HEAL, true);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_UNK_29 | UNIT_FLAG_NOT_SELECTABLE);
+ })
+ .Schedule(Seconds(6), [this](TaskContext /*context*/)
+ {
+ me->RemoveAurasDueToSpell(SPELL_PERMANENT_FEIGN_DEATH);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_UNK_29 | UNIT_FLAG_NOT_SELECTABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ DoZoneInCombat(me);
+
+ if (Creature* ladyDeathwhisper = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_LADY_DEATHWHISPER)))
+ ladyDeathwhisper->AI()->Talk(SAY_ANIMATE_DEAD);
+ });
+ break;
+ default:
+ break;
}
}
void UpdateAI(uint32 diff) override
{
- if (!UpdateVictim())
- return;
-
- Events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
+ if (!UpdateVictim() && !me->HasAura(SPELL_PERMANENT_FEIGN_DEATH))
return;
- while (uint32 eventId = Events.ExecuteEvent())
+ _scheduler.Update(diff, [this]
{
- switch (eventId)
- {
- case EVENT_FANATIC_NECROTIC_STRIKE:
- DoCastVictim(SPELL_NECROTIC_STRIKE);
- Events.ScheduleEvent(EVENT_FANATIC_NECROTIC_STRIKE, urand(11000, 13000));
- break;
- case EVENT_FANATIC_SHADOW_CLEAVE:
- DoCastVictim(SPELL_SHADOW_CLEAVE);
- Events.ScheduleEvent(EVENT_FANATIC_SHADOW_CLEAVE, urand(9500, 11000));
- break;
- case EVENT_FANATIC_VAMPIRIC_MIGHT:
- DoCast(me, SPELL_VAMPIRIC_MIGHT);
- Events.ScheduleEvent(EVENT_FANATIC_VAMPIRIC_MIGHT, urand(20000, 27000));
- break;
- case EVENT_CULTIST_DARK_MARTYRDOM:
- DoCast(me, SPELL_DARK_MARTYRDOM_FANATIC);
- Events.ScheduleEvent(EVENT_CULTIST_DARK_MARTYRDOM, urand(16000, 21000));
- break;
- }
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
- }
-
- DoMeleeAttackIfReady();
+ DoMeleeAttackIfReady();
+ });
}
protected:
- EventMap Events;
+ TaskScheduler _scheduler;
+ InstanceScript* _instance;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -732,80 +688,88 @@ class npc_cult_adherent : public CreatureScript
struct npc_cult_adherentAI : public ScriptedAI
{
- npc_cult_adherentAI(Creature* creature) : ScriptedAI(creature) { }
+ npc_cult_adherentAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void Reset() override
{
- Events.Reset();
- Events.ScheduleEvent(EVENT_ADHERENT_FROST_FEVER, urand(10000, 12000));
- Events.ScheduleEvent(EVENT_ADHERENT_DEATHCHILL, urand(14000, 16000));
- Events.ScheduleEvent(EVENT_ADHERENT_CURSE_OF_TORPOR, urand(14000, 16000));
- Events.ScheduleEvent(EVENT_ADHERENT_SHORUD_OF_THE_OCCULT, urand(32000, 39000));
- if (me->GetEntry() == NPC_CULT_ADHERENT)
- Events.ScheduleEvent(EVENT_CULTIST_DARK_MARTYRDOM, urand(18000, 32000));
+ _scheduler.CancelAll();
+ _scheduler
+ .SetValidator([this]
+ {
+ return !me->HasUnitState(UNIT_STATE_CASTING);
+ })
+ .Schedule(Seconds(5), [this](TaskContext deathchill)
+ {
+ if (me->GetEntry() == NPC_EMPOWERED_ADHERENT)
+ DoCastVictim(SPELL_DEATHCHILL_BLAST);
+ else
+ DoCastVictim(SPELL_DEATHCHILL_BOLT);
+ deathchill.Repeat(Milliseconds(2500));
+ })
+ .Schedule(Seconds(15), [this](TaskContext shroud_of_the_occult)
+ {
+ DoCastSelf(SPELL_SHROUD_OF_THE_OCCULT);
+ shroud_of_the_occult.Repeat(Seconds(10));
+ })
+ .Schedule(Seconds(15), [this](TaskContext curse_of_torpor)
+ {
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1))
+ DoCast(target, SPELL_CURSE_OF_TORPOR);
+ curse_of_torpor.Repeat(Seconds(18));
+ });
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
{
- if (spell->Id == SPELL_DARK_EMPOWERMENT)
- me->UpdateEntry(NPC_EMPOWERED_ADHERENT);
- else if (spell->Id == SPELL_DARK_EMPOWERMENT_T)
+ switch (spell->Id)
{
- Events.CancelEvent(EVENT_CULTIST_DARK_MARTYRDOM);
- me->InterruptNonMeleeSpells(true);
- DoCast(me, SPELL_DARK_EMPOWERMENT);
+ case SPELL_DARK_EMPOWERMENT_T:
+ me->UpdateEntry(NPC_EMPOWERED_ADHERENT);
+ break;
+ case SPELL_DARK_MARTYRDOM_T:
+ me->SetReactState(REACT_PASSIVE);
+ me->InterruptNonMeleeSpells(true);
+ me->AttackStop();
+ DoCastSelf(SPELL_DARK_MARTYRDOM_ADHERENT);
+ break;
+ case SPELL_DARK_MARTYRDOM_ADHERENT:
+ _scheduler
+ .Schedule(Seconds(2), [this](TaskContext /*context*/)
+ {
+ me->UpdateEntry(NPC_REANIMATED_ADHERENT);
+ DoCastSelf(SPELL_PERMANENT_FEIGN_DEATH);
+ DoCastSelf(SPELL_CLEAR_ALL_DEBUFFS);
+ DoCastSelf(SPELL_FULL_HEAL, true);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_UNK_29 | UNIT_FLAG_NOT_SELECTABLE);
+ })
+ .Schedule(Seconds(6), [this](TaskContext /*context*/)
+ {
+ me->RemoveAurasDueToSpell(SPELL_PERMANENT_FEIGN_DEATH);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_UNK_29 | UNIT_FLAG_NOT_SELECTABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ DoCastSelf(SPELL_SHROUD_OF_THE_OCCULT);
+ DoZoneInCombat(me);
+
+ if (Creature* ladyDeathwhisper = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_LADY_DEATHWHISPER)))
+ ladyDeathwhisper->AI()->Talk(SAY_ANIMATE_DEAD);
+ });
+ break;
+ default:
+ break;
}
}
void UpdateAI(uint32 diff) override
{
- if (!UpdateVictim())
+ if (!UpdateVictim() && !me->HasAura(SPELL_PERMANENT_FEIGN_DEATH))
return;
- Events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- while (uint32 eventId = Events.ExecuteEvent())
- {
- switch (eventId)
- {
- case EVENT_ADHERENT_FROST_FEVER:
- DoCastVictim(SPELL_FROST_FEVER);
- Events.ScheduleEvent(EVENT_ADHERENT_FROST_FEVER, urand(9000, 13000));
- break;
- case EVENT_ADHERENT_DEATHCHILL:
- if (me->GetEntry() == NPC_EMPOWERED_ADHERENT)
- DoCastVictim(SPELL_DEATHCHILL_BLAST);
- else
- DoCastVictim(SPELL_DEATHCHILL_BOLT);
- Events.ScheduleEvent(EVENT_ADHERENT_DEATHCHILL, urand(9000, 13000));
- break;
- case EVENT_ADHERENT_CURSE_OF_TORPOR:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1))
- DoCast(target, SPELL_CURSE_OF_TORPOR);
- Events.ScheduleEvent(EVENT_ADHERENT_CURSE_OF_TORPOR, urand(9000, 13000));
- break;
- case EVENT_ADHERENT_SHORUD_OF_THE_OCCULT:
- DoCast(me, SPELL_SHORUD_OF_THE_OCCULT);
- Events.ScheduleEvent(EVENT_ADHERENT_SHORUD_OF_THE_OCCULT, urand(27000, 32000));
- break;
- case EVENT_CULTIST_DARK_MARTYRDOM:
- DoCast(me, SPELL_DARK_MARTYRDOM_ADHERENT);
- Events.ScheduleEvent(EVENT_CULTIST_DARK_MARTYRDOM, urand(16000, 21000));
- break;
- }
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
- }
-
- DoMeleeAttackIfReady();
+ _scheduler.Update(diff);
}
protected:
- EventMap Events;
+ TaskScheduler _scheduler;
+ InstanceScript* _instance;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -821,15 +785,28 @@ class npc_vengeful_shade : public CreatureScript
struct npc_vengeful_shadeAI : public ScriptedAI
{
- npc_vengeful_shadeAI(Creature* creature) : ScriptedAI(creature)
- {
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- }
+ npc_vengeful_shadeAI(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
+ me->SetReactState(REACT_PASSIVE);
me->AddAura(SPELL_VENGEFUL_BLAST_PASSIVE, me);
+
+ _scheduler
+ .Schedule(Seconds(2), [this](TaskContext /*context*/)
+ {
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->AI()->AttackStart(ObjectAccessor::GetUnit(*me, _targetGUID));
+ })
+ .Schedule(Seconds(7), [this](TaskContext /*context*/)
+ {
+ me->KillSelf();
+ });
+ }
+
+ void SetGUID(ObjectGuid guid, int32 /*type*/) override
+ {
+ _targetGUID = guid;
}
void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) override
@@ -846,6 +823,18 @@ class npc_vengeful_shade : public CreatureScript
break;
}
}
+
+ void UpdateAI(uint32 diff) override
+ {
+ _scheduler.Update(diff, [this]
+ {
+ DoMeleeAttackIfReady();
+ });
+ }
+
+ private:
+ TaskScheduler _scheduler;
+ ObjectGuid _targetGUID;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -875,10 +864,10 @@ class npc_darnavan : public CreatureScript
void Reset() override
{
_events.Reset();
- _events.ScheduleEvent(EVENT_DARNAVAN_BLADESTORM, 10000);
- _events.ScheduleEvent(EVENT_DARNAVAN_INTIMIDATING_SHOUT, urand(20000, 25000));
- _events.ScheduleEvent(EVENT_DARNAVAN_MORTAL_STRIKE, urand(25000, 30000));
- _events.ScheduleEvent(EVENT_DARNAVAN_SUNDER_ARMOR, urand(5000, 8000));
+ _events.ScheduleEvent(EVENT_DARNAVAN_BLADESTORM, Seconds(10));
+ _events.ScheduleEvent(EVENT_DARNAVAN_INTIMIDATING_SHOUT, Seconds(20), Seconds(25));
+ _events.ScheduleEvent(EVENT_DARNAVAN_MORTAL_STRIKE, Seconds(25), Seconds(30));
+ _events.ScheduleEvent(EVENT_DARNAVAN_SUNDER_ARMOR, Seconds(5), Seconds(8));
Initialize();
}
@@ -889,7 +878,7 @@ class npc_darnavan : public CreatureScript
{
if (Group* group = owner->GetGroup())
{
- for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
+ for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
if (Player* member = itr->GetSource())
member->FailQuest(QUEST_DEPROGRAMMING);
}
@@ -925,7 +914,7 @@ class npc_darnavan : public CreatureScript
{
DoCastVictim(SPELL_SHATTERING_THROW);
_canShatter = false;
- _events.ScheduleEvent(EVENT_DARNAVAN_SHATTERING_THROW, 30000);
+ _events.ScheduleEvent(EVENT_DARNAVAN_SHATTERING_THROW, Seconds(30));
return;
}
@@ -933,7 +922,7 @@ class npc_darnavan : public CreatureScript
{
DoCastVictim(SPELL_CHARGE);
_canCharge = false;
- _events.ScheduleEvent(EVENT_DARNAVAN_CHARGE, 20000);
+ _events.ScheduleEvent(EVENT_DARNAVAN_CHARGE, Seconds(20));
return;
}
@@ -943,25 +932,25 @@ class npc_darnavan : public CreatureScript
{
case EVENT_DARNAVAN_BLADESTORM:
DoCast(SPELL_BLADESTORM);
- _events.ScheduleEvent(EVENT_DARNAVAN_BLADESTORM, urand(90000, 100000));
+ _events.ScheduleEvent(EVENT_DARNAVAN_BLADESTORM, Seconds(90), Seconds(100));
break;
case EVENT_DARNAVAN_CHARGE:
_canCharge = true;
break;
case EVENT_DARNAVAN_INTIMIDATING_SHOUT:
DoCast(SPELL_INTIMIDATING_SHOUT);
- _events.ScheduleEvent(EVENT_DARNAVAN_INTIMIDATING_SHOUT, urand(90000, 120000));
+ _events.ScheduleEvent(EVENT_DARNAVAN_INTIMIDATING_SHOUT, Seconds(90), Minutes(2));
break;
case EVENT_DARNAVAN_MORTAL_STRIKE:
DoCastVictim(SPELL_MORTAL_STRIKE);
- _events.ScheduleEvent(EVENT_DARNAVAN_MORTAL_STRIKE, urand(15000, 30000));
+ _events.ScheduleEvent(EVENT_DARNAVAN_MORTAL_STRIKE, Seconds(15), Seconds(30));
break;
case EVENT_DARNAVAN_SHATTERING_THROW:
_canShatter = true;
break;
case EVENT_DARNAVAN_SUNDER_ARMOR:
DoCastVictim(SPELL_SUNDER_ARMOR);
- _events.ScheduleEvent(EVENT_DARNAVAN_SUNDER_ARMOR, urand(3000, 7000));
+ _events.ScheduleEvent(EVENT_DARNAVAN_SUNDER_ARMOR, Seconds(3), Seconds(7));
break;
}
}
@@ -1013,50 +1002,86 @@ class spell_deathwhisper_mana_barrier : public SpellScriptLoader
}
};
-class spell_cultist_dark_martyrdom : public SpellScriptLoader
+class at_lady_deathwhisper_entrance : public AreaTriggerScript
{
public:
- spell_cultist_dark_martyrdom() : SpellScriptLoader("spell_cultist_dark_martyrdom") { }
+ at_lady_deathwhisper_entrance() : AreaTriggerScript("at_lady_deathwhisper_entrance") { }
- class spell_cultist_dark_martyrdom_SpellScript : public SpellScript
+ bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
{
- PrepareSpellScript(spell_cultist_dark_martyrdom_SpellScript);
+ if (InstanceScript* instance = player->GetInstanceScript())
+ if (instance->GetBossState(DATA_LADY_DEATHWHISPER) != DONE)
+ if (Creature* ladyDeathwhisper = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_LADY_DEATHWHISPER)))
+ ladyDeathwhisper->AI()->DoAction(ACTION_START_INTRO);
+
+ return true;
+ }
+};
+
+class spell_deathwhisper_dominated_mind : public SpellScriptLoader
+{
+ public:
+ spell_deathwhisper_dominated_mind() : SpellScriptLoader("spell_deathwhisper_dominated_mind") { }
- void HandleEffect(SpellEffIndex /*effIndex*/)
+ class spell_deathwhisper_dominated_mind_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_deathwhisper_dominated_mind_AuraScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
{
- if (GetCaster()->IsSummon())
- if (Unit* owner = GetCaster()->ToTempSummon()->GetSummoner())
- owner->GetAI()->SetGUID(GetCaster()->GetGUID(), GUID_CULTIST);
+ if (!sSpellMgr->GetSpellInfo(SPELL_DOMINATE_MIND_SCALE))
+ return false;
+ return true;
+ }
- GetCaster()->KillSelf();
- GetCaster()->SetDisplayId(uint32(GetCaster()->GetEntry() == NPC_CULT_FANATIC ? 38009 : 38010));
+ void HandleApply(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ target->CastSpell(target, SPELL_DOMINATE_MIND_SCALE, true);
}
void Register() override
{
- OnEffectHitTarget += SpellEffectFn(spell_cultist_dark_martyrdom_SpellScript::HandleEffect, EFFECT_2, SPELL_EFFECT_FORCE_DESELECT);
+ AfterEffectApply += AuraEffectApplyFn(spell_deathwhisper_dominated_mind_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_AOE_CHARM, AURA_EFFECT_HANDLE_REAL);
}
};
- SpellScript* GetSpellScript() const override
+ AuraScript* GetAuraScript() const override
{
- return new spell_cultist_dark_martyrdom_SpellScript();
+ return new spell_deathwhisper_dominated_mind_AuraScript();
}
};
-class at_lady_deathwhisper_entrance : public AreaTriggerScript
+class spell_deathwhisper_summon_spirits : public SpellScriptLoader
{
public:
- at_lady_deathwhisper_entrance() : AreaTriggerScript("at_lady_deathwhisper_entrance") { }
+ spell_deathwhisper_summon_spirits() : SpellScriptLoader("spell_deathwhisper_summon_spirits") { }
- bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
+ class spell_deathwhisper_summon_spirits_SpellScript : public SpellScript
{
- if (InstanceScript* instance = player->GetInstanceScript())
- if (instance->GetBossState(DATA_LADY_DEATHWHISPER) != DONE)
- if (Creature* ladyDeathwhisper = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_LADY_DEATHWHISPER)))
- ladyDeathwhisper->AI()->DoAction(ACTION_START_INTRO);
+ PrepareSpellScript(spell_deathwhisper_summon_spirits_SpellScript);
- return true;
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_SHADE))
+ return false;
+ return true;
+ }
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->CastSpell(GetHitUnit(), SPELL_SUMMON_SHADE, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_deathwhisper_summon_spirits_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_deathwhisper_summon_spirits_SpellScript();
}
};
@@ -1068,6 +1093,7 @@ void AddSC_boss_lady_deathwhisper()
new npc_vengeful_shade();
new npc_darnavan();
new spell_deathwhisper_mana_barrier();
- new spell_cultist_dark_martyrdom();
+ new spell_deathwhisper_dominated_mind();
+ new spell_deathwhisper_summon_spirits();
new at_lady_deathwhisper_entrance();
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
index 376cadd18d9..15e4885d4a7 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
@@ -838,9 +838,23 @@ class spell_putricide_gaseous_bloat : public SpellScriptLoader
}
}
+ void HandleProc(ProcEventInfo& eventInfo)
+ {
+ uint32 stack = GetStackAmount();
+ Unit* caster = eventInfo.GetActor();
+
+ int32 const mod = caster->GetMap()->Is25ManRaid() ? 1500 : 1250;
+ int32 dmg = 0;
+ for (uint8 i = 1; i <= stack; ++i)
+ dmg += mod * i;
+
+ caster->CastCustomSpell(SPELL_EXPUNGED_GAS, SPELLVALUE_BASE_POINT0, dmg);
+ }
+
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_putricide_gaseous_bloat_AuraScript::HandleExtraEffect, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
+ OnProc += AuraProcFn(spell_putricide_gaseous_bloat_AuraScript::HandleProc);
}
};
@@ -1078,6 +1092,45 @@ class spell_putricide_ooze_eruption_searcher : public SpellScriptLoader
}
};
+// 71770 - Ooze Spell Tank Protection
+class spell_putricide_ooze_tank_protection : public SpellScriptLoader
+{
+ public:
+ spell_putricide_ooze_tank_protection() : SpellScriptLoader("spell_putricide_ooze_tank_protection") { }
+
+ class spell_putricide_ooze_tank_protection_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_putricide_ooze_tank_protection_AuraScript);
+
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell) ||
+ !sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_1].TriggerSpell))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* actionTarget = eventInfo.GetActionTarget();
+ actionTarget->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_putricide_ooze_tank_protection_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ OnEffectProc += AuraEffectProcFn(spell_putricide_ooze_tank_protection_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_putricide_ooze_tank_protection_AuraScript();
+ }
+};
+
class spell_putricide_choking_gas_bomb : public SpellScriptLoader
{
public:
@@ -1602,6 +1655,7 @@ void AddSC_boss_professor_putricide()
new spell_putricide_slime_puddle_aura();
new spell_putricide_unstable_experiment();
new spell_putricide_ooze_eruption_searcher();
+ new spell_putricide_ooze_tank_protection();
new spell_putricide_choking_gas_bomb();
new spell_putricide_unbound_plague();
new spell_putricide_eat_ooze();
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
index a2348119dff..f3021cdbab5 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
@@ -1099,6 +1099,12 @@ class spell_sindragosa_s_fury : public SpellScriptLoader
if (!GetHitUnit()->IsAlive() || !_targetCount)
return;
+ if (GetHitUnit()->IsImmunedToDamage(GetSpellInfo()))
+ {
+ GetCaster()->SendSpellDamageImmune(GetHitUnit(), GetSpellInfo()->Id);
+ return;
+ }
+
float resistance = float(GetHitUnit()->GetResistance(SpellSchoolMask(GetSpellInfo()->SchoolMask)));
uint32 minResistFactor = uint32((resistance / (resistance + 510.0f)) * 10.0f) * 2;
uint32 randomResist = urand(0, (9 - minResistFactor) * 100) / 100 + minResistFactor;
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
index b618cb9ce2d..44f300e1efa 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
@@ -2991,8 +2991,12 @@ class spell_the_lich_king_dark_hunger : public SpellScriptLoader
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- int32 heal = int32(eventInfo.GetDamageInfo()->GetDamage() / 2);
- GetTarget()->CastCustomSpell(SPELL_DARK_HUNGER_HEAL, SPELLVALUE_BASE_POINT0, heal, GetTarget(), true, NULL, aurEff);
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 heal = static_cast<int32>(damageInfo->GetDamage()) / 2;
+ GetTarget()->CastCustomSpell(SPELL_DARK_HUNGER_HEAL, SPELLVALUE_BASE_POINT0, heal, GetTarget(), true, nullptr, aurEff);
}
void Register() override
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp
index fb8fddeb7db..43ef3bd1eac 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp
@@ -1189,7 +1189,8 @@ class npc_crok_scourgebane : public CreatureScript
}
else
{
- me->DealHeal(me, me->CountPctFromMaxHealth(5));
+ // looks totally hacky to me
+ me->ModifyHealth(me->CountPctFromMaxHealth(5));
_events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000);
}
break;
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
index 684e5866386..575c498ead3 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
@@ -639,7 +639,7 @@ class instance_icecrown_citadel : public InstanceMapScript
case GO_CACHE_OF_THE_DREAMWALKER_10H:
case GO_CACHE_OF_THE_DREAMWALKER_25H:
if (Creature* valithria = instance->GetCreature(ValithriaDreamwalkerGUID))
- go->SetLootRecipient(valithria->GetLootRecipient());
+ go->SetLootRecipient(valithria->GetLootRecipient(), valithria->GetLootRecipientGroup());
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE | GO_FLAG_NODESPAWN);
break;
case GO_ARTHAS_PLATFORM:
@@ -875,7 +875,7 @@ class instance_icecrown_citadel : public InstanceMapScript
if (GameObject* loot = instance->GetGameObject(DeathbringersCacheGUID))
{
if (Creature* deathbringer = instance->GetCreature(DeathbringerSaurfangGUID))
- loot->SetLootRecipient(deathbringer->GetLootRecipient());
+ loot->SetLootRecipient(deathbringer->GetLootRecipient(), deathbringer->GetLootRecipientGroup());
loot->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE | GO_FLAG_NODESPAWN);
}
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp
index ac69f422d5f..c34b3be99ea 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp
@@ -580,7 +580,7 @@ static const float MINION_AGGRO_DISTANCE = 20.0f;
struct npc_kelthuzad_minionAI : public ScriptedAI
{
public:
- npc_kelthuzad_minionAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()), _movementTimer(urandms(4,12)), _home(me->GetPosition()) { }
+ npc_kelthuzad_minionAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()), pocketId(0), _movementTimer(urandms(4,12)), _home(me->GetPosition()) { }
void Reset() override
{
@@ -602,6 +602,9 @@ struct npc_kelthuzad_minionAI : public ScriptedAI
return;
}
+ if (!pocketId)
+ return;
+
std::list<Creature*> others;
me->GetCreatureListWithEntryInGrid(others, me->GetEntry(), 80.0f);
for (Creature* other : others)
diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
index 326a2de43a3..ecf7ec2beb2 100644
--- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
+++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
@@ -2037,11 +2037,7 @@ class spell_scion_of_eternity_arcane_barrage : public SpellScriptLoader
void TriggerDamageSpellFromPlayer()
{
if (Player* hitTarget = GetHitPlayer())
- {
- // There is some proc in this spell I have absolutely no idea of use, but just in case...
- TriggerCastFlags triggerFlags = TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_DISALLOW_PROC_EVENTS);
- hitTarget->CastSpell(hitTarget, SPELL_ARCANE_BARRAGE_DAMAGE, triggerFlags, NULL, NULL, GetCaster()->GetGUID());
- }
+ hitTarget->CastSpell(hitTarget, SPELL_ARCANE_BARRAGE_DAMAGE, true, nullptr, nullptr, GetCaster()->GetGUID());
}
void Register() override
diff --git a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp
index 3d9ea97b136..b06bc9e872f 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp
+++ b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp
@@ -604,8 +604,11 @@ class spell_oculus_temporal_rift : public SpellScriptLoader
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- int32 amount = aurEff->GetAmount() + eventInfo.GetDamageInfo()->GetDamage();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+ int32 amount = aurEff->GetAmount() + damageInfo->GetDamage();
if (amount >= 15000)
{
if (Unit* caster = GetCaster())
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp
index 41dcfa5da93..e044e9dbb9c 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp
@@ -1063,6 +1063,51 @@ class spell_xt002_submerged : public SpellScriptLoader
}
};
+class spell_xt002_321_boombot_aura : public SpellScriptLoader
+{
+ public:
+ spell_xt002_321_boombot_aura() : SpellScriptLoader("spell_xt002_321_boombot_aura") { }
+
+ class spell_xt002_321_boombot_aura_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_xt002_321_boombot_aura_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_ACHIEVEMENT_CREDIT_NERF_SCRAPBOTS))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (eventInfo.GetActionTarget()->GetEntry() != NPC_XS013_SCRAPBOT)
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ InstanceScript* instance = eventInfo.GetActor()->GetInstanceScript();
+ if (!instance)
+ return;
+
+ instance->DoCastSpellOnPlayers(SPELL_ACHIEVEMENT_CREDIT_NERF_SCRAPBOTS);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_xt002_321_boombot_aura_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_xt002_321_boombot_aura_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_xt002_321_boombot_aura_AuraScript();
+ }
+};
+
class achievement_nerf_engineering : public AchievementCriteriaScript
{
public:
@@ -1122,6 +1167,7 @@ void AddSC_boss_xt002()
new spell_xt002_heart_overload_periodic();
new spell_xt002_tympanic_tantrum();
new spell_xt002_submerged();
+ new spell_xt002_321_boombot_aura();
new achievement_nerf_engineering();
new achievement_heartbreaker();
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 675268b4e93..70d9fc90cb9 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
@@ -2750,8 +2750,13 @@ class spell_yogg_saron_grim_reprisal : public SpellScriptLoader // 63305
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
- int32 damage = CalculatePct(int32(eventInfo.GetDamageInfo()->GetDamage()), 60);
- GetTarget()->CastCustomSpell(SPELL_GRIM_REPRISAL_DAMAGE, SPELLVALUE_BASE_POINT0, damage, eventInfo.GetDamageInfo()->GetAttacker(), true, NULL, aurEff);
+ PreventDefaultAction();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 damage = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), 60);
+ GetTarget()->CastCustomSpell(SPELL_GRIM_REPRISAL_DAMAGE, SPELLVALUE_BASE_POINT0, damage, damageInfo->GetAttacker(), true, nullptr, aurEff);
}
void Register() override
diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp
index cff5b93d7a2..e159902c3c8 100644
--- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp
+++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp
@@ -456,7 +456,11 @@ class spell_ingvar_woe_strike : public SpellScriptLoader
bool CheckProc(ProcEventInfo& eventInfo)
{
- return eventInfo.GetHealInfo()->GetHeal() != 0;
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return false;
+
+ return true;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp
index 6c9f7e215e6..82abb2836ba 100644
--- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp
+++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp
@@ -191,6 +191,57 @@ class spell_fixate : public SpellScriptLoader
}
};
+enum SecondWind
+{
+ SPELL_SECOND_WIND_TRIGGER = 42771
+};
+
+// 42770 - Second Wind
+class spell_uk_second_wind : public SpellScriptLoader
+{
+ public:
+ spell_uk_second_wind() : SpellScriptLoader("spell_uk_second_wind") { }
+
+ class spell_uk_second_wind_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_uk_second_wind_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SECOND_WIND_TRIGGER))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return false;
+
+ return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN))) != 0;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActionTarget();
+ caster->CastSpell(caster, SPELL_SECOND_WIND_TRIGGER, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_uk_second_wind_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_uk_second_wind_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_uk_second_wind_AuraScript();
+ }
+};
+
enum EnslavedProtoDrake
{
TYPE_PROTODRAKE_AT = 28,
@@ -301,4 +352,5 @@ void AddSC_utgarde_keep()
new npc_enslaved_proto_drake();
new spell_ticking_time_bomb();
new spell_fixate();
+ new spell_uk_second_wind();
}
diff --git a/src/server/scripts/Northrend/zone_dragonblight.cpp b/src/server/scripts/Northrend/zone_dragonblight.cpp
index c22cd2d9ad7..cb5a7462000 100644
--- a/src/server/scripts/Northrend/zone_dragonblight.cpp
+++ b/src/server/scripts/Northrend/zone_dragonblight.cpp
@@ -701,6 +701,31 @@ class npc_torturer_lecraft : public CreatureScript
}
};
+enum MessengerTorvus
+{
+ NPC_MESSENGER_TORVUS = 26649,
+ QUEST_MESSAGE_FROM_THE_WEST = 12033,
+
+ TALK_0 = 0
+};
+
+class at_nearby_messenger_torvus : public AreaTriggerScript
+{
+public:
+ at_nearby_messenger_torvus() : AreaTriggerScript("at_nearby_messenger_torvus") { }
+
+ bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/) override
+ {
+ if (player->IsAlive())
+ if (Quest const* quest = sObjectMgr->GetQuestTemplate(QUEST_MESSAGE_FROM_THE_WEST))
+ if (player->CanTakeQuest(quest, false))
+ if (Creature* creature = player->FindNearestCreature(NPC_MESSENGER_TORVUS, 50.0f, true))
+ creature->AI()->Talk(TALK_0, player);
+
+ return true;
+ }
+};
+
void AddSC_dragonblight()
{
new npc_commander_eligor_dawnbringer();
@@ -708,4 +733,5 @@ void AddSC_dragonblight()
new spell_q12096_q12092_bark();
new npc_wyrmrest_defender();
new npc_torturer_lecraft();
+ new at_nearby_messenger_torvus();
}
diff --git a/src/server/scripts/Northrend/zone_howling_fjord.cpp b/src/server/scripts/Northrend/zone_howling_fjord.cpp
index 0b38338ab7b..1bbf5adcb3d 100644
--- a/src/server/scripts/Northrend/zone_howling_fjord.cpp
+++ b/src/server/scripts/Northrend/zone_howling_fjord.cpp
@@ -40,13 +40,38 @@ EndContentData */
######*/
enum Entries
{
- NPC_APOTHECARY_HANES = 23784,
- FACTION_ESCORTEE_A = 774,
- FACTION_ESCORTEE_H = 775,
- NPC_HANES_FIRE_TRIGGER = 23968,
- QUEST_TRAIL_OF_FIRE = 11241,
- SPELL_COSMETIC_LOW_POLY_FIRE = 56274,
- SPELL_HEALING_POTION = 17534
+ NPC_APOTHECARY_HANES = 23784,
+ FACTION_ESCORTEE_H = 775,
+ QUEST_TRAIL_OF_FIRE = 11241,
+
+ SPELL_HEALING_POTION = 17534,
+ SPELL_BURN = 42685,
+
+ EVENT_EMOTE_BEG = 1,
+ EVENT_BEGIN = 2,
+ EVENT_START_ESCORT = 3,
+ EVENT_TALK_1 = 4,
+ EVENT_KNEEL = 5,
+ EVENT_TALK_2 = 6,
+ EVENT_BURN_CRATES = 7,
+ EVENT_TALK_3 = 8,
+ EVENT_TALK_4 = 9,
+ EVENT_LAUGH = 10,
+ EVENT_TALK_5 = 11,
+ EVENT_TALK_6 = 12,
+ EVENT_TALK_8 = 13,
+
+ TALK_0 = 0,
+ TALK_1 = 1,
+ TALK_2 = 2,
+ TALK_3 = 3,
+ TALK_4 = 4,
+ TALK_5 = 5,
+ TALK_6 = 6,
+ TALK_7 = 7,
+ TALK_8 = 8,
+
+ EQUIP_TORCH = 2
};
class npc_apothecary_hanes : public CreatureScript
@@ -58,16 +83,7 @@ public:
{
if (quest->GetQuestId() == QUEST_TRAIL_OF_FIRE)
{
- switch (player->GetTeam())
- {
- case ALLIANCE:
- creature->setFaction(FACTION_ESCORTEE_A);
- break;
- case HORDE:
- creature->setFaction(FACTION_ESCORTEE_H);
- break;
- }
- ENSURE_AI(npc_escortAI, (creature->AI()))->Start(true, false, player->GetGUID());
+ ENSURE_AI(npc_Apothecary_HanesAI, (creature->AI()))->StartEscort(player);
}
return true;
}
@@ -79,12 +95,25 @@ public:
Initialize();
}
+ void StartEscort(Player* player)
+ {
+ events.ScheduleEvent(EVENT_BEGIN, Seconds(2));
+ events.ScheduleEvent(EVENT_START_ESCORT, Seconds(6));
+ _player = player->GetGUID();
+ }
+
void Initialize()
{
PotTimer = 10000; //10 sec cooldown on potion
+ events.Reset();
+ events.ScheduleEvent(EVENT_EMOTE_BEG, Seconds(2));
+ me->SetStandState(UNIT_STAND_STATE_KNEEL);
+ _player = ObjectGuid();
}
uint32 PotTimer;
+ EventMap events;
+ ObjectGuid _player;
void Reset() override
{
@@ -98,7 +127,7 @@ public:
player->FailQuest(QUEST_TRAIL_OF_FIRE);
}
- void UpdateEscortAI(uint32 diff) override
+ void UpdateAI(uint32 diff) override
{
if (HealthBelowPct(75))
{
@@ -108,8 +137,77 @@ public:
PotTimer = 10000;
} else PotTimer -= diff;
}
+
if (GetAttack() && UpdateVictim())
DoMeleeAttackIfReady();
+
+ npc_escortAI::UpdateAI(diff);
+
+ if (me->IsInCombat())
+ return;
+
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_EMOTE_BEG:
+ me->HandleEmoteCommand(EMOTE_ONESHOT_BEG);
+ events.ScheduleEvent(EVENT_EMOTE_BEG, Seconds(25));
+ break;
+ case EVENT_BEGIN:
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _player))
+ Talk(TALK_0, player);
+ break;
+ case EVENT_START_ESCORT:
+ events.Reset();
+ me->setFaction(FACTION_ESCORTEE_H);
+ me->SetReactState(REACT_AGGRESSIVE);
+ ENSURE_AI(npc_escortAI, (me->AI()))->Start(true, true, _player);
+ break;
+ case EVENT_TALK_1:
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _player))
+ Talk(TALK_1, player);
+ break;
+ case EVENT_KNEEL:
+ me->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL);
+ break;
+ case EVENT_TALK_2:
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _player))
+ Talk(TALK_2, player);
+ me->LoadEquipment(EQUIP_TORCH);
+ me->SetSheath(SHEATH_STATE_MELEE);
+ break;
+ case EVENT_BURN_CRATES:
+ DoCastAOE(SPELL_BURN, true);
+ break;
+ case EVENT_TALK_3:
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _player))
+ Talk(TALK_3, player);
+ break;
+ case EVENT_TALK_4:
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _player))
+ Talk(TALK_4, player);
+ break;
+ case EVENT_LAUGH:
+ me->HandleEmoteCommand(EMOTE_ONESHOT_LAUGH);
+ break;
+ case EVENT_TALK_5:
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _player))
+ Talk(TALK_5, player);
+ me->HandleEmoteCommand(EMOTE_ONESHOT_RUDE);
+ break;
+ case EVENT_TALK_6:
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _player))
+ Talk(TALK_6, player);
+ break;
+ case EVENT_TALK_8:
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _player))
+ Talk(TALK_8, player);
+ break;
+ }
+ }
}
void WaypointReached(uint32 waypointId) override
@@ -121,42 +219,36 @@ public:
switch (waypointId)
{
case 1:
- me->SetReactState(REACT_AGGRESSIVE);
- SetRun(true);
- break;
- case 23:
- player->GroupEventHappens(QUEST_TRAIL_OF_FIRE, me);
- me->DespawnOrUnsummon();
- break;
- case 5:
- if (Unit* Trigger = me->FindNearestCreature(NPC_HANES_FIRE_TRIGGER, 10.0f))
- Trigger->CastSpell(Trigger, SPELL_COSMETIC_LOW_POLY_FIRE, false);
- SetRun(false);
+ events.ScheduleEvent(EVENT_TALK_1, Seconds(3));
+ events.ScheduleEvent(EVENT_KNEEL, Seconds(5));
+ events.ScheduleEvent(EVENT_TALK_2, Seconds(6));
+ me->SetStandState(UNIT_STAND_STATE_STAND);
break;
- case 6:
- if (Unit* Trigger = me->FindNearestCreature(NPC_HANES_FIRE_TRIGGER, 10.0f))
- Trigger->CastSpell(Trigger, SPELL_COSMETIC_LOW_POLY_FIRE, false);
- SetRun(true);
+ case 12:
+ events.ScheduleEvent(EVENT_BURN_CRATES, Seconds(1));
+ events.ScheduleEvent(EVENT_TALK_3, Seconds(3));
break;
- case 8:
- if (Unit* Trigger = me->FindNearestCreature(NPC_HANES_FIRE_TRIGGER, 10.0f))
- Trigger->CastSpell(Trigger, SPELL_COSMETIC_LOW_POLY_FIRE, false);
- SetRun(false);
+ case 20:
+ events.ScheduleEvent(EVENT_BURN_CRATES, 0);
break;
- case 9:
- if (Unit* Trigger = me->FindNearestCreature(NPC_HANES_FIRE_TRIGGER, 10.0f))
- Trigger->CastSpell(Trigger, SPELL_COSMETIC_LOW_POLY_FIRE, false);
+ case 21:
+ events.ScheduleEvent(EVENT_BURN_CRATES, 0);
+ events.ScheduleEvent(EVENT_TALK_4, Seconds(3));
break;
- case 10:
- SetRun(true);
+ case 28:
+ events.ScheduleEvent(EVENT_BURN_CRATES, 0);
+ events.ScheduleEvent(EVENT_LAUGH, Seconds(7));
+ events.ScheduleEvent(EVENT_TALK_5, Seconds(9));
+ events.ScheduleEvent(EVENT_TALK_6, Seconds(17));
break;
- case 13:
- SetRun(false);
+ case 35:
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _player))
+ Talk(TALK_7, player);
break;
- case 14:
- if (Unit* Trigger = me->FindNearestCreature(NPC_HANES_FIRE_TRIGGER, 10.0f))
- Trigger->CastSpell(Trigger, SPELL_COSMETIC_LOW_POLY_FIRE, false);
- SetRun(true);
+ case 40:
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _player))
+ player->GroupEventHappens(QUEST_TRAIL_OF_FIRE, me);
+ events.ScheduleEvent(EVENT_TALK_8, Seconds(4));
break;
}
}
diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp
index 2effc1d9a2a..54ae9c27aeb 100644
--- a/src/server/scripts/Northrend/zone_storm_peaks.cpp
+++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp
@@ -281,6 +281,7 @@ public:
void UpdateAI(uint32 diff) override
{
+ VehicleAI::UpdateAI(diff);
events.Update(diff);
switch (events.ExecuteEvent())
diff --git a/src/server/scripts/Northrend/zone_wintergrasp.cpp b/src/server/scripts/Northrend/zone_wintergrasp.cpp
index 781b784b3d8..e45b1f42fa1 100644
--- a/src/server/scripts/Northrend/zone_wintergrasp.cpp
+++ b/src/server/scripts/Northrend/zone_wintergrasp.cpp
@@ -247,39 +247,39 @@ class npc_wg_queue : public CreatureScript
public:
npc_wg_queue() : CreatureScript("npc_wg_queue") { }
- struct npc_wg_queueAI : public ScriptedAI
- {
- npc_wg_queueAI(Creature* creature) : ScriptedAI(creature)
+ struct npc_wg_queueAI : public ScriptedAI
{
- FrostArmor_Timer = 0;
- }
+ npc_wg_queueAI(Creature* creature) : ScriptedAI(creature)
+ {
+ FrostArmor_Timer = 0;
+ }
- uint32 FrostArmor_Timer;
+ uint32 FrostArmor_Timer;
- void Reset() override
- {
- FrostArmor_Timer = 0;
- }
+ void Reset() override
+ {
+ FrostArmor_Timer = 0;
+ }
- void EnterCombat(Unit* /*who*/) override { }
+ void EnterCombat(Unit* /*who*/) override { }
- void UpdateAI(uint32 diff) override
- {
- if (FrostArmor_Timer <= diff)
+ void UpdateAI(uint32 diff) override
{
- DoCast(me, SPELL_FROST_ARMOR);
- FrostArmor_Timer = 180000;
+ if (FrostArmor_Timer <= diff)
+ {
+ DoCast(me, SPELL_FROST_ARMOR);
+ FrostArmor_Timer = 180000;
+ }
+ else FrostArmor_Timer -= diff;
+
+ DoMeleeAttackIfReady();
}
- else FrostArmor_Timer -= diff;
+ };
- DoMeleeAttackIfReady();
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_wg_queueAI(creature);
}
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_wg_queueAI(creature);
- }
bool OnGossipHello(Player* player, Creature* creature) override
{
@@ -337,25 +337,39 @@ class go_wg_vehicle_teleporter : public GameObjectScript
struct go_wg_vehicle_teleporterAI : public GameObjectAI
{
- go_wg_vehicle_teleporterAI(GameObject* gameObject) : GameObjectAI(gameObject), _checkTimer(1000) { }
+ go_wg_vehicle_teleporterAI(GameObject* gameObject) : GameObjectAI(gameObject), _checkTimer(0) { }
- void UpdateAI(uint32 diff) override
+ bool IsFriendly(Unit* passenger)
+ {
+ return ((go->GetUInt32Value(GAMEOBJECT_FACTION) == WintergraspFaction[TEAM_HORDE] && passenger->getFaction() == HORDE) ||
+ (go->GetUInt32Value(GAMEOBJECT_FACTION) == WintergraspFaction[TEAM_ALLIANCE] && passenger->getFaction() == ALLIANCE));
+ }
+
+ Creature* GetValidVehicle(Creature* cVeh)
+ {
+ if (!cVeh->HasAura(SPELL_VEHICLE_TELEPORT))
+ if (Vehicle* vehicle = cVeh->GetVehicleKit())
+ if (Unit* passenger = vehicle->GetPassenger(0))
+ if (IsFriendly(passenger))
+ if (Creature* teleportTrigger = passenger->SummonTrigger(go->GetPositionX()-60.0f, go->GetPositionY(), go->GetPositionZ()+1.0f, cVeh->GetOrientation(), 1000))
+ return teleportTrigger;
+
+ return nullptr;
+ }
+
+ void UpdateAI(uint32 diff)
{
- if (_checkTimer <= diff)
+ _checkTimer += diff;
+ if (_checkTimer >= 1000)
{
- if (Battlefield* wg = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG))
- // Tabulation madness in the hole!
- for (uint8 i = 0; i < MAX_WINTERGRASP_VEHICLES; i++)
- if (Creature* vehicleCreature = go->FindNearestCreature(vehiclesList[i], 3.0f, true))
- if (!vehicleCreature->HasAura(SPELL_VEHICLE_TELEPORT) && vehicleCreature->getFaction() == WintergraspFaction[wg->GetDefenderTeam()])
- if (Creature* teleportTrigger = vehicleCreature->FindNearestCreature(NPC_WORLD_TRIGGER_LARGE_AOI_NOT_IMMUNE_PC_NPC, 100.0f, true))
- teleportTrigger->CastSpell(vehicleCreature, SPELL_VEHICLE_TELEPORT, true);
-
- _checkTimer = 1000;
+ for (uint8 i = 0; i < MAX_WINTERGRASP_VEHICLES; i++)
+ if (Creature* vehicleCreature = go->FindNearestCreature(vehiclesList[i], 3.0f, true))
+ if (Creature* teleportTrigger = GetValidVehicle(vehicleCreature))
+ teleportTrigger->CastSpell(vehicleCreature, SPELL_VEHICLE_TELEPORT, true);
+
+ _checkTimer = 0;
}
- else _checkTimer -= diff;
}
-
private:
uint32 _checkTimer;
};
@@ -366,111 +380,31 @@ class go_wg_vehicle_teleporter : public GameObjectScript
}
};
-class npc_wg_quest_giver : public CreatureScript
+class npc_wg_give_promotion_credit : public CreatureScript
{
public:
- npc_wg_quest_giver() : CreatureScript("npc_wg_quest_giver") { }
+ npc_wg_give_promotion_credit() : CreatureScript("npc_wg_give_promotion_credit") { }
- bool OnGossipHello(Player* player, Creature* creature) override
+ struct npc_wg_give_promotion_creditAI : public ScriptedAI
{
- Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG);
- if (!wintergrasp)
- return true;
-
- if (creature->IsVendor())
- {
- AddGossipItemFor(player, Player::GetDefaultGossipMenuForSource(creature), 0, GOSSIP_SENDER_MAIN, GOSSIP_OPTION_VENDOR);
- player->PlayerTalkClass->GetGossipMenu().AddGossipMenuItemData(0, 0, 0);
- }
-
- /// @todo: move this to conditions or something else
+ npc_wg_give_promotion_creditAI(Creature* creature) : ScriptedAI(creature) { }
- // Player::PrepareQuestMenu(guid)
- if (creature->IsQuestGiver())
+ void JustDied(Unit* killer) override
{
- QuestRelationBounds objectQR = sObjectMgr->GetCreatureQuestRelationBounds(creature->GetEntry());
- QuestRelationBounds objectQIR = sObjectMgr->GetCreatureQuestInvolvedRelationBounds(creature->GetEntry());
-
- QuestMenu& qm = player->PlayerTalkClass->GetQuestMenu();
- qm.ClearMenu();
+ if (killer->GetTypeId() != TYPEID_PLAYER)
+ return;
- for (QuestRelations::const_iterator i = objectQIR.first; i != objectQIR.second; ++i)
- {
- uint32 questId = i->second;
- QuestStatus status = player->GetQuestStatus(questId);
- if (status == QUEST_STATUS_COMPLETE)
- qm.AddMenuItem(questId, 4);
- else if (status == QUEST_STATUS_INCOMPLETE)
- qm.AddMenuItem(questId, 4);
- //else if (status == QUEST_STATUS_AVAILABLE)
- // qm.AddMenuItem(quest_id, 2);
- }
+ BattlefieldWG* wintergrasp = static_cast<BattlefieldWG*>(sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG));
+ if (!wintergrasp)
+ return;
- for (QuestRelations::const_iterator i = objectQR.first; i != objectQR.second; ++i)
- {
- uint32 questId = i->second;
- Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
- if (!quest)
- continue;
-
- if (!player->CanTakeQuest(quest, false))
- continue;
-
- switch (questId)
- {
- // Horde attacker
- case QUEST_BONES_AND_ARROWS_HORDE_ATT:
- case QUEST_JINXING_THE_WALLS_HORDE_ATT:
- case QUEST_SLAY_THEM_ALL_HORDE_ATT:
- case QUEST_FUELING_THE_DEMOLISHERS_HORDE_ATT:
- case QUEST_HEALING_WITH_ROSES_HORDE_ATT:
- case QUEST_DEFEND_THE_SIEGE_HORDE_ATT:
- if (wintergrasp->GetAttackerTeam() != TEAM_HORDE)
- continue;
- break;
- // Horde defender
- case QUEST_BONES_AND_ARROWS_HORDE_DEF:
- case QUEST_WARDING_THE_WALLS_HORDE_DEF:
- case QUEST_SLAY_THEM_ALL_HORDE_DEF:
- case QUEST_FUELING_THE_DEMOLISHERS_HORDE_DEF:
- case QUEST_HEALING_WITH_ROSES_HORDE_DEF:
- case QUEST_TOPPLING_THE_TOWERS_HORDE_DEF:
- case QUEST_STOP_THE_SIEGE_HORDE_DEF:
- if (wintergrasp->GetDefenderTeam() != TEAM_HORDE)
- continue;
- break;
- // Alliance attacker
- case QUEST_BONES_AND_ARROWS_ALLIANCE_ATT:
- case QUEST_WARDING_THE_WARRIORS_ALLIANCE_ATT:
- case QUEST_NO_MERCY_FOR_THE_MERCILESS_ALLIANCE_ATT:
- case QUEST_DEFEND_THE_SIEGE_ALLIANCE_ATT:
- case QUEST_A_RARE_HERB_ALLIANCE_ATT:
- if (wintergrasp->GetAttackerTeam() != TEAM_ALLIANCE)
- continue;
- break;
- // Alliance defender
- case QUEST_BONES_AND_ARROWS_ALLIANCE_DEF:
- case QUEST_WARDING_THE_WARRIORS_ALLIANCE_DEF:
- case QUEST_NO_MERCY_FOR_THE_MERCILESS_ALLIANCE_DEF:
- case QUEST_SHOUTHERN_SABOTAGE_ALLIANCE_DEF:
- case QUEST_STOP_THE_SIEGE_ALLIANCE_DEF:
- case QUEST_A_RARE_HERB_ALLIANCE_DEF:
- if (wintergrasp->GetDefenderTeam() != TEAM_ALLIANCE)
- continue;
- break;
- default:
- break;
- }
-
- if (quest->IsAutoComplete())
- qm.AddMenuItem(questId, 4);
- else if (player->GetQuestStatus(questId) == QUEST_STATUS_NONE)
- qm.AddMenuItem(questId, 2);
- }
+ wintergrasp->HandlePromotion(killer->ToPlayer(), me);
}
+ };
- SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
- return true;
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_wg_give_promotion_creditAI(creature);
}
};
@@ -540,26 +474,26 @@ class spell_wintergrasp_grab_passenger : public SpellScriptLoader
class achievement_wg_didnt_stand_a_chance : public AchievementCriteriaScript
{
-public:
- achievement_wg_didnt_stand_a_chance() : AchievementCriteriaScript("achievement_wg_didnt_stand_a_chance") { }
-
- bool OnCheck(Player* source, Unit* target) override
- {
- if (!target)
- return false;
+ public:
+ achievement_wg_didnt_stand_a_chance() : AchievementCriteriaScript("achievement_wg_didnt_stand_a_chance") { }
- if (Player* victim = target->ToPlayer())
+ bool OnCheck(Player* source, Unit* target) override
{
- if (!victim->IsMounted())
+ if (!target)
return false;
- if (Vehicle* vehicle = source->GetVehicle())
- if (vehicle->GetVehicleInfo()->m_ID == 244) // Wintergrasp Tower Cannon
- return true;
- }
+ if (Player* victim = target->ToPlayer())
+ {
+ if (!victim->IsMounted())
+ return false;
+
+ if (Vehicle* vehicle = source->GetVehicle())
+ if (vehicle->GetVehicleInfo()->m_ID == 244) // Wintergrasp Tower Cannon
+ return true;
+ }
- return false;
- }
+ return false;
+ }
};
enum WgTeleport
@@ -569,63 +503,91 @@ enum WgTeleport
class spell_wintergrasp_defender_teleport : public SpellScriptLoader
{
-public:
- spell_wintergrasp_defender_teleport() : SpellScriptLoader("spell_wintergrasp_defender_teleport") { }
-
- class spell_wintergrasp_defender_teleport_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_wintergrasp_defender_teleport_SpellScript);
+ public:
+ spell_wintergrasp_defender_teleport() : SpellScriptLoader("spell_wintergrasp_defender_teleport") { }
- SpellCastResult CheckCast()
+ class spell_wintergrasp_defender_teleport_SpellScript : public SpellScript
{
- if (Battlefield* wg = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG))
- if (Player* target = GetExplTargetUnit()->ToPlayer())
- // check if we are in Wintergrasp at all, SotA uses same teleport spells
- if ((target->GetZoneId() == 4197 && target->GetTeamId() != wg->GetDefenderTeam()) || target->HasAura(SPELL_WINTERGRASP_TELEPORT_TRIGGER))
- return SPELL_FAILED_BAD_TARGETS;
- return SPELL_CAST_OK;
- }
+ PrepareSpellScript(spell_wintergrasp_defender_teleport_SpellScript);
+
+ SpellCastResult CheckCast()
+ {
+ if (Battlefield* wg = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG))
+ if (Player* target = GetExplTargetUnit()->ToPlayer())
+ // check if we are in Wintergrasp at all, SotA uses same teleport spells
+ if ((target->GetZoneId() == 4197 && target->GetTeamId() != wg->GetDefenderTeam()) || target->HasAura(SPELL_WINTERGRASP_TELEPORT_TRIGGER))
+ return SPELL_FAILED_BAD_TARGETS;
+ return SPELL_CAST_OK;
+ }
- void Register() override
+ void Register() override
+ {
+ OnCheckCast += SpellCheckCastFn(spell_wintergrasp_defender_teleport_SpellScript::CheckCast);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
{
- OnCheckCast += SpellCheckCastFn(spell_wintergrasp_defender_teleport_SpellScript::CheckCast);
+ return new spell_wintergrasp_defender_teleport_SpellScript();
}
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_wintergrasp_defender_teleport_SpellScript();
- }
};
class spell_wintergrasp_defender_teleport_trigger : public SpellScriptLoader
{
-public:
- spell_wintergrasp_defender_teleport_trigger() : SpellScriptLoader("spell_wintergrasp_defender_teleport_trigger") { }
-
- class spell_wintergrasp_defender_teleport_trigger_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_wintergrasp_defender_teleport_trigger_SpellScript);
+ public:
+ spell_wintergrasp_defender_teleport_trigger() : SpellScriptLoader("spell_wintergrasp_defender_teleport_trigger") { }
- void HandleDummy(SpellEffIndex /*effindex*/)
+ class spell_wintergrasp_defender_teleport_trigger_SpellScript : public SpellScript
{
- if (Unit* target = GetHitUnit())
+ PrepareSpellScript(spell_wintergrasp_defender_teleport_trigger_SpellScript);
+
+ void HandleDummy(SpellEffIndex /*effindex*/)
+ {
+ if (Unit* target = GetHitUnit())
+ {
+ WorldLocation loc = target->GetWorldLocation();
+ SetExplTargetDest(loc);
+ }
+ }
+
+ void Register() override
{
- WorldLocation loc = target->GetWorldLocation();
- SetExplTargetDest(loc);
+ OnEffectHitTarget += SpellEffectFn(spell_wintergrasp_defender_teleport_trigger_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_wintergrasp_defender_teleport_trigger_SpellScript();
}
+};
+
+class condition_is_wintergrasp_horde : public ConditionScript
+{
+ public:
+ condition_is_wintergrasp_horde() : ConditionScript("condition_is_wintergrasp_horde") { }
- void Register() override
+ bool OnConditionCheck(Condition const* /* condition */, ConditionSourceInfo& /* sourceInfo */)
{
- OnEffectHitTarget += SpellEffectFn(spell_wintergrasp_defender_teleport_trigger_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG);
+ if (wintergrasp && wintergrasp->IsEnabled() && wintergrasp->GetDefenderTeam() == TEAM_HORDE)
+ return true;
+ return false;
}
- };
+};
+
+class condition_is_wintergrasp_alliance : public ConditionScript
+{
+ public:
+ condition_is_wintergrasp_alliance() : ConditionScript("condition_is_wintergrasp_alliance") { }
- SpellScript* GetSpellScript() const override
- {
- return new spell_wintergrasp_defender_teleport_trigger_SpellScript();
- }
+ bool OnConditionCheck(Condition const* /* condition */, ConditionSourceInfo& /* sourceInfo */)
+ {
+ Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG);
+ if (wintergrasp && wintergrasp->IsEnabled() && wintergrasp->GetDefenderTeam() == TEAM_ALLIANCE)
+ return true;
+ return false;
+ }
};
void AddSC_wintergrasp()
@@ -634,10 +596,12 @@ void AddSC_wintergrasp()
new npc_wg_spirit_guide();
new npc_wg_demolisher_engineer();
new go_wg_vehicle_teleporter();
- new npc_wg_quest_giver();
+ new npc_wg_give_promotion_credit();
new spell_wintergrasp_force_building();
new spell_wintergrasp_grab_passenger();
new achievement_wg_didnt_stand_a_chance();
new spell_wintergrasp_defender_teleport();
new spell_wintergrasp_defender_teleport_trigger();
+ new condition_is_wintergrasp_horde();
+ new condition_is_wintergrasp_alliance();
}
diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp
new file mode 100644
index 00000000000..bcfd40234b7
--- /dev/null
+++ b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ScriptMgr.h"
+#include "SpellMgr.h"
+#include "SpellScript.h"
+#include "SpellAuraEffects.h"
+
+enum Spells
+{
+ SPELL_MARK_OF_MALICE_TRIGGERED = 33494
+};
+
+class spell_mark_of_malice : public SpellScriptLoader
+{
+ public:
+ spell_mark_of_malice() : SpellScriptLoader("spell_mark_of_malice") { }
+
+ class spell_mark_of_malice_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mark_of_malice_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MARK_OF_MALICE_TRIGGERED))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+ // just drop charges
+ if (aurEff->GetBase()->GetCharges() > 1)
+ return;
+
+ GetTarget()->CastSpell(GetTarget(), SPELL_MARK_OF_MALICE_TRIGGERED, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_mark_of_malice_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mark_of_malice_AuraScript();
+ }
+};
+
+void AddSC_shadow_labyrinth()
+{
+ new spell_mark_of_malice();
+}
diff --git a/src/server/scripts/Outland/BlackTemple/black_temple.h b/src/server/scripts/Outland/BlackTemple/black_temple.h
index 0856639f4c2..9d2c3dacb3f 100644
--- a/src/server/scripts/Outland/BlackTemple/black_temple.h
+++ b/src/server/scripts/Outland/BlackTemple/black_temple.h
@@ -47,27 +47,29 @@ enum DataTypes
DATA_BLOOD_ELF_COUNCIL_VOICE = 15,
DATA_GO_ILLIDAN_GATE = 16,
- DATA_GO_ILLIDAN_DOOR_R = 17,
- DATA_GO_ILLIDAN_DOOR_L = 18
};
enum CreatureIds
{
+ //Bosses
NPC_HIGH_WARLORD_NAJENTUS = 22887,
NPC_SUPREMUS = 22898,
NPC_SHADE_OF_AKAMA = 22841,
- NPC_AKAMA_SHADE = 23191, // This is the Akama that starts the Shade of Akama encounter.
- NPC_AKAMA = 23089, // This is the Akama that starts the Illidan encounter.
+ NPC_TERON_GOREFIEND = 22871,
+ NPC_GURTOGG_BLOODBOIL = 22948,
+ NPC_RELIQUARY_OF_SOULS = 22856,
+ NPC_MOTHER_SHAHRAZ = 22947,
+ NPC_ILLIDARI_COUNCIL = 23426,
+ NPC_ILLIDAN_STORMRAGE = 22917,
+ //Misc
NPC_GATHIOS_THE_SHATTERER = 22949,
NPC_HIGH_NETHERMANCER_ZEREVOR = 22950,
NPC_LADY_MALANDE = 22951,
NPC_VERAS_DARKSHADOW = 22952,
- NPC_ILLIDARI_COUNCIL = 23426,
NPC_BLOOD_ELF_COUNCIL_VOICE = 23499,
-
- NPC_ILLIDAN_STORMRAGE = 22917,
-
+ NPC_AKAMA = 23089, // This is the Akama that starts the Illidan encounter.
+ NPC_AKAMA_SHADE = 23191, // This is the Akama that starts the Shade of Akama encounter.
NPC_SUPREMUS_VOLCANO = 23085
};
diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp
index a2215862219..07578b4c9ae 100644
--- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp
+++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp
@@ -539,8 +539,7 @@ public:
void EnterCombat(Unit* /*who*/) override
{
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
- me->setActive(true);
- DoZoneInCombat();
+ _EnterCombat();
}
void AttackStart(Unit* who) override
@@ -561,9 +560,6 @@ public:
{
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- for (uint8 i = DATA_GO_ILLIDAN_DOOR_R; i < DATA_GO_ILLIDAN_DOOR_L + 1; ++i)
- instance->HandleGameObject(instance->GetGuidData(i), true);
-
_JustDied();
}
@@ -1412,23 +1408,13 @@ public:
IllidanGUID = instance->GetGuidData(DATA_ILLIDAN_STORMRAGE);
GateGUID = instance->GetGuidData(DATA_GO_ILLIDAN_GATE);
- DoorGUID[0] = instance->GetGuidData(DATA_GO_ILLIDAN_DOOR_R);
- DoorGUID[1] = instance->GetGuidData(DATA_GO_ILLIDAN_DOOR_L);
if (JustCreated) // close all doors at create
- {
instance->HandleGameObject(GateGUID, false);
-
- for (uint8 i = 0; i < 2; ++i)
- instance->HandleGameObject(DoorGUID[i], false);
- }
else // open all doors, raid wiped
{
instance->HandleGameObject(GateGUID, true);
WalkCount = 1; // skip first wp
-
- for (uint8 i = 0; i < 2; ++i)
- instance->HandleGameObject(DoorGUID[i], true);
}
KillAllElites();
@@ -1480,9 +1466,6 @@ public:
void BeginTalk()
{
- instance->SetBossState(DATA_ILLIDAN_STORMRAGE, IN_PROGRESS);
- for (uint8 i = 0; i < 2; ++i)
- instance->HandleGameObject(DoorGUID[i], false);
if (Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID))
{
illidan->RemoveAurasDueToSpell(SPELL_KNEEL);
@@ -1674,10 +1657,6 @@ public:
{
switch (WalkCount)
{
- case 6:
- for (uint8 i = 0; i < 2; ++i)
- instance->HandleGameObject(DoorGUID[i], true);
- break;
case 8:
if (Phase == PHASE_WALK)
EnterPhase(PHASE_TALK);
@@ -1795,7 +1774,6 @@ public:
ObjectGuid ChannelGUID;
ObjectGuid SpiritGUID[2];
ObjectGuid GateGUID;
- ObjectGuid DoorGUID[2];
uint32 ChannelCount;
uint32 WalkCount;
uint32 TalkCount;
diff --git a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp
index 347843ec7ff..d83e9f8aed9 100644
--- a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp
+++ b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp
@@ -46,7 +46,7 @@ enum Spells
SPELL_FIXATE = 40607,
SPELL_CHAIN_LIGHTNING = 39945,
SPELL_DESTRUCTIVE_POISON = 40874,
- SPELL_AKAMA_SOUL_EXPEL = 40902,
+ SPELL_AKAMA_SOUL_RETRIEVE = 40902,
// Shade
SPELL_THREAT = 41602,
SPELL_SHADE_OF_AKAMA_TRIGGER = 40955,
@@ -108,7 +108,7 @@ enum Events
EVENT_CHAIN_LIGHTNING = 4,
EVENT_DESTRUCTIVE_POISON = 5,
EVENT_START_BROKEN_FREE = 6,
- EVENT_START_SOUL_EXPEL = 7,
+ EVENT_START_SOUL_RETRIEVE = 7,
EVENT_EVADE_CHECK = 8,
EVENT_BROKEN_FREE_1 = 9,
EVENT_BROKEN_FREE_2 = 10,
@@ -246,11 +246,11 @@ public:
events.ScheduleEvent(EVENT_START_CHANNELERS_AND_SPAWNERS, Seconds(1));
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE);
events.ScheduleEvent(EVENT_EVADE_CHECK, Seconds(10));
- if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE)))
+ if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE))
AttackStart(akama);
}
- if (spell->Id == SPELL_AKAMA_SOUL_EXPEL)
+ if (spell->Id == SPELL_AKAMA_SOUL_RETRIEVE)
DoCastSelf(SPELL_AKAMA_SOUL_EXPEL_CHANNEL);
}
@@ -273,7 +273,7 @@ public:
{
DoCastSelf(SPELL_SHADE_OF_AKAMA_TRIGGER);
- if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE)))
+ if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE))
akama->AI()->DoAction(ACTION_SHADE_OF_AKAMA_DEAD);
for (ObjectGuid const& spawnerGuid : _spawners)
@@ -401,7 +401,7 @@ public:
_isInCombat = true;
me->SetWalk(false);
me->RemoveAurasDueToSpell(SPELL_AKAMA_SOUL_CHANNEL);
- if (Creature* shade = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SHADE_OF_AKAMA)))
+ if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA))
{
shade->RemoveAurasDueToSpell(SPELL_AKAMA_SOUL_CHANNEL);
AttackStart(shade);
@@ -445,7 +445,7 @@ public:
{
me->SetWalk(false);
me->SetFacingTo(0.08726646f, true);
- _events.ScheduleEvent(EVENT_START_SOUL_EXPEL, Seconds(1));
+ _events.ScheduleEvent(EVENT_START_SOUL_RETRIEVE, Seconds(1));
}
}
@@ -489,14 +489,14 @@ public:
break;
case EVENT_CHAIN_LIGHTNING:
DoCastVictim(SPELL_CHAIN_LIGHTNING);
- _events.Repeat(randtime(Seconds(8), Seconds(15)));
+ _events.Repeat(Seconds(8), Seconds(15));
break;
case EVENT_DESTRUCTIVE_POISON:
DoCastSelf(SPELL_DESTRUCTIVE_POISON);
- _events.Repeat(randtime(Seconds(3), Seconds(7)));
+ _events.Repeat(Seconds(3), Seconds(7));
break;
- case EVENT_START_SOUL_EXPEL:
- DoCast(SPELL_AKAMA_SOUL_EXPEL);
+ case EVENT_START_SOUL_RETRIEVE:
+ DoCast(SPELL_AKAMA_SOUL_RETRIEVE);
_events.ScheduleEvent(EVENT_START_BROKEN_FREE, Seconds(15));
break;
case EVENT_START_BROKEN_FREE:
@@ -541,7 +541,7 @@ public:
{
_summons.DespawnAll();
Talk(SAY_DEAD);
- if (Creature* shade = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SHADE_OF_AKAMA)))
+ if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA))
if (shade->IsAlive())
shade->AI()->EnterEvadeMode(EVADE_REASON_OTHER);
}
@@ -587,7 +587,7 @@ public:
{
_scheduler.Schedule(Seconds(2), [this](TaskContext channel)
{
- if (Creature* shade = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SHADE_OF_AKAMA)))
+ if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA))
{
if (shade->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
DoCastSelf(SPELL_SHADE_SOUL_CHANNEL);
@@ -657,12 +657,12 @@ public:
if (_leftSide)
{
_events.ScheduleEvent(EVENT_SPAWN_WAVE_B, Milliseconds(100));
- _events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_SORCERER, randtime(Seconds(2), Seconds(5)));
+ _events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_SORCERER, Seconds(2), Seconds(5));
}
else
{
_events.ScheduleEvent(EVENT_SPAWN_WAVE_B, Seconds(10));
- _events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_DEFENDER, randtime(Seconds(2), Seconds(5)));
+ _events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_DEFENDER, Seconds(2), Seconds(5));
}
break;
case ACTION_STOP_SPAWNING:
@@ -687,15 +687,15 @@ public:
{
case EVENT_SPAWN_WAVE_B:
DoCastSelf(SPELL_ASHTONGUE_WAVE_B);
- _events.Repeat(randtime(Seconds(50), Seconds(60)));
+ _events.Repeat(Seconds(50), Seconds(60));
break;
case EVENT_SUMMON_ASHTONGUE_SORCERER: // left
DoCastSelf(SPELL_SUMMON_ASHTONGUE_SORCERER);
- _events.Repeat(randtime(Seconds(30), Seconds(35)));
+ _events.Repeat(Seconds(30), Seconds(35));
break;
case EVENT_SUMMON_ASHTONGUE_DEFENDER: // right
DoCastSelf(SPELL_SUMMON_ASHTONGUE_DEFENDER);
- _events.Repeat(randtime(Seconds(30), Seconds(40)));
+ _events.Repeat(Seconds(30), Seconds(40));
break;
default:
break;
@@ -736,16 +736,13 @@ public:
void Reset() override
{
- if (Creature* shade = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SHADE_OF_AKAMA)))
+ if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA))
{
if (shade->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
me->GetMotionMaster()->MovePoint(0, shade->GetPosition());
- else
- {
- if (Creature* akama = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AKAMA_SHADE)))
- AttackStart(akama);
- }
+ else if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE))
+ AttackStart(akama);
}
Initialize();
}
@@ -777,7 +774,7 @@ public:
_scheduler.Schedule(Seconds(1) + Milliseconds(500), [this](TaskContext sorcer_channel)
{
- if (Creature* shade = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SHADE_OF_AKAMA)))
+ if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA))
{
if (shade->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
{
@@ -789,7 +786,7 @@ public:
{
me->InterruptSpell(CURRENT_CHANNELED_SPELL);
_switchToCombat = true;
- if (Creature* akama = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AKAMA_SHADE)))
+ if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE))
AttackStart(akama);
}
}
@@ -837,7 +834,7 @@ public:
void Reset() override
{
- if (Creature* akama = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AKAMA_SHADE)))
+ if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE))
AttackStart(akama);
}
@@ -849,9 +846,9 @@ public:
void EnterCombat(Unit* /*who*/) override
{
_events.ScheduleEvent(EVENT_HEROIC_STRIKE, Seconds(5));
- _events.ScheduleEvent(EVENT_SHIELD_BASH, randtime(Seconds(10), Seconds(16)));
- _events.ScheduleEvent(EVENT_DEBILITATING_STRIKE, randtime(Seconds(10), Seconds(16)));
- _events.ScheduleEvent(EVENT_WINDFURY, randtime(Seconds(8), Seconds(12)));
+ _events.ScheduleEvent(EVENT_SHIELD_BASH, Seconds(10), Seconds(16));
+ _events.ScheduleEvent(EVENT_DEBILITATING_STRIKE, Seconds(10), Seconds(16));
+ _events.ScheduleEvent(EVENT_WINDFURY, Seconds(8), Seconds(12));
}
@@ -868,19 +865,19 @@ public:
{
case EVENT_DEBILITATING_STRIKE:
DoCastVictim(SPELL_DEBILITATING_STRIKE);
- _events.Repeat(randtime(Seconds(20), Seconds(25)));
+ _events.Repeat(Seconds(20), Seconds(25));
break;
case EVENT_HEROIC_STRIKE:
DoCastSelf(SPELL_HEROIC_STRIKE);
- _events.Repeat(randtime(Seconds(5), Seconds(15)));
+ _events.Repeat(Seconds(5), Seconds(15));
break;
case EVENT_SHIELD_BASH:
DoCastVictim(SPELL_SHIELD_BASH);
- _events.Repeat(randtime(Seconds(10), Seconds(20)));
+ _events.Repeat(Seconds(10), Seconds(20));
break;
case EVENT_WINDFURY:
DoCastVictim(SPELL_WINDFURY);
- _events.Repeat(randtime(Seconds(6), Seconds(8)));
+ _events.Repeat(Seconds(6), Seconds(8));
break;
default:
break;
@@ -915,7 +912,7 @@ public:
void Reset() override
{
- if (Creature* akama = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AKAMA_SHADE)))
+ if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE))
AttackStart(akama);
}
@@ -926,8 +923,8 @@ public:
void EnterCombat(Unit* /*who*/) override
{
- _events.ScheduleEvent(EVENT_DEBILITATING_POISON, randtime(Milliseconds(500), Seconds(2)));
- _events.ScheduleEvent(EVENT_EVISCERATE, randtime(Seconds(2), Seconds(5)));
+ _events.ScheduleEvent(EVENT_DEBILITATING_POISON, Milliseconds(500), Seconds(2));
+ _events.ScheduleEvent(EVENT_EVISCERATE, Seconds(2), Seconds(5));
}
void EnterEvadeMode(EvadeReason /*why*/) override { }
@@ -945,11 +942,11 @@ public:
{
case EVENT_DEBILITATING_POISON:
DoCastVictim(SPELL_DEBILITATING_POISON);
- _events.Repeat(randtime(Seconds(15), Seconds(20)));
+ _events.Repeat(Seconds(15), Seconds(20));
break;
case EVENT_EVISCERATE:
DoCastVictim(SPELL_EVISCERATE);
- _events.Repeat(randtime(Seconds(12), Seconds(20)));
+ _events.Repeat(Seconds(12), Seconds(20));
break;
default:
break;
@@ -984,7 +981,7 @@ public:
void Reset() override
{
- if (Creature* akama = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AKAMA_SHADE)))
+ if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE))
AttackStart(akama);
}
@@ -1014,11 +1011,11 @@ public:
{
case EVENT_RAIN_OF_FIRE:
DoCastVictim(SPELL_RAIN_OF_FIRE);
- _events.Repeat(randtime(Seconds(15), Seconds(20)));
+ _events.Repeat(Seconds(15), Seconds(20));
break;
case EVENT_LIGHTNING_BOLT:
DoCastVictim(SPELL_LIGHTNING_BOLT);
- _events.Repeat(randtime(Seconds(8), Seconds(15)));
+ _events.Repeat(Seconds(8), Seconds(15));
break;
default:
break;
@@ -1062,7 +1059,7 @@ public:
{
Initialize();
- if (Creature* akama = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AKAMA_SHADE)))
+ if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE))
AttackStart(akama);
}
@@ -1073,7 +1070,7 @@ public:
void EnterCombat(Unit* /*who*/) override
{
- _events.ScheduleEvent(EVENT_SPIRIT_HEAL, randtime(Seconds(5), Seconds(6)));
+ _events.ScheduleEvent(EVENT_SPIRIT_HEAL, Seconds(5), Seconds(6));
}
void DamageTaken(Unit* /*who*/, uint32& /*damage*/) override
@@ -1083,7 +1080,7 @@ public:
{
DoCastSelf(SPELL_SPIRIT_MEND);
_spiritMend = true;
- _events.ScheduleEvent(EVENT_SPIRIT_MEND_RESET, randtime(Seconds(10),Seconds(15)));
+ _events.ScheduleEvent(EVENT_SPIRIT_MEND_RESET, Seconds(10),Seconds(15));
}
if (!_chainHeal)
@@ -1091,7 +1088,7 @@ public:
{
DoCastSelf(SPELL_CHAIN_HEAL);
_chainHeal = true;
- _events.ScheduleEvent(EVENT_CHAIN_HEAL_RESET, randtime(Seconds(10), Seconds(15)));
+ _events.ScheduleEvent(EVENT_CHAIN_HEAL_RESET, Seconds(10), Seconds(15));
}
}
@@ -1108,7 +1105,7 @@ public:
{
case EVENT_SPIRIT_HEAL:
DoCastSelf(SPELL_SPIRITBINDER_SPIRIT_HEAL);
- _events.Repeat(randtime(Seconds(13), Seconds(16)));
+ _events.Repeat(Seconds(13), Seconds(16));
break;
case EVENT_SPIRIT_MEND_RESET:
_spiritMend = false;
@@ -1157,7 +1154,7 @@ public:
if (motionType != POINT_MOTION_TYPE)
return;
- if (Creature* akama = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AKAMA_SHADE)))
+ if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE))
me->SetFacingToObject(akama);
}
diff --git a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp
index bac996918ac..2784792fe8d 100644
--- a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp
+++ b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp
@@ -22,17 +22,20 @@
DoorData const doorData[] =
{
{ GO_NAJENTUS_GATE, DATA_HIGH_WARLORD_NAJENTUS, DOOR_TYPE_PASSAGE },
- { GO_NAJENTUS_GATE, DATA_SUPREMUS, DOOR_TYPE_ROOM },
+ { GO_NAJENTUS_GATE, DATA_SUPREMUS, DOOR_TYPE_ROOM },
{ GO_SUPREMUS_GATE, DATA_SUPREMUS, DOOR_TYPE_PASSAGE },
- { GO_SHADE_OF_AKAMA_DOOR, DATA_SHADE_OF_AKAMA, DOOR_TYPE_ROOM },
- { GO_TERON_DOOR_1, DATA_TERON_GOREFIEND, DOOR_TYPE_ROOM },
- { GO_TERON_DOOR_2, DATA_TERON_GOREFIEND, DOOR_TYPE_ROOM },
+ { GO_SHADE_OF_AKAMA_DOOR, DATA_SHADE_OF_AKAMA, DOOR_TYPE_ROOM },
+ { GO_TERON_DOOR_1, DATA_TERON_GOREFIEND, DOOR_TYPE_ROOM },
+ { GO_TERON_DOOR_2, DATA_TERON_GOREFIEND, DOOR_TYPE_ROOM },
{ GO_GURTOGG_DOOR, DATA_GURTOGG_BLOODBOIL, DOOR_TYPE_PASSAGE },
{ GO_TEMPLE_DOOR, DATA_RELIQUARY_OF_SOULS, DOOR_TYPE_PASSAGE },
{ GO_MOTHER_SHAHRAZ_DOOR, DATA_MOTHER_SHAHRAZ, DOOR_TYPE_PASSAGE },
- { GO_COUNCIL_DOOR_1, DATA_ILLIDARI_COUNCIL, DOOR_TYPE_ROOM },
- { GO_COUNCIL_DOOR_2, DATA_ILLIDARI_COUNCIL, DOOR_TYPE_ROOM },
- { 0, 0, DOOR_TYPE_ROOM } // END
+ { GO_COUNCIL_DOOR_1, DATA_ILLIDARI_COUNCIL, DOOR_TYPE_ROOM },
+ { GO_COUNCIL_DOOR_2, DATA_ILLIDARI_COUNCIL, DOOR_TYPE_ROOM },
+ //{ GO_ILLIDAN_GATE, DATA_GO_ILLIDAN_GATE, DOOR_TYPE_PASSAGE },
+ { GO_ILLIDAN_DOOR_R, DATA_ILLIDAN_STORMRAGE, DOOR_TYPE_ROOM },
+ { GO_ILLIDAN_DOOR_L, DATA_ILLIDAN_STORMRAGE, DOOR_TYPE_ROOM },
+ { 0, 0, DOOR_TYPE_ROOM } // END
};
BossBoundaryData const boundaries =
@@ -49,6 +52,27 @@ BossBoundaryData const boundaries =
{ DATA_ILLIDAN_STORMRAGE, new EllipseBoundary(Position(694.8f, 309.0f), 70.0 , 85.0) }
};
+ObjectData const creatureData[] =
+{
+ { NPC_HIGH_WARLORD_NAJENTUS, DATA_HIGH_WARLORD_NAJENTUS },
+ { NPC_SUPREMUS, DATA_SUPREMUS },
+ { NPC_SHADE_OF_AKAMA, DATA_SHADE_OF_AKAMA },
+ { NPC_TERON_GOREFIEND, DATA_TERON_GOREFIEND },
+ { NPC_GURTOGG_BLOODBOIL, DATA_GURTOGG_BLOODBOIL },
+ { NPC_RELIQUARY_OF_SOULS, DATA_RELIQUARY_OF_SOULS },
+ { NPC_MOTHER_SHAHRAZ, DATA_MOTHER_SHAHRAZ },
+ { NPC_ILLIDARI_COUNCIL, DATA_ILLIDARI_COUNCIL },
+ { NPC_ILLIDAN_STORMRAGE, DATA_ILLIDAN_STORMRAGE },
+ { NPC_AKAMA_SHADE, DATA_AKAMA_SHADE },
+ { NPC_AKAMA, DATA_AKAMA },
+ { NPC_GATHIOS_THE_SHATTERER, DATA_GATHIOS_THE_SHATTERER },
+ { NPC_HIGH_NETHERMANCER_ZEREVOR, DATA_HIGH_NETHERMANCER_ZEREVOR },
+ { NPC_LADY_MALANDE, DATA_LADY_MALANDE },
+ { NPC_VERAS_DARKSHADOW, DATA_VERAS_DARKSHADOW },
+ { NPC_BLOOD_ELF_COUNCIL_VOICE, DATA_BLOOD_ELF_COUNCIL_VOICE },
+ { 0, 0 } // end
+};
+
class instance_black_temple : public InstanceMapScript
{
public:
@@ -61,165 +85,28 @@ class instance_black_temple : public InstanceMapScript
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
LoadDoorData(doorData);
+ LoadObjectData(creatureData, nullptr);
LoadBossBoundaries(boundaries);
}
- void OnCreatureCreate(Creature* creature) override
- {
- switch (creature->GetEntry())
- {
- case NPC_HIGH_WARLORD_NAJENTUS:
- NajentusGUID = creature->GetGUID();
- break;
- case NPC_SUPREMUS:
- SupremusGUID = creature->GetGUID();
- break;
- case NPC_SHADE_OF_AKAMA:
- ShadeOfAkamaGUID = creature->GetGUID();
- break;
- case NPC_AKAMA_SHADE:
- AkamaShadeGUID = creature->GetGUID();
- break;
- case NPC_AKAMA:
- AkamaGUID = creature->GetGUID();
- break;
- case NPC_GATHIOS_THE_SHATTERER:
- GathiosTheShattererGUID = creature->GetGUID();
- break;
- case NPC_HIGH_NETHERMANCER_ZEREVOR:
- HighNethermancerZerevorGUID = creature->GetGUID();
- break;
- case NPC_LADY_MALANDE:
- LadyMalandeGUID = creature->GetGUID();
- break;
- case NPC_VERAS_DARKSHADOW:
- VerasDarkshadowGUID = creature->GetGUID();
- break;
- case NPC_ILLIDARI_COUNCIL:
- IllidariCouncilGUID = creature->GetGUID();
- break;
- case NPC_BLOOD_ELF_COUNCIL_VOICE:
- BloodElfCouncilVoiceGUID = creature->GetGUID();
- break;
- case NPC_ILLIDAN_STORMRAGE:
- IllidanStormrageGUID = creature->GetGUID();
- break;
- default:
- break;
- }
- }
-
void OnGameObjectCreate(GameObject* go) override
{
- switch (go->GetEntry())
- {
- case GO_NAJENTUS_GATE:
- case GO_SUPREMUS_GATE:
- case GO_SHADE_OF_AKAMA_DOOR:
- case GO_TERON_DOOR_1:
- case GO_TERON_DOOR_2:
- case GO_GURTOGG_DOOR:
- case GO_TEMPLE_DOOR:
- case GO_MOTHER_SHAHRAZ_DOOR:
- case GO_COUNCIL_DOOR_1:
- case GO_COUNCIL_DOOR_2:
- AddDoor(go, true);
- break;
- case GO_ILLIDAN_GATE:
- IllidanGateGUID = go->GetGUID();
- break;
- case GO_ILLIDAN_DOOR_R:
- IllidanDoorGUIDs[0] = go->GetGUID();
- break;
- case GO_ILLIDAN_DOOR_L:
- IllidanDoorGUIDs[1] = go->GetGUID();
- break;
- default:
- break;
- }
- }
+ if (go->GetEntry() == GO_ILLIDAN_GATE)
+ IllidanGateGUID = go->GetGUID();
- void OnGameObjectRemove(GameObject* go) override
- {
- switch (go->GetEntry())
- {
- case GO_NAJENTUS_GATE:
- case GO_SUPREMUS_GATE:
- case GO_SHADE_OF_AKAMA_DOOR:
- case GO_TERON_DOOR_1:
- case GO_TERON_DOOR_2:
- case GO_GURTOGG_DOOR:
- case GO_TEMPLE_DOOR:
- case GO_MOTHER_SHAHRAZ_DOOR:
- case GO_COUNCIL_DOOR_1:
- case GO_COUNCIL_DOOR_2:
- AddDoor(go, false);
- break;
- default:
- break;
- }
+ InstanceScript::OnGameObjectCreate(go);
}
ObjectGuid GetGuidData(uint32 type) const override
{
- switch (type)
- {
- case DATA_HIGH_WARLORD_NAJENTUS:
- return NajentusGUID;
- case DATA_SUPREMUS:
- return SupremusGUID;
- case DATA_SHADE_OF_AKAMA:
- return ShadeOfAkamaGUID;
- case DATA_AKAMA_SHADE:
- return AkamaShadeGUID;
- case DATA_AKAMA:
- return AkamaGUID;
- case DATA_GATHIOS_THE_SHATTERER:
- return GathiosTheShattererGUID;
- case DATA_HIGH_NETHERMANCER_ZEREVOR:
- return HighNethermancerZerevorGUID;
- case DATA_LADY_MALANDE:
- return LadyMalandeGUID;
- case DATA_VERAS_DARKSHADOW:
- return VerasDarkshadowGUID;
- case DATA_ILLIDARI_COUNCIL:
- return IllidariCouncilGUID;
- case DATA_BLOOD_ELF_COUNCIL_VOICE:
- return BloodElfCouncilVoiceGUID;
- case DATA_ILLIDAN_STORMRAGE:
- return IllidanStormrageGUID;
- case DATA_GO_ILLIDAN_GATE:
- return IllidanGateGUID;
- case DATA_GO_ILLIDAN_DOOR_R:
- return IllidanDoorGUIDs[0];
- case DATA_GO_ILLIDAN_DOOR_L:
- return IllidanDoorGUIDs[1];
- default:
- break;
- }
+ if (type == DATA_GO_ILLIDAN_GATE)
+ return IllidanGateGUID;
- return ObjectGuid::Empty;
+ return InstanceScript::GetGuidData(type);
}
protected:
- ObjectGuid NajentusGUID;
- ObjectGuid SupremusGUID;
- ObjectGuid ShadeOfAkamaGUID;
- ObjectGuid AkamaShadeGUID;
- ObjectGuid AkamaGUID;
-
- ObjectGuid GathiosTheShattererGUID;
- ObjectGuid HighNethermancerZerevorGUID;
- ObjectGuid LadyMalandeGUID;
- ObjectGuid VerasDarkshadowGUID;
-
- ObjectGuid IllidariCouncilGUID;
- ObjectGuid BloodElfCouncilVoiceGUID;
-
- ObjectGuid IllidanStormrageGUID;
-
ObjectGuid IllidanGateGUID;
- ObjectGuid IllidanDoorGUIDs[2];
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp
index ee7dca668a9..549786b1fd6 100644
--- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp
+++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp
@@ -50,16 +50,18 @@ enum Spells
SPELL_HAMSTRING = 26211
};
+enum Misc
+{
+ EMOTE_SPOUT = 0, // "The Lurker Below takes a deep breath."
+ SPOUT_DIST = 100
+};
+
enum Creatures
{
NPC_COILFANG_GUARDIAN = 21873,
NPC_COILFANG_AMBUSHER = 21865
};
-#define EMOTE_SPOUT "The Lurker Below takes a deep breath."
-
-#define SPOUT_DIST 100
-
float AddPos[9][3] =
{
// MOVE_AMBUSHER_1 X, Y, Z
@@ -240,7 +242,7 @@ public:
if (SpoutTimer <= diff)
{
- me->TextEmote(EMOTE_SPOUT, nullptr, true);
+ Talk(EMOTE_SPOUT);
me->SetReactState(REACT_PASSIVE);
me->GetMotionMaster()->MoveRotate(20000, urand(0, 1) ? ROTATE_DIRECTION_LEFT : ROTATE_DIRECTION_RIGHT);
SpoutTimer = 45000;
diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp
index f191a0c3ad7..9490995a633 100644
--- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp
@@ -231,11 +231,7 @@ class boss_kelidan_the_breaker : public CreatureScript
Talk(SAY_NOVA);
- if (SpellInfo const* nova = sSpellMgr->GetSpellInfo(SPELL_BURNING_NOVA))
- {
- if (Aura* aura = Aura::TryRefreshStackOrCreate(nova, MAX_EFFECT_MASK, me, me))
- aura->ApplyForTargets();
- }
+ me->AddAura(SPELL_BURNING_NOVA, me);
if (IsHeroic())
DoTeleportAll(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
diff --git a/src/server/scripts/Outland/boss_doomlord_kazzak.cpp b/src/server/scripts/Outland/boss_doomlord_kazzak.cpp
index d4f0637c0d1..daea6d24a4a 100644
--- a/src/server/scripts/Outland/boss_doomlord_kazzak.cpp
+++ b/src/server/scripts/Outland/boss_doomlord_kazzak.cpp
@@ -34,16 +34,17 @@ enum Texts
enum Spells
{
- SPELL_SHADOW_VOLLEY = 32963,
- SPELL_CLEAVE = 31779,
- SPELL_THUNDERCLAP = 36706,
- SPELL_VOID_BOLT = 39329,
- SPELL_MARK_OF_KAZZAK = 32960,
- SPELL_MARK_OF_KAZZAK_DAMAGE = 32961,
- SPELL_ENRAGE = 32964,
- SPELL_CAPTURE_SOUL = 32966,
- SPELL_TWISTED_REFLECTION = 21063,
- SPELL_BERSERK = 32965,
+ SPELL_SHADOW_VOLLEY = 32963,
+ SPELL_CLEAVE = 31779,
+ SPELL_THUNDERCLAP = 36706,
+ SPELL_VOID_BOLT = 39329,
+ SPELL_MARK_OF_KAZZAK = 32960,
+ SPELL_MARK_OF_KAZZAK_DAMAGE = 32961,
+ SPELL_ENRAGE = 32964,
+ SPELL_CAPTURE_SOUL = 32966,
+ SPELL_TWISTED_REFLECTION = 21063,
+ SPELL_TWISTED_REFLECTION_HEAL = 21064,
+ SPELL_BERSERK = 32965,
};
enum Events
@@ -222,8 +223,47 @@ class spell_mark_of_kazzak : public SpellScriptLoader
}
};
+class spell_twisted_reflection : public SpellScriptLoader
+{
+ public:
+ spell_twisted_reflection() : SpellScriptLoader("spell_twisted_reflection") { }
+
+ class spell_twisted_reflection_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_twisted_reflection_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_TWISTED_REFLECTION_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ eventInfo.GetActionTarget()->CastSpell(eventInfo.GetActor(), SPELL_TWISTED_REFLECTION_HEAL, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_twisted_reflection_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_twisted_reflection_AuraScript();
+ }
+};
+
void AddSC_boss_doomlordkazzak()
{
new boss_doomlord_kazzak();
new spell_mark_of_kazzak();
+ new spell_twisted_reflection();
}
diff --git a/src/server/scripts/Outland/outland_script_loader.cpp b/src/server/scripts/Outland/outland_script_loader.cpp
index ed2c21da6c3..e5c025a43cf 100644
--- a/src/server/scripts/Outland/outland_script_loader.cpp
+++ b/src/server/scripts/Outland/outland_script_loader.cpp
@@ -37,6 +37,7 @@ void AddSC_boss_ambassador_hellmaw();
void AddSC_boss_blackheart_the_inciter();
void AddSC_boss_grandmaster_vorpil();
void AddSC_boss_murmur();
+void AddSC_shadow_labyrinth();
void AddSC_instance_shadow_labyrinth();
// Black Temple
@@ -159,6 +160,7 @@ void AddOutlandScripts()
AddSC_boss_blackheart_the_inciter();
AddSC_boss_grandmaster_vorpil();
AddSC_boss_murmur();
+ AddSC_shadow_labyrinth();
AddSC_instance_shadow_labyrinth();
// Black Temple
diff --git a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp
index cf8298bc518..3b364d557ed 100644
--- a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp
+++ b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp
@@ -332,8 +332,14 @@ public:
enum FelGuard
{
- SPELL_SUMMON_POO = 37688,
- NPC_DERANGED_HELBOAR = 16863
+ SPELL_SUMMON_POO = 37688,
+ SPELL_FAKE_BLOOD = 37692,
+ NPC_DERANGED_HELBOAR = 16863,
+
+ EVENT_SEARCH_HELBOAR = 1,
+ EVENT_HELBOAR_FOUND = 2,
+ EVENT_SUMMON_POO = 3,
+ EVENT_FOLLOW_PLAYER = 4
};
class npc_fel_guard_hound : public CreatureScript
@@ -350,8 +356,8 @@ public:
void Initialize()
{
- checkTimer = 5000; //check for creature every 5 sec
helboarGUID.Clear();
+ _events.ScheduleEvent(EVENT_SEARCH_HELBOAR, Seconds(3));
}
void Reset() override
@@ -366,29 +372,54 @@ public:
if (Creature* helboar = ObjectAccessor::GetCreature(*me, helboarGUID))
{
- helboar->RemoveCorpse();
- DoCast(SPELL_SUMMON_POO);
-
- if (Player* owner = me->GetCharmerOrOwnerPlayerOrPlayerItself())
- me->GetMotionMaster()->MoveFollow(owner, 0.0f, 0.0f);
+ _events.CancelEvent(EVENT_SEARCH_HELBOAR);
+ me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK_UNARMED);
+ me->CastSpell(helboar, SPELL_FAKE_BLOOD);
+ _events.ScheduleEvent(EVENT_HELBOAR_FOUND, Seconds(2));
}
}
void UpdateAI(uint32 diff) override
{
- if (checkTimer <= diff)
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
{
- if (Creature* helboar = me->FindNearestCreature(NPC_DERANGED_HELBOAR, 10.0f, false))
+ switch (eventId)
{
- if (helboar->GetGUID() != helboarGUID && me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE && !me->FindCurrentSpellBySpellId(SPELL_SUMMON_POO))
- {
- helboarGUID = helboar->GetGUID();
- me->GetMotionMaster()->MovePoint(1, helboar->GetPositionX(), helboar->GetPositionY(), helboar->GetPositionZ());
- }
+ case EVENT_SEARCH_HELBOAR:
+ if (Creature* helboar = me->FindNearestCreature(NPC_DERANGED_HELBOAR, 10.0f, false))
+ {
+ if (helboar->GetGUID() != helboarGUID && me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE && !me->FindCurrentSpellBySpellId(SPELL_SUMMON_POO))
+ {
+ helboarGUID = helboar->GetGUID();
+ me->SetWalk(true);
+ me->GetMotionMaster()->MovePoint(1, helboar->GetPositionX(), helboar->GetPositionY(), helboar->GetPositionZ());
+ helboar->DespawnOrUnsummon(Seconds(10));
+ }
+ }
+ _events.Repeat(Seconds(3));
+ break;
+ case EVENT_HELBOAR_FOUND:
+ if (Creature* helboar = ObjectAccessor::GetCreature(*me, helboarGUID))
+ {
+ me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK_UNARMED);
+ me->CastSpell(helboar, SPELL_FAKE_BLOOD);
+ _events.ScheduleEvent(EVENT_SUMMON_POO, Seconds(1));
+ }
+ break;
+ case EVENT_SUMMON_POO:
+ DoCast(SPELL_SUMMON_POO);
+ _events.ScheduleEvent(EVENT_FOLLOW_PLAYER, Seconds(2));
+ break;
+ case EVENT_FOLLOW_PLAYER:
+ me->SetWalk(false);
+ if (Player* owner = me->GetCharmerOrOwnerPlayerOrPlayerItself())
+ me->GetMotionMaster()->MoveFollow(owner, 0.0f, 0.0f);
+ _events.ScheduleEvent(EVENT_SEARCH_HELBOAR, Seconds(3));
+ break;
}
- checkTimer = 5000;
}
- else checkTimer -= diff;
if (!UpdateVictim())
return;
@@ -397,7 +428,7 @@ public:
}
private:
- uint32 checkTimer;
+ EventMap _events;
ObjectGuid helboarGUID;
};
@@ -470,12 +501,161 @@ enum ExorcismMisc
enum ExorcismEvents
{
EVENT_BARADAS_TALK = 1,
+ EVENT_RESET = 2,
//Colonel Jules
EVENT_SUMMON_SKULL = 1,
};
/*######
+## npc_colonel_jules
+######*/
+
+class npc_colonel_jules : public CreatureScript
+{
+public:
+ npc_colonel_jules() : CreatureScript("npc_colonel_jules") { }
+
+ bool OnGossipHello(Player* player, Creature* creature) override
+ {
+ if (ENSURE_AI(npc_colonel_jules::npc_colonel_julesAI, creature->AI())->success)
+ player->KilledMonsterCredit(NPC_COLONEL_JULES, ObjectGuid::Empty);
+
+ SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
+ return true;
+ }
+
+ struct npc_colonel_julesAI : public ScriptedAI
+ {
+ npc_colonel_julesAI(Creature* creature) : ScriptedAI(creature), summons(me)
+ {
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ point = 3;
+ wpreached = false;
+ success = false;
+ }
+
+ void Reset() override
+ {
+ events.Reset();
+
+ summons.DespawnAll();
+ Initialize();
+ }
+
+ bool success;
+
+ 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->SetSpeedRate(MOVE_RUN, 0.2f);
+
+ me->SetFacingTo(3.207566f);
+ me->GetMotionMaster()->MoveJump(exorcismPos[2], 2.0f, 2.0f);
+
+ success = false;
+
+ events.ScheduleEvent(EVENT_SUMMON_SKULL, 10000);
+ break;
+ case ACTION_JULES_FLIGHT:
+ 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->SetSpeedRate(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 < 2; i++)
+ DoSummon(NPC_FOUL_PURGE, exorcismPos[8]);
+ }
+
+ if (id == 10)
+ {
+ wpreached = true;
+ point = 3;
+ }
+ }
+
+ 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 point;
+
+ bool wpreached;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_colonel_julesAI(creature);
+ }
+};
+
+/*######
## npc_barada
######*/
@@ -706,11 +886,11 @@ public:
break;
case 21:
//End
- if (Player* player = ObjectAccessor::FindPlayer(playerGUID))
- player->KilledMonsterCredit(NPC_COLONEL_JULES, ObjectGuid::Empty);
-
if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ {
+ ENSURE_AI(npc_colonel_jules::npc_colonel_julesAI, jules->AI())->success = true;
jules->RemoveAllAuras();
+ }
me->RemoveAura(SPELL_BARADAS_COMMAND);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
@@ -718,9 +898,14 @@ public:
Talk(SAY_BARADA_8);
me->GetMotionMaster()->MoveTargetedHome();
EnterEvadeMode();
+ events.ScheduleEvent(EVENT_RESET, Minutes(2));
break;
}
break;
+ case EVENT_RESET:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ ENSURE_AI(npc_colonel_jules::npc_colonel_julesAI, jules->AI())->success = false;
+ break;
}
}
}
@@ -738,142 +923,119 @@ public:
}
};
-/*######
-## npc_colonel_jules
-######*/
+enum Aledis
+{
+ SAY_CHALLENGE = 0,
+ SAY_DEFEATED = 1,
+ EVENT_TALK = 1,
+ EVENT_ATTACK = 2,
+ EVENT_EVADE = 3,
+ EVENT_FIREBALL = 4,
+ EVENT_FROSTNOVA = 5,
+ SPELL_FIREBALL = 20823,
+ SPELL_FROSTNOVA = 11831
+};
-class npc_colonel_jules : public CreatureScript
+class npc_magister_aledis : public CreatureScript
{
public:
- npc_colonel_jules() : CreatureScript("npc_colonel_jules") { }
+ npc_magister_aledis() : CreatureScript("npc_magister_aledis") { }
- struct npc_colonel_julesAI : public ScriptedAI
+ bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 /*action*/) override
{
- npc_colonel_julesAI(Creature* creature) : ScriptedAI(creature), summons(me)
- {
- Initialize();
- }
+ CloseGossipMenuFor(player);
+ creature->StopMoving();
+ ENSURE_AI(npc_magister_aledis::npc_magister_aledisAI, creature->AI())->StartFight(player);
+ return true;
+ }
- void Initialize()
+ struct npc_magister_aledisAI : public ScriptedAI
+ {
+ npc_magister_aledisAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void StartFight(Player* player)
{
- circleRounds = 0;
- point = 3;
- wpreached = false;
+ me->Dismount();
+ me->SetFacingToObject(player, true);
+ me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ _playerGUID = player->GetGUID();
+ _events.ScheduleEvent(EVENT_TALK, Seconds(2));
}
void Reset() override
{
- events.Reset();
-
- summons.DespawnAll();
- Initialize();
+ me->RestoreFaction();
+ me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER);
+ me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
}
- void DoAction(int32 action) override
+ void DamageTaken(Unit* /*attacker*/, uint32 &damage) override
{
- switch (action)
+ if (damage > me->GetHealth() || me->HealthBelowPctDamaged(20, damage))
{
- case ACTION_JULES_HOVER:
- me->AddAura(SPELL_JULES_GOES_PRONE, me);
- me->AddAura(SPELL_JULES_THREATENS_AURA, me);
-
- me->SetCanFly(true);
- me->SetSpeedRate(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->SetSpeedRate(MOVE_RUN, 1.0f);
- me->GetMotionMaster()->MovePoint(11, exorcismPos[2]);
-
- events.CancelEvent(EVENT_SUMMON_SKULL);
- break;
- }
- }
+ damage = 0;
- 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]);
- }
+ _events.Reset();
+ me->RestoreFaction();
+ me->RemoveAllAuras();
+ me->DeleteThreatList();
+ me->CombatStop(true);
+ me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+ Talk(SAY_DEFEATED);
- if (id == 10)
- {
- wpreached = true;
- point = 3;
- circleRounds++;
+ _events.ScheduleEvent(EVENT_EVADE, Minutes(1));
}
}
void UpdateAI(uint32 diff) override
{
- if (wpreached)
- {
- me->GetMotionMaster()->MovePoint(point, exorcismPos[point]);
- point++;
- wpreached = false;
- }
+ _events.Update(diff);
- events.Update(diff);
-
- while (uint32 eventId = events.ExecuteEvent())
+ 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;
+ case EVENT_TALK:
+ Talk(SAY_CHALLENGE);
+ _events.ScheduleEvent(EVENT_ATTACK, Seconds(2));
+ break;
+ case EVENT_ATTACK:
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+ me->setFaction(FACTION_HOSTILE);
+ me->CombatStart(ObjectAccessor::GetPlayer(*me, _playerGUID));
+ _events.ScheduleEvent(EVENT_FIREBALL, 1);
+ _events.ScheduleEvent(EVENT_FROSTNOVA, Seconds(5));
+ break;
+ case EVENT_FIREBALL:
+ DoCast(SPELL_FIREBALL);
+ _events.ScheduleEvent(EVENT_FIREBALL, Seconds(10));
+ break;
+ case EVENT_FROSTNOVA:
+ DoCastAOE(SPELL_FROSTNOVA);
+ _events.ScheduleEvent(EVENT_FROSTNOVA, Seconds(20));
+ break;
+ case EVENT_EVADE:
+ EnterEvadeMode();
+ break;
}
}
- }
- private:
- EventMap events;
- SummonList summons;
+ if (!UpdateVictim())
+ return;
- uint8 circleRounds;
- uint8 point;
+ DoMeleeAttackIfReady();
+ }
- bool wpreached;
+ private:
+ EventMap _events;
+ ObjectGuid _playerGUID;
};
CreatureAI* GetAI(Creature* creature) const override
{
- return new npc_colonel_julesAI(creature);
+ return new npc_magister_aledisAI(creature);
}
};
@@ -883,6 +1045,7 @@ void AddSC_hellfire_peninsula()
new npc_ancestral_wolf();
new npc_wounded_blood_elf();
new npc_fel_guard_hound();
- new npc_barada();
new npc_colonel_jules();
+ new npc_barada();
+ new npc_magister_aledis();
}
diff --git a/src/server/scripts/Pet/pet_hunter.cpp b/src/server/scripts/Pet/pet_hunter.cpp
index 321e44c8603..7092300af4d 100644
--- a/src/server/scripts/Pet/pet_hunter.cpp
+++ b/src/server/scripts/Pet/pet_hunter.cpp
@@ -22,6 +22,8 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "SpellAuraEffects.h"
enum HunterSpells
{
@@ -35,6 +37,21 @@ enum HunterCreatures
NPC_HUNTER_VIPER = 19921
};
+enum PetSpellsMisc
+{
+ SPELL_PET_GUARD_DOG_HAPPINESS = 54445,
+ SPELL_PET_SILVERBACK_RANK_1 = 62800,
+ SPELL_PET_SILVERBACK_RANK_2 = 62801,
+
+ SPELL_PET_SWOOP = 52825,
+ SPELL_PET_CHARGE = 61685,
+
+ PET_ICON_ID_GROWL = 201,
+ PET_ICON_ID_CLAW = 262,
+ PET_ICON_ID_BITE = 1680,
+ PET_ICON_ID_SMACK = 473
+};
+
class npc_pet_hunter_snake_trap : public CreatureScript
{
public:
@@ -139,7 +156,204 @@ class npc_pet_hunter_snake_trap : public CreatureScript
}
};
+// 57627 - Charge
+class spell_pet_charge : public SpellScriptLoader
+{
+ public:
+ spell_pet_charge() : SpellScriptLoader("spell_pet_charge") { }
+
+ class spell_pet_charge_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pet_charge_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PET_SWOOP) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PET_CHARGE))
+ return false;
+ return true;
+ }
+
+ void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ // Prevent console log
+ PreventDefaultAction();
+
+ // Remove +% AP aura
+ Unit* pet = eventInfo.GetActor();
+ Aura* aura = pet->GetAura(SPELL_PET_SWOOP, pet->GetGUID());
+ if (!aura)
+ aura = pet->GetAura(SPELL_PET_CHARGE, pet->GetGUID());
+
+ if (!aura)
+ return;
+
+ aura->DropCharge(AURA_REMOVE_BY_EXPIRE);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pet_charge_AuraScript::HandleDummy, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pet_charge_AuraScript();
+ }
+};
+
+// -53178 - Guard Dog
+class spell_pet_guard_dog : public SpellScriptLoader
+{
+ public:
+ spell_pet_guard_dog() : SpellScriptLoader("spell_pet_guard_dog") { }
+
+ class spell_pet_guard_dog_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pet_guard_dog_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PET_GUARD_DOG_HAPPINESS))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ // Growl shares family flags with other spells
+ // filter by spellIcon instead
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo || spellInfo->SpellIconID != PET_ICON_ID_GROWL)
+ return false;
+
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = eventInfo.GetActor();
+ caster->CastSpell((Unit*)nullptr, SPELL_PET_GUARD_DOG_HAPPINESS, true, nullptr, aurEff);
+
+ float addThreat = CalculatePct(ASSERT_NOTNULL(eventInfo.GetSpellInfo())->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount());
+ eventInfo.GetProcTarget()->AddThreat(caster, addThreat);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_pet_guard_dog_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_pet_guard_dog_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pet_guard_dog_AuraScript();
+ }
+};
+
+// -62764 - Silverback
+class spell_pet_silverback : public SpellScriptLoader
+{
+ public:
+ spell_pet_silverback() : SpellScriptLoader("spell_pet_silverback") { }
+
+ class spell_pet_silverback_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pet_silverback_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PET_GUARD_DOG_HAPPINESS))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ // Growl shares family flags with other spells
+ // filter by spellIcon instead
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo || spellInfo->SpellIconID != PET_ICON_ID_GROWL)
+ return false;
+
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ static uint32 const triggerSpell[2] = { SPELL_PET_SILVERBACK_RANK_1, SPELL_PET_SILVERBACK_RANK_2 };
+
+ PreventDefaultAction();
+
+ uint32 spellId = triggerSpell[GetSpellInfo()->GetRank() - 1];
+ eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_pet_silverback_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_pet_silverback_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pet_silverback_AuraScript();
+ }
+};
+
+// -61680 - Culling the Herd
+class spell_pet_culling_the_herd : public SpellScriptLoader
+{
+ public:
+ spell_pet_culling_the_herd() : SpellScriptLoader("spell_pet_culling_the_herd") { }
+
+ class spell_pet_culling_the_herd_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pet_culling_the_herd_AuraScript);
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ // Claw, Bite and Smack share FamilyFlags with other spells
+ // filter by spellIcon instead
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return false;
+
+ switch (spellInfo->SpellIconID)
+ {
+ case PET_ICON_ID_CLAW:
+ case PET_ICON_ID_BITE:
+ case PET_ICON_ID_SMACK:
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_pet_culling_the_herd_AuraScript::CheckProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pet_culling_the_herd_AuraScript();
+ }
+};
+
void AddSC_hunter_pet_scripts()
{
new npc_pet_hunter_snake_trap();
+ new spell_pet_charge();
+ new spell_pet_guard_dog();
+ new spell_pet_silverback();
+ new spell_pet_culling_the_herd();
}
diff --git a/src/server/scripts/Pet/pet_priest.cpp b/src/server/scripts/Pet/pet_priest.cpp
index a3110ce8f8b..a15b3bd7ffd 100644
--- a/src/server/scripts/Pet/pet_priest.cpp
+++ b/src/server/scripts/Pet/pet_priest.cpp
@@ -28,7 +28,7 @@
enum PriestSpells
{
SPELL_PRIEST_GLYPH_OF_SHADOWFIEND = 58228,
- SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA = 58227,
+ SPELL_PRIEST_SHADOWFIEND_DEATH = 57989,
SPELL_PRIEST_LIGHTWELL_CHARGES = 59907
};
@@ -70,12 +70,10 @@ class npc_pet_pri_shadowfiend : public CreatureScript
{
npc_pet_pri_shadowfiendAI(Creature* creature) : PetAI(creature) { }
- void JustDied(Unit* /*killer*/) override
+ void IsSummonedBy(Unit* summoner) override
{
- if (me->IsSummon())
- if (Unit* owner = me->ToTempSummon()->GetSummoner())
- if (owner->HasAura(SPELL_PRIEST_GLYPH_OF_SHADOWFIEND))
- owner->CastSpell(owner, SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA, true);
+ if (summoner->HasAura(SPELL_PRIEST_GLYPH_OF_SHADOWFIEND))
+ DoCastAOE(SPELL_PRIEST_SHADOWFIEND_DEATH);
}
};
diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp
index 980c0db19cc..13eec799493 100644
--- a/src/server/scripts/Spells/spell_dk.cpp
+++ b/src/server/scripts/Spells/spell_dk.cpp
@@ -73,7 +73,24 @@ enum DeathKnightSpells
SPELL_DK_UNHOLY_PRESENCE_TRIGGERED = 49772,
SPELL_DK_WILL_OF_THE_NECROPOLIS_TALENT_R1 = 49189,
SPELL_DK_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284,
- SPELL_DK_GHOUL_THRASH = 47480
+ SPELL_DK_GHOUL_THRASH = 47480,
+ SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT = 69961,
+ SPELL_DK_BUTCHERY_RUNIC_POWER = 50163,
+ SPELL_DK_MARK_OF_BLOOD_HEAL = 61607,
+ SPELL_DK_UNHOLY_BLIGHT_DAMAGE = 50536,
+ SPELL_DK_GLYPH_OF_UNHOLY_BLIGHT = 63332,
+ SPELL_DK_VENDETTA_HEAL = 50181,
+ SPELL_DK_NECROSIS_DAMAGE = 51460,
+ SPELL_DK_OBLITERATE_OFF_HAND_R1 = 66198,
+ SPELL_DK_FROST_STRIKE_OFF_HAND_R1 = 66196,
+ SPELL_DK_PLAGUE_STRIKE_OFF_HAND_R1 = 66216,
+ SPELL_DK_DEATH_STRIKE_OFF_HAND_R1 = 66188,
+ SPELL_DK_RUNE_STRIKE_OFF_HAND_R1 = 66217,
+ SPELL_DK_BLOOD_STRIKE_OFF_HAND_R1 = 66215,
+ SPELL_DK_RUNIC_RETURN = 61258,
+ SPELL_DK_WANDERING_PLAGUE_DAMAGE = 50526,
+ SPELL_DK_DEATH_COIL_R1 = 47541,
+ SPELL_DK_DEATH_GRIP_INITIAL = 49576
};
enum DeathKnightSpellIcons
@@ -83,7 +100,9 @@ enum DeathKnightSpellIcons
enum Misc
{
- NPC_DK_GHOUL = 26125
+ NPC_DK_GHOUL = 26125,
+ NPC_DK_DANCING_RUNE_WEAPON = 27893,
+ SPELL_CATEGORY_HOWLING_BLAST = 1248
};
// -49200 - Acclimation
@@ -110,9 +129,9 @@ public:
bool CheckProc(ProcEventInfo& eventInfo)
{
- if (eventInfo.GetDamageInfo())
+ if (DamageInfo* damageInfo = eventInfo.GetDamageInfo())
{
- switch (GetFirstSchoolInMask(eventInfo.GetDamageInfo()->GetSchoolMask()))
+ switch (GetFirstSchoolInMask(damageInfo->GetSchoolMask()))
{
case SPELL_SCHOOL_HOLY:
case SPELL_SCHOOL_FIRE:
@@ -393,6 +412,38 @@ class spell_dk_anti_magic_zone : public SpellScriptLoader
}
};
+// -49182 - Blade Barrier
+class spell_dk_blade_barrier : public SpellScriptLoader
+{
+ public:
+ spell_dk_blade_barrier() : SpellScriptLoader("spell_dk_blade_barrier") { }
+
+ class spell_dk_blade_barrier_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_blade_barrier_AuraScript);
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (eventInfo.GetSpellInfo() != nullptr)
+ if (Player* player = eventInfo.GetActor()->ToPlayer())
+ if (player->getClass() == CLASS_DEATH_KNIGHT && player->IsBaseRuneSlotsOnCooldown(RUNE_BLOOD))
+ return true;
+
+ return false;
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_dk_blade_barrier_AuraScript::CheckProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_blade_barrier_AuraScript();
+ }
+};
+
// 48721 - Blood Boil
class spell_dk_blood_boil : public SpellScriptLoader
{
@@ -478,8 +529,12 @@ class spell_dk_blood_gorged : public SpellScriptLoader
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- int32 bp = int32(eventInfo.GetDamageInfo()->GetDamage() * 1.5f);
- GetTarget()->CastCustomSpell(SPELL_DK_BLOOD_GORGED_HEAL, SPELLVALUE_BASE_POINT0, bp, _procTarget, true, NULL, aurEff);
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 bp = static_cast<int32>(damageInfo->GetDamage() * 1.5f);
+ GetTarget()->CastCustomSpell(SPELL_DK_BLOOD_GORGED_HEAL, SPELLVALUE_BASE_POINT0, bp, _procTarget, true, nullptr, aurEff);
}
void Register() override
@@ -525,6 +580,41 @@ class spell_dk_bloodworms : public SpellScriptLoader
}
};
+// -48979 - Butchery
+class spell_dk_butchery : public SpellScriptLoader
+{
+ public:
+ spell_dk_butchery() : SpellScriptLoader("spell_dk_butchery") { }
+
+ class spell_dk_butchery_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_butchery_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_BUTCHERY_RUNIC_POWER))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastCustomSpell(SPELL_DK_BUTCHERY_RUNIC_POWER, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dk_butchery_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_butchery_AuraScript();
+ }
+};
+
class CorpseExplosionCheck
{
public:
@@ -649,6 +739,69 @@ class spell_dk_corpse_explosion : public SpellScriptLoader
}
};
+// 49028 - Dancing Rune Weapon
+class spell_dk_dancing_rune_weapon : public SpellScriptLoader
+{
+ public:
+ spell_dk_dancing_rune_weapon() : SpellScriptLoader("spell_dk_dancing_rune_weapon") { }
+
+ class spell_dk_dancing_rune_weapon_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_dancing_rune_weapon_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sObjectMgr->GetCreatureTemplate(NPC_DK_DANCING_RUNE_WEAPON))
+ return false;
+ return true;
+ }
+
+ // This is a port of the old switch hack in Unit.cpp, it's not correct
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = GetCaster();
+ if (!caster)
+ return;
+
+ Unit* drw = nullptr;
+ for (Unit* controlled : caster->m_Controlled)
+ {
+ if (controlled->GetEntry() == NPC_DK_DANCING_RUNE_WEAPON)
+ {
+ drw = controlled;
+ break;
+ }
+ }
+
+ if (!drw || !drw->GetVictim())
+ return;
+
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return;
+
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 amount = static_cast<int32>(damageInfo->GetDamage()) / 2;
+ drw->SendSpellNonMeleeDamageLog(drw->GetVictim(), spellInfo->Id, amount, spellInfo->GetSchoolMask(), 0, 0, false, 0, false);
+ drw->DealDamage(drw->GetVictim(), amount, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dk_dancing_rune_weapon_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_dancing_rune_weapon_AuraScript();
+ }
+};
+
class spell_dk_death_and_decay : public SpellScriptLoader
{
public:
@@ -874,6 +1027,84 @@ class spell_dk_death_pact : public SpellScriptLoader
}
};
+// -54639 - Blood of the North
+// -49208 - Reaping
+// -49467 - Death Rune Mastery
+class spell_dk_death_rune : public SpellScriptLoader
+{
+ public:
+ spell_dk_death_rune() : SpellScriptLoader("spell_dk_death_rune") { }
+
+ class spell_dk_death_rune_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_death_rune_AuraScript);
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ Unit* caster = eventInfo.GetActor();
+
+ if (caster->GetTypeId() != TYPEID_PLAYER)
+ return false;
+
+ Player* player = caster->ToPlayer();
+ if (player->getClass() != CLASS_DEATH_KNIGHT)
+ return false;
+
+ return true;
+ }
+
+ void HandleProc(ProcEventInfo& eventInfo)
+ {
+ Player* player = eventInfo.GetActor()->ToPlayer();
+
+ AuraEffect* aurEff = GetEffect(EFFECT_0);
+ if (!aurEff)
+ return;
+
+ // Reset amplitude - set death rune remove timer to 30s
+ aurEff->ResetPeriodic(true);
+
+ uint32 runesLeft = 1;
+
+ // Death Rune Mastery
+ if (GetSpellInfo()->SpellIconID == 2622)
+ runesLeft = 2;
+
+ for (uint8 i = 0; i < MAX_RUNES && runesLeft; ++i)
+ {
+ if (GetSpellInfo()->SpellIconID == 2622)
+ {
+ if (player->GetBaseRune(i) == RUNE_BLOOD)
+ continue;
+ }
+ else
+ {
+ if (player->GetBaseRune(i) != RUNE_BLOOD)
+ continue;
+ }
+
+ if (player->GetRuneCooldown(i) != (player->GetRuneBaseCooldown(i) - player->GetLastRuneGraceTimer(i)))
+ continue;
+
+ --runesLeft;
+ // Mark aura as used
+ player->AddRuneByAuraEffect(i, RUNE_DEATH, aurEff);
+ }
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_dk_death_rune_AuraScript::CheckProc);
+ OnProc += AuraProcFn(spell_dk_death_rune_AuraScript::HandleProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_death_rune_AuraScript();
+ }
+};
+
// -49998 - Death Strike
class spell_dk_death_strike : public SpellScriptLoader
{
@@ -966,6 +1197,116 @@ class spell_dk_ghoul_explode : public SpellScriptLoader
}
};
+// 62259 - Glyph of Death Grip
+class spell_dk_glyph_of_death_grip : public SpellScriptLoader
+{
+ public:
+ spell_dk_glyph_of_death_grip() : SpellScriptLoader("spell_dk_glyph_of_death_grip") { }
+
+ class spell_dk_glyph_of_death_grip_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_glyph_of_death_grip_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_DEATH_GRIP_INITIAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->GetSpellHistory()->ResetCooldown(SPELL_DK_DEATH_GRIP_INITIAL, true);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dk_glyph_of_death_grip_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_glyph_of_death_grip_AuraScript();
+ }
+};
+
+// 58642 - Glyph of Scourge Strike
+class spell_dk_glyph_of_scourge_strike : public SpellScriptLoader
+{
+ public:
+ spell_dk_glyph_of_scourge_strike() : SpellScriptLoader("spell_dk_glyph_of_scourge_strike") { }
+
+ class spell_dk_glyph_of_scourge_strike_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_glyph_of_scourge_strike_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dk_glyph_of_scourge_strike_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_glyph_of_scourge_strike_AuraScript();
+ }
+};
+
+// 51209 - Hungering Cold
+class spell_dk_hungering_cold : public SpellScriptLoader
+{
+ public:
+ spell_dk_hungering_cold() : SpellScriptLoader("spell_dk_hungering_cold") { }
+
+ class spell_dk_hungering_cold_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_hungering_cold_AuraScript);
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo) // probably melee damage so let's proc
+ return true;
+
+ return (spellInfo->Dispel != DISPEL_DISEASE);
+ }
+
+ void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ // Prevent console spam
+ PreventDefaultAction();
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_dk_hungering_cold_AuraScript::CheckProc);
+
+ OnEffectProc += AuraEffectProcFn(spell_dk_hungering_cold_AuraScript::HandleDummy, EFFECT_1, SPELL_AURA_DUMMY);
+ OnEffectProc += AuraEffectProcFn(spell_dk_hungering_cold_AuraScript::HandleDummy, EFFECT_2, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_hungering_cold_AuraScript();
+ }
+};
+
// 48792 - Icebound Fortitude
class spell_dk_icebound_fortitude : public SpellScriptLoader
{
@@ -1049,10 +1390,18 @@ class spell_dk_improved_blood_presence : public SpellScriptLoader
target->RemoveAura(SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED);
}
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ // Prevent console spam
+ PreventDefaultAction();
+ }
+
void Register() override
{
AfterEffectApply += AuraEffectApplyFn(spell_dk_improved_blood_presence_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
AfterEffectRemove += AuraEffectRemoveFn(spell_dk_improved_blood_presence_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+
+ OnEffectProc += AuraEffectProcFn(spell_dk_improved_blood_presence_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
@@ -1091,7 +1440,7 @@ public:
{
PreventDefaultAction();
if (DamageInfo* dmgInfo = eventInfo.GetDamageInfo())
- eventInfo.GetActor()->CastCustomSpell(SPELL_DK_IMPROVED_BLOOD_PRESENCE_HEAL, SPELLVALUE_BASE_POINT0, CalculatePct(int32(dmgInfo->GetDamage()), aurEff->GetAmount()),
+ eventInfo.GetActor()->CastCustomSpell(SPELL_DK_IMPROVED_BLOOD_PRESENCE_HEAL, SPELLVALUE_BASE_POINT0, CalculatePct(static_cast<int32>(dmgInfo->GetDamage()), aurEff->GetAmount()),
eventInfo.GetActor(), true, nullptr, aurEff);
}
@@ -1213,6 +1562,127 @@ class spell_dk_improved_unholy_presence : public SpellScriptLoader
}
};
+// 61257 - Runic Power Back on Snare/Root
+class spell_dk_pvp_4p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_dk_pvp_4p_bonus() : SpellScriptLoader("spell_dk_pvp_4p_bonus") { }
+
+ class spell_dk_pvp_4p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_pvp_4p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_RUNIC_RETURN))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return false;
+
+ return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_SNARE))) != 0;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActionTarget()->CastSpell((Unit*)nullptr, SPELL_DK_RUNIC_RETURN, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_dk_pvp_4p_bonus_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_dk_pvp_4p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_pvp_4p_bonus_AuraScript();
+ }
+};
+
+// 49005 - Mark of Blood
+class spell_dk_mark_of_blood : public SpellScriptLoader
+{
+ public:
+ spell_dk_mark_of_blood() : SpellScriptLoader("spell_dk_mark_of_blood") { }
+
+ class spell_dk_mark_of_blood_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_mark_of_blood_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_MARK_OF_BLOOD_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_MARK_OF_BLOOD_HEAL, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dk_mark_of_blood_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_mark_of_blood_AuraScript();
+ }
+};
+
+// -51459 - Necrosis
+class spell_dk_necrosis : public SpellScriptLoader
+{
+ public:
+ spell_dk_necrosis() : SpellScriptLoader("spell_dk_necrosis") { }
+
+ class spell_dk_necrosis_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_necrosis_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_NECROSIS_DAMAGE))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
+ eventInfo.GetActor()->CastCustomSpell(SPELL_DK_NECROSIS_DAMAGE, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dk_necrosis_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_necrosis_AuraScript();
+ }
+};
+
// ID - 50842 Pestilence
class spell_dk_pestilence : public SpellScriptLoader
{
@@ -1565,6 +2035,71 @@ class spell_dk_raise_dead : public SpellScriptLoader
}
};
+// -49188 - Rime
+class spell_dk_rime : public SpellScriptLoader
+{
+ public:
+ spell_dk_rime() : SpellScriptLoader("spell_dk_rime") { }
+
+ class spell_dk_blade_barrier_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_blade_barrier_AuraScript);
+
+ bool CheckProc(ProcEventInfo& /*eventInfo*/)
+ {
+ return GetTarget()->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ GetTarget()->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
+ {
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
+ return spellInfo && spellInfo->GetCategory() == SPELL_CATEGORY_HOWLING_BLAST;
+ }, true);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_dk_blade_barrier_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_dk_blade_barrier_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_blade_barrier_AuraScript();
+ }
+};
+
+// 56817 - Rune strike proc (Serverside spell)
+class spell_dk_rune_strike_proc : public SpellScriptLoader
+{
+ public:
+ spell_dk_rune_strike_proc() : SpellScriptLoader("spell_dk_rune_strike_proc") { }
+
+ class spell_dk_rune_strike_proc_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_rune_strike_proc_AuraScript);
+
+ void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ // Prevent console log
+ PreventDefaultAction();
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dk_rune_strike_proc_AuraScript::HandleDummy, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_rune_strike_proc_AuraScript();
+ }
+};
+
// 59754 Rune Tap - Party
class spell_dk_rune_tap_party : public SpellScriptLoader
{
@@ -1613,7 +2148,7 @@ class spell_dk_scent_of_blood : public SpellScriptLoader
{
PreventDefaultAction();
GetTarget()->CastSpell(GetTarget(), SPELL_DK_SCENT_OF_BLOOD, true, NULL, aurEff);
- GetTarget()->RemoveAuraFromStack(GetSpellInfo()->Id);
+ ModStackAmount(-1);
}
void Register() override
@@ -1628,6 +2163,37 @@ class spell_dk_scent_of_blood : public SpellScriptLoader
}
};
+// -49004 - Scent of Blood trigger
+class spell_dk_scent_of_blood_trigger : public SpellScriptLoader
+{
+ public:
+ spell_dk_scent_of_blood_trigger() : SpellScriptLoader("spell_dk_scent_of_blood_trigger") { }
+
+ class spell_dk_scent_of_blood_trigger_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_scent_of_blood_trigger_AuraScript);
+
+ // Each rank of Scent of Blood adds a trigger spell effect
+ // thus each effect adds one stack when proccing
+ // We need to remove the old buff before proccing again
+ // or we would be adding stacks to a possibly existing aura
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ GetTarget()->RemoveAurasDueToSpell(GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dk_scent_of_blood_trigger_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_scent_of_blood_trigger_AuraScript();
+ }
+};
+
// 55090 - Scourge Strike (55265, 55270, 55271)
class spell_dk_scourge_strike : public SpellScriptLoader
{
@@ -1727,7 +2293,7 @@ class spell_dk_spell_deflection : public SpellScriptLoader
void Absorb(AuraEffect* /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount)
{
// You have a chance equal to your Parry chance
- if ((dmgInfo.GetDamageType() == SPELL_DIRECT_DAMAGE) && roll_chance_f(GetTarget()->GetUnitParryChance()))
+ if ((dmgInfo.GetDamageType() == SPELL_DIRECT_DAMAGE) && roll_chance_f(GetTarget()->GetFloatValue(PLAYER_PARRY_PERCENTAGE)))
absorbAmount = CalculatePct(dmgInfo.GetDamage(), absorbPct);
}
@@ -1744,6 +2310,188 @@ class spell_dk_spell_deflection : public SpellScriptLoader
}
};
+// -49018 - Sudden Doom
+class spell_dk_sudden_doom : public SpellScriptLoader
+{
+ public:
+ spell_dk_sudden_doom() : SpellScriptLoader("spell_dk_sudden_doom") { }
+
+ class spell_dk_sudden_doom_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_sudden_doom_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_DEATH_COIL_R1))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = eventInfo.GetActor();
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DK_DEATH_COIL_R1);
+ uint32 spellId = 0;
+
+ while (spellInfo)
+ {
+ if (!caster->HasSpell(spellInfo->Id))
+ break;
+
+ spellId = spellInfo->Id;
+ spellInfo = spellInfo->GetNextRankSpell();
+ }
+
+ if (!spellId)
+ return;
+
+ caster->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dk_sudden_doom_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_sudden_doom_AuraScript();
+ }
+};
+
+// -65661 Threat of Thassarian
+class spell_dk_threat_of_thassarian : public SpellScriptLoader
+{
+ public:
+ spell_dk_threat_of_thassarian() : SpellScriptLoader("spell_dk_threat_of_thassarian") { }
+
+ class spell_dk_threat_of_thassarian_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_threat_of_thassarian_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_OBLITERATE_OFF_HAND_R1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DK_FROST_STRIKE_OFF_HAND_R1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DK_PLAGUE_STRIKE_OFF_HAND_R1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DK_DEATH_STRIKE_OFF_HAND_R1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DK_RUNE_STRIKE_OFF_HAND_R1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DK_BLOOD_STRIKE_OFF_HAND_R1))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ if (!roll_chance_i(aurEff->GetAmount()))
+ return;
+
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return;
+
+ // Must dual wield
+ Unit* caster = eventInfo.GetActor();
+ if (!caster->haveOffhandWeapon())
+ return;
+
+ uint32 spellId = 0;
+ // Plague Strike
+ if (spellInfo->SpellFamilyFlags[0] & 0x00000001)
+ spellId = SPELL_DK_PLAGUE_STRIKE_OFF_HAND_R1;
+ // Death Strike
+ else if (spellInfo->SpellFamilyFlags[0] & 0x00000010)
+ spellId = SPELL_DK_DEATH_STRIKE_OFF_HAND_R1;
+ // Blood Strike
+ else if (spellInfo->SpellFamilyFlags[0] & 0x00400000)
+ spellId = SPELL_DK_BLOOD_STRIKE_OFF_HAND_R1;
+ // Frost Strike
+ else if (spellInfo->SpellFamilyFlags[1] & 0x00000004)
+ spellId = SPELL_DK_FROST_STRIKE_OFF_HAND_R1;
+ // Obliterate
+ else if (spellInfo->SpellFamilyFlags[1] & 0x00020000)
+ spellId = SPELL_DK_OBLITERATE_OFF_HAND_R1;
+ // Rune Strike
+ else if (spellInfo->SpellFamilyFlags[1] & 0x20000000)
+ spellId = SPELL_DK_RUNE_STRIKE_OFF_HAND_R1;
+
+ if (!spellId)
+ return;
+
+ spellId = sSpellMgr->GetSpellWithRank(spellId, spellInfo->GetRank());
+ caster->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dk_threat_of_thassarian_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_threat_of_thassarian_AuraScript();
+ }
+};
+
+// 49194 - Unholy Blight
+class spell_dk_unholy_blight : public SpellScriptLoader
+{
+ public:
+ spell_dk_unholy_blight() : SpellScriptLoader("spell_dk_unholy_blight") { }
+
+ class spell_dk_unholy_blight_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_unholy_blight_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_UNHOLY_BLIGHT_DAMAGE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DK_GLYPH_OF_UNHOLY_BLIGHT))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DK_UNHOLY_BLIGHT_DAMAGE);
+ int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
+ if (AuraEffect const* glyph = caster->GetAuraEffect(SPELL_DK_GLYPH_OF_UNHOLY_BLIGHT, EFFECT_0, caster->GetGUID()))
+ AddPct(amount, glyph->GetAmount());
+
+ amount /= spellInfo->GetMaxTicks();
+
+ // Add remaining ticks to healing done
+ amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_DK_UNHOLY_BLIGHT_DAMAGE, SPELL_AURA_PERIODIC_DAMAGE);
+
+ caster->CastCustomSpell(SPELL_DK_UNHOLY_BLIGHT_DAMAGE, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dk_unholy_blight_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_unholy_blight_AuraScript();
+ }
+};
// 55233 - Vampiric Blood
class spell_dk_vampiric_blood : public SpellScriptLoader
{
@@ -1771,6 +2519,88 @@ class spell_dk_vampiric_blood : public SpellScriptLoader
}
};
+// -49015 - Vendetta
+class spell_dk_vendetta : public SpellScriptLoader
+{
+ public:
+ spell_dk_vendetta() : SpellScriptLoader("spell_dk_vendetta") { }
+
+ class spell_dk_vendetta_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_vendetta_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_VENDETTA_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ int32 amount = caster->CountPctFromMaxHealth(aurEff->GetAmount());
+ caster->CastCustomSpell(SPELL_DK_VENDETTA_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dk_vendetta_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_vendetta_AuraScript();
+ }
+};
+
+// -49217 - Wandering Plague
+class spell_dk_wandering_plague : public SpellScriptLoader
+{
+ public:
+ spell_dk_wandering_plague() : SpellScriptLoader("spell_dk_wandering_plague") { }
+
+ class spell_dk_wandering_plague_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_wandering_plague_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_WANDERING_PLAGUE_DAMAGE))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+ if (!roll_chance_f(caster->GetUnitCriticalChance(BASE_ATTACK, target)))
+ return;
+
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
+ caster->CastCustomSpell(SPELL_DK_WANDERING_PLAGUE_DAMAGE, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dk_wandering_plague_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_wandering_plague_AuraScript();
+ }
+};
+
// 52284 - Will of the Necropolis
class spell_dk_will_of_the_necropolis : public SpellScriptLoader
{
@@ -1971,17 +2801,25 @@ public:
class player_ghoulAI : public PlayerAI
{
public:
- player_ghoulAI(Player* player, ObjectGuid ghoulGUID) : PlayerAI(player), _ghoulGUID(ghoulGUID) { }
+ player_ghoulAI(Player* player, ObjectGuid ghoulGUID) : PlayerAI(player), _ghoulGUID(ghoulGUID), _ghoulCheckTimer(1000){ }
- void UpdateAI(uint32 /*diff*/) override
+ void UpdateAI(uint32 diff) override
{
- Creature* ghoul = ObjectAccessor::GetCreature(*me, _ghoulGUID);
- if (!ghoul || !ghoul->IsAlive())
- me->RemoveAura(SPELL_DK_RAISE_ALLY);
+ if (_ghoulCheckTimer <= diff)
+ {
+ _ghoulCheckTimer = 1000;
+
+ Creature* ghoul = ObjectAccessor::GetCreature(*me, _ghoulGUID);
+ if (!ghoul || !ghoul->IsAlive())
+ me->RemoveAura(SPELL_DK_RAISE_ALLY);
+ }
+ else
+ _ghoulCheckTimer -= diff;
}
private:
ObjectGuid _ghoulGUID;
+ uint32 _ghoulCheckTimer;
};
// 46619 - Raise Ally
@@ -2003,7 +2841,7 @@ public:
void SendText()
{
if (Unit* original = GetOriginalCaster())
- original->Whisper(TEXT_RISE_ALLY, GetCaster()->ToPlayer(), true);
+ original->Unit::Whisper(TEXT_RISE_ALLY, GetCaster()->ToPlayer(), true);
}
void HandleSummon(SpellEffIndex effIndex)
@@ -2200,30 +3038,48 @@ void AddSC_deathknight_spell_scripts()
new spell_dk_anti_magic_shell_raid();
new spell_dk_anti_magic_shell_self();
new spell_dk_anti_magic_zone();
+ new spell_dk_blade_barrier();
new spell_dk_blood_boil();
new spell_dk_blood_gorged();
new spell_dk_bloodworms();
+ new spell_dk_butchery();
new spell_dk_corpse_explosion();
+ new spell_dk_dancing_rune_weapon();
new spell_dk_death_and_decay();
new spell_dk_death_coil();
new spell_dk_death_gate();
new spell_dk_death_grip();
new spell_dk_death_pact();
+ new spell_dk_death_rune();
new spell_dk_death_strike();
new spell_dk_ghoul_explode();
+ new spell_dk_glyph_of_death_grip();
+ new spell_dk_glyph_of_scourge_strike();
+ new spell_dk_hungering_cold();
new spell_dk_icebound_fortitude();
new spell_dk_improved_blood_presence();
new spell_dk_improved_blood_presence_triggered();
new spell_dk_improved_frost_presence();
new spell_dk_improved_unholy_presence();
+ new spell_dk_pvp_4p_bonus();
+ new spell_dk_mark_of_blood();
+ new spell_dk_necrosis();
new spell_dk_pestilence();
new spell_dk_presence();
new spell_dk_raise_dead();
+ new spell_dk_rime();
+ new spell_dk_rune_strike_proc();
new spell_dk_rune_tap_party();
new spell_dk_scent_of_blood();
+ new spell_dk_scent_of_blood_trigger();
new spell_dk_scourge_strike();
new spell_dk_spell_deflection();
+ new spell_dk_sudden_doom();
+ new spell_dk_threat_of_thassarian();
+ new spell_dk_unholy_blight();
new spell_dk_vampiric_blood();
+ new spell_dk_vendetta();
+ new spell_dk_wandering_plague();
new spell_dk_will_of_the_necropolis();
new spell_dk_death_grip_initial();
new spell_dk_raise_ally_initial();
diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp
index 0bf5ab01f45..56624346772 100644
--- a/src/server/scripts/Spells/spell_druid.cpp
+++ b/src/server/scripts/Spells/spell_druid.cpp
@@ -57,7 +57,68 @@ enum DruidSpells
SPELL_DRUID_SAVAGE_ROAR = 62071,
SPELL_DRUID_T9_FERAL_RELIC_BEAR = 67354,
SPELL_DRUID_T9_FERAL_RELIC_CAT = 67355,
- SPELL_DRUID_TIGER_S_FURY_ENERGIZE = 51178
+ SPELL_DRUID_TIGER_S_FURY_ENERGIZE = 51178,
+ SPELL_DRUID_T3_PROC_ENERGIZE_MANA = 28722,
+ SPELL_DRUID_T3_PROC_ENERGIZE_RAGE = 28723,
+ SPELL_DRUID_T3_PROC_ENERGIZE_ENERGY = 28724,
+ SPELL_DRUID_BLESSING_OF_THE_CLAW = 28750,
+ SPELL_DRUID_REVITALIZE_ENERGIZE_MANA = 48542,
+ SPELL_DRUID_REVITALIZE_ENERGIZE_RAGE = 48541,
+ SPELL_DRUID_REVITALIZE_ENERGIZE_ENERGY = 48540,
+ SPELL_DRUID_REVITALIZE_ENERGIZE_RP = 48543,
+ SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN = 54833,
+ SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT = 54846,
+ SPELL_DRUID_GLYPH_OF_RIP = 54818,
+ SPELL_DRUID_RIP_DURATION_LACERATE_DMG = 60141,
+ SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED = 54820,
+ SPELL_DRUID_IMP_LEADER_OF_THE_PACK_R1 = 34297,
+ SPELL_DRUID_IMP_LEADER_OF_THE_PACK_HEAL = 34299,
+ SPELL_DRUID_IMP_LEADER_OF_THE_PACK_MANA = 68285,
+ SPELL_DRUID_EXHILARATE = 28742,
+ SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL = 54755,
+ SPELL_DRUID_INFUSION = 37238,
+ SPELL_DRUID_BLESSING_OF_REMULOS = 40445,
+ SPELL_DRUID_BLESSING_OF_ELUNE = 40446,
+ SPELL_DRUID_BLESSING_OF_CENARIUS = 40452,
+ SPELL_DRUID_LANGUISH = 71023,
+ SPELL_DRUID_REJUVENATION_T10_PROC = 70691,
+ SPELL_DRUID_BALANCE_T10_BONUS = 70718,
+ SPELL_DRUID_BALANCE_T10_BONUS_PROC = 70721,
+ SPELL_DRUID_BARKSKIN_01 = 63058
+};
+
+// 22812 - Barkskin
+class spell_dru_barkskin : public SpellScriptLoader
+{
+ public:
+ spell_dru_barkskin() : SpellScriptLoader("spell_dru_barkskin") { }
+
+ class spell_dru_barkskin_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_barkskin_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_BARKSKIN_01))
+ return false;
+ return true;
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ GetTarget()->RemoveAurasDueToSpell(SPELL_DRUID_BARKSKIN_01);
+ }
+
+ void Register() override
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_dru_barkskin_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_barkskin_AuraScript();
+ }
};
// 1178 - Bear Form (Passive)
@@ -140,67 +201,90 @@ class spell_dru_dash : public SpellScriptLoader
}
};
+// -48516 - Eclipse
class spell_dru_eclipse : public SpellScriptLoader
{
-public:
- spell_dru_eclipse() : SpellScriptLoader("spell_dru_eclipse") { }
-
- class spell_dru_eclipse_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_dru_eclipse_AuraScript);
+ public:
+ spell_dru_eclipse() : SpellScriptLoader("spell_dru_eclipse") { }
- bool Validate(SpellInfo const* /*spellInfo*/) override
+ class spell_dru_eclipse_AuraScript : public AuraScript
{
- if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_ECLIPSE_LUNAR_PROC))
- return false;
- if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_ECLIPSE_SOLAR_PROC))
- return false;
- return true;
- }
+ PrepareAuraScript(spell_dru_eclipse_AuraScript);
- bool CheckProc(ProcEventInfo& eventInfo)
- {
- if (!eventInfo.GetSpellInfo())
- return false;
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_ECLIPSE_LUNAR_PROC))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_ECLIPSE_SOLAR_PROC))
+ return false;
+ return true;
+ }
- if (eventInfo.GetActor()->HasAura(SPELL_DRUID_ECLIPSE_LUNAR_PROC) || eventInfo.GetActor()->HasAura(SPELL_DRUID_ECLIPSE_SOLAR_PROC))
- return false;
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (eventInfo.GetActor()->HasAura(SPELL_DRUID_ECLIPSE_LUNAR_PROC) || eventInfo.GetActor()->HasAura(SPELL_DRUID_ECLIPSE_SOLAR_PROC))
+ return false;
- // Triggered by Wrath?
- if (eventInfo.GetSpellInfo()->SpellFamilyFlags[0] & 1)
- return roll_chance_f(GetSpellInfo()->ProcChance * 0.6f) && _lunarProcCooldownEnd <= std::chrono::steady_clock::now();
+ return true;
+ }
- return _solarProcCooldownEnd <= std::chrono::steady_clock::now();
- }
+ bool CheckSolar(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo || !(spellInfo->SpellFamilyFlags[0] & 4)) // Starfire
+ return false;
- void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
- {
- if (eventInfo.GetSpellInfo()->SpellFamilyFlags[0] & 1)
+ return _solarProcCooldownEnd <= std::chrono::steady_clock::now();
+ }
+
+ bool CheckLunar(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
- _lunarProcCooldownEnd = std::chrono::steady_clock::now() + Seconds(aurEff->GetAmount());
- eventInfo.GetActor()->CastSpell(eventInfo.GetActor(), SPELL_DRUID_ECLIPSE_LUNAR_PROC, TRIGGERED_FULL_MASK, nullptr, aurEff);
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo || !(spellInfo->SpellFamilyFlags[0] & 1)) // Wrath
+ return false;
+
+ // Reduced lunar proc chance (60% of normal)
+ if (!roll_chance_i(60))
+ return false;
+
+ return _lunarProcCooldownEnd <= std::chrono::steady_clock::now();
}
- else
+
+ void ProcSolar(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
- _solarProcCooldownEnd = std::chrono::steady_clock::now() + Seconds(aurEff->GetAmount());
+ PreventDefaultAction();
+
+ _solarProcCooldownEnd = std::chrono::steady_clock::now() + Seconds(30);
eventInfo.GetActor()->CastSpell(eventInfo.GetActor(), SPELL_DRUID_ECLIPSE_SOLAR_PROC, TRIGGERED_FULL_MASK, nullptr, aurEff);
}
- }
- void Register() override
- {
- DoCheckProc += AuraCheckProcFn(spell_dru_eclipse_AuraScript::CheckProc);
- OnEffectProc += AuraEffectProcFn(spell_dru_eclipse_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
- }
+ void ProcLunar(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
- std::chrono::steady_clock::time_point _lunarProcCooldownEnd = std::chrono::steady_clock::time_point::min();
- std::chrono::steady_clock::time_point _solarProcCooldownEnd = std::chrono::steady_clock::time_point::min();
- };
+ _lunarProcCooldownEnd = std::chrono::steady_clock::now() + Seconds(30);
+ eventInfo.GetActor()->CastSpell(eventInfo.GetActor(), SPELL_DRUID_ECLIPSE_LUNAR_PROC, TRIGGERED_FULL_MASK, nullptr, aurEff);
+ }
- AuraScript* GetAuraScript() const override
- {
- return new spell_dru_eclipse_AuraScript();
- }
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_dru_eclipse_AuraScript::CheckProc);
+
+ DoCheckEffectProc += AuraCheckEffectProcFn(spell_dru_eclipse_AuraScript::CheckSolar, EFFECT_0, SPELL_AURA_DUMMY);
+ DoCheckEffectProc += AuraCheckEffectProcFn(spell_dru_eclipse_AuraScript::CheckLunar, EFFECT_1, SPELL_AURA_DUMMY);
+
+ OnEffectProc += AuraEffectProcFn(spell_dru_eclipse_AuraScript::ProcSolar, EFFECT_0, SPELL_AURA_DUMMY);
+ OnEffectProc += AuraEffectProcFn(spell_dru_eclipse_AuraScript::ProcLunar, EFFECT_1, SPELL_AURA_DUMMY);
+ }
+
+ std::chrono::steady_clock::time_point _lunarProcCooldownEnd = std::chrono::steady_clock::time_point::min();
+ std::chrono::steady_clock::time_point _solarProcCooldownEnd = std::chrono::steady_clock::time_point::min();
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_eclipse_AuraScript();
+ }
};
// 5229 - Enrage
@@ -354,6 +438,259 @@ public:
}
};
+// -33943 - Flight Form
+class spell_dru_flight_form : public SpellScriptLoader
+{
+ public:
+ spell_dru_flight_form() : SpellScriptLoader("spell_dru_flight_form") { }
+
+ class spell_dru_flight_form_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_dru_flight_form_SpellScript);
+
+ SpellCastResult CheckCast()
+ {
+ Unit* caster = GetCaster();
+ if (caster->IsInDisallowedMountForm())
+ return SPELL_FAILED_NOT_SHAPESHIFT;
+
+ return SPELL_CAST_OK;
+ }
+
+ void Register() override
+ {
+ OnCheckCast += SpellCheckCastFn(spell_dru_flight_form_SpellScript::CheckCast);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_dru_flight_form_SpellScript();
+ }
+};
+
+// 63057 - Glyph of Barkskin
+class spell_dru_glyph_of_barkskin : public SpellScriptLoader
+{
+ public:
+ spell_dru_glyph_of_barkskin() : SpellScriptLoader("spell_dru_glyph_of_barkskin") { }
+
+ class spell_dru_glyph_of_barkskin_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_glyph_of_barkskin_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_BARKSKIN_01))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_DRUID_BARKSKIN_01, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_barkskin_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_glyph_of_barkskin_AuraScript();
+ }
+};
+
+// 54832 - Glyph of Innervate
+class spell_dru_glyph_of_innervate : public SpellScriptLoader
+{
+ public:
+ spell_dru_glyph_of_innervate() : SpellScriptLoader("spell_dru_glyph_of_innervate") { }
+
+ class spell_dru_glyph_of_innervate_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_glyph_of_innervate_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = eventInfo.GetActor();
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN);
+ int32 amount = CalculatePct(static_cast<int32>(caster->GetCreatePowers(POWER_MANA)), aurEff->GetAmount());
+ amount /= spellInfo->GetMaxTicks();
+
+ caster->CastCustomSpell(SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_innervate_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_glyph_of_innervate_AuraScript();
+ }
+};
+
+// 54821 - Glyph of Rake
+class spell_dru_glyph_of_rake : public SpellScriptLoader
+{
+ public:
+ spell_dru_glyph_of_rake() : SpellScriptLoader("spell_dru_glyph_of_rake") { }
+
+ class spell_dru_glyph_of_rake_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_glyph_of_rake_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ return eventInfo.GetProcTarget()->GetTypeId() == TYPEID_UNIT;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_dru_glyph_of_rake_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_rake_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_glyph_of_rake_AuraScript();
+ }
+};
+
+// 54754 - Glyph of Rejuvenation
+class spell_dru_glyph_of_rejuvenation : public SpellScriptLoader
+{
+ public:
+ spell_dru_glyph_of_rejuvenation() : SpellScriptLoader("spell_dru_glyph_of_rejuvenation") { }
+
+ class spell_dru_glyph_of_rejuvenation_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_glyph_of_rejuvenation_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ return eventInfo.GetProcTarget()->HealthBelowPct(50);
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
+ int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount());
+ eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_dru_glyph_of_rejuvenation_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_rejuvenation_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_glyph_of_rejuvenation_AuraScript();
+ }
+};
+
+// 54815 - Glyph of Shred
+class spell_dru_glyph_of_shred : public SpellScriptLoader
+{
+ public:
+ spell_dru_glyph_of_shred() : SpellScriptLoader("spell_dru_glyph_of_shred") { }
+
+ class spell_dru_glyph_of_shred_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_glyph_of_shred_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_GLYPH_OF_RIP) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DRUID_RIP_DURATION_LACERATE_DMG))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = eventInfo.GetActor();
+ // try to find spell Rip on the target
+ if (AuraEffect const* rip = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00800000, 0x0, 0x0, caster->GetGUID()))
+ {
+ // Rip's max duration, note: spells which modifies Rip's duration also counted like Glyph of Rip
+ uint32 countMin = rip->GetBase()->GetMaxDuration();
+
+ // just Rip's max duration without other spells
+ uint32 countMax = rip->GetSpellInfo()->GetMaxDuration();
+
+ // add possible auras' and Glyph of Shred's max duration
+ countMax += 3 * aurEff->GetAmount() * IN_MILLISECONDS; // Glyph of Shred -> +6 seconds
+ countMax += caster->HasAura(SPELL_DRUID_GLYPH_OF_RIP) ? 4 * IN_MILLISECONDS : 0; // Glyph of Rip -> +4 seconds
+ countMax += caster->HasAura(SPELL_DRUID_RIP_DURATION_LACERATE_DMG) ? 4 * IN_MILLISECONDS : 0; // T7 set bonus -> +4 seconds
+
+ // if min < max -> that means caster didn't cast 3 shred yet
+ // so set Rip's duration and max duration
+ if (countMin < countMax)
+ {
+ rip->GetBase()->SetDuration(rip->GetBase()->GetDuration() + aurEff->GetAmount() * IN_MILLISECONDS);
+ rip->GetBase()->SetMaxDuration(countMin + aurEff->GetAmount() * IN_MILLISECONDS);
+ }
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_shred_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_glyph_of_shred_AuraScript();
+ }
+};
+
// 54846 - Glyph of Starfire
class spell_dru_glyph_of_starfire : public SpellScriptLoader
{
@@ -375,6 +712,7 @@ class spell_dru_glyph_of_starfire : public SpellScriptLoader
{
Unit* caster = GetCaster();
if (Unit* unitTarget = GetHitUnit())
+ {
if (AuraEffect const* aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00000002, 0, 0, caster->GetGUID()))
{
Aura* aura = aurEff->GetBase();
@@ -392,6 +730,7 @@ class spell_dru_glyph_of_starfire : public SpellScriptLoader
aura->SetMaxDuration(countMin + 3000);
}
}
+ }
}
void Register() override
@@ -406,6 +745,41 @@ class spell_dru_glyph_of_starfire : public SpellScriptLoader
}
};
+// 54845 - Glyph of Starfire
+class spell_dru_glyph_of_starfire_dummy : public SpellScriptLoader
+{
+ public:
+ spell_dru_glyph_of_starfire_dummy() : SpellScriptLoader("spell_dru_glyph_of_starfire_dummy") { }
+
+ class spell_dru_glyph_of_starfire_dummy_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_glyph_of_starfire_dummy_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_starfire_dummy_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_glyph_of_starfire_dummy_AuraScript();
+ }
+};
+
// 34246 - Idol of the Emerald Queen
// 60779 - Idol of Lush Moss
class spell_dru_idol_lifebloom : public SpellScriptLoader
@@ -501,6 +875,65 @@ class spell_dru_insect_swarm : public SpellScriptLoader
}
};
+// 24932 - Leader of the Pack
+class spell_dru_leader_of_the_pack : public SpellScriptLoader
+{
+ public:
+ spell_dru_leader_of_the_pack() : SpellScriptLoader("spell_dru_leader_of_the_pack") { }
+
+ class spell_dru_leader_of_the_pack_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_leader_of_the_pack_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_IMP_LEADER_OF_THE_PACK_R1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DRUID_IMP_LEADER_OF_THE_PACK_HEAL) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DRUID_IMP_LEADER_OF_THE_PACK_MANA))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ if (!aurEff->GetAmount())
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ if (caster->GetSpellHistory()->HasCooldown(SPELL_DRUID_IMP_LEADER_OF_THE_PACK_HEAL))
+ return;
+
+ int32 amount = caster->CountPctFromMaxHealth(aurEff->GetAmount());
+ caster->CastCustomSpell(SPELL_DRUID_IMP_LEADER_OF_THE_PACK_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
+
+ // Because of how proc system works, we can't store proc cd on db, it would be applied to entire aura
+ // so aura could only proc once per 6 seconds, independently of caster
+ caster->GetSpellHistory()->AddCooldown(SPELL_DRUID_IMP_LEADER_OF_THE_PACK_HEAL, 0, Seconds(6));
+
+ // only proc on self
+ if (aurEff->GetCasterGUID() != caster->GetGUID())
+ return;
+
+ AuraEffect const* impLotpMana = caster->GetAuraEffectOfRankedSpell(SPELL_DRUID_IMP_LEADER_OF_THE_PACK_R1, EFFECT_0, aurEff->GetCasterGUID());
+ ASSERT(impLotpMana);
+
+ int32 manaAmount = CalculatePct(static_cast<int32>(caster->GetMaxPower(POWER_MANA)), impLotpMana->GetSpellInfo()->Effects[EFFECT_1].CalcValue());
+ caster->CastCustomSpell(SPELL_DRUID_IMP_LEADER_OF_THE_PACK_MANA, SPELLVALUE_BASE_POINT0, manaAmount, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dru_leader_of_the_pack_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_leader_of_the_pack_AuraScript();
+ }
+};
+
// -33763 - Lifebloom
class spell_dru_lifebloom : public SpellScriptLoader
{
@@ -603,8 +1036,13 @@ class spell_dru_living_seed : public SpellScriptLoader
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- int32 amount = CalculatePct(eventInfo.GetHealInfo()->GetHeal(), aurEff->GetAmount());
- GetTarget()->CastCustomSpell(SPELL_DRUID_LIVING_SEED_PROC, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, NULL, aurEff);
+
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
+ int32 amount = CalculatePct(healInfo->GetHeal(), aurEff->GetAmount());
+ GetTarget()->CastCustomSpell(SPELL_DRUID_LIVING_SEED_PROC, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, nullptr, aurEff);
}
void Register() override
@@ -705,6 +1143,43 @@ class spell_dru_moonkin_form_passive : public SpellScriptLoader
}
};
+// 16864 - Omen of Clarity
+class spell_dru_omen_of_clarity : public SpellScriptLoader
+{
+ public:
+ spell_dru_omen_of_clarity() : SpellScriptLoader("spell_dru_omen_of_clarity") { }
+
+ class spell_dru_omen_of_clarity_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_omen_of_clarity_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_BALANCE_T10_BONUS) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DRUID_BALANCE_T10_BONUS_PROC))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ Unit* target = GetTarget();
+ if (target->HasAura(SPELL_DRUID_BALANCE_T10_BONUS))
+ target->CastSpell((Unit*)nullptr, SPELL_DRUID_BALANCE_T10_BONUS_PROC, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dru_omen_of_clarity_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_omen_of_clarity_AuraScript();
+ }
+};
+
// 48391 - Owlkin Frenzy
class spell_dru_owlkin_frenzy : public SpellScriptLoader
{
@@ -812,6 +1287,68 @@ class spell_dru_primal_tenacity : public SpellScriptLoader
}
};
+// -48539 - Revitalize
+class spell_dru_revitalize : public SpellScriptLoader
+{
+ public:
+ spell_dru_revitalize() : SpellScriptLoader("spell_dru_revitalize") { }
+
+ class spell_dru_revitalize_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_revitalize_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_REVITALIZE_ENERGIZE_MANA) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DRUID_REVITALIZE_ENERGIZE_RAGE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DRUID_REVITALIZE_ENERGIZE_ENERGY) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DRUID_REVITALIZE_ENERGIZE_RP))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ if (!roll_chance_i(aurEff->GetAmount()))
+ return;
+
+ Unit* target = eventInfo.GetProcTarget();
+ uint32 spellId;
+
+ switch (target->getPowerType())
+ {
+ case POWER_MANA:
+ spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_MANA;
+ break;
+ case POWER_RAGE:
+ spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_RAGE;
+ break;
+ case POWER_ENERGY:
+ spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_ENERGY;
+ break;
+ case POWER_RUNIC_POWER:
+ spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_RP;
+ break;
+ default:
+ return;
+ }
+
+ eventInfo.GetActor()->CastSpell(target, spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dru_revitalize_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_revitalize_AuraScript();
+ }
+};
+
// -1079 - Rip
class spell_dru_rip : public SpellScriptLoader
{
@@ -860,7 +1397,7 @@ class spell_dru_rip : public SpellScriptLoader
}
};
-// 62606 - Savage Defense
+// 62600 - Savage Defense
class spell_dru_savage_defense : public SpellScriptLoader
{
public:
@@ -870,37 +1407,24 @@ class spell_dru_savage_defense : public SpellScriptLoader
{
PrepareAuraScript(spell_dru_savage_defense_AuraScript);
- public:
- spell_dru_savage_defense_AuraScript()
- {
- absorbPct = 0;
- }
-
- private:
- uint32 absorbPct;
-
- bool Load() override
+ bool Validate(SpellInfo const* spellInfo) override
{
- absorbPct = GetSpellInfo()->Effects[EFFECT_0].CalcValue(GetCaster());
+ if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell))
+ return false;
return true;
}
- void CalculateAmount(AuraEffect const* /*aurEff*/, int32 & amount, bool & /*canBeRecalculated*/)
- {
- // Set absorbtion amount to unlimited
- amount = -1;
- }
-
- void Absorb(AuraEffect* aurEff, DamageInfo & /*dmgInfo*/, uint32 & absorbAmount)
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
- absorbAmount = uint32(CalculatePct(GetTarget()->GetTotalAttackPowerValue(BASE_ATTACK), absorbPct));
- aurEff->SetAmount(0);
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ int32 amount = static_cast<int32>(CalculatePct(caster->GetTotalAttackPowerValue(BASE_ATTACK), aurEff->GetAmount()));
+ caster->CastCustomSpell(GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
}
void Register() override
{
- DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dru_savage_defense_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB);
- OnEffectAbsorb += AuraEffectAbsorbFn(spell_dru_savage_defense_AuraScript::Absorb, EFFECT_0);
+ OnEffectProc += AuraEffectProcFn(spell_dru_savage_defense_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
@@ -1088,7 +1612,7 @@ class spell_dru_survival_instincts : public SpellScriptLoader
{
Unit* target = GetTarget();
int32 bp0 = target->CountPctFromMaxHealth(aurEff->GetAmount());
- target->CastCustomSpell(target, SPELL_DRUID_SURVIVAL_INSTINCTS, &bp0, NULL, NULL, true);
+ target->CastCustomSpell(target, SPELL_DRUID_SURVIVAL_INSTINCTS, &bp0, nullptr, nullptr, true, nullptr, aurEff);
}
void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
@@ -1129,7 +1653,7 @@ class spell_dru_swift_flight_passive : public SpellScriptLoader
return GetCaster()->GetTypeId() == TYPEID_PLAYER;
}
- void CalculateAmount(AuraEffect const* /*aurEff*/, int32 & amount, bool & /*canBeRecalculated*/)
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool & /*canBeRecalculated*/)
{
if (Player* caster = GetCaster()->ToPlayer())
if (caster->Has310Flyer(false))
@@ -1148,37 +1672,6 @@ class spell_dru_swift_flight_passive : public SpellScriptLoader
}
};
-// -33943 - Flight Form
-class spell_dru_flight_form : public SpellScriptLoader
-{
- public:
- spell_dru_flight_form() : SpellScriptLoader("spell_dru_flight_form") { }
-
- class spell_dru_flight_form_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_dru_flight_form_SpellScript);
-
- SpellCastResult CheckCast()
- {
- Unit* caster = GetCaster();
- if (caster->IsInDisallowedMountForm())
- return SPELL_FAILED_NOT_SHAPESHIFT;
-
- return SPELL_CAST_OK;
- }
-
- void Register() override
- {
- OnCheckCast += SpellCheckCastFn(spell_dru_flight_form_SpellScript::CheckCast);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_dru_flight_form_SpellScript();
- }
-};
-
// -5217 - Tiger's Fury
class spell_dru_tiger_s_fury : public SpellScriptLoader
{
@@ -1236,6 +1729,247 @@ class spell_dru_typhoon : public SpellScriptLoader
}
};
+// 28716 - Rejuvenation
+class spell_dru_t3_2p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_dru_t3_2p_bonus() : SpellScriptLoader("spell_dru_t3_2p_bonus") { }
+
+ class spell_dru_t3_2p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_t3_2p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_T3_PROC_ENERGIZE_MANA) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DRUID_T3_PROC_ENERGIZE_RAGE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DRUID_T3_PROC_ENERGIZE_ENERGY))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& /*eventInfo*/)
+ {
+ if (!roll_chance_i(50))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* target = eventInfo.GetProcTarget();
+ uint32 spellId;
+
+ switch (target->getPowerType())
+ {
+ case POWER_MANA:
+ spellId = SPELL_DRUID_T3_PROC_ENERGIZE_MANA;
+ break;
+ case POWER_RAGE:
+ spellId = SPELL_DRUID_T3_PROC_ENERGIZE_RAGE;
+ break;
+ case POWER_ENERGY:
+ spellId = SPELL_DRUID_T3_PROC_ENERGIZE_ENERGY;
+ break;
+ default:
+ return;
+ }
+
+ eventInfo.GetActor()->CastSpell(target, spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_dru_t3_2p_bonus_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_dru_t3_2p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_t3_2p_bonus_AuraScript();
+ }
+};
+
+// 28744 - Regrowth
+class spell_dru_t3_6p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_dru_t3_6p_bonus() : SpellScriptLoader("spell_dru_t3_6p_bonus") { }
+
+ class spell_dru_t3_6p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_t3_6p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_BLESSING_OF_THE_CLAW))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_BLESSING_OF_THE_CLAW, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dru_t3_6p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_t3_6p_bonus_AuraScript();
+ }
+};
+
+// 28719 - Healing Touch
+class spell_dru_t3_8p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_dru_t3_8p_bonus() : SpellScriptLoader("spell_dru_t3_8p_bonus") { }
+
+ class spell_dru_t3_8p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_t3_8p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_EXHILARATE))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ int32 amount = CalculatePct(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask()), aurEff->GetAmount());
+ caster->CastCustomSpell(SPELL_DRUID_EXHILARATE, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dru_t3_8p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_t3_8p_bonus_AuraScript();
+ }
+};
+
+// 37288 - Mana Restore
+// 37295 - Mana Restore
+class spell_dru_t4_2p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_dru_t4_2p_bonus() : SpellScriptLoader("spell_dru_t4_2p_bonus") { }
+
+ class spell_dru_t4_2p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_t4_2p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_INFUSION))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_DRUID_INFUSION, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dru_t4_2p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_t4_2p_bonus_AuraScript();
+ }
+};
+
+// 40442 - Druid Tier 6 Trinket
+class spell_dru_item_t6_trinket : public SpellScriptLoader
+{
+ public:
+ spell_dru_item_t6_trinket() : SpellScriptLoader("spell_dru_item_t6_trinket") { }
+
+ class spell_dru_item_t6_trinket_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_item_t6_trinket_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_BLESSING_OF_REMULOS) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DRUID_BLESSING_OF_ELUNE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DRUID_BLESSING_OF_CENARIUS))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return;
+
+ uint32 spellId;
+ int32 chance;
+
+ // Starfire
+ if (spellInfo->SpellFamilyFlags[0] & 0x00000004)
+ {
+ spellId = SPELL_DRUID_BLESSING_OF_REMULOS;
+ chance = 25;
+ }
+ // Rejuvenation
+ else if (spellInfo->SpellFamilyFlags[0] & 0x00000010)
+ {
+ spellId = SPELL_DRUID_BLESSING_OF_ELUNE;
+ chance = 25;
+ }
+ // Mangle (Bear) and Mangle (Cat)
+ else if (spellInfo->SpellFamilyFlags[1] & 0x00000440)
+ {
+ spellId = SPELL_DRUID_BLESSING_OF_CENARIUS;
+ chance = 40;
+ }
+ else
+ return;
+
+ if (roll_chance_i(chance))
+ eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dru_item_t6_trinket_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_item_t6_trinket_AuraScript();
+ }
+};
+
// 67353 - T9 Feral Relic (Idol of Mutilation)
class spell_dru_t9_feral_relic : public SpellScriptLoader
{
@@ -1307,6 +2041,55 @@ public:
}
};
+// 70723 - Item - Druid T10 Balance 4P Bonus
+class spell_dru_t10_balance_4p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_dru_t10_balance_4p_bonus() : SpellScriptLoader("spell_dru_t10_balance_4p_bonus") { }
+
+ class spell_dru_t10_balance_4p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_t10_balance_4p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_LANGUISH))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DRUID_LANGUISH);
+ int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
+ amount /= spellInfo->GetMaxTicks();
+ // Add remaining ticks to damage done
+ amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_DRUID_LANGUISH, SPELL_AURA_PERIODIC_DAMAGE);
+
+ caster->CastCustomSpell(SPELL_DRUID_LANGUISH, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dru_t10_balance_4p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_t10_balance_4p_bonus_AuraScript();
+ }
+};
+
// 70691 - Item T10 Restoration 4P Bonus
class spell_dru_t10_restoration_4p_bonus : public SpellScriptLoader
{
@@ -1362,6 +2145,61 @@ class spell_dru_t10_restoration_4p_bonus : public SpellScriptLoader
}
};
+// 70664 - Druid T10 Restoration 4P Bonus (Rejuvenation)
+class spell_dru_t10_restoration_4p_bonus_dummy : public SpellScriptLoader
+{
+ public:
+ spell_dru_t10_restoration_4p_bonus_dummy() : SpellScriptLoader("spell_dru_t10_restoration_4p_bonus_dummy") { }
+
+ class spell_dru_t10_restoration_4p_bonus_dummy_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_t10_restoration_4p_bonus_dummy_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_REJUVENATION_T10_PROC))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo || spellInfo->Id == SPELL_DRUID_REJUVENATION_T10_PROC)
+ return false;
+
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return false;
+
+ Player* caster = eventInfo.GetActor()->ToPlayer();
+ if (!caster)
+ return false;
+
+ return caster->GetGroup() || caster != eventInfo.GetProcTarget();
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ int32 amount = static_cast<int32>(eventInfo.GetHealInfo()->GetHeal());
+ eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_REJUVENATION_T10_PROC, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_dru_t10_restoration_4p_bonus_dummy_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_dru_t10_restoration_4p_bonus_dummy_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dru_t10_restoration_4p_bonus_dummy_AuraScript();
+ }
+};
+
class RaidCheck
{
public:
@@ -1434,22 +2272,33 @@ class spell_dru_wild_growth : public SpellScriptLoader
void AddSC_druid_spell_scripts()
{
+ new spell_dru_barkskin();
new spell_dru_bear_form_passive();
new spell_dru_dash();
new spell_dru_eclipse();
new spell_dru_enrage();
new spell_dru_forms_trinket();
+ new spell_dru_flight_form();
+ new spell_dru_glyph_of_barkskin();
+ new spell_dru_glyph_of_innervate();
+ new spell_dru_glyph_of_rake();
+ new spell_dru_glyph_of_rejuvenation();
+ new spell_dru_glyph_of_shred();
new spell_dru_glyph_of_starfire();
+ new spell_dru_glyph_of_starfire_dummy();
new spell_dru_idol_lifebloom();
new spell_dru_innervate();
new spell_dru_insect_swarm();
+ new spell_dru_leader_of_the_pack();
new spell_dru_lifebloom();
new spell_dru_living_seed();
new spell_dru_living_seed_proc();
new spell_dru_moonkin_form_passive();
+ new spell_dru_omen_of_clarity();
new spell_dru_owlkin_frenzy();
new spell_dru_predatory_strikes();
new spell_dru_primal_tenacity();
+ new spell_dru_revitalize();
new spell_dru_rip();
new spell_dru_savage_defense();
new spell_dru_savage_roar();
@@ -1457,10 +2306,16 @@ void AddSC_druid_spell_scripts()
new spell_dru_starfall_dummy();
new spell_dru_survival_instincts();
new spell_dru_swift_flight_passive();
- new spell_dru_flight_form();
new spell_dru_tiger_s_fury();
new spell_dru_typhoon();
+ new spell_dru_t3_2p_bonus();
+ new spell_dru_t3_6p_bonus();
+ new spell_dru_t3_8p_bonus();
+ new spell_dru_t4_2p_bonus();
+ new spell_dru_item_t6_trinket();
new spell_dru_t9_feral_relic();
+ new spell_dru_t10_balance_4p_bonus();
new spell_dru_t10_restoration_4p_bonus();
+ new spell_dru_t10_restoration_4p_bonus_dummy();
new spell_dru_wild_growth();
}
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index 168284b31bc..d0fcd1080bb 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -113,7 +113,8 @@ class spell_gen_adaptive_warding : public SpellScriptLoader
bool CheckProc(ProcEventInfo& eventInfo)
{
- if (eventInfo.GetDamageInfo()->GetSpellInfo()) // eventInfo.GetSpellInfo()
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetSpellInfo())
return false;
// find Mage Armor
@@ -156,7 +157,7 @@ class spell_gen_adaptive_warding : public SpellScriptLoader
default:
return;
}
- GetTarget()->CastSpell(GetTarget(), spellId, true, NULL, aurEff);
+ GetTarget()->CastSpell(GetTarget(), spellId, true, nullptr, aurEff);
}
void Register() override
@@ -1099,9 +1100,17 @@ class spell_gen_creature_permanent_feign_death : public SpellScriptLoader
target->ToCreature()->SetReactState(REACT_PASSIVE);
}
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ target->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD);
+ target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
+ }
+
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_gen_creature_permanent_feign_death_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ OnEffectRemove += AuraEffectRemoveFn(spell_gen_creature_permanent_feign_death_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
@@ -1443,51 +1452,6 @@ class spell_gen_ds_flush_knockback : public SpellScriptLoader
}
};
-enum DummyTrigger
-{
- SPELL_PERSISTANT_SHIELD_TRIGGERED = 26470,
- SPELL_PERSISTANT_SHIELD = 26467
-};
-
-class spell_gen_dummy_trigger : public SpellScriptLoader
-{
- public:
- spell_gen_dummy_trigger() : SpellScriptLoader("spell_gen_dummy_trigger") { }
-
- class spell_gen_dummy_trigger_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_gen_dummy_trigger_SpellScript);
-
- bool Validate(SpellInfo const* /*spellInfo*/) override
- {
- if (!sSpellMgr->GetSpellInfo(SPELL_PERSISTANT_SHIELD_TRIGGERED) ||
- !sSpellMgr->GetSpellInfo(SPELL_PERSISTANT_SHIELD))
- return false;
- return true;
- }
-
- void HandleDummy(SpellEffIndex /* effIndex */)
- {
- int32 damage = GetEffectValue();
- Unit* caster = GetCaster();
- if (Unit* target = GetHitUnit())
- if (SpellInfo const* triggeredByAuraSpell = GetTriggeringSpell())
- if (triggeredByAuraSpell->Id == SPELL_PERSISTANT_SHIELD_TRIGGERED)
- caster->CastCustomSpell(target, SPELL_PERSISTANT_SHIELD_TRIGGERED, &damage, NULL, NULL, true);
- }
-
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_gen_dummy_trigger_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_gen_dummy_trigger_SpellScript();
- }
-};
-
class spell_gen_dungeon_credit : public SpellScriptLoader
{
public:
@@ -2357,7 +2321,8 @@ class spell_gen_obsidian_armor : public SpellScriptLoader
bool CheckProc(ProcEventInfo& eventInfo)
{
- if (eventInfo.GetDamageInfo()->GetSpellInfo()) // eventInfo.GetSpellInfo()
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetSpellInfo())
return false;
if (GetFirstSchoolInMask(eventInfo.GetSchoolMask()) == SPELL_SCHOOL_NORMAL)
@@ -2763,6 +2728,41 @@ class spell_gen_orc_disguise : public SpellScriptLoader
}
};
+class spell_gen_proc_below_pct_damaged : public SpellScriptLoader
+{
+ public:
+ spell_gen_proc_below_pct_damaged(const char* name) : SpellScriptLoader(name) { }
+
+ class spell_gen_proc_below_pct_damaged_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_gen_proc_below_pct_damaged_AuraScript);
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return false;
+
+ int32 pct = GetSpellInfo()->Effects[EFFECT_0].CalcValue();
+
+ if (eventInfo.GetActionTarget()->HealthBelowPctDamaged(pct, damageInfo->GetDamage()))
+ return true;
+
+ return false;
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_gen_proc_below_pct_damaged_AuraScript::CheckProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_gen_proc_below_pct_damaged_AuraScript();
+ }
+};
+
enum ParachuteSpells
{
SPELL_PARACHUTE = 45472,
@@ -3390,41 +3390,53 @@ class spell_gen_tournament_pennant : public SpellScriptLoader
}
};
-
-
enum PvPTrinketTriggeredSpells
{
SPELL_WILL_OF_THE_FORSAKEN_COOLDOWN_TRIGGER = 72752,
SPELL_WILL_OF_THE_FORSAKEN_COOLDOWN_TRIGGER_WOTF = 72757
};
+template <uint32 TriggeredSpellId>
class spell_pvp_trinket_wotf_shared_cd : public SpellScriptLoader
{
public:
- spell_pvp_trinket_wotf_shared_cd() : SpellScriptLoader("spell_pvp_trinket_wotf_shared_cd") { }
+ spell_pvp_trinket_wotf_shared_cd(char const* ScriptName) : SpellScriptLoader(ScriptName) { }
+ template <uint32 Triggered>
class spell_pvp_trinket_wotf_shared_cd_SpellScript : public SpellScript
{
PrepareSpellScript(spell_pvp_trinket_wotf_shared_cd_SpellScript);
- bool Load() override
- {
- return GetCaster()->GetTypeId() == TYPEID_PLAYER;
- }
-
bool Validate(SpellInfo const* /*spellInfo*/) override
{
- if (!sSpellMgr->GetSpellInfo(SPELL_WILL_OF_THE_FORSAKEN_COOLDOWN_TRIGGER) ||
- !sSpellMgr->GetSpellInfo(SPELL_WILL_OF_THE_FORSAKEN_COOLDOWN_TRIGGER_WOTF))
+ if (!sSpellMgr->GetSpellInfo(Triggered))
return false;
return true;
}
void HandleScript()
{
- // 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()->GetSpellHistory()->StartCooldown(GetSpellInfo(), 0, GetSpell());
+ /*
+ * @workaround: PendingCast flag normally means 'triggered' spell, however
+ * if the spell is cast triggered, the core won't send SMSG_SPELL_GO packet
+ * so client never registers the cooldown (see Spell::IsNeedSendToClient)
+ *
+ * ServerToClient: SMSG_SPELL_GO (0x0132) Length: 42 ConnIdx: 0 Time: 07/19/2010 02:32:35.000 Number: 362675
+ * Caster GUID: Full: Player
+ * Caster Unit GUID: Full: Player
+ * Cast Count: 0
+ * Spell ID: 72752 (72752)
+ * Cast Flags: PendingCast, Unknown3, Unknown7 (265)
+ * Time: 3901468825
+ * Hit Count: 1
+ * [0] Hit GUID: Player
+ * Miss Count: 0
+ * Target Flags: Unit (2)
+ * Target GUID: 0x0
+ */
+
+ // Spell flags need further research, until then just cast not triggered
+ GetCaster()->CastSpell((Unit*)nullptr, Triggered, false);
}
void Register() override
@@ -3435,7 +3447,7 @@ class spell_pvp_trinket_wotf_shared_cd : public SpellScriptLoader
SpellScript* GetSpellScript() const override
{
- return new spell_pvp_trinket_wotf_shared_cd_SpellScript();
+ return new spell_pvp_trinket_wotf_shared_cd_SpellScript<TriggeredSpellId>();
}
};
@@ -3535,6 +3547,53 @@ class spell_gen_upper_deck_create_foam_sword : public SpellScriptLoader
}
};
+enum VampiricTouch
+{
+ SPELL_VAMPIRIC_TOUCH_HEAL = 52724
+};
+
+// 52723 - Vampiric Touch
+// 60501 - Vampiric Touch
+class spell_gen_vampiric_touch : public SpellScriptLoader
+{
+ public:
+ spell_gen_vampiric_touch() : SpellScriptLoader("spell_gen_vampiric_touch") { }
+
+ class spell_gen_vampiric_touch_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_gen_vampiric_touch_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_VAMPIRIC_TOUCH_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ int32 bp = damageInfo->GetDamage() / 2;
+ caster->CastCustomSpell(SPELL_VAMPIRIC_TOUCH_HEAL, SPELLVALUE_BASE_POINT0, bp, caster, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_gen_vampiric_touch_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_gen_vampiric_touch_AuraScript();
+ }
+};
+
enum VehicleScaling
{
SPELL_GEAR_SCALING = 66668
@@ -4262,8 +4321,10 @@ class spell_gen_pony_mount_check : public SpellScriptLoader
void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
{
Unit* caster = GetCaster();
+ if (!caster)
+ return;
Player* owner = caster->GetOwner()->ToPlayer();
- if (!caster || !owner || !owner->HasAchieved(ACHIEV_PONY_UP))
+ if (!owner || !owner->HasAchieved(ACHIEV_PONY_UP))
return;
if (owner->IsMounted())
@@ -4322,7 +4383,6 @@ void AddSC_generic_spell_scripts()
new spell_gen_despawn_self();
new spell_gen_divine_storm_cd_reset();
new spell_gen_ds_flush_knockback();
- new spell_gen_dummy_trigger();
new spell_gen_dungeon_credit();
new spell_gen_elune_candle();
new spell_gen_gadgetzan_transporter_backfire();
@@ -4350,6 +4410,12 @@ void AddSC_generic_spell_scripts()
new spell_gen_on_tournament_mount();
new spell_gen_oracle_wolvar_reputation();
new spell_gen_orc_disguise();
+ new spell_gen_proc_below_pct_damaged("spell_item_soul_harvesters_charm");
+ new spell_gen_proc_below_pct_damaged("spell_item_commendation_of_kaelthas");
+ new spell_gen_proc_below_pct_damaged("spell_item_corpse_tongue_coin");
+ new spell_gen_proc_below_pct_damaged("spell_item_corpse_tongue_coin_heroic");
+ new spell_gen_proc_below_pct_damaged("spell_item_petrified_twilight_scale");
+ new spell_gen_proc_below_pct_damaged("spell_item_petrified_twilight_scale_heroic");
new spell_gen_parachute();
new spell_gen_pet_summoned();
new spell_gen_profession_research();
@@ -4364,9 +4430,11 @@ void AddSC_generic_spell_scripts()
new spell_gen_throw_shield();
new spell_gen_tournament_duel();
new spell_gen_tournament_pennant();
- new spell_pvp_trinket_wotf_shared_cd();
+ new spell_pvp_trinket_wotf_shared_cd<SPELL_WILL_OF_THE_FORSAKEN_COOLDOWN_TRIGGER>("spell_pvp_trinket_shared_cd");
+ new spell_pvp_trinket_wotf_shared_cd<SPELL_WILL_OF_THE_FORSAKEN_COOLDOWN_TRIGGER_WOTF>("spell_wotf_shared_cd");
new spell_gen_turkey_marker();
new spell_gen_upper_deck_create_foam_sword();
+ new spell_gen_vampiric_touch();
new spell_gen_vehicle_scaling();
new spell_gen_vendor_bark_trigger();
new spell_gen_wg_water();
diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp
index 84fe9297344..b341c5799ed 100644
--- a/src/server/scripts/Spells/spell_hunter.cpp
+++ b/src/server/scripts/Spells/spell_hunter.cpp
@@ -60,8 +60,14 @@ enum HunterSpells
SPELL_HUNTER_VIPER_ATTACK_SPEED = 60144,
SPELL_DRAENEI_GIFT_OF_THE_NAARU = 59543,
SPELL_ROAR_OF_SACRIFICE_TRIGGERED = 67481,
- SPELL_LOCK_AND_LOAD_TRIGGER = 56453,
- SPELL_LOCK_AND_LOAD_MARKER = 67544
+ SPELL_HUNTER_LOCK_AND_LOAD_TRIGGER = 56453,
+ SPELL_HUNTER_LOCK_AND_LOAD_MARKER = 67544,
+ SPELL_HUNTER_KILL_COMMAND_HUNTER = 34027,
+ SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA = 34720,
+ SPELL_REPLENISHMENT = 57669,
+ SPELL_HUNTER_RAPID_RECUPERATION_MANA_R1 = 56654,
+ SPELL_HUNTER_RAPID_RECUPERATION_MANA_R2 = 58882,
+ SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS = 57894
};
// 13161 - Aspect of the Beast
@@ -209,53 +215,51 @@ class spell_hun_chimera_shot : public SpellScriptLoader
flag96 familyFlag = aura->GetSpellInfo()->SpellFamilyFlags;
if (!(familyFlag[1] & 0x00000080 || familyFlag[0] & 0x0000C000))
continue;
- if (AuraEffect* aurEff = aura->GetEffect(0))
+ if (AuraEffect const* aurEff = aura->GetEffect(EFFECT_0))
{
// Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
if (familyFlag[0] & 0x4000)
{
- int32 TickCount = aurEff->GetTotalTicks();
spellId = SPELL_HUNTER_CHIMERA_SHOT_SERPENT;
+
+ // first, calculate damage of basic tick (C&P from AuraEffect::HandlePeriodicDamageAurasTick)
basePoint = (aurEff->GetAmount() + aurEff->GetBonusAmount()) * aurEff->GetDonePct();
- ApplyPct(basePoint, TickCount * 40);
- basePoint = unitTarget->SpellDamageBonusTaken(caster, aura->GetSpellInfo(), basePoint, DOT, aura->GetStackAmount());
if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(aura->GetSpellInfo()->Id, SPELLMOD_DOT, basePoint);
+ modOwner->ApplySpellMod<SPELLMOD_DOT>(aurEff->GetId(), basePoint);
+ basePoint = unitTarget->SpellDamageBonusTaken(caster, aurEff->GetSpellInfo(), basePoint, DOT, aura->GetStackAmount());
- aurEff->SetBonusAmount(caster->SpellDamageBonusDone(unitTarget, aurEff->GetSpellInfo(), 0, DOT));
+ // then, multiply to get damage potential
+ basePoint *= aurEff->GetTotalTicks();
+ ApplyPct(basePoint, 40);
}
// Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
else if (familyFlag[1] & 0x00000080)
{
- int32 TickCount = aura->GetEffect(0)->GetTotalTicks();
spellId = SPELL_HUNTER_CHIMERA_SHOT_VIPER;
- // Amount of one aura tick
- basePoint = int32(CalculatePct(unitTarget->GetMaxPower(POWER_MANA), aurEff->GetAmount()));
- int32 casterBasePoint = aurEff->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 50; /// @todo WTF? caster uses unitTarget?
- if (basePoint > casterBasePoint)
- basePoint = casterBasePoint;
- ApplyPct(basePoint, TickCount * 60);
+ // % of mana drained in max duration
+ basePoint = aurEff->GetAmount() * aurEff->GetTotalTicks();
+
+ // max value
+ int32 maxManaReturn = CalculatePct(static_cast<int32>(caster->GetMaxPower(POWER_MANA)), basePoint * 2);
+ ApplyPct(basePoint, unitTarget->GetMaxPower(POWER_MANA));
+ if (basePoint > maxManaReturn)
+ basePoint = maxManaReturn;
+
+ ApplyPct(basePoint, 60);
}
// Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
else if (familyFlag[0] & 0x00008000)
spellId = SPELL_HUNTER_CHIMERA_SHOT_SCORPID;
- // ?? nothing say in spell desc (possibly need addition check)
- //if (familyFlag & 0x0000010000000000LL || // dot
- // familyFlag & 0x0000100000000000LL) // stun
- //{
- // spellId = 53366; // 53366 Chimera Shot - Wyvern
- //}
// Refresh aura duration
aura->RefreshDuration();
}
break;
}
+
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->GetSpellHistory()->AddCooldown(spellId, 0, std::chrono::minutes(1));
+ caster->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, basePoint, unitTarget, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD));
}
}
@@ -271,6 +275,70 @@ class spell_hun_chimera_shot : public SpellScriptLoader
}
};
+// -53256 - Cobra Strikes
+class spell_hun_cobra_strikes : public SpellScriptLoader
+{
+ public:
+ spell_hun_cobra_strikes() : SpellScriptLoader("spell_hun_cobra_strikes") { }
+
+ class spell_hun_cobra_strikes_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hun_cobra_strikes_AuraScript);
+
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+
+ SpellInfo const* triggeredSpellInfo = sSpellMgr->AssertSpellInfo(GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell);
+ GetTarget()->CastCustomSpell(triggeredSpellInfo->Id, SPELLVALUE_AURA_STACK, triggeredSpellInfo->StackAmount, (Unit*)nullptr, true);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_hun_cobra_strikes_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hun_cobra_strikes_AuraScript();
+ }
+};
+
+// 53257 - Cobra Strikes (triggered spell)
+class spell_hun_cobra_strikes_triggered : public SpellScriptLoader
+{
+ public:
+ spell_hun_cobra_strikes_triggered() : SpellScriptLoader("spell_hun_cobra_strikes_triggered") { }
+
+ class spell_hun_cobra_strikes_triggered_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hun_cobra_strikes_triggered_AuraScript);
+
+ void HandleStackDrop(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ ModStackAmount(-1);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_hun_cobra_strikes_triggered_AuraScript::HandleStackDrop, EFFECT_0, SPELL_AURA_ADD_FLAT_MODIFIER);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hun_cobra_strikes_triggered_AuraScript();
+ }
+};
+
// 781 - Disengage
class spell_hun_disengage : public SpellScriptLoader
{
@@ -364,6 +432,76 @@ class spell_hun_glyph_of_arcane_shot : public SpellScriptLoader
}
};
+// 57870 - Glyph of Mend Pet
+class spell_hun_glyph_of_mend_pet : public SpellScriptLoader
+{
+ public:
+ spell_hun_glyph_of_mend_pet() : SpellScriptLoader("spell_hun_glyph_of_mend_pet") { }
+
+ class spell_hun_glyph_of_mend_pet_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hun_glyph_of_mend_pet_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetProcTarget()->CastSpell((Unit*)nullptr, SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_hun_glyph_of_mend_pet_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hun_glyph_of_mend_pet_AuraScript();
+ }
+};
+
+// -53290 - Hunting Party
+class spell_hun_hunting_party : public SpellScriptLoader
+{
+ public:
+ spell_hun_hunting_party() : SpellScriptLoader("spell_hun_hunting_party") { }
+
+ class spell_hun_hunting_party_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hun_hunting_party_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_REPLENISHMENT))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_hun_hunting_party_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hun_hunting_party_AuraScript();
+ }
+};
+
// -19572 - Improved Mend Pet
class spell_hun_improved_mend_pet : public SpellScriptLoader
{
@@ -442,6 +580,46 @@ class spell_hun_invigoration : public SpellScriptLoader
}
};
+// 58914 - Kill Command
+class spell_hun_kill_command_pet : public SpellScriptLoader
+{
+ public:
+ spell_hun_kill_command_pet() : SpellScriptLoader("spell_hun_kill_command_pet") { }
+
+ class spell_hun_kill_command_pet_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hun_kill_command_pet_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_KILL_COMMAND_HUNTER))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ // prevent charge drop (aura has both proc charge and stacks)
+ PreventDefaultAction();
+
+ if (Unit* owner = eventInfo.GetActor()->GetOwner())
+ owner->RemoveAuraFromStack(SPELL_HUNTER_KILL_COMMAND_HUNTER);
+
+ ModStackAmount(-1);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_hun_kill_command_pet_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hun_kill_command_pet_AuraScript();
+ }
+};
+
// 53478 - Last Stand Pet
class spell_hun_last_stand_pet : public SpellScriptLoader
{
@@ -490,48 +668,57 @@ class spell_hun_lock_and_load : public SpellScriptLoader
bool Validate(SpellInfo const* /*spellInfo*/) override
{
- if (!sSpellMgr->GetSpellInfo(SPELL_LOCK_AND_LOAD_TRIGGER) ||
- !sSpellMgr->GetSpellInfo(SPELL_LOCK_AND_LOAD_MARKER))
+ if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_LOCK_AND_LOAD_TRIGGER) ||
+ !sSpellMgr->GetSpellInfo(SPELL_HUNTER_LOCK_AND_LOAD_MARKER))
return false;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
- if (eventInfo.GetActor()->HasAura(SPELL_LOCK_AND_LOAD_MARKER))
+ if (eventInfo.GetActor()->HasAura(SPELL_HUNTER_LOCK_AND_LOAD_MARKER))
return false;
-
return true;
}
- template <uint32 mask>
- void HandleProcs(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ bool CheckTrapProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
- PreventDefaultAction();
+ if (!(eventInfo.GetTypeMask() & PROC_FLAG_DONE_TRAP_ACTIVATION))
+ return false;
- if (!(eventInfo.GetTypeMask() & mask))
- return;
+ // Do not proc on traps for immolation/explosive trap
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !(damageInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST))
+ return false;
- // Additional check: do not proc on traps for immolation/explosive trap
- // (But still do it for the periodic damage part)
- if (mask == PROC_FLAG_DONE_TRAP_ACTIVATION)
- if (!(eventInfo.GetDamageInfo()->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST))
- return;
+ return roll_chance_i(aurEff->GetAmount());
+ }
- if (!roll_chance_i(aurEff->GetAmount()))
- return;
+ bool CheckPeriodicProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ if (!(eventInfo.GetTypeMask() & PROC_FLAG_DONE_PERIODIC))
+ return false;
+
+ return roll_chance_i(aurEff->GetAmount());
+ }
+
+ void HandleProc(ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
Unit* caster = eventInfo.GetActor();
- caster->CastSpell(caster, SPELL_LOCK_AND_LOAD_TRIGGER, true);
- caster->CastSpell(caster, SPELL_LOCK_AND_LOAD_MARKER, true);
+ caster->CastSpell(caster, SPELL_HUNTER_LOCK_AND_LOAD_TRIGGER, true);
+ caster->CastSpell(caster, SPELL_HUNTER_LOCK_AND_LOAD_MARKER, true);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_hun_lock_and_load_AuraScript::CheckProc);
- OnEffectProc += AuraEffectProcFn(spell_hun_lock_and_load_AuraScript::HandleProcs<PROC_FLAG_DONE_TRAP_ACTIVATION>, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
- OnEffectProc += AuraEffectProcFn(spell_hun_lock_and_load_AuraScript::HandleProcs<PROC_FLAG_DONE_PERIODIC>, EFFECT_1, SPELL_AURA_DUMMY);
+ DoCheckEffectProc += AuraCheckEffectProcFn(spell_hun_lock_and_load_AuraScript::CheckTrapProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ DoCheckEffectProc += AuraCheckEffectProcFn(spell_hun_lock_and_load_AuraScript::CheckPeriodicProc, EFFECT_1, SPELL_AURA_DUMMY);
+
+ OnProc += AuraProcFn(spell_hun_lock_and_load_AuraScript::HandleProc);
}
};
@@ -558,30 +745,58 @@ class spell_hun_masters_call : public SpellScriptLoader
return true;
}
+ bool Load() override
+ {
+ return GetCaster()->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ SpellCastResult DoCheckCast()
+ {
+ Pet* pet = GetCaster()->ToPlayer()->GetPet();
+ ASSERT(pet); // checked in Spell::CheckCast
+
+ if (!pet->IsAlive())
+ return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW;
+
+ // Do a mini Spell::CheckCasterAuras on the pet, no other way of doing this
+ SpellCastResult result = SPELL_CAST_OK;
+ uint32 const unitflag = pet->GetUInt32Value(UNIT_FIELD_FLAGS);
+ if (pet->GetCharmerGUID())
+ result = SPELL_FAILED_CHARMED;
+ else if (unitflag & UNIT_FLAG_STUNNED)
+ result = SPELL_FAILED_STUNNED;
+ else if (unitflag & UNIT_FLAG_FLEEING)
+ result = SPELL_FAILED_FLEEING;
+ else if (unitflag & UNIT_FLAG_CONFUSED)
+ result = SPELL_FAILED_CONFUSED;
+
+ if (result != SPELL_CAST_OK)
+ return result;
+
+ Unit* target = GetExplTargetUnit();
+ if (!target)
+ return SPELL_FAILED_BAD_TARGETS;
+
+ if (!pet->IsWithinLOSInMap(target))
+ return SPELL_FAILED_LINE_OF_SIGHT;
+
+ return SPELL_CAST_OK;
+ }
+
void HandleDummy(SpellEffIndex /*effIndex*/)
{
- if (Unit* ally = GetHitUnit())
- if (Player* caster = GetCaster()->ToPlayer())
- if (Pet* target = caster->GetPet())
- {
- TriggerCastFlags castMask = TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_CASTER_AURASTATE);
- target->CastSpell(ally, GetEffectValue(), castMask);
- target->CastSpell(ally, GetSpellInfo()->Effects[EFFECT_0].CalcValue(), castMask);
- }
+ GetCaster()->ToPlayer()->GetPet()->CastSpell(GetHitUnit(), GetEffectValue(), true);
}
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
- if (Unit* target = GetHitUnit())
- {
- // Cannot be processed while pet is dead
- TriggerCastFlags castMask = TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_CASTER_AURASTATE);
- target->CastSpell(target, SPELL_HUNTER_MASTERS_CALL_TRIGGERED, castMask);
- }
+ GetHitUnit()->CastSpell((Unit*)nullptr, SPELL_HUNTER_MASTERS_CALL_TRIGGERED, true);
}
void Register() override
{
+ OnCheckCast += SpellCheckCastFn(spell_hun_masters_call_SpellScript::DoCheckCast);
+
OnEffectHitTarget += SpellEffectFn(spell_hun_masters_call_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
OnEffectHitTarget += SpellEffectFn(spell_hun_masters_call_SpellScript::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
}
@@ -753,11 +968,13 @@ class spell_hun_pet_heart_of_the_phoenix : public SpellScriptLoader
{
Unit* caster = GetCaster();
if (Unit* owner = caster->GetOwner())
+ {
if (!caster->HasAura(SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF))
{
owner->CastCustomSpell(SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_TRIGGERED, SPELLVALUE_BASE_POINT0, 100, caster, true);
caster->CastSpell(caster, SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF, true);
}
+ }
}
void Register() override
@@ -868,6 +1085,64 @@ class spell_hun_rapid_recuperation : public SpellScriptLoader
}
};
+// -53228 - Rapid Recuperation (talent aura)
+class spell_hun_rapid_recuperation_trigger : public SpellScriptLoader
+{
+ public:
+ spell_hun_rapid_recuperation_trigger() : SpellScriptLoader("spell_hun_rapid_recuperation_trigger") { }
+
+ class spell_hun_rapid_recuperation_trigger_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hun_rapid_recuperation_trigger_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_RAPID_RECUPERATION_MANA_R1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_HUNTER_RAPID_RECUPERATION_MANA_R2))
+ return false;
+ return true;
+ }
+
+ void HandleRapidFireProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ // Proc only from Rapid Fire
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo || !(spellInfo->SpellFamilyFlags[0] & 0x00000020))
+ {
+ PreventDefaultAction();
+ return;
+ }
+ }
+
+ void HandleRapidKillingProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ static uint32 const triggerSpells[2] = { SPELL_HUNTER_RAPID_RECUPERATION_MANA_R1, SPELL_HUNTER_RAPID_RECUPERATION_MANA_R2 };
+
+ PreventDefaultAction();
+
+ // Proc only from Rapid Killing
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo || !(spellInfo->SpellFamilyFlags[1] & 0x01000000))
+ return;
+
+ uint8 rank = GetSpellInfo()->GetRank();
+ uint32 spellId = triggerSpells[rank - 1];
+ eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_hun_rapid_recuperation_trigger_AuraScript::HandleRapidFireProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ OnEffectProc += AuraEffectProcFn(spell_hun_rapid_recuperation_trigger_AuraScript::HandleRapidKillingProc, EFFECT_1, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hun_rapid_recuperation_trigger_AuraScript();
+ }
+};
+
// 23989 - Readiness
class spell_hun_readiness : public SpellScriptLoader
{
@@ -930,9 +1205,16 @@ class spell_hun_roar_of_sacrifice : public SpellScriptLoader
return true;
}
- bool CheckProc(ProcEventInfo& eventInfo)
+ bool CheckProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
- return GetCaster() && (eventInfo.GetDamageInfo()->GetSchoolMask() & GetEffect(EFFECT_1)->GetMiscValue()) != 0;
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !(damageInfo->GetSchoolMask() & aurEff->GetMiscValue()))
+ return false;
+
+ if (!GetCaster())
+ return false;
+
+ return true;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
@@ -945,7 +1227,7 @@ class spell_hun_roar_of_sacrifice : public SpellScriptLoader
void Register() override
{
- DoCheckProc += AuraCheckProcFn(spell_hun_roar_of_sacrifice_AuraScript::CheckProc);
+ DoCheckEffectProc += AuraCheckEffectProcFn(spell_hun_roar_of_sacrifice_AuraScript::CheckProc, EFFECT_1, SPELL_AURA_DUMMY);
OnEffectProc += AuraEffectProcFn(spell_hun_roar_of_sacrifice_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
}
};
@@ -1135,6 +1417,64 @@ class spell_hun_target_only_pet_and_owner : public SpellScriptLoader
}
};
+// -34497 - Thrill of the Hunt
+class spell_hun_thrill_of_the_hunt : public SpellScriptLoader
+{
+ public:
+ spell_hun_thrill_of_the_hunt() : SpellScriptLoader("spell_hun_thrill_of_the_hunt") { }
+
+ class spell_hun_thrill_of_the_hunt_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hun_thrill_of_the_hunt_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ int32 amount = 0;
+
+ // Explosive Shot
+ if (spellInfo->SpellFamilyFlags[2] & 0x200)
+ {
+ if (AuraEffect const* explosiveShot = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_AURA_PERIODIC_DUMMY, SPELLFAMILY_HUNTER, 0x00000000, 0x80000000, 0x00000000, caster->GetGUID()))
+ {
+ // due to Lock and Load SpellInfo::CalcPowerCost might return 0, so just calculate it manually
+ amount = CalculatePct(static_cast<int32>(CalculatePct(caster->GetCreateMana(), explosiveShot->GetSpellInfo()->ManaCostPercentage)), aurEff->GetAmount());
+ amount /= explosiveShot->GetSpellInfo()->GetMaxTicks();
+ }
+ }
+ else
+ amount = CalculatePct(static_cast<int32>(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask())), aurEff->GetAmount());
+
+ if (!amount)
+ return;
+
+ caster->CastCustomSpell(SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_hun_thrill_of_the_hunt_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hun_thrill_of_the_hunt_AuraScript();
+ }
+};
+
// 67151 - T9 4P Bonus
class spell_hun_t9_4p_bonus : public SpellScriptLoader
{
@@ -1201,7 +1541,7 @@ class spell_hun_viper_attack_speed : public SpellScriptLoader
void OnApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
{
if (GetTarget()->HasAura(SPELL_HUNTER_ASPECT_OF_THE_VIPER))
- GetTarget()->CastSpell(GetTarget(), SPELL_HUNTER_VICIOUS_VIPER, true, NULL, aurEff);
+ GetTarget()->CastSpell(GetTarget(), SPELL_HUNTER_VICIOUS_VIPER, true, nullptr, aurEff);
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
@@ -1228,10 +1568,15 @@ void AddSC_hunter_spell_scripts()
new spell_hun_aspect_of_the_beast();
new spell_hun_ascpect_of_the_viper();
new spell_hun_chimera_shot();
+ new spell_hun_cobra_strikes();
+ new spell_hun_cobra_strikes_triggered();
new spell_hun_disengage();
new spell_hun_glyph_of_arcane_shot();
+ new spell_hun_glyph_of_mend_pet();
+ new spell_hun_hunting_party();
new spell_hun_improved_mend_pet();
new spell_hun_invigoration();
+ new spell_hun_kill_command_pet();
new spell_hun_last_stand_pet();
new spell_hun_lock_and_load();
new spell_hun_masters_call();
@@ -1241,12 +1586,14 @@ void AddSC_hunter_spell_scripts()
new spell_hun_pet_heart_of_the_phoenix();
new spell_hun_piercing_shots();
new spell_hun_rapid_recuperation();
+ new spell_hun_rapid_recuperation_trigger();
new spell_hun_readiness();
new spell_hun_roar_of_sacrifice();
new spell_hun_scatter_shot();
new spell_hun_sniper_training();
new spell_hun_tame_beast();
new spell_hun_target_only_pet_and_owner();
+ new spell_hun_thrill_of_the_hunt();
new spell_hun_t9_4p_bonus();
new spell_hun_viper_attack_speed();
}
diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp
index 562625e22f5..9ef5c5d0b4d 100644
--- a/src/server/scripts/Spells/spell_item.cpp
+++ b/src/server/scripts/Spells/spell_item.cpp
@@ -115,6 +115,143 @@ class spell_item_aegis_of_preservation : public SpellScriptLoader
}
};
+enum AlchemistStone
+{
+ SPELL_ALCHEMISTS_STONE_EXTRA_HEAL = 21399,
+ SPELL_ALCHEMISTS_STONE_EXTRA_MANA = 21400
+};
+
+// Item - 13503: Alchemist's Stone
+// Item - 35748: Guardian's Alchemist Stone
+// Item - 35749: Sorcerer's Alchemist Stone
+// Item - 35750: Redeemer's Alchemist Stone
+// Item - 35751: Assassin's Alchemist Stone
+// Item - 44322: Mercurial Alchemist Stone
+// Item - 44323: Indestructible Alchemist's Stone
+// Item - 44324: Mighty Alchemist's Stone
+
+// 17619 - Alchemist's Stone
+class spell_item_alchemists_stone : public SpellScriptLoader
+{
+ public:
+ spell_item_alchemists_stone() : SpellScriptLoader("spell_item_alchemists_stone") { }
+
+ class spell_item_alchemists_stone_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_alchemists_stone_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_ALCHEMISTS_STONE_EXTRA_HEAL) ||
+ !sSpellMgr->GetSpellInfo(SPELL_ALCHEMISTS_STONE_EXTRA_MANA))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return;
+
+ Unit* caster = eventInfo.GetActionTarget();
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ uint32 spellId;
+ switch (spellInfo->Effects[i].Effect)
+ {
+ case SPELL_EFFECT_HEAL:
+ spellId = SPELL_ALCHEMISTS_STONE_EXTRA_HEAL;
+ break;
+ case SPELL_EFFECT_ENERGIZE:
+ spellId = SPELL_ALCHEMISTS_STONE_EXTRA_MANA;
+ break;
+ default:
+ continue;
+ }
+
+ int32 amount = CalculatePct(spellInfo->Effects[i].CalcValue(caster), 40);
+ caster->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_alchemists_stone_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_alchemists_stone_AuraScript();
+ }
+};
+
+enum AngerCapacitor
+{
+ SPELL_MOTE_OF_ANGER = 71432,
+ SPELL_MANIFEST_ANGER_MAIN_HAND = 71433,
+ SPELL_MANIFEST_ANGER_OFF_HAND = 71434
+};
+
+// Item - 50351: Tiny Abomination in a Jar
+// 71406 - Anger Capacitor
+
+// Item - 50706: Tiny Abomination in a Jar (Heroic)
+// 71545 - Anger Capacitor
+template <uint8 StackAmount>
+class spell_item_anger_capacitor : public SpellScriptLoader
+{
+ public:
+ spell_item_anger_capacitor(char const* ScriptName) : SpellScriptLoader(ScriptName) { }
+
+ template <uint8 Stacks>
+ class spell_item_anger_capacitor_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_anger_capacitor_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MOTE_OF_ANGER) ||
+ !sSpellMgr->GetSpellInfo(SPELL_MANIFEST_ANGER_MAIN_HAND) ||
+ !sSpellMgr->GetSpellInfo(SPELL_MANIFEST_ANGER_OFF_HAND))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+
+ caster->CastSpell((Unit*)nullptr, SPELL_MOTE_OF_ANGER, true);
+ Aura const* motes = caster->GetAura(SPELL_MOTE_OF_ANGER);
+ if (!motes || motes->GetStackAmount() < Stacks)
+ return;
+
+ caster->RemoveAurasDueToSpell(SPELL_MOTE_OF_ANGER);
+ uint32 spellId = SPELL_MANIFEST_ANGER_MAIN_HAND;
+ if (Player* player = caster->ToPlayer())
+ if (player->GetWeaponForAttack(OFF_ATTACK, true) && urand(0, 1))
+ spellId = SPELL_MANIFEST_ANGER_OFF_HAND;
+
+ caster->CastSpell(target, spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_anger_capacitor_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_anger_capacitor_AuraScript<StackAmount>();
+ }
+};
+
// 26400 - Arcane Shroud
class spell_item_arcane_shroud : public SpellScriptLoader
{
@@ -144,6 +281,170 @@ class spell_item_arcane_shroud : public SpellScriptLoader
}
};
+// Item - 12846: Argent Dawn Commission
+// Item - 13209: Seal of the Dawn
+// Item - 19812: Rune of the Dawn
+
+// 17670 - Argent Dawn Commission
+class spell_item_argent_dawn_commission : public SpellScriptLoader
+{
+ public:
+ spell_item_argent_dawn_commission() : SpellScriptLoader("spell_item_argent_dawn_commission") { }
+
+ class spell_item_argent_dawn_commission_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_argent_dawn_commission_AuraScript);
+
+ void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ // Prevent console log
+ PreventDefaultAction();
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_argent_dawn_commission_AuraScript::HandleDummy, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_argent_dawn_commission_AuraScript();
+ }
+};
+
+enum AuraOfMadness
+{
+ SPELL_SOCIOPATH = 39511, // Sociopath: +35 strength(Paladin, Rogue, Druid, Warrior)
+ SPELL_DELUSIONAL = 40997, // Delusional: +70 attack power(Rogue, Hunter, Paladin, Warrior, Druid)
+ SPELL_KLEPTOMANIA = 40998, // Kleptomania: +35 agility(Warrior, Rogue, Paladin, Hunter, Druid)
+ SPELL_MEGALOMANIA = 40999, // Megalomania: +41 damage / healing(Druid, Shaman, Priest, Warlock, Mage, Paladin)
+ SPELL_PARANOIA = 41002, // Paranoia: +35 spell / melee / ranged crit strike rating(All classes)
+ SPELL_MANIC = 41005, // Manic: +35 haste(spell, melee and ranged) (All classes)
+ SPELL_NARCISSISM = 41009, // Narcissism: +35 intellect(Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
+ SPELL_MARTYR_COMPLEX = 41011, // Martyr Complex: +35 stamina(All classes)
+ SPELL_DEMENTIA = 41404, // Dementia: Every 5 seconds either gives you +5/-5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
+
+ SPELL_DEMENTIA_POS = 41406,
+ SPELL_DEMENTIA_NEG = 41409,
+
+ SAY_MADNESS = 21954
+};
+
+// Item - 31859: Darkmoon Card: Madness
+// 39446 - Aura of Madness
+class spell_item_aura_of_madness : public SpellScriptLoader
+{
+ public:
+ spell_item_aura_of_madness() : SpellScriptLoader("spell_item_aura_of_madness") { }
+
+ class spell_item_aura_of_madness_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_aura_of_madness_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SOCIOPATH) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DELUSIONAL) ||
+ !sSpellMgr->GetSpellInfo(SPELL_KLEPTOMANIA) ||
+ !sSpellMgr->GetSpellInfo(SPELL_MEGALOMANIA) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PARANOIA) ||
+ !sSpellMgr->GetSpellInfo(SPELL_MANIC) ||
+ !sSpellMgr->GetSpellInfo(SPELL_NARCISSISM) ||
+ !sSpellMgr->GetSpellInfo(SPELL_MARTYR_COMPLEX) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DEMENTIA) ||
+ !sObjectMgr->GetBroadcastText(SAY_MADNESS))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ static std::vector<uint32> const triggeredSpells[MAX_CLASSES] =
+ {
+ //CLASS_NONE
+ { },
+ //CLASS_WARRIOR
+ { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_MARTYR_COMPLEX },
+ //CLASS_PALADIN
+ { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA },
+ //CLASS_HUNTER
+ { SPELL_DELUSIONAL, SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA },
+ //CLASS_ROGUE
+ { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_MARTYR_COMPLEX },
+ //CLASS_PRIEST
+ { SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA },
+ //CLASS_DEATH_KNIGHT
+ { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_MARTYR_COMPLEX },
+ //CLASS_SHAMAN
+ { SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA },
+ //CLASS_MAGE
+ { SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA },
+ //CLASS_WARLOCK
+ { SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA },
+ //CLASS_UNK
+ { },
+ //CLASS_DRUID
+ { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA }
+ };
+
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ uint32 spellId = Trinity::Containers::SelectRandomContainerElement(triggeredSpells[caster->getClass()]);
+ caster->CastSpell(caster, spellId, true, nullptr, aurEff);
+
+ if (roll_chance_i(10))
+ caster->Unit::Say(SAY_MADNESS);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_aura_of_madness_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_aura_of_madness_AuraScript();
+ }
+};
+
+// 41404 - Dementia
+class spell_item_dementia : public SpellScriptLoader
+{
+ public:
+ spell_item_dementia() : SpellScriptLoader("spell_item_dementia") { }
+
+ class spell_item_dementia_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_dementia_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DEMENTIA_POS) ||
+ !sSpellMgr->GetSpellInfo(SPELL_DEMENTIA_NEG))
+ return false;
+ return true;
+ }
+
+ void HandlePeriodicDummy(AuraEffect const* aurEff)
+ {
+ PreventDefaultAction();
+ GetTarget()->CastSpell(GetTarget(), RAND(SPELL_DEMENTIA_POS, SPELL_DEMENTIA_NEG), true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_item_dementia_AuraScript::HandlePeriodicDummy, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_dementia_AuraScript();
+ }
+};
+
// 64411 - Blessing of Ancient Kings (Val'anyr, Hammer of Ancient Kings)
enum BlessingOfAncientKings
{
@@ -175,7 +476,11 @@ class spell_item_blessing_of_ancient_kings : public SpellScriptLoader
{
PreventDefaultAction();
- int32 absorb = int32(CalculatePct(eventInfo.GetHealInfo()->GetHeal(), 15.0f));
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
+ int32 absorb = int32(CalculatePct(healInfo->GetHeal(), 15.0f));
if (AuraEffect* protEff = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_PROTECTION_OF_ANCIENT_KINGS, 0, eventInfo.GetActor()->GetGUID()))
{
// The shield can grow to a maximum size of 20,000 damage absorbtion
@@ -185,7 +490,7 @@ class spell_item_blessing_of_ancient_kings : public SpellScriptLoader
protEff->GetBase()->RefreshDuration();
}
else
- GetTarget()->CastCustomSpell(SPELL_PROTECTION_OF_ANCIENT_KINGS, SPELLVALUE_BASE_POINT0, absorb, eventInfo.GetProcTarget(), true, NULL, aurEff);
+ GetTarget()->CastCustomSpell(SPELL_PROTECTION_OF_ANCIENT_KINGS, SPELLVALUE_BASE_POINT0, absorb, eventInfo.GetProcTarget(), true, nullptr, aurEff);
}
void Register() override
@@ -201,6 +506,168 @@ class spell_item_blessing_of_ancient_kings : public SpellScriptLoader
}
};
+enum DeadlyPrecision
+{
+ SPELL_DEADLY_PRECISION = 71564
+};
+
+// 71564 - Deadly Precision
+class spell_item_deadly_precision : public SpellScriptLoader
+{
+ public:
+ spell_item_deadly_precision() : SpellScriptLoader("spell_item_deadly_precision") { }
+
+ class spell_item_deadly_precision_charm_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_deadly_precision_charm_AuraScript);
+
+ void HandleStackDrop(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+ GetTarget()->RemoveAuraFromStack(GetId(), GetTarget()->GetGUID());
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_deadly_precision_charm_AuraScript::HandleStackDrop, EFFECT_0, SPELL_AURA_MOD_RATING);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_deadly_precision_charm_AuraScript();
+ }
+};
+
+// 71563 - Deadly Precision Dummy
+class spell_item_deadly_precision_dummy : public SpellScriptLoader
+{
+ public:
+ spell_item_deadly_precision_dummy() : SpellScriptLoader("spell_item_deadly_precision_dummy") { }
+
+ class spell_item_deadly_precision_dummy_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_item_deadly_precision_dummy_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DEADLY_PRECISION))
+ return false;
+ return true;
+ }
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DEADLY_PRECISION);
+ GetCaster()->CastCustomSpell(spellInfo->Id, SPELLVALUE_AURA_STACK, spellInfo->StackAmount, GetCaster(), true);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_item_deadly_precision_dummy_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_item_deadly_precision_dummy_SpellScript();
+ }
+};
+
+enum DeathbringersWill
+{
+ SPELL_STRENGTH_OF_THE_TAUNKA = 71484, // +600 Strength
+ SPELL_AGILITY_OF_THE_VRYKUL = 71485, // +600 Agility
+ SPELL_POWER_OF_THE_TAUNKA = 71486, // +1200 Attack Power
+ SPELL_AIM_OF_THE_IRON_DWARVES = 71491, // +600 Critical
+ SPELL_SPEED_OF_THE_VRYKUL = 71492, // +600 Haste
+
+ SPELL_AGILITY_OF_THE_VRYKUL_HERO = 71556, // +700 Agility
+ SPELL_POWER_OF_THE_TAUNKA_HERO = 71558, // +1400 Attack Power
+ SPELL_AIM_OF_THE_IRON_DWARVES_HERO = 71559, // +700 Critical
+ SPELL_SPEED_OF_THE_VRYKUL_HERO = 71560, // +700 Haste
+ SPELL_STRENGTH_OF_THE_TAUNKA_HERO = 71561 // +700 Strength
+};
+
+// Item - 50362: Deathbringer's Will
+// 71519 - Item - Icecrown 25 Normal Melee Trinket
+
+// Item - 50363: Deathbringer's Will
+// 71562 - Item - Icecrown 25 Heroic Melee Trinket
+template <uint32 StrengthSpellId, uint32 AgilitySpellId, uint32 APSpellId, uint32 CriticalSpellId, uint32 HasteSpellId>
+class spell_item_deathbringers_will : public SpellScriptLoader
+{
+ public:
+ spell_item_deathbringers_will(char const* ScriptName) : SpellScriptLoader(ScriptName) { }
+
+ template <uint32 Strength, uint32 Agility, uint32 AttackPower, uint32 Critical, uint32 Haste>
+ class spell_item_deathbringers_will_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_deathbringers_will_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(Strength) ||
+ !sSpellMgr->GetSpellInfo(Agility) ||
+ !sSpellMgr->GetSpellInfo(AttackPower) ||
+ !sSpellMgr->GetSpellInfo(Critical) ||
+ !sSpellMgr->GetSpellInfo(Haste))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ static std::vector<uint32> const triggeredSpells[MAX_CLASSES] =
+ {
+ //CLASS_NONE
+ { },
+ //CLASS_WARRIOR
+ { Strength, Critical, Haste },
+ //CLASS_PALADIN
+ { Strength, Critical, Haste },
+ //CLASS_HUNTER
+ { Agility, Critical, AttackPower },
+ //CLASS_ROGUE
+ { Agility, Haste, AttackPower },
+ //CLASS_PRIEST
+ { },
+ //CLASS_DEATH_KNIGHT
+ { Strength, Critical, Haste },
+ //CLASS_SHAMAN
+ { Agility, Haste, AttackPower },
+ //CLASS_MAGE
+ { },
+ //CLASS_WARLOCK
+ { },
+ //CLASS_UNK
+ { },
+ //CLASS_DRUID
+ { Strength, Agility, Haste }
+ };
+
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ std::vector<uint32> const& randomSpells = triggeredSpells[caster->getClass()];
+ if (randomSpells.empty())
+ return;
+
+ uint32 spellId = Trinity::Containers::SelectRandomContainerElement(randomSpells);
+ caster->CastSpell(caster, spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_deathbringers_will_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_deathbringers_will_AuraScript<StrengthSpellId, AgilitySpellId, APSpellId, CriticalSpellId, HasteSpellId>();
+ }
+};
+
// 47770 - Roll Dice
class spell_item_decahedral_dwarven_dice : public SpellScriptLoader
{
@@ -400,6 +867,46 @@ class spell_item_deviate_fish : public SpellScriptLoader
}
};
+enum DiscerningEyeBeastMisc
+{
+ SPELL_DISCERNING_EYE_BEAST = 59914
+};
+
+// 59915 - Discerning Eye of the Beast Dummy
+class spell_item_discerning_eye_beast_dummy : public SpellScriptLoader
+{
+ public:
+ spell_item_discerning_eye_beast_dummy() : SpellScriptLoader("spell_item_discerning_eye_beast_dummy") { }
+
+ class spell_item_discerning_eye_beast_dummy_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_discerning_eye_beast_dummy_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DISCERNING_EYE_BEAST))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_DISCERNING_EYE_BEAST, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_discerning_eye_beast_dummy_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_discerning_eye_beast_dummy_AuraScript();
+ }
+};
+
// 71610, 71641 - Echoes of Light (Althor's Abacus)
class spell_item_echoes_of_light : public SpellScriptLoader
{
@@ -458,6 +965,7 @@ class spell_item_fate_rune_of_unsurpassed_vigor : public SpellScriptLoader
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
{
+ PreventDefaultAction();
GetTarget()->CastSpell(GetTarget(), SPELL_UNSURPASSED_VIGOR, true);
}
@@ -543,6 +1051,53 @@ class spell_item_flask_of_the_north : public SpellScriptLoader
}
};
+enum FrozenShadoweave
+{
+ SPELL_SHADOWMEND = 39373
+};
+
+// 39372 - Frozen Shadoweave
+// Frozen Shadoweave set 3p bonus
+class spell_item_frozen_shadoweave : public SpellScriptLoader
+{
+ public:
+ spell_item_frozen_shadoweave() : SpellScriptLoader("spell_item_frozen_shadoweave") { }
+
+ class spell_item_frozen_shadoweave_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_frozen_shadoweave_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHADOWMEND))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
+ Unit* caster = eventInfo.GetActor();
+ caster->CastCustomSpell(SPELL_SHADOWMEND, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_frozen_shadoweave_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_frozen_shadoweave_AuraScript();
+ }
+};
+
// http://www.wowhead.com/item=10645 Gnomish Death Ray
// 13280 Gnomish Death Ray
enum GnomishDeathRay
@@ -573,9 +1128,9 @@ class spell_item_gnomish_death_ray : public SpellScriptLoader
if (Unit* target = GetHitUnit())
{
if (urand(0, 99) < 15)
- caster->CastSpell(caster, SPELL_GNOMISH_DEATH_RAY_SELF, true, NULL); // failure
+ caster->CastSpell(caster, SPELL_GNOMISH_DEATH_RAY_SELF, true); // failure
else
- caster->CastSpell(target, SPELL_GNOMISH_DEATH_RAY_TARGET, true, NULL);
+ caster->CastSpell(target, SPELL_GNOMISH_DEATH_RAY_TARGET, true);
}
}
@@ -591,6 +1146,159 @@ class spell_item_gnomish_death_ray : public SpellScriptLoader
}
};
+// Item 23004 - Idol of Longevity
+// 28847 - Healing Touch Refund
+enum IdolOfLongevity
+{
+ SPELL_HEALING_TOUCH_MANA = 28848
+};
+
+class spell_item_healing_touch_refund : public SpellScriptLoader
+{
+ public:
+ spell_item_healing_touch_refund() : SpellScriptLoader("spell_item_healing_touch_refund") { }
+
+ class spell_item_healing_touch_refund_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_healing_touch_refund_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_HEALING_TOUCH_MANA))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_HEALING_TOUCH_MANA, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_healing_touch_refund_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_healing_touch_refund_AuraScript();
+ }
+};
+
+enum Heartpierce
+{
+ SPELL_INVIGORATION_MANA = 71881,
+ SPELL_INVIGORATION_ENERGY = 71882,
+ SPELL_INVIGORATION_RAGE = 71883,
+ SPELL_INVIGORATION_RP = 71884,
+
+ SPELL_INVIGORATION_RP_HERO = 71885,
+ SPELL_INVIGORATION_RAGE_HERO = 71886,
+ SPELL_INVIGORATION_ENERGY_HERO = 71887,
+ SPELL_INVIGORATION_MANA_HERO = 71888
+};
+
+// Item - 49982: Heartpierce
+// 71880 - Item - Icecrown 25 Normal Dagger Proc
+
+// Item - 50641: Heartpierce (Heroic)
+// 71892 - Item - Icecrown 25 Heroic Dagger Proc
+template <uint32 EnergySpellId, uint32 ManaSpellId, uint32 RageSpellId, uint32 RPSpellId>
+class spell_item_heartpierce : public SpellScriptLoader
+{
+ public:
+ spell_item_heartpierce(char const* ScriptName) : SpellScriptLoader(ScriptName) { }
+
+ template <uint32 Energy, uint32 Mana, uint32 Rage, uint32 RunicPower>
+ class spell_item_heartpierce_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_heartpierce_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(Energy) ||
+ !sSpellMgr->GetSpellInfo(Mana) ||
+ !sSpellMgr->GetSpellInfo(Rage) ||
+ !sSpellMgr->GetSpellInfo(RunicPower))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+
+ uint32 spellId;
+ switch (caster->getPowerType())
+ {
+ case POWER_MANA:
+ spellId = Mana;
+ break;
+ case POWER_ENERGY:
+ spellId = Energy;
+ break;
+ case POWER_RAGE:
+ spellId = Rage;
+ break;
+ // Death Knights can't use daggers, but oh well
+ case POWER_RUNIC_POWER:
+ spellId = RunicPower;
+ break;
+ default:
+ return;
+ }
+
+ caster->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_heartpierce_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_heartpierce_AuraScript<EnergySpellId, ManaSpellId, RageSpellId, RPSpellId>();
+ }
+};
+
+// 40971 - Bonus Healing (Crystal Spire of Karabor)
+class spell_item_crystal_spire_of_karabor : public SpellScriptLoader
+{
+ public:
+ spell_item_crystal_spire_of_karabor() : SpellScriptLoader("spell_item_crystal_spire_of_karabor") { }
+
+ class spell_item_crystal_spire_of_karabor_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_crystal_spire_of_karabor_AuraScript);
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ int32 pct = GetSpellInfo()->Effects[EFFECT_0].BasePoints;
+ if (HealInfo* healInfo = eventInfo.GetHealInfo())
+ if (Unit* healTarget = healInfo->GetTarget())
+ if (healTarget->GetHealth() - healInfo->GetEffectiveHeal() <= healTarget->CountPctFromMaxHealth(pct))
+ return true;
+
+ return false;
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_item_crystal_spire_of_karabor_AuraScript::CheckProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_crystal_spire_of_karabor_AuraScript();
+ }
+};
+
// http://www.wowhead.com/item=27388 Mr. Pinchy
// 33060 Make a Wish
enum MakeAWish
@@ -649,6 +1357,53 @@ class spell_item_make_a_wish : public SpellScriptLoader
}
};
+enum MarkOfConquest
+{
+ SPELL_MARK_OF_CONQUEST_ENERGIZE = 39599
+};
+
+// Item - 27920: Mark of Conquest
+// Item - 27921: Mark of Conquest
+// 33510 - Health Restore
+class spell_item_mark_of_conquest : public SpellScriptLoader
+{
+ public:
+ spell_item_mark_of_conquest() : SpellScriptLoader("spell_item_mark_of_conquest") { }
+
+ class spell_item_mark_of_conquest_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_mark_of_conquest_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MARK_OF_CONQUEST_ENERGIZE))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ if (eventInfo.GetTypeMask() & (PROC_FLAG_DONE_RANGED_AUTO_ATTACK | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS))
+ {
+ // in that case, do not cast heal spell
+ PreventDefaultAction();
+ // but mana instead
+ eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MARK_OF_CONQUEST_ENERGIZE, true, nullptr, aurEff);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_mark_of_conquest_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_mark_of_conquest_AuraScript();
+ }
+};
+
// http://www.wowhead.com/item=32686 Mingo's Fortune Giblets
// 40802 Mingo's Fortune Generator
class spell_item_mingos_fortune_generator : public SpellScriptLoader
@@ -735,8 +1490,12 @@ class spell_item_necrotic_touch : public SpellScriptLoader
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- int32 bp = CalculatePct(int32(eventInfo.GetDamageInfo()->GetDamage()), aurEff->GetAmount());
- GetTarget()->CastCustomSpell(SPELL_ITEM_NECROTIC_TOUCH_PROC, SPELLVALUE_BASE_POINT0, bp, eventInfo.GetProcTarget(), true, NULL, aurEff);
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 bp = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
+ GetTarget()->CastCustomSpell(SPELL_ITEM_NECROTIC_TOUCH_PROC, SPELLVALUE_BASE_POINT0, bp, eventInfo.GetProcTarget(), true, nullptr, aurEff);
}
void Register() override
@@ -788,7 +1547,7 @@ class spell_item_net_o_matic : public SpellScriptLoader
else if (roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
spellId = SPELL_NET_O_MATIC_TRIGGERED2;
- GetCaster()->CastSpell(target, spellId, true, NULL);
+ GetCaster()->CastSpell(target, spellId, true, nullptr);
}
}
@@ -844,7 +1603,7 @@ class spell_item_noggenfogger_elixir : public SpellScriptLoader
case 2: spellId = SPELL_NOGGENFOGGER_ELIXIR_TRIGGERED2; break;
}
- caster->CastSpell(caster, spellId, true, NULL);
+ caster->CastSpell(caster, spellId, true, nullptr);
}
void Register() override
@@ -859,6 +1618,138 @@ class spell_item_noggenfogger_elixir : public SpellScriptLoader
}
};
+// 29601 - Enlightenment (Pendant of the Violet Eye)
+class spell_item_pendant_of_the_violet_eye : public SpellScriptLoader
+{
+ public:
+ spell_item_pendant_of_the_violet_eye() : SpellScriptLoader("spell_item_pendant_of_the_violet_eye") { }
+
+ class spell_item_pendant_of_the_violet_eye_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_pendant_of_the_violet_eye_AuraScript);
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
+ return spellInfo->PowerType == POWER_MANA || (spellInfo->ManaCost != 0 && spellInfo->ManaCostPercentage != 0 && spellInfo->ManaCostPerlevel != 0);
+
+ return false;
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_item_pendant_of_the_violet_eye_AuraScript::CheckProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_pendant_of_the_violet_eye_AuraScript();
+ }
+};
+
+enum PersistentShieldMisc
+{
+ SPELL_PERSISTENT_SHIELD_TRIGGERED = 26470
+};
+
+// 26467 - Persistent Shield
+class spell_item_persistent_shield : public SpellScriptLoader
+{
+ public:
+ spell_item_persistent_shield() : SpellScriptLoader("spell_item_persistent_shield") { }
+
+ class spell_item_persistent_shield_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_persistent_shield_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PERSISTENT_SHIELD_TRIGGERED))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ return eventInfo.GetHealInfo() && eventInfo.GetHealInfo()->GetHeal();
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+ int32 bp0 = CalculatePct(eventInfo.GetHealInfo()->GetHeal(), 15);
+
+ // Scarab Brooch does not replace stronger shields
+ if (AuraEffect const* shield = target->GetAuraEffect(SPELL_PERSISTENT_SHIELD_TRIGGERED, EFFECT_0, caster->GetGUID()))
+ if (shield->GetAmount() > bp0)
+ return;
+
+ caster->CastCustomSpell(SPELL_PERSISTENT_SHIELD_TRIGGERED, SPELLVALUE_BASE_POINT0, bp0, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_item_persistent_shield_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_item_persistent_shield_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_persistent_shield_AuraScript();
+ }
+};
+
+enum PetHealing
+{
+ SPELL_HEALTH_LINK = 37382
+};
+
+// 37381 - Pet Healing
+// Hunter T5 2P Bonus
+// Warlock T5 2P Bonus
+class spell_item_pet_healing : public SpellScriptLoader
+{
+ public:
+ spell_item_pet_healing() : SpellScriptLoader("spell_item_pet_healing") { }
+
+ class spell_item_pet_healing_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_pet_healing_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_HEALTH_LINK))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 bp = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
+ Unit* caster = eventInfo.GetActor();
+ caster->CastCustomSpell(SPELL_HEALTH_LINK, SPELLVALUE_BASE_POINT0, bp, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_pet_healing_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_pet_healing_AuraScript();
+ }
+};
+
// 17512 - Piccolo of the Flaming Fire
class spell_item_piccolo_of_the_flaming_fire : public SpellScriptLoader
{
@@ -1071,6 +1962,8 @@ class spell_item_shadows_fate : public SpellScriptLoader
void HandleProc(ProcEventInfo& procInfo)
{
+ PreventDefaultAction();
+
Unit* caster = procInfo.GetActor();
Unit* target = GetCaster();
if (!caster || !target)
@@ -1286,6 +2179,91 @@ class spell_item_six_demon_bag : public SpellScriptLoader
}
};
+enum SwiftHandJusticeMisc
+{
+ SPELL_SWIFT_HAND_OF_JUSTICE_HEAL = 59913
+};
+
+// 59906 - Swift Hand of Justice Dummy
+class spell_item_swift_hand_justice_dummy : public SpellScriptLoader
+{
+ public:
+ spell_item_swift_hand_justice_dummy() : SpellScriptLoader("spell_item_swift_hand_justice_dummy") { }
+
+ class spell_item_swift_hand_justice_dummy_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_swift_hand_justice_dummy_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SWIFT_HAND_OF_JUSTICE_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = eventInfo.GetActor();
+ int32 amount = caster->CountPctFromMaxHealth(aurEff->GetAmount());
+ caster->CastCustomSpell(SPELL_SWIFT_HAND_OF_JUSTICE_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_swift_hand_justice_dummy_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_swift_hand_justice_dummy_AuraScript();
+ }
+};
+
+enum TotemOfFlowingWater
+{
+ SPELL_LESSER_HEALING_WAVE_MANA = 28850
+};
+
+// Item - 23005: Totem of Flowing Water
+// 28849 - Lesser Healing Wave
+class spell_item_totem_of_flowing_water : public SpellScriptLoader
+{
+ public:
+ spell_item_totem_of_flowing_water() : SpellScriptLoader("spell_item_totem_of_flowing_water") { }
+
+ class spell_item_totem_of_flowing_water_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_totem_of_flowing_water_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_LESSER_HEALING_WAVE_MANA))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_LESSER_HEALING_WAVE_MANA, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_totem_of_flowing_water_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_totem_of_flowing_water_AuraScript();
+ }
+
+};
+
// 28862 - The Eye of Diminution
class spell_item_the_eye_of_diminution : public SpellScriptLoader
{
@@ -2731,6 +3709,64 @@ public:
}
};
+enum ShardOfTheScale
+{
+ SPELL_PURIFIED_CAUTERIZING_HEAL = 69733,
+ SPELL_PURIFIED_SEARING_FLAMES = 69729,
+
+ SPELL_SHINY_CAUTERIZING_HEAL = 69734,
+ SPELL_SHINY_SEARING_FLAMES = 69730
+};
+
+// Item - 49310: Purified Shard of the Scale
+// 69755 - Purified Shard of the Scale - Equip Effect
+
+// Item - 49488: Shiny Shard of the Scale
+// 69739 - Shiny Shard of the Scale - Equip Effect
+template <uint32 HealProcSpellId, uint32 DamageProcSpellId>
+class spell_item_shard_of_the_scale : public SpellScriptLoader
+{
+ public:
+ spell_item_shard_of_the_scale(char const* ScriptName) : SpellScriptLoader(ScriptName) { }
+
+ template <uint32 HealProc, uint32 DamageProc>
+ class spell_item_shard_of_the_scale_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_shard_of_the_scale_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(HealProc) ||
+ !sSpellMgr->GetSpellInfo(DamageProc))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+
+ if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS)
+ caster->CastSpell(target, HealProc, true, nullptr, aurEff);
+
+ if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG)
+ caster->CastSpell(target, DamageProc, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_shard_of_the_scale_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_shard_of_the_scale_AuraScript<HealProcSpellId, DamageProcSpellId>();
+ }
+};
+
enum SoulPreserver
{
SPELL_SOUL_PRESERVER_DRUID = 60512,
@@ -2795,6 +3831,90 @@ public:
}
};
+enum ExaltedSunwellNeck
+{
+ SPELL_LIGHTS_WRATH = 45479, // Light's Wrath if Exalted by Aldor
+ SPELL_ARCANE_BOLT = 45429, // Arcane Bolt if Exalted by Scryers
+
+ SPELL_LIGHTS_STRENGTH = 45480, // Light's Strength if Exalted by Aldor
+ SPELL_ARCANE_STRIKE = 45428, // Arcane Strike if Exalted by Scryers
+
+ SPELL_LIGHTS_WARD = 45432, // Light's Ward if Exalted by Aldor
+ SPELL_ARCANE_INSIGHT = 45431, // Arcane Insight if Exalted by Scryers
+
+ SPELL_LIGHTS_SALVATION = 45478, // Light's Salvation if Exalted by Aldor
+ SPELL_ARCANE_SURGE = 45430, // Arcane Surge if Exalted by Scryers
+
+ FACTION_ALDOR = 932,
+ FACTION_SCRYERS = 934
+};
+
+// Item - 34678: Shattered Sun Pendant of Acumen
+// 45481 - Sunwell Exalted Caster Neck
+
+// Item - 34679: Shattered Sun Pendant of Might
+// 45482 - Sunwell Exalted Melee Neck
+
+// Item - 34680: Shattered Sun Pendant of Resolve
+// 45483 - Sunwell Exalted Tank Neck
+
+// Item - 34677: Shattered Sun Pendant of Restoration
+// 45484 Sunwell Exalted Healer Neck
+template <uint32 AldorSpellId, uint32 ScryersSpellId>
+class spell_item_sunwell_neck : public SpellScriptLoader
+{
+ public:
+ spell_item_sunwell_neck(char const* ScriptName) : SpellScriptLoader(ScriptName) { }
+
+ template <uint32 Aldors, uint32 Scryers>
+ class spell_item_sunwell_neck_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_sunwell_neck_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sFactionStore.LookupEntry(FACTION_ALDOR) ||
+ !sFactionStore.LookupEntry(FACTION_SCRYERS) ||
+ !sSpellMgr->GetSpellInfo(Aldors) ||
+ !sSpellMgr->GetSpellInfo(Scryers))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (eventInfo.GetActor()->GetTypeId() != TYPEID_PLAYER)
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Player* player = eventInfo.GetActor()->ToPlayer();
+ Unit* target = eventInfo.GetProcTarget();
+
+ // Aggression checks are in the spell system... just cast and forget
+ if (player->GetReputationRank(FACTION_ALDOR) == REP_EXALTED)
+ player->CastSpell(target, Aldors, true, nullptr, aurEff);
+
+ if (player->GetReputationRank(FACTION_SCRYERS) == REP_EXALTED)
+ player->CastSpell(target, Scryers, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_item_sunwell_neck_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_item_sunwell_neck_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_sunwell_neck_AuraScript<AldorSpellId, ScryersSpellId>();
+ }
+};
+
class spell_item_toy_train_set_pulse : public SpellScriptLoader
{
public:
@@ -3190,6 +4310,11 @@ class spell_item_taunt_flag_targeting : public SpellScriptLoader
void FilterTargets(std::list<WorldObject*>& targets)
{
+ targets.remove_if([](WorldObject* obj) -> bool
+ {
+ return obj->GetTypeId() != TYPEID_PLAYER && obj->GetTypeId() != TYPEID_CORPSE;
+ });
+
if (targets.empty())
{
FinishCast(SPELL_FAILED_NO_VALID_TARGETS);
@@ -3221,6 +4346,182 @@ class spell_item_taunt_flag_targeting : public SpellScriptLoader
}
};
+// 13180 - Gnomish Mind Control Cap
+enum MindControlCap
+{
+ ROLL_CHANCE_DULLARD = 32,
+ ROLL_CHANCE_NO_BACKFIRE = 95,
+ SPELL_GNOMISH_MIND_CONTROL_CAP = 13181,
+ SPELL_DULLARD = 67809
+};
+
+class spell_item_mind_control_cap : public SpellScriptLoader
+{
+ public:
+ spell_item_mind_control_cap() : SpellScriptLoader("spell_item_mind_control_cap") { }
+
+ class spell_item_mind_control_cap_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_item_mind_control_cap_SpellScript);
+
+ bool Load() override
+ {
+ if (!GetCastItem())
+ return false;
+ return true;
+ }
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_GNOMISH_MIND_CONTROL_CAP) || !sSpellMgr->GetSpellInfo(SPELL_DULLARD))
+ return false;
+ return true;
+ }
+
+ void HandleDummy(SpellEffIndex /* effIndex */)
+ {
+ Unit* caster = GetCaster();
+ if (Unit* target = GetHitUnit())
+ {
+ if (roll_chance_i(ROLL_CHANCE_NO_BACKFIRE))
+ caster->CastSpell(target, roll_chance_i(ROLL_CHANCE_DULLARD) ? SPELL_DULLARD : SPELL_GNOMISH_MIND_CONTROL_CAP, true, GetCastItem());
+ else
+ target->CastSpell(caster, SPELL_GNOMISH_MIND_CONTROL_CAP, true); // backfire - 5% chance
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_item_mind_control_cap_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_item_mind_control_cap_SpellScript();
+ }
+};
+
+// 8344 - Universal Remote (Gnomish Universal Remote)
+enum UniversalRemote
+{
+ SPELL_CONTROL_MACHINE = 8345,
+ SPELL_MOBILITY_MALFUNCTION = 8346,
+ SPELL_TARGET_LOCK = 8347
+};
+
+class spell_item_universal_remote : public SpellScriptLoader
+{
+ public:
+ spell_item_universal_remote() : SpellScriptLoader("spell_item_universal_remote") { }
+
+ class spell_item_universal_remote_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_item_universal_remote_SpellScript);
+
+ bool Load() override
+ {
+ if (!GetCastItem())
+ return false;
+ return true;
+ }
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_CONTROL_MACHINE) || !sSpellMgr->GetSpellInfo(SPELL_MOBILITY_MALFUNCTION) || !sSpellMgr->GetSpellInfo(SPELL_TARGET_LOCK))
+ return false;
+ return true;
+ }
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* target = GetHitUnit())
+ {
+ uint8 chance = urand(0, 99);
+ if (chance < 15)
+ GetCaster()->CastSpell(target, SPELL_TARGET_LOCK, true, GetCastItem());
+ else if (chance < 25)
+ GetCaster()->CastSpell(target, SPELL_MOBILITY_MALFUNCTION, true, GetCastItem());
+ else
+ GetCaster()->CastSpell(target, SPELL_CONTROL_MACHINE, true, GetCastItem());
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_item_universal_remote_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_item_universal_remote_SpellScript();
+ }
+};
+
+enum ZandalarianCharms
+{
+ SPELL_UNSTABLE_POWER_AURA_STACK = 24659,
+ SPELL_RESTLESS_STRENGTH_AURA_STACK = 24662
+};
+
+// Item - 19950: Zandalarian Hero Charm
+// 24658 - Unstable Power
+
+// Item - 19949: Zandalarian Hero Medallion
+// 24661 - Restless Strength
+class spell_item_zandalarian_charm : public SpellScriptLoader
+{
+ public:
+ spell_item_zandalarian_charm(char const* ScriptName, uint32 SpellId) : SpellScriptLoader(ScriptName), _spellId(SpellId) { }
+
+ class spell_item_zandalarian_charm_AuraScript : public AuraScript
+ {
+ friend class spell_item_zandalarian_charm;
+ spell_item_zandalarian_charm_AuraScript(uint32 SpellId) : AuraScript(), _spellId(SpellId) { }
+
+ PrepareAuraScript(spell_item_zandalarian_charm_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(_spellId))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
+ if (spellInfo->Id != m_scriptSpellId)
+ return true;
+
+ return false;
+ }
+
+ void HandleStackDrop(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+ GetTarget()->RemoveAuraFromStack(_spellId);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_item_zandalarian_charm_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_item_zandalarian_charm_AuraScript::HandleStackDrop, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+
+ uint32 _spellId;
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_zandalarian_charm_AuraScript(_spellId);
+ }
+
+ private:
+ uint32 _spellId;
+};
+
void AddSC_item_spell_scripts()
{
// 23074 Arcanite Dragonling
@@ -3234,22 +4535,42 @@ void AddSC_item_spell_scripts()
new spell_item_aegis_of_preservation();
new spell_item_arcane_shroud();
+ new spell_item_alchemists_stone();
+ new spell_item_anger_capacitor<8>("spell_item_tiny_abomination_in_a_jar");
+ new spell_item_anger_capacitor<7>("spell_item_tiny_abomination_in_a_jar_hero");
+ new spell_item_argent_dawn_commission();
+ new spell_item_aura_of_madness();
+ new spell_item_dementia();
new spell_item_blessing_of_ancient_kings();
+ new spell_item_deadly_precision();
+ new spell_item_deadly_precision_dummy();
+ new spell_item_deathbringers_will<SPELL_STRENGTH_OF_THE_TAUNKA, SPELL_AGILITY_OF_THE_VRYKUL, SPELL_POWER_OF_THE_TAUNKA, SPELL_AIM_OF_THE_IRON_DWARVES, SPELL_SPEED_OF_THE_VRYKUL>("spell_item_deathbringers_will_normal");
+ new spell_item_deathbringers_will<SPELL_STRENGTH_OF_THE_TAUNKA_HERO, SPELL_AGILITY_OF_THE_VRYKUL_HERO, SPELL_POWER_OF_THE_TAUNKA_HERO, SPELL_AIM_OF_THE_IRON_DWARVES_HERO, SPELL_SPEED_OF_THE_VRYKUL_HERO>("spell_item_deathbringers_will_heroic");
new spell_item_decahedral_dwarven_dice();
new spell_item_defibrillate("spell_item_goblin_jumper_cables", 67, SPELL_GOBLIN_JUMPER_CABLES_FAIL);
new spell_item_defibrillate("spell_item_goblin_jumper_cables_xl", 50, SPELL_GOBLIN_JUMPER_CABLES_XL_FAIL);
new spell_item_defibrillate("spell_item_gnomish_army_knife", 33);
new spell_item_desperate_defense();
new spell_item_deviate_fish();
+ new spell_item_discerning_eye_beast_dummy();
new spell_item_echoes_of_light();
new spell_item_fate_rune_of_unsurpassed_vigor();
new spell_item_flask_of_the_north();
+ new spell_item_frozen_shadoweave();
new spell_item_gnomish_death_ray();
+ new spell_item_healing_touch_refund();
+ new spell_item_heartpierce<SPELL_INVIGORATION_ENERGY, SPELL_INVIGORATION_MANA, SPELL_INVIGORATION_RAGE, SPELL_INVIGORATION_RP>("spell_item_heartpierce");
+ new spell_item_heartpierce<SPELL_INVIGORATION_ENERGY_HERO, SPELL_INVIGORATION_MANA_HERO, SPELL_INVIGORATION_RAGE_HERO, SPELL_INVIGORATION_RP_HERO>("spell_item_heartpierce_hero");
+ new spell_item_crystal_spire_of_karabor();
new spell_item_make_a_wish();
+ new spell_item_mark_of_conquest();
new spell_item_mingos_fortune_generator();
new spell_item_necrotic_touch();
new spell_item_net_o_matic();
new spell_item_noggenfogger_elixir();
+ new spell_item_pendant_of_the_violet_eye();
+ new spell_item_persistent_shield();
+ new spell_item_pet_healing();
new spell_item_piccolo_of_the_flaming_fire();
new spell_item_savory_deviate_delight();
new spell_item_scroll_of_recall();
@@ -3258,6 +4579,8 @@ void AddSC_item_spell_scripts()
new spell_item_shadowmourne();
new spell_item_shadowmourne_soul_fragment();
new spell_item_six_demon_bag();
+ new spell_item_swift_hand_justice_dummy();
+ new spell_item_totem_of_flowing_water();
new spell_item_the_eye_of_diminution();
new spell_item_underbelly_elixir();
new spell_item_worn_troll_dice();
@@ -3291,7 +4614,13 @@ void AddSC_item_spell_scripts()
new spell_item_chicken_cover();
new spell_item_muisek_vessel();
new spell_item_greatmothers_soulcatcher();
+ new spell_item_shard_of_the_scale<SPELL_PURIFIED_CAUTERIZING_HEAL, SPELL_PURIFIED_SEARING_FLAMES>("spell_item_purified_shard_of_the_scale");
+ new spell_item_shard_of_the_scale<SPELL_SHINY_CAUTERIZING_HEAL, SPELL_SHINY_SEARING_FLAMES>("spell_item_shiny_shard_of_the_scale");
new spell_item_soul_preserver();
+ new spell_item_sunwell_neck<SPELL_LIGHTS_WRATH, SPELL_ARCANE_BOLT>("spell_item_sunwell_exalted_caster_neck");
+ new spell_item_sunwell_neck<SPELL_LIGHTS_STRENGTH, SPELL_ARCANE_STRIKE>("spell_item_sunwell_exalted_melee_neck");
+ new spell_item_sunwell_neck<SPELL_LIGHTS_WARD, SPELL_ARCANE_INSIGHT>("spell_item_sunwell_exalted_tank_neck");
+ new spell_item_sunwell_neck<SPELL_LIGHTS_SALVATION, SPELL_ARCANE_SURGE>("spell_item_sunwell_exalted_healer_neck");
new spell_item_toy_train_set_pulse();
new spell_item_death_choice();
new spell_item_trinket_stack("spell_item_lightning_capacitor", SPELL_LIGHTNING_CAPACITOR_STACK, SPELL_LIGHTNING_CAPACITOR_TRIGGER);
@@ -3302,4 +4631,9 @@ void AddSC_item_spell_scripts()
new spell_item_charm_witch_doctor();
new spell_item_mana_drain();
new spell_item_taunt_flag_targeting();
+ new spell_item_mind_control_cap();
+ new spell_item_universal_remote();
+
+ new spell_item_zandalarian_charm("spell_item_unstable_power", SPELL_UNSTABLE_POWER_AURA_STACK);
+ new spell_item_zandalarian_charm("spell_item_restless_strength", SPELL_RESTLESS_STRENGTH_AURA_STACK);
}
diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp
index bacbe31630c..5c496024599 100644
--- a/src/server/scripts/Spells/spell_mage.cpp
+++ b/src/server/scripts/Spells/spell_mage.cpp
@@ -50,6 +50,20 @@ enum MageSpells
SPELL_MAGE_SUMMON_WATER_ELEMENTAL_PERMANENT = 70908,
SPELL_MAGE_SUMMON_WATER_ELEMENTAL_TEMPORARY = 70907,
SPELL_MAGE_GLYPH_OF_BLAST_WAVE = 62126,
+ SPELL_MAGE_CHILLED = 12484,
+ SPELL_MAGE_MANA_SURGE = 37445,
+ SPELL_MAGE_MAGIC_ABSORPTION_MANA = 29442,
+ SPELL_MAGE_ARCANE_POTENCY_RANK_1 = 57529,
+ SPELL_MAGE_ARCANE_POTENCY_RANK_2 = 57531,
+ SPELL_MAGE_HOT_STREAK_PROC = 48108,
+ SPELL_MAGE_ARCANE_SURGE = 37436,
+ SPELL_MAGE_COMBUSTION_PROC = 28682,
+ SPELL_MAGE_EMPOWERED_FIRE_PROC = 67545,
+ SPELL_MAGE_T10_2P_BONUS = 70752,
+ SPELL_MAGE_T10_2P_BONUS_EFFECT = 70753,
+ SPELL_MAGE_T8_4P_BONUS = 64869,
+ SPELL_MAGE_MISSILE_BARRAGE = 44401,
+ SPELL_MAGE_FINGERS_OF_FROST_AURASTATE_AURA = 44544
};
enum MageSpellIcons
@@ -82,6 +96,46 @@ class spell_mage_incanters_absorbtion_base_AuraScript : public AuraScript
}
};
+// -31571 - Arcane Potency
+class spell_mage_arcane_potency : public SpellScriptLoader
+{
+ public:
+ spell_mage_arcane_potency() : SpellScriptLoader("spell_mage_arcane_potency") { }
+
+ class spell_mage_arcane_potency_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_arcane_potency_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_ARCANE_POTENCY_RANK_1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_MAGE_ARCANE_POTENCY_RANK_2))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ static uint32 const triggerSpell[2] = { SPELL_MAGE_ARCANE_POTENCY_RANK_1, SPELL_MAGE_ARCANE_POTENCY_RANK_2 };
+
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ uint32 spellId = triggerSpell[GetSpellInfo()->GetRank() - 1];
+ caster->CastSpell(caster, spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_mage_arcane_potency_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mage_arcane_potency_AuraScript();
+ }
+};
+
// -11113 - Blast Wave
class spell_mage_blast_wave : public SpellScriptLoader
{
@@ -153,6 +207,38 @@ public:
}
};
+// -54747 - Burning Determination
+// 54748 - Burning Determination
+class spell_mage_burning_determination : public SpellScriptLoader
+{
+ public:
+ spell_mage_burning_determination() : SpellScriptLoader("spell_mage_burning_determination") { }
+
+ class spell_mage_burning_determination_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_burning_determination_AuraScript);
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
+ if (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_INTERRUPT) | (1 << MECHANIC_SILENCE)))
+ return true;
+
+ return false;
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_mage_burning_determination_AuraScript::CheckProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mage_burning_determination_AuraScript();
+ }
+};
+
// -44449 - Burnout
class spell_mage_burnout : public SpellScriptLoader
{
@@ -172,17 +258,21 @@ class spell_mage_burnout : public SpellScriptLoader
bool CheckProc(ProcEventInfo& eventInfo)
{
- return eventInfo.GetDamageInfo()->GetSpellInfo() != nullptr;
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetSpellInfo())
+ return false;
+
+ return true;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- int32 mana = int32(eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask()));
+ int32 mana = eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask());
mana = CalculatePct(mana, aurEff->GetAmount());
- GetTarget()->CastCustomSpell(SPELL_MAGE_BURNOUT, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, NULL, aurEff);
+ GetTarget()->CastCustomSpell(SPELL_MAGE_BURNOUT, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, nullptr, aurEff);
}
void Register() override
@@ -235,6 +325,208 @@ class spell_mage_cold_snap : public SpellScriptLoader
}
};
+// 11129 - Combustion
+class spell_mage_combustion : public SpellScriptLoader
+{
+ public:
+ spell_mage_combustion() : SpellScriptLoader("spell_mage_combustion") { }
+
+ class spell_mage_combustion_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_combustion_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_COMBUSTION_PROC))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ // Do not take charges, add a stack of crit buff
+ if (!(eventInfo.GetHitMask() & PROC_HIT_CRITICAL))
+ {
+ eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MAGE_COMBUSTION_PROC, true);
+ return false;
+ }
+
+ return true;
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_mage_combustion_AuraScript::CheckProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mage_combustion_AuraScript();
+ }
+};
+
+// -11185 - Improved Blizzard
+class spell_mage_imp_blizzard : public SpellScriptLoader
+{
+ public:
+ spell_mage_imp_blizzard() : SpellScriptLoader("spell_mage_imp_blizzard") { }
+
+ class spell_mage_imp_blizzard_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_imp_blizzard_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_CHILLED))
+ return false;
+ return true;
+ }
+
+ void HandleChill(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ uint32 triggerSpellId = sSpellMgr->GetSpellWithRank(SPELL_MAGE_CHILLED, GetSpellInfo()->GetRank());
+ eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), triggerSpellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_mage_imp_blizzard_AuraScript::HandleChill, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mage_imp_blizzard_AuraScript();
+ }
+};
+
+// 37447 - Improved Mana Gems
+// 61062 - Improved Mana Gems
+class spell_mage_imp_mana_gems : public SpellScriptLoader
+{
+ public:
+ spell_mage_imp_mana_gems() : SpellScriptLoader("spell_mage_imp_mana_gems") { }
+
+ class spell_mage_imp_mana_gems_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_imp_mana_gems_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_MANA_SURGE))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MAGE_MANA_SURGE, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_mage_imp_mana_gems_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mage_imp_mana_gems_AuraScript();
+ }
+};
+
+// -31656 - Empowered Fire
+class spell_mage_empowered_fire : public SpellScriptLoader
+{
+ public:
+ spell_mage_empowered_fire() : SpellScriptLoader("spell_mage_empowered_fire") { }
+
+ class spell_mage_empowered_fire_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_empowered_fire_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_EMPOWERED_FIRE_PROC))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
+ if (spellInfo->Id == SPELL_MAGE_IGNITE)
+ return true;
+
+ return false;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+
+ Unit* target = GetTarget();
+ int32 bp0 = int32(CalculatePct(target->GetCreateMana(), aurEff->GetAmount()));
+ target->CastCustomSpell(SPELL_MAGE_EMPOWERED_FIRE_PROC, SPELLVALUE_BASE_POINT0, bp0, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_mage_empowered_fire_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_mage_empowered_fire_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_ADD_FLAT_MODIFIER);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mage_empowered_fire_AuraScript();
+ }
+};
+
+// 74396 - Fingers of Frost
+class spell_mage_fingers_of_frost : public SpellScriptLoader
+{
+ public:
+ spell_mage_fingers_of_frost() : SpellScriptLoader("spell_mage_fingers_of_frost") { }
+
+ class spell_mage_fingers_of_frost_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_fingers_of_frost_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_FINGERS_OF_FROST_AURASTATE_AURA))
+ return false;
+ return true;
+ }
+
+ void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->RemoveAuraFromStack(GetId());
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ GetTarget()->RemoveAurasDueToSpell(SPELL_MAGE_FINGERS_OF_FROST_AURASTATE_AURA);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_mage_fingers_of_frost_AuraScript::HandleDummy, EFFECT_0, SPELL_AURA_DUMMY);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_mage_fingers_of_frost_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mage_fingers_of_frost_AuraScript();
+ }
+};
+
// -543 - Fire Ward
// -6143 - Frost Ward
class spell_mage_fire_frost_ward : public SpellScriptLoader
@@ -354,6 +646,222 @@ class spell_mage_focus_magic : public SpellScriptLoader
}
};
+// 44401 - Missile Barrage
+// 48108 - Hot Streak
+// 57761 - Fireball!
+class spell_mage_gen_extra_effects : public SpellScriptLoader
+{
+ public:
+ spell_mage_gen_extra_effects() : SpellScriptLoader("spell_mage_gen_extra_effects") { }
+
+ class spell_mage_gen_extra_effects_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_gen_extra_effects_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_T10_2P_BONUS) ||
+ !sSpellMgr->GetSpellInfo(SPELL_MAGE_T10_2P_BONUS_EFFECT) ||
+ !sSpellMgr->GetSpellInfo(SPELL_MAGE_T8_4P_BONUS))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ Unit* caster = eventInfo.GetActor();
+ // Prevent double proc for Arcane missiles
+ if (caster == eventInfo.GetProcTarget())
+ return false;
+
+ // Proc chance is unknown, we'll just use dummy aura amount
+ if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_MAGE_T8_4P_BONUS, EFFECT_0))
+ if (roll_chance_i(aurEff->GetAmount()))
+ return false;
+
+ return true;
+ }
+
+ void HandleProc(ProcEventInfo& eventInfo)
+ {
+ Unit* caster = eventInfo.GetActor();
+
+ if (caster->HasAura(SPELL_MAGE_T10_2P_BONUS))
+ caster->CastSpell((Unit*)nullptr, SPELL_MAGE_T10_2P_BONUS_EFFECT, true);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_mage_gen_extra_effects_AuraScript::CheckProc);
+ OnProc += AuraProcFn(spell_mage_gen_extra_effects_AuraScript::HandleProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mage_gen_extra_effects_AuraScript();
+ }
+};
+
+// 56375 - Glyph of Polymorph
+class spell_mage_glyph_of_polymorph : public SpellScriptLoader
+{
+ public:
+ spell_mage_glyph_of_polymorph() : SpellScriptLoader("spell_mage_glyph_of_polymorph") { }
+
+ class spell_mage_glyph_of_polymorph_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_glyph_of_polymorph_AuraScript);
+
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* target = eventInfo.GetProcTarget();
+ target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, ObjectGuid::Empty, target->GetAura(32409)); // SW:D shall not be removed.
+ target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
+ target->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_mage_glyph_of_polymorph_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mage_glyph_of_polymorph_AuraScript();
+ }
+};
+
+// 56374 - Glyph of Icy Veins
+class spell_mage_glyph_of_icy_veins : public SpellScriptLoader
+{
+ public:
+ spell_mage_glyph_of_icy_veins() : SpellScriptLoader("spell_mage_glyph_of_icy_veins") { }
+
+ class spell_mage_glyph_of_icy_veins_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_glyph_of_icy_veins_AuraScript);
+
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ caster->RemoveAurasByType(SPELL_AURA_HASTE_SPELLS, ObjectGuid::Empty, 0, true, false);
+ caster->RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_mage_glyph_of_icy_veins_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mage_glyph_of_icy_veins_AuraScript();
+ }
+};
+
+// 56372 - Glyph of Ice Block
+class spell_mage_glyph_of_ice_block : public SpellScriptLoader
+{
+ public:
+ spell_mage_glyph_of_ice_block() : SpellScriptLoader("spell_mage_glyph_of_ice_block") { }
+
+ class spell_mage_glyph_of_ice_block_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_glyph_of_ice_block_AuraScript);
+
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ caster->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
+ {
+ SpellInfo const* cdSpell = sSpellMgr->GetSpellInfo(itr->first);
+ if (!cdSpell || cdSpell->SpellFamilyName != SPELLFAMILY_MAGE
+ || !(cdSpell->SpellFamilyFlags[0] & 0x00000040))
+ return false;
+ return true;
+ }, true);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_mage_glyph_of_ice_block_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mage_glyph_of_ice_block_AuraScript();
+ }
+};
+
+// -44445 - Hot Streak
+class spell_mage_hot_streak : public SpellScriptLoader
+{
+ public:
+ spell_mage_hot_streak() : SpellScriptLoader("spell_mage_hot_streak") { }
+
+ class spell_mage_hot_streak_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_hot_streak_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_HOT_STREAK_PROC))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ AuraEffect* counter = GetEffect(EFFECT_1);
+ if (!counter)
+ return;
+
+ // Count spell criticals in a row in second aura
+ if (eventInfo.GetHitMask() & PROC_HIT_CRITICAL)
+ {
+ counter->SetAmount(counter->GetAmount() * 2);
+ if (counter->GetAmount() < 100) // not enough
+ return;
+
+ // roll chance
+ if (!roll_chance_i(aurEff->GetAmount()))
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ caster->CastSpell(caster, SPELL_MAGE_HOT_STREAK_PROC, true, nullptr, aurEff);
+ }
+
+ // reset counter
+ counter->SetAmount(25);
+ }
+
+ void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ // Prevent console spam
+ PreventDefaultAction();
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_mage_hot_streak_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ OnEffectProc += AuraEffectProcFn(spell_mage_hot_streak_AuraScript::HandleDummy, EFFECT_1, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mage_hot_streak_AuraScript();
+ }
+};
+
// -11426 - Ice Barrier
class spell_mage_ice_barrier : public SpellScriptLoader
{
@@ -435,7 +943,7 @@ class spell_mage_ignite : public SpellScriptLoader
bool CheckProc(ProcEventInfo& eventInfo)
{
- return eventInfo.GetProcTarget() != nullptr;
+ return eventInfo.GetDamageInfo() && eventInfo.GetProcTarget();
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
@@ -447,7 +955,7 @@ class spell_mage_ignite : public SpellScriptLoader
int32 amount = int32(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), pct) / igniteDot->GetMaxTicks());
amount += eventInfo.GetProcTarget()->GetRemainingPeriodicAmount(eventInfo.GetActor()->GetGUID(), SPELL_MAGE_IGNITE, SPELL_AURA_PERIODIC_DAMAGE);
- GetTarget()->CastCustomSpell(SPELL_MAGE_IGNITE, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, NULL, aurEff);
+ GetTarget()->CastCustomSpell(SPELL_MAGE_IGNITE, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, nullptr, aurEff);
}
void Register() override
@@ -502,6 +1010,43 @@ class spell_mage_living_bomb : public SpellScriptLoader
}
};
+// -29441 - Magic Absorption
+class spell_mage_magic_absorption : public SpellScriptLoader
+{
+ public:
+ spell_mage_magic_absorption() : SpellScriptLoader("spell_mage_magic_absorption") { }
+
+ class spell_mage_magic_absorption_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_magic_absorption_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_MAGIC_ABSORPTION_MANA))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActionTarget();
+ int32 bp = CalculatePct(static_cast<int32>(caster->GetMaxPower(POWER_MANA)), aurEff->GetAmount());
+ caster->CastCustomSpell(SPELL_MAGE_MAGIC_ABSORPTION_MANA, SPELLVALUE_BASE_POINT0, bp, caster, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_mage_magic_absorption_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mage_magic_absorption_AuraScript();
+ }
+};
+
// -1463 - Mana Shield
class spell_mage_mana_shield : public SpellScriptLoader
{
@@ -512,6 +1057,14 @@ class spell_mage_mana_shield : public SpellScriptLoader
{
PrepareAuraScript(spell_mage_mana_shield_AuraScript);
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ if (!spell_mage_incanters_absorbtion_base_AuraScript::Validate(spellInfo) ||
+ !sSpellMgr->GetSpellInfo(SPELL_MAGE_ARCANE_SURGE))
+ return false;
+ return true;
+ }
+
void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& canBeRecalculated)
{
canBeRecalculated = false;
@@ -527,10 +1080,18 @@ class spell_mage_mana_shield : public SpellScriptLoader
}
}
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ Unit* caster = eventInfo.GetActionTarget();
+ caster->CastSpell(caster, SPELL_MAGE_ARCANE_SURGE, true, nullptr, aurEff);
+ }
+
void Register() override
{
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mage_mana_shield_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_MANA_SHIELD);
AfterEffectManaShield += AuraEffectManaShieldFn(spell_mage_mana_shield_AuraScript::Trigger, EFFECT_0);
+
+ OnEffectProc += AuraEffectProcFn(spell_mage_mana_shield_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_MANA_SHIELD);
}
};
@@ -559,18 +1120,22 @@ class spell_mage_master_of_elements : public SpellScriptLoader
bool CheckProc(ProcEventInfo& eventInfo)
{
- return eventInfo.GetDamageInfo()->GetSpellInfo() != nullptr;
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetSpellInfo())
+ return false;
+
+ return true;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- int32 mana = int32(eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask()));
+ int32 mana = eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask());
mana = CalculatePct(mana, aurEff->GetAmount());
if (mana > 0)
- GetTarget()->CastCustomSpell(SPELL_MAGE_MASTER_OF_ELEMENTS_ENERGIZE, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, NULL, aurEff);
+ GetTarget()->CastCustomSpell(SPELL_MAGE_MASTER_OF_ELEMENTS_ENERGIZE, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, nullptr, aurEff);
}
void Register() override
@@ -586,6 +1151,42 @@ class spell_mage_master_of_elements : public SpellScriptLoader
}
};
+// -44404 - Missile Barrage
+class spell_mage_missile_barrage : public SpellScriptLoader
+{
+ public:
+ spell_mage_missile_barrage() : SpellScriptLoader("spell_mage_missile_barrage") { }
+
+ class spell_mage_missile_barrage_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_missile_barrage_AuraScript);
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return false;
+
+ // Arcane Blast - full chance
+ if (spellInfo->SpellFamilyFlags[0] & 0x20000000)
+ return true;
+
+ // Rest of spells have half chance
+ return roll_chance_i(50);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_mage_missile_barrage_AuraScript::CheckProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mage_missile_barrage_AuraScript();
+ }
+};
+
enum SilvermoonPolymorph
{
NPC_AUROSALIA = 18744,
@@ -683,17 +1284,31 @@ class spell_mage_summon_water_elemental : public SpellScriptLoader
void AddSC_mage_spell_scripts()
{
+ new spell_mage_arcane_potency();
new spell_mage_blast_wave();
new spell_mage_blazing_speed();
+ new spell_mage_burning_determination();
new spell_mage_burnout();
new spell_mage_cold_snap();
+ new spell_mage_combustion();
+ new spell_mage_imp_blizzard();
+ new spell_mage_imp_mana_gems();
+ new spell_mage_empowered_fire();
+ new spell_mage_fingers_of_frost();
new spell_mage_fire_frost_ward();
new spell_mage_focus_magic();
+ new spell_mage_gen_extra_effects();
+ new spell_mage_glyph_of_polymorph();
+ new spell_mage_glyph_of_icy_veins();
+ new spell_mage_glyph_of_ice_block();
+ new spell_mage_hot_streak();
new spell_mage_ice_barrier();
new spell_mage_ignite();
new spell_mage_living_bomb();
+ new spell_mage_magic_absorption();
new spell_mage_mana_shield();
new spell_mage_master_of_elements();
+ new spell_mage_missile_barrage();
new spell_mage_polymorph_cast_visual();
new spell_mage_summon_water_elemental();
}
diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp
index 6de95af8d8f..693990edd0a 100644
--- a/src/server/scripts/Spells/spell_paladin.cpp
+++ b/src/server/scripts/Spells/spell_paladin.cpp
@@ -70,6 +70,9 @@ enum PaladinSpells
SPELL_PALADIN_JUDGEMENT_OF_LIGHT = 20185,
SPELL_PALADIN_JUDGEMENT_OF_WISDOM = 20186,
+ SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL = 20267,
+ SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA = 20268,
+
SPELL_PALADIN_GLYPH_OF_SALVATION = 63225,
SPELL_PALADIN_RIGHTEOUS_DEFENSE_TAUNT = 31790,
@@ -89,7 +92,41 @@ enum PaladinSpells
SPELL_PALADIN_AURA_MASTERY_IMMUNE = 64364,
SPELL_GENERIC_ARENA_DAMPENING = 74410,
- SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411
+ SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411,
+
+ SPELL_PALADIN_SACRED_SHIELD = 53601,
+ SPELL_PALADIN_T9_HOLY_4P_BONUS = 67191,
+ SPELL_PALADIN_FLASH_OF_LIGHT_PROC = 66922,
+
+ SPELL_PALADIN_JUDGEMENTS_OF_THE_JUST_PROC = 68055,
+
+ SPELL_PALADIN_GLYPH_OF_DIVINITY_PROC = 54986,
+
+ SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA = 31930,
+ SPELL_REPLENISHMENT = 57669,
+ SPELL_PALADIN_RIGHTEOUS_VENGEANCE_DAMAGE = 61840,
+ SPELL_PALADIN_SHEATH_OF_LIGHT_HEAL = 54203,
+ SPELL_PALADIN_SACRED_SHIELD_TRIGGER = 58597,
+ SPELL_PALADIN_T8_HOLY_4P_BONUS = 64895,
+ SPELL_PALADIN_HEART_OF_THE_CRUSADER_EFF_R1 = 21183,
+
+ SPELL_PALADIN_HOLY_POWER_ARMOR = 28790,
+ SPELL_PALADIN_HOLY_POWER_ATTACK_POWER = 28791,
+ SPELL_PALADIN_HOLY_POWER_SPELL_POWER = 28793,
+ SPELL_PALADIN_HOLY_POWER_MP5 = 28795,
+
+ SPELL_PALADIN_HOLY_VENGEANCE = 31803,
+ SPELL_PALADIN_SEAL_OF_VENGEANCE_DAMAGE = 42463,
+ SPELL_PALADIN_BLOOD_CORRUPTION = 53742,
+ SPELL_PALADIN_SEAL_OF_CORRUPTION_DAMAGE = 53739,
+
+ SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA = 31786,
+
+ SPELL_PALADIN_ENDURING_LIGHT = 40471,
+ SPELL_PALADIN_ENDURING_JUDGEMENT = 40472,
+
+ SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL = 54968,
+ SPELL_PALADIN_HOLY_MENDING = 64891
};
enum PaladinSpellIcons
@@ -119,9 +156,16 @@ class spell_pal_ardent_defender : public SpellScriptLoader
enum Spell
{
- PAL_SPELL_ARDENT_DEFENDER_HEAL = 66235,
+ PAL_SPELL_ARDENT_DEFENDER_HEAL = 66235
};
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(PAL_SPELL_ARDENT_DEFENDER_HEAL))
+ return false;
+ return true;
+ }
+
bool Load() override
{
healPct = GetSpellInfo()->Effects[EFFECT_1].CalcValue();
@@ -155,7 +199,7 @@ class spell_pal_ardent_defender : public SpellScriptLoader
: float(defenseSkillValue) / float(reqDefForMaxHeal);
int32 healAmount = int32(victim->CountPctFromMaxHealth(uint32(healPct * pctFromDefense)));
- victim->CastCustomSpell(victim, PAL_SPELL_ARDENT_DEFENDER_HEAL, &healAmount, NULL, NULL, true, NULL, aurEff);
+ victim->CastCustomSpell(PAL_SPELL_ARDENT_DEFENDER_HEAL, SPELLVALUE_BASE_POINT0, healAmount, victim, true, nullptr, aurEff);
victim->GetSpellHistory()->AddCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL, 0, std::chrono::minutes(2));
}
else if (remainingHealth < int32(allowedHealth))
@@ -416,6 +460,37 @@ class spell_pal_blessing_of_sanctuary : public SpellScriptLoader
}
};
+// -31871 - Divine Purpose
+class spell_pal_divine_purpose : public SpellScriptLoader
+{
+ public:
+ spell_pal_divine_purpose() : SpellScriptLoader("spell_pal_divine_purpose") { }
+
+ class spell_pal_divine_purpose_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_divine_purpose_AuraScript);
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ if (!roll_chance_i(aurEff->GetAmount()))
+ return;
+
+ eventInfo.GetProcTarget()->RemoveAurasWithMechanic(1 << MECHANIC_STUN, AURA_REMOVE_BY_ENEMY_SPELL);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_divine_purpose_AuraScript::HandleProc, EFFECT_2, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_divine_purpose_AuraScript();
+ }
+};
+
// 64205 - Divine Sacrifice
class spell_pal_divine_sacrifice : public SpellScriptLoader
{
@@ -630,9 +705,13 @@ class spell_pal_eye_for_an_eye : public SpellScriptLoader
void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
// return damage % to attacker but < 50% own total health
- int32 damage = int32(std::min(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), aurEff->GetAmount()), GetTarget()->GetMaxHealth() / 2));
- GetTarget()->CastCustomSpell(SPELL_PALADIN_EYE_FOR_AN_EYE_DAMAGE, SPELLVALUE_BASE_POINT0, damage, eventInfo.GetProcTarget(), true, NULL, aurEff);
+ int32 damage = std::min(CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount()), static_cast<int32>(GetTarget()->GetMaxHealth()) / 2);
+ GetTarget()->CastCustomSpell(SPELL_PALADIN_EYE_FOR_AN_EYE_DAMAGE, SPELLVALUE_BASE_POINT0, damage, eventInfo.GetProcTarget(), true, nullptr, aurEff);
}
void Register() override
@@ -647,6 +726,50 @@ class spell_pal_eye_for_an_eye : public SpellScriptLoader
}
};
+// 54939 - Glyph of Divinity
+class spell_pal_glyph_of_divinity : public SpellScriptLoader
+{
+ public:
+ spell_pal_glyph_of_divinity() : SpellScriptLoader("spell_pal_glyph_of_divinity") { }
+
+ class spell_pal_glyph_of_divinity_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_glyph_of_divinity_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_GLYPH_OF_DIVINITY_PROC))
+ return false;
+ return true;
+ }
+
+ void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ // Lay on Hands (Rank 1) does not have mana effect
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo || spellInfo->Effects[EFFECT_1].Effect != SPELL_EFFECT_ENERGIZE)
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ if (caster == eventInfo.GetProcTarget())
+ return;
+
+ int32 mana = spellInfo->Effects[EFFECT_1].CalcValue() * 2;
+ caster->CastCustomSpell(SPELL_PALADIN_GLYPH_OF_DIVINITY_PROC, SPELLVALUE_BASE_POINT1, mana, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_glyph_of_divinity_AuraScript::OnProc, EFFECT_0, SPELL_AURA_ADD_PCT_MODIFIER);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_glyph_of_divinity_AuraScript();
+ }
+};
+
// 54968 - Glyph of Holy Light
class spell_pal_glyph_of_holy_light : public SpellScriptLoader
{
@@ -680,6 +803,49 @@ class spell_pal_glyph_of_holy_light : public SpellScriptLoader
}
};
+// 54937 - Glyph of Holy Light (dummy aura)
+class spell_pal_glyph_of_holy_light_dummy : public SpellScriptLoader
+{
+ public:
+ spell_pal_glyph_of_holy_light_dummy() : SpellScriptLoader("spell_pal_glyph_of_holy_light_dummy") { }
+
+ class spell_pal_glyph_of_holy_light_dummy_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_glyph_of_holy_light_dummy_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+ int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount());
+
+ caster->CastCustomSpell(SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_glyph_of_holy_light_dummy_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_glyph_of_holy_light_dummy_AuraScript();
+ }
+};
+
// 63521 - Guarded by The Light
class spell_pal_guarded_by_the_light : public SpellScriptLoader
{
@@ -800,6 +966,43 @@ class spell_pal_hand_of_salvation : public SpellScriptLoader
}
};
+// -20335 - Heart of the Crusader
+class spell_pal_heart_of_the_crusader : public SpellScriptLoader
+{
+ public:
+ spell_pal_heart_of_the_crusader() : SpellScriptLoader("spell_pal_heart_of_the_crusader") { }
+
+ class spell_pal_heart_of_the_crusader_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_heart_of_the_crusader_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_HEART_OF_THE_CRUSADER_EFF_R1))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_PALADIN_HEART_OF_THE_CRUSADER_EFF_R1, GetSpellInfo()->GetRank());
+ eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_heart_of_the_crusader_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_heart_of_the_crusader_AuraScript();
+ }
+};
+
// -20473 - Holy Shock
class spell_pal_holy_shock : public SpellScriptLoader
{
@@ -992,7 +1195,7 @@ class spell_pal_improved_aura : public SpellScriptLoader
uint32 _spellId;
};
-// 63510 - Improved Concentraction Aura (Area Aura)
+// 63510 - Improved Concentration Aura (Area Aura)
// 63514 - Improved Devotion Aura (Area Aura)
// 63531 - Sanctified Retribution (Area Aura)
class spell_pal_improved_aura_effect : public SpellScriptLoader
@@ -1034,6 +1237,108 @@ class spell_pal_improved_aura_effect : public SpellScriptLoader
}
};
+// -20234 - Improved Lay on Hands
+class spell_pal_improved_lay_of_hands : public SpellScriptLoader
+{
+ public:
+ spell_pal_improved_lay_of_hands() : SpellScriptLoader("spell_pal_improved_lay_of_hands") { }
+
+ class spell_pal_improved_lay_of_hands_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_improved_lay_of_hands_AuraScript);
+
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActionTarget()->CastSpell(eventInfo.GetActionTarget(), GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true, nullptr, aurEff, GetTarget()->GetGUID());
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_improved_lay_of_hands_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_improved_lay_of_hands_AuraScript();
+ }
+};
+
+// -53569 - Infusion of Light
+class spell_pal_infusion_of_light : public SpellScriptLoader
+{
+ public:
+ spell_pal_infusion_of_light() : SpellScriptLoader("spell_pal_infusion_of_light") { }
+
+ class spell_pal_infusion_of_light_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_infusion_of_light_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_SACRED_SHIELD) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PALADIN_T9_HOLY_4P_BONUS) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PALADIN_FLASH_OF_LIGHT_PROC))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
+ {
+ // Flash of Light HoT on Flash of Light when Sacred Shield active
+ if (spellInfo->SpellFamilyFlags[0] & 0x40000000 && spellInfo->SpellIconID == 242)
+ {
+ PreventDefaultAction();
+
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
+ Unit* procTarget = eventInfo.GetActionTarget();
+ if (procTarget && procTarget->HasAura(SPELL_PALADIN_SACRED_SHIELD))
+ {
+ Unit* target = GetTarget();
+ int32 duration = sSpellMgr->AssertSpellInfo(SPELL_PALADIN_FLASH_OF_LIGHT_PROC)->GetMaxDuration() / 1000;
+ int32 pct = GetSpellInfo()->Effects[EFFECT_2].CalcValue();
+ ASSERT(duration > 0);
+
+ int32 bp0 = CalculatePct(healInfo->GetHeal() / duration, pct);
+
+ // Item - Paladin T9 Holy 4P Bonus
+ if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_PALADIN_T9_HOLY_4P_BONUS, 0))
+ AddPct(bp0, aurEff->GetAmount());
+
+ target->CastCustomSpell(SPELL_PALADIN_FLASH_OF_LIGHT_PROC, SPELLVALUE_BASE_POINT0, bp0, procTarget, true, nullptr, aurEff);
+ }
+ }
+ // but should not proc on non-critical Holy Shocks
+ else if ((spellInfo->SpellFamilyFlags[0] & 0x200000 || spellInfo->SpellFamilyFlags[1] & 0x10000) && !(eventInfo.GetHitMask() & PROC_HIT_CRITICAL))
+ PreventDefaultAction();
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_infusion_of_light_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_infusion_of_light_AuraScript();
+ }
+};
+
// 37705 - Healing Discount
class spell_pal_item_healing_discount : public SpellScriptLoader
{
@@ -1069,6 +1374,65 @@ class spell_pal_item_healing_discount : public SpellScriptLoader
}
};
+// 40470 - Paladin Tier 6 Trinket
+class spell_pal_item_t6_trinket : public SpellScriptLoader
+{
+ public:
+ spell_pal_item_t6_trinket() : SpellScriptLoader("spell_pal_item_t6_trinket") { }
+
+ class spell_pal_item_t6_trinket_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_item_t6_trinket_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_ENDURING_LIGHT) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PALADIN_ENDURING_JUDGEMENT))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return;
+
+ uint32 spellId;
+ int32 chance;
+
+ // Holy Light & Flash of Light
+ if (spellInfo->SpellFamilyFlags[0] & 0xC0000000)
+ {
+ spellId = SPELL_PALADIN_ENDURING_LIGHT;
+ chance = 15;
+ }
+ // Judgements
+ else if (spellInfo->SpellFamilyFlags[0] & 0x00800000)
+ {
+ spellId = SPELL_PALADIN_ENDURING_JUDGEMENT;
+ chance = 50;
+ }
+ else
+ return;
+
+ if (roll_chance_i(chance))
+ eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_item_t6_trinket_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_item_t6_trinket_AuraScript();
+ }
+};
+
// 53407 - Judgement of Justice
// 20271 - Judgement of Light
// 53408 - Judgement of Wisdom
@@ -1101,11 +1465,13 @@ class spell_pal_judgement : public SpellScriptLoader
for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
{
if ((*i)->GetSpellInfo()->GetSpellSpecific() == SPELL_SPECIFIC_SEAL && (*i)->GetEffIndex() == EFFECT_2)
+ {
if (sSpellMgr->GetSpellInfo((*i)->GetAmount()))
{
spellId2 = (*i)->GetAmount();
break;
}
+ }
}
GetCaster()->CastSpell(GetHitUnit(), _spellId, true);
@@ -1159,6 +1525,164 @@ class spell_pal_judgement_of_command : public SpellScriptLoader
}
};
+// 20185 - Judgement of Light
+class spell_pal_judgement_of_light_heal : public SpellScriptLoader
+{
+ public:
+ spell_pal_judgement_of_light_heal() : SpellScriptLoader("spell_pal_judgement_of_light_heal") { }
+
+ class spell_pal_judgement_of_light_heal_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_judgement_of_light_heal_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = eventInfo.GetProcTarget();
+ int32 amount = static_cast<int32>(caster->CountPctFromMaxHealth(aurEff->GetAmount()));
+
+ caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff, GetCasterGUID());
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_judgement_of_light_heal_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_judgement_of_light_heal_AuraScript();
+ }
+};
+
+// 20186 - Judgement of Wisdom
+class spell_pal_judgement_of_wisdom_mana : public SpellScriptLoader
+{
+ public:
+ spell_pal_judgement_of_wisdom_mana() : SpellScriptLoader("spell_pal_judgement_of_wisdom_mana") { }
+
+ class spell_pal_judgement_of_wisdom_mana_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_judgement_of_wisdom_mana_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ return eventInfo.GetProcTarget()->getPowerType() == POWER_MANA;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = eventInfo.GetProcTarget();
+ int32 amount = CalculatePct(static_cast<int32>(caster->GetCreateMana()), aurEff->GetAmount());
+
+ caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff, GetCasterGUID());
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_pal_judgement_of_wisdom_mana_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_pal_judgement_of_wisdom_mana_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_judgement_of_wisdom_mana_AuraScript();
+ }
+};
+
+// -53695 - Judgements of the Just
+class spell_pal_judgements_of_the_just : public SpellScriptLoader
+{
+ public:
+ spell_pal_judgements_of_the_just() : SpellScriptLoader("spell_pal_judgements_of_the_just") { }
+
+ class spell_pal_judgements_of_the_just_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_judgements_of_the_just_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_JUDGEMENTS_OF_THE_JUST_PROC))
+ return false;
+ return true;
+ }
+
+ void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ GetTarget()->CastSpell(eventInfo.GetActionTarget(), SPELL_PALADIN_JUDGEMENTS_OF_THE_JUST_PROC, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_judgements_of_the_just_AuraScript::OnProc, EFFECT_0, SPELL_AURA_ADD_FLAT_MODIFIER);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_judgements_of_the_just_AuraScript();
+ }
+};
+
+// -31876 - Judgements of the Wise
+class spell_pal_judgements_of_the_wise : public SpellScriptLoader
+{
+ public:
+ spell_pal_judgements_of_the_wise() : SpellScriptLoader("spell_pal_judgements_of_the_wise") { }
+
+ class spell_pal_judgements_of_the_wise_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_judgements_of_the_wise_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_REPLENISHMENT) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = eventInfo.GetActor();
+ caster->CastSpell((Unit*)nullptr, SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA, true, nullptr, aurEff);
+ caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_judgements_of_the_wise_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_judgements_of_the_wise_AuraScript();
+ }
+};
+
// -633 - Lay on Hands
class spell_pal_lay_on_hands : public SpellScriptLoader
{
@@ -1251,8 +1775,12 @@ class spell_pal_light_s_beacon : public SpellScriptLoader
if (!procSpell)
return;
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
uint32 healSpellId = procSpell->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_PALADIN_HOLY_LIGHT)) ? SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_1 : SPELL_PALADIN_BEACON_OF_LIGHT_HEAL_3;
- uint32 heal = CalculatePct(eventInfo.GetHealInfo()->GetHeal(), aurEff->GetAmount());
+ uint32 heal = CalculatePct(healInfo->GetHeal(), aurEff->GetAmount());
Unit* beaconTarget = GetCaster();
if (!beaconTarget || !beaconTarget->HasAura(SPELL_PALADIN_BEACON_OF_LIGHT, eventInfo.GetActor()->GetGUID()))
@@ -1261,7 +1789,7 @@ class spell_pal_light_s_beacon : public SpellScriptLoader
/// @todo: caster must be the healed unit to perform distance checks correctly
/// but that will break animation on clientside
/// caster in spell packets must be the healing unit
- eventInfo.GetActor()->CastCustomSpell(healSpellId, SPELLVALUE_BASE_POINT0, heal, beaconTarget, true);
+ eventInfo.GetActor()->CastCustomSpell(healSpellId, SPELLVALUE_BASE_POINT0, heal, beaconTarget, true, nullptr, aurEff);
}
void Register() override
@@ -1341,6 +1869,55 @@ class spell_pal_righteous_defense : public SpellScriptLoader
}
};
+// -53380 - Righteous Vengeance
+class spell_pal_righteous_vengeance : public SpellScriptLoader
+{
+ public:
+ spell_pal_righteous_vengeance() : SpellScriptLoader("spell_pal_righteous_vengeance") { }
+
+ class spell_pal_righteous_vengeance_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_righteous_vengeance_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_RIGHTEOUS_VENGEANCE_DAMAGE))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_PALADIN_RIGHTEOUS_VENGEANCE_DAMAGE);
+ int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
+ amount /= spellInfo->GetMaxTicks();
+ // Add remaining ticks to damage done
+ amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_PALADIN_RIGHTEOUS_VENGEANCE_DAMAGE, SPELL_AURA_PERIODIC_DAMAGE);
+
+ caster->CastCustomSpell(SPELL_PALADIN_RIGHTEOUS_VENGEANCE_DAMAGE, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_righteous_vengeance_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_righteous_vengeance_AuraScript();
+ }
+};
+
// 58597 - Sacred Shield
class spell_pal_sacred_shield : public SpellScriptLoader
{
@@ -1385,6 +1962,59 @@ class spell_pal_sacred_shield : public SpellScriptLoader
}
};
+// 53601 - Sacred Shield (dummy)
+class spell_pal_sacred_shield_dummy : public SpellScriptLoader
+{
+ public:
+ spell_pal_sacred_shield_dummy() : SpellScriptLoader("spell_pal_sacred_shield_dummy") { }
+
+ class spell_pal_sacred_shield_dummy_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_sacred_shield_dummy_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_SACRED_SHIELD_TRIGGER) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PALADIN_T8_HOLY_4P_BONUS))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = GetCaster();
+ if (!caster)
+ return;
+
+ std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
+ if (_cooldownEnd > now)
+ return;
+
+ Seconds cooldown(aurEff->GetAmount());
+ if (AuraEffect const* bonus = caster->GetAuraEffect(SPELL_PALADIN_T8_HOLY_4P_BONUS, EFFECT_0, caster->GetGUID()))
+ cooldown = Seconds(bonus->GetAmount());
+
+ _cooldownEnd = now + cooldown;
+ caster->CastSpell(eventInfo.GetActionTarget(), SPELL_PALADIN_SACRED_SHIELD_TRIGGER, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_sacred_shield_dummy_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+
+ // Cooldown tracking can't be done in DB because of T8 bonus
+ std::chrono::steady_clock::time_point _cooldownEnd = std::chrono::steady_clock::time_point::min();
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_sacred_shield_dummy_AuraScript();
+ }
+};
+
// 20154, 21084 - Seal of Righteousness - melee proc dummy (addition ${$MWS*(0.022*$AP+0.044*$SPH)} damage)
class spell_pal_seal_of_righteousness : public SpellScriptLoader
{
@@ -1431,6 +2061,342 @@ class spell_pal_seal_of_righteousness : public SpellScriptLoader
}
};
+// 31801 - Seal of Vengeance
+// 53736 - Seal of Corruption
+template <uint32 DoTSpellId, uint32 DamageSpellId>
+class spell_pal_seal_of_vengeance : public SpellScriptLoader
+{
+ public:
+ spell_pal_seal_of_vengeance(char const* ScriptName) : SpellScriptLoader(ScriptName) { }
+
+ template <uint32 DoTSpell, uint32 DamageSpell>
+ class spell_pal_seal_of_vengeance_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_seal_of_vengeance_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(DoTSpell) ||
+ !sSpellMgr->GetSpellInfo(DamageSpell))
+ return false;
+ return true;
+ }
+
+ /*
+ When an auto-attack lands (does not dodge/parry/miss) that can proc a seal the of the following things happen independently of each other (see 2 roll system).
+
+ 1) A "hidden strike" which uses melee combat mechanics occurs. If it lands it refreshes/stacks SoV DoT. Only white swings can trigger a refresh or stack. (This hidden strike mechanic can also proc things like berserking..)
+ 2) A weapon damage based proc will occur if you used a special (CS/DS/judge) or if you have a 5 stack (from auto attacks). This attack can not be avoided.
+
+ Remember #2 happens regardless of #1 landing, it just requires the initial attack (autos, cs, etc) to land.
+
+ Stack Number % of Weapon Damage % with SotP
+ 0 0% 0%
+ 1 6.6% 7.6%
+ 2 13.2% 15.2%
+ 3 19.8% 22.8%
+ 4 26.4% 30.4%
+ 5 33% 38%
+ */
+
+ void HandleApplyDoT(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ if (!(eventInfo.GetTypeMask() & PROC_FLAG_DONE_MELEE_AUTO_ATTACK))
+ return;
+
+ // don't cast triggered, spell already has SPELL_ATTR4_CAN_CAST_WHILE_CASTING attr
+ eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), DoTSpell, TRIGGERED_DONT_RESET_PERIODIC_TIMER, nullptr, aurEff);
+ }
+
+ void HandleSeal(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+
+ // get current aura on target, if any
+ AuraEffect const* sealDot = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PALADIN, 0x00000000, 0x00000800, 0x00000000, caster->GetGUID());
+ if (!sealDot)
+ return;
+
+ uint8 const stacks = sealDot->GetBase()->GetStackAmount();
+ uint8 const maxStacks = sealDot->GetSpellInfo()->StackAmount;
+
+ if (stacks < maxStacks && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS))
+ return;
+
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(DamageSpell);
+ int32 amount = spellInfo->Effects[EFFECT_0].CalcValue();
+ amount *= stacks;
+ amount /= maxStacks;
+
+ caster->CastCustomSpell(DamageSpell, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_seal_of_vengeance_AuraScript::HandleApplyDoT, EFFECT_0, SPELL_AURA_DUMMY);
+ OnEffectProc += AuraEffectProcFn(spell_pal_seal_of_vengeance_AuraScript::HandleSeal, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_seal_of_vengeance_AuraScript<DoTSpellId, DamageSpellId>();
+ }
+};
+
+// 20375 - Seal of Command
+// 21084 - Seal of Righteousness
+// 31801 - Seal of Vengeance
+// 31892 - Seal of Blood
+// 33127 - Seal of Command
+// 38008 - Seal of Blood
+// 41459 - Seal of Blood
+// 53720 - Seal of the Martyr
+// 53736 - Seal of Corruption
+class spell_pal_seals : public SpellScriptLoader
+{
+ public:
+ spell_pal_seals() : SpellScriptLoader("spell_pal_seals") { }
+
+ class spell_pal_seals_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_seals_AuraScript);
+
+ // Effect 2 is used by Judgement code, we prevent the proc to avoid console logging of unknown spell trigger
+ bool CheckDummyProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ return false;
+ }
+
+ void Register() override
+ {
+ DoCheckEffectProc += AuraCheckEffectProcFn(spell_pal_seals_AuraScript::CheckDummyProc, EFFECT_2, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_seals_AuraScript();
+ }
+};
+
+// -31785 - Spiritual Attunement
+class spell_pal_spiritual_attunement : public SpellScriptLoader
+{
+ public:
+ spell_pal_spiritual_attunement() : SpellScriptLoader("spell_pal_spiritual_attunement") { }
+
+ class spell_pal_spiritual_attunement_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_spiritual_attunement_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ // "when healed by other friendly targets' spells"
+ if (eventInfo.GetProcTarget() == eventInfo.GetActionTarget())
+ return false;
+
+ return eventInfo.GetHealInfo() && eventInfo.GetHealInfo()->GetEffectiveHeal();
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ int32 amount = CalculatePct(static_cast<int32>(healInfo->GetEffectiveHeal()), aurEff->GetAmount());
+
+ eventInfo.GetActionTarget()->CastCustomSpell(SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_pal_spiritual_attunement_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_pal_spiritual_attunement_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_spiritual_attunement_AuraScript();
+ }
+};
+
+// -53501 - Sheath of Light
+class spell_pal_sheath_of_light : public SpellScriptLoader
+{
+ public:
+ spell_pal_sheath_of_light() : SpellScriptLoader("spell_pal_sheath_of_light") { }
+
+ class spell_pal_sheath_of_light_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_sheath_of_light_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_SHEATH_OF_LIGHT_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_PALADIN_SHEATH_OF_LIGHT_HEAL);
+ int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount());
+ amount /= spellInfo->GetMaxTicks();
+ // Add remaining ticks to healing done
+ amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_PALADIN_SHEATH_OF_LIGHT_HEAL, SPELL_AURA_PERIODIC_HEAL);
+
+ caster->CastCustomSpell(SPELL_PALADIN_SHEATH_OF_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_sheath_of_light_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_sheath_of_light_AuraScript();
+ }
+};
+
+// 28789 - Holy Power
+class spell_pal_t3_6p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_pal_t3_6p_bonus() : SpellScriptLoader("spell_pal_t3_6p_bonus") { }
+
+ class spell_pal_t3_6p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_t3_6p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_HOLY_POWER_ARMOR) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PALADIN_HOLY_POWER_ATTACK_POWER) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PALADIN_HOLY_POWER_SPELL_POWER) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PALADIN_HOLY_POWER_MP5))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ uint32 spellId;
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+
+ switch (target->getClass())
+ {
+ case CLASS_PALADIN:
+ case CLASS_PRIEST:
+ case CLASS_SHAMAN:
+ case CLASS_DRUID:
+ spellId = SPELL_PALADIN_HOLY_POWER_MP5;
+ break;
+ case CLASS_MAGE:
+ case CLASS_WARLOCK:
+ spellId = SPELL_PALADIN_HOLY_POWER_SPELL_POWER;
+ break;
+ case CLASS_HUNTER:
+ case CLASS_ROGUE:
+ spellId = SPELL_PALADIN_HOLY_POWER_ATTACK_POWER;
+ break;
+ case CLASS_WARRIOR:
+ spellId = SPELL_PALADIN_HOLY_POWER_ARMOR;
+ break;
+ default:
+ return;
+ }
+
+ caster->CastSpell(target, spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_t3_6p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_t3_6p_bonus_AuraScript();
+ }
+};
+
+// 64890 Item - Paladin T8 Holy 2P Bonus
+class spell_pal_t8_2p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_pal_t8_2p_bonus() : SpellScriptLoader("spell_pal_t8_2p_bonus") { }
+
+ class spell_pal_t8_2p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_t8_2p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_HOLY_MENDING))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_PALADIN_HOLY_MENDING);
+ int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount());
+ amount /= spellInfo->GetMaxTicks();
+ // Add remaining ticks to healing done
+ amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_PALADIN_HOLY_MENDING, SPELL_AURA_PERIODIC_HEAL);
+
+ caster->CastCustomSpell(SPELL_PALADIN_HOLY_MENDING, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_t8_2p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pal_t8_2p_bonus_AuraScript();
+ }
+};
+
void AddSC_paladin_spell_scripts()
{
new spell_pal_ardent_defender();
@@ -1439,15 +2405,19 @@ void AddSC_paladin_spell_scripts()
new spell_pal_avenging_wrath();
new spell_pal_blessing_of_faith();
new spell_pal_blessing_of_sanctuary();
+ new spell_pal_divine_purpose();
new spell_pal_divine_sacrifice();
new spell_pal_divine_storm();
new spell_pal_divine_storm_dummy();
new spell_pal_exorcism_and_holy_wrath_damage();
new spell_pal_eye_for_an_eye();
+ new spell_pal_glyph_of_divinity();
new spell_pal_glyph_of_holy_light();
+ new spell_pal_glyph_of_holy_light_dummy();
new spell_pal_guarded_by_the_light();
new spell_pal_hand_of_sacrifice();
new spell_pal_hand_of_salvation();
+ new spell_pal_heart_of_the_crusader();
new spell_pal_holy_shock();
new spell_pal_illumination();
new spell_pal_improved_aura("spell_pal_improved_concentraction_aura", SPELL_PALADIN_IMPROVED_CONCENTRACTION_AURA);
@@ -1457,14 +2427,30 @@ void AddSC_paladin_spell_scripts()
new spell_pal_improved_aura_effect("spell_pal_improved_concentraction_aura_effect");
new spell_pal_improved_aura_effect("spell_pal_improved_devotion_aura_effect");
new spell_pal_improved_aura_effect("spell_pal_sanctified_retribution_effect");
+ new spell_pal_improved_lay_of_hands();
+ new spell_pal_infusion_of_light();
new spell_pal_item_healing_discount();
+ new spell_pal_item_t6_trinket();
new spell_pal_judgement("spell_pal_judgement_of_justice", SPELL_PALADIN_JUDGEMENT_OF_JUSTICE);
new spell_pal_judgement("spell_pal_judgement_of_light", SPELL_PALADIN_JUDGEMENT_OF_LIGHT);
new spell_pal_judgement("spell_pal_judgement_of_wisdom", SPELL_PALADIN_JUDGEMENT_OF_WISDOM);
new spell_pal_judgement_of_command();
+ new spell_pal_judgement_of_light_heal();
+ new spell_pal_judgement_of_wisdom_mana();
+ new spell_pal_judgements_of_the_just();
+ new spell_pal_judgements_of_the_wise();
new spell_pal_lay_on_hands();
new spell_pal_light_s_beacon();
new spell_pal_righteous_defense();
+ new spell_pal_righteous_vengeance();
new spell_pal_sacred_shield();
+ new spell_pal_sacred_shield_dummy();
new spell_pal_seal_of_righteousness();
+ new spell_pal_seal_of_vengeance<SPELL_PALADIN_HOLY_VENGEANCE, SPELL_PALADIN_SEAL_OF_VENGEANCE_DAMAGE>("spell_pal_seal_of_vengeance");
+ new spell_pal_seal_of_vengeance<SPELL_PALADIN_BLOOD_CORRUPTION, SPELL_PALADIN_SEAL_OF_CORRUPTION_DAMAGE>("spell_pal_seal_of_corruption");
+ new spell_pal_seals();
+ new spell_pal_spiritual_attunement();
+ new spell_pal_sheath_of_light();
+ new spell_pal_t3_6p_bonus();
+ new spell_pal_t8_2p_bonus();
}
diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp
index 9e2d265aa9c..8a4bdeedccc 100644
--- a/src/server/scripts/Spells/spell_priest.cpp
+++ b/src/server/scripts/Spells/spell_priest.cpp
@@ -46,6 +46,20 @@ enum PriestSpells
SPELL_PRIEST_SHADOW_WORD_DEATH = 32409,
SPELL_PRIEST_T9_HEALING_2P = 67201,
SPELL_PRIEST_VAMPIRIC_TOUCH_DISPEL = 64085,
+ SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA = 58227,
+ SPELL_REPLENISHMENT = 57669,
+ SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER = 64136,
+ SPELL_PRIEST_ABOLISH_DISEASE = 552,
+ SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL = 15290,
+ SPELL_PRIEST_DIVINE_BLESSING = 40440,
+ SPELL_PRIEST_DIVINE_WRATH = 40441,
+ SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL = 56131,
+ SPELL_PRIEST_ORACULAR_HEAL = 26170,
+ SPELL_PRIEST_ARMOR_OF_FAITH = 28810,
+ SPELL_PRIEST_BLESSED_HEALING = 70772,
+ SPELL_PRIEST_MIND_BLAST_R1 = 8092,
+ SPELL_PRIEST_SHADOW_WORD_DEATH_R1 = 32379,
+ SPELL_PRIEST_MIND_FLAY_DAMAGE = 58381
};
enum PriestSpellIcons
@@ -89,6 +103,50 @@ class RaidCheck
Unit const* _caster;
};
+// 26169 - Oracle Healing Bonus
+class spell_pri_aq_3p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_pri_aq_3p_bonus() : SpellScriptLoader("spell_pri_aq_3p_bonus") { }
+
+ class spell_pri_aq_3p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_aq_3p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_ORACULAR_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ if (caster == eventInfo.GetProcTarget())
+ return;
+
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
+ int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), 10);
+ caster->CastCustomSpell(SPELL_PRIEST_ORACULAR_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pri_aq_3p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pri_aq_3p_bonus_AuraScript();
+ }
+};
+
// -27811 - Blessed Recovery
class spell_pri_blessed_recovery : public SpellScriptLoader
{
@@ -109,16 +167,18 @@ public:
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- if (DamageInfo* dmgInfo = eventInfo.GetDamageInfo())
- {
- if (Unit* target = eventInfo.GetActionTarget())
- {
- uint32 triggerSpell = sSpellMgr->GetSpellWithRank(SPELL_PRIEST_BLESSED_RECOVERY_R1, aurEff->GetSpellInfo()->GetRank());
- uint32 bp = CalculatePct(int32(dmgInfo->GetDamage()), aurEff->GetAmount()) / 3;
- bp += target->GetRemainingPeriodicAmount(target->GetGUID(), triggerSpell, SPELL_AURA_PERIODIC_HEAL);
- target->CastCustomSpell(triggerSpell, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, aurEff);
- }
- }
+ DamageInfo* dmgInfo = eventInfo.GetDamageInfo();
+ if (!dmgInfo || !dmgInfo->GetDamage())
+ return;
+
+ Unit* target = eventInfo.GetActionTarget();
+ uint32 triggerSpell = sSpellMgr->GetSpellWithRank(SPELL_PRIEST_BLESSED_RECOVERY_R1, aurEff->GetSpellInfo()->GetRank());
+ SpellInfo const* triggerInfo = sSpellMgr->AssertSpellInfo(triggerSpell);
+
+ int32 bp = CalculatePct(static_cast<int32>(dmgInfo->GetDamage()), aurEff->GetAmount());
+ bp /= triggerInfo->GetMaxTicks();
+ bp += target->GetRemainingPeriodicAmount(target->GetGUID(), triggerSpell, SPELL_AURA_PERIODIC_HEAL);
+ target->CastCustomSpell(triggerSpell, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, aurEff);
}
void Register() override
@@ -133,6 +193,65 @@ public:
}
};
+// -64127 - Body and Soul
+class spell_pri_body_and_soul : public SpellScriptLoader
+{
+ public:
+ spell_pri_body_and_soul() : SpellScriptLoader("spell_pri_body_and_soul") { }
+
+ class spell_pri_body_and_soul_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_body_and_soul_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PRIEST_ABOLISH_DISEASE))
+ return false;
+ return true;
+ }
+
+ void HandleProcTriggerSpell(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ // Proc only on Power Word: Shield
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo || !(spellInfo->SpellFamilyFlags[0] & 0x00000001))
+ {
+ PreventDefaultAction();
+ return;
+ }
+ }
+
+ void HandleProcDummy(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ // Proc only on self casted abolish disease
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ if (spellInfo->Id != SPELL_PRIEST_ABOLISH_DISEASE || caster != eventInfo.GetProcTarget())
+ return;
+
+ if (roll_chance_i(aurEff->GetAmount()))
+ caster->CastSpell(caster, SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pri_body_and_soul_AuraScript::HandleProcTriggerSpell, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ OnEffectProc += AuraEffectProcFn(spell_pri_body_and_soul_AuraScript::HandleProcDummy, EFFECT_1, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pri_body_and_soul_AuraScript();
+ }
+};
+
// -34861 - Circle of Healing
class spell_pri_circle_of_healing : public SpellScriptLoader
{
@@ -201,7 +320,11 @@ class spell_pri_divine_aegis : public SpellScriptLoader
{
PreventDefaultAction();
- int32 absorb = CalculatePct(int32(eventInfo.GetHealInfo()->GetHeal()), aurEff->GetAmount());
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
+ int32 absorb = CalculatePct(healInfo->GetHeal(), aurEff->GetAmount());
// Multiple effects stack, so let's try to find this aura.
if (AuraEffect const* aegis = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_PRIEST_DIVINE_AEGIS, EFFECT_0))
@@ -209,7 +332,7 @@ class spell_pri_divine_aegis : public SpellScriptLoader
absorb = std::min(absorb, eventInfo.GetProcTarget()->getLevel() * 125);
- GetTarget()->CastCustomSpell(SPELL_PRIEST_DIVINE_AEGIS, SPELLVALUE_BASE_POINT0, absorb, eventInfo.GetProcTarget(), true, NULL, aurEff);
+ GetTarget()->CastCustomSpell(SPELL_PRIEST_DIVINE_AEGIS, SPELLVALUE_BASE_POINT0, absorb, eventInfo.GetProcTarget(), true, nullptr, aurEff);
}
void Register() override
@@ -260,6 +383,50 @@ class spell_pri_divine_hymn : public SpellScriptLoader
}
};
+// 55677 - Glyph of Dispel Magic
+class spell_pri_glyph_of_dispel_magic : public SpellScriptLoader
+{
+ public:
+ spell_pri_glyph_of_dispel_magic() : SpellScriptLoader("spell_pri_glyph_of_dispel_magic") { }
+
+ class spell_pri_glyph_of_dispel_magic_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_glyph_of_dispel_magic_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ // Dispel Magic shares spellfamilyflag with abolish disease
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo || spellInfo->SpellIconID != 74)
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+ int32 amount = static_cast<int32>(target->CountPctFromMaxHealth(aurEff->GetAmount()));
+
+ caster->CastCustomSpell(SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pri_glyph_of_dispel_magic_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pri_glyph_of_dispel_magic_AuraScript();
+ }
+};
+
// 55680 - Glyph of Prayer of Healing
class spell_pri_glyph_of_prayer_of_healing : public SpellScriptLoader
{
@@ -281,9 +448,13 @@ class spell_pri_glyph_of_prayer_of_healing : public SpellScriptLoader
{
PreventDefaultAction();
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
SpellInfo const* triggeredSpellInfo = sSpellMgr->AssertSpellInfo(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL);
- int32 heal = int32(CalculatePct(int32(eventInfo.GetHealInfo()->GetHeal()), aurEff->GetAmount()) / triggeredSpellInfo->GetMaxTicks());
- GetTarget()->CastCustomSpell(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL, SPELLVALUE_BASE_POINT0, heal, eventInfo.GetProcTarget(), true, NULL, aurEff);
+ int32 heal = int32(CalculatePct(healInfo->GetHeal(), aurEff->GetAmount()) / triggeredSpellInfo->GetMaxTicks());
+ GetTarget()->CastCustomSpell(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL, SPELLVALUE_BASE_POINT0, heal, eventInfo.GetProcTarget(), true, nullptr, aurEff);
}
void Register() override
@@ -398,38 +569,117 @@ class spell_pri_hymn_of_hope : public SpellScriptLoader
}
};
-// 37594 - Greater Heal Refund
-class spell_pri_item_greater_heal_refund : public SpellScriptLoader
+// -47569 - Improved Shadowform
+class spell_pri_imp_shadowform : public SpellScriptLoader
+{
+ public:
+ spell_pri_imp_shadowform() : SpellScriptLoader("spell_pri_imp_shadowform") { }
+
+ class spell_pri_imp_shadowform_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_imp_shadowform_AuraScript);
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ if (roll_chance_i(aurEff->GetAmount()))
+ eventInfo.GetActor()->RemoveMovementImpairingAuras();
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pri_imp_shadowform_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pri_imp_shadowform_AuraScript();
+ }
+};
+
+// -15337 - Improved Spirit Tap
+class spell_pri_improved_spirit_tap : public SpellScriptLoader
{
public:
- spell_pri_item_greater_heal_refund() : SpellScriptLoader("spell_pri_item_greater_heal_refund") { }
+ spell_pri_improved_spirit_tap() : SpellScriptLoader("spell_pri_improved_spirit_tap") { }
- class spell_pri_item_greater_heal_refund_AuraScript : public AuraScript
+ class spell_pri_improved_spirit_tap_AuraScript : public AuraScript
{
- PrepareAuraScript(spell_pri_item_greater_heal_refund_AuraScript);
+ PrepareAuraScript(spell_pri_improved_spirit_tap_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
- if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_ITEM_EFFICIENCY))
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_SHADOW_WORD_DEATH_R1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PRIEST_MIND_BLAST_R1))
return false;
return true;
}
- void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
+ {
+ if (spellInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_PRIEST_SHADOW_WORD_DEATH_R1)) ||
+ spellInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_PRIEST_MIND_BLAST_R1)))
+ return true;
+ else if (spellInfo->Id == SPELL_PRIEST_MIND_FLAY_DAMAGE)
+ return roll_chance_i(50);
+ }
+
+ return false;
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_pri_improved_spirit_tap_AuraScript::CheckProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pri_improved_spirit_tap_AuraScript();
+ }
+};
+
+// 40438 - Priest Tier 6 Trinket
+class spell_pri_item_t6_trinket : public SpellScriptLoader
+{
+ public:
+ spell_pri_item_t6_trinket() : SpellScriptLoader("spell_pri_item_t6_trinket") { }
+
+ class spell_pri_item_t6_trinket_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_item_t6_trinket_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_DIVINE_BLESSING) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PRIEST_DIVINE_WRATH))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- GetTarget()->CastSpell(GetTarget(), SPELL_PRIEST_ITEM_EFFICIENCY, true, NULL, aurEff);
+ Unit* caster = eventInfo.GetActor();
+ if (eventInfo.GetSpellTypeMask() & PROC_SPELL_TYPE_HEAL)
+ caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_BLESSING, true, nullptr, aurEff);
+
+ if (eventInfo.GetSpellTypeMask() & PROC_SPELL_TYPE_DAMAGE)
+ caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_WRATH, true, nullptr, aurEff);
}
void Register() override
{
- OnEffectProc += AuraEffectProcFn(spell_pri_item_greater_heal_refund_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ OnEffectProc += AuraEffectProcFn(spell_pri_item_t6_trinket_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
AuraScript* GetAuraScript() const override
{
- return new spell_pri_item_greater_heal_refund_AuraScript();
+ return new spell_pri_item_t6_trinket_AuraScript();
}
};
@@ -572,6 +822,33 @@ class spell_pri_mind_sear : public SpellScriptLoader
}
};
+// -47580 - Pain and Suffering (dummy aura)
+class spell_pri_pain_and_suffering_dummy : public SpellScriptLoader
+{
+ public:
+ spell_pri_pain_and_suffering_dummy() : SpellScriptLoader("spell_pri_pain_and_suffering_dummy") { }
+
+ class spell_pri_pain_and_suffering_dummy_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_pain_and_suffering_dummy_AuraScript);
+
+ bool CheckDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ return false;
+ }
+
+ void Register() override
+ {
+ DoCheckEffectProc += AuraCheckEffectProcFn(spell_pri_pain_and_suffering_dummy_AuraScript::CheckDummy, EFFECT_1, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pri_pain_and_suffering_dummy_AuraScript;
+ }
+};
+
// 47948 - Pain and Suffering (Proc)
class spell_pri_pain_and_suffering_proc : public SpellScriptLoader
{
@@ -587,12 +864,14 @@ class spell_pri_pain_and_suffering_proc : public SpellScriptLoader
Unit* caster = GetCaster();
// Refresh Shadow Word: Pain on target
if (Unit* target = GetHitUnit())
+ {
if (AuraEffect* aur = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, caster->GetGUID()))
{
aur->SetBonusAmount(caster->SpellDamageBonusDone(target, aur->GetSpellInfo(), 0, DOT));
aur->CalculatePeriodic(caster, false, false);
aur->GetBase()->RefreshDuration();
}
+ }
}
void Register() override
@@ -812,17 +1091,22 @@ class spell_pri_renew : public SpellScriptLoader
void HandleApplyEffect(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
{
- if (Unit* caster = GetCaster())
+ Unit* caster = GetCaster();
+ if (!caster)
+ return;
+
+ // Empowered Renew
+ if (AuraEffect const* empoweredRenewAurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, PRIEST_ICON_ID_EMPOWERED_RENEW_TALENT, EFFECT_1))
{
- // Empowered Renew
- if (AuraEffect const* empoweredRenewAurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, PRIEST_ICON_ID_EMPOWERED_RENEW_TALENT, EFFECT_1))
- {
- uint32 heal = caster->SpellHealingBonusDone(GetTarget(), GetSpellInfo(), GetEffect(EFFECT_0)->GetAmount(), DOT);
- heal = GetTarget()->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT);
+ int32 heal = (aurEff->GetAmount() + aurEff->GetBonusAmount()) * aurEff->GetDonePct();
+ if (Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod<SPELLMOD_DOT>(GetId(), heal);
+ heal = GetTarget()->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT);
- int32 basepoints0 = empoweredRenewAurEff->GetAmount() * GetEffect(EFFECT_0)->GetTotalTicks() * int32(heal) / 100;
- caster->CastCustomSpell(GetTarget(), SPELL_PRIEST_EMPOWERED_RENEW, &basepoints0, NULL, NULL, true, NULL, aurEff);
- }
+ heal *= GetSpellInfo()->GetMaxTicks();
+
+ int32 basepoints0 = CalculatePct(heal, empoweredRenewAurEff->GetAmount());
+ caster->CastCustomSpell(SPELL_PRIEST_EMPOWERED_RENEW, SPELLVALUE_BASE_POINT0, basepoints0, GetTarget(), true, nullptr, aurEff);
}
}
@@ -838,6 +1122,56 @@ class spell_pri_renew : public SpellScriptLoader
}
};
+// 57989 - Shadowfiend Death
+class spell_pri_shadowfiend_death : public SpellScriptLoader
+{
+ public:
+ spell_pri_shadowfiend_death() : SpellScriptLoader("spell_pri_shadowfiend_death") { }
+
+ class spell_pri_shadowfiend_death_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_shadowfiend_death_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return false;
+
+ Unit* shadowfiend = eventInfo.GetActionTarget();
+ if (!shadowfiend->GetOwner())
+ return false;
+
+ return shadowfiend->HealthBelowPctDamaged(1, damageInfo->GetDamage());
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActionTarget()->GetOwner();
+ caster->CastSpell(caster, SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_pri_shadowfiend_death_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_pri_shadowfiend_death_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pri_shadowfiend_death_AuraScript();
+ }
+};
+
// -32379 - Shadow Word Death
class spell_pri_shadow_word_death : public SpellScriptLoader
{
@@ -871,6 +1205,48 @@ class spell_pri_shadow_word_death : public SpellScriptLoader
}
};
+// 15286 - Vampiric Embrace
+class spell_pri_vampiric_embrace : public SpellScriptLoader
+{
+ public:
+ spell_pri_vampiric_embrace() : SpellScriptLoader("spell_pri_vampiric_embrace") { }
+
+ class spell_pri_vampiric_embrace_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_vampiric_embrace_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 selfHeal = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
+ int32 partyHeal = selfHeal / 5;
+ Unit* caster = eventInfo.GetActor();
+ caster->CastCustomSpell((Unit*)nullptr, SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL, &partyHeal, &selfHeal, nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pri_vampiric_embrace_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pri_vampiric_embrace_AuraScript();
+ }
+};
+
// -34914 - Vampiric Touch
class spell_pri_vampiric_touch : public SpellScriptLoader
{
@@ -883,26 +1259,45 @@ class spell_pri_vampiric_touch : public SpellScriptLoader
bool Validate(SpellInfo const* /*spellInfo*/) override
{
- if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_VAMPIRIC_TOUCH_DISPEL))
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_VAMPIRIC_TOUCH_DISPEL) ||
+ !sSpellMgr->GetSpellInfo(SPELL_REPLENISHMENT))
return false;
return true;
}
+ bool CheckDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ return false;
+ }
+
void HandleDispel(DispelInfo* /*dispelInfo*/)
{
if (Unit* caster = GetCaster())
+ {
if (Unit* target = GetUnitOwner())
+ {
if (AuraEffect const* aurEff = GetEffect(EFFECT_1))
{
int32 damage = aurEff->GetAmount() * 8;
// backfire damage
- caster->CastCustomSpell(target, SPELL_PRIEST_VAMPIRIC_TOUCH_DISPEL, &damage, NULL, NULL, true, NULL, aurEff);
+ caster->CastCustomSpell(SPELL_PRIEST_VAMPIRIC_TOUCH_DISPEL, SPELLVALUE_BASE_POINT0, damage, target, true, nullptr, aurEff);
}
+ }
+ }
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true, nullptr, aurEff);
}
void Register() override
{
+ DoCheckEffectProc += AuraCheckEffectProcFn(spell_pri_vampiric_touch_AuraScript::CheckDummy, EFFECT_0, SPELL_AURA_DUMMY);
+
AfterDispel += AuraDispelFn(spell_pri_vampiric_touch_AuraScript::HandleDispel);
+ OnEffectProc += AuraEffectProcFn(spell_pri_vampiric_touch_AuraScript::HandleProc, EFFECT_2, SPELL_AURA_DUMMY);
}
};
@@ -912,25 +1307,167 @@ class spell_pri_vampiric_touch : public SpellScriptLoader
}
};
+// 28809 - Greater Heal
+class spell_pri_t3_4p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_pri_t3_4p_bonus() : SpellScriptLoader("spell_pri_t3_4p_bonus") { }
+
+ class spell_pri_t3_4p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_t3_4p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_ARMOR_OF_FAITH))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_PRIEST_ARMOR_OF_FAITH, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pri_t3_4p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pri_t3_4p_bonus_AuraScript();
+ }
+};
+
+// 37594 - Greater Heal Refund
+class spell_pri_t5_heal_2p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_pri_t5_heal_2p_bonus() : SpellScriptLoader("spell_pri_t5_heal_2p_bonus") { }
+
+ class spell_pri_t5_heal_2p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_t5_heal_2p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_ITEM_EFFICIENCY))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (HealInfo* healInfo = eventInfo.GetHealInfo())
+ if (Unit* healTarget = healInfo->GetTarget())
+ if (healInfo->GetEffectiveHeal())
+ if (healTarget->GetHealth() >= healTarget->GetMaxHealth())
+ return true;
+
+ return false;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+ GetTarget()->CastSpell(GetTarget(), SPELL_PRIEST_ITEM_EFFICIENCY, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_pri_t5_heal_2p_bonus_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_pri_t5_heal_2p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pri_t5_heal_2p_bonus_AuraScript();
+ }
+};
+
+// 70770 - Item - Priest T10 Healer 2P Bonus
+class spell_pri_t10_heal_2p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_pri_t10_heal_2p_bonus() : SpellScriptLoader("spell_pri_t10_heal_2p_bonus") { }
+
+ class spell_pri_t10_heal_2p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_t10_heal_2p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_BLESSED_HEALING))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_PRIEST_BLESSED_HEALING);
+ int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount());
+ amount /= spellInfo->GetMaxTicks();
+
+ // Add remaining ticks to healing done
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+ amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_PRIEST_BLESSED_HEALING, SPELL_AURA_PERIODIC_HEAL);
+
+ caster->CastCustomSpell(SPELL_PRIEST_BLESSED_HEALING, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pri_t10_heal_2p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_pri_t10_heal_2p_bonus_AuraScript();
+ }
+};
+
void AddSC_priest_spell_scripts()
{
+ new spell_pri_aq_3p_bonus();
new spell_pri_blessed_recovery();
+ new spell_pri_body_and_soul();
new spell_pri_circle_of_healing();
new spell_pri_divine_aegis();
new spell_pri_divine_hymn();
+ new spell_pri_glyph_of_dispel_magic();
new spell_pri_glyph_of_prayer_of_healing();
new spell_pri_guardian_spirit();
new spell_pri_hymn_of_hope();
- new spell_pri_item_greater_heal_refund();
+ new spell_pri_imp_shadowform();
+ new spell_pri_improved_spirit_tap();
+ new spell_pri_item_t6_trinket();
new spell_pri_lightwell_renew();
new spell_pri_mana_burn();
new spell_pri_mana_leech();
new spell_pri_mind_sear();
+ new spell_pri_pain_and_suffering_dummy();
new spell_pri_pain_and_suffering_proc();
new spell_pri_penance();
new spell_pri_power_word_shield();
new spell_pri_prayer_of_mending_heal();
new spell_pri_renew();
+ new spell_pri_shadowfiend_death();
new spell_pri_shadow_word_death();
+ new spell_pri_vampiric_embrace();
new spell_pri_vampiric_touch();
+ new spell_pri_t3_4p_bonus();
+ new spell_pri_t5_heal_2p_bonus();
+ new spell_pri_t10_heal_2p_bonus();
}
diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp
index 2eca20199b4..fd99888f8d9 100644
--- a/src/server/scripts/Spells/spell_quest.cpp
+++ b/src/server/scripts/Spells/spell_quest.cpp
@@ -2565,6 +2565,146 @@ public:
}
};
+enum ApplyHeatAndStir
+{
+ SPELL_SPURTS_AND_SMOKE = 38594,
+ SPELL_FAILED_MIX_1 = 43376,
+ SPELL_FAILED_MIX_2 = 43378,
+ SPELL_FAILED_MIX_3 = 43970,
+ SPELL_SUCCESSFUL_MIX = 43377,
+
+ CREATURE_GENERIC_TRIGGER_LAB = 24042,
+
+ TALK_0 = 0,
+ TALK_1 = 1
+};
+
+class spell_q11306_mixing_blood : public SpellScriptLoader
+{
+public:
+ spell_q11306_mixing_blood() : SpellScriptLoader("spell_q11306_mixing_blood") { }
+
+ class spell_q11306_mixing_blood_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_q11306_mixing_blood_SpellScript);
+
+ void HandleEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* caster = GetCaster())
+ if (Creature* trigger = caster->FindNearestCreature(CREATURE_GENERIC_TRIGGER_LAB, 100.0f))
+ trigger->AI()->DoCastSelf(SPELL_SPURTS_AND_SMOKE);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_q11306_mixing_blood_SpellScript::HandleEffect, EFFECT_1, SPELL_EFFECT_SEND_EVENT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_q11306_mixing_blood_SpellScript();
+ }
+};
+
+class spell_q11306_mixing_vrykul_blood : public SpellScriptLoader
+{
+ public:
+ spell_q11306_mixing_vrykul_blood() : SpellScriptLoader("spell_q11306_mixing_vrykul_blood") { }
+
+ class spell_q11306_mixing_vrykul_blood_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_q11306_mixing_vrykul_blood_SpellScript);
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* caster = GetCaster())
+ {
+ uint8 chance = urand(0, 99);
+ uint32 spellId = 0;
+
+ // 90% chance of getting one out of three failure effects
+ if (chance < 30)
+ spellId = SPELL_FAILED_MIX_1;
+ else if (chance < 60)
+ spellId = SPELL_FAILED_MIX_2;
+ else if (chance < 90)
+ spellId = SPELL_FAILED_MIX_3;
+ else // 10% chance of successful cast
+ spellId = SPELL_SUCCESSFUL_MIX;
+
+ caster->CastSpell(caster, spellId, true);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_q11306_mixing_vrykul_blood_SpellScript::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_q11306_mixing_vrykul_blood_SpellScript();
+ }
+};
+
+class spell_q11306_failed_mix_43376 : public SpellScriptLoader
+{
+public:
+ spell_q11306_failed_mix_43376() : SpellScriptLoader("spell_q11306_failed_mix_43376") { }
+
+ class spell_q11306_failed_mix_43376_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_q11306_failed_mix_43376_SpellScript);
+
+ void HandleEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* caster = GetCaster())
+ if (Creature* trigger = caster->FindNearestCreature(CREATURE_GENERIC_TRIGGER_LAB, 100.0f))
+ trigger->AI()->Talk(TALK_0, caster);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_q11306_failed_mix_43376_SpellScript::HandleEffect, EFFECT_1, SPELL_EFFECT_SEND_EVENT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_q11306_failed_mix_43376_SpellScript();
+ }
+};
+
+class spell_q11306_failed_mix_43378 : public SpellScriptLoader
+{
+public:
+ spell_q11306_failed_mix_43378() : SpellScriptLoader("spell_q11306_failed_mix_43378") { }
+
+ class spell_q11306_failed_mix_43378_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_q11306_failed_mix_43378_SpellScript);
+
+ void HandleEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* caster = GetCaster())
+ if (Creature* trigger = caster->FindNearestCreature(CREATURE_GENERIC_TRIGGER_LAB, 100.0f))
+ trigger->AI()->Talk(TALK_1, caster);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_q11306_failed_mix_43378_SpellScript::HandleEffect, EFFECT_2, SPELL_EFFECT_SEND_EVENT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_q11306_failed_mix_43378_SpellScript();
+ }
+};
+
void AddSC_quest_spell_scripts()
{
new spell_q55_sacred_cleansing();
@@ -2628,4 +2768,8 @@ void AddSC_quest_spell_scripts()
new spell_q12414_hand_over_reins();
new spell_q13665_q13790_bested_trigger();
new spell_59064_59439_portals();
+ new spell_q11306_mixing_blood();
+ new spell_q11306_mixing_vrykul_blood();
+ new spell_q11306_failed_mix_43376();
+ new spell_q11306_failed_mix_43378();
}
diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp
index 40bb3c8ad42..f3d30af1f84 100644
--- a/src/server/scripts/Spells/spell_rogue.cpp
+++ b/src/server/scripts/Spells/spell_rogue.cpp
@@ -44,7 +44,10 @@ enum RogueSpells
SPELL_ROGUE_HONOR_AMONG_THIEVES = 51698,
SPELL_ROGUE_HONOR_AMONG_THIEVES_PROC = 52916,
SPELL_ROGUE_HONOR_AMONG_THIEVES_2 = 51699,
- SPELL_ROGUE_T10_2P_BONUS = 70804
+ SPELL_ROGUE_T10_2P_BONUS = 70804,
+ SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER = 63975,
+ SPELL_ROGUE_QUICK_RECOVERY_ENERGY = 31663,
+ SPELL_ROGUE_CRIPPLING_POISON = 3409
};
// 13877, 33735, (check 51211, 65956) - Blade Flurry
@@ -80,10 +83,10 @@ class spell_rog_blade_flurry : public SpellScriptLoader
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- if (eventInfo.GetDamageInfo())
+ if (DamageInfo* damageInfo = eventInfo.GetDamageInfo())
{
- int32 damage = eventInfo.GetDamageInfo()->GetDamage();
- GetTarget()->CastCustomSpell(SPELL_ROGUE_BLADE_FLURRY_EXTRA_ATTACK, SPELLVALUE_BASE_POINT0, damage, _procTarget, true, NULL, aurEff);
+ int32 damage = damageInfo->GetDamage();
+ GetTarget()->CastCustomSpell(SPELL_ROGUE_BLADE_FLURRY_EXTRA_ATTACK, SPELLVALUE_BASE_POINT0, damage, _procTarget, true, nullptr, aurEff);
}
}
@@ -173,6 +176,80 @@ class spell_rog_cheat_death : public SpellScriptLoader
}
};
+// -51664 - Cut to the Chase
+class spell_rog_cut_to_the_chase : public SpellScriptLoader
+{
+ public:
+ spell_rog_cut_to_the_chase() : SpellScriptLoader("spell_rog_cut_to_the_chase") { }
+
+ class spell_rog_cut_to_the_chase_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_rog_cut_to_the_chase_AuraScript);
+
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ // "refresh your Slice and Dice duration to its 5 combo point maximum"
+ Unit* caster = eventInfo.GetActor();
+ // lookup Slice and Dice
+ if (AuraEffect const* snd = caster->GetAuraEffect(SPELL_AURA_MOD_MELEE_HASTE, SPELLFAMILY_ROGUE, 0x00040000, 0x00000000, 0x00000000, caster->GetGUID()))
+ {
+ // Max 5 cp duration
+ uint32 countMax = snd->GetSpellInfo()->GetMaxDuration();
+
+ snd->GetBase()->SetDuration(countMax, true);
+ snd->GetBase()->SetMaxDuration(snd->GetBase()->GetDuration());
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_rog_cut_to_the_chase_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_rog_cut_to_the_chase_AuraScript();
+ }
+};
+
+// -51625 - Deadly Brew
+class spell_rog_deadly_brew : public SpellScriptLoader
+{
+ public:
+ spell_rog_deadly_brew() : SpellScriptLoader("spell_rog_deadly_brew") { }
+
+ class spell_rog_deadly_brew_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_rog_deadly_brew_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_CRIPPLING_POISON))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_CRIPPLING_POISON, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_rog_deadly_brew_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_rog_deadly_brew_AuraScript();
+ }
+};
+
// -2818 - Deadly Poison
class spell_rog_deadly_poison : public SpellScriptLoader
{
@@ -522,8 +599,49 @@ class spell_rog_prey_on_the_weak : public SpellScriptLoader
}
};
+// -31244 - Quick Recovery
+class spell_rog_quick_recovery : public SpellScriptLoader
+{
+ public:
+ spell_rog_quick_recovery() : SpellScriptLoader("spell_rog_quick_recovery") { }
+
+ class spell_rog_quick_recovery_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_rog_quick_recovery_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_QUICK_RECOVERY_ENERGY))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ int32 amount = CalculatePct(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask()), aurEff->GetAmount());
+ caster->CastCustomSpell(SPELL_ROGUE_QUICK_RECOVERY_ENERGY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_rog_quick_recovery_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_rog_quick_recovery_AuraScript();
+ }
+};
+
// -1943 - Rupture
-#define RuptureScriptName "spell_rog_rupture"
+static char const* const RuptureScriptName = "spell_rog_rupture";
class spell_rog_rupture : public SpellScriptLoader
{
public:
@@ -586,6 +704,41 @@ class spell_rog_rupture : public SpellScriptLoader
}
};
+// 56800 - Glyph of Backstab (dummy)
+class spell_rog_glyph_of_backstab : public SpellScriptLoader
+{
+ public:
+ spell_rog_glyph_of_backstab() : SpellScriptLoader("spell_rog_glyph_of_backstab") { }
+
+ class spell_rog_glyph_of_backstab_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_rog_glyph_of_backstab_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_rog_glyph_of_backstab_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_rog_glyph_of_backstab_AuraScript();
+ }
+};
+
// 63975 - Glyph of Backstab (triggered - serverside)
class spell_rog_glyph_of_backstab_triggered : public SpellScriptLoader
{
@@ -642,6 +795,37 @@ class spell_rog_glyph_of_backstab_triggered : public SpellScriptLoader
}
};
+// -13983 - Setup
+class spell_rog_setup : public SpellScriptLoader
+{
+ public:
+ spell_rog_setup() : SpellScriptLoader("spell_rog_setup") { }
+
+ class spell_rog_setup_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_rog_setup_AuraScript);
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (Player* target = GetTarget()->ToPlayer())
+ if (eventInfo.GetActor() == target->GetSelectedUnit())
+ return true;
+
+ return false;
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_rog_setup_AuraScript::CheckProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_rog_setup_AuraScript();
+ }
+};
+
// 5938 - Shiv
class spell_rog_shiv : public SpellScriptLoader
{
@@ -785,16 +969,21 @@ public:
{
PrepareAuraScript(spell_rog_honor_among_thieves_AuraScript);
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_HONOR_AMONG_THIEVES_2) ||
+ !sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell))
+ return false;
+ return true;
+ }
+
bool CheckProc(ProcEventInfo& /*eventInfo*/)
{
Unit* caster = GetCaster();
- if (!caster)
+ if (!caster || caster->HasAura(SPELL_ROGUE_HONOR_AMONG_THIEVES_2))
return false;
- if (!caster->GetSpellHistory()->HasCooldown(GetSpellInfo()->Effects[EFFECT_0].TriggerSpell))
- return true;
-
- return false;
+ return true;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
@@ -806,7 +995,7 @@ public:
return;
Unit* target = GetTarget();
- target->CastSpell(target, GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), nullptr, aurEff, caster->GetGUID());
+ target->CastSpell(target, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true, nullptr, aurEff, caster->GetGUID());
}
void Register() override
@@ -851,36 +1040,9 @@ public:
targets.push_back(target);
}
- void HandleBeforeHit()
- {
- Unit* target = GetHitUnit();
- if (!target)
- return;
-
- /*
- * The applied aura has a duration of 8 seconds
- * This prevents new applications while its active
- * Removing it on each new proc enables the application from different sources (different grouped players)
- * and on new procs after the source cooldown is finished (1 second)
- */
- if (target->HasAura(GetSpellInfo()->Id))
- target->RemoveAura(GetSpellInfo()->Id);
- }
-
- void TriggerCooldown()
- {
- Unit* target = GetHitUnit();
- if (!target)
- return;
-
- target->GetSpellHistory()->AddCooldown(GetSpellInfo()->Id, 0, std::chrono::seconds(1));
- }
-
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rog_honor_among_thieves_proc_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_PARTY);
- BeforeHit += SpellHitFn(spell_rog_honor_among_thieves_proc_SpellScript::HandleBeforeHit);
- AfterHit += SpellHitFn(spell_rog_honor_among_thieves_proc_SpellScript::TriggerCooldown);
}
};
@@ -895,14 +1057,17 @@ public:
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
- if (Player* player = GetTarget()->ToPlayer())
- if (Unit* spellTarget = ObjectAccessor::GetUnit(*player, player->GetTarget()))
- player->CastSpell(spellTarget, SPELL_ROGUE_HONOR_AMONG_THIEVES_2, true);
+ Unit* caster = GetCaster();
+ if (!caster)
+ return;
+
+ if (Player* player = caster->ToPlayer())
+ player->CastSpell((Unit*)nullptr, SPELL_ROGUE_HONOR_AMONG_THIEVES_2, true);
}
void Register() override
{
- AfterEffectApply += AuraEffectApplyFn(spell_rog_honor_among_thieves_proc_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectApply += AuraEffectApplyFn(spell_rog_honor_among_thieves_proc_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
}
};
@@ -912,55 +1077,101 @@ public:
}
};
-// 70805 - Rogue T10 2P Bonus -- THIS SHOULD BE REMOVED WITH NEW PROC SYSTEM.
-class spell_rog_t10_2p_bonus : public SpellScriptLoader
+// -51627 - Turn the Tables
+class spell_rog_turn_the_tables : public SpellScriptLoader
{
-public:
- spell_rog_t10_2p_bonus() : SpellScriptLoader("spell_rog_t10_2p_bonus") { }
+ public:
+ spell_rog_turn_the_tables() : SpellScriptLoader("spell_rog_turn_the_tables") { }
- class spell_rog_t10_2p_bonus_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_rog_t10_2p_bonus_AuraScript);
+ class spell_rog_turn_the_tables_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_rog_turn_the_tables_AuraScript);
- bool Validate(SpellInfo const* /*spellInfo*/) override
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = GetCaster();
+ if (!caster)
+ return;
+
+ Unit* target = GetTarget();
+ target->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true, nullptr, aurEff, caster->GetGUID());
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_rog_turn_the_tables_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
{
- if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_T10_2P_BONUS))
- return false;
- return true;
+ return new spell_rog_turn_the_tables_AuraScript();
}
+};
- bool CheckProc(ProcEventInfo& eventInfo)
+// 52910,52914,52915 - Turn the Tables proc
+class spell_rog_turn_the_tables_proc : public SpellScriptLoader
+{
+ public:
+ spell_rog_turn_the_tables_proc() : SpellScriptLoader("spell_rog_turn_the_tables_proc") { }
+
+ class spell_rog_turn_the_tables_proc_SpellScript : public SpellScript
{
- return eventInfo.GetActor() == eventInfo.GetActionTarget();
- }
+ PrepareSpellScript(spell_rog_turn_the_tables_proc_SpellScript);
- void Register() override
+ void FilterTargets(std::list<WorldObject*>& targets)
+ {
+ targets.clear();
+
+ Unit* target = GetOriginalCaster();
+ if (!target)
+ return;
+
+ targets.push_back(target);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rog_turn_the_tables_proc_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_RAID);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
{
- DoCheckProc += AuraCheckProcFn(spell_rog_t10_2p_bonus_AuraScript::CheckProc);
+ return new spell_rog_turn_the_tables_proc_SpellScript();
}
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_rog_t10_2p_bonus_AuraScript();
- }
};
void AddSC_rogue_spell_scripts()
{
new spell_rog_blade_flurry();
new spell_rog_cheat_death();
+ new spell_rog_cut_to_the_chase();
+ new spell_rog_deadly_brew();
new spell_rog_deadly_poison();
new spell_rog_killing_spree();
new spell_rog_nerves_of_steel();
new spell_rog_preparation();
new spell_rog_prey_on_the_weak();
+ new spell_rog_quick_recovery();
new spell_rog_rupture();
+ new spell_rog_glyph_of_backstab();
new spell_rog_glyph_of_backstab_triggered();
+ new spell_rog_setup();
new spell_rog_shiv();
new spell_rog_tricks_of_the_trade();
new spell_rog_tricks_of_the_trade_proc();
new spell_rog_honor_among_thieves();
new spell_rog_honor_among_thieves_proc();
- new spell_rog_t10_2p_bonus();
+ new spell_rog_turn_the_tables();
+ new spell_rog_turn_the_tables_proc();
}
diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp
index ad65c7c6ec7..37b08aee7ca 100644
--- a/src/server/scripts/Spells/spell_shaman.cpp
+++ b/src/server/scripts/Spells/spell_shaman.cpp
@@ -31,6 +31,7 @@
enum ShamanSpells
{
+ SPELL_SHAMAN_ANCESTRAL_AWAKENING_DUMMY = 52759,
SPELL_SHAMAN_ANCESTRAL_AWAKENING_PROC = 52752,
SPELL_SHAMAN_BIND_SIGHT = 6277,
SPELL_SHAMAN_CLEANSING_TOTEM_EFFECT = 52025,
@@ -58,13 +59,79 @@ enum ShamanSpells
SPELL_SHAMAN_TOTEM_EARTHBIND_TOTEM = 6474,
SPELL_SHAMAN_TOTEM_EARTHEN_POWER = 59566,
SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL = 52042,
- SPELL_SHAMAN_TOTEMIC_MASTERY = 38437
+ SPELL_SHAMAN_TOTEMIC_MASTERY = 38437,
+ SPELL_SHAMAN_TIDAL_FORCE_CRIT = 55166,
+ SPELL_SHAMAN_TOTEMIC_POWER_MP5 = 28824,
+ SPELL_SHAMAN_TOTEMIC_POWER_SPELL_POWER = 28825,
+ SPELL_SHAMAN_TOTEMIC_POWER_ATTACK_POWER = 28826,
+ SPELL_SHAMAN_TOTEMIC_POWER_ARMOR = 28827,
+ SPELL_SHAMAN_WINDFURY_WEAPON_R1 = 8232,
+ SPELL_SHAMAN_WINDFURY_ATTACK_MH = 25504,
+ SPELL_SHAMAN_WINDFURY_ATTACK_OH = 33750,
+ SPELL_SHAMAN_ENERGY_SURGE = 40465,
+ SPELL_SHAMAN_POWER_SURGE = 40466,
+ SPELL_SHAMAN_GLYPH_OF_HEALING_WAVE_HEAL = 55533,
+ SPELL_SHAMAN_SPIRIT_HUNT_HEAL = 58879,
+ SPELL_SHAMAN_ELECTRIFIED = 64930,
+ SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE = 71824,
+ SPELL_SHAMAN_CHAINED_HEAL = 70809,
+ SPELL_SHAMAN_TOTEM_OF_WRATH_SPELL_POWER = 63283,
+ SPELL_SHAMAN_FREEZE = 63685,
+ SPELL_SHAMAN_FLAMETONGUE_ATTACK = 10444,
+ SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD_R1 = 45284,
+ SPELL_SHAMAN_CHAIN_LIGHTNING_OVERLOAD_R1 = 45297,
+ SPELL_SHAMAN_LIGHTNING_SHIELD_DAMAGE_R1 = 26364,
+ SPELL_SHAMAN_SHAMANISTIC_RAGE_PROC = 30824,
+ SPELL_SHAMAN_MAELSTROM_POWER = 70831,
+ SPELL_SHAMAN_T10_ENHANCEMENT_4P_BONUS = 70832,
+ SPELL_SHAMAN_BLESSING_OF_THE_ETERNALS_R1 = 51554
};
enum ShamanSpellIcons
{
SHAMAN_ICON_ID_RESTORATIVE_TOTEMS = 338,
- SHAMAN_ICON_ID_SHAMAN_LAVA_FLOW = 3087
+ SHAMAN_ICON_ID_SHAMAN_LAVA_FLOW = 3087,
+ SHAMAN_ICON_ID_TOTEM_OF_WRATH = 2019
+};
+
+// -51556 - Ancestral Awakening
+class spell_sha_ancestral_awakening : public SpellScriptLoader
+{
+ public:
+ spell_sha_ancestral_awakening() : SpellScriptLoader("spell_sha_ancestral_awakening") { }
+
+ class spell_sha_ancestral_awakening_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_ancestral_awakening_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_ANCESTRAL_AWAKENING_DUMMY))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
+ int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount());
+ eventInfo.GetActor()->CastCustomSpell(SPELL_SHAMAN_ANCESTRAL_AWAKENING_DUMMY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_ancestral_awakening_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_ancestral_awakening_AuraScript();
+ }
};
// 52759 - Ancestral Awakening (Proc)
@@ -167,6 +234,37 @@ class spell_sha_astral_shift : public SpellScriptLoader
}
};
+// -51474 - Astral Shift aura
+class spell_sha_astral_shift_aura : public SpellScriptLoader
+{
+ public:
+ spell_sha_astral_shift_aura() : SpellScriptLoader("spell_sha_astral_shift_aura") { }
+
+ class spell_sha_astral_shift_aura_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_astral_shift_aura_AuraScript);
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
+ if (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_SILENCE) | (1 << MECHANIC_STUN) | (1 << MECHANIC_FEAR)))
+ return true;
+
+ return false;
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_sha_astral_shift_aura_AuraScript::CheckProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_astral_shift_aura_AuraScript();
+ }
+};
+
// 2825 - Bloodlust
class spell_sha_bloodlust : public SpellScriptLoader
{
@@ -311,57 +409,26 @@ class spell_sha_earth_shield : public SpellScriptLoader
{
if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_EARTH_SHIELD_HEAL))
return false;
- if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_GLYPH_OF_EARTH_SHIELD))
- return false;
return true;
}
- void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool & /*canBeRecalculated*/)
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
if (Unit* caster = GetCaster())
- {
amount = caster->SpellHealingBonusDone(GetUnitOwner(), GetSpellInfo(), amount, HEAL);
- amount = GetUnitOwner()->SpellHealingBonusTaken(caster, GetSpellInfo(), amount, HEAL);
-
- //! WORKAROUND
- // If target is affected by healing reduction, modifier is guaranteed to be negative
- // value (e.g. -50). To revert the effect, multiply amount with reciprocal of relative value:
- // (100 / ((-1) * modifier)) * 100 = (-1) * 100 * 100 / modifier = -10000 / modifier
- if (int32 modifier = GetUnitOwner()->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT))
- ApplyPct(amount, -10000.0f / float(modifier));
-
- // Glyph of Earth Shield
- //! WORKAROUND
- //! this glyph is a proc
- if (AuraEffect* glyph = caster->GetAuraEffect(SPELL_SHAMAN_GLYPH_OF_EARTH_SHIELD, EFFECT_0))
- AddPct(amount, glyph->GetAmount());
- }
- }
-
- bool CheckProc(ProcEventInfo& /*eventInfo*/)
- {
- //! HACK due to currenct proc system implementation
- if (Player* player = GetTarget()->ToPlayer())
- if (player->GetSpellHistory()->HasCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL))
- return false;
- return true;
+ // SpellHealingBonusTaken will be called on Heal
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
{
PreventDefaultAction();
- GetTarget()->CastCustomSpell(SPELL_SHAMAN_EARTH_SHIELD_HEAL, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), GetTarget(), true, NULL, aurEff, GetCasterGUID());
-
- /// @hack: due to currenct proc system implementation
- if (Player* player = GetTarget()->ToPlayer())
- player->GetSpellHistory()->AddCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL, 0, std::chrono::seconds(3));
+ GetTarget()->CastCustomSpell(SPELL_SHAMAN_EARTH_SHIELD_HEAL, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), GetTarget(), true, nullptr, aurEff, GetCasterGUID());
}
void Register() override
{
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_sha_earth_shield_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_DUMMY);
- DoCheckProc += AuraCheckProcFn(spell_sha_earth_shield_AuraScript::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_sha_earth_shield_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
@@ -471,6 +538,46 @@ class spell_sha_earthen_power : public SpellScriptLoader
}
};
+// -51940 - Earthliving Weapon (Passive)
+class spell_sha_earthliving_weapon : public SpellScriptLoader
+{
+ public:
+ spell_sha_earthliving_weapon() : SpellScriptLoader("spell_sha_earthliving_weapon") { }
+
+ class spell_sha_earthliving_weapon_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_earthliving_weapon_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_BLESSING_OF_THE_ETERNALS_R1))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ int32 chance = 20;
+ Unit* caster = eventInfo.GetActor();
+ if (AuraEffect const* aurEff = caster->GetAuraEffectOfRankedSpell(SPELL_SHAMAN_BLESSING_OF_THE_ETERNALS_R1, EFFECT_1, caster->GetGUID()))
+ if (eventInfo.GetProcTarget()->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT))
+ chance += aurEff->GetAmount();
+
+ return roll_chance_i(chance);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_sha_earthliving_weapon_AuraScript::CheckProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_earthliving_weapon_AuraScript();
+ }
+};
+
// -1535 - Fire Nova
class spell_sha_fire_nova : public SpellScriptLoader
{
@@ -575,6 +682,281 @@ class spell_sha_flame_shock : public SpellScriptLoader
}
};
+// -10400 - Flametongue Weapon (Passive)
+class spell_sha_flametongue_weapon : public SpellScriptLoader
+{
+ public:
+ spell_sha_flametongue_weapon() : SpellScriptLoader("spell_sha_flametongue_weapon") { }
+
+ class spell_sha_flametongue_weapon_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_flametongue_weapon_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_FLAMETONGUE_ATTACK))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ Player* player = eventInfo.GetActor()->ToPlayer();
+ if (!player)
+ return false;
+
+ Item* item = player->GetItemByGuid(GetAura()->GetCastItemGUID());
+ if (!item || !item->IsEquipped())
+ return false;
+
+ WeaponAttackType attType = static_cast<WeaponAttackType>(player->GetAttackBySlot(item->GetSlot()));
+ if (attType != BASE_ATTACK && attType != OFF_ATTACK)
+ return false;
+
+ if (((attType == BASE_ATTACK) && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_MAINHAND_ATTACK)) ||
+ ((attType == OFF_ATTACK) && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_OFFHAND_ATTACK)))
+ return false;
+
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Player* player = eventInfo.GetActor()->ToPlayer();
+ Unit* target = eventInfo.GetProcTarget();
+ WeaponAttackType attType = BASE_ATTACK;
+ if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_OFFHAND_ATTACK)
+ attType = OFF_ATTACK;
+
+ Item* item = ASSERT_NOTNULL(player->GetWeaponForAttack(attType));
+
+ float const basePoints = GetSpellInfo()->Effects[aurEff->GetEffIndex()].CalcValue();
+
+ // Flametongue max damage is normalized based on a 4.0 speed weapon
+ // Tooltip says max damage = BasePoints / 25, so BasePoints / 25 / 4 to get base damage per 1.0s AS
+ float fireDamage = basePoints / 100.0f;
+ float const attackSpeed = player->GetAttackTime(attType) / 1000.f;
+ fireDamage *= attackSpeed;
+
+ // clip value between (BasePoints / 77) and (BasePoints / 25) as the tooltip indicates
+ RoundToInterval(fireDamage, basePoints / 77.0f, basePoints / 25.0f);
+
+ // Calculate Spell Power scaling
+ float spellPowerBonus = player->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE) + target->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_FIRE);
+ float const spCoeff = 0.03811f;
+ spellPowerBonus *= spCoeff * attackSpeed;
+
+ // All done, now proc damage
+ int32 amount = static_cast<int32>(fireDamage + spellPowerBonus);
+ player->CastCustomSpell(SPELL_SHAMAN_FLAMETONGUE_ATTACK, SPELLVALUE_BASE_POINT0, amount, target, true, item, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_sha_flametongue_weapon_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_sha_flametongue_weapon_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_flametongue_weapon_AuraScript();
+ }
+};
+
+// -63373 - Frozen Power
+class spell_sha_frozen_power : public SpellScriptLoader
+{
+ public:
+ spell_sha_frozen_power() : SpellScriptLoader("spell_sha_frozen_power") { }
+
+ class spell_sha_frozen_power_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_frozen_power_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_FREEZE))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ if (!roll_chance_i(aurEff->GetAmount()))
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_FREEZE);
+ float minDistance(spellInfo->Effects[EFFECT_0].CalcValue(caster));
+
+ Unit* target = eventInfo.GetProcTarget();
+ if (caster->GetDistance(target) < minDistance)
+ return;
+
+ caster->CastSpell(target, SPELL_SHAMAN_FREEZE, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_frozen_power_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_frozen_power_AuraScript();
+ }
+};
+
+// 63279 - Glyph of Earth Shield
+class spell_sha_glyph_of_earth_shield : public SpellScriptLoader
+{
+ public:
+ spell_sha_glyph_of_earth_shield() : SpellScriptLoader("spell_sha_glyph_of_earth_shield") { }
+
+ class spell_sha_glyph_of_earth_shield_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_glyph_of_earth_shield_AuraScript);
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ SpellInfo const* earthShield = eventInfo.GetSpellInfo();
+ if (!earthShield)
+ return;
+
+ AuraEffect* earthShieldEffect = eventInfo.GetProcTarget()->GetAuraEffect(earthShield->Id, EFFECT_0, eventInfo.GetActor()->GetGUID());
+ if (!earthShieldEffect)
+ return;
+
+ int32 amount = earthShieldEffect->GetAmount();
+ AddPct(amount, aurEff->GetAmount());
+ earthShieldEffect->SetAmount(amount);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_glyph_of_earth_shield_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_glyph_of_earth_shield_AuraScript();
+ }
+};
+
+// 55440 - Glyph of Healing Wave
+class spell_sha_glyph_of_healing_wave : public SpellScriptLoader
+{
+ public:
+ spell_sha_glyph_of_healing_wave() : SpellScriptLoader("spell_sha_glyph_of_healing_wave") { }
+
+ class spell_sha_glyph_of_healing_wave_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_glyph_of_healing_wave_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_GLYPH_OF_HEALING_WAVE_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ if (caster == eventInfo.GetProcTarget())
+ return;
+
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
+ int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount());
+ caster->CastCustomSpell(SPELL_SHAMAN_GLYPH_OF_HEALING_WAVE_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_glyph_of_healing_wave_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_glyph_of_healing_wave_AuraScript();
+ }
+};
+
+// 63280 - Glyph of Totem of Wrath
+class spell_sha_glyph_of_totem_of_wrath : public SpellScriptLoader
+{
+ public:
+ spell_sha_glyph_of_totem_of_wrath() : SpellScriptLoader("spell_sha_glyph_of_totem_of_wrath") { }
+
+ class spell_sha_glyph_of_totem_of_wrath_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_glyph_of_totem_of_wrath_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_TOTEM_OF_WRATH_SPELL_POWER))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ // Totem of Wrath shares family flags with other totems
+ // filter by spellIcon instead
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo || spellInfo->SpellIconID != SHAMAN_ICON_ID_TOTEM_OF_WRATH)
+ return false;
+
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = eventInfo.GetActor();
+
+ // Fire totem summon slot
+ Creature* totem = ObjectAccessor::GetCreature(*caster, caster->m_SummonSlot[1]);
+ if (!totem)
+ return;
+
+ SpellInfo const* totemSpell = sSpellMgr->GetSpellInfo(totem->m_spells[0]);
+ if (!totemSpell)
+ return;
+
+ int32 bp0 = CalculatePct(totemSpell->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount());
+ int32 bp1 = CalculatePct(totemSpell->Effects[EFFECT_1].CalcValue(caster), aurEff->GetAmount());
+ caster->CastCustomSpell((Unit*)nullptr, SPELL_SHAMAN_TOTEM_OF_WRATH_SPELL_POWER, &bp0, &bp1, nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_sha_glyph_of_totem_of_wrath_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_sha_glyph_of_totem_of_wrath_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_glyph_of_totem_of_wrath_AuraScript();
+ }
+};
+
// 52041, 52046, 52047, 52048, 52049, 52050, 58759, 58760, 58761 - Healing Stream Totem
class spell_sha_healing_stream_totem : public SpellScriptLoader
{
@@ -597,6 +979,7 @@ class spell_sha_healing_stream_totem : public SpellScriptLoader
int32 damage = GetEffectValue();
SpellInfo const* triggeringSpell = GetTriggeringSpell();
if (Unit* target = GetHitUnit())
+ {
if (Unit* caster = GetCaster())
{
if (Unit* owner = caster->GetOwner())
@@ -614,8 +997,10 @@ class spell_sha_healing_stream_totem : public SpellScriptLoader
damage = int32(target->SpellHealingBonusTaken(owner, triggeringSpell, damage, HEAL));
}
- caster->CastCustomSpell(target, SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL, &damage, 0, 0, true, 0, 0, GetOriginalCaster()->GetGUID());
+
+ caster->CastCustomSpell(SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL, SPELLVALUE_BASE_POINT0, damage, target, true, nullptr, nullptr, GetOriginalCaster()->GetGUID());
}
+ }
}
void Register() override
@@ -660,9 +1045,8 @@ class spell_sha_heroism : public SpellScriptLoader
void Register() override
{
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism_SpellScript::RemoveInvalidTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_RAID);
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism_SpellScript::RemoveInvalidTargets, EFFECT_1, TARGET_UNIT_CASTER_AREA_RAID);
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism_SpellScript::RemoveInvalidTargets, EFFECT_2, TARGET_UNIT_CASTER_AREA_RAID);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism_SpellScript::RemoveInvalidTargets, EFFECT_ALL, TARGET_UNIT_CASTER_AREA_RAID);
+
AfterHit += SpellHitFn(spell_sha_heroism_SpellScript::ApplyDebuff);
}
};
@@ -673,6 +1057,125 @@ class spell_sha_heroism : public SpellScriptLoader
}
};
+// -16180 - Improved Water Shield
+class spell_sha_imp_water_shield : public SpellScriptLoader
+{
+ public:
+ spell_sha_imp_water_shield() : SpellScriptLoader("spell_sha_imp_water_shield") { }
+
+ class spell_sha_imp_water_shield_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_imp_water_shield_AuraScript);
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return false;
+
+ // If we're here, we've already passed initial aura roll
+ // So just chance based on 100%
+
+ // Default chance for Healing Wave and Riptide
+ int32 chance = 100;
+ // Lesser Healing Wave - 0.6 of default
+ if (spellInfo->SpellFamilyFlags[0] & 0x00000080)
+ chance = 60;
+ // Chain heal - 0.3 of default
+ else if (spellInfo->SpellFamilyFlags[0] & 0x00000100)
+ chance = 30;
+
+ if (!roll_chance_i(chance))
+ return false;
+
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ // Get Water Shield
+ AuraEffect const* waterShield = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x00000000, 0x00000020, 0x00000000, caster->GetGUID());
+ if (!waterShield)
+ return;
+
+ uint32 spellId = waterShield->GetSpellInfo()->Effects[waterShield->GetEffIndex()].TriggerSpell;
+ caster->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_sha_imp_water_shield_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_sha_imp_water_shield_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_imp_water_shield_AuraScript();
+ }
+};
+
+// -30675 - Lightning Overload
+class spell_sha_lightning_overload : public SpellScriptLoader
+{
+ public:
+ spell_sha_lightning_overload() : SpellScriptLoader("spell_sha_lightning_overload") { }
+
+ class spell_sha_lightning_overload_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_lightning_overload_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD_R1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_SHAMAN_CHAIN_LIGHTNING_OVERLOAD_R1))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return;
+
+ uint32 spellId;
+
+ // Lightning Bolt
+ if (spellInfo->SpellFamilyFlags[0] & 0x00000001)
+ spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD_R1, spellInfo->GetRank());
+ // Chain Lightning
+ else
+ {
+ // Chain lightning has [LightOverload_Proc_Chance] / [Max_Number_of_Targets] chance to proc of each individual target hit.
+ // A maxed LO would have a 33% / 3 = 11% chance to proc of each target.
+ // LO chance was already "accounted" at the proc chance roll, now need to divide the chance by [Max_Number_of_Targets]
+ float chance = 100.0f / spellInfo->Effects[EFFECT_0].ChainTarget;
+ if (!roll_chance_f(chance))
+ return;
+
+ spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_CHAIN_LIGHTNING_OVERLOAD_R1, spellInfo->GetRank());
+ }
+
+ eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_lightning_overload_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_lightning_overload_AuraScript();
+ }
+};
+
// 23551 - Lightning Shield T2 Bonus
class spell_sha_item_lightning_shield : public SpellScriptLoader
{
@@ -693,7 +1196,7 @@ class spell_sha_item_lightning_shield : public SpellScriptLoader
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- GetTarget()->CastSpell(eventInfo.GetProcTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD, true, NULL, aurEff);
+ GetTarget()->CastSpell(eventInfo.GetProcTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD, true, nullptr, aurEff);
}
void Register() override
@@ -728,7 +1231,7 @@ class spell_sha_item_lightning_shield_trigger : public SpellScriptLoader
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
{
PreventDefaultAction();
- GetTarget()->CastSpell(GetTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE, true, NULL, aurEff);
+ GetTarget()->CastSpell(GetTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE, true, nullptr, aurEff);
}
void Register() override
@@ -760,23 +1263,21 @@ class spell_sha_item_mana_surge : public SpellScriptLoader
return true;
}
- bool CheckProc(ProcEventInfo& eventInfo)
- {
- return eventInfo.GetDamageInfo()->GetSpellInfo() != nullptr;
- }
-
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- int32 mana = eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetSchoolMask());
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return;
+
+ int32 mana = spellInfo->CalcPowerCost(GetTarget(), eventInfo.GetSchoolMask());
int32 damage = CalculatePct(mana, 35);
- GetTarget()->CastCustomSpell(SPELL_SHAMAN_ITEM_MANA_SURGE, SPELLVALUE_BASE_POINT0, damage, GetTarget(), true, NULL, aurEff);
+ GetTarget()->CastCustomSpell(SPELL_SHAMAN_ITEM_MANA_SURGE, SPELLVALUE_BASE_POINT0, damage, GetTarget(), true, nullptr, aurEff);
}
void Register() override
{
- DoCheckProc += AuraCheckProcFn(spell_sha_item_mana_surge_AuraScript::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_sha_item_mana_surge_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
@@ -787,6 +1288,71 @@ class spell_sha_item_mana_surge : public SpellScriptLoader
}
};
+// 40463 - Shaman Tier 6 Trinket
+class spell_sha_item_t6_trinket : public SpellScriptLoader
+{
+ public:
+ spell_sha_item_t6_trinket() : SpellScriptLoader("spell_sha_item_t6_trinket") { }
+
+ class spell_sha_item_t6_trinket_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_item_t6_trinket_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_ENERGY_SURGE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_SHAMAN_POWER_SURGE))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return;
+
+ uint32 spellId;
+ int32 chance;
+
+ // Lesser Healing Wave
+ if (spellInfo->SpellFamilyFlags[0] & 0x00000080)
+ {
+ spellId = SPELL_SHAMAN_ENERGY_SURGE;
+ chance = 10;
+ }
+ // Lightning Bolt
+ else if (spellInfo->SpellFamilyFlags[0] & 0x00000001)
+ {
+ spellId = SPELL_SHAMAN_ENERGY_SURGE;
+ chance = 15;
+ }
+ // Stormstrike
+ else if (spellInfo->SpellFamilyFlags[1] & 0x00000010)
+ {
+ spellId = SPELL_SHAMAN_POWER_SURGE;
+ chance = 50;
+ }
+ else
+ return;
+
+ if (roll_chance_i(chance))
+ eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_item_t6_trinket_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_item_t6_trinket_AuraScript();
+ }
+};
+
// 70811 - Item - Shaman T10 Elemental 2P Bonus
class spell_sha_item_t10_elemental_2p_bonus : public SpellScriptLoader
{
@@ -844,11 +1410,12 @@ class spell_sha_lava_lash : public SpellScriptLoader
{
int32 damage = GetEffectValue();
int32 hitDamage = GetHitDamage();
- if (caster->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND))
+ if (Item* offhand = caster->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND))
{
// Damage is increased by 25% if your off-hand weapon is enchanted with Flametongue.
- if (caster->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0x200000, 0, 0))
- AddPct(hitDamage, damage);
+ if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0x200000, 0, 0))
+ if (aurEff->GetBase()->GetCastItemGUID() == offhand->GetGUID())
+ AddPct(hitDamage, damage);
SetHitDamage(hitDamage);
}
}
@@ -912,6 +1479,49 @@ public:
}
};
+// 53817 - Maelstrom Weapon
+class spell_sha_maelstrom_weapon : public SpellScriptLoader
+{
+ public:
+ spell_sha_maelstrom_weapon() : SpellScriptLoader("spell_sha_maelstrom_weapon") { }
+
+ class spell_sha_maelstrom_weapon_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_maelstrom_weapon_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_MAELSTROM_POWER) ||
+ !sSpellMgr->GetSpellInfo(SPELL_SHAMAN_T10_ENHANCEMENT_4P_BONUS))
+ return false;
+ return true;
+ }
+
+ void HandleBonus(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (GetStackAmount() < GetSpellInfo()->StackAmount)
+ return;
+
+ Unit* caster = GetUnitOwner();
+ AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_SHAMAN_T10_ENHANCEMENT_4P_BONUS, EFFECT_0);
+ if (!aurEff || !roll_chance_i(aurEff->GetAmount()))
+ return;
+
+ caster->CastSpell((Unit*)nullptr, SPELL_SHAMAN_MAELSTROM_POWER, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_sha_maelstrom_weapon_AuraScript::HandleBonus, EFFECT_0, SPELL_AURA_ADD_PCT_MODIFIER, AURA_EFFECT_HANDLE_CHANGE_AMOUNT);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_maelstrom_weapon_AuraScript();
+ }
+};
+
// 52031, 52033, 52034, 52035, 52036, 58778, 58779, 58780 - Mana Spring Totem
class spell_sha_mana_spring_totem : public SpellScriptLoader
{
@@ -983,7 +1593,7 @@ class spell_sha_mana_tide_totem : public SpellScriptLoader
effValue += dummy->GetAmount();
// Regenerate 6% of Total Mana Every 3 secs
int32 effBasePoints0 = int32(CalculatePct(unitTarget->GetMaxPower(POWER_MANA), effValue));
- caster->CastCustomSpell(unitTarget, SPELL_SHAMAN_MANA_TIDE_TOTEM, &effBasePoints0, NULL, NULL, true, NULL, NULL, GetOriginalCaster()->GetGUID());
+ caster->CastCustomSpell(SPELL_SHAMAN_MANA_TIDE_TOTEM, SPELLVALUE_BASE_POINT0, effBasePoints0, unitTarget, true, nullptr, nullptr, GetOriginalCaster()->GetGUID());
}
}
}
@@ -1021,13 +1631,16 @@ public:
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
int32 healthpct = aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue(); // %s2 - the 30% threshold for health
if (Unit* target = eventInfo.GetActionTarget())
{
- if (target->HealthBelowPctDamaged(healthpct, eventInfo.GetDamageInfo()->GetDamage()))
+ if (target->HealthBelowPctDamaged(healthpct, damageInfo->GetDamage()))
{
-
uint32 bp = CalculatePct(target->GetMaxHealth(), aurEff->GetAmount());
target->CastCustomSpell(SPELL_SHAMAN_NATURE_GUARDIAN, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, aurEff);
@@ -1096,6 +1709,170 @@ class spell_sha_sentry_totem : public SpellScriptLoader
}
};
+// 30823 - Shamanistic Rage
+class spell_sha_shamanistic_rage : public SpellScriptLoader
+{
+ public:
+ spell_sha_shamanistic_rage() : SpellScriptLoader("spell_sha_shamanistic_rage") { }
+
+ class spell_sha_shamanistic_rage_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_shamanistic_rage_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_SHAMANISTIC_RAGE_PROC))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+
+ Unit* target = GetTarget();
+ int32 amount = CalculatePct(static_cast<int32>(target->GetTotalAttackPowerValue(BASE_ATTACK)), aurEff->GetAmount());
+ target->CastCustomSpell(SPELL_SHAMAN_SHAMANISTIC_RAGE_PROC, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_shamanistic_rage_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_shamanistic_rage_AuraScript();
+ }
+};
+
+// 58877 - Spirit Hunt
+class spell_sha_spirit_hunt : public SpellScriptLoader
+{
+ public:
+ spell_sha_spirit_hunt() : SpellScriptLoader("spell_sha_spirit_hunt") { }
+
+ class spell_sha_spirit_hunt_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_spirit_hunt_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_SPIRIT_HUNT_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = caster->GetOwner();
+ if (!target)
+ return;
+
+ int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
+ caster->CastCustomSpell(SPELL_SHAMAN_SPIRIT_HUNT_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true, nullptr, aurEff);
+ caster->CastCustomSpell(SPELL_SHAMAN_SPIRIT_HUNT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_spirit_hunt_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_spirit_hunt_AuraScript();
+ }
+};
+
+// -51525 - Static Shock
+class spell_sha_static_shock : public SpellScriptLoader
+{
+ public:
+ spell_sha_static_shock() : SpellScriptLoader("spell_sha_static_shock") { }
+
+ class spell_sha_static_shock_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_static_shock_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_LIGHTNING_SHIELD_DAMAGE_R1))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = eventInfo.GetActor();
+
+ // Get Lightning Shield
+ AuraEffect const* lightningShield = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x00000400, 0x00000000, 0x00000000, caster->GetGUID());
+ if (!lightningShield)
+ return;
+
+ uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_LIGHTNING_SHIELD_DAMAGE_R1, lightningShield->GetSpellInfo()->GetRank());
+ eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff);
+ lightningShield->GetBase()->DropCharge();
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_static_shock_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_static_shock_AuraScript();
+ }
+};
+
+// 55198 - Tidal Force
+class spell_sha_tidal_force_dummy : public SpellScriptLoader
+{
+ public:
+ spell_sha_tidal_force_dummy() : SpellScriptLoader("spell_sha_tidal_force_dummy") { }
+
+ class spell_sha_tidal_force_dummy_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_tidal_force_dummy_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_TIDAL_FORCE_CRIT))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ eventInfo.GetActor()->RemoveAuraFromStack(SPELL_SHAMAN_TIDAL_FORCE_CRIT);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_tidal_force_dummy_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_tidal_force_dummy_AuraScript();
+ }
+};
+
// -51490 - Thunderstorm
class spell_sha_thunderstorm : public SpellScriptLoader
{
@@ -1142,14 +1919,14 @@ public:
return true;
}
- void HandleDummy(AuraEffect const* /*aurEff*/)
+ void HandleDummy(AuraEffect const* aurEff)
{
Unit* target = GetTarget();
for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
if (!target->m_SummonSlot[i])
return;
- target->CastSpell(target, SPELL_SHAMAN_TOTEMIC_MASTERY, true);
+ target->CastSpell(target, SPELL_SHAMAN_TOTEMIC_MASTERY, true, nullptr, aurEff);
PreventDefaultAction();
}
@@ -1165,30 +1942,406 @@ public:
}
};
+// 28823 - Totemic Power
+class spell_sha_t3_6p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_sha_t3_6p_bonus() : SpellScriptLoader("spell_sha_t3_6p_bonus") { }
+
+ class spell_sha_t3_6p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_t3_6p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_TOTEMIC_POWER_ARMOR) ||
+ !sSpellMgr->GetSpellInfo(SPELL_SHAMAN_TOTEMIC_POWER_ATTACK_POWER) ||
+ !sSpellMgr->GetSpellInfo(SPELL_SHAMAN_TOTEMIC_POWER_SPELL_POWER) ||
+ !sSpellMgr->GetSpellInfo(SPELL_SHAMAN_TOTEMIC_POWER_MP5))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ uint32 spellId;
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+
+ switch (target->getClass())
+ {
+ case CLASS_PALADIN:
+ case CLASS_PRIEST:
+ case CLASS_SHAMAN:
+ case CLASS_DRUID:
+ spellId = SPELL_SHAMAN_TOTEMIC_POWER_MP5;
+ break;
+ case CLASS_MAGE:
+ case CLASS_WARLOCK:
+ spellId = SPELL_SHAMAN_TOTEMIC_POWER_SPELL_POWER;
+ break;
+ case CLASS_HUNTER:
+ case CLASS_ROGUE:
+ spellId = SPELL_SHAMAN_TOTEMIC_POWER_ATTACK_POWER;
+ break;
+ case CLASS_WARRIOR:
+ spellId = SPELL_SHAMAN_TOTEMIC_POWER_ARMOR;
+ break;
+ default:
+ return;
+ }
+
+ caster->CastSpell(target, spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_t3_6p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_t3_6p_bonus_AuraScript();
+ }
+};
+
+// 64928 - Item - Shaman T8 Elemental 4P Bonus
+class spell_sha_t8_elemental_4p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_sha_t8_elemental_4p_bonus() : SpellScriptLoader("spell_sha_t8_elemental_4p_bonus") { }
+
+ class spell_sha_t8_elemental_4p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_t8_elemental_4p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_ELECTRIFIED))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_ELECTRIFIED);
+ int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
+ amount /= spellInfo->GetMaxTicks();
+
+ // Add remaining ticks to damage done
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+ amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_SHAMAN_ELECTRIFIED, SPELL_AURA_PERIODIC_DAMAGE);
+
+ caster->CastCustomSpell(SPELL_SHAMAN_ELECTRIFIED, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_t8_elemental_4p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_t8_elemental_4p_bonus_AuraScript();
+ }
+};
+
+// 67228 - Item - Shaman T9 Elemental 4P Bonus (Lava Burst)
+class spell_sha_t9_elemental_4p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_sha_t9_elemental_4p_bonus() : SpellScriptLoader("spell_sha_t9_elemental_4p_bonus") { }
+
+ class spell_sha_t9_elemental_4p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_t9_elemental_4p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE);
+ int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
+ amount /= spellInfo->GetMaxTicks();
+
+ // Add remaining ticks to damage done
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+ amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE, SPELL_AURA_PERIODIC_DAMAGE);
+
+ caster->CastCustomSpell(SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_t9_elemental_4p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_t9_elemental_4p_bonus_AuraScript();
+ }
+};
+
+// 70817 - Item - Shaman T10 Elemental 4P Bonus
+class spell_sha_t10_elemental_4p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_sha_t10_elemental_4p_bonus() : SpellScriptLoader("spell_sha_t10_elemental_4p_bonus") { }
+
+ class spell_sha_t10_elemental_4p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_t10_elemental_4p_bonus_AuraScript);
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+
+ // try to find spell Flame Shock on the target
+ AuraEffect* flameShock = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0x00000000, 0x00000000, caster->GetGUID());
+ if (!flameShock)
+ return;
+
+ Aura* flameShockAura = flameShock->GetBase();
+
+ int32 maxDuration = flameShockAura->GetMaxDuration();
+ int32 newDuration = flameShockAura->GetDuration() + aurEff->GetAmount() * IN_MILLISECONDS;
+
+ flameShockAura->SetDuration(newDuration);
+ // is it blizzlike to change max duration for FS?
+ if (newDuration > maxDuration)
+ flameShockAura->SetMaxDuration(newDuration);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_t10_elemental_4p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_t10_elemental_4p_bonus_AuraScript();
+ }
+};
+
+// 70808 - Item - Shaman T10 Restoration 4P Bonus
+class spell_sha_t10_restoration_4p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_sha_t10_restoration_4p_bonus() : SpellScriptLoader("spell_sha_t10_restoration_4p_bonus") { }
+
+ class spell_sha_t10_restoration_4p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_t10_restoration_4p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_CHAINED_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ HealInfo* healInfo = eventInfo.GetHealInfo();
+ if (!healInfo || !healInfo->GetHeal())
+ return;
+
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_CHAINED_HEAL);
+ int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount());
+ amount /= spellInfo->GetMaxTicks();
+
+ // Add remaining ticks to healing done
+ Unit* caster = eventInfo.GetActor();
+ Unit* target = eventInfo.GetProcTarget();
+ amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_SHAMAN_CHAINED_HEAL, SPELL_AURA_PERIODIC_HEAL);
+
+ caster->CastCustomSpell(SPELL_SHAMAN_CHAINED_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_sha_t10_restoration_4p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_t10_restoration_4p_bonus_AuraScript();
+ }
+};
+
+// 33757 - Windfury Weapon (Passive)
+class spell_sha_windfury_weapon : public SpellScriptLoader
+{
+ public:
+ spell_sha_windfury_weapon() : SpellScriptLoader("spell_sha_windfury_weapon") { }
+
+ class spell_sha_windfury_weapon_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_windfury_weapon_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_WINDFURY_WEAPON_R1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_SHAMAN_WINDFURY_ATTACK_MH) ||
+ !sSpellMgr->GetSpellInfo(SPELL_SHAMAN_WINDFURY_ATTACK_OH))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ Player* player = eventInfo.GetActor()->ToPlayer();
+ if (!player)
+ return false;
+
+ Item* item = player->GetItemByGuid(GetAura()->GetCastItemGUID());
+ if (!item || !item->IsEquipped())
+ return false;
+
+ WeaponAttackType attType = static_cast<WeaponAttackType>(player->GetAttackBySlot(item->GetSlot()));
+ if (attType != BASE_ATTACK && attType != OFF_ATTACK)
+ return false;
+
+ if (((attType == BASE_ATTACK) && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_MAINHAND_ATTACK)) ||
+ ((attType == OFF_ATTACK) && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_OFFHAND_ATTACK)))
+ return false;
+
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Player* player = eventInfo.GetActor()->ToPlayer();
+
+ uint32 spellId = 0;
+ WeaponAttackType attType = BASE_ATTACK;
+ if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_MAINHAND_ATTACK)
+ spellId = SPELL_SHAMAN_WINDFURY_ATTACK_MH;
+
+ if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_OFFHAND_ATTACK)
+ {
+ spellId = SPELL_SHAMAN_WINDFURY_ATTACK_OH;
+ attType = OFF_ATTACK;
+ }
+
+ Item* item = ASSERT_NOTNULL(player->GetWeaponForAttack(attType));
+
+ int32 enchantId = static_cast<int32>(item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT));
+ int32 extraAttackPower = 0;
+ SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_WINDFURY_WEAPON_R1);
+ while (spellInfo)
+ {
+ if (spellInfo->Effects[EFFECT_0].MiscValue == enchantId)
+ {
+ extraAttackPower = spellInfo->Effects[EFFECT_1].CalcValue(player);
+ break;
+ }
+ spellInfo = spellInfo->GetNextRankSpell();
+ }
+
+ if (!extraAttackPower)
+ return;
+
+ // Value gained from additional AP
+ int32 amount = static_cast<int32>(extraAttackPower / 14.f * player->GetAttackTime(attType) / 1000.f);
+
+ // Attack twice
+ for (uint8 i = 0; i < 2; ++i)
+ player->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, item, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_sha_windfury_weapon_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_sha_windfury_weapon_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sha_windfury_weapon_AuraScript();
+ }
+};
+
void AddSC_shaman_spell_scripts()
{
+ new spell_sha_ancestral_awakening();
new spell_sha_ancestral_awakening_proc();
new spell_sha_astral_shift();
+ new spell_sha_astral_shift_aura();
new spell_sha_bloodlust();
new spell_sha_chain_heal();
new spell_sha_cleansing_totem_pulse();
new spell_sha_earth_shield();
new spell_sha_earthbind_totem();
new spell_sha_earthen_power();
+ new spell_sha_earthliving_weapon();
new spell_sha_fire_nova();
new spell_sha_flame_shock();
+ new spell_sha_flametongue_weapon();
+ new spell_sha_frozen_power();
+ new spell_sha_glyph_of_earth_shield();
+ new spell_sha_glyph_of_healing_wave();
+ new spell_sha_glyph_of_totem_of_wrath();
new spell_sha_healing_stream_totem();
new spell_sha_heroism();
+ new spell_sha_imp_water_shield();
+ new spell_sha_lightning_overload();
new spell_sha_item_lightning_shield();
new spell_sha_item_lightning_shield_trigger();
new spell_sha_item_mana_surge();
+ new spell_sha_item_t6_trinket();
new spell_sha_item_t10_elemental_2p_bonus();
new spell_sha_lava_lash();
new spell_sha_lightning_shield();
+ new spell_sha_maelstrom_weapon();
new spell_sha_mana_spring_totem();
new spell_sha_mana_tide_totem();
new spell_sha_nature_guardian();
new spell_sha_sentry_totem();
+ new spell_sha_shamanistic_rage();
+ new spell_sha_spirit_hunt();
+ new spell_sha_static_shock();
+ new spell_sha_tidal_force_dummy();
new spell_sha_thunderstorm();
new spell_sha_totemic_mastery();
+ new spell_sha_t3_6p_bonus();
+ new spell_sha_t8_elemental_4p_bonus();
+ new spell_sha_t9_elemental_4p_bonus();
+ new spell_sha_t10_elemental_4p_bonus();
+ new spell_sha_t10_restoration_4p_bonus();
+ new spell_sha_windfury_weapon();
}
diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp
index 5e0074bf9f7..1a8252ad7ec 100644
--- a/src/server/scripts/Spells/spell_warlock.cpp
+++ b/src/server/scripts/Spells/spell_warlock.cpp
@@ -37,6 +37,7 @@ enum WarlockSpells
SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELGUARD = 54508,
SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELHUNTER = 54509,
SPELL_WARLOCK_DEMONIC_EMPOWERMENT_IMP = 54444,
+ SPELL_WARLOCK_DEMONIC_PACT_PROC = 48090,
SPELL_WARLOCK_FEL_SYNERGY_HEAL = 54181,
SPELL_WARLOCK_GLYPH_OF_SHADOWFLAME = 63311,
SPELL_WARLOCK_GLYPH_OF_SIPHON_LIFE = 63106,
@@ -58,13 +59,30 @@ enum WarlockSpells
SPELL_WARLOCK_NETHER_PROTECTION_NATURE = 54375,
SPELL_WARLOCK_SOULSHATTER = 32835,
SPELL_WARLOCK_SIPHON_LIFE_HEAL = 63106,
- SPELL_WARLOCK_UNSTABLE_AFFLICTION_DISPEL = 31117
+ SPELL_WARLOCK_UNSTABLE_AFFLICTION_DISPEL = 31117,
+ SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED = 63321,
+ SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1 = 27285,
+ SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC = 32865,
+ SPELL_WARLOCK_SHADOW_TRANCE = 17941,
+ SPELL_WARLOCK_SOUL_LEECH_HEAL = 30294,
+ SPELL_WARLOCK_IMP_SOUL_LEECH_R1 = 54117,
+ SPELL_WARLOCK_SOUL_LEECH_PET_MANA_1 = 54607,
+ SPELL_WARLOCK_SOUL_LEECH_PET_MANA_2 = 59118,
+ SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_1 = 54300,
+ SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_2 = 59117,
+ SPELL_REPLENISHMENT = 57669,
+ SPELL_WARLOCK_SHADOWFLAME = 37378,
+ SPELL_WARLOCK_FLAMESHADOW = 37379,
+ SPELL_WARLOCK_GLYPH_OF_SUCCUBUS = 56250,
+ SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_R1 = 18213,
+ SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC = 18371
};
enum WarlockSpellIcons
{
WARLOCK_ICON_ID_IMPROVED_LIFE_TAP = 208,
- WARLOCK_ICON_ID_MANA_FEED = 1982
+ WARLOCK_ICON_ID_MANA_FEED = 1982,
+ WARLOCK_ICON_ID_DEMONIC_PACT = 3220
};
// -710 - Banish
@@ -250,6 +268,36 @@ class spell_warl_curse_of_doom : public SpellScriptLoader
}
};
+class spell_warl_decimation : public SpellScriptLoader
+{
+ public:
+ spell_warl_decimation() : SpellScriptLoader("spell_warl_decimation") { }
+
+ class spell_warl_decimation_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warl_decimation_AuraScript);
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
+ if (eventInfo.GetActionTarget()->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellInfo, eventInfo.GetActor()))
+ return true;
+
+ return false;
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_warl_decimation_AuraScript::CheckProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warl_decimation_AuraScript();
+ }
+};
+
// 48018 - Demonic Circle: Summon
class spell_warl_demonic_circle_summon : public SpellScriptLoader
{
@@ -402,6 +450,50 @@ class spell_warl_demonic_empowerment : public SpellScriptLoader
}
};
+// -1120 - Drain Soul
+class spell_warl_drain_soul : public SpellScriptLoader
+{
+ public:
+ spell_warl_drain_soul() : SpellScriptLoader("spell_warl_drain_soul") { }
+
+ class spell_warl_drain_soul_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warl_drain_soul_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_R1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = eventInfo.GetActor();
+ // Improved Drain Soul
+ Aura const* impDrainSoul = caster->GetAuraOfRankedSpell(SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_R1, caster->GetGUID());
+ if (!impDrainSoul)
+ return;
+
+ int32 amount = CalculatePct(caster->GetMaxPower(POWER_MANA), impDrainSoul->GetSpellInfo()->Effects[EFFECT_2].CalcValue());
+ caster->CastCustomSpell(SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_warl_drain_soul_AuraScript::HandleProc, EFFECT_2, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warl_drain_soul_AuraScript();
+ }
+};
+
// 47422 - Everlasting Affliction
class spell_warl_everlasting_affliction : public SpellScriptLoader
{
@@ -416,6 +508,7 @@ class spell_warl_everlasting_affliction : public SpellScriptLoader
{
Unit* caster = GetCaster();
if (Unit* target = GetHitUnit())
+ {
// Refresh corruption on target
if (AuraEffect* aur = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x2, 0, 0, caster->GetGUID()))
{
@@ -423,6 +516,7 @@ class spell_warl_everlasting_affliction : public SpellScriptLoader
aur->CalculatePeriodic(caster, false, false);
aur->GetBase()->RefreshDuration(true);
}
+ }
}
void Register() override
@@ -456,15 +550,19 @@ class spell_warl_fel_synergy : public SpellScriptLoader
bool CheckProc(ProcEventInfo& eventInfo)
{
- return GetTarget()->GetGuardianPet() && eventInfo.GetDamageInfo()->GetDamage();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return false;
+
+ return GetTarget()->GetGuardianPet() != nullptr;
}
void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- int32 heal = CalculatePct(int32(eventInfo.GetDamageInfo()->GetDamage()), aurEff->GetAmount());
- GetTarget()->CastCustomSpell(SPELL_WARLOCK_FEL_SYNERGY_HEAL, SPELLVALUE_BASE_POINT0, heal, (Unit*)NULL, true, NULL, aurEff); // TARGET_UNIT_PET
+ int32 heal = CalculatePct(static_cast<int32>(eventInfo.GetDamageInfo()->GetDamage()), aurEff->GetAmount());
+ GetTarget()->CastCustomSpell(SPELL_WARLOCK_FEL_SYNERGY_HEAL, SPELLVALUE_BASE_POINT0, heal, (Unit*)nullptr, true, nullptr, aurEff); // TARGET_UNIT_PET
}
void Register() override
@@ -480,6 +578,79 @@ class spell_warl_fel_synergy : public SpellScriptLoader
}
};
+// -18094 - Nightfall
+// 56218 - Glyph of Corruption
+class spell_warl_glyph_of_corruption_nightfall : public SpellScriptLoader
+{
+ public:
+ spell_warl_glyph_of_corruption_nightfall() : SpellScriptLoader("spell_warl_glyph_of_corruption_nightfall") { }
+
+ class spell_warl_glyph_of_corruption_nightfall_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warl_glyph_of_corruption_nightfall_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_SHADOW_TRANCE))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ caster->CastSpell(caster, SPELL_WARLOCK_SHADOW_TRANCE, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_warl_glyph_of_corruption_nightfall_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warl_glyph_of_corruption_nightfall_AuraScript();
+ }
+};
+
+// 63320 - Glyph of Life Tap
+class spell_warl_glyph_of_life_tap : public SpellScriptLoader
+{
+public:
+ spell_warl_glyph_of_life_tap() : SpellScriptLoader("spell_warl_glyph_of_life_tap") { }
+
+ class spell_warl_glyph_of_life_tap_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warl_glyph_of_life_tap_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ caster->CastSpell(caster, SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_warl_glyph_of_life_tap_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warl_glyph_of_life_tap_AuraScript();
+ }
+};
+
// 63310 - Glyph of Shadowflame
class spell_warl_glyph_of_shadowflame : public SpellScriptLoader
{
@@ -714,9 +885,9 @@ public:
bool CheckProc(ProcEventInfo& eventInfo)
{
- if (eventInfo.GetDamageInfo())
+ if (DamageInfo* damageInfo = eventInfo.GetDamageInfo())
{
- switch (GetFirstSchoolInMask(eventInfo.GetDamageInfo()->GetSchoolMask()))
+ switch (GetFirstSchoolInMask(damageInfo->GetSchoolMask()))
{
case SPELL_SCHOOL_HOLY:
case SPELL_SCHOOL_FIRE:
@@ -779,6 +950,55 @@ public:
}
};
+// 54909, 53646 - Demonic Pact
+class spell_warl_demonic_pact : public SpellScriptLoader
+{
+ public:
+ spell_warl_demonic_pact() : SpellScriptLoader("spell_warl_demonic_pact") { }
+
+ class spell_warl_demonic_pact_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warl_demonic_pact_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_DEMONIC_PACT_PROC))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ return eventInfo.GetActor() && eventInfo.GetActor()->IsPet();
+ }
+
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ if (Unit* owner = eventInfo.GetActor()->GetOwner())
+ {
+ if (AuraEffect* aurEff = owner->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, WARLOCK_ICON_ID_DEMONIC_PACT, EFFECT_0))
+ {
+ int32 bp0 = static_cast<int32>((aurEff->GetAmount() * owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_MAGIC) + 100.0f) / 100.0f);
+ owner->CastCustomSpell(SPELL_WARLOCK_DEMONIC_PACT_PROC, SPELLVALUE_BASE_POINT0, bp0, (Unit*)nullptr, true, nullptr, aurEff);
+ }
+ }
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_warl_demonic_pact_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_warl_demonic_pact_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warl_demonic_pact_AuraScript();
+ }
+};
+
// 18541 - Ritual of Doom Effect
class spell_warl_ritual_of_doom_effect : public SpellScriptLoader
{
@@ -807,6 +1027,47 @@ class spell_warl_ritual_of_doom_effect : public SpellScriptLoader
}
};
+// 6358 - Seduction
+class spell_warl_seduction : public SpellScriptLoader
+{
+ public:
+ spell_warl_seduction() : SpellScriptLoader("spell_warl_seduction") { }
+
+ class spell_warl_seduction_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_warl_seduction_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_GLYPH_OF_SUCCUBUS))
+ return false;
+ return true;
+ }
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ Unit* owner = GetCaster()->GetOwner();
+ if (!owner || !owner->HasAura(SPELL_WARLOCK_GLYPH_OF_SUCCUBUS))
+ return;
+
+ Unit* target = GetHitUnit();
+ target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, ObjectGuid::Empty, target->GetAura(32409)); // SW:D shall not be removed.
+ target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
+ target->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
+ }
+
+ void Register() override
+ {
+ OnEffectLaunchTarget += SpellEffectFn(spell_warl_seduction_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_warl_seduction_SpellScript();
+ }
+};
+
// -27285 - Seed of Corruption
class spell_warl_seed_of_corruption : public SpellScriptLoader
{
@@ -835,6 +1096,118 @@ class spell_warl_seed_of_corruption : public SpellScriptLoader
}
};
+// -27243 - Seed of Corruption
+class spell_warl_seed_of_corruption_dummy : public SpellScriptLoader
+{
+ public:
+ spell_warl_seed_of_corruption_dummy() : SpellScriptLoader("spell_warl_seed_of_corruption_dummy") { }
+
+ class spell_warl_seed_of_corruption_dummy_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warl_seed_of_corruption_dummy_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 amount = aurEff->GetAmount() - damageInfo->GetDamage();
+ if (amount > 0)
+ {
+ const_cast<AuraEffect*>(aurEff)->SetAmount(amount);
+ if (!GetTarget()->HealthBelowPctDamaged(1, damageInfo->GetDamage()))
+ return;
+ }
+
+ Remove();
+
+ Unit* caster = GetCaster();
+ if (!caster)
+ return;
+
+ uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1, GetSpellInfo()->GetRank());
+ caster->CastSpell(eventInfo.GetActionTarget(), spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_warl_seed_of_corruption_dummy_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warl_seed_of_corruption_dummy_AuraScript();
+ }
+};
+
+// 32863 - Seed of Corruption
+// 36123 - Seed of Corruption
+// 38252 - Seed of Corruption
+// 39367 - Seed of Corruption
+// 44141 - Seed of Corruption
+// 70388 - Seed of Corruption
+// Monster spells, triggered only on amount drop (not on death)
+class spell_warl_seed_of_corruption_generic : public SpellScriptLoader
+{
+ public:
+ spell_warl_seed_of_corruption_generic() : SpellScriptLoader("spell_warl_seed_of_corruption_generic") { }
+
+ class spell_warl_seed_of_corruption_generic_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warl_seed_of_corruption_generic_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ int32 amount = aurEff->GetAmount() - damageInfo->GetDamage();
+ if (amount > 0)
+ {
+ const_cast<AuraEffect*>(aurEff)->SetAmount(amount);
+ return;
+ }
+
+ Remove();
+
+ Unit* caster = GetCaster();
+ if (!caster)
+ return;
+
+ caster->CastSpell(eventInfo.GetActionTarget(), SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_warl_seed_of_corruption_generic_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warl_seed_of_corruption_generic_AuraScript();
+ }
+};
+
// -7235 - Shadow Ward
class spell_warl_shadow_ward : public SpellScriptLoader
{
@@ -893,19 +1266,23 @@ class spell_warl_siphon_life : public SpellScriptLoader
bool CheckProc(ProcEventInfo& eventInfo)
{
- return eventInfo.GetDamageInfo()->GetDamage() && GetTarget()->IsAlive();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return false;
+
+ return GetTarget()->IsAlive();
}
void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- int32 amount = int32(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), aurEff->GetAmount()));
+ int32 amount = CalculatePct(static_cast<int32>(eventInfo.GetDamageInfo()->GetDamage()), aurEff->GetAmount());
// Glyph of Siphon Life
if (AuraEffect const* glyph = GetTarget()->GetAuraEffect(SPELL_WARLOCK_GLYPH_OF_SIPHON_LIFE, EFFECT_0))
AddPct(amount, glyph->GetAmount());
- GetTarget()->CastCustomSpell(SPELL_WARLOCK_SIPHON_LIFE_HEAL, SPELLVALUE_BASE_POINT0, amount, GetTarget(), true, NULL, aurEff);
+ GetTarget()->CastCustomSpell(SPELL_WARLOCK_SIPHON_LIFE_HEAL, SPELLVALUE_BASE_POINT0, amount, GetTarget(), true, nullptr, aurEff);
}
void Register() override
@@ -921,6 +1298,71 @@ class spell_warl_siphon_life : public SpellScriptLoader
}
};
+// -30293 - Soul Leech
+class spell_warl_soul_leech : public SpellScriptLoader
+{
+ public:
+ spell_warl_soul_leech() : SpellScriptLoader("spell_warl_soul_leech") { }
+
+ class spell_warl_soul_leech_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warl_soul_leech_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_SOUL_LEECH_HEAL) ||
+ !sSpellMgr->GetSpellInfo(SPELL_WARLOCK_IMP_SOUL_LEECH_R1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_WARLOCK_SOUL_LEECH_PET_MANA_1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_WARLOCK_SOUL_LEECH_PET_MANA_2) ||
+ !sSpellMgr->GetSpellInfo(SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_2) ||
+ !sSpellMgr->GetSpellInfo(SPELL_REPLENISHMENT))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ static uint32 const casterMana[2] = { SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_1, SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_2 };
+ static uint32 const petMana[2] = { SPELL_WARLOCK_SOUL_LEECH_PET_MANA_1, SPELL_WARLOCK_SOUL_LEECH_PET_MANA_2 };
+
+ PreventDefaultAction();
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo || !damageInfo->GetDamage())
+ return;
+
+ Unit* caster = eventInfo.GetActor();
+ int32 bp = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
+ caster->CastCustomSpell(SPELL_WARLOCK_SOUL_LEECH_HEAL, SPELLVALUE_BASE_POINT0, bp, caster, true);
+
+ // Improved Soul Leech code below
+ AuraEffect const* impSoulLeech = GetTarget()->GetAuraEffectOfRankedSpell(SPELL_WARLOCK_IMP_SOUL_LEECH_R1, EFFECT_1, aurEff->GetCasterGUID());
+ if (!impSoulLeech)
+ return;
+
+ uint8 impSoulLeechRank = impSoulLeech->GetSpellInfo()->GetRank();
+ uint32 selfSpellId = casterMana[impSoulLeechRank - 1];
+ uint32 petSpellId = petMana[impSoulLeechRank - 1];
+
+ caster->CastSpell((Unit*)nullptr, selfSpellId, true, nullptr, aurEff);
+ caster->CastSpell((Unit*)nullptr, petSpellId, true, nullptr, aurEff);
+
+ if (roll_chance_i(impSoulLeech->GetAmount()))
+ caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_warl_soul_leech_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warl_soul_leech_AuraScript();
+ }
+};
+
// 29858 - Soulshatter
class spell_warl_soulshatter : public SpellScriptLoader
{
@@ -960,6 +1402,45 @@ class spell_warl_soulshatter : public SpellScriptLoader
}
};
+// 37377 - Shadowflame
+// 39437 - Shadowflame Hellfire and RoF
+template <uint32 TriggerSpellId>
+class spell_warl_t4_2p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_warl_t4_2p_bonus(char const* ScriptName) : SpellScriptLoader(ScriptName) { }
+
+ template <uint32 Trigger>
+ class spell_warl_t4_2p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warl_t4_2p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(Trigger))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ caster->CastSpell(caster, Trigger, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_warl_t4_2p_bonus_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warl_t4_2p_bonus_AuraScript<TriggerSpellId>();
+ }
+};
+
// -30108 - Unstable Affliction
class spell_warl_unstable_affliction : public SpellScriptLoader
{
@@ -1005,20 +1486,31 @@ void AddSC_warlock_spell_scripts()
new spell_warl_banish();
new spell_warl_create_healthstone();
new spell_warl_curse_of_doom();
+ new spell_warl_decimation();
new spell_warl_demonic_circle_summon();
new spell_warl_demonic_circle_teleport();
new spell_warl_demonic_empowerment();
+ new spell_warl_demonic_pact();
+ new spell_warl_drain_soul();
new spell_warl_everlasting_affliction();
new spell_warl_fel_synergy();
+ new spell_warl_glyph_of_life_tap();
new spell_warl_glyph_of_shadowflame();
new spell_warl_haunt();
new spell_warl_health_funnel();
+ new spell_warl_glyph_of_corruption_nightfall();
new spell_warl_life_tap();
new spell_warl_nether_protection();
new spell_warl_ritual_of_doom_effect();
+ new spell_warl_seduction();
new spell_warl_seed_of_corruption();
+ new spell_warl_seed_of_corruption_dummy();
+ new spell_warl_seed_of_corruption_generic();
new spell_warl_shadow_ward();
new spell_warl_siphon_life();
+ new spell_warl_soul_leech();
new spell_warl_soulshatter();
+ new spell_warl_t4_2p_bonus<SPELL_WARLOCK_FLAMESHADOW>("spell_warl_t4_2p_bonus_shadow");
+ new spell_warl_t4_2p_bonus<SPELL_WARLOCK_SHADOWFLAME>("spell_warl_t4_2p_bonus_fire");
new spell_warl_unstable_affliction();
}
diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp
index ea9ccc956e5..81fb4ec2457 100644
--- a/src/server/scripts/Spells/spell_warrior.cpp
+++ b/src/server/scripts/Spells/spell_warrior.cpp
@@ -32,6 +32,7 @@ enum WarriorSpells
SPELL_WARRIOR_BLADESTORM_PERIODIC_WHIRLWIND = 50622,
SPELL_WARRIOR_BLOODTHIRST = 23885,
SPELL_WARRIOR_BLOODTHIRST_DAMAGE = 23881,
+ SPELL_WARRIOR_BLOODSURGE_R1 = 29723,
SPELL_WARRIOR_CHARGE = 34846,
SPELL_WARRIOR_DAMAGE_SHIELD_DAMAGE = 59653,
SPELL_WARRIOR_DEEP_WOUNDS_RANK_1 = 12162,
@@ -39,6 +40,8 @@ enum WarriorSpells
SPELL_WARRIOR_DEEP_WOUNDS_RANK_3 = 12868,
SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC = 12721,
SPELL_WARRIOR_EXECUTE = 20647,
+ SPELL_WARRIOR_EXECUTE_GCD_REDUCED = 71069,
+ SPELL_WARRIOR_EXTRA_CHARGE = 70849,
SPELL_WARRIOR_GLYPH_OF_EXECUTION = 58367,
SPELL_WARRIOR_GLYPH_OF_VIGILANCE = 63326,
SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_BUFF = 65156,
@@ -46,6 +49,8 @@ enum WarriorSpells
SPELL_WARRIOR_LAST_STAND_TRIGGERED = 12976,
SPELL_WARRIOR_RETALIATION_DAMAGE = 22858,
SPELL_WARRIOR_SLAM = 50783,
+ SPELL_WARRIOR_SLAM_GCD_REDUCED = 71072,
+ SPELL_WARRIOR_SUDDEN_DEATH_R1 = 46913,
SPELL_WARRIOR_SUNDER_ARMOR = 58567,
SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_1 = 12723,
SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_2 = 26654,
@@ -55,7 +60,13 @@ enum WarriorSpells
SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_1 = 64849,
SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_2 = 64850,
SPELL_WARRIOR_VIGILANCE_PROC = 50725,
- SPELL_WARRIOR_VIGILANCE_REDIRECT_THREAT = 59665
+ SPELL_WARRIOR_VIGILANCE_REDIRECT_THREAT = 59665,
+ SPELL_WARRIOR_IMPROVED_SPELL_REFLECTION_TRIGGER = 59725,
+ SPELL_WARRIOR_SECOND_WIND_TRIGGER_1 = 29841,
+ SPELL_WARRIOR_SECOND_WIND_TRIGGER_2 = 29842,
+ SPELL_WARRIOR_GLYPH_OF_BLOCKING = 58374,
+ SPELL_WARRIOR_STOICISM = 70845,
+ SPELL_WARRIOR_T10_MELEE_4P_BONUS = 70847
};
enum WarriorSpellIcons
@@ -69,6 +80,7 @@ enum MiscSpells
SPELL_PALADIN_GREATER_BLESSING_OF_SANCTUARY = 25899,
SPELL_PRIEST_RENEWED_HOPE = 63944,
SPELL_GEN_DAMAGE_REDUCTION_AURA = 68066,
+ SPELL_CATEGORY_SHIELD_SLAM = 1209
};
// 23881 - Bloodthirst
@@ -258,7 +270,10 @@ class spell_warr_deep_wounds : public SpellScriptLoader
bool Validate(SpellInfo const* /*spellInfo*/) override
{
- if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_1) || !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_2) || !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_3))
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_2) ||
+ !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_3) ||
+ !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC))
return false;
return true;
}
@@ -272,15 +287,11 @@ class spell_warr_deep_wounds : public SpellScriptLoader
ApplyPct(damage, 16 * GetSpellInfo()->GetRank());
SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC);
- uint32 ticks = uint32(spellInfo->GetDuration()) / spellInfo->Effects[EFFECT_0].Amplitude;
+ damage /= spellInfo->GetMaxTicks();
// Add remaining ticks to damage done
- if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC, EFFECT_0, caster->GetGUID()))
- damage += (aurEff->GetAmount() + aurEff->GetBonusAmount()) * aurEff->GetDonePct() * int32(ticks - aurEff->GetTickNumber());
-
- damage /= int32(ticks);
-
- caster->CastCustomSpell(target, SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC, &damage, NULL, NULL, true);
+ damage += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC, SPELL_AURA_PERIODIC_DAMAGE);
+ caster->CastCustomSpell(SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC, SPELLVALUE_BASE_POINT0, damage, target, true);
}
}
@@ -296,6 +307,60 @@ class spell_warr_deep_wounds : public SpellScriptLoader
}
};
+// -12834 - Deep Wounds Aura
+class spell_warr_deep_wounds_aura : public SpellScriptLoader
+{
+ public:
+ spell_warr_deep_wounds_aura() : SpellScriptLoader("spell_warr_deep_wounds_aura") { }
+
+ class spell_warr_deep_wounds_aura_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warr_deep_wounds_aura_AuraScript);
+
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo)
+ return false;
+
+ return eventInfo.GetActor()->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* actor = eventInfo.GetActor();
+ float damage = 0.f;
+
+ if (eventInfo.GetDamageInfo()->GetAttackType() == OFF_ATTACK)
+ damage = (actor->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + actor->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE)) / 2.f;
+ else
+ damage = (actor->GetFloatValue(UNIT_FIELD_MINDAMAGE) + actor->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2.f;
+
+ actor->CastCustomSpell(GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, SPELLVALUE_BASE_POINT0, int32(damage), eventInfo.GetProcTarget(), true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_warr_deep_wounds_aura_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_warr_deep_wounds_aura_AuraScript::OnProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warr_deep_wounds_aura_AuraScript();
+ }
+};
+
// -5308 - Execute
class spell_warr_execute : public SpellScriptLoader
{
@@ -352,6 +417,94 @@ class spell_warr_execute : public SpellScriptLoader
}
};
+// -29723 - Bloodsurge
+// -46913 - Sudden Death
+class spell_warr_extra_proc : public SpellScriptLoader
+{
+ public:
+ spell_warr_extra_proc() : SpellScriptLoader("spell_warr_extra_proc") { }
+
+ class spell_warr_extra_proc_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warr_extra_proc_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_T10_MELEE_4P_BONUS) ||
+ !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_EXTRA_CHARGE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_SLAM_GCD_REDUCED) ||
+ !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_EXECUTE_GCD_REDUCED))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ Unit* target = GetTarget();
+ AuraEffect const* bonusAurEff = target->GetAuraEffect(SPELL_WARRIOR_T10_MELEE_4P_BONUS, EFFECT_0);
+ if (!bonusAurEff)
+ return;
+
+ if (!roll_chance_i(bonusAurEff->GetAmount()))
+ return;
+
+ target->CastSpell((Unit*)nullptr, SPELL_WARRIOR_EXTRA_CHARGE, true, nullptr, aurEff);
+
+ SpellInfo const* auraInfo = aurEff->GetSpellInfo();
+ if (auraInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_WARRIOR_BLOODSURGE_R1)))
+ target->CastSpell((Unit*)nullptr, SPELL_WARRIOR_SLAM_GCD_REDUCED, true, nullptr, aurEff);
+ else if (auraInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_WARRIOR_SUDDEN_DEATH_R1)))
+ target->CastSpell((Unit*)nullptr, SPELL_WARRIOR_EXECUTE_GCD_REDUCED, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_warr_extra_proc_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warr_extra_proc_AuraScript();
+ }
+};
+
+// 58375 - Glyph of Blocking
+class spell_warr_glyph_of_blocking : public SpellScriptLoader
+{
+ public:
+ spell_warr_glyph_of_blocking() : SpellScriptLoader("spell_warr_glyph_of_blocking") { }
+
+ class spell_warr_glyph_of_blocking_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warr_glyph_of_blocking_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_GLYPH_OF_BLOCKING))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ caster->CastSpell(caster, SPELL_WARRIOR_GLYPH_OF_BLOCKING, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_warr_glyph_of_blocking_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warr_glyph_of_blocking_AuraScript();
+ }
+};
+
// 58387 - Glyph of Sunder Armor
class spell_warr_glyph_of_sunder_armor : public SpellScriptLoader
{
@@ -388,31 +541,39 @@ class spell_warr_glyph_of_sunder_armor : public SpellScriptLoader
}
};
-// 59725 - Improved Spell Reflection
+// -59088 - Improved Spell Reflection
class spell_warr_improved_spell_reflection : public SpellScriptLoader
{
public:
spell_warr_improved_spell_reflection() : SpellScriptLoader("spell_warr_improved_spell_reflection") { }
- class spell_warr_improved_spell_reflection_SpellScript : public SpellScript
+ class spell_warr_improved_spell_reflection_AuraScript : public AuraScript
{
- PrepareSpellScript(spell_warr_improved_spell_reflection_SpellScript);
+ PrepareAuraScript(spell_warr_improved_spell_reflection_AuraScript);
- void FilterTargets(std::list<WorldObject*>& unitList)
+ bool Validate(SpellInfo const* /*spellInfo*/) override
{
- if (GetCaster())
- unitList.remove(GetCaster());
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_IMPROVED_SPELL_REFLECTION_TRIGGER))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActor();
+ caster->CastCustomSpell(SPELL_WARRIOR_IMPROVED_SPELL_REFLECTION_TRIGGER, SPELLVALUE_MAX_TARGETS, aurEff->GetAmount(), caster, true, nullptr, aurEff);
}
void Register() override
{
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_warr_improved_spell_reflection_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_PARTY);
+ OnEffectProc += AuraEffectProcFn(spell_warr_improved_spell_reflection_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
}
};
- SpellScript* GetSpellScript() const override
+ AuraScript* GetAuraScript() const override
{
- return new spell_warr_improved_spell_reflection_SpellScript();
+ return new spell_warr_improved_spell_reflection_AuraScript();
}
};
@@ -444,6 +605,44 @@ class spell_warr_intimidating_shout : public SpellScriptLoader
}
};
+// 70844 - Item - Warrior T10 Protection 4P Bonus
+class spell_warr_item_t10_prot_4p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_warr_item_t10_prot_4p_bonus() : SpellScriptLoader("spell_warr_item_t10_prot_4p_bonus") { }
+
+ class spell_warr_item_t10_prot_4p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warr_item_t10_prot_4p_bonus_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_STOICISM))
+ return false;
+ return true;
+ }
+
+ void HandleProc(ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ Unit* target = eventInfo.GetActionTarget();
+ int32 bp0 = CalculatePct(target->GetMaxHealth(), GetSpellInfo()->Effects[EFFECT_1].CalcValue());
+ target->CastCustomSpell(SPELL_WARRIOR_STOICISM, SPELLVALUE_BASE_POINT0, bp0, (Unit*)nullptr, true);
+ }
+
+ void Register() override
+ {
+ OnProc += AuraProcFn(spell_warr_item_t10_prot_4p_bonus_AuraScript::HandleProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warr_item_t10_prot_4p_bonus_AuraScript();
+ }
+};
+
// 12975 - Last Stand
class spell_warr_last_stand : public SpellScriptLoader
{
@@ -606,6 +805,56 @@ class spell_warr_retaliation : public SpellScriptLoader
}
};
+// -29834 - Second Wind
+class spell_warr_second_wind : public SpellScriptLoader
+{
+ public:
+ spell_warr_second_wind() : SpellScriptLoader("spell_warr_second_wind") { }
+
+ class spell_warr_second_wind_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warr_second_wind_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_SECOND_WIND_TRIGGER_1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_SECOND_WIND_TRIGGER_2))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return false;
+
+ return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN))) != 0;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ static uint32 const triggeredSpells[2] = { SPELL_WARRIOR_SECOND_WIND_TRIGGER_1, SPELL_WARRIOR_SECOND_WIND_TRIGGER_2 };
+
+ PreventDefaultAction();
+ Unit* caster = eventInfo.GetActionTarget();
+ uint32 spellId = triggeredSpells[GetSpellInfo()->GetRank() - 1];
+ caster->CastSpell(caster, spellId, true, nullptr, aurEff);
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_warr_second_wind_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_warr_second_wind_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warr_second_wind_AuraScript();
+ }
+};
+
// 64380, 65941 - Shattering Throw
class spell_warr_shattering_throw : public SpellScriptLoader
{
@@ -705,18 +954,18 @@ class spell_warr_sweeping_strikes : public SpellScriptLoader
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- if (eventInfo.GetDamageInfo())
+ if (DamageInfo* damageInfo = eventInfo.GetDamageInfo())
{
- SpellInfo const* spellInfo = eventInfo.GetDamageInfo()->GetSpellInfo();
+ SpellInfo const* spellInfo = damageInfo->GetSpellInfo();
if (spellInfo && (spellInfo->Id == SPELL_WARRIOR_BLADESTORM_PERIODIC_WHIRLWIND || (spellInfo->Id == SPELL_WARRIOR_EXECUTE && !_procTarget->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT))))
{
// If triggered by Execute (while target is not under 20% hp) or Bladestorm deals normalized weapon damage
- GetTarget()->CastSpell(_procTarget, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_2, true, NULL, aurEff);
+ GetTarget()->CastSpell(_procTarget, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_2, true, nullptr, aurEff);
}
else
{
- int32 damage = eventInfo.GetDamageInfo()->GetDamage();
- GetTarget()->CastCustomSpell(SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_1, SPELLVALUE_BASE_POINT0, damage, _procTarget, true, NULL, aurEff);
+ int32 damage = damageInfo->GetDamage();
+ GetTarget()->CastCustomSpell(SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_1, SPELLVALUE_BASE_POINT0, damage, _procTarget, true, nullptr, aurEff);
}
}
}
@@ -737,6 +986,101 @@ class spell_warr_sweeping_strikes : public SpellScriptLoader
}
};
+// -46951 - Sword and Board
+class spell_warr_sword_and_board : public SpellScriptLoader
+{
+ public:
+ spell_warr_sword_and_board() : SpellScriptLoader("spell_warr_sword_and_board") { }
+
+ class spell_warr_sword_and_board_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warr_sword_and_board_AuraScript);
+
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ // Remove cooldown on Shield Slam
+ GetTarget()->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
+ {
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
+ return spellInfo && spellInfo->GetCategory() == SPELL_CATEGORY_SHIELD_SLAM;
+ }, true);
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_warr_sword_and_board_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warr_sword_and_board_AuraScript();
+ }
+};
+
+// 28845 - Cheat Death
+class spell_warr_t3_prot_8p_bonus : public SpellScriptLoader
+{
+ public:
+ spell_warr_t3_prot_8p_bonus() : SpellScriptLoader("spell_warr_t3_prot_8p_bonus") { }
+
+ class spell_warr_t3_prot_8p_bonus_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warr_t3_prot_8p_bonus_AuraScript);
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (eventInfo.GetActionTarget()->HealthBelowPct(20))
+ return true;
+
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (damageInfo && damageInfo->GetDamage())
+ if (GetTarget()->HealthBelowPctDamaged(20, damageInfo->GetDamage()))
+ return true;
+
+ return false;
+ }
+
+ void Register() override
+ {
+ DoCheckProc += AuraCheckProcFn(spell_warr_t3_prot_8p_bonus_AuraScript::CheckProc);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warr_t3_prot_8p_bonus_AuraScript();
+ }
+};
+
+// 32216 - Victorious
+class spell_warr_victorious : public SpellScriptLoader
+{
+ public:
+ spell_warr_victorious() : SpellScriptLoader("spell_warr_victorious") { }
+
+ class spell_warr_victorious_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warr_victorious_AuraScript);
+
+ void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ // Prevent console log
+ PreventDefaultAction();
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_warr_victorious_AuraScript::HandleDummy, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_warr_victorious_AuraScript();
+ }
+};
+
// 50720 - Vigilance
class spell_warr_vigilance : public SpellScriptLoader
{
@@ -871,17 +1215,25 @@ void AddSC_warrior_spell_scripts()
new spell_warr_concussion_blow();
new spell_warr_damage_shield();
new spell_warr_deep_wounds();
+ new spell_warr_deep_wounds_aura();
new spell_warr_execute();
+ new spell_warr_extra_proc();
+ new spell_warr_glyph_of_blocking();
new spell_warr_glyph_of_sunder_armor();
new spell_warr_improved_spell_reflection();
new spell_warr_intimidating_shout();
+ new spell_warr_item_t10_prot_4p_bonus();
new spell_warr_last_stand();
new spell_warr_overpower();
new spell_warr_rend();
new spell_warr_retaliation();
+ new spell_warr_second_wind();
new spell_warr_shattering_throw();
new spell_warr_slam();
new spell_warr_sweeping_strikes();
+ new spell_warr_sword_and_board();
+ new spell_warr_t3_prot_8p_bonus();
+ new spell_warr_victorious();
new spell_warr_vigilance();
new spell_warr_vigilance_trigger();
}
diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp
index 514a9b7eead..91166294355 100644
--- a/src/server/scripts/World/go_scripts.cpp
+++ b/src/server/scripts/World/go_scripts.cpp
@@ -51,6 +51,7 @@ EndContentData */
#include "Spell.h"
#include "Player.h"
#include "WorldSession.h"
+#include "GameEventMgr.h"
/*######
## go_cat_figurine
@@ -1262,6 +1263,312 @@ class go_toy_train_set : public GameObjectScript
}
};
+/*####
+## go_brewfest_music
+####*/
+
+enum BrewfestMusic
+{
+ EVENT_BREWFESTDWARF01 = 11810, // 1.35 min
+ EVENT_BREWFESTDWARF02 = 11812, // 1.55 min
+ EVENT_BREWFESTDWARF03 = 11813, // 0.23 min
+ EVENT_BREWFESTGOBLIN01 = 11811, // 1.08 min
+ EVENT_BREWFESTGOBLIN02 = 11814, // 1.33 min
+ EVENT_BREWFESTGOBLIN03 = 11815 // 0.28 min
+};
+
+// These are in seconds
+enum BrewfestMusicTime
+{
+ EVENT_BREWFESTDWARF01_TIME = 95000,
+ EVENT_BREWFESTDWARF02_TIME = 155000,
+ EVENT_BREWFESTDWARF03_TIME = 23000,
+ EVENT_BREWFESTGOBLIN01_TIME = 68000,
+ EVENT_BREWFESTGOBLIN02_TIME = 93000,
+ EVENT_BREWFESTGOBLIN03_TIME = 28000
+};
+
+enum BrewfestMusicAreas
+{
+ SILVERMOON = 3430, // Horde
+ UNDERCITY = 1497,
+ ORGRIMMAR_1 = 1296,
+ ORGRIMMAR_2 = 14,
+ THUNDERBLUFF = 1638,
+ IRONFORGE_1 = 809, // Alliance
+ IRONFORGE_2 = 1,
+ STORMWIND = 12,
+ EXODAR = 3557,
+ DARNASSUS = 1657,
+ SHATTRATH = 3703 // General
+};
+
+enum BrewfestMusicEvents
+{
+ EVENT_BM_SELECT_MUSIC = 1,
+ EVENT_BM_START_MUSIC = 2
+};
+
+class go_brewfest_music : public GameObjectScript
+{
+public:
+ go_brewfest_music() : GameObjectScript("go_brewfest_music") { }
+
+ struct go_brewfest_musicAI : public GameObjectAI
+ {
+ uint32 rnd = 0;
+ uint32 musicTime = 1000;
+
+ go_brewfest_musicAI(GameObject* go) : GameObjectAI(go)
+ {
+ _events.ScheduleEvent(EVENT_BM_SELECT_MUSIC, 1000);
+ _events.ScheduleEvent(EVENT_BM_START_MUSIC, 2000);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_BM_SELECT_MUSIC:
+ if (!IsHolidayActive(HOLIDAY_BREWFEST)) // Check if Brewfest is active
+ break;
+ rnd = urand(0, 2); // Select random music sample
+ _events.ScheduleEvent(EVENT_BM_SELECT_MUSIC, musicTime); // Select new song music after play time is over
+ break;
+ case EVENT_BM_START_MUSIC:
+ if (!IsHolidayActive(HOLIDAY_BREWFEST)) // Check if Brewfest is active
+ break;
+ // Check if gob is correct area, play music, set time of music
+ if (go->GetAreaId() == SILVERMOON || go->GetAreaId() == UNDERCITY || go->GetAreaId() == ORGRIMMAR_1 || go->GetAreaId() == ORGRIMMAR_2 || go->GetAreaId() == THUNDERBLUFF || go->GetAreaId() == SHATTRATH)
+ {
+ if (rnd == 0)
+ {
+ go->PlayDirectMusic(EVENT_BREWFESTGOBLIN01);
+ musicTime = EVENT_BREWFESTGOBLIN01_TIME;
+ }
+ else if (rnd == 1)
+ {
+ go->PlayDirectMusic(EVENT_BREWFESTGOBLIN02);
+ musicTime = EVENT_BREWFESTGOBLIN02_TIME;
+ }
+ else
+ {
+ go->PlayDirectMusic(EVENT_BREWFESTGOBLIN03);
+ musicTime = EVENT_BREWFESTGOBLIN03_TIME;
+ }
+ }
+ if (go->GetAreaId() == IRONFORGE_1 || go->GetAreaId() == IRONFORGE_2 || go->GetAreaId() == STORMWIND || go->GetAreaId() == EXODAR || go->GetAreaId() == DARNASSUS || go->GetAreaId() == SHATTRATH)
+ {
+ if (rnd == 0)
+ {
+ go->PlayDirectMusic(EVENT_BREWFESTDWARF01);
+ musicTime = EVENT_BREWFESTDWARF01_TIME;
+ }
+ else if (rnd == 1)
+ {
+ go->PlayDirectMusic(EVENT_BREWFESTDWARF02);
+ musicTime = EVENT_BREWFESTDWARF02_TIME;
+ }
+ else
+ {
+ go->PlayDirectMusic(EVENT_BREWFESTDWARF03);
+ musicTime = EVENT_BREWFESTDWARF03_TIME;
+ }
+ }
+ _events.ScheduleEvent(EVENT_BM_START_MUSIC, 5000); // Every 5 second's SMSG_PLAY_MUSIC packet (PlayDirectMusic) is pushed to the client
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ private:
+ EventMap _events;
+ };
+
+ GameObjectAI* GetAI(GameObject* go) const override
+ {
+ return new go_brewfest_musicAI(go);
+ }
+};
+
+/*####
+## go_midsummer_music
+####*/
+
+enum MidsummerMusic
+{
+ EVENTMIDSUMMERFIREFESTIVAL_A = 12319, // 1.08 min
+ EVENTMIDSUMMERFIREFESTIVAL_H = 12325, // 1.12 min
+};
+
+enum MidsummerMusicEvents
+{
+ EVENT_MM_START_MUSIC = 1
+};
+
+class go_midsummer_music : public GameObjectScript
+{
+public:
+ go_midsummer_music() : GameObjectScript("go_midsummer_music") { }
+
+ struct go_midsummer_musicAI : public GameObjectAI
+ {
+ go_midsummer_musicAI(GameObject* go) : GameObjectAI(go)
+ {
+ _events.ScheduleEvent(EVENT_MM_START_MUSIC, 1000);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_MM_START_MUSIC:
+ {
+ if (!IsHolidayActive(HOLIDAY_FIRE_FESTIVAL))
+ break;
+
+ std::vector<Player*> playersNearby;
+ go->GetPlayerListInGrid(playersNearby, go->GetMap()->GetVisibilityRange());
+ for (Player* player : playersNearby)
+ {
+ if (player->GetTeamId() == TEAM_HORDE)
+ go->PlayDirectMusic(EVENTMIDSUMMERFIREFESTIVAL_H, player);
+ else
+ go->PlayDirectMusic(EVENTMIDSUMMERFIREFESTIVAL_A, player);
+ }
+ _events.ScheduleEvent(EVENT_MM_START_MUSIC, 5000); // Every 5 second's SMSG_PLAY_MUSIC packet (PlayDirectMusic) is pushed to the client (sniffed value)
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ private:
+ EventMap _events;
+ };
+
+ GameObjectAI* GetAI(GameObject* go) const override
+ {
+ return new go_midsummer_musicAI(go);
+ }
+};
+
+/*####
+## go_darkmoon_faire_music
+####*/
+
+enum DarkmoonFaireMusic
+{
+ MUSIC_DARKMOON_FAIRE_MUSIC = 8440
+};
+
+enum DarkmoonFaireMusicEvents
+{
+ EVENT_DFM_START_MUSIC = 1
+};
+
+class go_darkmoon_faire_music : public GameObjectScript
+{
+public:
+ go_darkmoon_faire_music() : GameObjectScript("go_darkmoon_faire_music") { }
+
+ struct go_darkmoon_faire_musicAI : public GameObjectAI
+ {
+ go_darkmoon_faire_musicAI(GameObject* go) : GameObjectAI(go)
+ {
+ _events.ScheduleEvent(EVENT_DFM_START_MUSIC, 1000);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_DFM_START_MUSIC:
+ if (!IsHolidayActive(HOLIDAY_DARKMOON_FAIRE_ELWYNN) || !IsHolidayActive(HOLIDAY_DARKMOON_FAIRE_THUNDER) || !IsHolidayActive(HOLIDAY_DARKMOON_FAIRE_SHATTRATH))
+ break;
+ go->PlayDirectMusic(MUSIC_DARKMOON_FAIRE_MUSIC);
+ _events.ScheduleEvent(EVENT_DFM_START_MUSIC, 5000); // Every 5 second's SMSG_PLAY_MUSIC packet (PlayDirectMusic) is pushed to the client (sniffed value)
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ private:
+ EventMap _events;
+ };
+
+ GameObjectAI* GetAI(GameObject* go) const override
+ {
+ return new go_darkmoon_faire_musicAI(go);
+ }
+};
+
+/*####
+## go_pirate_day_music
+####*/
+
+enum PirateDayMusic
+{
+ MUSIC_PIRATE_DAY_MUSIC = 12845
+};
+
+enum PirateDayMusicEvents
+{
+ EVENT_PDM_START_MUSIC = 1
+};
+
+class go_pirate_day_music : public GameObjectScript
+{
+public:
+ go_pirate_day_music() : GameObjectScript("go_pirate_day_music") { }
+
+ struct go_pirate_day_musicAI : public GameObjectAI
+ {
+ go_pirate_day_musicAI(GameObject* go) : GameObjectAI(go)
+ {
+ _events.ScheduleEvent(EVENT_PDM_START_MUSIC, 1000);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_PDM_START_MUSIC:
+ if (!IsHolidayActive(HOLIDAY_PIRATES_DAY))
+ break;
+ go->PlayDirectMusic(MUSIC_PIRATE_DAY_MUSIC);
+ _events.ScheduleEvent(EVENT_PDM_START_MUSIC, 5000); // Every 5 second's SMSG_PLAY_MUSIC packet (PlayDirectMusic) is pushed to the client (sniffed value)
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ private:
+ EventMap _events;
+ };
+
+ GameObjectAI* GetAI(GameObject* go) const override
+ {
+ return new go_pirate_day_musicAI(go);
+ }
+};
+
void AddSC_go_scripts()
{
new go_cat_figurine();
@@ -1299,4 +1606,8 @@ void AddSC_go_scripts()
new go_midsummer_bonfire();
new go_midsummer_ribbon_pole();
new go_toy_train_set();
+ new go_brewfest_music();
+ new go_midsummer_music();
+ new go_darkmoon_faire_music();
+ new go_pirate_day_music();
}
diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp
index a598f017eb6..8dd606f8b66 100644
--- a/src/server/scripts/World/npcs_special.cpp
+++ b/src/server/scripts/World/npcs_special.cpp
@@ -243,47 +243,6 @@ public:
}
};
-/*######
-## npc_lunaclaw_spirit
-######*/
-
-enum LunaclawSpirit
-{
- QUEST_BODY_HEART_A = 6001,
- QUEST_BODY_HEART_H = 6002,
-
- TEXT_ID_DEFAULT = 4714,
- TEXT_ID_PROGRESS = 4715
-};
-
-#define GOSSIP_ITEM_GRANT "You have thought well, spirit. I ask you to grant me the strength of your body and the strength of your heart."
-
-class npc_lunaclaw_spirit : public CreatureScript
-{
-public:
- npc_lunaclaw_spirit() : CreatureScript("npc_lunaclaw_spirit") { }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (player->GetQuestStatus(QUEST_BODY_HEART_A) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(QUEST_BODY_HEART_H) == QUEST_STATUS_INCOMPLETE)
- AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM_GRANT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
-
- SendGossipMenuFor(player, TEXT_ID_DEFAULT, creature->GetGUID());
- return true;
- }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- ClearGossipMenuFor(player);
- if (action == GOSSIP_ACTION_INFO_DEF + 1)
- {
- SendGossipMenuFor(player, TEXT_ID_PROGRESS, creature->GetGUID());
- player->AreaExploredOrEventHappens(player->GetTeam() == ALLIANCE ? QUEST_BODY_HEART_A : QUEST_BODY_HEART_H);
- }
- return true;
- }
-};
-
/*########
# npc_chicken_cluck
#########*/
@@ -2644,7 +2603,6 @@ public:
void AddSC_npcs_special()
{
new npc_air_force_bots();
- new npc_lunaclaw_spirit();
new npc_chicken_cluck();
new npc_dancing_flames();
new npc_torch_tossing_target_bunny_controller();
diff --git a/src/server/shared/Dynamic/LinkedList.h b/src/server/shared/Dynamic/LinkedList.h
index 94f67cac909..1c99144db0e 100644
--- a/src/server/shared/Dynamic/LinkedList.h
+++ b/src/server/shared/Dynamic/LinkedList.h
@@ -32,18 +32,18 @@ class LinkedListElement
LinkedListElement* iNext;
LinkedListElement* iPrev;
+
public:
- LinkedListElement() : iNext(NULL), iPrev(NULL) { }
- virtual ~LinkedListElement() { delink(); }
+ LinkedListElement() : iNext(nullptr), iPrev(nullptr) { }
- bool hasNext() const { return(iNext && iNext->iNext != NULL); }
- bool hasPrev() const { return(iPrev && iPrev->iPrev != NULL); }
- bool isInList() const { return(iNext != NULL && iPrev != NULL); }
+ bool hasNext() const { return (iNext && iNext->iNext != nullptr); }
+ bool hasPrev() const { return (iPrev && iPrev->iPrev != nullptr); }
+ bool isInList() const { return (iNext != nullptr && iPrev != nullptr); }
- LinkedListElement * next() { return hasNext() ? iNext : NULL; }
- LinkedListElement const* next() const { return hasNext() ? iNext : NULL; }
- LinkedListElement * prev() { return hasPrev() ? iPrev : NULL; }
- LinkedListElement const* prev() const { return hasPrev() ? iPrev : NULL; }
+ LinkedListElement * next() { return hasNext() ? iNext : nullptr; }
+ LinkedListElement const* next() const { return hasNext() ? iNext : nullptr; }
+ LinkedListElement * prev() { return hasPrev() ? iPrev : nullptr; }
+ LinkedListElement const* prev() const { return hasPrev() ? iPrev : nullptr; }
LinkedListElement * nocheck_next() { return iNext; }
LinkedListElement const* nocheck_next() const { return iNext; }
@@ -52,10 +52,13 @@ class LinkedListElement
void delink()
{
- if (isInList())
- {
- iNext->iPrev = iPrev; iPrev->iNext = iNext; iNext = NULL; iPrev = NULL;
- }
+ if (!isInList())
+ return;
+
+ iNext->iPrev = iPrev;
+ iPrev->iNext = iNext;
+ iNext = nullptr;
+ iPrev = nullptr;
}
void insertBefore(LinkedListElement* pElem)
@@ -75,8 +78,14 @@ class LinkedListElement
}
private:
- LinkedListElement(LinkedListElement const&);
- LinkedListElement& operator=(LinkedListElement const&);
+ LinkedListElement(LinkedListElement const&) = delete;
+ LinkedListElement& operator=(LinkedListElement const&) = delete;
+
+ protected:
+ ~LinkedListElement()
+ {
+ delink();
+ }
};
//============================================
@@ -97,15 +106,13 @@ class LinkedListHead
iLast.iPrev = &iFirst;
}
- virtual ~LinkedListHead() { }
-
bool isEmpty() const { return(!iFirst.iNext->isInList()); }
- LinkedListElement * getFirst() { return(isEmpty() ? NULL : iFirst.iNext); }
- LinkedListElement const* getFirst() const { return(isEmpty() ? NULL : iFirst.iNext); }
+ LinkedListElement * getFirst() { return (isEmpty() ? nullptr : iFirst.iNext); }
+ LinkedListElement const* getFirst() const { return (isEmpty() ? nullptr : iFirst.iNext); }
- LinkedListElement * getLast() { return(isEmpty() ? NULL : iLast.iPrev); }
- LinkedListElement const* getLast() const { return(isEmpty() ? NULL : iLast.iPrev); }
+ LinkedListElement * getLast() { return(isEmpty() ? nullptr : iLast.iPrev); }
+ LinkedListElement const* getLast() const { return(isEmpty() ? nullptr : iLast.iPrev); }
void insertFirst(LinkedListElement* pElem)
{
@@ -248,8 +255,11 @@ class LinkedListHead
typedef Iterator<LinkedListElement> iterator;
private:
- LinkedListHead(LinkedListHead const&);
- LinkedListHead& operator=(LinkedListHead const&);
+ LinkedListHead(LinkedListHead const&) = delete;
+ LinkedListHead& operator=(LinkedListHead const&) = delete;
+
+ protected:
+ ~LinkedListHead() { }
};
//============================================
diff --git a/src/server/shared/Dynamic/LinkedReference/RefManager.h b/src/server/shared/Dynamic/LinkedReference/RefManager.h
index 9dbab4f338e..3c716e3c6b7 100644
--- a/src/server/shared/Dynamic/LinkedReference/RefManager.h
+++ b/src/server/shared/Dynamic/LinkedReference/RefManager.h
@@ -23,31 +23,29 @@
#include "Dynamic/LinkedList.h"
#include "Dynamic/LinkedReference/Reference.h"
-template <class TO, class FROM> class RefManager : public LinkedListHead
+template <class TO, class FROM>
+class RefManager : public LinkedListHead
{
public:
- typedef LinkedListHead::Iterator< Reference<TO, FROM> > iterator;
+ typedef LinkedListHead::Iterator<Reference<TO, FROM>> iterator;
RefManager() { }
- virtual ~RefManager() { clearReferences(); }
- Reference<TO, FROM>* getFirst() { return ((Reference<TO, FROM>*) LinkedListHead::getFirst()); }
- Reference<TO, FROM> const* getFirst() const { return ((Reference<TO, FROM> const*) LinkedListHead::getFirst()); }
- Reference<TO, FROM>* getLast() { return ((Reference<TO, FROM>*) LinkedListHead::getLast()); }
- Reference<TO, FROM> const* getLast() const { return ((Reference<TO, FROM> const*) LinkedListHead::getLast()); }
+ Reference<TO, FROM>* getFirst() { return static_cast<Reference<TO, FROM>*>(LinkedListHead::getFirst()); }
+
+ Reference<TO, FROM> const* getFirst() const { return static_cast<Reference<TO, FROM> const*>(LinkedListHead::getFirst()); }
iterator begin() { return iterator(getFirst()); }
- iterator end() { return iterator(NULL); }
- iterator rbegin() { return iterator(getLast()); }
- iterator rend() { return iterator(NULL); }
+ iterator end() { return iterator(nullptr); }
+
+ virtual ~RefManager()
+ {
+ clearReferences();
+ }
void clearReferences()
{
- LinkedListElement* ref;
- while ((ref = getFirst()) != NULL)
- {
- ((Reference<TO, FROM>*) ref)->invalidate();
- ref->delink(); // the delink might be already done by invalidate(), but doing it here again does not hurt and insures an empty list
- }
+ while (Reference<TO, FROM>* ref = getFirst())
+ ref->invalidate();
}
};
diff --git a/src/server/shared/Dynamic/LinkedReference/Reference.h b/src/server/shared/Dynamic/LinkedReference/Reference.h
index 4a473b0f2ac..0dcf91fb052 100644
--- a/src/server/shared/Dynamic/LinkedReference/Reference.h
+++ b/src/server/shared/Dynamic/LinkedReference/Reference.h
@@ -29,6 +29,7 @@ template <class TO, class FROM> class Reference : public LinkedListElement
private:
TO* iRefTo;
FROM* iRefFrom;
+
protected:
// Tell our refTo (target) object that we have a link
virtual void targetObjectBuildLink() = 0;
@@ -90,14 +91,14 @@ template <class TO, class FROM> class Reference : public LinkedListElement
Reference<TO, FROM> * nocheck_prev() { return((Reference<TO, FROM> *) LinkedListElement::nocheck_prev()); }
Reference<TO, FROM> const* nocheck_prev() const { return((Reference<TO, FROM> const*) LinkedListElement::nocheck_prev()); }
- TO* operator ->() const { return iRefTo; }
+ TO* operator->() const { return iRefTo; }
TO* getTarget() const { return iRefTo; }
FROM* GetSource() const { return iRefFrom; }
private:
- Reference(Reference const&);
- Reference& operator=(Reference const&);
+ Reference(Reference const&) = delete;
+ Reference& operator=(Reference const&) = delete;
};
//=====================================================
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index 0513f2b0ab4..1d173057e6f 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1018,6 +1018,15 @@ Quests.IgnoreAutoAccept = 0
Quests.IgnoreAutoComplete = 0
#
+# Quests.DailyResetTime
+# Description: Hour of the day when daily quest reset occurs.
+# Range: 0-23
+# Default: 3 - (3:00 AM, Blizzlike)
+#
+
+Quests.DailyResetTime = 3
+
+#
# Guild.EventLogRecordsCount
# Description: Number of log entries for guild events that are stored per guild. Old entries
# will be overwritten if the number of log entries exceed the configured value.
@@ -1682,10 +1691,10 @@ Creature.MovingStopTimeForPlayer = 180000
# Description: Chat protection from creating fake messages using a lot spaces or other
# invisible symbols. Not applied to the addon language, but may break old
# addons that use normal languages for sending data to other clients.
-# Default: 0 - (Disabled)
-# 1 - (Enabled)
+# Default: 1 - (Enabled, Blizzlike)
+# 0 - (Disabled)
-ChatFakeMessagePreventing = 0
+ChatFakeMessagePreventing = 1
#
# ChatStrictLinkChecking.Severity
@@ -3061,6 +3070,15 @@ PreventRenameCharacterOnCustomization = 0
###################################################################################################
# AUCTION HOUSE BOT SETTINGS
#
+# AuctionHouseBot.Account
+# Description: Account ID for AHBot characters. If non-zero, all auctions and bids associated
+# with the AHBot will randomly be assigned one of this account's characters.
+# Default: 0
+#
+
+AuctionHouseBot.Account = 0
+
+#
# AuctionHouseBot.Update.Interval
# Description: Interval in seconds for AHBot to get updated
# Default: 20
diff --git a/src/tools/vmap4_extractor/mpq_libmpq.cpp b/src/tools/vmap4_extractor/mpq_libmpq.cpp
index 690600867d9..f106f96f5ec 100644
--- a/src/tools/vmap4_extractor/mpq_libmpq.cpp
+++ b/src/tools/vmap4_extractor/mpq_libmpq.cpp
@@ -19,6 +19,7 @@
#include "mpq_libmpq04.h"
#include <deque>
#include <cstdio>
+#include <algorithm>
ArchiveSet gOpenArchives;
@@ -52,6 +53,11 @@ MPQArchive::MPQArchive(const char* filename)
gOpenArchives.push_front(this);
}
+bool MPQArchive::isOpened() const
+{
+ return std::find(gOpenArchives.begin(), gOpenArchives.end(), this) != gOpenArchives.end();
+}
+
void MPQArchive::close()
{
//gOpenArchives.erase(erase(&mpq_a);
diff --git a/src/tools/vmap4_extractor/mpq_libmpq04.h b/src/tools/vmap4_extractor/mpq_libmpq04.h
index 97b77d4643b..f4a9d2aa596 100644
--- a/src/tools/vmap4_extractor/mpq_libmpq04.h
+++ b/src/tools/vmap4_extractor/mpq_libmpq04.h
@@ -34,7 +34,7 @@ public:
mpq_archive_s *mpq_a;
MPQArchive(const char* filename);
- ~MPQArchive() { close(); }
+ ~MPQArchive() { if (isOpened()) close(); }
void GetFileListTo(std::vector<std::string>& filelist) {
uint32_t filenum;
@@ -66,6 +66,7 @@ public:
private:
void close();
+ bool isOpened() const;
};
typedef std::deque<MPQArchive*> ArchiveSet;
@@ -95,13 +96,8 @@ public:
inline void flipcc(char *fcc)
{
- char t;
- t=fcc[0];
- fcc[0]=fcc[3];
- fcc[3]=t;
- t=fcc[1];
- fcc[1]=fcc[2];
- fcc[2]=t;
+ std::swap(fcc[0], fcc[3]);
+ std::swap(fcc[1], fcc[2]);
}
#endif