aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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.cpp73
-rw-r--r--src/server/authserver/Server/AuthSession.h10
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.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.h32
-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/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/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/BattlegroundMgr.cpp2
-rw-r--r--src/server/game/Chat/Channels/Channel.cpp2
-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.cpp27
-rw-r--r--src/server/game/Entities/Creature/Creature.h3
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp38
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h7
-rw-r--r--src/server/game/Entities/Item/Item.cpp38
-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.cpp112
-rw-r--r--src/server/game/Entities/Object/Object.h11
-rw-r--r--src/server/game/Entities/Player/Player.cpp221
-rw-r--r--src/server/game/Entities/Player/Player.h5
-rw-r--r--src/server/game/Entities/Transport/Transport.cpp6
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp640
-rw-r--r--src/server/game/Entities/Unit/Unit.h94
-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/Notifiers/GridNotifiers.h344
-rw-r--r--src/server/game/Groups/Group.cpp2
-rw-r--r--src/server/game/Handlers/AuctionHouseHandler.cpp2
-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/SpellHandler.cpp8
-rw-r--r--src/server/game/Handlers/TradeHandler.cpp6
-rw-r--r--src/server/game/Loot/LootMgr.cpp153
-rw-r--r--src/server/game/Loot/LootMgr.h38
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h15
-rw-r--r--src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp2
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp21
-rw-r--r--src/server/game/Scripting/ScriptMgr.h5
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp410
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.h2
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp232
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h10
-rw-r--r--src/server/game/Spells/Spell.cpp712
-rw-r--r--src/server/game/Spells/Spell.h38
-rw-r--r--src/server/game/Spells/SpellEffects.cpp71
-rw-r--r--src/server/game/Spells/SpellInfo.cpp860
-rw-r--r--src/server/game/Spells/SpellInfo.h445
-rw-r--r--src/server/game/Spells/SpellMgr.cpp573
-rw-r--r--src/server/game/Spells/SpellMgr.h18
-rw-r--r--src/server/game/Spells/SpellScript.cpp68
-rw-r--r--src/server/game/Spells/SpellScript.h8
-rw-r--r--src/server/game/World/World.cpp10
-rw-r--r--src/server/scripts/Commands/cs_cast.cpp15
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp19
-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/TheBlackMorass/the_black_morass.cpp62
-rw-r--r--src/server/scripts/Kalimdor/zone_stonetalon_mountains.cpp68
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h3
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp6
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp2
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp19
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp14
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp423
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp818
-rw-r--r--src/server/scripts/Northrend/zone_dragonblight.cpp26
-rw-r--r--src/server/scripts/Northrend/zone_wintergrasp.cpp196
-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/zone_hellfire_peninsula.cpp184
-rw-r--r--src/server/scripts/Pet/pet_hunter.cpp2
-rw-r--r--src/server/scripts/Spells/spell_dk.cpp20
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp8
-rw-r--r--src/server/scripts/Spells/spell_hunter.cpp154
-rw-r--r--src/server/scripts/Spells/spell_item.cpp117
-rw-r--r--src/server/scripts/Spells/spell_paladin.cpp6
-rw-r--r--src/server/scripts/Spells/spell_quest.cpp144
-rw-r--r--src/server/scripts/Spells/spell_shaman.cpp56
-rw-r--r--src/server/scripts/Spells/spell_warlock.cpp87
-rw-r--r--src/server/scripts/World/go_scripts.cpp25
-rw-r--r--src/server/worldserver/worldserver.conf.dist9
-rw-r--r--src/tools/vmap4_extractor/mpq_libmpq.cpp6
-rw-r--r--src/tools/vmap4_extractor/mpq_libmpq04.h12
109 files changed, 5078 insertions, 3973 deletions
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 45c2b61436f..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
{
@@ -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 bbf03248ec2..6122e5aca7b 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -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/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 08cc4fa3960..37a7020752b 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
@@ -417,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/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/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/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 85d03ef6b1f..afaa0063a45 100644
--- a/src/server/game/Chat/Channels/Channel.cpp
+++ b/src/server/game/Chat/Channels/Channel.cpp
@@ -55,7 +55,6 @@ Channel::Channel(uint32 channelId, uint32 team /*= 0*/, AreaTableEntry const* zo
_channelFlags |= CHANNEL_FLAG_NOT_LFG;
}
-
Channel::Channel(std::string const& name, uint32 team /*= 0*/) :
_announceEnabled(true),
_ownershipEnabled(true),
@@ -749,7 +748,6 @@ void Channel::Say(ObjectGuid guid, std::string const& what, uint32 lang) const
};
SendToAll(builder, !info.IsModerator() ? guid : ObjectGuid::Empty);
-
}
void Channel::Invite(Player const* player, std::string const& newname)
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 fa603b9509e..9df9d2ad53c 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -1450,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
{
@@ -1663,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);
@@ -1696,6 +1695,7 @@ void Creature::setDeathState(DeathState s)
SetLootRecipient(nullptr);
ResetPlayerDamageReq();
+ SetCannotReachTarget(false);
UpdateMovementFlags();
ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~UNIT_STATE_IGNORE_PATHFINDING));
@@ -1767,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)
@@ -1779,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 bb85fa9fc5b..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;
@@ -691,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/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 8c43d287c91..3869c8be56d 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::NearestUnfriendlyNoTotemUnitInObjectRangeCheck checker(this, owner, radius);
+ Trinity::UnitLastSearcher<Trinity::NearestUnfriendlyNoTotemUnitInObjectRangeCheck> 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)
{
@@ -1828,6 +1846,9 @@ 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());
@@ -1839,7 +1860,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId, TriggerCastFlags trigge
}
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);
@@ -2231,6 +2252,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 85b37abaf3c..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;
@@ -818,6 +819,9 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
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..9d60eb62be6 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()))
@@ -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 aea923f6eac..f7d4fb38cee 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -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);
@@ -2623,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 2fdb9433356..e107a5f6bfd 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -558,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 ac8c3696530..41d9bf7b2b2 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -939,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);
@@ -10140,7 +10149,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)
@@ -10162,6 +10171,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))
{
@@ -11627,10 +11656,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)
@@ -12296,7 +12323,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);
}
}
@@ -12314,7 +12341,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);
@@ -12387,7 +12414,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)
@@ -14825,7 +14852,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;
}
}
@@ -14840,7 +14869,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;
}
}
@@ -14989,20 +15020,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);
}
}
@@ -15187,13 +15218,16 @@ void Player::SetRewardedQuest(uint32 quest_id)
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);
@@ -15219,13 +15253,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);
}
}
@@ -15236,13 +15270,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);
}
}
@@ -15946,21 +15980,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;
}
@@ -15973,7 +16004,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);
@@ -15983,9 +16014,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;
@@ -16546,12 +16575,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);
@@ -16560,7 +16589,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)
@@ -16575,7 +16604,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
@@ -16585,17 +16614,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;
}
}
@@ -18079,13 +18108,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))
{
@@ -18096,7 +18125,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
{
@@ -18114,11 +18143,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());
@@ -18142,7 +18171,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)
@@ -19538,7 +19567,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);
@@ -20853,29 +20881,30 @@ 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 (int32 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 (SpellModifier* spellMod : m_spellMods[mod->op])
+ modMask[i] = uint32(1) << eff;
+ if ((mod->mask & modMask))
{
- if (spellMod->type == mod->type && (spellMod->mask & _mask))
- val += spellMod->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)
@@ -21482,9 +21511,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);
@@ -21521,7 +21550,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);
@@ -22709,7 +22738,7 @@ 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();
@@ -24609,9 +24638,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);
@@ -24877,7 +24906,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))
@@ -24897,7 +24926,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;
}
@@ -25861,6 +25892,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();*/
@@ -26037,7 +26082,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;
@@ -26097,7 +26142,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 7c4bf2f9471..565d4f4ac2f 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1199,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;
@@ -1405,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;
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/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 1d4886c1915..40c7ee9fc3f 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -112,7 +112,7 @@ DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo)
break;
}
- if (m_absorb)
+ if (dmgInfo.HitInfo & (HITINFO_PARTIAL_ABSORB | HITINFO_FULL_ABSORB))
m_hitMask |= PROC_HIT_ABSORB;
if (dmgInfo.HitInfo & HITINFO_FULL_RESIST)
@@ -121,6 +121,8 @@ DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo)
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:
@@ -138,10 +140,12 @@ DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo)
case MELEE_HIT_CRUSHING:
case MELEE_HIT_GLANCING:
case MELEE_HIT_NORMAL:
- m_hitMask |= PROC_HIT_NORMAL;
+ if (!damageNullified)
+ m_hitMask |= PROC_HIT_NORMAL;
break;
case MELEE_HIT_CRIT:
- m_hitMask |= PROC_HIT_CRITICAL;
+ if (!damageNullified)
+ m_hitMask |= PROC_HIT_CRITICAL;
break;
default:
break;
@@ -161,7 +165,7 @@ DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEff
void DamageInfo::ModifyDamage(int32 amount)
{
- amount = std::min(amount, int32(GetDamage()));
+ amount = std::max(amount, -static_cast<int32>(GetDamage()));
m_damage += amount;
}
@@ -179,7 +183,10 @@ void DamageInfo::ResistDamage(uint32 amount)
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)
@@ -189,7 +196,10 @@ void DamageInfo::BlockDamage(uint32 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
@@ -294,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;
@@ -646,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()))
{
@@ -967,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)
@@ -979,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);
}
@@ -988,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)
@@ -1042,7 +1049,21 @@ 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(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)
+ {
+ 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.SetDst(x, y, z, GetOrientation());
+
+ CastSpell(targets, spellInfo, nullptr, triggerFlags, castItem, triggeredByAura, originalCaster);
}
void Unit::CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castItem, AuraEffect* triggeredByAura, ObjectGuid originalCaster)
@@ -1056,7 +1077,7 @@ void Unit::CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castI
SpellCastTargets targets;
targets.SetGOTarget(go);
- 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);
}
// Obsolete func need remove, here only for comotability vs another patches
@@ -1155,7 +1176,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_RANGED);
break;
}
- // Magical Attacks
+ // Magical Attacks
case SPELL_DAMAGE_CLASS_NONE:
case SPELL_DAMAGE_CLASS_MAGIC:
{
@@ -1178,15 +1199,13 @@ 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->damage = dmgInfo.GetDamage();
}
void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss)
@@ -1396,7 +1415,10 @@ 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);
@@ -1404,7 +1426,7 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
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;
@@ -1731,57 +1753,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, BASE_ATTACK);
-
- 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
@@ -1794,19 +1808,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)
@@ -1820,16 +1834,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
@@ -1842,14 +1856,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;
@@ -1857,15 +1871,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)
@@ -1876,39 +1890,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;
}
@@ -1916,66 +1930,62 @@ 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
- DamageInfo damageInfo(caster, this, splitDamage, (*itr)->GetSpellInfo(), schoolMask, DIRECT_DAMAGE, BASE_ATTACK);
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(HealInfo& healInfo)
+void Unit::CalcHealAbsorb(HealInfo& healInfo) const
{
if (!healInfo.GetHeal())
return;
@@ -2086,6 +2096,49 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr
}
}
+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)
@@ -2321,7 +2374,7 @@ 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
@@ -2330,13 +2383,8 @@ bool Unit::isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttac
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 = GetUnitBlockChance(attackType, victim);
- if (roll_chance_f(blockChance))
+ if (blockChance && roll_chance_f(blockChance))
return true;
}
@@ -2391,11 +2439,6 @@ bool Unit::CanUseAttackType(uint8 attacktype) const
// Melee based spells hit result calculations
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
@@ -2449,7 +2492,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;
@@ -2543,7 +2586,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(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();
@@ -2586,8 +2629,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;
@@ -2609,10 +2651,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
@@ -2641,6 +2680,9 @@ 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;
@@ -2787,15 +2829,18 @@ float Unit::GetUnitParryChance(WeaponAttackType attType, Unit const* victim) con
skillBonus = 0.04f * skillDiff;
}
}
- else if (victim->GetTypeId() == TYPEID_UNIT && !(victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY))
+ else
{
- chance = 5.0f;
- chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
+ if (!victim->IsTotem() && !(victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY))
+ {
+ chance = 5.0f;
+ chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
- if (skillDiff <= 10)
- skillBonus = skillDiff * 0.1f;
- else
- skillBonus = 1.0f + (skillDiff - 10) * 1.6f;
+ if (skillDiff <= 10)
+ skillBonus = skillDiff * 0.1f;
+ else
+ skillBonus = 1.0f + (skillDiff - 10) * 1.6f;
+ }
}
chance += skillBonus;
@@ -2864,8 +2909,8 @@ float Unit::GetUnitBlockChance(WeaponAttackType attType, Unit const* victim) con
float Unit::GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victim) const
{
int32 const attackerWeaponSkill = GetWeaponSkillValue(attackType, victim);
- int32 const victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
- int32 const skillDiff = victimMaxSkillValueForLevel - attackerWeaponSkill;
+ int32 const victimDefenseSkill = victim->GetDefenseSkillValue(this);
+ int32 const skillDiff = victimDefenseSkill - attackerWeaponSkill;
float chance = 0.0f;
float skillBonus = 0.0f;
@@ -3259,10 +3304,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
@@ -5298,8 +5346,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();
@@ -5434,6 +5482,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;
}
@@ -5868,17 +5918,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;
}
}
}
@@ -6553,7 +6600,7 @@ void Unit::SendHealSpellLog(HealInfo& healInfo, bool critical /*= false*/)
// we guess size
WorldPacket data(SMSG_SPELLHEALLOG, 8 + 8 + 4 + 4 + 4 + 4 + 1 + 1);
data << healInfo.GetTarget()->GetPackGUID();
- data << GetPackGUID();
+ data << healInfo.GetHealer()->GetPackGUID();
data << uint32(healInfo.GetSpellInfo()->Id);
data << uint32(healInfo.GetHeal());
data << uint32(healInfo.GetHeal() - healInfo.GetEffectiveHeal());
@@ -7820,18 +7867,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;
@@ -7839,23 +7886,20 @@ bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask) const
bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
{
- if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
+ if (spellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) || spellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
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;
- }
+ 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;
@@ -7867,29 +7911,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;
@@ -7897,8 +7938,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;
@@ -7909,13 +7948,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;
@@ -7928,9 +7967,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;
}
@@ -7938,9 +7977,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;
}
@@ -7955,33 +7994,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;
@@ -8287,52 +8328,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)
+ auto bounds = m_spellImmune[op].equal_range(type);
+ for (auto itr = bounds.first; itr != bounds.second;)
{
- 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();)
- {
- 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;
}
@@ -8650,13 +8653,9 @@ 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;
-
// 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)))))
+ // skip visibility check for GO casts, needs removal when go cast is implemented
+ if (GetEntry() != WORLD_TRIGGER && (!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;
// can't attack dead
@@ -9724,63 +9723,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;
+ DiminishingReturn& diminish = m_Diminishing[group];
+ if (!diminish.hitCount)
+ return DIMINISHING_LEVEL_1;
- if (!i->hitTime)
- 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;
@@ -9789,7 +9778,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;
@@ -9802,12 +9791,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;
@@ -9825,24 +9814,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)
@@ -10900,7 +10891,7 @@ void Unit::GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTrigg
if (uint8 procEffectMask = aurApp->GetBase()->IsProcTriggeredOnEvent(aurApp, eventInfo, now))
{
aurApp->GetBase()->PrepareProcToTrigger(aurApp, eventInfo, now);
- aurasTriggeringProc.emplace_back(std::make_pair(procEffectMask, aurApp));
+ aurasTriggeringProc.emplace_back(procEffectMask, aurApp);
}
}
}
@@ -10912,7 +10903,7 @@ void Unit::GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTrigg
if (uint8 procEffectMask = itr->second->GetBase()->IsProcTriggeredOnEvent(itr->second, eventInfo, now))
{
itr->second->GetBase()->PrepareProcToTrigger(itr->second, eventInfo, now);
- aurasTriggeringProc.emplace_back(std::make_pair(procEffectMask, itr->second));
+ aurasTriggeringProc.emplace_back(procEffectMask, itr->second);
}
}
}
@@ -10932,6 +10923,21 @@ void Unit::TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uin
{
AuraApplicationProcContainer myAurasTriggeringProc;
GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, nullptr, myProcEventInfo);
+
+ // 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);
}
@@ -10947,6 +10953,11 @@ void Unit::TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uin
void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProcContainer& aurasTriggeringProc)
{
+ Spell const* triggeringSpell = eventInfo.GetProcSpell();
+ bool const disableProcs = triggeringSpell && triggeringSpell->IsProcDisabled();
+ if (disableProcs)
+ SetCantProc(true);
+
for (auto const& aurAppProc : aurasTriggeringProc)
{
AuraApplication* aurApp;
@@ -10965,6 +10976,9 @@ void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProc
if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
SetCantProc(false);
}
+
+ if (disableProcs)
+ SetCantProc(false);
}
SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const
@@ -12461,8 +12475,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
@@ -12480,8 +12495,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)
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 525d0d54ecb..f2135583c78 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -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_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,11 +802,15 @@ 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) { }
+
+ void Clear()
+ {
+ stack = 0;
+ hitTime = 0;
+ hitCount = DIMINISHING_LEVEL_1;
+ }
- DiminishingGroup DRGroup;
uint16 stack;
uint32 hitTime;
uint32 hitCount;
@@ -1255,9 +1260,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::deque<std::pair<uint8 /*procEffectMask*/, AuraApplication*>> AuraApplicationProcContainer;
+ typedef std::vector<std::pair<uint8 /*procEffectMask*/, AuraApplication*>> AuraApplicationProcContainer;
typedef std::map<uint8, AuraApplication*> VisibleAuraMap;
@@ -1272,11 +1277,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;
@@ -1428,7 +1433,7 @@ 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); }
@@ -1447,6 +1452,7 @@ class TC_GAME_API Unit : public WorldObject
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);
@@ -1556,17 +1562,18 @@ class TC_GAME_API Unit : public WorldObject
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);
@@ -1930,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
@@ -2015,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;
@@ -2027,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(HealInfo& healInfo);
+ void CalcAbsorbResist(DamageInfo& damageInfo);
+ void CalcHealAbsorb(HealInfo& healInfo) const;
void UpdateSpeed(UnitMoveType mtype);
float GetSpeed(UnitMoveType mtype) const;
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/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h
index 317378dfa8b..263ba355865 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.h
@@ -642,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)
@@ -657,6 +658,7 @@ namespace Trinity
return go->IsWithinDistInMap(i_unit, dist);
}
+
private:
Unit const* i_unit;
uint32 i_focusId;
@@ -667,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))
@@ -676,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))
@@ -698,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)
@@ -712,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))
@@ -721,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
@@ -761,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)
@@ -770,6 +777,7 @@ namespace Trinity
}
return false;
}
+
private:
Unit const* i_obj;
float i_range;
@@ -780,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)))
@@ -789,6 +798,7 @@ namespace Trinity
}
return false;
}
+
private:
Unit const* i_obj;
float i_range;
@@ -798,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;
@@ -817,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 NearestUnfriendlyNoTotemUnitInObjectRangeCheck
{
public:
- AnyUnfriendlyNoTotemUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) { }
+ NearestUnfriendlyNoTotemUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) { }
+
bool operator()(Unit* u)
{
if (!u->IsAlive())
@@ -848,8 +861,13 @@ namespace Trinity
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->IsFriendlyTo(u))
+ return false;
+
+ i_range = i_obj->GetDistance(*u);
+ return true;
}
+
private:
WorldObject const* i_obj;
Unit const* i_funit;
@@ -860,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;
@@ -877,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)
@@ -899,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;
@@ -922,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) &&
@@ -933,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;
@@ -980,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;
@@ -1007,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))
@@ -1043,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))
@@ -1077,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;
@@ -1108,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;
@@ -1139,6 +1153,7 @@ namespace Trinity
return true;
}
+
private:
Unit* const i_funit;
Unit* const i_enemy;
@@ -1167,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)
@@ -1193,7 +1208,7 @@ namespace Trinity
}
return false;
}
- float GetLastRange() const { return i_range; }
+
private:
WorldObject const& i_obj;
uint32 i_entry;
@@ -1201,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;
@@ -1228,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)
{
@@ -1246,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;
@@ -1294,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;
}
@@ -1364,7 +1389,8 @@ namespace Trinity
{
public:
ObjectGUIDCheck(ObjectGuid GUID) : _GUID(GUID) { }
- bool operator()(WorldObject* object)
+
+ bool operator()(WorldObject* object) const
{
return object->GetGUID() == _GUID;
}
@@ -1377,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;
@@ -1407,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/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/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/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/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 da50b818341..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,24 +380,20 @@ 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
if (!(pProto->FlagsCu & ITEM_FLAGS_CU_IGNORE_QUEST_STATUS) && ((needs_quest || (pProto->StartQuest && player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE)) && !player->HasQuestForItem(itemid)))
return false;
- // Don't show bind-when-picked-up unique items if player already has the maximum allowed quantity.
- if (pProto->Bonding == BIND_WHEN_PICKED_UP && pProto->MaxCount && int32(player->GetItemCount(itemid, true)) >= pProto->MaxCount)
- return false;
-
return true;
}
@@ -433,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;
}
}
@@ -487,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);
@@ -521,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;
}
}
@@ -544,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)
{
@@ -557,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
@@ -582,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;
@@ -661,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)
@@ -721,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];
@@ -744,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;
@@ -760,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;
@@ -786,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);
}
@@ -806,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)
@@ -819,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)
@@ -832,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)
@@ -980,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)
@@ -1021,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)
@@ -1039,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;
}
}
@@ -1657,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
@@ -1682,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())
@@ -1745,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 bca5cde1fa5..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;
@@ -308,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;
@@ -340,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();
@@ -377,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;
@@ -385,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/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index f7c440ce8bc..bc84e3fde29 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)
@@ -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.]
@@ -3136,7 +3137,9 @@ enum DiminishingGroup : uint16
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 2737c852d98..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)
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 997c2904e9e..8631c94c98a 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -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
@@ -890,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
@@ -976,15 +974,12 @@ bool AuraEffect::CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventIn
return false;
// Spell own damage at apply won't break CC
- if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
+ if (spellInfo && spellInfo == GetSpellInfo())
{
- if (spellInfo == GetSpellInfo())
- {
- Aura* aura = GetBase();
- // called from spellcast, should not have ticked yet
- if (aura->GetDuration() == aura->GetMaxDuration())
- return false;
- }
+ Aura* aura = GetBase();
+ // called from spellcast, should not have ticked yet
+ if (aura->GetDuration() == aura->GetMaxDuration())
+ return false;
}
break;
}
@@ -1779,7 +1774,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());
@@ -1851,11 +1851,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();
@@ -3069,249 +3068,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
@@ -3320,52 +3083,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
@@ -3374,8 +3092,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();
@@ -3397,11 +3114,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
@@ -3410,8 +3123,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)
{
@@ -3421,12 +3133,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);
}
@@ -3439,23 +3154,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 schoolMask = GetMiscValue();
- target->RemoveAppliedAuras([this, schoolMask](AuraApplication const* aurApp)
- {
- SpellInfo const* spell = aurApp->GetBase()->GetSpellInfo();
- return (spell->GetSchoolMask() & schoolMask) // Check for school mask
- && GetSpellInfo()->CanDispelAura(spell)
- && !aurApp->IsPositive() // Don't remove positive spells
- && !spell->IsPassive() // Don't remove passive auras
- && spell->Id != GetId(); // Don't remove self
- });
- }
}
void AuraEffect::HandleAuraModDmgImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -3464,8 +3162,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
@@ -3474,8 +3171,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);
}
/*********************************************************/
@@ -5446,13 +5142,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;
@@ -5849,8 +5543,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.
@@ -5945,13 +5637,16 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target);
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);
@@ -5960,10 +5655,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 hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
- 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)
@@ -5972,7 +5669,6 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
SpellPeriodicAuraLogInfo pInfo(this, damage, overkill, absorb, resist, 0.0f, crit);
target->SendPeriodicAuraLog(&pInfo);
- DamageInfo damageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK);
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);
@@ -5993,8 +5689,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);
@@ -6037,29 +5731,33 @@ 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 hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
- 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())
- {
- DamageInfo damageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK);
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())
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h
index 2bfdde97b4b..05bfe7c0534 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.h
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.h
@@ -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;
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 2a6545520ae..39797269c2b 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -360,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;
@@ -381,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
@@ -490,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
@@ -530,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
@@ -584,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
@@ -602,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));
@@ -988,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;
}
@@ -1592,6 +1593,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);
}
@@ -1602,7 +1606,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;
}
@@ -1893,8 +1902,16 @@ uint8 Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& event
if (!sSpellMgr->CanSpellTriggerProcOnEvent(*procEntry, eventInfo))
return 0;
- // check if aura can proc when spell is triggered
- if (!(procEntry->AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC))
+ // 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 aura can proc when spell is triggered (exception for hunter auto shot & wands)
+ if (!(procEntry->AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC) && !(eventInfo.GetTypeMask() & AUTO_ATTACK_PROC_FLAG_MASK))
if (Spell const* spell = eventInfo.GetProcSpell())
if (spell->IsTriggered())
if (!GetSpellInfo()->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED))
@@ -2025,30 +2042,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);
@@ -2059,10 +2067,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);
@@ -2072,10 +2080,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);
@@ -2086,10 +2094,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);
@@ -2106,10 +2114,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);
@@ -2124,10 +2132,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);
@@ -2138,10 +2146,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);
@@ -2153,10 +2161,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);
@@ -2172,10 +2180,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);
@@ -2186,10 +2194,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);
@@ -2200,10 +2208,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);
@@ -2214,10 +2222,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);
@@ -2228,10 +2236,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()))
@@ -2246,10 +2254,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);
@@ -2260,10 +2268,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);
@@ -2274,10 +2282,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);
@@ -2288,10 +2296,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);
@@ -2303,10 +2311,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);
@@ -2319,10 +2327,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);
@@ -2338,10 +2346,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);
@@ -2354,10 +2362,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);
@@ -2368,10 +2376,10 @@ void Aura::CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventI
bool Aura::CallScriptCheckEffectProcHandlers(AuraEffect const* aurEff, 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_EFFECT_PROC, aurApp);
- std::list<AuraScript::CheckEffectProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckEffectProc.end(), hookItr = (*scritr)->DoCheckEffectProc.begin();
+ 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);
@@ -2385,10 +2393,10 @@ bool Aura::CallScriptCheckEffectProcHandlers(AuraEffect const* aurEff, AuraAppli
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);
@@ -2403,10 +2411,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);
@@ -2449,18 +2457,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);
@@ -2472,48 +2479,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;
}
}
}
@@ -2536,7 +2543,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();
@@ -2545,28 +2552,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 a526dd8e340..450a8c4dde2 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -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);}
@@ -238,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;
@@ -283,7 +285,7 @@ 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; }
@@ -301,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 f072d71d9ff..a35f36f5e81 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -586,8 +586,6 @@ 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;
@@ -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);
@@ -1994,11 +2003,17 @@ void Spell::prepareDataForTriggerSystem()
// 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;
+ // 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)
{
@@ -2052,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
@@ -2354,7 +2369,19 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
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)
{
@@ -2517,15 +2544,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;
+ }
}
}
}
@@ -2556,12 +2580,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
@@ -2591,16 +2610,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)
@@ -2643,8 +2665,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)
@@ -2659,7 +2680,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()))
@@ -2936,7 +2957,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
@@ -2957,7 +2979,10 @@ 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;
@@ -2982,7 +3007,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());
@@ -2995,8 +3020,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);
@@ -3144,10 +3169,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)
@@ -3460,9 +3486,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();
@@ -3554,7 +3577,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
@@ -3576,7 +3599,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;
@@ -3589,8 +3612,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)
@@ -3692,7 +3719,7 @@ void Spell::finish(bool ok)
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);
@@ -3700,115 +3727,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;
@@ -3816,13 +3913,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)
@@ -4471,7 +4568,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;
@@ -4496,7 +4593,7 @@ SpellCastResult Spell::CheckRuneCost(uint32 runeCostID)
{
runeCost[i] = src->RuneCost[i];
if (Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod<SPELLMOD_COST>(m_spellInfo->Id, runeCost[i], this);
+ modOwner->ApplySpellMod<SPELLMOD_COST>(m_spellInfo->Id, runeCost[i], const_cast<Spell*>(this));
}
runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later
@@ -4616,7 +4713,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();
@@ -4695,7 +4792,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
@@ -4706,7 +4803,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)
@@ -4732,7 +4829,7 @@ 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->IsPassive() && !(m_spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD) || (IsTriggered() && !m_triggeredByAuraSpell)))
@@ -4795,13 +4892,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
@@ -4897,14 +4996,18 @@ SpellCastResult Spell::CheckCast(bool strict)
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;
@@ -5005,7 +5108,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;
}
@@ -5025,7 +5128,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURAS))
{
- castResult = CheckCasterAuras();
+ castResult = CheckCasterAuras(param1);
if (castResult != SPELL_CAST_OK)
return castResult;
}
@@ -5039,6 +5142,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))
@@ -5054,6 +5158,7 @@ SpellCastResult Spell::CheckCast(bool strict)
hasNonDispelEffect = true;
break;
}
+ }
if (!hasNonDispelEffect && !hasDispellableAura && dispelMask && !IsTriggered())
{
@@ -5168,7 +5273,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())
@@ -5637,139 +5742,110 @@ 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 allowed stun auras, another stun types must prevent cast spell
- if (usableInStun)
- {
- static uint32 const allowedStunMask =
- 1 << MECHANIC_STUN
- | 1 << MECHANIC_FREEZE
- | 1 << MECHANIC_SAPPED
- | 1 << MECHANIC_SLEEP;
-
- 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)
- {
- uint32 mechanicMask = (*i)->GetSpellInfo()->GetAllEffectsMechanicMask();
- if (mechanicMask && !(mechanicMask & allowedStunMask))
- {
- foundNotStun = true;
- break;
- }
- }
- if (foundNotStun)
- 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() && !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)
@@ -5828,7 +5904,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)
@@ -5858,20 +5934,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);
@@ -5913,14 +5989,14 @@ std::pair<float, float> Spell::GetMinMaxRange(bool strict)
maxRange *= ranged->GetTemplate()->RangedModRange * 0.01f;
if (Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod<SPELLMOD_RANGE>(m_spellInfo->Id, 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)
@@ -5956,12 +6032,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)
@@ -6037,10 +6116,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
@@ -6052,7 +6132,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
@@ -6090,7 +6170,11 @@ SpellCastResult Spell::CheckItems()
}
}
if (!player->HasItemCount(itemid, itemcount))
+ {
+ if (param1)
+ *param1 = itemid;
return SPELL_FAILED_REAGENTS;
+ }
}
}
@@ -6174,7 +6258,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);
@@ -6294,21 +6378,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;
@@ -6317,21 +6409,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;
@@ -6603,14 +6703,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
@@ -6689,11 +6789,6 @@ 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?
@@ -7071,7 +7166,7 @@ void Spell::SetSpellValue(SpellValueMod mod, int32 value)
void Spell::PrepareTargetProcessing()
{
- CheckEffectExecuteData();
+ AssertEffectExecuteData();
}
void Spell::FinishTargetProcessing()
@@ -7096,7 +7191,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]);
@@ -7104,29 +7199,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);
@@ -7136,10 +7222,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);
@@ -7149,10 +7235,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);
@@ -7163,10 +7249,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);
@@ -7181,7 +7267,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();
}
@@ -7189,9 +7275,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)
{
@@ -7235,10 +7321,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);
@@ -7248,10 +7334,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);
@@ -7261,10 +7347,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);
@@ -7274,10 +7360,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);
@@ -7287,10 +7373,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);
@@ -7301,10 +7387,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);
@@ -7315,10 +7401,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);
@@ -7333,15 +7419,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)))
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 5823ea72dbd..881e95fc9a4 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -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,9 +481,9 @@ 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;
@@ -507,7 +515,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 +569,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;
@@ -640,7 +644,7 @@ class TC_GAME_API Spell
// spell execution log
void InitEffectExecuteData(uint8 effIndex);
- void CheckEffectExecuteData();
+ void AssertEffectExecuteData() const;
// Scripting system
void LoadScripts();
@@ -658,7 +662,7 @@ 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
{
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 1b570e7778c..c570d5fcf21 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)
@@ -2023,7 +2027,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)
@@ -2686,7 +2690,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;
@@ -3531,21 +3535,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);
+ linkedTrap->SetRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0);
+ linkedTrap->SetSpellId(m_spellInfo->Id);
- ExecuteLogEffectSummonObject(effIndex, linkedGO);
-
- // Wild object not have owner and check clickable by players
- map->AddToMap(linkedGO);
- }
- else
- delete linkedGO;
+ ExecuteLogEffectSummonObject(effIndex, linkedTrap);
}
}
@@ -4579,8 +4574,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)) // Check if the quest has already been turned in.
- player->SetRewardedQuest(questId); // If not, set status to rewarded without broadcasting it to client.
+ 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.
}
}
@@ -4757,7 +4752,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)
@@ -5137,26 +5132,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);
}
}
@@ -5169,7 +5152,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)
@@ -5194,7 +5177,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)
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 1e3eeee676a..a7b86d2d433 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"
@@ -1181,12 +1182,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
@@ -1210,6 +1221,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);
@@ -1221,42 +1246,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->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;
@@ -1411,9 +1435,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;
}
@@ -1982,9 +2008,27 @@ void SpellInfo::_LoadSpellSpecific()
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;
@@ -2108,6 +2152,770 @@ void SpellInfo::_LoadSpellSpecific()
}();
}
+void SpellInfo::_LoadSpellDiminishInfo()
+{
+ auto diminishingGroupCompute = [this](bool triggered) -> DiminishingGroup
+ {
+ if (IsPositive())
+ return DIMINISHING_NONE;
+
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (Effects[i].ApplyAuraName == SPELL_AURA_MOD_TAUNT)
+ return DIMINISHING_TAUNT;
+ }
+
+ // Explicit Diminishing Groups
+ switch (SpellFamilyName)
+ {
+ 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;
+ }
+
+ // 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;
+ }
+ };
+
+ auto diminishingMaxLevelCompute = [](DiminishingGroup group) -> DiminishingLevels
+ {
+ switch (group)
+ {
+ case DIMINISHING_TAUNT:
+ return DIMINISHING_LEVEL_TAUNT_IMMUNE;
+ default:
+ return DIMINISHING_LEVEL_IMMUNE;
+ }
+ };
+
+ auto diminishingLimitDurationCompute = [this](DiminishingGroup group) -> int32
+ {
+ auto isGroupDurationLimited = [group]() -> bool
+ {
+ 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;
+ }
+ };
+
+ 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;
+ }
+
+ 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)
+ {
+ 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;
+
+ 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;
+
+ 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;
+ }
+
+ 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();
+ }
+}
+
+void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, uint8 effIndex, bool apply) const
+{
+ ImmunityInfo const* immuneInfo = _immunityInfo + effIndex;
+
+ if (uint32 schoolImmunity = immuneInfo->SchoolImmuneMask)
+ {
+ target->ApplySpellImmune(Id, IMMUNITY_SCHOOL, schoolImmunity, apply);
+
+ 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
+ });
+ }
+ }
+
+ 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))
+ {
+ target->RemoveAppliedAuras([dispelImmunity](AuraApplication const* aurApp) -> bool
+ {
+ SpellInfo const* spellInfo = aurApp->GetBase()->GetSpellInfo();
+ if (spellInfo->Dispel == dispelImmunity)
+ return true;
+
+ return false;
+ });
+ }
+ }
+
+ 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)
+ {
+ ImmunityInfo const* immuneInfo = _immunityInfo + i;
+
+ if (!auraSpellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
+ {
+ 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())
+ {
+ 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 false;
+}
+
float SpellInfo::GetMinRange(bool positive) const
{
if (!RangeEntry)
@@ -2455,6 +3263,9 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const
// Impact
if (SpellIconID == 45)
return true;
+ // Arcane Missiles
+ if (SpellFamilyFlags[0] == 0x00000800)
+ return false;
break;
case SPELLFAMILY_PRIEST:
switch (Id)
@@ -2484,6 +3295,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;
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 2f94555e493..4b2eff28bd6 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,207 +294,251 @@ private:
static StaticData _data[TOTAL_SPELL_EFFECTS];
};
-class TC_GAME_API SpellInfo
+struct TC_GAME_API SpellDiminishInfo
{
-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);
- void _LoadSpellSpecific();
- void _LoadAuraState();
-
- // unloading helpers
- void _UnloadImplicitTargetConditionLists();
+ DiminishingGroup DiminishGroup = DIMINISHING_NONE;
+ DiminishingReturnsType DiminishReturnType = DRTYPE_NONE;
+ DiminishingLevels DiminishMaxLevel = DIMINISHING_LEVEL_IMMUNE;
+ int32 DiminishDurationLimit = 0;
+};
-private:
- SpellSpecificType _spellSpecific;
- AuraStateType _auraState;
+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
+{
+ 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;
+
+ 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 94d34d78bd6..d034c744cc1 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -51,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()
@@ -811,7 +515,8 @@ bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcE
return true;
// do triggered cast checks
- if (!(procEntry.AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC))
+ // 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())
{
@@ -830,20 +535,13 @@ bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcE
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;
}
@@ -1707,71 +1405,6 @@ void SpellMgr::LoadSpellGroupStackRules()
TC_LOG_INFO("server.loading", ">> Loaded %u spell group stack rules in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
-// Used for prepare can/can't triggr aura
-static bool InitTriggerAuraData();
-// Define can trigger auras
-static bool isTriggerAura[TOTAL_AURAS];
-// Triggered always, even from triggered spells
-static bool isAlwaysTriggeredAura[TOTAL_AURAS];
-// Prepare lists
-static bool procPrepared = InitTriggerAuraData();
-
-// 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;
- isAlwaysTriggeredAura[i] = false;
- }
- isTriggerAura[SPELL_AURA_DUMMY] = true; // Most dummy auras should require scripting. Remove?
- 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_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;
-}
-
void SpellMgr::LoadSpellProcs()
{
uint32 oldMSTime = getMSTime();
@@ -1900,6 +1533,73 @@ void SpellMgr::LoadSpellProcs()
TC_LOG_INFO("server.loading", ">> Loaded %u spell proc conditions and data in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ // 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;
@@ -1910,10 +1610,16 @@ void SpellMgr::LoadSpellProcs()
if (!spellInfo)
continue;
+ // Data already present in DB, overwrites default proc
if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
continue;
- bool found = false, addTriggerFlag = false;
+ // Nothing to do if no flags set
+ if (!spellInfo->ProcFlags)
+ continue;
+
+ bool addTriggerFlag = false;
+ uint32 procSpellTypeMask = PROC_SPELL_TYPE_NONE;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (!spellInfo->Effects[i].IsEffect())
@@ -1926,28 +1632,42 @@ void SpellMgr::LoadSpellProcs()
if (!isTriggerAura[auraName])
continue;
- found = true;
-
- if (!addTriggerFlag && isAlwaysTriggeredAura[auraName])
+ procSpellTypeMask |= spellTypeMask[auraName];
+ if (isAlwaysTriggeredAura[auraName])
addTriggerFlag = true;
+
+ // 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)
+ {
+ switch (auraName)
+ {
+ case SPELL_AURA_PROC_TRIGGER_SPELL:
+ case SPELL_AURA_PROC_TRIGGER_DAMAGE:
+ addTriggerFlag = true;
+ break;
+ default:
+ break;
+ }
+ }
break;
}
- if (!found)
- continue;
-
- if (!spellInfo->ProcFlags)
+ if (!procSpellTypeMask)
continue;
SpellProcEntry procEntry;
procEntry.SchoolMask = 0;
- procEntry.SpellFamilyName = spellInfo->SpellFamilyName;
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;
- procEntry.SpellTypeMask = PROC_SPELL_TYPE_MASK_ALL;
+ if (procEntry.SpellFamilyMask)
+ procEntry.SpellFamilyName = spellInfo->SpellFamilyName;
+
+ procEntry.SpellTypeMask = procSpellTypeMask;
procEntry.SpellPhaseMask = PROC_SPELL_PHASE_HIT;
procEntry.HitMask = PROC_HIT_NONE; // uses default proc @see SpellMgr::CanSpellTriggerProcOnEvent
@@ -2895,6 +2615,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;
@@ -2922,6 +2644,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:
@@ -3004,6 +2735,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;
@@ -3041,15 +2778,14 @@ void SpellMgr::LoadSpellInfoCorrections()
case 44544: // Fingers of Frost
spellInfo->Effects[EFFECT_0].SpellClassMask = flag96(685904631, 1151048, 0);
break;
- case 53257: // Cobra Strikes
- spellInfo->ProcCharges = 2;
- spellInfo->StackAmount = 0;
- 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;
@@ -3129,6 +2865,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
@@ -3236,9 +2985,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
@@ -3277,8 +3023,23 @@ void SpellMgr::LoadSpellInfoCorrections()
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)
@@ -3748,3 +3509,33 @@ void SpellMgr::LoadSpellInfoSpellSpecificAndAuraState()
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 52ea6f25d1f..1304ac8cacd 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
@@ -546,13 +547,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
@@ -685,6 +679,8 @@ class TC_GAME_API SpellMgr
void LoadSpellInfoCustomAttributes();
void LoadSpellInfoCorrections();
void LoadSpellInfoSpellSpecificAndAuraState();
+ void LoadSpellInfoDiminishing();
+ void LoadSpellInfoImmunities();
private:
SpellDifficultySearcherMap mSpellDifficultySearcherMap;
diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp
index 67aaa582776..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,99 +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<CheckEffectProcHandler>::iterator itr = DoCheckEffectProc.begin(); itr != DoCheckEffectProc.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 (std::list<AuraProcHandler>::iterator itr = DoPrepareProc.begin(); itr != DoPrepareProc.end(); ++itr)
+ 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());
diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h
index 1ec10f03820..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);
};
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 443d0c63efa..7bbf73d028d 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1449,8 +1449,11 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading SpellInfo custom attributes...");
sSpellMgr->LoadSpellInfoCustomAttributes();
- TC_LOG_INFO("server.loading", "Loading SpellInfo SpellSpecific and AuraState...");
- sSpellMgr->LoadSpellInfoSpellSpecificAndAuraState();
+ 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);
@@ -1511,6 +1514,9 @@ 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();
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_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 16217fbaea6..1e4daaea2d2 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;
}
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/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_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 685d0f51edd..2eda9509bb8 100644
--- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h
+++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h
@@ -33,7 +33,8 @@ enum DataTypes
DATA_WATCHER_NARJIL,
DATA_WATCHER_GASHRA,
DATA_WATCHER_SILTHIK,
- DATA_ANUBARAK_WALL
+ DATA_ANUBARAK_WALL,
+ DATA_ANUBARAK_WALL_2
};
enum CreatureIds
diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp
index 06a91d58705..2860698a8b2 100644
--- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp
@@ -121,12 +121,16 @@ public:
_petCount = 0;
}
+ bool CanAIAttack(Unit const* /*who*/) const override { return true; } // do not check boundary here
+
void EnterCombat(Unit* who) override
{
BossAI::EnterCombat(who);
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);
Talk(SAY_AGGRO);
instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_GOTTA_GO_START_EVENT);
@@ -179,6 +183,8 @@ public:
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);
diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp
index 7338774c21e..c41ec1c488d 100644
--- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp
@@ -789,7 +789,7 @@ struct npc_hadronox_foeAI : public ScriptedAI
me->GetMotionMaster()->MovePoint(MOVE_HADRONOX, hadronoxStep[2]);
break;
}
- me->GetMotionMaster()->MoveChase(hadronox);
+ AttackStart(hadronox);
}
break;
}
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 ea912da4c3d..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
@@ -138,10 +138,10 @@ class boss_krik_thir : public CreatureScript
for (uint8 i = 1; i <= 3; ++i)
{
- std::list<TempSummon*> summons;
- me->SummonCreatureGroup(i, &summons);
- for (TempSummon* summon : summons)
- summon->AI()->SetData(DATA_PET_GROUP, i);
+ std::list<TempSummon*> adds;
+ me->SummonCreatureGroup(i, &adds);
+ for (TempSummon* add : adds)
+ add->AI()->SetData(DATA_PET_GROUP, i);
}
}
@@ -416,10 +416,7 @@ class npc_watcher_gashra : public CreatureScript
struct npc_watcher_gashraAI : public npc_gatewatcher_petAI
{
- npc_watcher_gashraAI(Creature* creature) : npc_gatewatcher_petAI(creature, true)
- {
- me->SetReactState(REACT_PASSIVE);
- }
+ npc_watcher_gashraAI(Creature* creature) : npc_gatewatcher_petAI(creature, true) { }
void Reset() override
{
@@ -928,11 +925,15 @@ class spell_gatewatcher_subboss_trigger : public SpellScriptLoader
void HandleTargets(std::list<WorldObject*>& targetList)
{
// Remove any Watchers that are already in combat
- for (std::list<WorldObject*>::iterator it = targetList.begin(); it != targetList.end(); ++it)
+ auto it = targetList.begin();
+ while (it != targetList.end())
{
if (Creature* creature = (*it)->ToCreature())
if (creature->IsAlive() && !creature->IsInCombat())
+ {
+ ++it;
continue;
+ }
it = targetList.erase(it);
}
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 8af4f6cecc4..7f0ce5c369e 100644
--- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp
@@ -41,7 +41,8 @@ ObjectData const creatureData[] =
ObjectData const gameobjectData[] =
{
- { GO_ANUBARAK_DOOR_3, DATA_ANUBARAK_WALL },
+ { GO_ANUBARAK_DOOR_1, DATA_ANUBARAK_WALL },
+ { GO_ANUBARAK_DOOR_3, DATA_ANUBARAK_WALL_2 },
{ 0, 0 } // END
};
@@ -77,6 +78,17 @@ class instance_azjol_nerub : public InstanceMapScript
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;
+ }
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
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 1041d250cc7..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,30 +259,28 @@ 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;
}
}
@@ -292,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:
@@ -299,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);
}
@@ -360,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))
@@ -416,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
@@ -1145,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:
@@ -1293,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/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/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_wintergrasp.cpp b/src/server/scripts/Northrend/zone_wintergrasp.cpp
index a85d97d4c1d..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
{
@@ -474,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;
- return false;
- }
+ if (Vehicle* vehicle = source->GetVehicle())
+ if (vehicle->GetVehicleInfo()->m_ID == 244) // Wintergrasp Tower Cannon
+ return true;
+ }
+
+ return false;
+ }
};
enum WgTeleport
@@ -503,91 +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*/)
{
- WorldLocation loc = target->GetWorldLocation();
- SetExplTargetDest(loc);
+ if (Unit* target = GetHitUnit())
+ {
+ WorldLocation loc = target->GetWorldLocation();
+ SetExplTargetDest(loc);
+ }
}
- }
- void Register() override
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_wintergrasp_defender_teleport_trigger_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
{
- OnEffectHitTarget += SpellEffectFn(spell_wintergrasp_defender_teleport_trigger_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ return new spell_wintergrasp_defender_teleport_trigger_SpellScript();
}
- };
-
- 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") { }
+ public:
+ condition_is_wintergrasp_horde() : ConditionScript("condition_is_wintergrasp_horde") { }
- bool OnConditionCheck(Condition const* /* condition */, ConditionSourceInfo& /* sourceInfo */)
- {
- Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG);
- if (wintergrasp->IsEnabled() && wintergrasp->GetDefenderTeam() == TEAM_HORDE)
- return true;
- return false;
- }
+ bool OnConditionCheck(Condition const* /* condition */, ConditionSourceInfo& /* sourceInfo */)
+ {
+ 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") { }
+ public:
+ condition_is_wintergrasp_alliance() : ConditionScript("condition_is_wintergrasp_alliance") { }
- bool OnConditionCheck(Condition const* /* condition */, ConditionSourceInfo& /* sourceInfo */)
- {
- Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG);
- if (wintergrasp->IsEnabled() && wintergrasp->GetDefenderTeam() == TEAM_ALLIANCE)
- return true;
- return false;
- }
+ 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()
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/zone_hellfire_peninsula.cpp b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp
index 90bf8bb1948..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;
};
@@ -892,6 +923,122 @@ public:
}
};
+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_magister_aledis : public CreatureScript
+{
+public:
+ npc_magister_aledis() : CreatureScript("npc_magister_aledis") { }
+
+ bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 /*action*/) override
+ {
+ CloseGossipMenuFor(player);
+ creature->StopMoving();
+ ENSURE_AI(npc_magister_aledis::npc_magister_aledisAI, creature->AI())->StartFight(player);
+ return true;
+ }
+
+ struct npc_magister_aledisAI : public ScriptedAI
+ {
+ npc_magister_aledisAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void StartFight(Player* player)
+ {
+ 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
+ {
+ 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 DamageTaken(Unit* /*attacker*/, uint32 &damage) override
+ {
+ if (damage > me->GetHealth() || me->HealthBelowPctDamaged(20, damage))
+ {
+ damage = 0;
+
+ _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);
+
+ _events.ScheduleEvent(EVENT_EVADE, Minutes(1));
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ 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;
+ }
+ }
+
+ if (!UpdateVictim())
+ return;
+
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ EventMap _events;
+ ObjectGuid _playerGUID;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_magister_aledisAI(creature);
+ }
+};
+
void AddSC_hellfire_peninsula()
{
new npc_aeranas();
@@ -900,4 +1047,5 @@ void AddSC_hellfire_peninsula()
new npc_fel_guard_hound();
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 5b4b26e599e..a155dbc36c4 100644
--- a/src/server/scripts/Pet/pet_hunter.cpp
+++ b/src/server/scripts/Pet/pet_hunter.cpp
@@ -215,7 +215,7 @@ class spell_pet_guard_dog : public SpellScriptLoader
Unit* caster = eventInfo.GetActor();
caster->CastSpell((Unit*)nullptr, SPELL_PET_GUARD_DOG_HAPPINESS, true);
- float addThreat = CalculatePct(eventInfo.GetSpellInfo()->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount());
+ float addThreat = CalculatePct(ASSERT_NOTNULL(eventInfo.GetSpellInfo())->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount());
eventInfo.GetProcTarget()->AddThreat(caster, addThreat);
}
diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp
index a1543e1199c..7cce7e4655e 100644
--- a/src/server/scripts/Spells/spell_dk.cpp
+++ b/src/server/scripts/Spells/spell_dk.cpp
@@ -2801,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
@@ -2833,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)
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index 794ef470d40..f1eaf45770e 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -1100,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);
}
};
diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp
index e95bfe4395c..e18dc838965 100644
--- a/src/server/scripts/Spells/spell_hunter.cpp
+++ b/src/server/scripts/Spells/spell_hunter.cpp
@@ -275,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
{
@@ -388,7 +452,7 @@ class spell_hun_glyph_of_mend_pet : public SpellScriptLoader
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS, true);
+ eventInfo.GetProcTarget()->CastSpell((Unit*)nullptr, SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS, true);
}
void Register() override
@@ -664,35 +728,6 @@ class spell_hun_lock_and_load : public SpellScriptLoader
}
};
-// 56342 - Lock and Load (Rank 1)
-class spell_hun_lock_and_load_dummy : public SpellScriptLoader
-{
- public:
- spell_hun_lock_and_load_dummy() : SpellScriptLoader("spell_hun_lock_and_load_dummy") { }
-
- class spell_hun_lock_and_load_dummy_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_hun_lock_and_load_dummy_AuraScript);
-
- bool DummyCheck(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
- {
- // Prevents Aura proc from this dummy effect
- // Only rank 1 has this aura
- return false;
- }
-
- void Register() override
- {
- DoCheckEffectProc += AuraCheckEffectProcFn(spell_hun_lock_and_load_dummy_AuraScript::DummyCheck, EFFECT_2, SPELL_AURA_DUMMY);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_hun_lock_and_load_dummy_AuraScript();
- }
-};
-
// 53271 - Masters Call
class spell_hun_masters_call : public SpellScriptLoader
{
@@ -710,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);
}
@@ -1505,6 +1568,8 @@ 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();
@@ -1514,7 +1579,6 @@ void AddSC_hunter_spell_scripts()
new spell_hun_kill_command_pet();
new spell_hun_last_stand_pet();
new spell_hun_lock_and_load();
- new spell_hun_lock_and_load_dummy();
new spell_hun_masters_call();
new spell_hun_misdirection();
new spell_hun_misdirection_proc();
diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp
index f51b9e8e965..b45df66e0ac 100644
--- a/src/server/scripts/Spells/spell_item.cpp
+++ b/src/server/scripts/Spells/spell_item.cpp
@@ -1961,6 +1961,8 @@ class spell_item_shadows_fate : public SpellScriptLoader
void HandleProc(ProcEventInfo& procInfo)
{
+ PreventDefaultAction();
+
Unit* caster = procInfo.GetActor();
Unit* target = GetCaster();
if (!caster || !target)
@@ -4343,6 +4345,119 @@ 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,
@@ -4515,6 +4630,8 @@ 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_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp
index 30dfd2cd5d0..2aaa2e29d9c 100644
--- a/src/server/scripts/Spells/spell_paladin.cpp
+++ b/src/server/scripts/Spells/spell_paladin.cpp
@@ -1303,6 +1303,8 @@ class spell_pal_infusion_of_light : public SpellScriptLoader
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
@@ -1540,7 +1542,7 @@ class spell_pal_judgement_of_light_heal : public SpellScriptLoader
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);
+ caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff, GetCasterGUID());
}
void Register() override
@@ -1584,7 +1586,7 @@ class spell_pal_judgement_of_wisdom_mana : public SpellScriptLoader
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);
+ caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff, GetCasterGUID());
}
void Register() override
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_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp
index cff94b6e219..397427b505f 100644
--- a/src/server/scripts/Spells/spell_shaman.cpp
+++ b/src/server/scripts/Spells/spell_shaman.cpp
@@ -83,7 +83,8 @@ enum ShamanSpells
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_T10_ENHANCEMENT_4P_BONUS = 70832,
+ SPELL_SHAMAN_BLESSING_OF_THE_ETERNALS_R1 = 51554
};
enum ShamanSpellIcons
@@ -537,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
{
@@ -1222,19 +1263,12 @@ class spell_sha_item_mana_surge : public SpellScriptLoader
return true;
}
- bool CheckProc(ProcEventInfo& eventInfo)
- {
- DamageInfo* damageInfo = eventInfo.GetDamageInfo();
- if (!damageInfo || !damageInfo->GetSpellInfo())
- return false;
-
- return true;
- }
-
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ if (!spellInfo)
+ return;
int32 mana = spellInfo->CalcPowerCost(GetTarget(), eventInfo.GetSchoolMask());
int32 damage = CalculatePct(mana, 35);
@@ -1244,7 +1278,6 @@ class spell_sha_item_mana_surge : public SpellScriptLoader
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);
}
};
@@ -2276,6 +2309,7 @@ void AddSC_shaman_spell_scripts()
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();
diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp
index 492da48c455..cccebab6259 100644
--- a/src/server/scripts/Spells/spell_warlock.cpp
+++ b/src/server/scripts/Spells/spell_warlock.cpp
@@ -74,6 +74,7 @@ enum WarlockSpells
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
};
@@ -449,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
{
@@ -509,7 +554,7 @@ class spell_warl_fel_synergy : public SpellScriptLoader
if (!damageInfo || !damageInfo->GetDamage())
return false;
- return GetTarget()->GetGuardianPet();
+ return GetTarget()->GetGuardianPet() != nullptr;
}
void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
@@ -744,44 +789,6 @@ class spell_warl_health_funnel : public SpellScriptLoader
}
};
-// -18213 - Improved Drain Soul
-class spell_warl_improved_drain_soul : public SpellScriptLoader
-{
- public:
- spell_warl_improved_drain_soul() : SpellScriptLoader("spell_warl_improved_drain_soul") { }
-
- class spell_warl_improved_drain_soul_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_warl_improved_drain_soul_AuraScript);
-
- bool Validate(SpellInfo const* /*spellInfo*/) override
- {
- if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC))
- return false;
- return true;
- }
-
- void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
- {
- PreventDefaultAction();
-
- Unit* target = GetTarget();
- int32 bp0 = CalculatePct(target->GetMaxPower(POWER_MANA), GetSpellInfo()->Effects[EFFECT_2].BasePoints);
- target->CastCustomSpell(SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC, SPELLVALUE_BASE_POINT0, bp0, target, true, nullptr, aurEff);
- }
-
- void Register() override
- {
- OnEffectProc += AuraEffectProcFn(spell_warl_improved_drain_soul_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_warl_improved_drain_soul_AuraScript();
- }
-};
-
// -1454 - Life Tap
class spell_warl_life_tap : public SpellScriptLoader
{
@@ -1484,6 +1491,7 @@ void AddSC_warlock_spell_scripts()
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();
@@ -1491,7 +1499,6 @@ void AddSC_warlock_spell_scripts()
new spell_warl_haunt();
new spell_warl_health_funnel();
new spell_warl_glyph_of_corruption_nightfall();
- new spell_warl_improved_drain_soul();
new spell_warl_life_tap();
new spell_warl_nether_protection();
new spell_warl_ritual_of_doom_effect();
diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp
index 272ba71d609..91166294355 100644
--- a/src/server/scripts/World/go_scripts.cpp
+++ b/src/server/scripts/World/go_scripts.cpp
@@ -1429,30 +1429,23 @@ public:
{
switch (eventId)
{
- case EVENT_MM_START_MUSIC:
- {
- if (!IsHolidayActive(HOLIDAY_FIRE_FESTIVAL))
- break;
-
- Map::PlayerList const &players = go->GetMap()->GetPlayers();
- for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
+ case EVENT_MM_START_MUSIC:
{
- if (Player* player = itr->GetSource())
+ 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;
}
-
- _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;
}
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index fab4cf54a9a..1d173057e6f 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -3070,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