diff options
Diffstat (limited to 'src')
93 files changed, 4238 insertions, 3740 deletions
diff --git a/src/common/Common.h b/src/common/Common.h index aa04abacd30..af9b9b17321 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -35,6 +35,7 @@ #include <unordered_map> #include <unordered_set> #include <vector> +#include <numeric> #include <cmath> #include <cstdio> diff --git a/src/common/Metric/Metric.cpp b/src/common/Metric/Metric.cpp index 9484cebcc72..cb6b3b1217b 100644 --- a/src/common/Metric/Metric.cpp +++ b/src/common/Metric/Metric.cpp @@ -22,7 +22,7 @@ void Metric::Initialize(std::string const& realmName, boost::asio::io_service& ioService, std::function<void()> overallStatusLogger) { - _realmName = realmName; + _realmName = FormatInfluxDBTagValue(realmName); _batchTimer = Trinity::make_unique<boost::asio::deadline_timer>(ioService); _overallStatusTimer = Trinity::make_unique<boost::asio::deadline_timer>(ioService); _overallStatusLogger = overallStatusLogger; diff --git a/src/common/Metric/Metric.h b/src/common/Metric/Metric.h index 1855e1d0098..9230983da4d 100644 --- a/src/common/Metric/Metric.h +++ b/src/common/Metric/Metric.h @@ -79,6 +79,14 @@ private: static std::string FormatInfluxDBValue(double value) { return std::to_string(value); } static std::string FormatInfluxDBValue(float value) { return FormatInfluxDBValue(double(value)); } + static std::string FormatInfluxDBTagValue(std::string const& value) + { + // ToDo: should handle '=' and ',' characters too + return boost::replace_all_copy(value, " ", "\\ "); + } + + // ToDo: should format TagKey and FieldKey too in the same way as TagValue + public: static Metric* instance(); diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index fc322a89583..88708a79cd6 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -327,33 +327,35 @@ TC_COMMON_API bool StringToBool(std::string const& str); // simple class for not-modifyable list template <typename T> -class HookList +class HookList final { - typedef typename std::list<T>::iterator ListIterator; private: - typename std::list<T> m_list; + typedef std::vector<T> ContainerType; + + ContainerType _container; + public: - HookList<T> & operator+=(T t) - { - m_list.push_back(t); - return *this; - } - HookList<T> & operator-=(T t) + typedef typename ContainerType::iterator iterator; + + HookList<T>& operator+=(T t) { - m_list.remove(t); + _container.push_back(t); return *this; } + size_t size() { - return m_list.size(); + return _container.size(); } - ListIterator begin() + + iterator begin() { - return m_list.begin(); + return _container.begin(); } - ListIterator end() + + iterator end() { - return m_list.end(); + return _container.end(); } }; diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index 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/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index d3d2be4aed5..48315eb44ed 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1671,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: @@ -3587,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/Battlefield/Zones/BattlefieldWG.cpp b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp index 7016494de0e..8df95619ae5 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp @@ -419,6 +419,7 @@ bool BattlefieldWG::SetupBattlefield() m_StartGroupingTimer = 15 * MINUTE * IN_MILLISECONDS; m_StartGrouping = false; + m_tenacityTeam = TEAM_NEUTRAL; m_tenacityStack = 0; KickPosition.Relocate(5728.117f, 2714.346f, 697.733f, 0); @@ -1084,6 +1085,7 @@ void BattlefieldWG::OnPlayerLeaveWar(Player* player) player->RemoveAurasDueToSpell(SPELL_ALLIANCE_CONTROLS_FACTORY_PHASE_SHIFT); player->RemoveAurasDueToSpell(SPELL_HORDE_CONTROL_PHASE_SHIFT); player->RemoveAurasDueToSpell(SPELL_ALLIANCE_CONTROL_PHASE_SHIFT); + UpdateTenacity(); } void BattlefieldWG::OnPlayerLeaveZone(Player* player) @@ -1289,7 +1291,6 @@ void BattlefieldWG::UpdateVehicleCountWG() void BattlefieldWG::UpdateTenacity() { - TeamId team = TEAM_NEUTRAL; uint32 alliancePlayers = m_PlayersInWar[TEAM_ALLIANCE].size(); uint32 hordePlayers = m_PlayersInWar[TEAM_HORDE].size(); int32 newStack = 0; @@ -1305,21 +1306,16 @@ void BattlefieldWG::UpdateTenacity() if (newStack == int32(m_tenacityStack)) return; - if (m_tenacityStack > 0 && newStack <= 0) // old buff was on alliance - team = TEAM_ALLIANCE; - else if (newStack >= 0) // old buff was on horde - team = TEAM_HORDE; - m_tenacityStack = newStack; // Remove old buff - if (team != TEAM_NEUTRAL) + if (m_tenacityTeam != TEAM_NEUTRAL) { - for (auto itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) + for (auto itr = m_players[m_tenacityTeam].begin(); itr != m_players[m_tenacityTeam].end(); ++itr) if (Player* player = ObjectAccessor::FindPlayer(*itr)) if (player->getLevel() >= m_MinLevel) player->RemoveAurasDueToSpell(SPELL_TENACITY); - for (auto itr = m_vehicles[team].begin(); itr != m_vehicles[team].end(); ++itr) + for (auto itr = m_vehicles[m_tenacityTeam].begin(); itr != m_vehicles[m_tenacityTeam].end(); ++itr) if (Creature* creature = GetCreature(*itr)) creature->RemoveAurasDueToSpell(SPELL_TENACITY_VEHICLE); } @@ -1327,7 +1323,7 @@ void BattlefieldWG::UpdateTenacity() // Apply new buff if (newStack) { - team = newStack > 0 ? TEAM_ALLIANCE : TEAM_HORDE; + m_tenacityTeam = newStack > 0 ? TEAM_ALLIANCE : TEAM_HORDE; if (newStack < 0) newStack = -newStack; @@ -1342,25 +1338,27 @@ void BattlefieldWG::UpdateTenacity() if (newStack < 5) buff_honor = 0; - for (auto itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr) + for (auto itr = m_PlayersInWar[m_tenacityTeam].begin(); itr != m_PlayersInWar[m_tenacityTeam].end(); ++itr) if (Player* player = ObjectAccessor::FindPlayer(*itr)) player->SetAuraStack(SPELL_TENACITY, player, newStack); - for (auto itr = m_vehicles[team].begin(); itr != m_vehicles[team].end(); ++itr) + for (auto itr = m_vehicles[m_tenacityTeam].begin(); itr != m_vehicles[m_tenacityTeam].end(); ++itr) if (Creature* creature = GetCreature(*itr)) creature->SetAuraStack(SPELL_TENACITY_VEHICLE, creature, newStack); if (buff_honor != 0) { - for (auto itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr) + for (auto itr = m_PlayersInWar[m_tenacityTeam].begin(); itr != m_PlayersInWar[m_tenacityTeam].end(); ++itr) if (Player* player = ObjectAccessor::FindPlayer(*itr)) player->CastSpell(player, buff_honor, true); - for (auto itr = m_vehicles[team].begin(); itr != m_vehicles[team].end(); ++itr) + for (auto itr = m_vehicles[m_tenacityTeam].begin(); itr != m_vehicles[m_tenacityTeam].end(); ++itr) if (Creature* creature = GetCreature(*itr)) creature->CastSpell(creature, buff_honor, true); } } + else + m_tenacityTeam = TEAM_NEUTRAL; } WintergraspCapturePoint::WintergraspCapturePoint(BattlefieldWG* battlefield, TeamId teamInControl) : BfCapturePoint(battlefield) diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.h b/src/server/game/Battlefield/Zones/BattlefieldWG.h index 7769a9b4b6d..3bd719c1a60 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.h +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.h @@ -393,6 +393,7 @@ class TC_GAME_API BattlefieldWG : public Battlefield GuidUnorderedSet m_vehicles[BG_TEAMS_COUNT]; GuidVector CanonList; + TeamId m_tenacityTeam; uint32 m_tenacityStack; uint32 m_saveTimer; 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/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index a6445b27a44..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 diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index bed9123ac4c..9df9d2ad53c 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1695,6 +1695,7 @@ void Creature::setDeathState(DeathState s) SetLootRecipient(nullptr); ResetPlayerDamageReq(); + SetCannotReachTarget(false); UpdateMovementFlags(); ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~UNIT_STATE_IGNORE_PATHFINDING)); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 8c43d287c91..f1365ac3150 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -310,6 +310,18 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u if (map->Is25ManRaid()) loot.maxDuplicates = 3; + if (uint32 linkedEntry = GetGOInfo()->GetLinkedGameObjectEntry()) + { + GameObject* linkedGO = new GameObject(); + if (linkedGO->Create(map->GenerateLowGuid<HighGuid::GameObject>(), linkedEntry, map, phaseMask, pos, rotation, 255, GO_STATE_READY)) + { + SetLinkedTrap(linkedGO); + map->AddToMap(linkedGO); + } + else + delete linkedGO; + } + return true; } @@ -428,6 +440,10 @@ void GameObject::Update(uint32 diff) m_SkillupList.clear(); m_usetimes = 0; + // If nearby linked trap exists, respawn it + if (GameObject* linkedTrap = GetLinkedTrap()) + linkedTrap->SetLootState(GO_READY); + switch (GetGoType()) { case GAMEOBJECT_TYPE_FISHINGNODE: // can't fish now @@ -511,11 +527,9 @@ void GameObject::Update(uint32 diff) if (Unit* owner = GetOwner()) { // Hunter trap: Search units which are unfriendly to the trap's owner - Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck checker(this, owner, radius); - Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck> searcher(this, target, checker); - VisitNearbyGridObject(radius, searcher); - if (!target) - VisitNearbyWorldObject(radius, searcher); + Trinity::NearestAttackableNoTotemUnitInObjectRangeCheck checker(this, owner, radius); + Trinity::UnitLastSearcher<Trinity::NearestAttackableNoTotemUnitInObjectRangeCheck> searcher(this, target, checker); + VisitNearbyObject(radius, searcher); } else { @@ -613,6 +627,10 @@ void GameObject::Update(uint32 diff) } case GO_JUST_DEACTIVATED: { + // If nearby linked trap exists, despawn it + if (GameObject* linkedTrap = GetLinkedTrap()) + linkedTrap->SetLootState(GO_JUST_DEACTIVATED); + //if Gameobject should cast spell, then this, but some GOs (type = 10) should be destroyed if (GetGoType() == GAMEOBJECT_TYPE_GOOBER) { @@ -1092,25 +1110,8 @@ void GameObject::TriggeringLinkedGameObject(uint32 trapEntry, Unit* target) if (!trapSpell) // checked at load already return; - float range = float(target->GetSpellMaxRangeForTarget(GetOwner(), trapSpell)); - - // search nearest linked GO - GameObject* trapGO = nullptr; - { - // using original GO distance - CellCoord p(Trinity::ComputeCellCoord(GetPositionX(), GetPositionY())); - Cell cell(p); - - Trinity::NearestGameObjectEntryInObjectRangeCheck go_check(*target, trapEntry, range); - Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> checker(this, trapGO, go_check); - - TypeContainerVisitor<Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck>, GridTypeMapContainer > object_checker(checker); - cell.Visit(p, object_checker, *GetMap(), *target, range); - } - - // found correct GO - if (trapGO) - trapGO->CastSpell(target, trapInfo->trap.spellId); + if (GameObject* trapGO = GetLinkedTrap()) + trapGO->CastSpell(target, trapSpell->Id); } GameObject* GameObject::LookupFishingHoleAround(float range) @@ -1828,18 +1829,23 @@ void GameObject::CastSpell(Unit* target, uint32 spellId, TriggerCastFlags trigge if (!trigger) return; + // remove immunity flags, to allow spell to target anything + trigger->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_IMMUNE_TO_PC); + if (Unit* owner = GetOwner()) { trigger->setFaction(owner->getFaction()); if (owner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE)) trigger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + // copy pvp state flags from owner + trigger->SetByteValue(UNIT_FIELD_BYTES_2, 1, owner->GetByteValue(UNIT_FIELD_BYTES_2, 1)); // needed for GO casts for proper target validation checks trigger->SetOwnerGUID(owner->GetGUID()); trigger->CastSpell(target ? target : trigger, spellInfo, triggered, nullptr, nullptr, owner->GetGUID()); } else { - trigger->setFaction(14); + trigger->setFaction(spellInfo->IsPositive() ? 35 : 14); // Set owner guid for target if no owner available - needed by trigger auras // - trigger gets despawned and there's no caster avalible (see AuraEffect::TriggerSpell()) trigger->CastSpell(target ? target : trigger, spellInfo, triggered, nullptr, nullptr, target ? target->GetGUID() : ObjectGuid::Empty); @@ -2231,6 +2237,11 @@ bool GameObject::IsLootAllowedFor(Player const* player) const return true; } +GameObject* GameObject::GetLinkedTrap() +{ + return ObjectAccessor::GetGameObject(*this, m_linkedTrap); +} + void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const { if (!target) diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 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 3946e110c26..1173831be0b 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -824,13 +824,13 @@ bool Item::IsFitToSpellRequirements(SpellInfo const* spellInfo) const { ItemTemplate const* proto = GetTemplate(); + bool const isEnchantSpell = spellInfo->HasEffect(SPELL_EFFECT_ENCHANT_ITEM) || spellInfo->HasEffect(SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) || spellInfo->HasEffect(SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC); if (spellInfo->EquippedItemClass != -1) // -1 == any item class { // Special case - accept vellum for armor/weapon requirements - if ((spellInfo->EquippedItemClass == ITEM_CLASS_ARMOR && proto->IsArmorVellum()) - ||(spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && proto->IsWeaponVellum())) - if (spellInfo->IsAbilityOfSkillType(SKILL_ENCHANTING)) // only for enchanting spells - return true; + if (isEnchantSpell && ((spellInfo->EquippedItemClass == ITEM_CLASS_ARMOR && proto->IsArmorVellum()) + || (spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && proto->IsWeaponVellum()))) + return true; if (spellInfo->EquippedItemClass != int32(proto->Class)) return false; // wrong item class @@ -842,7 +842,7 @@ bool Item::IsFitToSpellRequirements(SpellInfo const* spellInfo) const } } - if (spellInfo->EquippedItemInventoryTypeMask != 0) // 0 == any inventory type + if (isEnchantSpell && spellInfo->EquippedItemInventoryTypeMask != 0) // 0 == any inventory type { // Special case - accept weapon type for main and offhand requirements if (proto->InventoryType == INVTYPE_WEAPON && @@ -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/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index f7d4fb38cee..a5f5aa18b1d 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -173,7 +173,7 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c if (flags & UPDATEFLAG_STATIONARY_POSITION) { // UPDATETYPE_CREATE_OBJECT2 dynamic objects, corpses... - if (isType(TYPEMASK_DYNAMICOBJECT) || isType(TYPEMASK_CORPSE) || isType(TYPEMASK_PLAYER)) + if (isType(TYPEMASK_DYNAMICOBJECT | TYPEMASK_CORPSE | TYPEMASK_PLAYER)) updateType = UPDATETYPE_CREATE_OBJECT2; // UPDATETYPE_CREATE_OBJECT2 for pets... diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 59b109ab754..3e0f9078c2c 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); @@ -3314,7 +3323,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent if (active) { if (spellInfo->IsPassive() && IsNeedCastPassiveSpellAtLearn(spellInfo)) - CastSpell (this, spellId, true); + CastSpell(this, spellId, true); } else if (IsInWorld()) { @@ -3588,6 +3597,15 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const bool need_cast = (!spellInfo->Stances || (form && (spellInfo->Stances & (UI64LIT(1) << (form - 1)))) || (!form && spellInfo->HasAttribute(SPELL_ATTR2_NOT_NEED_SHAPESHIFT))); + // Check EquippedItemClass + // passive spells which apply aura and have an item requirement are to be added in Player::ApplyItemDependentAuras + if (spellInfo->IsPassive() && spellInfo->EquippedItemClass >= 0) + { + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (spellInfo->Effects[i].IsAura()) + return false; + } + //Check CasterAuraStates return need_cast && (!spellInfo->CasterAuraState || HasAuraState(AuraStateType(spellInfo->CasterAuraState))); } @@ -4216,9 +4234,10 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe charDelete_method = CHAR_DELETE_REMOVE; } + SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (ObjectGuid::LowType guildId = GetGuildIdFromDB(playerguid)) if (Guild* guild = sGuildMgr->GetGuildById(guildId)) - guild->DeleteMember(playerguid, false, false, true); + guild->DeleteMember(trans, playerguid, false, false, true); // close player ticket if any GmTicket* ticket = sTicketMgr->GetTicketByPlayer(playerguid); @@ -4245,8 +4264,6 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe // Completely remove from the database case CHAR_DELETE_REMOVE: { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_COD_ITEM_MAIL); stmt->setUInt32(0, guid); PreparedQueryResult resultMail = CharacterDatabase.Query(stmt); @@ -4535,26 +4552,27 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe trans->Append(stmt); Corpse::DeleteFromDB(playerguid, trans); - - CharacterDatabase.CommitTransaction(trans); break; } // The character gets unlinked from the account, the name gets freed up and appears as deleted ingame case CHAR_DELETE_UNLINK: { stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_DELETE_INFO); - stmt->setUInt32(0, guid); - - CharacterDatabase.Execute(stmt); + trans->Append(stmt); break; } default: TC_LOG_ERROR("entities.player.cheat", "Player::DeleteFromDB: Tried to delete player (%s) with unsupported delete method (%u).", playerguid.ToString().c_str(), charDelete_method); + + if (trans->GetSize() > 0) + CharacterDatabase.CommitTransaction(trans); return; } + CharacterDatabase.CommitTransaction(trans); + if (updateRealmChars) sWorld->UpdateRealmCharCount(accountId); @@ -7377,20 +7395,16 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply) TC_LOG_DEBUG("entities.player.items", "Player::_ApplyItemMods: Applying mods for item %s", item->GetGUID().ToString().c_str()); - uint8 attacktype = Player::GetAttackBySlot(slot); - if (proto->Socket[0].Color) //only (un)equipping of items with sockets can influence metagems, so no need to waste time with normal items CorrectMetaGemEnchants(slot, apply); - if (attacktype < MAX_ATTACK) - _ApplyWeaponDependentAuraMods(item, WeaponAttackType(attacktype), apply); - _ApplyItemBonuses(proto, slot, apply); if (slot == EQUIPMENT_SLOT_RANGED) _ApplyAmmoBonuses(); ApplyItemEquipSpell(item, apply); + ApplyItemDependentAuras(item, apply); ApplyEnchantment(item, apply); TC_LOG_DEBUG("entities.player.items", "Player::_ApplyItemMods: completed"); @@ -7744,86 +7758,26 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt UpdateDamagePhysical(attType); } -void Player::_ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply) -{ - AuraEffectList const& auraCritList = GetAuraEffectsByType(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT); - for (AuraEffectList::const_iterator itr = auraCritList.begin(); itr != auraCritList.end(); ++itr) - _ApplyWeaponDependentAuraCritMod(item, attackType, *itr, apply); - - AuraEffectList const& auraDamageFlatList = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE); - for (AuraEffectList::const_iterator itr = auraDamageFlatList.begin(); itr != auraDamageFlatList.end(); ++itr) - _ApplyWeaponDependentAuraDamageMod(item, attackType, *itr, apply); - - AuraEffectList const& auraDamagePctList = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - for (AuraEffectList::const_iterator itr = auraDamagePctList.begin(); itr != auraDamagePctList.end(); ++itr) - _ApplyWeaponDependentAuraDamageMod(item, attackType, *itr, apply); -} - -void Player::_ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply) -{ - // don't apply mod if item is broken or cannot be used - if (item->IsBroken() || !CanUseAttackType(attackType)) - return; - - // generic not weapon specific case processes in aura code - if (aura->GetSpellInfo()->EquippedItemClass == -1) - return; - - BaseModGroup mod; - switch (attackType) - { - case BASE_ATTACK: mod = CRIT_PERCENTAGE; break; - case OFF_ATTACK: mod = OFFHAND_CRIT_PERCENTAGE;break; - case RANGED_ATTACK: mod = RANGED_CRIT_PERCENTAGE; break; - default: return; - } - - if (item->IsFitToSpellRequirements(aura->GetSpellInfo())) - HandleBaseModValue(mod, FLAT_MOD, float (aura->GetAmount()), apply); -} - -void Player::_ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply) +void Player::ApplyItemDependentAuras(Item* item, bool apply) { - // don't apply mod if item is broken or cannot be used - if (item->IsBroken() || !CanUseAttackType(attackType)) - return; - - // ignore spell mods for not wands - if ((aura->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) == 0 && (getClassMask() & CLASSMASK_WAND_USERS) == 0) - return; - - // generic not weapon specific case processes in aura code - if (aura->GetSpellInfo()->EquippedItemClass == -1) - return; - - UnitMods unitMod; - switch (attackType) + if (apply) { - case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break; - case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break; - case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break; - default: return; - } + PlayerSpellMap const& spells = GetSpellMap(); + for (auto itr = spells.begin(); itr != spells.end(); ++itr) + { + if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) + continue; - UnitModifierType unitModType; - switch (aura->GetAuraType()) - { - case SPELL_AURA_MOD_DAMAGE_DONE: unitModType = TOTAL_VALUE; break; - case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE: unitModType = TOTAL_PCT; break; - default: return; - } + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first); + if (!spellInfo || !spellInfo->IsPassive() || spellInfo->EquippedItemClass < 0) + continue; - if (item->IsFitToSpellRequirements(aura->GetSpellInfo())) - { - HandleStatModifier(unitMod, unitModType, float(aura->GetAmount()), apply); - if (unitModType == TOTAL_VALUE) - { - if (aura->GetAmount() > 0) - ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, aura->GetAmount(), apply); - else - ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, aura->GetAmount(), apply); + if (!HasAura(itr->first) && HasItemFitToSpellRequirements(spellInfo)) + AddAura(itr->first, this); // no SMSG_SPELL_GO in sniff found } } + else + RemoveItemDependentAurasAndCasts(item); } void Player::ApplyItemEquipSpell(Item* item, bool apply, bool form_change) @@ -8198,10 +8152,7 @@ void Player::_RemoveAllItemMods() if (!proto) continue; - uint32 attacktype = Player::GetAttackBySlot(i); - if (attacktype < MAX_ATTACK) - _ApplyWeaponDependentAuraMods(m_items[i], WeaponAttackType(attacktype), false); - + ApplyItemDependentAuras(m_items[i], false); _ApplyItemBonuses(proto, i, false); if (i == EQUIPMENT_SLOT_RANGED) @@ -8227,10 +8178,7 @@ void Player::_ApplyAllItemMods() if (!proto) continue; - uint32 attacktype = Player::GetAttackBySlot(i); - if (attacktype < MAX_ATTACK) - _ApplyWeaponDependentAuraMods(m_items[i], WeaponAttackType(attacktype), true); - + ApplyItemDependentAuras(m_items[i], true); _ApplyItemBonuses(proto, i, true); if (i == EQUIPMENT_SLOT_RANGED) @@ -12221,9 +12169,6 @@ void Player::RemoveItem(uint8 bag, uint8 slot, bool update) // remove item dependent auras and casts (only weapon and armor slots) if (slot < EQUIPMENT_SLOT_END) { - if (update) - RemoveItemDependentAurasAndCasts(pItem); - // remove held enchantments, update expertise if (slot == EQUIPMENT_SLOT_MAINHAND) { @@ -12374,9 +12319,6 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update) if (slot < EQUIPMENT_SLOT_END) { - // remove item dependent auras and casts (only weapon and armor slots) - RemoveItemDependentAurasAndCasts(pItem); - // update expertise and armor penetration - passive auras may need it switch (slot) { @@ -15011,20 +14953,20 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, { if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RequiredItemId[i])) { - if (quest->RequiredItemCount[i] > 0 && (itemTemplate->Bonding == BIND_QUEST_ITEM || itemTemplate->Bonding == BIND_QUEST_ITEM1)) - DestroyItemCount(quest->RequiredItemId[i], 9999, true, true); + if (quest->RequiredItemCount[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM && !quest->IsRepeatable() && !HasQuestForItem(quest->RequiredItemId[i], quest_id, true)) + DestroyItemCount(quest->RequiredItemId[i], 9999, true); else - DestroyItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i], true, true); + DestroyItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i], true); } } for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) { if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i])) { - if (quest->ItemDropQuantity[i] > 0 && (itemTemplate->Bonding == BIND_QUEST_ITEM || itemTemplate->Bonding == BIND_QUEST_ITEM1)) - DestroyItemCount(quest->ItemDrop[i], 9999, true, true); + if (quest->ItemDropQuantity[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM && !quest->IsRepeatable() && !HasQuestForItem(quest->ItemDrop[i], quest_id)) + DestroyItemCount(quest->ItemDrop[i], 9999, true); else - DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true, true); + DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true); } } @@ -15244,13 +15186,13 @@ void Player::FailQuest(uint32 questId) // Destroy quest items on quest failure. for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RequiredItemId[i])) - if (quest->RequiredItemCount[i] > 0 && (itemTemplate->Bonding == BIND_QUEST_ITEM || itemTemplate->Bonding == BIND_QUEST_ITEM1)) - DestroyItemCount(quest->RequiredItemId[i], 9999, true, true); + if (quest->RequiredItemCount[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM) + DestroyItemCount(quest->RequiredItemId[i], 9999, true); for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i])) - if (quest->ItemDropQuantity[i] > 0 && (itemTemplate->Bonding == BIND_QUEST_ITEM || itemTemplate->Bonding == BIND_QUEST_ITEM1)) - DestroyItemCount(quest->ItemDrop[i], 9999, true, true); + if (quest->ItemDropQuantity[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM) + DestroyItemCount(quest->ItemDrop[i], 9999, true); } } @@ -15261,13 +15203,13 @@ void Player::AbandonQuest(uint32 questId) // Destroy quest items on quest abandon. for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RequiredItemId[i])) - if (quest->RequiredItemCount[i] > 0 && (itemTemplate->Bonding == BIND_QUEST_ITEM || itemTemplate->Bonding == BIND_QUEST_ITEM1)) - DestroyItemCount(quest->RequiredItemId[i], 9999, true, true); + if (quest->RequiredItemCount[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM) + DestroyItemCount(quest->RequiredItemId[i], 9999, true); for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i])) - if (quest->ItemDropQuantity[i] > 0 && (itemTemplate->Bonding == BIND_QUEST_ITEM || itemTemplate->Bonding == BIND_QUEST_ITEM1)) - DestroyItemCount(quest->ItemDrop[i], 9999, true, true); + if (quest->ItemDropQuantity[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM) + DestroyItemCount(quest->ItemDrop[i], 9999, true); } } @@ -15971,7 +15913,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); @@ -15995,7 +15937,7 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) if (!quest) continue; - if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK, quest->GetQuestId(), this)) + if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_QUEST_ACCEPT, quest->GetQuestId(), this)) continue; QuestStatus status = GetQuestStatus(questId); @@ -16566,12 +16508,12 @@ void Player::ReputationChanged2(FactionEntry const* factionEntry) } } -bool Player::HasQuestForItem(uint32 itemid) const +bool Player::HasQuestForItem(uint32 itemid, uint32 excludeQuestId /* 0 */, bool turnIn /* false */) const { for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i) { uint32 questid = GetQuestSlotQuestId(i); - if (questid == 0) + if (questid == 0 || questid == excludeQuestId) continue; QuestStatusMap::const_iterator qs_itr = m_QuestStatus.find(questid); @@ -16580,7 +16522,7 @@ bool Player::HasQuestForItem(uint32 itemid) const QuestStatusData const& q_status = qs_itr->second; - if (q_status.Status == QUEST_STATUS_INCOMPLETE) + if ((q_status.Status == QUEST_STATUS_INCOMPLETE) || (turnIn && q_status.Status == QUEST_STATUS_COMPLETE)) { Quest const* qinfo = sObjectMgr->GetQuestTemplate(questid); if (!qinfo) @@ -16595,7 +16537,7 @@ bool Player::HasQuestForItem(uint32 itemid) const // This part for ReqItem drop for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j) { - if (itemid == qinfo->RequiredItemId[j] && q_status.ItemCount[j] < qinfo->RequiredItemCount[j]) + if ((itemid == qinfo->RequiredItemId[j] && q_status.ItemCount[j] < qinfo->RequiredItemCount[j]) || (turnIn && q_status.ItemCount[j] >= qinfo->RequiredItemCount[j])) return true; } // This part - for ReqSource @@ -16605,17 +16547,17 @@ bool Player::HasQuestForItem(uint32 itemid) const if (qinfo->ItemDrop[j] == itemid) { ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid); - + uint32 ownedCount = GetItemCount(itemid, true); // 'unique' item - if (pProto->MaxCount && int32(GetItemCount(itemid, true)) < pProto->MaxCount) + if ((pProto->MaxCount && int32(ownedCount) < pProto->MaxCount) || (turnIn && int32(ownedCount) >= pProto->MaxCount)) return true; // allows custom amount drop when not 0 if (qinfo->ItemDropQuantity[j]) { - if (GetItemCount(itemid, true) < qinfo->ItemDropQuantity[j]) + if ((ownedCount < qinfo->ItemDropQuantity[j]) || (turnIn && ownedCount >= qinfo->ItemDropQuantity[j])) return true; - } else if (GetItemCount(itemid, true) < pProto->GetMaxStackSize()) + } else if (ownedCount < pProto->GetMaxStackSize()) return true; } } @@ -19558,7 +19500,6 @@ void Player::_SaveAuras(SQLTransaction& trans) stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AURA); stmt->setUInt32(index++, GetGUID().GetCounter()); stmt->setUInt64(index++, itr->second->GetCasterGUID().GetRawValue()); - stmt->setUInt64(index++, itr->second->GetCastItemGUID().GetRawValue()); stmt->setUInt32(index++, itr->second->GetId()); stmt->setUInt8(index++, effMask); stmt->setUInt8(index++, recalculateMask); @@ -20873,29 +20814,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) @@ -23582,9 +23524,9 @@ void Player::RemoveItemDependentAurasAndCasts(Item* pItem) { Aura* aura = itr->second; - // skip passive (passive item dependent spells work in another way) and not self applied auras + // skip not self applied auras SpellInfo const* spellInfo = aura->GetSpellInfo(); - if (aura->IsPassive() || aura->GetCasterGUID() != GetGUID()) + if (aura->GetCasterGUID() != GetGUID()) { ++itr; continue; @@ -24629,9 +24571,9 @@ void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore cons void Player::StoreLootItem(uint8 lootSlot, Loot* loot) { - QuestItem* qitem = nullptr; - QuestItem* ffaitem = nullptr; - QuestItem* conditem = nullptr; + NotNormalLootItem* qitem = nullptr; + NotNormalLootItem* ffaitem = nullptr; + NotNormalLootItem* conditem = nullptr; LootItem* item = loot->LootItemInSlot(lootSlot, this, &qitem, &ffaitem, &conditem); @@ -25883,6 +25825,20 @@ void Player::ActivateSpec(uint8 spec) UnsummonAllTotems(); ExitVehicle(); RemoveAllControlled(); + + // remove single target auras at other targets + AuraList& scAuras = GetSingleCastAuras(); + for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();) + { + Aura* aura = *iter; + if (aura->GetUnitOwner() != this) + { + aura->Remove(); + iter = scAuras.begin(); + } + else + ++iter; + } /*RemoveAllAurasOnDeath(); if (GetPet()) GetPet()->RemoveAllAurasOnDeath();*/ @@ -26000,6 +25956,13 @@ void Player::ActivateSpec(uint8 spec) SetPower(POWER_MANA, 0); // Mana must be 0 even if it isn't the active power type. SetPower(pw, 0); + + Unit::AuraEffectList const& shapeshiftAuras = GetAuraEffectsByType(SPELL_AURA_MOD_SHAPESHIFT); + for (AuraEffect* aurEff : shapeshiftAuras) + { + aurEff->HandleShapeshiftBoosts(this, false); + aurEff->HandleShapeshiftBoosts(this, true); + } } void Player::ResetTimeSync() diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 4ecdad742e9..ed5dc7e954f 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1406,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; @@ -1958,9 +1958,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void ResetAllPowers(); - void _ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply); - void _ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply); - void _ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply); + void ApplyItemDependentAuras(Item* item, bool apply); void _ApplyItemMods(Item* item, uint8 slot, bool apply); void _RemoveAllItemMods(); diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index fad197949a8..cdb4b931a07 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -131,6 +131,7 @@ void Transport::Update(uint32 diff) m_goValue.Transport.PathProgress += diff; uint32 timer = m_goValue.Transport.PathProgress % GetTransportPeriod(); + bool justStopped = false; // Set current waypoint // Desired outcome: _currentFrame->DepartureTime < timer < _nextFrame->ArriveTime @@ -149,6 +150,7 @@ void Transport::Update(uint32 diff) if (timer < _currentFrame->DepartureTime) { SetMoving(false); + justStopped = true; if (_pendingStop && GetGoState() != GO_STATE_READY) { SetGoState(GO_STATE_READY); @@ -203,12 +205,14 @@ void Transport::Update(uint32 diff) _positionChangeTimer.Reset(positionUpdateDelay); if (IsMoving()) { - float t = CalculateSegmentPos(float(timer) * 0.001f); + float t = !justStopped ? CalculateSegmentPos(float(timer) * 0.001f) : 1.0f; G3D::Vector3 pos, dir; _currentFrame->Spline->evaluate_percent(_currentFrame->Index, t, pos); _currentFrame->Spline->evaluate_derivative(_currentFrame->Index, t, dir); UpdatePosition(pos.x, pos.y, pos.z, std::atan2(dir.y, dir.x) + float(M_PI)); } + else if (justStopped) + UpdatePosition(_currentFrame->Node->LocX, _currentFrame->Node->LocY, _currentFrame->Node->LocZ, _currentFrame->InitialOrientation); else { /* There are four possible scenarios that trigger loading/unloading passengers: diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 699709fabb1..0cad0b2cb05 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -184,8 +184,17 @@ void Player::UpdateSpellDamageAndHealingBonus() // Get healing bonus for all schools SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, SpellBaseHealingBonusDone(SPELL_SCHOOL_MASK_ALL)); // Get damage bonus for all schools - for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) - SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonusDone(SpellSchoolMask(1 << i))); + Unit::AuraEffectList const& modDamageAuras = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE); + for (uint16 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) + { + SetInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + i, std::accumulate(modDamageAuras.begin(), modDamageAuras.end(), 0, [i](int32 negativeMod, AuraEffect const* aurEff) + { + if (aurEff->GetAmount() < 0 && aurEff->GetMiscValue() & (1 << i)) + negativeMod += aurEff->GetAmount(); + return negativeMod; + })); + SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + i, SpellBaseDamageBonusDone(SpellSchoolMask(1 << i)) - GetInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + i)); + } } bool Player::UpdateAllStats() @@ -530,9 +539,9 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo break; } - float attackSpeedMod = GetAPMultiplier(attType, normalized); + float const attackPowerMod = std::max(GetAPMultiplier(attType, normalized), 0.25f); - float baseValue = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * attackSpeedMod; + float baseValue = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * attackPowerMod; float basePct = GetModifierValue(unitMod, BASE_PCT); float totalValue = GetModifierValue(unitMod, TOTAL_VALUE); float totalPct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f; @@ -546,8 +555,8 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo if (lvl > 60) lvl = 60; - weaponMinDamage = lvl * 0.85f * attackSpeedMod; - weaponMaxDamage = lvl * 1.25f * attackSpeedMod; + weaponMinDamage = lvl * 0.85f * attackPowerMod; + weaponMaxDamage = lvl * 1.25f * attackPowerMod; } else if (!CanUseAttackType(attType)) // check if player not in form but still can't use (disarm case) { @@ -563,8 +572,8 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo } else if (attType == RANGED_ATTACK) // add ammo DPS to ranged damage { - weaponMinDamage += GetAmmoDPS() * attackSpeedMod; - weaponMaxDamage += GetAmmoDPS() * attackSpeedMod; + weaponMinDamage += GetAmmoDPS() * attackPowerMod; + weaponMaxDamage += GetAmmoDPS() * attackPowerMod; } minDamage = ((weaponMinDamage + baseValue) * basePct + totalValue) * totalPct; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index cecec8660c7..7ff01efa363 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,10 +1049,10 @@ void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, SpellCastTargets targets; targets.SetDst(x, y, z, GetOrientation()); - CastSpell(targets, spellInfo, NULL, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster); + CastSpell(targets, spellInfo, nullptr, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster); } -void Unit::CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castItem, AuraEffect* triggeredByAura, ObjectGuid originalCaster) +void Unit::CastSpell(float x, float y, float z, uint32 spellId, TriggerCastFlags triggerFlags, Item* castItem, AuraEffect const* triggeredByAura, ObjectGuid originalCaster) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) @@ -1054,26 +1061,23 @@ void Unit::CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castI return; } SpellCastTargets targets; - targets.SetGOTarget(go); + targets.SetDst(x, y, z, GetOrientation()); - CastSpell(targets, spellInfo, NULL, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster); + CastSpell(targets, spellInfo, nullptr, triggerFlags, castItem, triggeredByAura, originalCaster); } -// Obsolete func need remove, here only for comotability vs another patches -uint32 Unit::SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage) +void Unit::CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castItem, AuraEffect* triggeredByAura, ObjectGuid originalCaster) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) - return 0; - SpellNonMeleeDamage damageInfo(this, victim, spellInfo->Id, spellInfo->SchoolMask); - damage = SpellDamageBonusDone(victim, spellInfo, damage, SPELL_DIRECT_DAMAGE); - damage = victim->SpellDamageBonusTaken(this, spellInfo, damage, SPELL_DIRECT_DAMAGE); + { + TC_LOG_ERROR("entities.unit", "CastSpell: unknown spell id %u by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUID().GetCounter() : GetEntry())); + return; + } + SpellCastTargets targets; + targets.SetGOTarget(go); - CalculateSpellDamageTaken(&damageInfo, damage, spellInfo); - DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); - SendSpellNonMeleeDamageLog(&damageInfo); - DealSpellDamage(&damageInfo, true); - return damageInfo.damage; + CastSpell(targets, spellInfo, nullptr, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, castItem, triggeredByAura, originalCaster); } void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType, bool crit) @@ -1144,8 +1148,11 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama // double blocked amount if block is critical if (victim->isBlockCritical()) damageInfo->blocked += damageInfo->blocked; - if (damage < int32(damageInfo->blocked)) + if (damage <= int32(damageInfo->blocked)) + { damageInfo->blocked = uint32(damage); + damageInfo->fullBlock = true; + } damage -= damageInfo->blocked; } @@ -1155,7 +1162,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,24 +1185,30 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama sScriptMgr->ModifySpellDamageTaken(damageInfo->target, damageInfo->attacker, damage); // Calculate absorb resist - if (damage > 0) - { - CalcAbsorbResist(victim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo); - damage -= damageInfo->absorb + damageInfo->resist; - } - else + if (damage < 0) damage = 0; damageInfo->damage = damage; + DamageInfo dmgInfo(*damageInfo, SPELL_DIRECT_DAMAGE, BASE_ATTACK, PROC_HIT_NONE); + CalcAbsorbResist(dmgInfo); + damageInfo->absorb = dmgInfo.GetAbsorb(); + damageInfo->resist = dmgInfo.GetResist(); + + if (damageInfo->absorb) + damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB); + + if (damageInfo->resist) + damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST); + + damageInfo->damage = dmgInfo.GetDamage(); } void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss) { - if (damageInfo == 0) + if (!damageInfo) return; Unit* victim = damageInfo->target; - if (!victim) return; @@ -1396,7 +1409,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 +1420,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; @@ -1500,46 +1516,47 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) // We're going to call functions which can modify content of the list during iteration over it's elements // Let's copy the list so we can prevent iterator invalidation AuraEffectList vDamageShieldsCopy(victim->GetAuraEffectsByType(SPELL_AURA_DAMAGE_SHIELD)); - for (AuraEffectList::const_iterator dmgShieldItr = vDamageShieldsCopy.begin(); dmgShieldItr != vDamageShieldsCopy.end(); ++dmgShieldItr) + for (AuraEffect const* aurEff : vDamageShieldsCopy) { - SpellInfo const* i_spellProto = (*dmgShieldItr)->GetSpellInfo(); + SpellInfo const* spellInfo = aurEff->GetSpellInfo(); + // Damage shield can be resisted... - if (SpellMissInfo missInfo = victim->SpellHitResult(this, i_spellProto, false)) + SpellMissInfo missInfo = victim->SpellHitResult(this, spellInfo, false); + if (missInfo != SPELL_MISS_NONE) { - victim->SendSpellMiss(this, i_spellProto->Id, missInfo); + victim->SendSpellMiss(this, spellInfo->Id, missInfo); continue; } // ...or immuned - if (IsImmunedToDamage(i_spellProto)) + if (IsImmunedToDamage(spellInfo)) { - victim->SendSpellDamageImmune(this, i_spellProto->Id); + victim->SendSpellDamageImmune(this, spellInfo->Id); continue; } - uint32 damage = (*dmgShieldItr)->GetAmount(); - - if (Unit* caster = (*dmgShieldItr)->GetCaster()) + uint32 damage = aurEff->GetAmount(); + if (Unit* caster = aurEff->GetCaster()) { - damage = caster->SpellDamageBonusDone(this, i_spellProto, damage, SPELL_DIRECT_DAMAGE); - damage = this->SpellDamageBonusTaken(caster, i_spellProto, damage, SPELL_DIRECT_DAMAGE); + damage = caster->SpellDamageBonusDone(this, spellInfo, damage, SPELL_DIRECT_DAMAGE); + damage = SpellDamageBonusTaken(caster, spellInfo, damage, SPELL_DIRECT_DAMAGE); } // No Unit::CalcAbsorbResist here - opcode doesn't send that data - this damage is probably not affected by that - victim->DealDamageMods(this, damage, NULL); + victim->DealDamageMods(this, damage, nullptr); /// @todo Move this to a packet handler WorldPacket data(SMSG_SPELLDAMAGESHIELD, 8 + 8 + 4 + 4 + 4 + 4 + 4); data << uint64(victim->GetGUID()); data << uint64(GetGUID()); - data << uint32(i_spellProto->Id); + data << uint32(spellInfo->Id); data << uint32(damage); // Damage - int32 overkill = int32(damage) - int32(GetHealth()); - data << uint32(overkill > 0 ? overkill : 0); // Overkill - data << uint32(i_spellProto->SchoolMask); + int32 const overkill = int32(damage) - int32(GetHealth()); + data << uint32(std::max(overkill, 0)); // Overkill + data << uint32(spellInfo->SchoolMask); victim->SendMessageToSet(&data, true); - victim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, i_spellProto->GetSchoolMask(), i_spellProto, true); + victim->DealDamage(this, damage, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true); } } } @@ -1731,57 +1748,49 @@ uint32 Unit::CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, Spell return resistance * 10; } -void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint32 const damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo /*= NULL*/) +void Unit::CalcAbsorbResist(DamageInfo& damageInfo) { - if (!victim || !victim->IsAlive() || !damage) + if (!damageInfo.GetVictim() || !damageInfo.GetVictim()->IsAlive() || !damageInfo.GetDamage()) return; - DamageInfo dmgInfo = DamageInfo(this, victim, damage, spellInfo, schoolMask, damagetype, 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 +1803,19 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe bool defaultPrevented = false; - absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb, defaultPrevented); + absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented); currentAbsorb = tempAbsorb; if (defaultPrevented) continue; // absorb must be smaller than the damage itself - currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage())); + currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage())); - dmgInfo.AbsorbDamage(currentAbsorb); + damageInfo.AbsorbDamage(currentAbsorb); tempAbsorb = currentAbsorb; - absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb); + absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb); // Check if our aura is using amount to count damage if (absorbAurEff->GetAmount() >= 0) @@ -1820,16 +1829,16 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe } // absorb by mana cost - AuraEffectList vManaShieldCopy(victim->GetAuraEffectsByType(SPELL_AURA_MANA_SHIELD)); - for (AuraEffectList::const_iterator itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr) + AuraEffectList vManaShieldCopy(damageInfo.GetVictim()->GetAuraEffectsByType(SPELL_AURA_MANA_SHIELD)); + for (AuraEffectList::const_iterator itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (damageInfo.GetDamage() > 0); ++itr) { AuraEffect* absorbAurEff = *itr; // Check if aura was removed during iteration - we don't need to work on such auras - AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID()); + AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID()); if (!aurApp) continue; // check damage school mask - if (!(absorbAurEff->GetMiscValue() & schoolMask)) + if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask())) continue; // get amount which can be still absorbed by the aura @@ -1842,14 +1851,14 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe bool defaultPrevented = false; - absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb, defaultPrevented); + absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented); currentAbsorb = tempAbsorb; if (defaultPrevented) continue; // absorb must be smaller than the damage itself - currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage())); + currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage())); int32 manaReduction = currentAbsorb; @@ -1857,15 +1866,15 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe if (float manaMultiplier = absorbAurEff->GetSpellInfo()->Effects[absorbAurEff->GetEffIndex()].CalcValueMultiplier(absorbAurEff->GetCaster())) manaReduction = int32(float(manaReduction) * manaMultiplier); - int32 manaTaken = -victim->ModifyPower(POWER_MANA, -manaReduction); + int32 manaTaken = -damageInfo.GetVictim()->ModifyPower(POWER_MANA, -manaReduction); // take case when mana has ended up into account currentAbsorb = currentAbsorb ? int32(float(currentAbsorb) * (float(manaTaken) / float(manaReduction))) : 0; - dmgInfo.AbsorbDamage(currentAbsorb); + damageInfo.AbsorbDamage(currentAbsorb); tempAbsorb = currentAbsorb; - absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb); + absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb); // Check if our aura is using amount to count damage if (absorbAurEff->GetAmount() >= 0) @@ -1876,39 +1885,39 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe } } - dmgInfo.ModifyDamage(absorbIgnoringDamage); + damageInfo.ModifyDamage(absorbIgnoringDamage); // split damage auras - only when not damaging self - if (victim != this) + if (damageInfo.GetVictim() != this) { // We're going to call functions which can modify content of the list during iteration over it's elements // Let's copy the list so we can prevent iterator invalidation - AuraEffectList vSplitDamageFlatCopy(victim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_FLAT)); - for (AuraEffectList::iterator itr = vSplitDamageFlatCopy.begin(); (itr != vSplitDamageFlatCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr) + AuraEffectList vSplitDamageFlatCopy(damageInfo.GetVictim()->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_FLAT)); + for (AuraEffectList::iterator itr = vSplitDamageFlatCopy.begin(); (itr != vSplitDamageFlatCopy.end()) && (damageInfo.GetDamage() > 0); ++itr) { // Check if aura was removed during iteration - we don't need to work on such auras - if (!((*itr)->GetBase()->IsAppliedOnTarget(victim->GetGUID()))) + if (!((*itr)->GetBase()->IsAppliedOnTarget(damageInfo.GetVictim()->GetGUID()))) continue; // check damage school mask - if (!((*itr)->GetMiscValue() & schoolMask)) + if (!((*itr)->GetMiscValue() & damageInfo.GetSchoolMask())) continue; // Damage can be splitted only if aura has an alive caster Unit* caster = (*itr)->GetCaster(); - if (!caster || (caster == victim) || !caster->IsInWorld() || !caster->IsAlive()) + if (!caster || (caster == damageInfo.GetVictim()) || !caster->IsInWorld() || !caster->IsAlive()) continue; int32 splitDamage = (*itr)->GetAmount(); // absorb must be smaller than the damage itself - splitDamage = RoundToInterval(splitDamage, 0, int32(dmgInfo.GetDamage())); + splitDamage = RoundToInterval(splitDamage, 0, int32(damageInfo.GetDamage())); - dmgInfo.AbsorbDamage(splitDamage); + damageInfo.AbsorbDamage(splitDamage); // check if caster is immune to damage - if (caster->IsImmunedToDamage(schoolMask)) + if (caster->IsImmunedToDamage(damageInfo.GetSchoolMask())) { - victim->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE); + damageInfo.GetVictim()->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE); continue; } @@ -1916,66 +1925,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; @@ -2364,7 +2369,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 @@ -2429,11 +2434,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 @@ -2581,7 +2581,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(); @@ -2675,19 +2675,23 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo // Resist SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool CanReflect) { + if (spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT)) + return SPELL_MISS_NONE; + // Check for immune if (victim->IsImmunedToSpell(spellInfo)) return SPELL_MISS_IMMUNE; + // Damage immunity is only checked if the spell has damage effects, this immunity must not prevent aura apply + // returns SPELL_MISS_IMMUNE in that case, for other spells, the SMSG_SPELL_GO must show hit + if (spellInfo->HasOnlyDamageEffects() && victim->IsImmunedToDamage(spellInfo)) + return SPELL_MISS_IMMUNE; + // All positive spells can`t miss /// @todo client not show miss log for this spells - so need find info for this in dbc and use it! if (spellInfo->IsPositive() && !IsHostileTo(victim)) // prevent from affecting enemy by "positive" spell return SPELL_MISS_NONE; - // Check for immune - if (victim->IsImmunedToDamage(spellInfo)) - return SPELL_MISS_IMMUNE; - if (this == victim) return SPELL_MISS_NONE; @@ -2901,8 +2905,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; @@ -3296,10 +3300,13 @@ int32 Unit::GetCurrentSpellCastTime(uint32 spell_id) const bool Unit::CanMoveDuringChannel() const { if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL]) - if (spell->getState() != SPELL_STATE_FINISHED) - return spell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING) && spell->IsChannelActive(); + { + if (spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive()) + if (!spell->GetSpellInfo()->IsMoveAllowedChannel()) + return false; + } - return false; + return true; } bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const @@ -5242,10 +5249,10 @@ void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 SpellID, uint32 Damag void Unit::ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo) { WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK; - if (typeMaskActor && CanProc()) + if (typeMaskActor) ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType); - if (typeMaskActionTarget && actionTarget && actionTarget->CanProc()) + if (typeMaskActionTarget && actionTarget) actionTarget->ProcSkillsAndReactives(true, this, typeMaskActionTarget, hitMask, attType); TriggerAurasProcOnEvent(actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); @@ -5471,6 +5478,8 @@ FactionTemplateEntry const* Unit::GetFactionTemplateEntry() const TC_LOG_ERROR("entities.unit", "Creature (template id: %u) has invalid faction (faction template id) #%u", creature->GetCreatureTemplate()->Entry, getFaction()); else TC_LOG_ERROR("entities.unit", "Unit (name=%s, type=%u) has invalid faction (faction template id) #%u", GetName().c_str(), uint32(GetTypeId()), getFaction()); + + ABORT(); } return entry; } @@ -5526,8 +5535,7 @@ ReputationRank Unit::GetReactionTo(Unit const* target) const } // check FFA_PVP - if (GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_FFA_PVP - && target->GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_FFA_PVP) + if (IsFFAPvP() && target->IsFFAPvP()) return REP_HOSTILE; if (selfPlayerOwner) @@ -5905,17 +5913,14 @@ void Unit::ModifyAuraState(AuraStateType flag, bool apply) { RemoveFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)); - if (flag != AURA_STATE_ENRAGE) // enrage aura state triggering continues auras + Unit::AuraApplicationMap& tAuras = GetAppliedAuras(); + for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();) { - Unit::AuraApplicationMap& tAuras = GetAppliedAuras(); - for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();) - { - SpellInfo const* spellProto = (*itr).second->GetBase()->GetSpellInfo(); - if (spellProto->CasterAuraState == uint32(flag)) - RemoveAura(itr); - else - ++itr; - } + SpellInfo const* spellProto = itr->second->GetBase()->GetSpellInfo(); + if (itr->second->GetBase()->GetCasterGUID() == GetGUID() && spellProto->CasterAuraState == uint32(flag) && (spellProto->IsPassive() || flag != AURA_STATE_ENRAGE)) + RemoveAura(itr); + else + ++itr; } } } @@ -6590,7 +6595,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()); @@ -6680,11 +6685,12 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin // Impurity (dummy effect) if (GetTypeId() == TYPEID_PLAYER) { - PlayerSpellMap playerSpells = ToPlayer()->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = playerSpells.begin(); itr != playerSpells.end(); ++itr) + PlayerSpellMap const& playerSpells = ToPlayer()->GetSpellMap(); + for (auto itr = playerSpells.begin(); itr != playerSpells.end(); ++itr) { if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) continue; + switch (itr->first) { case 49220: @@ -6693,7 +6699,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin case 49636: case 49638: if (SpellInfo const* proto = sSpellMgr->GetSpellInfo(itr->first)) - AddPct(ApCoeffMod, proto->Effects[0].CalcValue()); + AddPct(ApCoeffMod, proto->Effects[EFFECT_0].CalcValue()); break; } } @@ -6709,33 +6715,28 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin DoneAdvertisedBenefit += ((Guardian*)this)->GetBonusDamage(); // Check for table values - float coeff = 0; + float coeff = 0.0f; SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id); if (bonus) { + WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK; + float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)); + APbonus += GetTotalAttackPowerValue(attType); + if (damagetype == DOT) { coeff = bonus->dot_damage; if (bonus->ap_dot_bonus > 0) - { - WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK; - float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)); - APbonus += GetTotalAttackPowerValue(attType); DoneTotal += int32(bonus->ap_dot_bonus * stack * ApCoeffMod * APbonus); - } } else { coeff = bonus->direct_damage; if (bonus->ap_bonus > 0) - { - WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK; - float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)); - APbonus += GetTotalAttackPowerValue(attType); DoneTotal += int32(bonus->ap_bonus * stack * ApCoeffMod * APbonus); - } } } + // Default calculation if (DoneAdvertisedBenefit) { @@ -6753,14 +6754,16 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod); } + float tmpDamage = (int32(pdamage) + DoneTotal); + + // DOTs calculated in AuraEffect::PeriodicDamageAurasTick // Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods. - float tmpDamage = (int32(pdamage) + DoneTotal) * (damagetype == DOT ? 1.0f : SpellDamagePctDone(victim, spellProto, damagetype)); - // apply spellmod to Done damage (flat and pct) - if (Player* modOwner = GetSpellModOwner()) + if (damagetype != DOT) { - if (damagetype == DOT) - modOwner->ApplySpellMod<SPELLMOD_DOT>(spellProto->Id, tmpDamage); - else + tmpDamage *= SpellDamagePctDone(victim, spellProto, damagetype); + + // apply spellmod to Done damage (flat and pct) + if (Player* modOwner = GetSpellModOwner()) modOwner->ApplySpellMod<SPELLMOD_DAMAGE>(spellProto->Id, tmpDamage); } @@ -6787,22 +6790,17 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage if (GetTypeId() == TYPEID_UNIT && !IsPet()) DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureTemplate()->rank); - AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i) + float maxModDamagePercentSchool = 0.0f; + if (GetTypeId() == TYPEID_PLAYER) { - if (spellProto->EquippedItemClass == -1 && (*i)->GetSpellInfo()->EquippedItemClass != -1) //prevent apply mods from weapon specific case to non weapon specific spells (Example: thunder clap and two-handed weapon specialization) - continue; - - if ((*i)->GetMiscValue() & spellProto->GetSchoolMask()) - { - if ((*i)->GetSpellInfo()->EquippedItemClass == -1) - AddPct(DoneTotalMod, (*i)->GetAmount()); - else if (!(*i)->GetSpellInfo()->HasAttribute(SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0)) - AddPct(DoneTotalMod, (*i)->GetAmount()); - else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellInfo())) - AddPct(DoneTotalMod, (*i)->GetAmount()); - } + for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i) + if (spellProto->GetSchoolMask() & (1 << i)) + maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, GetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i)); } + else + maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, spellProto->GetSchoolMask()); + + DoneTotalMod *= maxModDamagePercentSchool; uint32 creatureTypeMask = victim->GetCreatureTypeMask(); @@ -7183,13 +7181,9 @@ int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const int32 DoneAdvertisedBenefit = 0; AuraEffectList const& mDamageDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE); - for (AuraEffectList::const_iterator i = mDamageDone.begin(); i != mDamageDone.end(); ++i) - if (((*i)->GetMiscValue() & schoolMask) != 0 && - (*i)->GetSpellInfo()->EquippedItemClass == -1 && - // -1 == any item class (not wand then) - (*i)->GetSpellInfo()->EquippedItemInventoryTypeMask == 0) - // 0 == any inventory type (not wand then) - DoneAdvertisedBenefit += (*i)->GetAmount(); + for (AuraEffect const* aurEff : mDamageDone) + if (aurEff->GetMiscValue() & schoolMask) + DoneAdvertisedBenefit += aurEff->GetAmount(); if (GetTypeId() == TYPEID_PLAYER) { @@ -7198,22 +7192,20 @@ int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const // Damage bonus from stats AuraEffectList const& mDamageDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT); - for (AuraEffectList::const_iterator i = mDamageDoneOfStatPercent.begin(); i != mDamageDoneOfStatPercent.end(); ++i) + for (AuraEffect const* aurEff : mDamageDoneOfStatPercent) { - if ((*i)->GetMiscValue() & schoolMask) + if ((aurEff->GetMiscValue() & schoolMask) != 0) { // stat used stored in miscValueB for this aura - Stats usedStat = Stats((*i)->GetMiscValueB()); - DoneAdvertisedBenefit += int32(CalculatePct(GetStat(usedStat), (*i)->GetAmount())); + Stats const usedStat = static_cast<Stats>(aurEff->GetMiscValueB()); + DoneAdvertisedBenefit += static_cast<int32>(CalculatePct(GetStat(usedStat), aurEff->GetAmount())); } } - // ... and attack power - AuraEffectList const& mDamageDonebyAP = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER); - for (AuraEffectList::const_iterator i =mDamageDonebyAP.begin(); i != mDamageDonebyAP.end(); ++i) - if ((*i)->GetMiscValue() & schoolMask) - DoneAdvertisedBenefit += int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), (*i)->GetAmount())); + // ... and attack power + DoneAdvertisedBenefit += static_cast<int32>(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER, schoolMask))); } + return DoneAdvertisedBenefit; } @@ -7534,6 +7526,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui if (spellProto->SpellFamilyName == SPELLFAMILY_POTION) return healamount; + float ApCoeffMod = 1.0f; int32 DoneTotal = 0; // done scripted mod (take it from owner) @@ -7555,6 +7548,35 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui } } + // Custom scripted damage + switch (spellProto->SpellFamilyName) + { + case SPELLFAMILY_DEATHKNIGHT: + // Impurity (dummy effect) + if (GetTypeId() == TYPEID_PLAYER) + { + PlayerSpellMap const& playerSpells = ToPlayer()->GetSpellMap(); + for (auto itr = playerSpells.begin(); itr != playerSpells.end(); ++itr) + { + if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) + continue; + + switch (itr->first) + { + case 49220: + case 49633: + case 49635: + case 49636: + case 49638: + if (SpellInfo const* proto = sSpellMgr->GetSpellInfo(itr->first)) + AddPct(ApCoeffMod, proto->Effects[EFFECT_0].CalcValue()); + break; + } + } + } + break; + } + // Done fixed damage bonus auras int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(spellProto->GetSchoolMask()); @@ -7568,15 +7590,15 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui { coeff = bonus->dot_damage; if (bonus->ap_dot_bonus > 0) - DoneTotal += int32(bonus->ap_dot_bonus * stack * GetTotalAttackPowerValue( - (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK)); + DoneTotal += int32(bonus->ap_dot_bonus * ApCoeffMod * stack * GetTotalAttackPowerValue( + (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK)); } else { coeff = bonus->direct_damage; if (bonus->ap_bonus > 0) - DoneTotal += int32(bonus->ap_bonus * stack * GetTotalAttackPowerValue( - (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK)); + DoneTotal += int32(bonus->ap_bonus * ApCoeffMod * stack * GetTotalAttackPowerValue( + (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK)); } } else @@ -7622,14 +7644,16 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui DoneTotal = 0; } + float heal = float(int32(healamount) + DoneTotal); + + // DOTs calculated in AuraEffect::HandlePeriodicHealAurasTick // Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods. - float heal = float(int32(healamount) + DoneTotal) * (damagetype == DOT ? 1.0f : SpellHealingPctDone(victim, spellProto)); - // apply spellmod to Done amount - if (Player* modOwner = GetSpellModOwner()) + if (damagetype != DOT) { - if (damagetype == DOT) - modOwner->ApplySpellMod<SPELLMOD_DOT>(spellProto->Id, heal); - else + heal *= SpellHealingPctDone(victim, spellProto); + + // apply spellmod to Done amount + if (Player* modOwner = GetSpellModOwner()) modOwner->ApplySpellMod<SPELLMOD_DAMAGE>(spellProto->Id, heal); } @@ -7857,18 +7881,18 @@ int32 Unit::SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) const return advertisedBenefit; } -bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask) const +bool Unit::IsImmunedToDamage(SpellSchoolMask schoolMask) const { // If m_immuneToSchool type contain this school type, IMMUNE damage. - SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; - for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr) - if (itr->type & shoolMask) + SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; + for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr) + if ((itr->first & schoolMask) != 0) return true; // If m_immuneToDamage type contain magic, IMMUNE damage. - SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE]; - for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr) - if (itr->type & shoolMask) + SpellImmuneContainer const& damageList = m_spellImmune[IMMUNITY_DAMAGE]; + for (auto itr = damageList.begin(); itr != damageList.end(); ++itr) + if ((itr->first & schoolMask) != 0) return true; return false; @@ -7876,23 +7900,27 @@ bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask) const bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const { - if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)) + if (!spellInfo) return false; - uint32 shoolMask = spellInfo->GetSchoolMask(); - if (spellInfo->Id != 42292 && spellInfo->Id != 59752) - { - // If m_immuneToSchool type contain this school type, IMMUNE damage. - SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; - for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr) - if (itr->type & shoolMask && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->spellId))) - return true; - } + // for example 40175 + if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) && spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT)) + return false; + + if (spellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) || spellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE)) + return false; + + uint32 schoolMask = spellInfo->GetSchoolMask(); + // If m_immuneToSchool type contain this school type, IMMUNE damage. + SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; + for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr) + if ((itr->first & schoolMask) && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->second))) + return true; // If m_immuneToDamage type contain magic, IMMUNE damage. - SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE]; - for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr) - if (itr->type & shoolMask) + SpellImmuneContainer const& damageList = m_spellImmune[IMMUNITY_DAMAGE]; + for (auto itr = damageList.begin(); itr != damageList.end(); ++itr) + if ((itr->first & schoolMask) != 0) return true; return false; @@ -7904,29 +7932,26 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const return false; // Single spell immunity. - SpellImmuneList const& idList = m_spellImmune[IMMUNITY_ID]; - for (SpellImmuneList::const_iterator itr = idList.begin(); itr != idList.end(); ++itr) - if (itr->type == spellInfo->Id) - return true; + SpellImmuneContainer const& idList = m_spellImmune[IMMUNITY_ID]; + if (idList.count(spellInfo->Id) > 0) + return true; if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)) return false; - if (spellInfo->Dispel) + if (uint32 dispel = spellInfo->Dispel) { - SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL]; - for (SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr) - if (itr->type == spellInfo->Dispel) - return true; + SpellImmuneContainer const& dispelList = m_spellImmune[IMMUNITY_DISPEL]; + if (dispelList.count(dispel) > 0) + return true; } // Spells that don't have effectMechanics. - if (spellInfo->Mechanic) + if (uint32 mechanic = spellInfo->Mechanic) { - SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; - for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) - if (itr->type == spellInfo->Mechanic) - return true; + SpellImmuneContainer const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; + if (mechanicList.count(mechanic) > 0) + return true; } bool immuneToAllEffects = true; @@ -7934,8 +7959,6 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const { // State/effect immunities applied by aura expect full spell immunity // Ignore effects with mechanic, they are supposed to be checked separately - if (!spellInfo->Effects[i].IsEffect()) - continue; if (!IsImmunedToSpellEffect(spellInfo, i)) { immuneToAllEffects = false; @@ -7946,13 +7969,13 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects. return true; - if (spellInfo->Id != 42292 && spellInfo->Id != 59752) + if (!spellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !spellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE)) { - SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; - for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr) + SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; + for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr) { - SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->spellId); - if ((itr->type & spellInfo->GetSchoolMask()) + SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second); + if ((itr->first & spellInfo->GetSchoolMask()) && !(immuneSpellInfo && immuneSpellInfo->IsPositive() && spellInfo->IsPositive()) && !spellInfo->CanPierceImmuneAura(immuneSpellInfo)) return true; @@ -7965,9 +7988,9 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const uint32 Unit::GetSchoolImmunityMask() const { uint32 mask = 0; - SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_SCHOOL]; - for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) - mask |= itr->type; + SpellImmuneContainer const& mechanicList = m_spellImmune[IMMUNITY_SCHOOL]; + for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) + mask |= itr->first; return mask; } @@ -7975,9 +7998,9 @@ uint32 Unit::GetSchoolImmunityMask() const uint32 Unit::GetMechanicImmunityMask() const { uint32 mask = 0; - SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; - for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) - mask |= (1 << itr->type); + SpellImmuneContainer const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; + for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) + mask |= (1 << itr->first); return mask; } @@ -7992,33 +8015,35 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons // If m_immuneToEffect type contain this effect type, IMMUNE effect. uint32 effect = spellInfo->Effects[index].Effect; - SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT]; - for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr) - if (itr->type == effect) - return true; + auto const& effectList = m_spellImmune[IMMUNITY_EFFECT]; + if (effectList.count(effect) > 0) + return true; if (uint32 mechanic = spellInfo->Effects[index].Mechanic) { - SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; - for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) - if (itr->type == mechanic) - return true; + auto const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; + if (mechanicList.count(mechanic) > 0) + return true; } - if (uint32 aura = spellInfo->Effects[index].ApplyAuraName) + if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT)) { - SpellImmuneList const& list = m_spellImmune[IMMUNITY_STATE]; - for (SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr) - if (itr->type == aura) - if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT)) - return true; - - // Check for immune to application of harmful magical effects - AuraEffectList const& immuneAuraApply = GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL); - for (AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter) - if (((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) && // Check school - !spellInfo->IsPositiveEffect(index)) // Harmful + if (uint32 aura = spellInfo->Effects[index].ApplyAuraName) + { + SpellImmuneContainer const& list = m_spellImmune[IMMUNITY_STATE]; + if (list.count(aura) > 0) return true; + + if (!spellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE)) + { + // Check for immune to application of harmful magical effects + AuraEffectList const& immuneAuraApply = GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL); + for (AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter) + if (((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) && // Check school + !spellInfo->IsPositiveEffect(index)) // Harmful + return true; + } + } } return false; @@ -8069,15 +8094,8 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType if (APbonus != 0) // Can be negative { - bool normalized = false; - if (spellProto) - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (spellProto->Effects[i].Effect == SPELL_EFFECT_NORMALIZED_WEAPON_DMG) - { - normalized = true; - break; - } - DoneFlatBenefit += int32(APbonus/14.0f * GetAPMultiplier(attType, normalized)); + bool const normalized = spellProto && spellProto->HasEffect(SPELL_EFFECT_NORMALIZED_WEAPON_DMG); + DoneFlatBenefit += int32(APbonus / 14.0f * GetAPMultiplier(attType, normalized)); } // Done total percent damage auras @@ -8085,22 +8103,23 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType // Some spells don't benefit from pct done mods if (spellProto) - if (!spellProto->HasAttribute(SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS)) + { + // mods for SPELL_SCHOOL_MASK_NORMAL are already factored in base melee damage calculation + if (!spellProto->HasAttribute(SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS) && !(spellProto->GetSchoolMask() & SPELL_SCHOOL_MASK_NORMAL)) { - AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i) + float maxModDamagePercentSchool = 0.0f; + if (GetTypeId() == TYPEID_PLAYER) { - if ((*i)->GetMiscValue() & spellProto->GetSchoolMask() && !(spellProto->GetSchoolMask() & SPELL_SCHOOL_MASK_NORMAL)) - { - if ((*i)->GetSpellInfo()->EquippedItemClass == -1) - AddPct(DoneTotalMod, (*i)->GetAmount()); - else if (!(*i)->GetSpellInfo()->HasAttribute(SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0)) - AddPct(DoneTotalMod, (*i)->GetAmount()); - else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellInfo())) - AddPct(DoneTotalMod, (*i)->GetAmount()); - } + for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) + if (spellProto->GetSchoolMask() & (1 << i)) + maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, GetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i)); } + else + maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, spellProto->GetSchoolMask()); + + DoneTotalMod *= maxModDamagePercentSchool; } + } AuraEffectList const& mDamageDoneVersus = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS); for (AuraEffectList::const_iterator i = mDamageDoneVersus.begin(); i != mDamageDoneVersus.end(); ++i) @@ -8324,52 +8343,14 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply) { if (apply) - { - for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next) - { - next = itr; ++next; - if (itr->type == type) - { - m_spellImmune[op].erase(itr); - next = m_spellImmune[op].begin(); - } - } - SpellImmune Immune; - Immune.spellId = spellId; - Immune.type = type; - m_spellImmune[op].push_back(Immune); - } + m_spellImmune[op].emplace(type, spellId); else { - for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr) - { - if (itr->spellId == spellId && itr->type == type) - { - m_spellImmune[op].erase(itr); - break; - } - } - } -} - -void Unit::ApplySpellDispelImmunity(const SpellInfo* spellProto, DispelType type, bool apply) -{ - ApplySpellImmune(spellProto->Id, IMMUNITY_DISPEL, type, apply); - - if (apply && spellProto->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)) - { - // Create dispel mask by dispel type - uint32 dispelMask = SpellInfo::GetDispelMask(type); - // Dispel all existing auras vs current dispel type - AuraApplicationMap& auras = GetAppliedAuras(); - for (AuraApplicationMap::iterator itr = auras.begin(); itr != auras.end();) + auto bounds = m_spellImmune[op].equal_range(type); + for (auto itr = bounds.first; itr != bounds.second;) { - SpellInfo const* spell = itr->second->GetBase()->GetSpellInfo(); - if (spell->GetDispelMask() & dispelMask) - { - // Dispel aura - RemoveAura(itr); - } + if (itr->second == spellId) + itr = m_spellImmune[op].erase(itr); else ++itr; } @@ -8687,9 +8668,26 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo || (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster())) 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))))) - return false; + // visibility checks + // skip visibility check for GO casts, needs removal when go cast is implemented. Also ignore for gameobject and dynauras + if (GetEntry() != WORLD_TRIGGER && (!obj || !obj->isType(TYPEMASK_GAMEOBJECT | TYPEMASK_DYNAMICOBJECT))) + { + // can't attack invisible + if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) + { + if (obj && !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea())) + return false; + else if (!obj) + { + // ignore stealth for aoe spells. Ignore stealth if target is player and unit in combat with same player + bool const ignoreStealthCheck = (bySpell && bySpell->IsAffectingArea()) || + (target->GetTypeId() == TYPEID_PLAYER && target->HasStealthAura() && target->IsInCombat() && IsInCombatWith(target)); + + if (!CanSeeOrDetect(target, ignoreStealthCheck)) + return false; + } + } + } // can't attack dead if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && !target->IsAlive()) @@ -8720,7 +8718,7 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo // PvP, PvC, CvP case // can't attack friendly targets - if ( GetReactionTo(target) > REP_NEUTRAL + if (GetReactionTo(target) > REP_NEUTRAL || target->GetReactionTo(this) > REP_NEUTRAL) return false; @@ -8728,10 +8726,8 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo Player const* playerAffectingTarget = target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) ? target->GetAffectingPlayer() : nullptr; // Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar) - if ( - (playerAffectingAttacker && !playerAffectingTarget) || - (!playerAffectingAttacker && playerAffectingTarget) - ) + if ((playerAffectingAttacker && !playerAffectingTarget) || + (!playerAffectingAttacker && playerAffectingTarget)) { Player const* player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget; Unit const* creature = playerAffectingAttacker ? target : this; @@ -8765,15 +8761,14 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo // additional checks - only PvP case if (playerAffectingAttacker && playerAffectingTarget) { - if (target->GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_PVP) + if (target->IsPvP()) return true; - if (GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_FFA_PVP - && target->GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_FFA_PVP) + if (IsFFAPvP() && target->IsFFAPvP()) return true; - return (GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_UNK1) - || (target->GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_UNK1); + return HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_UNK1) + || target->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_UNK1); } return true; } @@ -9760,9 +9755,6 @@ DiminishingLevels Unit::GetDiminishing(DiminishingGroup group) if (!diminish.hitCount) return DIMINISHING_LEVEL_1; - if (!diminish.hitTime) - return DIMINISHING_LEVEL_1; - // If last spell was cast more than 15 seconds ago - reset the count. if (!diminish.stack && GetMSTimeDiffToNow(diminish.hitTime) > 15000) { @@ -10799,14 +10791,13 @@ uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCond hitMask |= PROC_HIT_PARRY; break; case SPELL_MISS_BLOCK: - hitMask |= PROC_HIT_BLOCK; + // spells can't be partially blocked (it's damage can though) + hitMask |= PROC_HIT_BLOCK | PROC_HIT_FULL_BLOCK; break; case SPELL_MISS_EVADE: hitMask |= PROC_HIT_EVADE; break; case SPELL_MISS_IMMUNE: - hitMask |= PROC_HIT_IMMUNE; - break; case SPELL_MISS_IMMUNE2: hitMask |= PROC_HIT_IMMUNE; break; @@ -10819,6 +10810,9 @@ uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCond case SPELL_MISS_REFLECT: hitMask |= PROC_HIT_REFLECT; break; + case SPELL_MISS_RESIST: + hitMask |= PROC_HIT_FULL_RESIST; + break; default: break; } @@ -10827,15 +10821,27 @@ uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCond { // On block if (damageInfo->blocked) + { hitMask |= PROC_HIT_BLOCK; + if (damageInfo->fullBlock) + hitMask |= PROC_HIT_FULL_BLOCK; + } // On absorb if (damageInfo->absorb) hitMask |= PROC_HIT_ABSORB; - // On crit - if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT) - hitMask |= PROC_HIT_CRITICAL; - else - hitMask |= PROC_HIT_NORMAL; + + // Don't set hit/crit hitMask if damage is nullified + bool const damageNullified = (damageInfo->HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 || (hitMask & PROC_HIT_FULL_BLOCK) != 0; + if (!damageNullified) + { + // On crit + if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT) + hitMask |= PROC_HIT_CRITICAL; + else + hitMask |= PROC_HIT_NORMAL; + } + else if ((damageInfo->HitInfo & HITINFO_FULL_RESIST) != 0) + hitMask |= PROC_HIT_FULL_RESIST; } return hitMask; @@ -10924,7 +10930,7 @@ void Unit::GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTrigg for (AuraApplication* aurApp : *procAuras) { ASSERT(aurApp->GetTarget() == this); - if (uint8 procEffectMask = aurApp->GetBase()->IsProcTriggeredOnEvent(aurApp, eventInfo, now)) + if (uint8 procEffectMask = aurApp->GetBase()->GetProcEffectMask(aurApp, eventInfo, now)) { aurApp->GetBase()->PrepareProcToTrigger(aurApp, eventInfo, now); aurasTriggeringProc.emplace_back(procEffectMask, aurApp); @@ -10936,7 +10942,7 @@ void Unit::GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTrigg { for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr != GetAppliedAuras().end(); ++itr) { - if (uint8 procEffectMask = itr->second->GetBase()->IsProcTriggeredOnEvent(itr->second, eventInfo, now)) + if (uint8 procEffectMask = itr->second->GetBase()->GetProcEffectMask(itr->second, eventInfo, now)) { itr->second->GetBase()->PrepareProcToTrigger(itr->second, eventInfo, now); aurasTriggeringProc.emplace_back(procEffectMask, itr->second); @@ -10955,16 +10961,31 @@ void Unit::TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uin { // prepare data for self trigger ProcEventInfo myProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); - if (typeMaskActor && CanProc()) + if (typeMaskActor) { 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); } // prepare data for target trigger ProcEventInfo targetProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); - if (typeMaskActionTarget && actionTarget && actionTarget->CanProc()) + if (typeMaskActionTarget && actionTarget) { AuraApplicationProcContainer targetAurasTriggeringProc; actionTarget->GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, nullptr, targetProcEventInfo); @@ -10974,6 +10995,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; @@ -10992,6 +11018,9 @@ void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProc if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC)) SetCantProc(false); } + + if (disableProcs) + SetCantProc(false); } SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const @@ -11441,26 +11470,41 @@ float Unit::CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffect float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) { - if (!normalized || GetTypeId() != TYPEID_PLAYER) - return float(GetAttackTime(attType)) / 1000.0f; + if (GetTypeId() != TYPEID_PLAYER) + return GetAttackTime(attType) / 1000.0f; + + Item* weapon = ToPlayer()->GetWeaponForAttack(attType, true); + if (!weapon) + return BASE_ATTACK_TIME / 1000.0f; - Item* Weapon = ToPlayer()->GetWeaponForAttack(attType, true); - if (!Weapon) - return 2.4f; // fist attack + if (!normalized) + return weapon->GetTemplate()->Delay / 1000.0f; - switch (Weapon->GetTemplate()->InventoryType) + switch (weapon->GetTemplate()->SubClass) { - case INVTYPE_2HWEAPON: + case ITEM_SUBCLASS_WEAPON_AXE2: + case ITEM_SUBCLASS_WEAPON_MACE2: + case ITEM_SUBCLASS_WEAPON_POLEARM: + case ITEM_SUBCLASS_WEAPON_SWORD2: + case ITEM_SUBCLASS_WEAPON_STAFF: + case ITEM_SUBCLASS_WEAPON_FISHING_POLE: return 3.3f; - case INVTYPE_RANGED: - case INVTYPE_RANGEDRIGHT: - case INVTYPE_THROWN: + case ITEM_SUBCLASS_WEAPON_BOW: + case ITEM_SUBCLASS_WEAPON_GUN: + case ITEM_SUBCLASS_WEAPON_CROSSBOW: + case ITEM_SUBCLASS_WEAPON_THROWN: return 2.8f; - case INVTYPE_WEAPON: - case INVTYPE_WEAPONMAINHAND: - case INVTYPE_WEAPONOFFHAND: + case ITEM_SUBCLASS_WEAPON_AXE: + case ITEM_SUBCLASS_WEAPON_MACE: + case ITEM_SUBCLASS_WEAPON_SWORD: + case ITEM_SUBCLASS_WEAPON_EXOTIC: + case ITEM_SUBCLASS_WEAPON_EXOTIC2: + case ITEM_SUBCLASS_WEAPON_FIST: + return 2.4f; + case ITEM_SUBCLASS_WEAPON_DAGGER: + return 1.7f; default: - return Weapon->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER ? 1.7f : 2.4f; + return weapon->GetTemplate()->Delay / 1000.0f; } } @@ -12488,8 +12532,9 @@ bool Unit::IsInPartyWith(Unit const* unit) const else if ((u2->GetTypeId() == TYPEID_PLAYER && u1->GetTypeId() == TYPEID_UNIT && u1->ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT) || (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_UNIT && u2->ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT)) return true; - else - return false; + + // else u1->GetTypeId() == u2->GetTypeId() == TYPEID_UNIT + return u1->getFaction() == u2->getFaction(); } bool Unit::IsInRaidWith(Unit const* unit) const @@ -12507,8 +12552,9 @@ bool Unit::IsInRaidWith(Unit const* unit) const else if ((u2->GetTypeId() == TYPEID_PLAYER && u1->GetTypeId() == TYPEID_UNIT && u1->ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT) || (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_UNIT && u2->ToCreature()->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT)) return true; - else - return false; + + // else u1->GetTypeId() == u2->GetTypeId() == TYPEID_UNIT + return u1->getFaction() == u2->getFaction(); } void Unit::GetPartyMembers(std::list<Unit*> &TagUnitMap) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 20cdc75c001..917e5d24c79 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -377,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 { @@ -425,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 @@ -983,7 +983,7 @@ struct TC_GAME_API SpellNonMeleeDamage { SpellNonMeleeDamage(Unit* _attacker, Unit* _target, uint32 _SpellID, uint32 _schoolMask) : target(_target), attacker(_attacker), SpellID(_SpellID), damage(0), overkill(0), schoolMask(_schoolMask), - absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0) + absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0), fullBlock(false) { } Unit *target; @@ -1000,6 +1000,7 @@ struct TC_GAME_API SpellNonMeleeDamage uint32 HitInfo; // Used for help uint32 cleanDamage; + bool fullBlock; }; struct SpellPeriodicAuraLogInfo @@ -1433,7 +1434,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); } @@ -1560,19 +1561,19 @@ class TC_GAME_API Unit : public WorldObject int32 HealBySpell(HealInfo& healInfo, bool critical = false); void SendEnergizeSpellLog(Unit* victim, uint32 spellID, int32 damage, Powers powerType); void EnergizeBySpell(Unit* victim, uint32 SpellID, int32 Damage, Powers powertype); - uint32 SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage); - - void CastSpell(SpellCastTargets const& targets, SpellInfo const* spellInfo, CustomSpellValues const* value, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); - void CastSpell(Unit* victim, uint32 spellId, bool triggered, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); - void CastSpell(Unit* victim, uint32 spellId, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); - void CastSpell(Unit* victim, SpellInfo const* spellInfo, bool triggered, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); - void CastSpell(Unit* victim, SpellInfo const* spellInfo, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); - void CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); - void CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castItem = NULL, AuraEffect* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); - void CastCustomSpell(Unit* victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); - void CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* victim, bool triggered, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); - void CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* victim = NULL, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); - void CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit* victim = NULL, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty); + + void CastSpell(SpellCastTargets const& targets, SpellInfo const* spellInfo, CustomSpellValues const* value, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty); + void CastSpell(Unit* victim, uint32 spellId, bool triggered, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty); + void CastSpell(Unit* victim, uint32 spellId, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty); + void CastSpell(Unit* victim, SpellInfo const* spellInfo, bool triggered, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty); + void CastSpell(Unit* victim, SpellInfo const* spellInfo, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty); + void CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty); + void CastSpell(float x, float y, float z, uint32 spellId, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty); + void CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castItem = nullptr, AuraEffect* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty); + void CastCustomSpell(Unit* victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty); + void CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* victim, bool triggered, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty); + void CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* victim = nullptr, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty); + void CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit* victim = nullptr, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty); Aura* AddAura(uint32 spellId, Unit* target); Aura* AddAura(SpellInfo const* spellInfo, uint8 effMask, Unit* target); void SetAuraStack(uint32 spellId, Unit* target, uint32 stack); @@ -1936,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 @@ -2021,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; @@ -2033,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 21bb6261971..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; diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index df4788a0a1e..ac153f31b8e 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 NearestAttackableNoTotemUnitInObjectRangeCheck { public: - AnyUnfriendlyNoTotemUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) { } + NearestAttackableNoTotemUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) { } + bool operator()(Unit* u) { if (!u->IsAlive()) @@ -842,14 +855,19 @@ namespace Trinity if (u->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET) return false; - if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->IsTotem()) + if (u->GetTypeId() == TYPEID_UNIT && u->ToCreature()->IsTotem()) return false; if (!u->isTargetableForAttack(false)) return false; - return i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u); + if (!i_obj->IsWithinDistInMap(u, i_range) || !i_funit->_IsValidAttackTarget(u, nullptr, i_obj)) + return false; + + i_range = i_obj->GetDistance(*u); + return true; } + private: WorldObject const* i_obj; Unit const* i_funit; @@ -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; @@ -878,7 +898,8 @@ namespace Trinity { public: 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) + + bool operator()(Unit* u) const { if (G3D::fuzzyEq(_range, 0.0f)) return false; @@ -909,13 +930,15 @@ namespace Trinity { 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; @@ -926,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) && @@ -937,13 +961,14 @@ 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 @@ -952,17 +977,12 @@ namespace Trinity 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 (!_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()) @@ -973,8 +993,8 @@ namespace Trinity 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; @@ -986,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; @@ -1013,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)) @@ -1049,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)) @@ -1083,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; @@ -1114,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; @@ -1145,6 +1153,7 @@ namespace Trinity return true; } + private: Unit* const i_funit; Unit* const i_enemy; @@ -1173,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) @@ -1199,7 +1208,7 @@ namespace Trinity } return false; } - float GetLastRange() const { return i_range; } + private: WorldObject const& i_obj; uint32 i_entry; @@ -1207,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; @@ -1234,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) { @@ -1252,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; @@ -1300,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; } @@ -1370,7 +1389,8 @@ namespace Trinity { public: ObjectGUIDCheck(ObjectGuid GUID) : _GUID(GUID) { } - bool operator()(WorldObject* object) + + bool operator()(WorldObject* object) const { return object->GetGUID() == _GUID; } @@ -1383,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; @@ -1413,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/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index b95d2ed1981..84b2da9b2ea 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -29,10 +29,13 @@ #include "SocialMgr.h" #include "Opcodes.h" -#define MAX_GUILD_BANK_TAB_TEXT_LEN 500 -#define EMBLEM_PRICE 10 * GOLD -std::string _GetGuildEventString(GuildEvents event) +size_t const MAX_GUILD_BANK_TAB_TEXT_LEN = 500; + +uint32 const EMBLEM_PRICE = 10 * GOLD; + +// only used in logs +char const* GetGuildEventString(GuildEvents event) { switch (event) { @@ -82,18 +85,13 @@ std::string _GetGuildEventString(GuildEvents event) return "<None>"; } -inline uint32 _GetGuildBankTabPrice(uint8 tabId) +inline uint32 GetGuildBankTabPrice(uint8 tabId) { - switch (tabId) - { - case 0: return 100; - case 1: return 250; - case 2: return 500; - case 3: return 1000; - case 4: return 2500; - case 5: return 5000; - default: return 0; - } + // these prices are in gold units, not copper + static uint32 const tabPrices[GUILD_BANK_MAX_TABS] = { 100, 250, 500, 1000, 2500, 5000 }; + ASSERT(tabId < GUILD_BANK_MAX_TABS); + + return tabPrices[tabId]; } void Guild::SendCommandResult(WorldSession* session, GuildCommandType type, GuildCommandError errCode, std::string const& param) @@ -121,7 +119,7 @@ void Guild::SendSaveEmblemResult(WorldSession* session, GuildEmblemError errCode Guild::LogHolder::~LogHolder() { // Cleanup - for (GuildLog::iterator itr = m_log.begin(); itr != m_log.end(); ++itr) + for (auto itr = m_log.begin(); itr != m_log.end(); ++itr) delete (*itr); } @@ -154,7 +152,7 @@ inline void Guild::LogHolder::AddEvent(SQLTransaction& trans, LogEntry* entry) inline void Guild::LogHolder::WritePacket(WorldPacket& data) const { data << uint8(m_log.size()); - for (GuildLog::const_iterator itr = m_log.begin(); itr != m_log.end(); ++itr) + for (auto itr = m_log.begin(); itr != m_log.end(); ++itr) (*itr)->WritePacket(data); } @@ -175,7 +173,7 @@ void Guild::EventLogEntry::SaveToDB(SQLTransaction& trans) const PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_EVENTLOG); stmt->setUInt32(0, m_guildId); stmt->setUInt32(1, m_guid); - CharacterDatabase.ExecuteOrAppend(trans, stmt); + trans->Append(stmt); uint8 index = 0; stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_EVENTLOG); @@ -186,7 +184,7 @@ void Guild::EventLogEntry::SaveToDB(SQLTransaction& trans) const stmt->setUInt32(++index, m_playerGuid2); stmt->setUInt8 (++index, m_newRank); stmt->setUInt64(++index, m_timestamp); - CharacterDatabase.ExecuteOrAppend(trans, stmt); + trans->Append(stmt); } void Guild::EventLogEntry::WritePacket(WorldPacket& data) const @@ -202,7 +200,7 @@ void Guild::EventLogEntry::WritePacket(WorldPacket& data) const if (m_eventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || m_eventType == GUILD_EVENT_LOG_DEMOTE_PLAYER) data << uint8(m_newRank); // Event timestamp - data << uint32(::time(NULL) - m_timestamp); + data << uint32(::time(nullptr) - m_timestamp); } // BankEventLogEntry @@ -214,7 +212,7 @@ void Guild::BankEventLogEntry::SaveToDB(SQLTransaction& trans) const stmt->setUInt32( index, m_guildId); stmt->setUInt32(++index, m_guid); stmt->setUInt8 (++index, m_bankTabId); - CharacterDatabase.ExecuteOrAppend(trans, stmt); + trans->Append(stmt); index = 0; stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_BANK_EVENTLOG); @@ -227,7 +225,7 @@ void Guild::BankEventLogEntry::SaveToDB(SQLTransaction& trans) const stmt->setUInt16(++index, m_itemStackCount); stmt->setUInt8 (++index, m_destTabId); stmt->setUInt64(++index, m_timestamp); - CharacterDatabase.ExecuteOrAppend(trans, stmt); + trans->Append(stmt); } void Guild::BankEventLogEntry::WritePacket(WorldPacket& data) const @@ -252,7 +250,7 @@ void Guild::BankEventLogEntry::WritePacket(WorldPacket& data) const data << uint32(m_itemOrMoney); } - data << uint32(time(NULL) - m_timestamp); + data << uint32(time(nullptr) - m_timestamp); } // RankInfo @@ -434,14 +432,16 @@ bool Guild::BankTab::LoadItemFromDB(Field* fields) void Guild::BankTab::Delete(SQLTransaction& trans, bool removeItemsFromDB) { for (uint8 slotId = 0; slotId < GUILD_BANK_MAX_SLOTS; ++slotId) + { if (Item* pItem = m_items[slotId]) { pItem->RemoveFromWorld(); if (removeItemsFromDB) pItem->DeleteFromDB(trans); delete pItem; - pItem = NULL; + pItem = nullptr; } + } } inline void Guild::BankTab::WritePacket(WorldPacket& data) const @@ -491,12 +491,14 @@ bool Guild::BankTab::WriteSlotPacket(WorldPacket& data, uint8 slotId, bool ignor data << uint8(enchCount); // Number of enchantments for (uint32 i = PERM_ENCHANTMENT_SLOT; i < MAX_ENCHANTMENT_SLOT; ++i) + { if (uint32 enchId = pItem->GetEnchantmentId(EnchantmentSlot(i))) { data << uint8(i); data << uint32(enchId); ++enchCount; } + } data.put<uint8>(enchCountPos, enchCount); } return true; @@ -534,7 +536,7 @@ void Guild::BankTab::SetText(std::string const& text) } // Sets/removes contents of specified slot. -// If pItem == NULL contents are removed. +// If pItem == nullptr contents are removed. bool Guild::BankTab::SetItem(SQLTransaction& trans, uint8 slotId, Item* item) { if (slotId >= GUILD_BANK_MAX_SLOTS) @@ -546,7 +548,7 @@ bool Guild::BankTab::SetItem(SQLTransaction& trans, uint8 slotId, Item* item) stmt->setUInt32(0, m_guildId); stmt->setUInt8 (1, m_tabId); stmt->setUInt8 (2, slotId); - CharacterDatabase.ExecuteOrAppend(trans, stmt); + trans->Append(stmt); if (item) { @@ -555,13 +557,14 @@ bool Guild::BankTab::SetItem(SQLTransaction& trans, uint8 slotId, Item* item) stmt->setUInt8 (1, m_tabId); stmt->setUInt8 (2, slotId); stmt->setUInt32(3, item->GetGUID().GetCounter()); - CharacterDatabase.ExecuteOrAppend(trans, stmt); + trans->Append(stmt); item->SetGuidValue(ITEM_FIELD_CONTAINED, ObjectGuid::Empty); item->SetGuidValue(ITEM_FIELD_OWNER, ObjectGuid::Empty); item->FSetState(ITEM_NEW); item->SaveToDB(trans); // Not in inventory and can be saved standalone } + return true; } @@ -629,7 +632,7 @@ void Guild::Member::SetOfficerNote(std::string const& officerNote) CharacterDatabase.Execute(stmt); } -void Guild::Member::ChangeRank(uint8 newRank) +void Guild::Member::ChangeRank(SQLTransaction& trans, uint8 newRank) { m_rankId = newRank; @@ -640,7 +643,7 @@ void Guild::Member::ChangeRank(uint8 newRank) PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_MEMBER_RANK); stmt->setUInt8 (0, newRank); stmt->setUInt32(1, m_guid.GetCounter()); - CharacterDatabase.Execute(stmt); + CharacterDatabase.ExecuteOrAppend(trans, stmt); } void Guild::Member::SaveToDB(SQLTransaction& trans) const @@ -714,7 +717,7 @@ void Guild::Member::WritePacket(WorldPacket& data, bool sendOfficerNote) const << uint32(m_zoneId); if (!m_flags) - data << float(float(::time(NULL) - m_logoutTime) / DAY); + data << float(float(::time(nullptr) - m_logoutTime) / DAY); data << m_publicNote; @@ -839,7 +842,7 @@ void Guild::MoveItemData::LogAction(MoveItemData* pFrom) const inline void Guild::MoveItemData::CopySlots(SlotIds& ids) const { - for (ItemPosCountVec::const_iterator itr = m_vec.begin(); itr != m_vec.end(); ++itr) + for (auto itr = m_vec.begin(); itr != m_vec.end(); ++itr) ids.insert(uint8(itr->pos)); } @@ -853,16 +856,16 @@ bool Guild::PlayerMoveItemData::InitItem() if (m_pItem->IsNotEmptyBag()) { m_pPlayer->SendEquipError(EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS, m_pItem); - m_pItem = NULL; + m_pItem = nullptr; } // Bound items cannot be put into bank. else if (!m_pItem->CanBeTraded()) { m_pPlayer->SendEquipError(EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, m_pItem); - m_pItem = NULL; + m_pItem = nullptr; } } - return (m_pItem != NULL); + return (m_pItem != nullptr); } void Guild::PlayerMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* /*pOther*/, uint32 splitedAmount) @@ -877,7 +880,7 @@ void Guild::PlayerMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* { m_pPlayer->MoveItemFromInventory(m_container, m_slotId, true); m_pItem->DeleteFromInventoryDB(trans); - m_pItem = NULL; + m_pItem = nullptr; } } @@ -906,7 +909,7 @@ inline InventoryResult Guild::PlayerMoveItemData::CanStore(Item* pItem, bool swa bool Guild::BankMoveItemData::InitItem() { m_pItem = m_pGuild->_GetItem(m_container, m_slotId); - return (m_pItem != NULL); + return (m_pItem != nullptr); } bool Guild::BankMoveItemData::HasStoreRights(MoveItemData* pOther) const @@ -944,7 +947,7 @@ void Guild::BankMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* pO else { m_pGuild->_RemoveItem(trans, m_container, m_slotId); - m_pItem = NULL; + m_pItem = nullptr; } // Decrease amount of player's remaining items (if item is moved to different tab or to player) if (!pOther->IsBank() || pOther->GetContainer() != m_container) @@ -954,14 +957,14 @@ void Guild::BankMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* pO Item* Guild::BankMoveItemData::StoreItem(SQLTransaction& trans, Item* pItem) { if (!pItem) - return NULL; + return nullptr; BankTab* pTab = m_pGuild->GetBankTab(m_container); if (!pTab) - return NULL; + return nullptr; Item* pLastItem = pItem; - for (ItemPosCountVec::const_iterator itr = m_vec.begin(); itr != m_vec.end(); ) + for (auto itr = m_vec.begin(); itr != m_vec.end(); ) { ItemPosCount pos(*itr); ++itr; @@ -1025,7 +1028,7 @@ Item* Guild::BankMoveItemData::_StoreItem(SQLTransaction& trans, BankTab* pTab, if (pItem && pTab->SetItem(trans, slotId, pItem)) return pItem; - return NULL; + return nullptr; } // Tries to reserve space for source item. @@ -1065,10 +1068,10 @@ void Guild::BankMoveItemData::CanStoreItemInTab(Item* pItem, uint8 skipSlotId, b Item* pItemDest = m_pGuild->_GetItem(m_container, slotId); if (pItemDest == pItem) - pItemDest = NULL; + pItemDest = nullptr; // If merge skip empty, if not merge skip non-empty - if ((pItemDest != NULL) != merge) + if ((pItemDest != nullptr) != merge) continue; _ReserveSpace(slotId, pItem, pItemDest, count); @@ -1095,7 +1098,7 @@ InventoryResult Guild::BankMoveItemData::CanStore(Item* pItem, bool swap) Item* pItemDest = m_pGuild->_GetItem(m_container, m_slotId); // Ignore swapped item (this slot will be empty after move) if ((pItemDest == pItem) || swap) - pItemDest = NULL; + pItemDest = nullptr; if (!_ReserveSpace(m_slotId, pItem, pItemDest, count)) return EQUIP_ERR_ITEM_CANT_STACK; @@ -1128,30 +1131,30 @@ Guild::Guild(): m_createdDate(0), m_accountsNumber(0), m_bankMoney(0), - m_eventLog(NULL) + m_eventLog(nullptr) { memset(&m_bankEventLog, 0, (GUILD_BANK_MAX_TABS + 1) * sizeof(LogHolder*)); } Guild::~Guild() { - SQLTransaction temp(NULL); + SQLTransaction temp(nullptr); _DeleteBankItems(temp); // Cleanup delete m_eventLog; - m_eventLog = NULL; + m_eventLog = nullptr; for (uint8 tabId = 0; tabId <= GUILD_BANK_MAX_TABS; ++tabId) { delete m_bankEventLog[tabId]; - m_bankEventLog[tabId] = NULL; + m_bankEventLog[tabId] = nullptr; } - for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) { delete itr->second; - itr->second = NULL; + itr->second = nullptr; } } @@ -1172,7 +1175,7 @@ bool Guild::Create(Player* pLeader, std::string const& name) m_info = ""; m_motd = "No message set."; m_bankMoney = 0; - m_createdDate = ::time(NULL); + m_createdDate = ::time(nullptr); _CreateLogHolders(); TC_LOG_DEBUG("guild", "GUILD: creating guild [%s] for leader %s (%u)", @@ -1200,9 +1203,10 @@ bool Guild::Create(Player* pLeader, std::string const& name) stmt->setUInt64(++index, m_bankMoney); trans->Append(stmt); + _CreateDefaultGuildRanks(trans, pLeaderSession->GetSessionDbLocaleIndex()); // Create default ranks + bool ret = AddMember(trans, m_leaderGuid, GR_GUILDMASTER); // Add guildmaster + CharacterDatabase.CommitTransaction(trans); - _CreateDefaultGuildRanks(pLeaderSession->GetSessionDbLocaleIndex()); // Create default ranks - bool ret = AddMember(m_leaderGuid, GR_GUILDMASTER); // Add guildmaster if (ret) sScriptMgr->OnGuildCreate(this, pLeader, name); @@ -1217,15 +1221,15 @@ void Guild::Disband() sScriptMgr->OnGuildDisband(this); _BroadcastEvent(GE_DISBANDED, ObjectGuid::Empty); + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); // Remove all members while (!m_members.empty()) { - Members::const_iterator itr = m_members.begin(); - DeleteMember(itr->second->GetGUID(), true); + auto itr = m_members.begin(); + DeleteMember(trans, itr->second->GetGUID(), true); } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD); stmt->setUInt32(0, m_id); trans->Append(stmt); @@ -1313,10 +1317,10 @@ void Guild::HandleRoster(WorldSession* session) data << m_info; data << uint32(_GetRanksSize()); - for (Ranks::const_iterator ritr = m_ranks.begin(); ritr != m_ranks.end(); ++ritr) + for (auto ritr = m_ranks.begin(); ritr != m_ranks.end(); ++ritr) ritr->WritePacket(data); - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) itr->second->WritePacket(data, _HasRankRight(session->GetPlayer(), GR_RIGHT_VIEWOFFNOTE)); TC_LOG_DEBUG("guild", "SMSG_GUILD_ROSTER [%s]", session->GetPlayerInfo().c_str()); @@ -1420,7 +1424,9 @@ void Guild::HandleSetLeader(WorldSession* session, std::string const& name) if (Member* pNewLeader = GetMember(name)) { _SetLeaderGUID(pNewLeader); - pOldLeader->ChangeRank(GR_OFFICER); + + SQLTransaction trans(nullptr); + pOldLeader->ChangeRank(trans, GR_OFFICER); _BroadcastEvent(GE_LEADER_CHANGED, ObjectGuid::Empty, player->GetName().c_str(), name.c_str()); } } @@ -1436,11 +1442,8 @@ void Guild::HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string return; } - char aux[2]; - sprintf(aux, "%u", tabId); - tab->SetInfo(name, icon); - _BroadcastEvent(GE_BANK_TAB_UPDATED, ObjectGuid::Empty, aux, name.c_str(), icon.c_str()); + _BroadcastEvent(GE_BANK_TAB_UPDATED, ObjectGuid::Empty, std::to_string(tabId).c_str(), name.c_str(), icon.c_str()); } void Guild::HandleSetMemberNote(WorldSession* session, std::string const& name, std::string const& note, bool officer) @@ -1472,12 +1475,10 @@ void Guild::HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string c rankInfo->SetRights(rights); _SetRankBankMoneyPerDay(rankId, moneyPerDay); - for (GuildBankRightsAndSlotsVec::const_iterator itr = rightsAndSlots.begin(); itr != rightsAndSlots.end(); ++itr) + for (auto itr = rightsAndSlots.begin(); itr != rightsAndSlots.end(); ++itr) _SetRankBankTabRightsAndSlots(rankId, *itr); - char aux[2]; - sprintf(aux, "%u", rankId); - _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, aux, name.c_str()); + _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, std::to_string(rankId).c_str(), name.c_str()); } } @@ -1497,10 +1498,10 @@ void Guild::HandleBuyBankTab(WorldSession* session, uint8 tabId) if (tabId != _GetPurchasedTabsSize()) return; - uint32 tabCost = _GetGuildBankTabPrice(tabId) * GOLD; - if (!tabCost) + if (tabId >= GUILD_BANK_MAX_TABS) return; + uint32 tabCost = GetGuildBankTabPrice(tabId) * GOLD; if (!player->HasEnoughMoney(tabCost)) // Should not happen, this is checked by client return; @@ -1570,7 +1571,8 @@ void Guild::HandleAcceptMember(WorldSession* session) player->GetTeam() != sObjectMgr->GetPlayerTeamByGUID(GetLeaderGUID())) return; - AddMember(player->GetGUID()); + SQLTransaction trans(nullptr); + AddMember(trans, player->GetGUID()); } void Guild::HandleLeaveMember(WorldSession* session) @@ -1593,7 +1595,8 @@ void Guild::HandleLeaveMember(WorldSession* session) } else { - DeleteMember(player->GetGUID(), false, false); + SQLTransaction trans(nullptr); + DeleteMember(trans, player->GetGUID(), false, false); _LogEvent(GUILD_EVENT_LOG_LEAVE_GUILD, player->GetGUID().GetCounter()); _BroadcastEvent(GE_LEFT, player->GetGUID(), player->GetName().c_str()); @@ -1627,8 +1630,10 @@ void Guild::HandleRemoveMember(WorldSession* session, std::string const& name) else { ObjectGuid guid = member->GetGUID(); + // After call to DeleteMember pointer to member becomes invalid - DeleteMember(guid, false, true); + SQLTransaction trans(nullptr); + DeleteMember(trans, guid, false, true); _LogEvent(GUILD_EVENT_LOG_UNINVITE_PLAYER, player->GetGUID().GetCounter(), guid.GetCounter()); _BroadcastEvent(GE_REMOVED, ObjectGuid::Empty, name.c_str(), player->GetName().c_str()); } @@ -1682,7 +1687,8 @@ void Guild::HandleUpdateMemberRank(WorldSession* session, std::string const& nam } uint32 newRankId = member->GetRankId() + (demote ? 1 : -1); - member->ChangeRank(newRankId); + SQLTransaction trans(nullptr); + member->ChangeRank(trans, newRankId); _LogEvent(demote ? GUILD_EVENT_LOG_DEMOTE_PLAYER : GUILD_EVENT_LOG_PROMOTE_PLAYER, player->GetGUID().GetCounter(), member->GetGUID().GetCounter(), newRankId); _BroadcastEvent(demote ? GE_DEMOTION : GE_PROMOTION, ObjectGuid::Empty, player->GetName().c_str(), name.c_str(), _GetRankName(newRankId).c_str()); } @@ -1696,12 +1702,11 @@ void Guild::HandleAddNewRank(WorldSession* session, std::string const& name) // Only leader can add new rank if (_IsLeader(session->GetPlayer())) - if (_CreateRank(name, GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK)) - { - char aux[2]; - sprintf(aux, "%u", size); - _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, aux, name.c_str()); - } + { + SQLTransaction trans(nullptr); + if (_CreateRank(trans, name, GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK)) + _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, std::to_string(size).c_str(), name.c_str()); + } } void Guild::HandleRemoveLowestRank(WorldSession* session) @@ -1973,10 +1978,11 @@ void Guild::LoadRankFromDB(Field* fields) bool Guild::LoadMemberFromDB(Field* fields) { ObjectGuid::LowType lowguid = fields[1].GetUInt32(); - Member *member = new Member(m_id, ObjectGuid(HighGuid::Player, lowguid), fields[2].GetUInt8()); + Member* member = new Member(m_id, ObjectGuid(HighGuid::Player, lowguid), fields[2].GetUInt8()); if (!member->LoadFromDB(fields)) { - _DeleteMemberFromDB(lowguid); + SQLTransaction trans(nullptr); + _DeleteMemberFromDB(trans, lowguid); delete member; return false; } @@ -2080,6 +2086,8 @@ bool Guild::Validate() // Min ranks count is 5 and max is 10. bool broken_ranks = false; uint8 ranks = _GetRanksSize(); + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (ranks < GUILD_RANKS_MIN_COUNT || ranks > GUILD_RANKS_MAX_COUNT) { TC_LOG_ERROR("guild", "Guild %u has invalid number of ranks, creating new...", m_id); @@ -2096,24 +2104,20 @@ bool Guild::Validate() broken_ranks = true; } else - { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); rankInfo->CreateMissingTabsIfNeeded(_GetPurchasedTabsSize(), trans, true); - CharacterDatabase.CommitTransaction(trans); - } } } if (broken_ranks) { m_ranks.clear(); - _CreateDefaultGuildRanks(DEFAULT_LOCALE); + _CreateDefaultGuildRanks(trans, DEFAULT_LOCALE); } // Validate members' data - for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) if (itr->second->GetRankId() > _GetRanksSize()) - itr->second->ChangeRank(_GetLowestRankId()); + itr->second->ChangeRank(trans, _GetLowestRankId()); // Repair the structure of the guild. // If the guildmaster doesn't exist or isn't member of the guild @@ -2121,7 +2125,8 @@ bool Guild::Validate() Member* pLeader = GetMember(m_leaderGuid); if (!pLeader) { - DeleteMember(m_leaderGuid); + SQLTransaction trans(nullptr); + DeleteMember(trans, m_leaderGuid); // If no more members left, disband guild if (m_members.empty()) { @@ -2134,10 +2139,12 @@ bool Guild::Validate() // Check config if multiple guildmasters are allowed if (!sConfigMgr->GetBoolDefault("Guild.AllowMultipleGuildMaster", 0)) - for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) if (itr->second->GetRankId() == GR_GUILDMASTER && !itr->second->IsSamePlayer(m_leaderGuid)) - itr->second->ChangeRank(GR_OFFICER); + itr->second->ChangeRank(trans, GR_OFFICER); + if (trans->GetSize() > 0) + CharacterDatabase.CommitTransaction(trans); _UpdateAccountsNumber(); return true; } @@ -2148,8 +2155,8 @@ void Guild::BroadcastToGuild(WorldSession* session, bool officerOnly, std::strin if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK)) { WorldPacket data; - ChatHandler::BuildChatPacket(data, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), NULL, msg); - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + ChatHandler::BuildChatPacket(data, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), nullptr, msg); + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) if (Player* player = itr->second->FindConnectedPlayer()) if (player->GetSession() && _HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) && !player->GetSocial()->HasIgnore(session->GetPlayer()->GetGUID().GetCounter())) @@ -2159,7 +2166,7 @@ void Guild::BroadcastToGuild(WorldSession* session, bool officerOnly, std::strin void Guild::BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const { - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) if (itr->second->IsRank(rankId)) if (Player* player = itr->second->FindConnectedPlayer()) player->GetSession()->SendPacket(packet); @@ -2167,7 +2174,7 @@ void Guild::BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const void Guild::BroadcastPacket(WorldPacket* packet) const { - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) if (Player* player = itr->second->FindPlayer()) player->GetSession()->SendPacket(packet); } @@ -2179,7 +2186,7 @@ void Guild::MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 max WorldPacket data(SMSG_CALENDAR_FILTER_GUILD); data << uint32(count); // count placeholder - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) { // not sure if needed, maybe client checks it as well if (count >= CALENDAR_MAX_INVITES) @@ -2206,7 +2213,7 @@ void Guild::MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 max } // Members handling -bool Guild::AddMember(ObjectGuid guid, uint8 rankId) +bool Guild::AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId) { Player* player = ObjectAccessor::FindConnectedPlayer(guid); // Player cannot be in guild @@ -2269,7 +2276,6 @@ bool Guild::AddMember(ObjectGuid guid, uint8 rankId) m_members[lowguid] = member; } - SQLTransaction trans(NULL); member->SaveToDB(trans); _UpdateAccountsNumber(); @@ -2282,7 +2288,7 @@ bool Guild::AddMember(ObjectGuid guid, uint8 rankId) return true; } -void Guild::DeleteMember(ObjectGuid guid, bool isDisbanding, bool isKicked, bool canDeleteGuild) +void Guild::DeleteMember(SQLTransaction& trans, ObjectGuid guid, bool isDisbanding, bool isKicked, bool canDeleteGuild) { ObjectGuid::LowType lowguid = guid.GetCounter(); Player* player = ObjectAccessor::FindConnectedPlayer(guid); @@ -2291,9 +2297,9 @@ void Guild::DeleteMember(ObjectGuid guid, bool isDisbanding, bool isKicked, bool // or when he is removed from guild by gm command if (m_leaderGuid == guid && !isDisbanding) { - Member* oldLeader = NULL; - Member* newLeader = NULL; - for (Guild::Members::iterator i = m_members.begin(); i != m_members.end(); ++i) + Member* oldLeader = nullptr; + Member* newLeader = nullptr; + for (auto i = m_members.begin(); i != m_members.end(); ++i) { if (i->first == lowguid) oldLeader = i->second; @@ -2336,19 +2342,22 @@ void Guild::DeleteMember(ObjectGuid guid, bool isDisbanding, bool isKicked, bool player->SetRank(0); } - _DeleteMemberFromDB(lowguid); + _DeleteMemberFromDB(trans, lowguid); if (!isDisbanding) _UpdateAccountsNumber(); } -bool Guild::ChangeMemberRank(ObjectGuid guid, uint8 newRank) +bool Guild::ChangeMemberRank(SQLTransaction& trans, ObjectGuid guid, uint8 newRank) { if (newRank <= _GetLowestRankId()) // Validate rank (allow only existing ranks) + { if (Member* member = GetMember(guid)) { - member->ChangeRank(newRank); + member->ChangeRank(trans, newRank); return true; } + } + return false; } @@ -2386,7 +2395,7 @@ void Guild::SetBankTabText(uint8 tabId, std::string const& text) if (BankTab* pTab = GetBankTab(tabId)) { pTab->SetText(text); - pTab->SendText(this, NULL); + pTab->SendText(this, nullptr); } } @@ -2416,30 +2425,32 @@ void Guild::_CreateNewBankTab() trans->Append(stmt); ++tabId; - for (Ranks::iterator itr = m_ranks.begin(); itr != m_ranks.end(); ++itr) + for (auto itr = m_ranks.begin(); itr != m_ranks.end(); ++itr) (*itr).CreateMissingTabsIfNeeded(tabId, trans, false); CharacterDatabase.CommitTransaction(trans); } -void Guild::_CreateDefaultGuildRanks(LocaleConstant loc) +void Guild::_CreateDefaultGuildRanks(SQLTransaction& trans, LocaleConstant loc) { + ASSERT(trans); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_RANKS); stmt->setUInt32(0, m_id); - CharacterDatabase.Execute(stmt); + trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_RIGHTS); stmt->setUInt32(0, m_id); - CharacterDatabase.Execute(stmt); + trans->Append(stmt); - _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_MASTER, loc), GR_RIGHT_ALL); - _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_OFFICER, loc), GR_RIGHT_ALL); - _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_VETERAN, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); - _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_MEMBER, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); - _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_INITIATE, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_MASTER, loc), GR_RIGHT_ALL); + _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_OFFICER, loc), GR_RIGHT_ALL); + _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_VETERAN, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_MEMBER, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_INITIATE, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); } -bool Guild::_CreateRank(std::string const& name, uint32 rights) +bool Guild::_CreateRank(SQLTransaction& trans, std::string const& name, uint32 rights) { uint8 newRankId = _GetRanksSize(); if (newRankId >= GUILD_RANKS_MAX_COUNT) @@ -2449,10 +2460,15 @@ bool Guild::_CreateRank(std::string const& name, uint32 rights) RankInfo info(m_id, newRankId, name, rights, 0); m_ranks.push_back(info); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + bool const isInTransaction = bool(trans); + if (!isInTransaction) + trans = CharacterDatabase.BeginTransaction(); + info.CreateMissingTabsIfNeeded(_GetPurchasedTabsSize(), trans); info.SaveToDB(trans); - CharacterDatabase.CommitTransaction(trans); + + if (!isInTransaction) + CharacterDatabase.CommitTransaction(trans); return true; } @@ -2463,7 +2479,7 @@ void Guild::_UpdateAccountsNumber() { // We use a set to be sure each element will be unique std::set<uint32> accountsIdSet; - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) accountsIdSet.insert(itr->second->GetAccountId()); m_accountsNumber = accountsIdSet.size(); @@ -2487,7 +2503,7 @@ void Guild::_DeleteBankItems(SQLTransaction& trans, bool removeItemsFromDB) { m_bankTabs[tabId]->Delete(trans, removeItemsFromDB); delete m_bankTabs[tabId]; - m_bankTabs[tabId] = NULL; + m_bankTabs[tabId] = nullptr; } m_bankTabs.clear(); } @@ -2516,13 +2532,16 @@ void Guild::_SetLeaderGUID(Member* pLeader) if (!pLeader) return; + SQLTransaction trans = CharacterDatabase.BeginTransaction(); m_leaderGuid = pLeader->GetGUID(); - pLeader->ChangeRank(GR_GUILDMASTER); + pLeader->ChangeRank(trans, GR_GUILDMASTER); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_LEADER); stmt->setUInt32(0, m_leaderGuid.GetCounter()); stmt->setUInt32(1, m_id); - CharacterDatabase.Execute(stmt); + trans->Append(stmt); + + CharacterDatabase.CommitTransaction(trans); } void Guild::_SetRankBankMoneyPerDay(uint8 rankId, uint32 moneyPerDay) @@ -2670,13 +2689,13 @@ inline Item* Guild::_GetItem(uint8 tabId, uint8 slotId) const { if (const BankTab* tab = GetBankTab(tabId)) return tab->GetItem(slotId); - return NULL; + return nullptr; } inline void Guild::_RemoveItem(SQLTransaction& trans, uint8 tabId, uint8 slotId) { if (BankTab* pTab = GetBankTab(tabId)) - pTab->SetItem(trans, slotId, NULL); + pTab->SetItem(trans, slotId, nullptr); } void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAmount) @@ -2717,7 +2736,7 @@ void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAm } else // 6. No split { - // 6.1. Try to merge items in destination (pDest->GetItem() == NULL) + // 6.1. Try to merge items in destination (pDest->GetItem() == nullptr) if (!_DoItemsMove(pSrc, pDest, false)) // Item could not be merged { // 6.2. Try to swap items @@ -2732,7 +2751,7 @@ void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAm if (!pDest->HasWithdrawRights(pSrc)) return; // Player has no rights to withdraw item from destination (opposite direction) - // 6.2.3. Swap items (pDest->GetItem() != NULL) + // 6.2.3. Swap items (pDest->GetItem() != nullptr) _DoItemsMove(pSrc, pDest, true); } } @@ -2743,7 +2762,7 @@ void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAm bool Guild::_DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError, uint32 splitedAmount) { Item* pDestItem = pDest->GetItem(); - bool swap = (pDestItem != NULL); + bool swap = (pDestItem != nullptr); Item* pSrcItem = pSrc->GetItem(splitedAmount != 0); // 1. Can store source item in destination @@ -2832,7 +2851,7 @@ void Guild::_SendBankContentUpdate(MoveItemData* pSrc, MoveItemData* pDest) cons void Guild::_SendBankContentUpdate(uint8 tabId, SlotIds slots) const { - _SendBankList(NULL, tabId, false, &slots); + _SendBankList(nullptr, tabId, false, &slots); } void Guild::_BroadcastEvent(GuildEvents guildEvent, ObjectGuid guid, const char* param1, const char* param2, const char* param3) const @@ -2855,10 +2874,10 @@ void Guild::_BroadcastEvent(GuildEvents guildEvent, ObjectGuid guid, const char* BroadcastPacket(&data); - TC_LOG_DEBUG("guild", "SMSG_GUILD_EVENT [Broadcast] Event: %s (%u)", _GetGuildEventString(guildEvent).c_str(), guildEvent); + TC_LOG_DEBUG("guild", "SMSG_GUILD_EVENT [Broadcast] Event: %s (%u)", GetGuildEventString(guildEvent), guildEvent); } -void Guild::_SendBankList(WorldSession* session /* = NULL*/, uint8 tabId /*= 0*/, bool sendAllSlots /*= false*/, SlotIds *slots /*= NULL*/) const +void Guild::_SendBankList(WorldSession* session /* = nullptr*/, uint8 tabId /*= 0*/, bool sendAllSlots /*= false*/, SlotIds *slots /*= nullptr*/) const { WorldPacket data(SMSG_GUILD_BANK_LIST, 500); data << uint64(m_bankMoney); @@ -2882,7 +2901,7 @@ void Guild::_SendBankList(WorldSession* session /* = NULL*/, uint8 tabId /*= 0*/ else if (slots && !slots->empty()) { data << uint8(slots->size()); - for (SlotIds::const_iterator itr = slots->begin(); itr != slots->end(); ++itr) + for (auto itr = slots->begin(); itr != slots->end(); ++itr) tab->WriteSlotPacket(data, *itr, false); } else @@ -2900,7 +2919,7 @@ void Guild::_SendBankList(WorldSession* session /* = NULL*/, uint8 tabId /*= 0*/ } else /// @todo - Probably this is just sent to session + those that have sent CMSG_GUILD_BANKER_ACTIVATE { - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) { if (!_MemberHasTabRights(itr->second->GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB)) continue; @@ -2919,7 +2938,7 @@ void Guild::_SendBankList(WorldSession* session /* = NULL*/, uint8 tabId /*= 0*/ void Guild::ResetTimes() { - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) itr->second->ResetValues(); _BroadcastEvent(GE_BANK_TAB_AND_MONEY_UPDATED, ObjectGuid::Empty); diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index e25a3201957..742923f51a1 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -225,54 +225,54 @@ enum GuildMemberFlags // Emblem info class TC_GAME_API EmblemInfo { -public: - EmblemInfo() : m_style(0), m_color(0), m_borderStyle(0), m_borderColor(0), m_backgroundColor(0) { } - - void LoadFromDB(Field* fields); - void SaveToDB(ObjectGuid::LowType guildId) const; - void ReadPacket(WorldPacket& recv); - void WritePacket(WorldPacket& data) const; - - uint32 GetStyle() const { return m_style; } - uint32 GetColor() const { return m_color; } - uint32 GetBorderStyle() const { return m_borderStyle; } - uint32 GetBorderColor() const { return m_borderColor; } - uint32 GetBackgroundColor() const { return m_backgroundColor; } - -private: - uint32 m_style; - uint32 m_color; - uint32 m_borderStyle; - uint32 m_borderColor; - uint32 m_backgroundColor; + public: + EmblemInfo() : m_style(0), m_color(0), m_borderStyle(0), m_borderColor(0), m_backgroundColor(0) { } + + void LoadFromDB(Field* fields); + void SaveToDB(ObjectGuid::LowType guildId) const; + void ReadPacket(WorldPacket& recv); + void WritePacket(WorldPacket& data) const; + + uint32 GetStyle() const { return m_style; } + uint32 GetColor() const { return m_color; } + uint32 GetBorderStyle() const { return m_borderStyle; } + uint32 GetBorderColor() const { return m_borderColor; } + uint32 GetBackgroundColor() const { return m_backgroundColor; } + + private: + uint32 m_style; + uint32 m_color; + uint32 m_borderStyle; + uint32 m_borderColor; + uint32 m_backgroundColor; }; // Structure for storing guild bank rights and remaining slots together. class GuildBankRightsAndSlots { -public: - GuildBankRightsAndSlots() : tabId(TAB_UNDEFINED), rights(0), slots(0) { } - GuildBankRightsAndSlots(uint8 _tabId) : tabId(_tabId), rights(0), slots(0) { } - GuildBankRightsAndSlots(uint8 _tabId, uint8 _rights, uint32 _slots) : tabId(_tabId), rights(_rights), slots(_slots) { } - - void SetGuildMasterValues() - { - rights = GUILD_BANK_RIGHT_FULL; - slots = uint32(GUILD_WITHDRAW_SLOT_UNLIMITED); - } - - void SetTabId(uint8 _tabId) { tabId = _tabId; } - void SetSlots(uint32 _slots) { slots = _slots; } - void SetRights(uint8 _rights) { rights = _rights; } - - int8 GetTabId() const { return tabId; } - int32 GetSlots() const { return slots; } - int8 GetRights() const { return rights; } - -private: - uint8 tabId; - uint8 rights; - uint32 slots; + public: + GuildBankRightsAndSlots() : tabId(TAB_UNDEFINED), rights(0), slots(0) { } + GuildBankRightsAndSlots(uint8 _tabId) : tabId(_tabId), rights(0), slots(0) { } + GuildBankRightsAndSlots(uint8 _tabId, uint8 _rights, uint32 _slots) : tabId(_tabId), rights(_rights), slots(_slots) { } + + void SetGuildMasterValues() + { + rights = GUILD_BANK_RIGHT_FULL; + slots = uint32(GUILD_WITHDRAW_SLOT_UNLIMITED); + } + + void SetTabId(uint8 _tabId) { tabId = _tabId; } + void SetSlots(uint32 _slots) { slots = _slots; } + void SetRights(uint8 _rights) { rights = _rights; } + + int8 GetTabId() const { return tabId; } + int32 GetSlots() const { return slots; } + int8 GetRights() const { return rights; } + + private: + uint8 tabId; + uint8 rights; + uint32 slots; }; typedef std::vector <GuildBankRightsAndSlots> GuildBankRightsAndSlotsVec; @@ -281,577 +281,577 @@ typedef std::set <uint8> SlotIds; class TC_GAME_API Guild { -private: - // Class representing guild member - class Member - { - public: - Member(ObjectGuid::LowType guildId, ObjectGuid guid, uint8 rankId) : - m_guildId(guildId), - m_guid(guid), - m_zoneId(0), - m_level(0), - m_class(0), - m_flags(GUILDMEMBER_STATUS_NONE), - m_logoutTime(::time(NULL)), - m_accountId(0), - m_rankId(rankId) + private: + // Class representing guild member + class Member { - memset(m_bankWithdraw, 0, (GUILD_BANK_MAX_TABS + 1) * sizeof(int32)); - } - - void SetStats(Player* player); - void SetStats(std::string const& name, uint8 level, uint8 _class, uint32 zoneId, uint32 accountId); - bool CheckStats() const; + public: + Member(ObjectGuid::LowType guildId, ObjectGuid guid, uint8 rankId) : + m_guildId(guildId), + m_guid(guid), + m_zoneId(0), + m_level(0), + m_class(0), + m_flags(GUILDMEMBER_STATUS_NONE), + m_logoutTime(::time(nullptr)), + m_accountId(0), + m_rankId(rankId) + { + memset(m_bankWithdraw, 0, (GUILD_BANK_MAX_TABS + 1) * sizeof(int32)); + } + + void SetStats(Player* player); + void SetStats(std::string const& name, uint8 level, uint8 _class, uint32 zoneId, uint32 accountId); + bool CheckStats() const; + + void SetPublicNote(std::string const& publicNote); + void SetOfficerNote(std::string const& officerNote); + void SetZoneID(uint32 id) { m_zoneId = id; } + void SetLevel(uint8 var) { m_level = var; } + + void AddFlag(uint8 var) { m_flags |= var; } + void RemFlag(uint8 var) { m_flags &= ~var; } + void ResetFlags() { m_flags = GUILDMEMBER_STATUS_NONE; } + + bool LoadFromDB(Field* fields); + void SaveToDB(SQLTransaction& trans) const; + void WritePacket(WorldPacket& data, bool sendOfficerNote) const; + + ObjectGuid GetGUID() const { return m_guid; } + std::string const& GetName() const { return m_name; } + uint32 GetAccountId() const { return m_accountId; } + uint8 GetRankId() const { return m_rankId; } + uint64 GetLogoutTime() const { return m_logoutTime; } + std::string GetPublicNote() const { return m_publicNote; } + std::string GetOfficerNote() const { return m_officerNote; } + uint8 GetClass() const { return m_class; } + uint8 GetLevel() const { return m_level; } + uint8 GetFlags() const { return m_flags; } + uint32 GetZoneId() const { return m_zoneId; } + bool IsOnline() const { return (m_flags & GUILDMEMBER_STATUS_ONLINE); } + + void ChangeRank(SQLTransaction& trans, uint8 newRank); + + inline void UpdateLogoutTime() { m_logoutTime = ::time(nullptr); } + inline bool IsRank(uint8 rankId) const { return m_rankId == rankId; } + inline bool IsRankNotLower(uint8 rankId) const { return m_rankId <= rankId; } + inline bool IsSamePlayer(ObjectGuid guid) const { return m_guid == guid; } + + void UpdateBankWithdrawValue(SQLTransaction& trans, uint8 tabId, uint32 amount); + int32 GetBankWithdrawValue(uint8 tabId) const; + void ResetValues(); + + inline Player* FindPlayer() const { return ObjectAccessor::FindPlayer(m_guid); } + inline Player* FindConnectedPlayer() const { return ObjectAccessor::FindConnectedPlayer(m_guid); } + + private: + ObjectGuid::LowType m_guildId; + // Fields from characters table + ObjectGuid m_guid; + std::string m_name; + uint32 m_zoneId; + uint8 m_level; + uint8 m_class; + uint8 m_flags; + uint64 m_logoutTime; + uint32 m_accountId; + // Fields from guild_member table + uint8 m_rankId; + std::string m_publicNote; + std::string m_officerNote; + + int32 m_bankWithdraw[GUILD_BANK_MAX_TABS + 1]; + }; + + // Base class for event entries + class LogEntry + { + public: + LogEntry(ObjectGuid::LowType guildId, uint32 guid) : m_guildId(guildId), m_guid(guid), m_timestamp(::time(nullptr)) { } + LogEntry(ObjectGuid::LowType guildId, uint32 guid, time_t timestamp) : m_guildId(guildId), m_guid(guid), m_timestamp(timestamp) { } + virtual ~LogEntry() { } - void SetPublicNote(std::string const& publicNote); - void SetOfficerNote(std::string const& officerNote); - void SetZoneID(uint32 id) { m_zoneId = id; } - void SetLevel(uint8 var) { m_level = var; } + uint32 GetGUID() const { return m_guid; } + uint64 GetTimestamp() const { return m_timestamp; } - void AddFlag(uint8 var) { m_flags |= var; } - void RemFlag(uint8 var) { m_flags &= ~var; } - void ResetFlags() { m_flags = GUILDMEMBER_STATUS_NONE; } + virtual void SaveToDB(SQLTransaction& trans) const = 0; + virtual void WritePacket(WorldPacket& data) const = 0; - bool LoadFromDB(Field* fields); - void SaveToDB(SQLTransaction& trans) const; - void WritePacket(WorldPacket& data, bool sendOfficerNote) const; + protected: + ObjectGuid::LowType m_guildId; + uint32 m_guid; + uint64 m_timestamp; + }; - ObjectGuid GetGUID() const { return m_guid; } - std::string const& GetName() const { return m_name; } - uint32 GetAccountId() const { return m_accountId; } - uint8 GetRankId() const { return m_rankId; } - uint64 GetLogoutTime() const { return m_logoutTime; } - std::string GetPublicNote() const { return m_publicNote; } - std::string GetOfficerNote() const { return m_officerNote; } - uint8 GetClass() const { return m_class; } - uint8 GetLevel() const { return m_level; } - uint8 GetFlags() const { return m_flags; } - uint32 GetZoneId() const { return m_zoneId; } - bool IsOnline() const { return (m_flags & GUILDMEMBER_STATUS_ONLINE); } - - void ChangeRank(uint8 newRank); - - inline void UpdateLogoutTime() { m_logoutTime = ::time(NULL); } - inline bool IsRank(uint8 rankId) const { return m_rankId == rankId; } - inline bool IsRankNotLower(uint8 rankId) const { return m_rankId <= rankId; } - inline bool IsSamePlayer(ObjectGuid guid) const { return m_guid == guid; } - - void UpdateBankWithdrawValue(SQLTransaction& trans, uint8 tabId, uint32 amount); - int32 GetBankWithdrawValue(uint8 tabId) const; - void ResetValues(); - - inline Player* FindPlayer() const { return ObjectAccessor::FindPlayer(m_guid); } - inline Player* FindConnectedPlayer() const { return ObjectAccessor::FindConnectedPlayer(m_guid); } + // Event log entry + class EventLogEntry : public LogEntry + { + public: + EventLogEntry(ObjectGuid::LowType guildId, uint32 guid, GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank) : + LogEntry(guildId, guid), m_eventType(eventType), m_playerGuid1(playerGuid1), m_playerGuid2(playerGuid2), m_newRank(newRank) { } - private: - ObjectGuid::LowType m_guildId; - // Fields from characters table - ObjectGuid m_guid; - std::string m_name; - uint32 m_zoneId; - uint8 m_level; - uint8 m_class; - uint8 m_flags; - uint64 m_logoutTime; - uint32 m_accountId; - // Fields from guild_member table - uint8 m_rankId; - std::string m_publicNote; - std::string m_officerNote; - - int32 m_bankWithdraw[GUILD_BANK_MAX_TABS + 1]; - }; - - // Base class for event entries - class LogEntry - { - public: - LogEntry(ObjectGuid::LowType guildId, uint32 guid) : m_guildId(guildId), m_guid(guid), m_timestamp(::time(NULL)) { } - LogEntry(ObjectGuid::LowType guildId, uint32 guid, time_t timestamp) : m_guildId(guildId), m_guid(guid), m_timestamp(timestamp) { } - virtual ~LogEntry() { } + EventLogEntry(ObjectGuid::LowType guildId, uint32 guid, time_t timestamp, GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank) : + LogEntry(guildId, guid, timestamp), m_eventType(eventType), m_playerGuid1(playerGuid1), m_playerGuid2(playerGuid2), m_newRank(newRank) { } - uint32 GetGUID() const { return m_guid; } - uint64 GetTimestamp() const { return m_timestamp; } + ~EventLogEntry() { } - virtual void SaveToDB(SQLTransaction& trans) const = 0; - virtual void WritePacket(WorldPacket& data) const = 0; + void SaveToDB(SQLTransaction& trans) const override; + void WritePacket(WorldPacket& data) const override; - protected: - ObjectGuid::LowType m_guildId; - uint32 m_guid; - uint64 m_timestamp; - }; - - // Event log entry - class EventLogEntry : public LogEntry - { - public: - EventLogEntry(ObjectGuid::LowType guildId, uint32 guid, GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank) : - LogEntry(guildId, guid), m_eventType(eventType), m_playerGuid1(playerGuid1), m_playerGuid2(playerGuid2), m_newRank(newRank) { } + private: + GuildEventLogTypes m_eventType; + ObjectGuid::LowType m_playerGuid1; + ObjectGuid::LowType m_playerGuid2; + uint8 m_newRank; + }; - EventLogEntry(ObjectGuid::LowType guildId, uint32 guid, time_t timestamp, GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank) : - LogEntry(guildId, guid, timestamp), m_eventType(eventType), m_playerGuid1(playerGuid1), m_playerGuid2(playerGuid2), m_newRank(newRank) { } + // Bank event log entry + class BankEventLogEntry : public LogEntry + { + public: + static bool IsMoneyEvent(GuildBankEventLogTypes eventType) + { + return + eventType == GUILD_BANK_LOG_DEPOSIT_MONEY || + eventType == GUILD_BANK_LOG_WITHDRAW_MONEY || + eventType == GUILD_BANK_LOG_REPAIR_MONEY; + } + + BankEventLogEntry(ObjectGuid::LowType guildId, uint32 guid, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) : + LogEntry(guildId, guid), m_eventType(eventType), m_bankTabId(tabId), m_playerGuid(playerGuid), + m_itemOrMoney(itemOrMoney), m_itemStackCount(itemStackCount), m_destTabId(destTabId) { } + + BankEventLogEntry(ObjectGuid::LowType guildId, uint32 guid, time_t timestamp, uint8 tabId, GuildBankEventLogTypes eventType, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) : + LogEntry(guildId, guid, timestamp), m_eventType(eventType), m_bankTabId(tabId), m_playerGuid(playerGuid), + m_itemOrMoney(itemOrMoney), m_itemStackCount(itemStackCount), m_destTabId(destTabId) { } + + ~BankEventLogEntry() { } + + void SaveToDB(SQLTransaction& trans) const override; + void WritePacket(WorldPacket& data) const override; + + private: + GuildBankEventLogTypes m_eventType; + uint8 m_bankTabId; + ObjectGuid::LowType m_playerGuid; + uint32 m_itemOrMoney; + uint16 m_itemStackCount; + uint8 m_destTabId; + }; + + // Class encapsulating work with events collection + typedef std::list<LogEntry*> GuildLog; + + class LogHolder + { + public: + LogHolder(uint32 maxRecords) : m_maxRecords(maxRecords), m_nextGUID(uint32(GUILD_EVENT_LOG_GUID_UNDEFINED)) { } + ~LogHolder(); + + uint8 GetSize() const { return uint8(m_log.size()); } + // Checks if new log entry can be added to holder when loading from DB + inline bool CanInsert() const { return m_log.size() < m_maxRecords; } + // Adds event from DB to collection + void LoadEvent(LogEntry* entry); + // Adds new event to collection and saves it to DB + void AddEvent(SQLTransaction& trans, LogEntry* entry); + // Writes information about all events to packet + void WritePacket(WorldPacket& data) const; + uint32 GetNextGUID(); + + private: + GuildLog m_log; + uint32 m_maxRecords; + uint32 m_nextGUID; + }; + + // Class encapsulating guild rank data + class RankInfo + { + public: + RankInfo(): m_guildId(0), m_rankId(GUILD_RANK_NONE), m_rights(GR_RIGHT_EMPTY), m_bankMoneyPerDay(0) { } + RankInfo(ObjectGuid::LowType guildId) : m_guildId(guildId), m_rankId(GUILD_RANK_NONE), m_rights(GR_RIGHT_EMPTY), m_bankMoneyPerDay(0) { } + RankInfo(ObjectGuid::LowType guildId, uint8 rankId, std::string const& name, uint32 rights, uint32 money) : + m_guildId(guildId), m_rankId(rankId), m_name(name), m_rights(rights), + m_bankMoneyPerDay(rankId != GR_GUILDMASTER ? money : GUILD_WITHDRAW_MONEY_UNLIMITED) { } - ~EventLogEntry() { } + void LoadFromDB(Field* fields); + void SaveToDB(SQLTransaction& trans) const; + void WritePacket(WorldPacket& data) const; - void SaveToDB(SQLTransaction& trans) const override; - void WritePacket(WorldPacket& data) const override; + uint8 GetId() const { return m_rankId; } - private: - GuildEventLogTypes m_eventType; - ObjectGuid::LowType m_playerGuid1; - ObjectGuid::LowType m_playerGuid2; - uint8 m_newRank; - }; - - // Bank event log entry - class BankEventLogEntry : public LogEntry - { - public: - static bool IsMoneyEvent(GuildBankEventLogTypes eventType) - { - return - eventType == GUILD_BANK_LOG_DEPOSIT_MONEY || - eventType == GUILD_BANK_LOG_WITHDRAW_MONEY || - eventType == GUILD_BANK_LOG_REPAIR_MONEY; - } + std::string const& GetName() const { return m_name; } + void SetName(std::string const& name); - BankEventLogEntry(ObjectGuid::LowType guildId, uint32 guid, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) : - LogEntry(guildId, guid), m_eventType(eventType), m_bankTabId(tabId), m_playerGuid(playerGuid), - m_itemOrMoney(itemOrMoney), m_itemStackCount(itemStackCount), m_destTabId(destTabId) { } + uint32 GetRights() const { return m_rights; } + void SetRights(uint32 rights); - BankEventLogEntry(ObjectGuid::LowType guildId, uint32 guid, time_t timestamp, uint8 tabId, GuildBankEventLogTypes eventType, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) : - LogEntry(guildId, guid, timestamp), m_eventType(eventType), m_bankTabId(tabId), m_playerGuid(playerGuid), - m_itemOrMoney(itemOrMoney), m_itemStackCount(itemStackCount), m_destTabId(destTabId) { } + int32 GetBankMoneyPerDay() const { return m_bankMoneyPerDay; } - ~BankEventLogEntry() { } + void SetBankMoneyPerDay(uint32 money); - void SaveToDB(SQLTransaction& trans) const override; - void WritePacket(WorldPacket& data) const override; + inline int8 GetBankTabRights(uint8 tabId) const + { + return tabId < GUILD_BANK_MAX_TABS ? m_bankTabRightsAndSlots[tabId].GetRights() : 0; + } - private: - GuildBankEventLogTypes m_eventType; - uint8 m_bankTabId; - ObjectGuid::LowType m_playerGuid; - uint32 m_itemOrMoney; - uint16 m_itemStackCount; - uint8 m_destTabId; - }; - - // Class encapsulating work with events collection - typedef std::list<LogEntry*> GuildLog; - - class LogHolder - { - public: - LogHolder(uint32 maxRecords) : m_maxRecords(maxRecords), m_nextGUID(uint32(GUILD_EVENT_LOG_GUID_UNDEFINED)) { } - ~LogHolder(); - - uint8 GetSize() const { return uint8(m_log.size()); } - // Checks if new log entry can be added to holder when loading from DB - inline bool CanInsert() const { return m_log.size() < m_maxRecords; } - // Adds event from DB to collection - void LoadEvent(LogEntry* entry); - // Adds new event to collection and saves it to DB - void AddEvent(SQLTransaction& trans, LogEntry* entry); - // Writes information about all events to packet - void WritePacket(WorldPacket& data) const; - uint32 GetNextGUID(); + inline int32 GetBankTabSlotsPerDay(uint8 tabId) const + { + return tabId < GUILD_BANK_MAX_TABS ? m_bankTabRightsAndSlots[tabId].GetSlots() : 0; + } - private: - GuildLog m_log; - uint32 m_maxRecords; - uint32 m_nextGUID; - }; - - // Class encapsulating guild rank data - class RankInfo - { - public: - RankInfo(): m_guildId(0), m_rankId(GUILD_RANK_NONE), m_rights(GR_RIGHT_EMPTY), m_bankMoneyPerDay(0) { } - RankInfo(ObjectGuid::LowType guildId) : m_guildId(guildId), m_rankId(GUILD_RANK_NONE), m_rights(GR_RIGHT_EMPTY), m_bankMoneyPerDay(0) { } - RankInfo(ObjectGuid::LowType guildId, uint8 rankId, std::string const& name, uint32 rights, uint32 money) : - m_guildId(guildId), m_rankId(rankId), m_name(name), m_rights(rights), - m_bankMoneyPerDay(rankId != GR_GUILDMASTER ? money : GUILD_WITHDRAW_MONEY_UNLIMITED) { } + void SetBankTabSlotsAndRights(GuildBankRightsAndSlots rightsAndSlots, bool saveToDB); + void CreateMissingTabsIfNeeded(uint8 ranks, SQLTransaction& trans, bool logOnCreate = false); - void LoadFromDB(Field* fields); - void SaveToDB(SQLTransaction& trans) const; - void WritePacket(WorldPacket& data) const; + private: + ObjectGuid::LowType m_guildId; - uint8 GetId() const { return m_rankId; } + uint8 m_rankId; + std::string m_name; + uint32 m_rights; + uint32 m_bankMoneyPerDay; + GuildBankRightsAndSlots m_bankTabRightsAndSlots[GUILD_BANK_MAX_TABS]; + }; - std::string const& GetName() const { return m_name; } - void SetName(std::string const& name); + class BankTab + { + public: + BankTab(ObjectGuid::LowType guildId, uint8 tabId) : m_guildId(guildId), m_tabId(tabId) + { + memset(m_items, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*)); + } + + void LoadFromDB(Field* fields); + bool LoadItemFromDB(Field* fields); + void Delete(SQLTransaction& trans, bool removeItemsFromDB = false); + + void WritePacket(WorldPacket& data) const; + bool WriteSlotPacket(WorldPacket& data, uint8 slotId, bool ignoreEmpty = true) const; + void WriteInfoPacket(WorldPacket& data) const + { + data << m_name; + data << m_icon; + } + + void SetInfo(std::string const& name, std::string const& icon); + void SetText(std::string const& text); + void SendText(const Guild* guild, WorldSession* session) const; + + inline Item* GetItem(uint8 slotId) const { return slotId < GUILD_BANK_MAX_SLOTS ? m_items[slotId] : NULL; } + bool SetItem(SQLTransaction& trans, uint8 slotId, Item* pItem); + + private: + ObjectGuid::LowType m_guildId; + uint8 m_tabId; + + Item* m_items[GUILD_BANK_MAX_SLOTS]; + std::string m_name; + std::string m_icon; + std::string m_text; + }; + + // Movement data + class MoveItemData + { + public: + MoveItemData(Guild* guild, Player* player, uint8 container, uint8 slotId) : m_pGuild(guild), m_pPlayer(player), + m_container(container), m_slotId(slotId), m_pItem(NULL), m_pClonedItem(NULL) { } + virtual ~MoveItemData() { } + + virtual bool IsBank() const = 0; + // Initializes item pointer. Returns true, if item exists, false otherwise. + virtual bool InitItem() = 0; + // Checks splited amount against item. Splited amount cannot be more that number of items in stack. + virtual bool CheckItem(uint32& splitedAmount); + // Defines if player has rights to save item in container + virtual bool HasStoreRights(MoveItemData* /*pOther*/) const { return true; } + // Defines if player has rights to withdraw item from container + virtual bool HasWithdrawRights(MoveItemData* /*pOther*/) const { return true; } + // Checks if container can store specified item + bool CanStore(Item* pItem, bool swap, bool sendError); + // Clones stored item + bool CloneItem(uint32 count); + // Remove item from container (if splited update items fields) + virtual void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount = 0) = 0; + // Saves item to container + virtual Item* StoreItem(SQLTransaction& trans, Item* pItem) = 0; + // Log bank event + virtual void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const = 0; + // Log GM action + virtual void LogAction(MoveItemData* pFrom) const; + // Copy slots id from position vector + void CopySlots(SlotIds& ids) const; + + Item* GetItem(bool isCloned = false) const { return isCloned ? m_pClonedItem : m_pItem; } + uint8 GetContainer() const { return m_container; } + uint8 GetSlotId() const { return m_slotId; } + + protected: + virtual InventoryResult CanStore(Item* pItem, bool swap) = 0; + + Guild* m_pGuild; + Player* m_pPlayer; + uint8 m_container; + uint8 m_slotId; + Item* m_pItem; + Item* m_pClonedItem; + ItemPosCountVec m_vec; + }; + + class PlayerMoveItemData : public MoveItemData + { + public: + PlayerMoveItemData(Guild* guild, Player* player, uint8 container, uint8 slotId) : + MoveItemData(guild, player, container, slotId) { } + + bool IsBank() const override { return false; } + bool InitItem() override; + void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount = 0) override; + Item* StoreItem(SQLTransaction& trans, Item* pItem) override; + void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const override; + protected: + InventoryResult CanStore(Item* pItem, bool swap) override; + }; + + class BankMoveItemData : public MoveItemData + { + public: + BankMoveItemData(Guild* guild, Player* player, uint8 container, uint8 slotId) : + MoveItemData(guild, player, container, slotId) { } + + bool IsBank() const override { return true; } + bool InitItem() override; + bool HasStoreRights(MoveItemData* pOther) const override; + bool HasWithdrawRights(MoveItemData* pOther) const override; + void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount) override; + Item* StoreItem(SQLTransaction& trans, Item* pItem) override; + void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const override; + void LogAction(MoveItemData* pFrom) const override; + + protected: + InventoryResult CanStore(Item* pItem, bool swap) override; + + private: + Item* _StoreItem(SQLTransaction& trans, BankTab* pTab, Item* pItem, ItemPosCount& pos, bool clone) const; + bool _ReserveSpace(uint8 slotId, Item* pItem, Item* pItemDest, uint32& count); + void CanStoreItemInTab(Item* pItem, uint8 skipSlotId, bool merge, uint32& count); + }; + + typedef std::unordered_map<uint32, Member*> Members; + typedef std::vector<RankInfo> Ranks; + typedef std::vector<BankTab*> BankTabs; - uint32 GetRights() const { return m_rights; } - void SetRights(uint32 rights); + public: + static void SendCommandResult(WorldSession* session, GuildCommandType type, GuildCommandError errCode, std::string const& param = ""); + static void SendSaveEmblemResult(WorldSession* session, GuildEmblemError errCode); - int32 GetBankMoneyPerDay() const { return m_bankMoneyPerDay; } + Guild(); + ~Guild(); - void SetBankMoneyPerDay(uint32 money); + bool Create(Player* pLeader, std::string const& name); + void Disband(); - inline int8 GetBankTabRights(uint8 tabId) const + // Getters + ObjectGuid::LowType GetId() const { return m_id; } + ObjectGuid GetLeaderGUID() const { return m_leaderGuid; } + std::string const& GetName() const { return m_name; } + std::string const& GetMOTD() const { return m_motd; } + std::string const& GetInfo() const { return m_info; } + uint32 GetMemberCount() const { return m_members.size(); } + time_t GetCreatedDate() const { return m_createdDate; } + uint64 GetBankMoney() const { return m_bankMoney; } + + bool SetName(std::string const& name); + + // Handle client commands + void HandleRoster(WorldSession* session); + void HandleQuery(WorldSession* session); + void HandleSetMOTD(WorldSession* session, std::string const& motd); + void HandleSetInfo(WorldSession* session, std::string const& info); + void HandleSetEmblem(WorldSession* session, const EmblemInfo& emblemInfo); + void HandleSetLeader(WorldSession* session, std::string const& name); + void HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string const& name, std::string const& icon); + void HandleSetMemberNote(WorldSession* session, std::string const& name, std::string const& note, bool officer); + void HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string const& name, uint32 rights, uint32 moneyPerDay, const GuildBankRightsAndSlotsVec& rightsAndSlots); + void HandleBuyBankTab(WorldSession* session, uint8 tabId); + void HandleInviteMember(WorldSession* session, std::string const& name); + void HandleAcceptMember(WorldSession* session); + void HandleLeaveMember(WorldSession* session); + void HandleRemoveMember(WorldSession* session, std::string const& name); + void HandleUpdateMemberRank(WorldSession* session, std::string const& name, bool demote); + void HandleAddNewRank(WorldSession* session, std::string const& name); + void HandleRemoveRank(WorldSession* session, uint8 rankId); + void HandleRemoveLowestRank(WorldSession* session); + void HandleMemberDepositMoney(WorldSession* session, uint32 amount); + bool HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool repair = false); + void HandleMemberLogout(WorldSession* session); + void HandleDisband(WorldSession* session); + + void UpdateMemberData(Player* player, uint8 dataid, uint32 value); + void OnPlayerStatusChange(Player* player, uint32 flag, bool state); + + // Send info to client + void SendInfo(WorldSession* session) const; + void SendEventLog(WorldSession* session) const; + void SendBankLog(WorldSession* session, uint8 tabId) const; + void SendBankTabsInfo(WorldSession* session, bool showTabs = false) const; + void SendBankTabData(WorldSession* session, uint8 tabId) const; + void SendBankTabText(WorldSession* session, uint8 tabId) const; + void SendPermissions(WorldSession* session) const; + void SendMoneyInfo(WorldSession* session) const; + void SendLoginInfo(WorldSession* session); + + // Load from DB + bool LoadFromDB(Field* fields); + void LoadRankFromDB(Field* fields); + bool LoadMemberFromDB(Field* fields); + bool LoadEventLogFromDB(Field* fields); + void LoadBankRightFromDB(Field* fields); + void LoadBankTabFromDB(Field* fields); + bool LoadBankEventLogFromDB(Field* fields); + bool LoadBankItemFromDB(Field* fields); + bool Validate(); + + // Broadcasts + void BroadcastToGuild(WorldSession* session, bool officerOnly, std::string const& msg, uint32 language = LANG_UNIVERSAL) const; + void BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const; + void BroadcastPacket(WorldPacket* packet) const; + + void MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 maxLevel, uint32 minRank); + + template<class Do> + void BroadcastWorker(Do& _do, Player* except = nullptr) { - return tabId < GUILD_BANK_MAX_TABS ? m_bankTabRightsAndSlots[tabId].GetRights() : 0; + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) + if (Player* player = itr->second->FindConnectedPlayer()) + if (player != except) + _do(player); } - inline int32 GetBankTabSlotsPerDay(uint8 tabId) const - { - return tabId < GUILD_BANK_MAX_TABS ? m_bankTabRightsAndSlots[tabId].GetSlots() : 0; - } + // Members + // Adds member to guild. If rankId == GUILD_RANK_NONE, lowest rank is assigned. + bool AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId = GUILD_RANK_NONE); + void DeleteMember(SQLTransaction& trans, ObjectGuid guid, bool isDisbanding = false, bool isKicked = false, bool canDeleteGuild = false); + bool ChangeMemberRank(SQLTransaction& trans, ObjectGuid guid, uint8 newRank); - void SetBankTabSlotsAndRights(GuildBankRightsAndSlots rightsAndSlots, bool saveToDB); - void CreateMissingTabsIfNeeded(uint8 ranks, SQLTransaction& trans, bool logOnCreate = false); + // Bank + void SwapItems(Player* player, uint8 tabId, uint8 slotId, uint8 destTabId, uint8 destSlotId, uint32 splitedAmount); + void SwapItemsWithInventory(Player* player, bool toChar, uint8 tabId, uint8 slotId, uint8 playerBag, uint8 playerSlotId, uint32 splitedAmount); - private: - ObjectGuid::LowType m_guildId; + // Bank tabs + void SetBankTabText(uint8 tabId, std::string const& text); - uint8 m_rankId; + void ResetTimes(); + + protected: + ObjectGuid::LowType m_id; std::string m_name; - uint32 m_rights; - uint32 m_bankMoneyPerDay; - GuildBankRightsAndSlots m_bankTabRightsAndSlots[GUILD_BANK_MAX_TABS]; - }; + ObjectGuid m_leaderGuid; + std::string m_motd; + std::string m_info; + time_t m_createdDate; - class BankTab - { - public: - BankTab(ObjectGuid::LowType guildId, uint8 tabId) : m_guildId(guildId), m_tabId(tabId) - { - memset(m_items, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*)); - } + EmblemInfo m_emblemInfo; + uint32 m_accountsNumber; + uint64 m_bankMoney; - void LoadFromDB(Field* fields); - bool LoadItemFromDB(Field* fields); - void Delete(SQLTransaction& trans, bool removeItemsFromDB = false); + Ranks m_ranks; + Members m_members; + BankTabs m_bankTabs; - void WritePacket(WorldPacket& data) const; - bool WriteSlotPacket(WorldPacket& data, uint8 slotId, bool ignoreEmpty = true) const; - void WriteInfoPacket(WorldPacket& data) const + // These are actually ordered lists. The first element is the oldest entry. + LogHolder* m_eventLog; + LogHolder* m_bankEventLog[GUILD_BANK_MAX_TABS + 1]; + + private: + inline uint8 _GetRanksSize() const { return uint8(m_ranks.size()); } + inline RankInfo const* GetRankInfo(uint8 rankId) const { return rankId < _GetRanksSize() ? &m_ranks[rankId] : nullptr; } + inline RankInfo* GetRankInfo(uint8 rankId) { return rankId < _GetRanksSize() ? &m_ranks[rankId] : nullptr; } + inline bool _HasRankRight(Player* player, uint32 right) const { - data << m_name; - data << m_icon; + if (player) + if (Member const* member = GetMember(player->GetGUID())) + return (_GetRankRights(member->GetRankId()) & right) != GR_RIGHT_EMPTY; + return false; } - void SetInfo(std::string const& name, std::string const& icon); - void SetText(std::string const& text); - void SendText(const Guild* guild, WorldSession* session) const; + inline uint8 _GetLowestRankId() const { return uint8(m_ranks.size() - 1); } - inline Item* GetItem(uint8 slotId) const { return slotId < GUILD_BANK_MAX_SLOTS ? m_items[slotId] : NULL; } - bool SetItem(SQLTransaction& trans, uint8 slotId, Item* pItem); + inline uint8 _GetPurchasedTabsSize() const { return uint8(m_bankTabs.size()); } + inline BankTab* GetBankTab(uint8 tabId) { return tabId < m_bankTabs.size() ? m_bankTabs[tabId] : nullptr; } + inline BankTab const* GetBankTab(uint8 tabId) const { return tabId < m_bankTabs.size() ? m_bankTabs[tabId] : nullptr; } - private: - ObjectGuid::LowType m_guildId; - uint8 m_tabId; - - Item* m_items[GUILD_BANK_MAX_SLOTS]; - std::string m_name; - std::string m_icon; - std::string m_text; - }; + inline Member const* GetMember(ObjectGuid guid) const + { + auto itr = m_members.find(guid.GetCounter()); + return itr != m_members.end() ? itr->second : nullptr; + } - // Movement data - class MoveItemData - { - public: - MoveItemData(Guild* guild, Player* player, uint8 container, uint8 slotId) : m_pGuild(guild), m_pPlayer(player), - m_container(container), m_slotId(slotId), m_pItem(NULL), m_pClonedItem(NULL) { } - virtual ~MoveItemData() { } - - virtual bool IsBank() const = 0; - // Initializes item pointer. Returns true, if item exists, false otherwise. - virtual bool InitItem() = 0; - // Checks splited amount against item. Splited amount cannot be more that number of items in stack. - virtual bool CheckItem(uint32& splitedAmount); - // Defines if player has rights to save item in container - virtual bool HasStoreRights(MoveItemData* /*pOther*/) const { return true; } - // Defines if player has rights to withdraw item from container - virtual bool HasWithdrawRights(MoveItemData* /*pOther*/) const { return true; } - // Checks if container can store specified item - bool CanStore(Item* pItem, bool swap, bool sendError); - // Clones stored item - bool CloneItem(uint32 count); - // Remove item from container (if splited update items fields) - virtual void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount = 0) = 0; - // Saves item to container - virtual Item* StoreItem(SQLTransaction& trans, Item* pItem) = 0; - // Log bank event - virtual void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const = 0; - // Log GM action - virtual void LogAction(MoveItemData* pFrom) const; - // Copy slots id from position vector - void CopySlots(SlotIds& ids) const; - - Item* GetItem(bool isCloned = false) const { return isCloned ? m_pClonedItem : m_pItem; } - uint8 GetContainer() const { return m_container; } - uint8 GetSlotId() const { return m_slotId; } + inline Member* GetMember(ObjectGuid guid) + { + auto itr = m_members.find(guid.GetCounter()); + return itr != m_members.end() ? itr->second : nullptr; + } - protected: - virtual InventoryResult CanStore(Item* pItem, bool swap) = 0; - - Guild* m_pGuild; - Player* m_pPlayer; - uint8 m_container; - uint8 m_slotId; - Item* m_pItem; - Item* m_pClonedItem; - ItemPosCountVec m_vec; - }; - - class PlayerMoveItemData : public MoveItemData - { - public: - PlayerMoveItemData(Guild* guild, Player* player, uint8 container, uint8 slotId) : - MoveItemData(guild, player, container, slotId) { } - - bool IsBank() const override { return false; } - bool InitItem() override; - void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount = 0) override; - Item* StoreItem(SQLTransaction& trans, Item* pItem) override; - void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const override; - protected: - InventoryResult CanStore(Item* pItem, bool swap) override; - }; + inline Member* GetMember(std::string const& name) + { + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) + if (itr->second->GetName() == name) + return itr->second; - class BankMoveItemData : public MoveItemData - { - public: - BankMoveItemData(Guild* guild, Player* player, uint8 container, uint8 slotId) : - MoveItemData(guild, player, container, slotId) { } - - bool IsBank() const override { return true; } - bool InitItem() override; - bool HasStoreRights(MoveItemData* pOther) const override; - bool HasWithdrawRights(MoveItemData* pOther) const override; - void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount) override; - Item* StoreItem(SQLTransaction& trans, Item* pItem) override; - void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const override; - void LogAction(MoveItemData* pFrom) const override; + return nullptr; + } - protected: - InventoryResult CanStore(Item* pItem, bool swap) override; + inline void _DeleteMemberFromDB(SQLTransaction& trans, ObjectGuid::LowType lowguid) const + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_MEMBER); + stmt->setUInt32(0, lowguid); + CharacterDatabase.ExecuteOrAppend(trans, stmt); + } - private: - Item* _StoreItem(SQLTransaction& trans, BankTab* pTab, Item* pItem, ItemPosCount& pos, bool clone) const; - bool _ReserveSpace(uint8 slotId, Item* pItem, Item* pItemDest, uint32& count); - void CanStoreItemInTab(Item* pItem, uint8 skipSlotId, bool merge, uint32& count); - }; - - typedef std::unordered_map<uint32, Member*> Members; - typedef std::vector<RankInfo> Ranks; - typedef std::vector<BankTab*> BankTabs; - -public: - static void SendCommandResult(WorldSession* session, GuildCommandType type, GuildCommandError errCode, std::string const& param = ""); - static void SendSaveEmblemResult(WorldSession* session, GuildEmblemError errCode); - - Guild(); - ~Guild(); - - bool Create(Player* pLeader, std::string const& name); - void Disband(); - - // Getters - ObjectGuid::LowType GetId() const { return m_id; } - ObjectGuid GetLeaderGUID() const { return m_leaderGuid; } - std::string const& GetName() const { return m_name; } - std::string const& GetMOTD() const { return m_motd; } - std::string const& GetInfo() const { return m_info; } - uint32 GetMemberCount() const { return m_members.size(); } - time_t GetCreatedDate() const { return m_createdDate; } - uint64 GetBankMoney() const { return m_bankMoney; } - - bool SetName(std::string const& name); - - // Handle client commands - void HandleRoster(WorldSession* session); - void HandleQuery(WorldSession* session); - void HandleSetMOTD(WorldSession* session, std::string const& motd); - void HandleSetInfo(WorldSession* session, std::string const& info); - void HandleSetEmblem(WorldSession* session, const EmblemInfo& emblemInfo); - void HandleSetLeader(WorldSession* session, std::string const& name); - void HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string const& name, std::string const& icon); - void HandleSetMemberNote(WorldSession* session, std::string const& name, std::string const& note, bool officer); - void HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string const& name, uint32 rights, uint32 moneyPerDay, const GuildBankRightsAndSlotsVec& rightsAndSlots); - void HandleBuyBankTab(WorldSession* session, uint8 tabId); - void HandleInviteMember(WorldSession* session, std::string const& name); - void HandleAcceptMember(WorldSession* session); - void HandleLeaveMember(WorldSession* session); - void HandleRemoveMember(WorldSession* session, std::string const& name); - void HandleUpdateMemberRank(WorldSession* session, std::string const& name, bool demote); - void HandleAddNewRank(WorldSession* session, std::string const& name); - void HandleRemoveRank(WorldSession* session, uint8 rankId); - void HandleRemoveLowestRank(WorldSession* session); - void HandleMemberDepositMoney(WorldSession* session, uint32 amount); - bool HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool repair = false); - void HandleMemberLogout(WorldSession* session); - void HandleDisband(WorldSession* session); - - void UpdateMemberData(Player* player, uint8 dataid, uint32 value); - void OnPlayerStatusChange(Player* player, uint32 flag, bool state); - - // Send info to client - void SendInfo(WorldSession* session) const; - void SendEventLog(WorldSession* session) const; - void SendBankLog(WorldSession* session, uint8 tabId) const; - void SendBankTabsInfo(WorldSession* session, bool showTabs = false) const; - void SendBankTabData(WorldSession* session, uint8 tabId) const; - void SendBankTabText(WorldSession* session, uint8 tabId) const; - void SendPermissions(WorldSession* session) const; - void SendMoneyInfo(WorldSession* session) const; - void SendLoginInfo(WorldSession* session); - - // Load from DB - bool LoadFromDB(Field* fields); - void LoadRankFromDB(Field* fields); - bool LoadMemberFromDB(Field* fields); - bool LoadEventLogFromDB(Field* fields); - void LoadBankRightFromDB(Field* fields); - void LoadBankTabFromDB(Field* fields); - bool LoadBankEventLogFromDB(Field* fields); - bool LoadBankItemFromDB(Field* fields); - bool Validate(); - - // Broadcasts - void BroadcastToGuild(WorldSession* session, bool officerOnly, std::string const& msg, uint32 language = LANG_UNIVERSAL) const; - void BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const; - void BroadcastPacket(WorldPacket* packet) const; - - void MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 maxLevel, uint32 minRank); - - template<class Do> - void BroadcastWorker(Do& _do, Player* except = NULL) - { - for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) - if (Player* player = itr->second->FindConnectedPlayer()) - if (player != except) - _do(player); - } - - // Members - // Adds member to guild. If rankId == GUILD_RANK_NONE, lowest rank is assigned. - bool AddMember(ObjectGuid guid, uint8 rankId = GUILD_RANK_NONE); - void DeleteMember(ObjectGuid guid, bool isDisbanding = false, bool isKicked = false, bool canDeleteGuild = false); - bool ChangeMemberRank(ObjectGuid guid, uint8 newRank); - - // Bank - void SwapItems(Player* player, uint8 tabId, uint8 slotId, uint8 destTabId, uint8 destSlotId, uint32 splitedAmount); - void SwapItemsWithInventory(Player* player, bool toChar, uint8 tabId, uint8 slotId, uint8 playerBag, uint8 playerSlotId, uint32 splitedAmount); - - // Bank tabs - void SetBankTabText(uint8 tabId, std::string const& text); - - void ResetTimes(); - -protected: - ObjectGuid::LowType m_id; - std::string m_name; - ObjectGuid m_leaderGuid; - std::string m_motd; - std::string m_info; - time_t m_createdDate; - - EmblemInfo m_emblemInfo; - uint32 m_accountsNumber; - uint64 m_bankMoney; - - Ranks m_ranks; - Members m_members; - BankTabs m_bankTabs; - - // These are actually ordered lists. The first element is the oldest entry. - LogHolder* m_eventLog; - LogHolder* m_bankEventLog[GUILD_BANK_MAX_TABS + 1]; - -private: - inline uint8 _GetRanksSize() const { return uint8(m_ranks.size()); } - inline const RankInfo* GetRankInfo(uint8 rankId) const { return rankId < _GetRanksSize() ? &m_ranks[rankId] : NULL; } - inline RankInfo* GetRankInfo(uint8 rankId) { return rankId < _GetRanksSize() ? &m_ranks[rankId] : NULL; } - inline bool _HasRankRight(Player* player, uint32 right) const - { - if (player) - if (Member const* member = GetMember(player->GetGUID())) - return (_GetRankRights(member->GetRankId()) & right) != GR_RIGHT_EMPTY; - return false; - } - - inline uint8 _GetLowestRankId() const { return uint8(m_ranks.size() - 1); } - - inline uint8 _GetPurchasedTabsSize() const { return uint8(m_bankTabs.size()); } - inline BankTab* GetBankTab(uint8 tabId) { return tabId < m_bankTabs.size() ? m_bankTabs[tabId] : NULL; } - inline const BankTab* GetBankTab(uint8 tabId) const { return tabId < m_bankTabs.size() ? m_bankTabs[tabId] : NULL; } - - inline const Member* GetMember(ObjectGuid guid) const - { - Members::const_iterator itr = m_members.find(guid.GetCounter()); - return itr != m_members.end() ? itr->second : NULL; - } - - inline Member* GetMember(ObjectGuid guid) - { - Members::iterator itr = m_members.find(guid.GetCounter()); - return itr != m_members.end() ? itr->second : NULL; - } - - inline Member* GetMember(std::string const& name) - { - for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) - if (itr->second->GetName() == name) - return itr->second; - - return NULL; - } - - inline void _DeleteMemberFromDB(ObjectGuid::LowType lowguid) const - { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_MEMBER); - stmt->setUInt32(0, lowguid); - CharacterDatabase.Execute(stmt); - } - - // Creates log holders (either when loading or when creating guild) - void _CreateLogHolders(); - // Tries to create new bank tab - void _CreateNewBankTab(); - // Creates default guild ranks with names in given locale - void _CreateDefaultGuildRanks(LocaleConstant loc); - // Creates new rank - bool _CreateRank(std::string const& name, uint32 rights); - // Update account number when member added/removed from guild - void _UpdateAccountsNumber(); - bool _IsLeader(Player* player) const; - void _DeleteBankItems(SQLTransaction& trans, bool removeItemsFromDB = false); - bool _ModifyBankMoney(SQLTransaction& trans, uint64 amount, bool add); - void _SetLeaderGUID(Member* pLeader); - - void _SetRankBankMoneyPerDay(uint8 rankId, uint32 moneyPerDay); - void _SetRankBankTabRightsAndSlots(uint8 rankId, GuildBankRightsAndSlots rightsAndSlots, bool saveToDB = true); - int8 _GetRankBankTabRights(uint8 rankId, uint8 tabId) const; - uint32 _GetRankRights(uint8 rankId) const; - int32 _GetRankBankMoneyPerDay(uint8 rankId) const; - int32 _GetRankBankTabSlotsPerDay(uint8 rankId, uint8 tabId) const; - std::string _GetRankName(uint8 rankId) const; - - int32 _GetMemberRemainingSlots(Member const* member, uint8 tabId) const; - int32 _GetMemberRemainingMoney(Member const* member) const; - void _UpdateMemberWithdrawSlots(SQLTransaction& trans, ObjectGuid guid, uint8 tabId); - bool _MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 rights) const; - - void _LogEvent(GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2 = 0, uint8 newRank = 0); - void _LogBankEvent(SQLTransaction& trans, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount = 0, uint8 destTabId = 0); - - Item* _GetItem(uint8 tabId, uint8 slotId) const; - void _RemoveItem(SQLTransaction& trans, uint8 tabId, uint8 slotId); - void _MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAmount); - bool _DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError, uint32 splitedAmount = 0); - - void _SendBankContent(WorldSession* session, uint8 tabId) const; - void _SendBankMoneyUpdate(WorldSession* session) const; - void _SendBankContentUpdate(MoveItemData* pSrc, MoveItemData* pDest) const; - void _SendBankContentUpdate(uint8 tabId, SlotIds slots) const; - void _SendBankList(WorldSession* session = NULL, uint8 tabId = 0, bool sendFullSlots = false, SlotIds *slots = NULL) const; - - void _BroadcastEvent(GuildEvents guildEvent, ObjectGuid guid, const char* param1 = NULL, const char* param2 = NULL, const char* param3 = NULL) const; + // Creates log holders (either when loading or when creating guild) + void _CreateLogHolders(); + // Tries to create new bank tab + void _CreateNewBankTab(); + // Creates default guild ranks with names in given locale + void _CreateDefaultGuildRanks(SQLTransaction& trans, LocaleConstant loc); + // Creates new rank + bool _CreateRank(SQLTransaction& trans, std::string const& name, uint32 rights); + // Update account number when member added/removed from guild + void _UpdateAccountsNumber(); + bool _IsLeader(Player* player) const; + void _DeleteBankItems(SQLTransaction& trans, bool removeItemsFromDB = false); + bool _ModifyBankMoney(SQLTransaction& trans, uint64 amount, bool add); + void _SetLeaderGUID(Member* pLeader); + + void _SetRankBankMoneyPerDay(uint8 rankId, uint32 moneyPerDay); + void _SetRankBankTabRightsAndSlots(uint8 rankId, GuildBankRightsAndSlots rightsAndSlots, bool saveToDB = true); + int8 _GetRankBankTabRights(uint8 rankId, uint8 tabId) const; + uint32 _GetRankRights(uint8 rankId) const; + int32 _GetRankBankMoneyPerDay(uint8 rankId) const; + int32 _GetRankBankTabSlotsPerDay(uint8 rankId, uint8 tabId) const; + std::string _GetRankName(uint8 rankId) const; + + int32 _GetMemberRemainingSlots(Member const* member, uint8 tabId) const; + int32 _GetMemberRemainingMoney(Member const* member) const; + void _UpdateMemberWithdrawSlots(SQLTransaction& trans, ObjectGuid guid, uint8 tabId); + bool _MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 rights) const; + + void _LogEvent(GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2 = 0, uint8 newRank = 0); + void _LogBankEvent(SQLTransaction& trans, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount = 0, uint8 destTabId = 0); + + Item* _GetItem(uint8 tabId, uint8 slotId) const; + void _RemoveItem(SQLTransaction& trans, uint8 tabId, uint8 slotId); + void _MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAmount); + bool _DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError, uint32 splitedAmount = 0); + + void _SendBankContent(WorldSession* session, uint8 tabId) const; + void _SendBankMoneyUpdate(WorldSession* session) const; + void _SendBankContentUpdate(MoveItemData* pSrc, MoveItemData* pDest) const; + void _SendBankContentUpdate(uint8 tabId, SlotIds slots) const; + void _SendBankList(WorldSession* session = NULL, uint8 tabId = 0, bool sendFullSlots = false, SlotIds *slots = NULL) const; + + void _BroadcastEvent(GuildEvents guildEvent, ObjectGuid guid, const char* param1 = NULL, const char* param2 = NULL, const char* param3 = NULL) const; }; #endif diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 53c62858c04..157511afd96 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1843,13 +1843,10 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) { // Reset guild stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER); - stmt->setUInt32(0, lowGuid); - - PreparedQueryResult result = CharacterDatabase.Query(stmt); - if (result) + if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) if (Guild* guild = sGuildMgr->GetGuildById((result->Fetch()[0]).GetUInt32())) - guild->DeleteMember(factionChangeInfo.Guid, false, false, true); + guild->DeleteMember(trans, factionChangeInfo.Guid, false, false, true); Player::LeaveAllArenaTeams(factionChangeInfo.Guid); } diff --git a/src/server/game/Handlers/PetitionsHandler.cpp b/src/server/game/Handlers/PetitionsHandler.cpp index c0b5db65d90..a4d41bbff1f 100644 --- a/src/server/game/Handlers/PetitionsHandler.cpp +++ b/src/server/game/Handlers/PetitionsHandler.cpp @@ -849,12 +849,18 @@ void WorldSession::HandleTurnInPetitionOpcode(WorldPacket& recvData) Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_COMMAND_SUCCESS, name); - // Add members from signatures - for (uint8 i = 0; i < signatures; ++i) { - Field* fields = result->Fetch(); - guild->AddMember(ObjectGuid(HighGuid::Player, fields[0].GetUInt32())); - result->NextRow(); + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + + // Add members from signatures + for (uint8 i = 0; i < signatures; ++i) + { + Field* fields = result->Fetch(); + guild->AddMember(trans, ObjectGuid(HighGuid::Player, fields[0].GetUInt32())); + result->NextRow(); + } + + CharacterDatabase.CommitTransaction(trans); } } else diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 9686fb9622f..b69bb41d3ad 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -483,7 +483,7 @@ void Loot::FillNotNormalLootFor(Player* player, bool presentAtLooting) { ObjectGuid::LowType plguid = player->GetGUID().GetCounter(); - QuestItemMap::const_iterator qmapitr = PlayerQuestItems.find(plguid); + NotNormalLootItemMap::const_iterator qmapitr = PlayerQuestItems.find(plguid); if (qmapitr == PlayerQuestItems.end()) FillQuestLoot(player); @@ -517,16 +517,16 @@ void Loot::FillNotNormalLootFor(Player* player, bool presentAtLooting) } } -QuestItemList* Loot::FillFFALoot(Player* player) +NotNormalLootItemList* Loot::FillFFALoot(Player* player) { - QuestItemList* ql = new QuestItemList(); + NotNormalLootItemList* ql = new NotNormalLootItemList(); for (uint8 i = 0; i < items.size(); ++i) { LootItem &item = items[i]; if (!item.is_looted && item.freeforall && item.AllowedForPlayer(player)) { - ql->push_back(QuestItem(i)); + ql->push_back(NotNormalLootItem(i)); ++unlootedCount; } } @@ -540,12 +540,12 @@ QuestItemList* Loot::FillFFALoot(Player* player) return ql; } -QuestItemList* Loot::FillQuestLoot(Player* player) +NotNormalLootItemList* Loot::FillQuestLoot(Player* player) { if (items.size() == MAX_NR_LOOT_ITEMS) return NULL; - QuestItemList* ql = new QuestItemList(); + NotNormalLootItemList* ql = new NotNormalLootItemList(); for (uint8 i = 0; i < quest_items.size(); ++i) { @@ -553,7 +553,7 @@ QuestItemList* Loot::FillQuestLoot(Player* player) if (!item.is_looted && (item.AllowedForPlayer(player) || (item.follow_loot_rules && player->GetGroup() && ((player->GetGroup()->GetLootMethod() == MASTER_LOOT && player->GetGroup()->GetMasterLooterGuid() == player->GetGUID()) || player->GetGroup()->GetLootMethod() != MASTER_LOOT)))) { - ql->push_back(QuestItem(i)); + ql->push_back(NotNormalLootItem(i)); // quest items get blocked when they first appear in a // player's quest vector @@ -578,20 +578,20 @@ QuestItemList* Loot::FillQuestLoot(Player* player) return ql; } -QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting) +NotNormalLootItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting) { - QuestItemList* ql = new QuestItemList(); + NotNormalLootItemList* ql = new NotNormalLootItemList(); for (uint8 i = 0; i < items.size(); ++i) { LootItem &item = items[i]; - if (!item.is_looted && !item.freeforall && (item.AllowedForPlayer(player) || (item.follow_loot_rules && player->GetGroup() && ((player->GetGroup()->GetLootMethod() == MASTER_LOOT && player->GetGroup()->GetMasterLooterGuid() == player->GetGUID()) || player->GetGroup()->GetLootMethod() != MASTER_LOOT)))) + if (!item.is_looted && !item.freeforall && (item.AllowedForPlayer(player))) { if (presentAtLooting) item.AddAllowedLooter(player); if (!item.conditions.empty()) { - ql->push_back(QuestItem(i)); + ql->push_back(NotNormalLootItem(i)); if (!item.is_counted) { ++unlootedCount; @@ -657,11 +657,11 @@ void Loot::NotifyQuestItemRemoved(uint8 questIndex) ++i_next; if (Player* player = ObjectAccessor::FindPlayer(*i)) { - QuestItemMap::const_iterator pq = PlayerQuestItems.find(player->GetGUID().GetCounter()); + NotNormalLootItemMap::const_iterator pq = PlayerQuestItems.find(player->GetGUID().GetCounter()); if (pq != PlayerQuestItems.end() && pq->second) { // find where/if the player has the given item in it's vector - QuestItemList& pql = *pq->second; + NotNormalLootItemList& pql = *pq->second; uint8 j; for (j = 0; j < pql.size(); ++j) @@ -717,17 +717,17 @@ void Loot::DeleteLootMoneyFromContainerItemDB() CharacterDatabase.Execute(stmt); } -LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem* *qitem, QuestItem* *ffaitem, QuestItem* *conditem) +LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, NotNormalLootItem* *qitem, NotNormalLootItem* *ffaitem, NotNormalLootItem* *conditem) { LootItem* item = NULL; bool is_looted = true; if (lootSlot >= items.size()) { uint32 questSlot = lootSlot - items.size(); - QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUID().GetCounter()); + NotNormalLootItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUID().GetCounter()); if (itr != PlayerQuestItems.end() && questSlot < itr->second->size()) { - QuestItem* qitem2 = &itr->second->at(questSlot); + NotNormalLootItem* qitem2 = &itr->second->at(questSlot); if (qitem) *qitem = qitem2; item = &quest_items[qitem2->index]; @@ -740,13 +740,13 @@ LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem* *qite is_looted = item->is_looted; if (item->freeforall) { - QuestItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUID().GetCounter()); + NotNormalLootItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUID().GetCounter()); if (itr != PlayerFFAItems.end()) { - for (QuestItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter) + for (NotNormalLootItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter) if (iter->index == lootSlot) { - QuestItem* ffaitem2 = (QuestItem*)&(*iter); + NotNormalLootItem* ffaitem2 = (NotNormalLootItem*)&(*iter); if (ffaitem) *ffaitem = ffaitem2; is_looted = ffaitem2->is_looted; @@ -756,14 +756,14 @@ LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem* *qite } else if (!item->conditions.empty()) { - QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUID().GetCounter()); + NotNormalLootItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUID().GetCounter()); if (itr != PlayerNonQuestNonFFAConditionalItems.end()) { - for (QuestItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter) + for (NotNormalLootItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter) { if (iter->index == lootSlot) { - QuestItem* conditem2 = (QuestItem*)&(*iter); + NotNormalLootItem* conditem2 = (NotNormalLootItem*)&(*iter); if (conditem) *conditem = conditem2; is_looted = conditem2->is_looted; @@ -782,7 +782,7 @@ LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem* *qite uint32 Loot::GetMaxSlotInLootFor(Player* player) const { - QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUID().GetCounter()); + NotNormalLootItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUID().GetCounter()); return items.size() + (itr != PlayerQuestItems.end() ? itr->second->size() : 0); } @@ -802,12 +802,12 @@ bool Loot::hasItemForAll() const // return true if there is any FFA, quest or conditional item for the player. bool Loot::hasItemFor(Player* player) const { - QuestItemMap const& lootPlayerQuestItems = GetPlayerQuestItems(); - QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(player->GetGUID().GetCounter()); + NotNormalLootItemMap const& lootPlayerQuestItems = GetPlayerQuestItems(); + NotNormalLootItemMap::const_iterator q_itr = lootPlayerQuestItems.find(player->GetGUID().GetCounter()); if (q_itr != lootPlayerQuestItems.end()) { - QuestItemList* q_list = q_itr->second; - for (QuestItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi) + NotNormalLootItemList* q_list = q_itr->second; + for (NotNormalLootItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi) { const LootItem &item = quest_items[qi->index]; if (!qi->is_looted && !item.is_looted) @@ -815,12 +815,12 @@ bool Loot::hasItemFor(Player* player) const } } - QuestItemMap const& lootPlayerFFAItems = GetPlayerFFAItems(); - QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(player->GetGUID().GetCounter()); + NotNormalLootItemMap const& lootPlayerFFAItems = GetPlayerFFAItems(); + NotNormalLootItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(player->GetGUID().GetCounter()); if (ffa_itr != lootPlayerFFAItems.end()) { - QuestItemList* ffa_list = ffa_itr->second; - for (QuestItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi) + NotNormalLootItemList* ffa_list = ffa_itr->second; + for (NotNormalLootItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi) { const LootItem &item = items[fi->index]; if (!fi->is_looted && !item.is_looted) @@ -828,12 +828,12 @@ bool Loot::hasItemFor(Player* player) const } } - QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = GetPlayerNonQuestNonFFAConditionalItems(); - QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(player->GetGUID().GetCounter()); + NotNormalLootItemMap const& lootPlayerNonQuestNonFFAConditionalItems = GetPlayerNonQuestNonFFAConditionalItems(); + NotNormalLootItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(player->GetGUID().GetCounter()); if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end()) { - QuestItemList* conditional_list = nn_itr->second; - for (QuestItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci) + NotNormalLootItemList* conditional_list = nn_itr->second; + for (NotNormalLootItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci) { const LootItem &item = items[ci->index]; if (!ci->is_looted && !item.is_looted) @@ -976,12 +976,12 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) } LootSlotType slotType = lv.permission == OWNER_PERMISSION ? LOOT_SLOT_TYPE_OWNER : LOOT_SLOT_TYPE_ALLOW_LOOT; - QuestItemMap const& lootPlayerQuestItems = l.GetPlayerQuestItems(); - QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(lv.viewer->GetGUID().GetCounter()); + NotNormalLootItemMap const& lootPlayerQuestItems = l.GetPlayerQuestItems(); + NotNormalLootItemMap::const_iterator q_itr = lootPlayerQuestItems.find(lv.viewer->GetGUID().GetCounter()); if (q_itr != lootPlayerQuestItems.end()) { - QuestItemList* q_list = q_itr->second; - for (QuestItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi) + NotNormalLootItemList* q_list = q_itr->second; + for (NotNormalLootItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi) { LootItem &item = l.quest_items[qi->index]; if (!qi->is_looted && !item.is_looted) @@ -1017,12 +1017,12 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) } } - QuestItemMap const& lootPlayerFFAItems = l.GetPlayerFFAItems(); - QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(lv.viewer->GetGUID().GetCounter()); + NotNormalLootItemMap const& lootPlayerFFAItems = l.GetPlayerFFAItems(); + NotNormalLootItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(lv.viewer->GetGUID().GetCounter()); if (ffa_itr != lootPlayerFFAItems.end()) { - QuestItemList* ffa_list = ffa_itr->second; - for (QuestItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi) + NotNormalLootItemList* ffa_list = ffa_itr->second; + for (NotNormalLootItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi) { LootItem &item = l.items[fi->index]; if (!fi->is_looted && !item.is_looted) @@ -1035,42 +1035,37 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) } } - QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFAConditionalItems(); - QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(lv.viewer->GetGUID().GetCounter()); + NotNormalLootItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFAConditionalItems(); + NotNormalLootItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(lv.viewer->GetGUID().GetCounter()); if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end()) { - QuestItemList* conditional_list = nn_itr->second; - for (QuestItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci) + NotNormalLootItemList* conditional_list = nn_itr->second; + for (NotNormalLootItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci) { LootItem &item = l.items[ci->index]; if (!ci->is_looted && !item.is_looted) { b << uint8(ci->index); b << item; - if (item.follow_loot_rules) + switch (lv.permission) { - switch (lv.permission) - { - case MASTER_PERMISSION: - b << uint8(LOOT_SLOT_TYPE_MASTER); - break; - case RESTRICTED_PERMISSION: - b << (item.is_blocked ? uint8(LOOT_SLOT_TYPE_LOCKED) : uint8(slotType)); - break; - case GROUP_PERMISSION: - case ROUND_ROBIN_PERMISSION: - if (!item.is_blocked) - b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT); - else - b << uint8(LOOT_SLOT_TYPE_ROLL_ONGOING); - break; - default: - b << uint8(slotType); - break; - } - } - else + case MASTER_PERMISSION: + b << uint8(LOOT_SLOT_TYPE_MASTER); + break; + case RESTRICTED_PERMISSION: + b << (item.is_blocked ? uint8(LOOT_SLOT_TYPE_LOCKED) : uint8(slotType)); + break; + case GROUP_PERMISSION: + case ROUND_ROBIN_PERMISSION: + if (!item.is_blocked) + b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT); + else + b << uint8(LOOT_SLOT_TYPE_ROLL_ONGOING); + break; + default: b << uint8(slotType); + break; + } ++itemsShown; } } 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 ce0c749c294..bf913081fef 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -374,9 +374,9 @@ enum SpellAttr2 SPELL_ATTR2_IS_ARCANE_CONCENTRATION = 0x00800000, // 23 Only mage Arcane Concentration have this flag SPELL_ATTR2_UNK24 = 0x01000000, // 24 SPELL_ATTR2_UNK25 = 0x02000000, // 25 - SPELL_ATTR2_UNK26 = 0x04000000, // 26 unaffected by school immunity + SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE = 0x04000000, // 26 unaffected by school immunity SPELL_ATTR2_UNK27 = 0x08000000, // 27 - SPELL_ATTR2_UNK28 = 0x10000000, // 28 + SPELL_ATTR2_IGNORE_ITEM_CHECK = 0x10000000, // 28 Spell is cast without checking item requirements (charges/reagents/totem) SPELL_ATTR2_CANT_CRIT = 0x20000000, // 29 Spell can't crit SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC = 0x40000000, // 30 spell can trigger even if triggered SPELL_ATTR2_FOOD_BUFF = 0x80000000 // 31 Food or Drink Buff (like Well Fed) @@ -472,7 +472,7 @@ enum SpellAttr5 SPELL_ATTR5_HASTE_AFFECT_DURATION = 0x00002000, // 13 haste effects decrease duration of this SPELL_ATTR5_UNK14 = 0x00004000, // 14 SPELL_ATTR5_UNK15 = 0x00008000, // 15 Inflits on multiple targets? - SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK = 0x00010000, // 16 this allows spells with EquippedItemClass to affect spells from other items if the required item is equipped + SPELL_ATTR5_UNK16 = 0x00010000, // 16 SPELL_ATTR5_USABLE_WHILE_FEARED = 0x00020000, // 17 usable while feared SPELL_ATTR5_USABLE_WHILE_CONFUSED = 0x00040000, // 18 usable while confused SPELL_ATTR5_DONT_TURN_DURING_CAST = 0x00080000, // 19 Blocks caster's turning when casting (client does not automatically turn caster's model to face UNIT_FIELD_TARGET) @@ -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.] diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 4ad2a314111..105b4245ff3 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -20,7 +20,6 @@ #include "CreatureAISelector.h" #include "Creature.h" #include "ScriptSystem.h" - #include "ConfusedMovementGenerator.h" #include "FleeingMovementGenerator.h" #include "HomeMovementGenerator.h" @@ -33,9 +32,21 @@ #include "MoveSpline.h" #include "MoveSplineInit.h" -inline bool isStatic(MovementGenerator *mv) +inline bool IsStatic(MovementGenerator* movement) +{ + return (movement == &si_idleMovement); +} + +MotionMaster::~MotionMaster() { - return (mv == &si_idleMovement); + // clear ALL movement generators (including default) + while (!empty()) + { + MovementGenerator *curr = top(); + pop(); + if (curr && !IsStatic(curr)) + delete curr; // Skip finalizing on delete, it might launch new movement + } } void MotionMaster::Initialize() @@ -66,18 +77,6 @@ void MotionMaster::InitDefault() } } -MotionMaster::~MotionMaster() -{ - // clear ALL movement generators (including default) - while (!empty()) - { - MovementGenerator *curr = top(); - pop(); - if (curr && !isStatic(curr)) - delete curr; // Skip finalizing on delete, it might launch new movement - } -} - void MotionMaster::UpdateMotion(uint32 diff) { if (!_owner) @@ -97,20 +96,20 @@ void MotionMaster::UpdateMotion(uint32 diff) else _cleanFlag &= ~MMCF_UPDATE; - if (_expList) + if (_expireList) { - for (size_t i = 0; i < _expList->size(); ++i) + for (size_t i = 0; i < _expireList->size(); ++i) { - MovementGenerator* mg = (*_expList)[i]; + MovementGenerator* mg = (*_expireList)[i]; DirectDelete(mg); } - delete _expList; - _expList = NULL; + delete _expireList; + _expireList = nullptr; if (empty()) Initialize(); - else if (needInitTop()) + else if (NeedInitTop()) InitTop(); else if (_cleanFlag & MMCF_RESET) top()->Reset(_owner); @@ -122,84 +121,84 @@ void MotionMaster::UpdateMotion(uint32 diff) _owner->UpdateUnderwaterState(_owner->GetMap(), _owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ()); } -void MotionMaster::DirectClean(bool reset) +void MotionMaster::Clear(bool reset /*= true*/) { - while (size() > 1) + if (_cleanFlag & MMCF_UPDATE) { - MovementGenerator *curr = top(); - pop(); - if (curr) DirectDelete(curr); + if (reset) + _cleanFlag |= MMCF_RESET; + else + _cleanFlag &= ~MMCF_RESET; + DelayedClean(); } - - if (empty()) - return; - - if (needInitTop()) - InitTop(); - else if (reset) - top()->Reset(_owner); + else + DirectClean(reset); } -void MotionMaster::DelayedClean() +void MotionMaster::MovementExpired(bool reset /*= true*/) { - while (size() > 1) + if (_cleanFlag & MMCF_UPDATE) { - MovementGenerator *curr = top(); - pop(); - if (curr) - DelayedDelete(curr); + if (reset) + _cleanFlag |= MMCF_RESET; + else + _cleanFlag &= ~MMCF_RESET; + DelayedExpire(); } + else + DirectExpire(reset); } -void MotionMaster::DirectExpire(bool reset) +MovementGeneratorType MotionMaster::GetCurrentMovementGeneratorType() const { - if (size() > 1) - { - MovementGenerator *curr = top(); - pop(); - DirectDelete(curr); - } + if (empty()) + return IDLE_MOTION_TYPE; - while (!empty() && !top()) - --_top; + return top()->GetMovementGeneratorType(); +} - if (empty()) - Initialize(); - else if (needInitTop()) - InitTop(); - else if (reset) - top()->Reset(_owner); +MovementGeneratorType MotionMaster::GetMotionSlotType(int slot) const +{ + if (!_slot[slot]) + return NULL_MOTION_TYPE; + else + return _slot[slot]->GetMovementGeneratorType(); } -void MotionMaster::DelayedExpire() +MovementGenerator* MotionMaster::GetMotionSlot(int slot) const { - if (size() > 1) + ASSERT(slot >= 0); + return _slot[slot]; +} + +void MotionMaster::propagateSpeedChange() +{ + for (int i = 0; i <= _top; ++i) { - MovementGenerator *curr = top(); - pop(); - DelayedDelete(curr); + if (_slot[i]) + _slot[i]->unitSpeedChanged(); } +} - while (!empty() && !top()) - --_top; +bool MotionMaster::GetDestination(float &x, float &y, float &z) +{ + if (_owner->movespline->Finalized()) + return false; + + G3D::Vector3 const& dest = _owner->movespline->FinalDestination(); + x = dest.x; + y = dest.y; + z = dest.z; + return true; } void MotionMaster::MoveIdle() { //! Should be preceded by MovementExpired or Clear if there's an overlying movementgenerator active - if (empty() || !isStatic(top())) + if (empty() || !IsStatic(top())) Mutate(&si_idleMovement, MOTION_SLOT_IDLE); } -void MotionMaster::MoveRandom(float spawndist) -{ - if (_owner->GetTypeId() == TYPEID_UNIT) - { - TC_LOG_DEBUG("misc", "Creature (GUID: %u) started random movement.", _owner->GetGUID().GetCounter()); - Mutate(new RandomMovementGenerator<Creature>(spawndist), MOTION_SLOT_IDLE); - } -} - void MotionMaster::MoveTargetedHome() { Clear(false); @@ -225,18 +224,36 @@ void MotionMaster::MoveTargetedHome() } } -void MotionMaster::MoveConfused() +void MotionMaster::MoveRandom(float spawndist) { + if (_owner->GetTypeId() == TYPEID_UNIT) + { + TC_LOG_DEBUG("misc", "Creature (GUID: %u) started random movement.", _owner->GetGUID().GetCounter()); + Mutate(new RandomMovementGenerator<Creature>(spawndist), MOTION_SLOT_IDLE); + } +} + +void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlot slot) +{ + // ignore movement request if target not exist + if (!target || target == _owner) + return; + + //_owner->AddUnitState(UNIT_STATE_FOLLOW); if (_owner->GetTypeId() == TYPEID_PLAYER) { - TC_LOG_DEBUG("misc", "Player (GUID: %u) move confused", _owner->GetGUID().GetCounter()); - Mutate(new ConfusedMovementGenerator<Player>(), MOTION_SLOT_CONTROLLED); + TC_LOG_DEBUG("misc", "Player (GUID: %u) follows %s (GUID: %u).", _owner->GetGUID().GetCounter(), + target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", + target->GetTypeId() == TYPEID_PLAYER ? target->GetGUID().GetCounter() : target->ToCreature()->GetSpawnId()); + Mutate(new FollowMovementGenerator<Player>(target, dist, angle), slot); } else { - TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) move confused", - _owner->GetEntry(), _owner->GetGUID().GetCounter()); - Mutate(new ConfusedMovementGenerator<Creature>(), MOTION_SLOT_CONTROLLED); + TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) follows %s (GUID: %u).", + _owner->GetEntry(), _owner->GetGUID().GetCounter(), + target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", + target->GetTypeId() == TYPEID_PLAYER ? target->GetGUID().GetCounter() : target->ToCreature()->GetSpawnId()); + Mutate(new FollowMovementGenerator<Creature>(target, dist, angle), slot); } } @@ -265,27 +282,44 @@ void MotionMaster::MoveChase(Unit* target, float dist, float angle) } } -void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlot slot) +void MotionMaster::MoveConfused() { - // ignore movement request if target not exist - if (!target || target == _owner) + if (_owner->GetTypeId() == TYPEID_PLAYER) + { + TC_LOG_DEBUG("misc", "Player (GUID: %u) move confused", _owner->GetGUID().GetCounter()); + Mutate(new ConfusedMovementGenerator<Player>(), MOTION_SLOT_CONTROLLED); + } + else + { + TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) move confused", + _owner->GetEntry(), _owner->GetGUID().GetCounter()); + Mutate(new ConfusedMovementGenerator<Creature>(), MOTION_SLOT_CONTROLLED); + } +} + +void MotionMaster::MoveFleeing(Unit* enemy, uint32 time) +{ + if (!enemy) return; - //_owner->AddUnitState(UNIT_STATE_FOLLOW); if (_owner->GetTypeId() == TYPEID_PLAYER) { - TC_LOG_DEBUG("misc", "Player (GUID: %u) follows %s (GUID: %u).", _owner->GetGUID().GetCounter(), - target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", - target->GetTypeId() == TYPEID_PLAYER ? target->GetGUID().GetCounter() : target->ToCreature()->GetSpawnId()); - Mutate(new FollowMovementGenerator<Player>(target, dist, angle), slot); + TC_LOG_DEBUG("misc", "Player (GUID: %u) flees from %s (GUID: %u).", _owner->GetGUID().GetCounter(), + enemy->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", + enemy->GetTypeId() == TYPEID_PLAYER ? enemy->GetGUID().GetCounter() : enemy->ToCreature()->GetSpawnId()); + Mutate(new FleeingMovementGenerator<Player>(enemy->GetGUID()), MOTION_SLOT_CONTROLLED); } else { - TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) follows %s (GUID: %u).", + TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) flees from %s (GUID: %u)%s.", _owner->GetEntry(), _owner->GetGUID().GetCounter(), - target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", - target->GetTypeId() == TYPEID_PLAYER ? target->GetGUID().GetCounter() : target->ToCreature()->GetSpawnId()); - Mutate(new FollowMovementGenerator<Creature>(target, dist, angle), slot); + enemy->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", + enemy->GetTypeId() == TYPEID_PLAYER ? enemy->GetGUID().GetCounter() : enemy->ToCreature()->GetSpawnId(), + time ? " for a limited time" : ""); + if (time) + Mutate(new TimedFleeingMovementGenerator(enemy->GetGUID(), time), MOTION_SLOT_CONTROLLED); + else + Mutate(new FleeingMovementGenerator<Creature>(enemy->GetGUID()), MOTION_SLOT_CONTROLLED); } } @@ -353,6 +387,37 @@ void MotionMaster::MoveTakeoff(uint32 id, Position const& pos) Mutate(new EffectMovementGenerator(id), MOTION_SLOT_ACTIVE); } +void MotionMaster::MoveCharge(float x, float y, float z, float speed /*= SPEED_CHARGE*/, uint32 id /*= EVENT_CHARGE*/, bool generatePath /*= false*/) +{ + if (_slot[MOTION_SLOT_CONTROLLED] && _slot[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE) + return; + + if (_owner->GetTypeId() == TYPEID_PLAYER) + { + TC_LOG_DEBUG("misc", "Player (GUID: %u) charged point (X: %f Y: %f Z: %f).", _owner->GetGUID().GetCounter(), x, y, z); + Mutate(new PointMovementGenerator<Player>(id, x, y, z, generatePath, speed), MOTION_SLOT_CONTROLLED); + } + else + { + TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) charged point (X: %f Y: %f Z: %f).", + _owner->GetEntry(), _owner->GetGUID().GetCounter(), x, y, z); + Mutate(new PointMovementGenerator<Creature>(id, x, y, z, generatePath, speed), MOTION_SLOT_CONTROLLED); + } +} + +void MotionMaster::MoveCharge(PathGenerator const& path, float speed /*= SPEED_CHARGE*/) +{ + G3D::Vector3 dest = path.GetActualEndPosition(); + + MoveCharge(dest.x, dest.y, dest.z, speed, EVENT_CHARGE_PREPATH); + + // Charge movement is not started when using EVENT_CHARGE_PREPATH + Movement::MoveSplineInit init(_owner); + init.MovebyPath(path.GetPath()); + init.SetVelocity(speed); + init.Launch(); +} + void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ) { //this function may make players fall below map @@ -531,37 +596,6 @@ void MotionMaster::MoveFall(uint32 id /*=0*/) Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED); } -void MotionMaster::MoveCharge(float x, float y, float z, float speed /*= SPEED_CHARGE*/, uint32 id /*= EVENT_CHARGE*/, bool generatePath /*= false*/) -{ - if (Impl[MOTION_SLOT_CONTROLLED] && Impl[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE) - return; - - if (_owner->GetTypeId() == TYPEID_PLAYER) - { - TC_LOG_DEBUG("misc", "Player (GUID: %u) charged point (X: %f Y: %f Z: %f).", _owner->GetGUID().GetCounter(), x, y, z); - Mutate(new PointMovementGenerator<Player>(id, x, y, z, generatePath, speed), MOTION_SLOT_CONTROLLED); - } - else - { - TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) charged point (X: %f Y: %f Z: %f).", - _owner->GetEntry(), _owner->GetGUID().GetCounter(), x, y, z); - Mutate(new PointMovementGenerator<Creature>(id, x, y, z, generatePath, speed), MOTION_SLOT_CONTROLLED); - } -} - -void MotionMaster::MoveCharge(PathGenerator const& path, float speed /*= SPEED_CHARGE*/) -{ - G3D::Vector3 dest = path.GetActualEndPosition(); - - MoveCharge(dest.x, dest.y, dest.z, speed, EVENT_CHARGE_PREPATH); - - // Charge movement is not started when using EVENT_CHARGE_PREPATH - Movement::MoveSplineInit init(_owner); - init.MovebyPath(path.GetPath()); - init.SetVelocity(speed); - init.Launch(); -} - void MotionMaster::MoveSeekAssistance(float x, float y, float z) { if (_owner->GetTypeId() == TYPEID_PLAYER) @@ -593,32 +627,6 @@ void MotionMaster::MoveSeekAssistanceDistract(uint32 time) } } -void MotionMaster::MoveFleeing(Unit* enemy, uint32 time) -{ - if (!enemy) - return; - - if (_owner->GetTypeId() == TYPEID_PLAYER) - { - TC_LOG_DEBUG("misc", "Player (GUID: %u) flees from %s (GUID: %u).", _owner->GetGUID().GetCounter(), - enemy->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", - enemy->GetTypeId() == TYPEID_PLAYER ? enemy->GetGUID().GetCounter() : enemy->ToCreature()->GetSpawnId()); - Mutate(new FleeingMovementGenerator<Player>(enemy->GetGUID()), MOTION_SLOT_CONTROLLED); - } - else - { - TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) flees from %s (GUID: %u)%s.", - _owner->GetEntry(), _owner->GetGUID().GetCounter(), - enemy->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", - enemy->GetTypeId() == TYPEID_PLAYER ? enemy->GetGUID().GetCounter() : enemy->ToCreature()->GetSpawnId(), - time ? " for a limited time" : ""); - if (time) - Mutate(new TimedFleeingMovementGenerator(enemy->GetGUID(), time), MOTION_SLOT_CONTROLLED); - else - Mutate(new FleeingMovementGenerator<Creature>(enemy->GetGUID()), MOTION_SLOT_CONTROLLED); - } -} - void MotionMaster::MoveTaxiFlight(uint32 path, uint32 pathnode) { if (_owner->GetTypeId() == TYPEID_PLAYER) @@ -645,7 +653,7 @@ void MotionMaster::MoveTaxiFlight(uint32 path, uint32 pathnode) void MotionMaster::MoveDistract(uint32 timer) { - if (Impl[MOTION_SLOT_CONTROLLED]) + if (_slot[MOTION_SLOT_CONTROLLED]) return; if (_owner->GetTypeId() == TYPEID_PLAYER) @@ -662,11 +670,56 @@ void MotionMaster::MoveDistract(uint32 timer) Mutate(mgen, MOTION_SLOT_CONTROLLED); } +void MotionMaster::MovePath(uint32 path_id, bool repeatable) +{ + if (!path_id) + return; + + Mutate(new WaypointMovementGenerator<Creature>(path_id, repeatable), MOTION_SLOT_IDLE); + + TC_LOG_DEBUG("misc", "%s (GUID: %u) starts moving over path(Id:%u, repeatable: %s).", + _owner->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature", + _owner->GetGUID().GetCounter(), path_id, repeatable ? "YES" : "NO"); +} + +void MotionMaster::MoveRotate(uint32 time, RotateDirection direction) +{ + if (!time) + return; + + Mutate(new RotateMovementGenerator(time, direction), MOTION_SLOT_ACTIVE); +} + +/******************** Private methods ********************/ + +void MotionMaster::pop() +{ + if (empty()) + return; + + _slot[_top] = nullptr; + while (!empty() && !top()) + --_top; +} + +bool MotionMaster::NeedInitTop() const +{ + if (empty()) + return false; + return _initialize[_top]; +} + +void MotionMaster::InitTop() +{ + top()->Initialize(_owner); + _initialize[_top] = false; +} + void MotionMaster::Mutate(MovementGenerator *m, MovementSlot slot) { - if (MovementGenerator *curr = Impl[slot]) + if (MovementGenerator *curr = _slot[slot]) { - Impl[slot] = NULL; // in case a new one is generated in this slot during directdelete + _slot[slot] = nullptr; // in case a new one is generated in this slot during directdelete if (_top == slot && (_cleanFlag & MMCF_UPDATE)) DelayedDelete(curr); else @@ -677,110 +730,92 @@ void MotionMaster::Mutate(MovementGenerator *m, MovementSlot slot) _top = slot; } - Impl[slot] = m; + _slot[slot] = m; if (_top > slot) - _needInit[slot] = true; + _initialize[slot] = true; else { - _needInit[slot] = false; + _initialize[slot] = false; m->Initialize(_owner); } } -void MotionMaster::MovePath(uint32 path_id, bool repeatable) +void MotionMaster::DirectClean(bool reset) { - if (!path_id) - return; - //We set waypoint movement as new default movement generator - // clear ALL movement generators (including default) - /*while (!empty()) + while (size() > 1) { MovementGenerator *curr = top(); - curr->Finalize(*_owner); pop(); - if (!isStatic(curr)) - delete curr; - }*/ - - //_owner->GetTypeId() == TYPEID_PLAYER ? - //Mutate(new WaypointMovementGenerator<Player>(path_id, repeatable)): - Mutate(new WaypointMovementGenerator<Creature>(path_id, repeatable), MOTION_SLOT_IDLE); - - TC_LOG_DEBUG("misc", "%s (GUID: %u) starts moving over path(Id:%u, repeatable: %s).", - _owner->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature", - _owner->GetGUID().GetCounter(), path_id, repeatable ? "YES" : "NO"); -} + if (curr) DirectDelete(curr); + } -void MotionMaster::MoveRotate(uint32 time, RotateDirection direction) -{ - if (!time) + if (empty()) return; - Mutate(new RotateMovementGenerator(time, direction), MOTION_SLOT_ACTIVE); + if (NeedInitTop()) + InitTop(); + else if (reset) + top()->Reset(_owner); } -void MotionMaster::propagateSpeedChange() +void MotionMaster::DelayedClean() { - /*Impl::container_type::iterator it = Impl::c.begin(); - for (; it != end(); ++it) - { - (*it)->unitSpeedChanged(); - }*/ - for (int i = 0; i <= _top; ++i) + while (size() > 1) { - if (Impl[i]) - Impl[i]->unitSpeedChanged(); + MovementGenerator *curr = top(); + pop(); + if (curr) + DelayedDelete(curr); } } -MovementGeneratorType MotionMaster::GetCurrentMovementGeneratorType() const +void MotionMaster::DirectExpire(bool reset) { - if (empty()) - return IDLE_MOTION_TYPE; + if (size() > 1) + { + MovementGenerator *curr = top(); + pop(); + DirectDelete(curr); + } - return top()->GetMovementGeneratorType(); -} + while (!empty() && !top()) + --_top; -MovementGeneratorType MotionMaster::GetMotionSlotType(int slot) const -{ - if (!Impl[slot]) - return NULL_MOTION_TYPE; - else - return Impl[slot]->GetMovementGeneratorType(); + if (empty()) + Initialize(); + else if (NeedInitTop()) + InitTop(); + else if (reset) + top()->Reset(_owner); } -void MotionMaster::InitTop() +void MotionMaster::DelayedExpire() { - top()->Initialize(_owner); - _needInit[_top] = false; + if (size() > 1) + { + MovementGenerator *curr = top(); + pop(); + DelayedDelete(curr); + } + + while (!empty() && !top()) + --_top; } -void MotionMaster::DirectDelete(_Ty curr) +void MotionMaster::DirectDelete(MovementGenerator* curr) { - if (isStatic(curr)) + if (IsStatic(curr)) return; curr->Finalize(_owner); delete curr; } -void MotionMaster::DelayedDelete(_Ty curr) +void MotionMaster::DelayedDelete(MovementGenerator* curr) { TC_LOG_FATAL("misc", "Unit (Entry %u) is trying to delete its updating Movement Generator (Type %u)!", _owner->GetEntry(), curr->GetMovementGeneratorType()); - if (isStatic(curr)) + if (IsStatic(curr)) return; - if (!_expList) - _expList = new ExpireList(); - _expList->push_back(curr); -} - -bool MotionMaster::GetDestination(float &x, float &y, float &z) -{ - if (_owner->movespline->Finalized()) - return false; - - G3D::Vector3 const& dest = _owner->movespline->FinalDestination(); - x = dest.x; - y = dest.y; - z = dest.z; - return true; + if (!_expireList) + _expireList = new ExpireList(); + _expireList->push_back(curr); } diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index d376f6aa58f..0f46f42e08e 100644 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -16,8 +16,8 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef TRINITY_MOTIONMASTER_H -#define TRINITY_MOTIONMASTER_H +#ifndef MOTIONMASTER_H +#define MOTIONMASTER_H #include "Common.h" #include <vector> @@ -32,31 +32,32 @@ class PathGenerator; // Creature Entry ID used for waypoints show, visible only for GMs #define VISUAL_WAYPOINT 1 +// assume it is 25 yard per 0.6 second +#define SPEED_CHARGE 42.0f -// values 0 ... MAX_DB_MOTION_TYPE-1 used in DB enum MovementGeneratorType { - IDLE_MOTION_TYPE = 0, // IdleMovementGenerator.h - RANDOM_MOTION_TYPE = 1, // RandomMovementGenerator.h - WAYPOINT_MOTION_TYPE = 2, // WaypointMovementGenerator.h - MAX_DB_MOTION_TYPE = 3, // *** this and below motion types can't be set in DB. - ANIMAL_RANDOM_MOTION_TYPE = MAX_DB_MOTION_TYPE, // AnimalRandomMovementGenerator.h - CONFUSED_MOTION_TYPE = 4, // ConfusedMovementGenerator.h - CHASE_MOTION_TYPE = 5, // TargetedMovementGenerator.h - HOME_MOTION_TYPE = 6, // HomeMovementGenerator.h - FLIGHT_MOTION_TYPE = 7, // WaypointMovementGenerator.h - POINT_MOTION_TYPE = 8, // PointMovementGenerator.h - FLEEING_MOTION_TYPE = 9, // FleeingMovementGenerator.h - DISTRACT_MOTION_TYPE = 10, // IdleMovementGenerator.h - ASSISTANCE_MOTION_TYPE= 11, // PointMovementGenerator.h (first part of flee for assistance) - ASSISTANCE_DISTRACT_MOTION_TYPE = 12, // IdleMovementGenerator.h (second part of flee for assistance) - TIMED_FLEEING_MOTION_TYPE = 13, // FleeingMovementGenerator.h (alt.second part of flee for assistance) - FOLLOW_MOTION_TYPE = 14, - ROTATE_MOTION_TYPE = 15, - EFFECT_MOTION_TYPE = 16, - NULL_MOTION_TYPE = 17, - SPLINE_CHAIN_MOTION_TYPE = 18, // SplineChainMovementGenerator.h - MAX_MOTION_TYPE // limit + IDLE_MOTION_TYPE = 0, // IdleMovementGenerator.h + RANDOM_MOTION_TYPE = 1, // RandomMovementGenerator.h + WAYPOINT_MOTION_TYPE = 2, // WaypointMovementGenerator.h + MAX_DB_MOTION_TYPE = 3, // Below motion types can't be set in DB. + ANIMAL_RANDOM_MOTION_TYPE = MAX_DB_MOTION_TYPE, // AnimalRandomMovementGenerator.h + CONFUSED_MOTION_TYPE = 4, // ConfusedMovementGenerator.h + CHASE_MOTION_TYPE = 5, // TargetedMovementGenerator.h + HOME_MOTION_TYPE = 6, // HomeMovementGenerator.h + FLIGHT_MOTION_TYPE = 7, // WaypointMovementGenerator.h + POINT_MOTION_TYPE = 8, // PointMovementGenerator.h + FLEEING_MOTION_TYPE = 9, // FleeingMovementGenerator.h + DISTRACT_MOTION_TYPE = 10, // IdleMovementGenerator.h + ASSISTANCE_MOTION_TYPE = 11, // PointMovementGenerator.h (first part of flee for assistance) + ASSISTANCE_DISTRACT_MOTION_TYPE = 12, // IdleMovementGenerator.h (second part of flee for assistance) + TIMED_FLEEING_MOTION_TYPE = 13, // FleeingMovementGenerator.h (alt.second part of flee for assistance) + FOLLOW_MOTION_TYPE = 14, + ROTATE_MOTION_TYPE = 15, + EFFECT_MOTION_TYPE = 16, + NULL_MOTION_TYPE = 17, + SPLINE_CHAIN_MOTION_TYPE = 18, // SplineChainMovementGenerator.h + MAX_MOTION_TYPE // limit }; enum MovementSlot @@ -80,91 +81,41 @@ enum RotateDirection ROTATE_DIRECTION_RIGHT }; -// assume it is 25 yard per 0.6 second -#define SPEED_CHARGE 42.0f - -class TC_GAME_API MotionMaster //: private std::stack<MovementGenerator *> +class TC_GAME_API MotionMaster { private: - //typedef std::stack<MovementGenerator *> Impl; - typedef MovementGenerator* _Ty; - - void pop() - { - if (empty()) - return; + typedef std::vector<MovementGenerator*> ExpireList; - Impl[_top] = NULL; - while (!empty() && !top()) - --_top; - } - void push(_Ty _Val) { ++_top; Impl[_top] = _Val; } - - bool needInitTop() const - { - if (empty()) - return false; - return _needInit[_top]; - } - void InitTop(); public: - - explicit MotionMaster(Unit* unit) : _expList(NULL), _top(-1), _owner(unit), _cleanFlag(MMCF_NONE) + explicit MotionMaster(Unit* unit) : _expireList(nullptr), _top(-1), _owner(unit), _cleanFlag(MMCF_NONE) { for (uint8 i = 0; i < MAX_MOTION_SLOT; ++i) { - Impl[i] = NULL; - _needInit[i] = true; + _slot[i] = nullptr; + _initialize[i] = true; } } ~MotionMaster(); - void Initialize(); - void InitDefault(); - bool empty() const { return (_top < 0); } int size() const { return _top + 1; } - _Ty top() const - { - ASSERT(!empty()); - return Impl[_top]; - } - _Ty GetMotionSlot(int slot) const - { - ASSERT(slot >= 0); - return Impl[slot]; - } + MovementGenerator* top() const { ASSERT(!empty()); return _slot[_top]; } - void DirectDelete(_Ty curr); - void DelayedDelete(_Ty curr); + void Initialize(); + void InitDefault(); void UpdateMotion(uint32 diff); - void Clear(bool reset = true) - { - if (_cleanFlag & MMCF_UPDATE) - { - if (reset) - _cleanFlag |= MMCF_RESET; - else - _cleanFlag &= ~MMCF_RESET; - DelayedClean(); - } - else - DirectClean(reset); - } - void MovementExpired(bool reset = true) - { - if (_cleanFlag & MMCF_UPDATE) - { - if (reset) - _cleanFlag |= MMCF_RESET; - else - _cleanFlag &= ~MMCF_RESET; - DelayedExpire(); - } - else - DirectExpire(reset); - } + + void Clear(bool reset = true); + void MovementExpired(bool reset = true); + + MovementGeneratorType GetCurrentMovementGeneratorType() const; + MovementGeneratorType GetMotionSlotType(int slot) const; + MovementGenerator* GetMotionSlot(int slot) const; + + void propagateSpeedChange(); + + bool GetDestination(float &x, float &y, float &z); void MoveIdle(); void MoveTargetedHome(); @@ -174,7 +125,9 @@ class TC_GAME_API MotionMaster //: private std::stack<MovementGenerator *> void MoveConfused(); void MoveFleeing(Unit* enemy, uint32 time = 0); void MovePoint(uint32 id, Position const& pos, bool generatePath = true) - { MovePoint(id, pos.m_positionX, pos.m_positionY, pos.m_positionZ, generatePath); } + { + MovePoint(id, pos.m_positionX, pos.m_positionY, pos.m_positionZ, generatePath); + } void MovePoint(uint32 id, float x, float y, float z, bool generatePath = true); /* Makes the unit move toward the target until it is at a certain distance from it. The unit then stops. @@ -212,27 +165,27 @@ class TC_GAME_API MotionMaster //: private std::stack<MovementGenerator *> void MovePath(uint32 path_id, bool repeatable); void MoveRotate(uint32 time, RotateDirection direction); - MovementGeneratorType GetCurrentMovementGeneratorType() const; - MovementGeneratorType GetMotionSlotType(int slot) const; + private: + void pop(); - void propagateSpeedChange(); + bool NeedInitTop() const; + void InitTop(); - bool GetDestination(float &x, float &y, float &z); - private: - void Mutate(MovementGenerator *m, MovementSlot slot); // use Move* functions instead + void Mutate(MovementGenerator *m, MovementSlot slot); void DirectClean(bool reset); void DelayedClean(); - void DirectExpire(bool reset); void DelayedExpire(); + void DirectDelete(MovementGenerator* curr); + void DelayedDelete(MovementGenerator* curr); - typedef std::vector<_Ty> ExpireList; - ExpireList* _expList; - _Ty Impl[MAX_MOTION_SLOT]; + ExpireList* _expireList; + MovementGenerator* _slot[MAX_MOTION_SLOT]; int _top; Unit* _owner; - bool _needInit[MAX_MOTION_SLOT]; + bool _initialize[MAX_MOTION_SLOT]; uint8 _cleanFlag; }; -#endif + +#endif // MOTIONMASTER_H 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..2b4e2e4177d 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; } @@ -1176,15 +1171,15 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const if (apply) { if (spellId) - target->CastSpell(target, spellId, true, NULL, this); + target->CastSpell(target, spellId, true, nullptr, this); if (spellId2) - target->CastSpell(target, spellId2, true, NULL, this); + target->CastSpell(target, spellId2, true, nullptr, this); if (target->GetTypeId() == TYPEID_PLAYER) { - const PlayerSpellMap& sp_list = target->ToPlayer()->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) + PlayerSpellMap const& sp_list = target->ToPlayer()->GetSpellMap(); + for (auto itr = sp_list.begin(); itr != sp_list.end(); ++itr) { if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) continue; @@ -1197,7 +1192,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const continue; if (spellInfo->Stances & (UI64LIT(1) << (GetMiscValue() - 1))) - target->CastSpell(target, itr->first, true, NULL, this); + target->CastSpell(target, itr->first, true, nullptr, this); } // Also do it for Glyphs @@ -1212,7 +1207,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const continue; if (spellInfo->Stances & (UI64LIT(1) << (GetMiscValue() - 1))) - target->CastSpell(target, glyph->SpellId, true, NULL, this); + target->CastSpell(target, glyph->SpellId, true, nullptr, this); } } } @@ -1222,7 +1217,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(24932); if (spellInfo && spellInfo->Stances & (UI64LIT(1) << (GetMiscValue() - 1))) - target->CastSpell(target, 24932, true, NULL, this); + target->CastSpell(target, 24932, true, nullptr, this); } // Improved Barkskin - apply/remove armor bonus due to shapeshift if (target->ToPlayer()->HasSpell(63410) || target->ToPlayer()->HasSpell(63411)) @@ -1235,14 +1230,14 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const if (HotWSpellId) { // hacky, but the only way as spell family is not SPELLFAMILY_DRUID Unit::AuraEffectList const& mModTotalStatPct = target->GetAuraEffectsByType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE); - for (Unit::AuraEffectList::const_iterator i = mModTotalStatPct.begin(); i != mModTotalStatPct.end(); ++i) + for (AuraEffect const* aurEff : mModTotalStatPct) { // Heart of the Wild - if ((*i)->GetSpellInfo()->SpellIconID == 240 && (*i)->GetMiscValue() == 3) + if (aurEff->GetSpellInfo()->SpellIconID == 240 && aurEff->GetMiscValue() == 3) { - int32 HotWMod = (*i)->GetAmount() / 2; // For each 2% Intelligence, you get 1% stamina and 1% attack power. + int32 HotWMod = aurEff->GetAmount() / 2; // For each 2% Intelligence, you get 1% stamina and 1% attack power. - target->CastCustomSpell(target, HotWSpellId, &HotWMod, NULL, NULL, true, NULL, this); + target->CastCustomSpell(HotWSpellId, SPELLVALUE_BASE_POINT0, HotWMod, target, true, nullptr, this); break; } } @@ -1266,13 +1261,13 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const spellId3 = 47180; break; } - target->CastSpell(target, spellId3, true, NULL, this); + target->CastSpell(target, spellId3, true, nullptr, this); } // Master Shapeshifter - Cat if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) { int32 bp = aurEff->GetAmount(); - target->CastCustomSpell(target, 48420, &bp, NULL, NULL, true); + target->CastCustomSpell(48420, SPELLVALUE_BASE_POINT0, bp, target, true); } break; case FORM_DIREBEAR: @@ -1281,13 +1276,13 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) { int32 bp = aurEff->GetAmount(); - target->CastCustomSpell(target, 48418, &bp, NULL, NULL, true); + target->CastCustomSpell(48418, SPELLVALUE_BASE_POINT0, bp, target, true); } // Survival of the Fittest if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, SPELLFAMILY_DRUID, 961, 0)) { int32 bp = aurEff->GetSpellInfo()->Effects[EFFECT_2].CalcValue(); - target->CastCustomSpell(target, 62069, &bp, NULL, NULL, true, 0, this); + target->CastCustomSpell(62069, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, this); } break; case FORM_MOONKIN: @@ -1295,7 +1290,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) { int32 bp = aurEff->GetAmount(); - target->CastCustomSpell(target, 48421, &bp, NULL, NULL, true); + target->CastCustomSpell(48421, SPELLVALUE_BASE_POINT0, bp, target, true); } break; // Master Shapeshifter - Tree of Life @@ -1303,7 +1298,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) { int32 bp = aurEff->GetAmount(); - target->CastCustomSpell(target, 48422, &bp, NULL, NULL, true); + target->CastCustomSpell(48422, SPELLVALUE_BASE_POINT0, bp, target, true); } break; } @@ -1317,7 +1312,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const target->RemoveOwnedAura(spellId2, target->GetGUID()); // Improved Barkskin - apply/remove armor bonus due to shapeshift - if (Player* player=target->ToPlayer()) + if (Player* player = target->ToPlayer()) { if (player->HasSpell(63410) || player->HasSpell(63411)) { @@ -1326,19 +1321,20 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const } } - const Unit::AuraEffectList& shapeshifts = target->GetAuraEffectsByType(SPELL_AURA_MOD_SHAPESHIFT); - AuraEffect* newAura = NULL; + Unit::AuraEffectList const& shapeshifts = target->GetAuraEffectsByType(SPELL_AURA_MOD_SHAPESHIFT); + AuraEffect const* newAura = nullptr; // Iterate through all the shapeshift auras that the target has, if there is another aura with SPELL_AURA_MOD_SHAPESHIFT, then this aura is being removed due to that one being applied - for (Unit::AuraEffectList::const_iterator itr = shapeshifts.begin(); itr != shapeshifts.end(); ++itr) + for (AuraEffect const* aurEff : shapeshifts) { - if ((*itr) != this) + if (aurEff != this) { - newAura = *itr; + newAura = aurEff; break; } } + Unit::AuraApplicationMap& tAuras = target->GetAppliedAuras(); - for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();) + for (auto itr = tAuras.begin(); itr != tAuras.end();) { // Use the new aura to see on what stance the target will be uint64 newStance = newAura ? (UI64LIT(1) << (newAura->GetMiscValue() - 1)) : 0; @@ -1779,7 +1775,12 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo if (aurApp->GetRemoveMode()) return; + ShapeshiftForm prevForm = target->GetShapeshiftForm(); target->SetShapeshiftForm(form); + // add the shapeshift aura's boosts + if (prevForm != form) + HandleShapeshiftBoosts(target, true); + if (modelid > 0) { SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(target->getTransForm()); @@ -1851,11 +1852,10 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo default: break; } - } - // adding/removing linked auras - // add/remove the shapeshift aura's boosts - HandleShapeshiftBoosts(target, apply); + // remove the shapeshift aura's boosts + HandleShapeshiftBoosts(target, false); + } if (target->GetTypeId() == TYPEID_PLAYER) target->ToPlayer()->InitDataForForm(); @@ -2307,11 +2307,9 @@ void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode, { uint8 attacktype = Player::GetAttackBySlot(slot); + player->ApplyItemDependentAuras(item, !apply); if (attacktype < MAX_ATTACK) - { player->_ApplyWeaponDamage(slot, item->GetTemplate(), NULL, !apply); - player->_ApplyWeaponDependentAuraMods(item, WeaponAttackType(attacktype), !apply); - } } } @@ -3069,249 +3067,13 @@ void AuraEffect::HandleAuraModUseNormalSpeed(AuraApplication const* aurApp, uint /*** IMMUNITY ***/ /*********************************************************/ -void AuraEffect::HandleModStateImmunityMask(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModMechanicImmunityMask(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); - std::list <AuraType> aura_immunity_list; - uint32 mechanic_immunity_list = 0; - int32 miscVal = GetMiscValue(); - - switch (miscVal) - { - case 27: - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SILENCE, apply); - aura_immunity_list.push_back(SPELL_AURA_MOD_SILENCE); - break; - case 96: - case 1615: - { - if (GetAmount()) - { - mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT) - | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN) - | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM) - | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR) - | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED) - | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN); - - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply); - aura_immunity_list.push_back(SPELL_AURA_MOD_STUN); - aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED); - aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT); - aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE); - aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR); - } - break; - } - case 679: - { - if (GetId() == 57742) - { - mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT) - | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN) - | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM) - | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR) - | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED) - | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN); - - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply); - aura_immunity_list.push_back(SPELL_AURA_MOD_STUN); - aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED); - aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT); - aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE); - aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR); - } - break; - } - case 1557: - { - if (GetId() == 64187) - { - mechanic_immunity_list = (1 << MECHANIC_STUN); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply); - aura_immunity_list.push_back(SPELL_AURA_MOD_STUN); - } - else - { - mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT) - | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN) - | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM) - | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR) - | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED) - | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN); - - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply); - aura_immunity_list.push_back(SPELL_AURA_MOD_STUN); - aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED); - aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT); - aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE); - aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR); - } - break; - } - case 1614: - case 1694: - { - target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, apply); - aura_immunity_list.push_back(SPELL_AURA_MOD_TAUNT); - break; - } - case 1630: - { - if (!GetAmount()) - { - target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, apply); - aura_immunity_list.push_back(SPELL_AURA_MOD_TAUNT); - } - else - { - mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT) - | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN) - | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM) - | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR) - | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED) - | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN); - - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply); - aura_immunity_list.push_back(SPELL_AURA_MOD_STUN); - aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED); - aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT); - aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE); - aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR); - } - break; - } - case 477: - case 1733: - { - if (!GetAmount()) - { - mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT) - | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN) - | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM) - | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR) - | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED) - | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN); - - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, apply); - aura_immunity_list.push_back(SPELL_AURA_MOD_STUN); - aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED); - aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT); - aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE); - aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR); - } - break; - } - case 878: - { - if (GetAmount() == 1) - { - mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_STUN) - | (1 << MECHANIC_DISORIENTED) | (1 << MECHANIC_FREEZE); - - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply); - aura_immunity_list.push_back(SPELL_AURA_MOD_STUN); - aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED); - } - break; - } - default: - break; - } - - if (aura_immunity_list.empty()) - { - if (miscVal & (1<<10)) - aura_immunity_list.push_back(SPELL_AURA_MOD_STUN); - if (miscVal & (1<<1)) - aura_immunity_list.push_back(SPELL_AURA_TRANSFORM); - - // These flag can be recognized wrong: - if (miscVal & (1<<6)) - aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED); - if (miscVal & (1<<0)) - aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT); - if (miscVal & (1<<2)) - aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE); - if (miscVal & (1<<9)) - aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR); - if (miscVal & (1<<7)) - aura_immunity_list.push_back(SPELL_AURA_MOD_DISARM); - } - - // apply immunities - for (std::list <AuraType>::iterator iter = aura_immunity_list.begin(); iter != aura_immunity_list.end(); ++iter) - target->ApplySpellImmune(GetId(), IMMUNITY_STATE, *iter, apply); - - if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)) - { - target->RemoveAurasWithMechanic(mechanic_immunity_list, AURA_REMOVE_BY_DEFAULT, GetId()); - for (std::list <AuraType>::iterator iter = aura_immunity_list.begin(); iter != aura_immunity_list.end(); ++iter) - target->RemoveAurasByType(*iter); - } + m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetEffIndex(), apply); } void AuraEffect::HandleModMechanicImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3320,52 +3082,7 @@ void AuraEffect::HandleModMechanicImmunity(AuraApplication const* aurApp, uint8 return; Unit* target = aurApp->GetTarget(); - uint32 mechanic; - - switch (GetId()) - { - case 34471: // The Beast Within - case 19574: // Bestial Wrath - mechanic = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK; - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_KNOCKOUT, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_BANISH, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SHACKLE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DAZE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply); - break; - case 42292: // PvP trinket - case 59752: // Every Man for Himself - case 53490: // Bullheaded - mechanic = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK; - // Actually we should apply immunities here, too, but the aura has only 100 ms duration, so there is practically no point - break; - case 54508: // Demonic Empowerment - mechanic = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply); - break; - default: - if (GetMiscValue() < 1) - return; - mechanic = 1 << GetMiscValue(); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, GetMiscValue(), apply); - break; - } - - if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)) - target->RemoveAurasWithMechanic(mechanic, AURA_REMOVE_BY_DEFAULT, GetId()); + m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetEffIndex(), apply); } void AuraEffect::HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3374,8 +3091,7 @@ void AuraEffect::HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint return; Unit* target = aurApp->GetTarget(); - - target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, GetMiscValue(), apply); + m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetEffIndex(), apply); // when removing flag aura, handle flag drop Player* player = target->ToPlayer(); @@ -3397,11 +3113,7 @@ void AuraEffect::HandleAuraModStateImmunity(AuraApplication const* aurApp, uint8 return; Unit* target = aurApp->GetTarget(); - - target->ApplySpellImmune(GetId(), IMMUNITY_STATE, GetMiscValue(), apply); - - if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)) - target->RemoveAurasByType(AuraType(GetMiscValue()), ObjectGuid::Empty, GetBase()); + m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetEffIndex(), apply); } void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3410,8 +3122,7 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint return; Unit* target = aurApp->GetTarget(); - - target->ApplySpellImmune(GetId(), IMMUNITY_SCHOOL, GetMiscValue(), (apply)); + m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetEffIndex(), apply); if (GetSpellInfo()->Mechanic == MECHANIC_BANISH) { @@ -3421,12 +3132,15 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint { bool banishFound = false; Unit::AuraEffectList const& banishAuras = target->GetAuraEffectsByType(GetAuraType()); - for (Unit::AuraEffectList::const_iterator i = banishAuras.begin(); i != banishAuras.end(); ++i) - if ((*i)->GetSpellInfo()->Mechanic == MECHANIC_BANISH) + for (AuraEffect const* aurEff : banishAuras) + { + if (aurEff->GetSpellInfo()->Mechanic == MECHANIC_BANISH) { banishFound = true; break; } + } + if (!banishFound) target->ClearUnitState(UNIT_STATE_ISOLATED); } @@ -3439,23 +3153,6 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint if (GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) && GetSpellInfo()->HasAttribute(SPELL_ATTR2_DAMAGE_REDUCED_SHIELD)) target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); - - /// @todo optimalize this cycle - use RemoveAurasWithInterruptFlags call or something else - if (apply - && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) - && GetSpellInfo()->IsPositive()) // Only positive immunity removes auras - { - uint32 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 +3161,7 @@ void AuraEffect::HandleAuraModDmgImmunity(AuraApplication const* aurApp, uint8 m return; Unit* target = aurApp->GetTarget(); - - target->ApplySpellImmune(GetId(), IMMUNITY_DAMAGE, GetMiscValue(), apply); + m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetEffIndex(), apply); } void AuraEffect::HandleAuraModDispelImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3474,8 +3170,7 @@ void AuraEffect::HandleAuraModDispelImmunity(AuraApplication const* aurApp, uint return; Unit* target = aurApp->GetTarget(); - - target->ApplySpellDispelImmunity(m_spellInfo, DispelType(GetMiscValue()), (apply)); + m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetEffIndex(), apply); } /*********************************************************/ @@ -4071,29 +3766,14 @@ void AuraEffect::HandleAuraModWeaponCritPercent(AuraApplication const* aurApp, u if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; - Unit* target = aurApp->GetTarget(); + Player* target = aurApp->GetTarget()->ToPlayer(); - if (target->GetTypeId() != TYPEID_PLAYER) + if (!target) return; - for (int i = 0; i < MAX_ATTACK; ++i) - if (Item* pItem = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true)) - target->ToPlayer()->_ApplyWeaponDependentAuraCritMod(pItem, WeaponAttackType(i), this, apply); - - // mods must be applied base at equipped weapon class and subclass comparison - // with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask - // GetMiscValue() comparison with item generated damage types - - if (GetSpellInfo()->EquippedItemClass == -1) - { - target->ToPlayer()->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); - target->ToPlayer()->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); - target->ToPlayer()->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); - } - else - { - // done in Player::_ApplyWeaponDependentAuraMods - } + target->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float(GetAmount()), apply); + target->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float(GetAmount()), apply); + target->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float(GetAmount()), apply); } void AuraEffect::HandleModHitChance(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -4394,6 +4074,7 @@ void AuraEffect::HandleAuraModAttackPowerOfArmor(AuraApplication const* aurApp, if (target->GetTypeId() == TYPEID_PLAYER) target->ToPlayer()->UpdateAttackPowerAndDamage(false); } + /********************************/ /*** DAMAGE BONUS ***/ /********************************/ @@ -4404,79 +4085,22 @@ void AuraEffect::HandleModDamageDone(AuraApplication const* aurApp, uint8 mode, Unit* target = aurApp->GetTarget(); - // apply item specific bonuses for already equipped weapon - if (target->GetTypeId() == TYPEID_PLAYER) - { - for (int i = 0; i < MAX_ATTACK; ++i) - if (Item* pItem = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true)) - target->ToPlayer()->_ApplyWeaponDependentAuraDamageMod(pItem, WeaponAttackType(i), this, apply); - } - - // GetMiscValue() is bitmask of spell schools - // 1 (0-bit) - normal school damage (SPELL_SCHOOL_MASK_NORMAL) - // 126 - full bitmask all magic damages (SPELL_SCHOOL_MASK_MAGIC) including wands - // 127 - full bitmask any damages - // - // mods must be applied base at equipped weapon class and subclass comparison - // with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask - // GetMiscValue() comparison with item generated damage types - - if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0) - { - // apply generic physical damage bonuses including wand case - if (GetSpellInfo()->EquippedItemClass == -1 || target->GetTypeId() != TYPEID_PLAYER) - { - target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(GetAmount()), apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(GetAmount()), apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(GetAmount()), apply); - - if (target->GetTypeId() == TYPEID_PLAYER) - { - if (GetAmount() > 0) - target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, GetAmount(), apply); - else - target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, GetAmount(), apply); - } - } - else - { - // done in Player::_ApplyWeaponDependentAuraMods - } - } - - // Skip non magic case for speedup - if ((GetMiscValue() & SPELL_SCHOOL_MASK_MAGIC) == 0) - return; - - if (GetSpellInfo()->EquippedItemClass != -1 || GetSpellInfo()->EquippedItemInventoryTypeMask != 0) + if (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) { - // wand magic case (skip generic to all item spell bonuses) - // done in Player::_ApplyWeaponDependentAuraMods - - // Skip item specific requirements for not wand magic damage - return; + target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(GetAmount()), apply); } - // Magic damage modifiers implemented in Unit::SpellDamageBonus + // Magic damage modifiers implemented in Unit::SpellBaseDamageBonusDone // This information for client side use only if (target->GetTypeId() == TYPEID_PLAYER) { - if (GetAmount() > 0) - { - for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++) - { - if ((GetMiscValue() & (1<<i)) != 0) - target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, GetAmount(), apply); - } - } - else - { - for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++) - { - if ((GetMiscValue() & (1<<i)) != 0) - target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG+i, GetAmount(), apply); - } - } + uint16 baseField = GetAmount() >= 0 ? PLAYER_FIELD_MOD_DAMAGE_DONE_POS : PLAYER_FIELD_MOD_DAMAGE_DONE_NEG; + for (uint16 i = 0; i < MAX_SPELL_SCHOOL; ++i) + if (GetMiscValue() & (1 << i)) + target->ApplyModUInt32Value(baseField + i, GetAmount(), apply); + if (Guardian* pet = target->ToPlayer()->GetGuardianPet()) pet->UpdateAttackPowerAndDamage(); } @@ -4492,14 +4116,7 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 if (abs(spellGroupVal) >= abs(GetAmount())) return; - if (target->GetTypeId() == TYPEID_PLAYER) - { - for (int i = 0; i < MAX_ATTACK; ++i) - if (Item* item = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), false)) - target->ToPlayer()->_ApplyWeaponDependentAuraDamageMod(item, WeaponAttackType(i), this, apply); - } - - if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) && (GetSpellInfo()->EquippedItemClass == -1 || target->GetTypeId() != TYPEID_PLAYER)) + if (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) { if (spellGroupVal) { @@ -4507,22 +4124,25 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(spellGroupVal), !apply); target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(spellGroupVal), !apply); } + target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(GetAmount()), apply); target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply); target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(GetAmount()), apply); + } - if (Player* player = target->ToPlayer()) + if (target->GetTypeId() == TYPEID_PLAYER) + { + for (uint16 i = 0; i < MAX_SPELL_SCHOOL; ++i) { - if (spellGroupVal) - player->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float(spellGroupVal), !apply); + if (GetMiscValue() & (1 << i)) + { + if (spellGroupVal) + target->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i, float(spellGroupVal), !apply); - player->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float(GetAmount()), apply); + target->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i, float(GetAmount()), apply); + } } } - else - { - // done in Player::_ApplyWeaponDependentAuraMods for SPELL_SCHOOL_MASK_NORMAL && EquippedItemClass != -1 and also for wand case - } } void AuraEffect::HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -5446,13 +5066,11 @@ void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const { // Master of Subtlety case 31666: - if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) - target->RemoveAurasDueToSpell(31665); + target->RemoveAurasDueToSpell(31665); break; // Overkill case 58428: - if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) - target->RemoveAurasDueToSpell(58427); + target->RemoveAurasDueToSpell(58427); break; } break; @@ -5849,8 +5467,6 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const } } - uint32 absorb = 0; - uint32 resist = 0; CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); // AOE spells are not affected by the new periodic system. @@ -5945,13 +5561,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 +5579,12 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const // Set trigger flag uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; - uint32 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 +5593,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 +5613,6 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c caster->SpellHitResult(target, GetSpellInfo(), false) != SPELL_MISS_NONE) return; - uint32 absorb = 0; - uint32 resist = 0; CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); @@ -6009,6 +5627,9 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c else damage = std::max(int32(damage * GetDonePct()), 0); + if (Player* modOwner = caster->GetSpellModOwner()) + modOwner->ApplySpellMod<SPELLMOD_DOT>(GetSpellInfo()->Id, damage); + damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); // Calculate armor mitigation @@ -6020,12 +5641,14 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c } if (!m_spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE)) + { if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura) { damage = uint32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); if (caster->GetTypeId() != TYPEID_PLAYER) damage = uint32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); } + } bool crit = false; @@ -6037,29 +5660,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()) @@ -6478,6 +6105,12 @@ void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEv Unit* target = aurApp->GetTarget(); Unit* triggerTarget = eventInfo.GetProcTarget(); + if (triggerTarget->HasUnitState(UNIT_STATE_ISOLATED) || triggerTarget->IsImmunedToDamage(GetSpellInfo())) + { + SendTickImmune(triggerTarget, target); + return; + } + SpellNonMeleeDamage damageInfo(target, triggerTarget, GetId(), GetSpellInfo()->SchoolMask); uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE); damage = triggerTarget->SpellDamageBonusTaken(target, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 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 970bb93b271..45ea44f1dfb 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 @@ -987,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; } @@ -1291,20 +1293,27 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b case SPELLFAMILY_PRIEST: if (!caster) break; + // Devouring Plague - if (GetSpellInfo()->SpellFamilyFlags[0] & 0x02000000 && GetEffect(0)) + if (GetSpellInfo()->SpellFamilyFlags[0] & 0x02000000) { + AuraEffect const* devouringPlague = GetEffect(EFFECT_0); + if (!devouringPlague) + break; + // Improved Devouring Plague if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 3790, 1)) { - uint32 damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), GetEffect(0)->GetAmount(), DOT); - damage *= caster->SpellDamagePctDone(target, GetSpellInfo(), SPELL_DIRECT_DAMAGE); + int32 damage = (devouringPlague->GetAmount() + devouringPlague->GetBonusAmount()) * devouringPlague->GetDonePct(); + if (Player* modOwner = caster->GetSpellModOwner()) + modOwner->ApplySpellMod<SPELLMOD_DOT>(GetSpellInfo()->Id, damage); + damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT); - int32 basepoints0 = aurEff->GetAmount() * GetEffect(0)->GetTotalTicks() * int32(damage) / 100; - int32 heal = int32(CalculatePct(basepoints0, 15)); - caster->CastCustomSpell(target, 63675, &basepoints0, NULL, NULL, true, NULL, GetEffect(0)); - caster->CastCustomSpell(caster, 75999, &heal, NULL, NULL, true, NULL, GetEffect(0)); + int32 basepoints0 = CalculatePct(devouringPlague->GetTotalTicks() * static_cast<int32>(damage), aurEff->GetAmount()); + int32 heal = CalculatePct(basepoints0, 15); + caster->CastCustomSpell(63675, SPELLVALUE_BASE_POINT0, basepoints0, target, true, nullptr, devouringPlague); + caster->CastCustomSpell(75999, SPELLVALUE_BASE_POINT0, heal, (Unit*)nullptr, true, nullptr, devouringPlague); } } // Power Word: Shield @@ -1591,6 +1600,9 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b target->CastSpell(target, 31666, true); else { + // Remove counter aura + target->RemoveAurasDueToSpell(31666); + int32 basepoints0 = aurEff->GetAmount(); target->CastCustomSpell(target, 31665, &basepoints0, NULL, NULL, true); } @@ -1601,7 +1613,12 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b if (!apply) target->CastSpell(target, 58428, true); else + { + // Remove counter aura + target->RemoveAurasDueToSpell(58428); + target->CastSpell(target, 58427, true); + } } break; } @@ -1865,13 +1882,34 @@ void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInf AddProcCooldown(now + procEntry->Cooldown); } -uint8 Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const +uint8 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const { SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId()); // only auras with spell proc entry can trigger proc if (!procEntry) return 0; + // check spell triggering us + if (Spell const* spell = eventInfo.GetProcSpell()) + { + // Do not allow auras to proc from effect triggered from itself + if (spell->IsTriggeredByAura(m_spellInfo)) + return 0; + + // check if aura can proc when spell is triggered (exception for hunter auto shot & wands) + if (spell->IsTriggered() && !(procEntry->AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC) && !(eventInfo.GetTypeMask() & AUTO_ATTACK_PROC_FLAG_MASK)) + if (!GetSpellInfo()->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED)) + return 0; + } + + // check don't break stealth attr present + if (m_spellInfo->HasAura(SPELL_AURA_MOD_STEALTH)) + { + if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) + if (spellInfo->HasAttribute(SPELL_ATTR0_CU_DONT_BREAK_STEALTH)) + return 0; + } + // check if we have charges to proc with if (IsUsingCharges()) { @@ -1889,16 +1927,9 @@ uint8 Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& event return 0; // do checks against db data - if (!sSpellMgr->CanSpellTriggerProcOnEvent(*procEntry, eventInfo)) + if (!SpellMgr::CanSpellTriggerProcOnEvent(*procEntry, eventInfo)) 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)) - return 0; - // do checks using conditions table if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_SPELL_PROC, GetId(), eventInfo.GetActor(), eventInfo.GetActionTarget())) return 0; @@ -1909,11 +1940,11 @@ uint8 Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& event return 0; // At least one effect has to pass checks to proc aura - uint8 procEffectMask = 0; + uint8 procEffectMask = aurApp->GetEffectMask(); for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (aurApp->HasEffect(i)) - if (GetEffect(i)->CheckEffectProc(aurApp, eventInfo)) - procEffectMask |= (1 << i); + if (procEffectMask & (1 << i)) + if ((procEntry->AttributesMask & (PROC_ATTR_DISABLE_EFF_0 << i)) || !GetEffect(i)->CheckEffectProc(aurApp, eventInfo)) + procEffectMask &= ~(1 << i); if (!procEffectMask) return 0; @@ -2024,30 +2055,21 @@ void Aura::_DeleteRemovedApplications() void Aura::LoadScripts() { - sScriptMgr->CreateAuraScripts(m_spellInfo->Id, m_loadedScripts); - for (std::list<AuraScript*>::iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end();) + sScriptMgr->CreateAuraScripts(m_spellInfo->Id, m_loadedScripts, this); + for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr) { - if (!(*itr)->_Load(this)) - { - std::list<AuraScript*>::iterator bitr = itr; - ++itr; - delete (*bitr); - m_loadedScripts.erase(bitr); - continue; - } TC_LOG_DEBUG("spells", "Aura::LoadScripts: Script `%s` for aura `%u` is loaded now", (*itr)->_GetScriptName()->c_str(), m_spellInfo->Id); (*itr)->Register(); - ++itr; } } bool Aura::CallScriptCheckAreaTargetHandlers(Unit* target) { bool result = true; - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_AREA_TARGET); - std::list<AuraScript::CheckAreaTargetHandler>::iterator hookItrEnd = (*scritr)->DoCheckAreaTarget.end(), hookItr = (*scritr)->DoCheckAreaTarget.begin(); + auto hookItrEnd = (*scritr)->DoCheckAreaTarget.end(), hookItr = (*scritr)->DoCheckAreaTarget.begin(); for (; hookItr != hookItrEnd; ++hookItr) result &= hookItr->Call(*scritr, target); @@ -2058,10 +2080,10 @@ bool Aura::CallScriptCheckAreaTargetHandlers(Unit* target) void Aura::CallScriptDispel(DispelInfo* dispelInfo) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_DISPEL); - std::list<AuraScript::AuraDispelHandler>::iterator hookItrEnd = (*scritr)->OnDispel.end(), hookItr = (*scritr)->OnDispel.begin(); + auto hookItrEnd = (*scritr)->OnDispel.end(), hookItr = (*scritr)->OnDispel.begin(); for (; hookItr != hookItrEnd; ++hookItr) hookItr->Call(*scritr, dispelInfo); @@ -2071,10 +2093,10 @@ void Aura::CallScriptDispel(DispelInfo* dispelInfo) void Aura::CallScriptAfterDispel(DispelInfo* dispelInfo) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_AFTER_DISPEL); - std::list<AuraScript::AuraDispelHandler>::iterator hookItrEnd = (*scritr)->AfterDispel.end(), hookItr = (*scritr)->AfterDispel.begin(); + auto hookItrEnd = (*scritr)->AfterDispel.end(), hookItr = (*scritr)->AfterDispel.begin(); for (; hookItr != hookItrEnd; ++hookItr) hookItr->Call(*scritr, dispelInfo); @@ -2085,10 +2107,10 @@ void Aura::CallScriptAfterDispel(DispelInfo* dispelInfo) bool Aura::CallScriptEffectApplyHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, AuraEffectHandleModes mode) { bool preventDefault = false; - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_APPLY, aurApp); - std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectApply.end(), effItr = (*scritr)->OnEffectApply.begin(); + auto effEndItr = (*scritr)->OnEffectApply.end(), effItr = (*scritr)->OnEffectApply.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) effItr->Call(*scritr, aurEff, mode); @@ -2105,10 +2127,10 @@ bool Aura::CallScriptEffectApplyHandlers(AuraEffect const* aurEff, AuraApplicati bool Aura::CallScriptEffectRemoveHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, AuraEffectHandleModes mode) { bool preventDefault = false; - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_REMOVE, aurApp); - std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectRemove.end(), effItr = (*scritr)->OnEffectRemove.begin(); + auto effEndItr = (*scritr)->OnEffectRemove.end(), effItr = (*scritr)->OnEffectRemove.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) effItr->Call(*scritr, aurEff, mode); @@ -2123,10 +2145,10 @@ bool Aura::CallScriptEffectRemoveHandlers(AuraEffect const* aurEff, AuraApplicat void Aura::CallScriptAfterEffectApplyHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, AuraEffectHandleModes mode) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_APPLY, aurApp); - std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->AfterEffectApply.end(), effItr = (*scritr)->AfterEffectApply.begin(); + auto effEndItr = (*scritr)->AfterEffectApply.end(), effItr = (*scritr)->AfterEffectApply.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) effItr->Call(*scritr, aurEff, mode); @@ -2137,10 +2159,10 @@ void Aura::CallScriptAfterEffectApplyHandlers(AuraEffect const* aurEff, AuraAppl void Aura::CallScriptAfterEffectRemoveHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, AuraEffectHandleModes mode) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_REMOVE, aurApp); - std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->AfterEffectRemove.end(), effItr = (*scritr)->AfterEffectRemove.begin(); + auto effEndItr = (*scritr)->AfterEffectRemove.end(), effItr = (*scritr)->AfterEffectRemove.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) effItr->Call(*scritr, aurEff, mode); @@ -2152,10 +2174,10 @@ void Aura::CallScriptAfterEffectRemoveHandlers(AuraEffect const* aurEff, AuraApp bool Aura::CallScriptEffectPeriodicHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp) { bool preventDefault = false; - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_PERIODIC, aurApp); - std::list<AuraScript::EffectPeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectPeriodic.end(), effItr = (*scritr)->OnEffectPeriodic.begin(); + auto effEndItr = (*scritr)->OnEffectPeriodic.end(), effItr = (*scritr)->OnEffectPeriodic.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) effItr->Call(*scritr, aurEff); @@ -2171,10 +2193,10 @@ bool Aura::CallScriptEffectPeriodicHandlers(AuraEffect const* aurEff, AuraApplic void Aura::CallScriptEffectUpdatePeriodicHandlers(AuraEffect* aurEff) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_UPDATE_PERIODIC); - std::list<AuraScript::EffectUpdatePeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectUpdatePeriodic.end(), effItr = (*scritr)->OnEffectUpdatePeriodic.begin(); + auto effEndItr = (*scritr)->OnEffectUpdatePeriodic.end(), effItr = (*scritr)->OnEffectUpdatePeriodic.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) effItr->Call(*scritr, aurEff); @@ -2185,10 +2207,10 @@ void Aura::CallScriptEffectUpdatePeriodicHandlers(AuraEffect* aurEff) void Aura::CallScriptEffectCalcAmountHandlers(AuraEffect const* aurEff, int32 & amount, bool & canBeRecalculated) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_AMOUNT); - std::list<AuraScript::EffectCalcAmountHandler>::iterator effEndItr = (*scritr)->DoEffectCalcAmount.end(), effItr = (*scritr)->DoEffectCalcAmount.begin(); + auto effEndItr = (*scritr)->DoEffectCalcAmount.end(), effItr = (*scritr)->DoEffectCalcAmount.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) effItr->Call(*scritr, aurEff, amount, canBeRecalculated); @@ -2199,10 +2221,10 @@ void Aura::CallScriptEffectCalcAmountHandlers(AuraEffect const* aurEff, int32 & void Aura::CallScriptEffectCalcPeriodicHandlers(AuraEffect const* aurEff, bool & isPeriodic, int32 & amplitude) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_PERIODIC); - std::list<AuraScript::EffectCalcPeriodicHandler>::iterator effEndItr = (*scritr)->DoEffectCalcPeriodic.end(), effItr = (*scritr)->DoEffectCalcPeriodic.begin(); + auto effEndItr = (*scritr)->DoEffectCalcPeriodic.end(), effItr = (*scritr)->DoEffectCalcPeriodic.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) effItr->Call(*scritr, aurEff, isPeriodic, amplitude); @@ -2213,10 +2235,10 @@ void Aura::CallScriptEffectCalcPeriodicHandlers(AuraEffect const* aurEff, bool & void Aura::CallScriptEffectCalcSpellModHandlers(AuraEffect const* aurEff, SpellModifier* & spellMod) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_SPELLMOD); - std::list<AuraScript::EffectCalcSpellModHandler>::iterator effEndItr = (*scritr)->DoEffectCalcSpellMod.end(), effItr = (*scritr)->DoEffectCalcSpellMod.begin(); + auto effEndItr = (*scritr)->DoEffectCalcSpellMod.end(), effItr = (*scritr)->DoEffectCalcSpellMod.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) effItr->Call(*scritr, aurEff, spellMod); @@ -2227,10 +2249,10 @@ void Aura::CallScriptEffectCalcSpellModHandlers(AuraEffect const* aurEff, SpellM void Aura::CallScriptEffectAbsorbHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount, bool& defaultPrevented) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_ABSORB, aurApp); - std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->OnEffectAbsorb.end(), effItr = (*scritr)->OnEffectAbsorb.begin(); + auto effEndItr = (*scritr)->OnEffectAbsorb.end(), effItr = (*scritr)->OnEffectAbsorb.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) @@ -2245,10 +2267,10 @@ void Aura::CallScriptEffectAbsorbHandlers(AuraEffect* aurEff, AuraApplication co void Aura::CallScriptEffectAfterAbsorbHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_ABSORB, aurApp); - std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->AfterEffectAbsorb.end(), effItr = (*scritr)->AfterEffectAbsorb.begin(); + auto effEndItr = (*scritr)->AfterEffectAbsorb.end(), effItr = (*scritr)->AfterEffectAbsorb.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount); @@ -2259,10 +2281,10 @@ void Aura::CallScriptEffectAfterAbsorbHandlers(AuraEffect* aurEff, AuraApplicati void Aura::CallScriptEffectManaShieldHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount, bool & /*defaultPrevented*/) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_MANASHIELD, aurApp); - std::list<AuraScript::EffectManaShieldHandler>::iterator effEndItr = (*scritr)->OnEffectManaShield.end(), effItr = (*scritr)->OnEffectManaShield.begin(); + auto effEndItr = (*scritr)->OnEffectManaShield.end(), effItr = (*scritr)->OnEffectManaShield.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount); @@ -2273,10 +2295,10 @@ void Aura::CallScriptEffectManaShieldHandlers(AuraEffect* aurEff, AuraApplicatio void Aura::CallScriptEffectAfterManaShieldHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD, aurApp); - std::list<AuraScript::EffectManaShieldHandler>::iterator effEndItr = (*scritr)->AfterEffectManaShield.end(), effItr = (*scritr)->AfterEffectManaShield.begin(); + auto effEndItr = (*scritr)->AfterEffectManaShield.end(), effItr = (*scritr)->AfterEffectManaShield.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount); @@ -2287,10 +2309,10 @@ void Aura::CallScriptEffectAfterManaShieldHandlers(AuraEffect* aurEff, AuraAppli void Aura::CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & splitAmount) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_SPLIT, aurApp); - std::list<AuraScript::EffectSplitHandler>::iterator effEndItr = (*scritr)->OnEffectSplit.end(), effItr = (*scritr)->OnEffectSplit.begin(); + auto effEndItr = (*scritr)->OnEffectSplit.end(), effItr = (*scritr)->OnEffectSplit.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) effItr->Call(*scritr, aurEff, dmgInfo, splitAmount); @@ -2302,10 +2324,10 @@ void Aura::CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication con bool Aura::CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo) { bool result = true; - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_PROC, aurApp); - std::list<AuraScript::CheckProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckProc.end(), hookItr = (*scritr)->DoCheckProc.begin(); + auto hookItrEnd = (*scritr)->DoCheckProc.end(), hookItr = (*scritr)->DoCheckProc.begin(); for (; hookItr != hookItrEnd; ++hookItr) result &= hookItr->Call(*scritr, eventInfo); @@ -2318,10 +2340,10 @@ bool Aura::CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventI bool Aura::CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo) { bool prepare = true; - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_PREPARE_PROC, aurApp); - std::list<AuraScript::AuraProcHandler>::iterator effEndItr = (*scritr)->DoPrepareProc.end(), effItr = (*scritr)->DoPrepareProc.begin(); + auto effEndItr = (*scritr)->DoPrepareProc.end(), effItr = (*scritr)->DoPrepareProc.begin(); for (; effItr != effEndItr; ++effItr) effItr->Call(*scritr, eventInfo); @@ -2337,10 +2359,10 @@ bool Aura::CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEven bool Aura::CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo) { bool handled = false; - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_PROC, aurApp); - std::list<AuraScript::AuraProcHandler>::iterator hookItrEnd = (*scritr)->OnProc.end(), hookItr = (*scritr)->OnProc.begin(); + auto hookItrEnd = (*scritr)->OnProc.end(), hookItr = (*scritr)->OnProc.begin(); for (; hookItr != hookItrEnd; ++hookItr) hookItr->Call(*scritr, eventInfo); @@ -2353,10 +2375,10 @@ bool Aura::CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& void Aura::CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_AFTER_PROC, aurApp); - std::list<AuraScript::AuraProcHandler>::iterator hookItrEnd = (*scritr)->AfterProc.end(), hookItr = (*scritr)->AfterProc.begin(); + auto hookItrEnd = (*scritr)->AfterProc.end(), hookItr = (*scritr)->AfterProc.begin(); for (; hookItr != hookItrEnd; ++hookItr) hookItr->Call(*scritr, eventInfo); @@ -2367,10 +2389,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); @@ -2384,10 +2406,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); @@ -2402,10 +2424,10 @@ bool Aura::CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplicatio void Aura::CallScriptAfterEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo) { - for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_PROC, aurApp); - std::list<AuraScript::EffectProcHandler>::iterator effEndItr = (*scritr)->AfterEffectProc.end(), effItr = (*scritr)->AfterEffectProc.begin(); + auto effEndItr = (*scritr)->AfterEffectProc.end(), effItr = (*scritr)->AfterEffectProc.begin(); for (; effItr != effEndItr; ++effItr) if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) effItr->Call(*scritr, aurEff, eventInfo); diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index a6dd29f11d0..1533746893a 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -204,7 +204,7 @@ class TC_GAME_API Aura bool IsUsingCharges() const { return m_isUsingCharges; } void SetUsingCharges(bool val) { m_isUsingCharges = val; } void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now); - uint8 IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const; + uint8 GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const; float CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const; void TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo); @@ -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; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index a83a5a122ad..c082c0a7584 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -626,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) @@ -647,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) @@ -1119,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)) { @@ -1206,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); @@ -1992,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) { @@ -2050,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 @@ -2308,7 +2325,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) m_spellAura = nullptr; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied // Spells with this flag cannot trigger if effect is cast on self - bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2); + bool const canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2); Unit* spellHitTarget = nullptr; if (missInfo == SPELL_MISS_NONE) // In case spell hit target, do all effect on that target @@ -2352,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) { @@ -2413,15 +2442,29 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // Fill base damage struct (unitTarget - is real spell target) SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask); - // Add bonuses and fill damageInfo struct - caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo, m_attackType, target->crit); - caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); + // Check damage immunity + if (unitTarget->IsImmunedToDamage(m_spellInfo)) + { + hitMask = PROC_HIT_IMMUNE; + m_damage = 0; + + // no packet found in sniffs + } + else + { + // Add bonuses and fill damageInfo struct + caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo, m_attackType, target->crit); + caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); - // Send log damage message to client - caster->SendSpellNonMeleeDamageLog(&damageInfo); + // Send log damage message to client + caster->SendSpellNonMeleeDamageLog(&damageInfo); - hitMask |= createProcHitMask(&damageInfo, missInfo); - procVictim |= PROC_FLAG_TAKEN_DAMAGE; + hitMask |= createProcHitMask(&damageInfo, missInfo); + procVictim |= PROC_FLAG_TAKEN_DAMAGE; + + m_damage = damageInfo.damage; + caster->DealSpellDamage(&damageInfo, true); + } // Do triggers for unit if (canEffectTrigger) @@ -2433,10 +2476,6 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) caster->ToPlayer()->CastItemCombatSpell(spellDamageInfo); } - - m_damage = damageInfo.damage; - - caster->DealSpellDamage(&damageInfo, true); } // Passive spell hits/misses or active spells only misses (only triggers) else @@ -2502,7 +2541,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA return SPELL_MISS_EVADE; // For delayed spells immunity may be applied between missile launch and hit - check immunity for that case - if (m_spellInfo->Speed && (unit->IsImmunedToDamage(m_spellInfo) || unit->IsImmunedToSpell(m_spellInfo))) + if (m_spellInfo->Speed && unit->IsImmunedToSpell(m_spellInfo)) return SPELL_MISS_IMMUNE; // disable effects to which unit is immune @@ -2551,12 +2590,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA return SPELL_MISS_EVADE; if (m_caster->_IsValidAttackTarget(unit, m_spellInfo)) - { unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_HITBYSPELL); - - if (!m_spellInfo->HasAttribute(SPELL_ATTR0_CU_DONT_BREAK_STEALTH)) - unit->RemoveAurasByType(SPELL_AURA_MOD_STEALTH); - } else if (m_caster->IsFriendlyTo(unit)) { // for delayed spells ignore negative spells (after duel end) for friendly targets @@ -2720,8 +2754,8 @@ void Spell::DoTriggersOnSpellHit(Unit* unit, uint8 effMask) // info confirmed with retail sniffs of permafrost and shadow weaving if (!m_hitTriggerSpells.empty()) { - int _duration = 0; - for (HitTriggerSpellList::const_iterator i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i) + int32 _duration = 0; + for (auto i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i) { if (CanExecuteTriggersOnHit(effMask, i->triggeredByAura) && roll_chance_i(i->chance)) { @@ -2933,7 +2967,8 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered if ((_triggeredCastFlags & TRIGGERED_IGNORE_COMBO_POINTS) || m_CastItem || !m_caster->m_playerMovingMe) m_needComboPoints = false; - SpellCastResult result = CheckCast(true); + uint32 param1 = 0, param2 = 0; + SpellCastResult result = CheckCast(true, ¶m1, ¶m2); 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 @@ -2954,7 +2989,10 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered m_caster->ToPlayer()->SetSpellModTakingSpell(this, false); } - SendCastResult(result); + if (param1 || param2) + SendCastResult(result, ¶m1, ¶m2); + else + SendCastResult(result); finish(false); return; @@ -2979,7 +3017,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered m_casttime = m_spellInfo->CalcCastTime(this); if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED)) // _UNIT actually means creature. for some reason. - if (!(IsNextMeleeSwingSpell() || IsAutoRepeat() || _triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING)) + if (!(m_spellInfo->IsNextMeleeSwingSpell() || IsAutoRepeat() || (_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING))) { if (m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget()) m_caster->ToCreature()->FocusTarget(this, m_targets.GetObjectTarget()); @@ -2992,8 +3030,8 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered // (even if they are interrupted on moving, spells with almost immediate effect get to have their effect processed before movement interrupter kicks in) if ((m_spellInfo->IsChanneled() || m_casttime) && m_caster->GetTypeId() == TYPEID_PLAYER && !(m_caster->IsCharmed() && m_caster->GetCharmerGUID().IsCreature()) && m_caster->isMoving() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT)) { - // 1. Is a channel spell, 2. Has no casttime, 3. And has flag to allow movement during channel - if (!(m_spellInfo->IsChanneled() && !m_casttime && m_spellInfo->HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING))) + // 1. Has casttime, 2. Or doesn't have flag to allow movement during channel + if (m_casttime || !m_spellInfo->IsMoveAllowedChannel()) { SendCastResult(SPELL_FAILED_MOVING); finish(false); @@ -3141,10 +3179,11 @@ void Spell::cast(bool skipCheck) // skip check if done already (for instant cast spells for example) if (!skipCheck) { - SpellCastResult castResult = CheckCast(false); + uint32 param1 = 0, param2 = 0; + SpellCastResult castResult = CheckCast(false, ¶m1, ¶m2); if (castResult != SPELL_CAST_OK) { - SendCastResult(castResult); + SendCastResult(castResult, ¶m1, ¶m2); SendInterrupted(0); //restore spell mods if (m_caster->GetTypeId() == TYPEID_PLAYER) @@ -3548,7 +3587,7 @@ void Spell::update(uint32 difftime) (m_spellInfo->Effects[0].Effect != SPELL_EFFECT_STUCK || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR)))) { // don't cancel for melee, autorepeat, triggered and instant spells - if (!IsNextMeleeSwingSpell() && !IsAutoRepeat() && !IsTriggered() && !(IsChannelActive() && m_spellInfo->HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING))) + if (!m_spellInfo->IsNextMeleeSwingSpell() && !IsAutoRepeat() && !IsTriggered() && !(IsChannelActive() && m_spellInfo->IsMoveAllowedChannel())) { // if charmed by creature, trust the AI not to cheat and allow the cast to proceed // @todo this is a hack, "creature" movesplines don't differentiate turning/moving right now @@ -3570,7 +3609,7 @@ void Spell::update(uint32 difftime) m_timer -= difftime; } - if (m_timer == 0 && !IsNextMeleeSwingSpell() && !IsAutoRepeat()) + if (m_timer == 0 && !m_spellInfo->IsNextMeleeSwingSpell() && !IsAutoRepeat()) // don't CheckCast for instant spells - done in spell::prepare, skip duplicate checks, needed for range checks for example cast(!m_casttime); break; @@ -3690,7 +3729,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); @@ -3698,115 +3737,185 @@ void Spell::WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo con switch (result) { case SPELL_FAILED_REQUIRES_SPELL_FOCUS: - data << uint32(spellInfo->RequiresSpellFocus); // SpellFocusObject.dbc id + if (param1) + data << uint32(*param1); + else + data << uint32(spellInfo->RequiresSpellFocus); // SpellFocusObject.dbc id break; case SPELL_FAILED_REQUIRES_AREA: // AreaTable.dbc id - // hardcode areas limitation case - switch (spellInfo->Id) + if (param1) + data << uint32(*param1); + else { - case 41617: // Cenarion Mana Salve - case 41619: // Cenarion Healing Salve - data << uint32(3905); - break; - case 41618: // Bottled Nethergon Energy - case 41620: // Bottled Nethergon Vapor - data << uint32(3842); - break; - case 45373: // Bloodberry Elixir - data << uint32(4075); - break; - default: // default case (don't must be) - data << uint32(0); - break; + // hardcode areas limitation case + switch (spellInfo->Id) + { + case 41617: // Cenarion Mana Salve + case 41619: // Cenarion Healing Salve + data << uint32(3905); + break; + case 41618: // Bottled Nethergon Energy + case 41620: // Bottled Nethergon Vapor + data << uint32(3842); + break; + case 45373: // Bloodberry Elixir + data << uint32(4075); + break; + default: // default case (don't must be) + data << uint32(0); + break; + } } break; case SPELL_FAILED_TOTEMS: - if (spellInfo->Totem[0]) - data << uint32(spellInfo->Totem[0]); - if (spellInfo->Totem[1]) - data << uint32(spellInfo->Totem[1]); + if (param1) + { + data << uint32(*param1); + if (param2) + data << uint32(*param2); + } + else + { + if (spellInfo->Totem[0]) + data << uint32(spellInfo->Totem[0]); + if (spellInfo->Totem[1]) + data << uint32(spellInfo->Totem[1]); + } break; case SPELL_FAILED_TOTEM_CATEGORY: - if (spellInfo->TotemCategory[0]) - data << uint32(spellInfo->TotemCategory[0]); - if (spellInfo->TotemCategory[1]) - data << uint32(spellInfo->TotemCategory[1]); + if (param1) + { + data << uint32(*param1); + if (param2) + data << uint32(*param2); + } + else + { + if (spellInfo->TotemCategory[0]) + data << uint32(spellInfo->TotemCategory[0]); + if (spellInfo->TotemCategory[1]) + data << uint32(spellInfo->TotemCategory[1]); + } break; case SPELL_FAILED_EQUIPPED_ITEM_CLASS: case SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND: case SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND: - data << uint32(spellInfo->EquippedItemClass); - data << uint32(spellInfo->EquippedItemSubClassMask); + if (param1 && param2) + { + data << uint32(*param1); + data << uint32(*param2); + } + else + { + data << uint32(spellInfo->EquippedItemClass); + data << uint32(spellInfo->EquippedItemSubClassMask); + } break; case SPELL_FAILED_TOO_MANY_OF_ITEM: { - uint32 item = 0; - for (int8 eff = 0; eff < MAX_SPELL_EFFECTS; eff++) - if (spellInfo->Effects[eff].ItemType) - item = spellInfo->Effects[eff].ItemType; - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item); - if (proto && proto->ItemLimitCategory) - data << uint32(proto->ItemLimitCategory); - break; + if (param1) + data << uint32(*param1); + else + { + uint32 item = 0; + for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS && !item; ++effIndex) + if (uint32 itemType = spellInfo->Effects[effIndex].ItemType) + item = itemType; + + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item); + if (proto && proto->ItemLimitCategory) + data << uint32(proto->ItemLimitCategory); + } + break; } case SPELL_FAILED_CUSTOM_ERROR: data << uint32(customError); break; case SPELL_FAILED_REAGENTS: { - uint32 missingItem = 0; - for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++) + if (param1) + data << uint32(*param1); + else { - if (spellInfo->Reagent[i] <= 0) - continue; + uint32 missingItem = 0; + for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++) + { + if (spellInfo->Reagent[i] <= 0) + continue; - uint32 itemid = spellInfo->Reagent[i]; - uint32 itemcount = spellInfo->ReagentCount[i]; + uint32 itemid = spellInfo->Reagent[i]; + uint32 itemcount = spellInfo->ReagentCount[i]; - if (!caster->HasItemCount(itemid, itemcount)) - { - missingItem = itemid; - break; + if (!caster->HasItemCount(itemid, itemcount)) + { + missingItem = itemid; + break; + } } - } - data << uint32(missingItem); // first missing item + data << uint32(missingItem); // first missing item + } break; } case SPELL_FAILED_PREVENTED_BY_MECHANIC: - data << uint32(spellInfo->Mechanic); + if (param1) + data << uint32(*param1); + else + data << uint32(spellInfo->Mechanic); break; case SPELL_FAILED_NEED_EXOTIC_AMMO: - data << uint32(spellInfo->EquippedItemSubClassMask); + if (param1) + data << uint32(*param1); + else + data << uint32(spellInfo->EquippedItemSubClassMask); break; case SPELL_FAILED_NEED_MORE_ITEMS: - data << uint32(0); // Item entry - data << uint32(0); // Count + if (param1 && param2) + { + data << uint32(*param1); + data << uint32(*param2); + } + else + { + data << uint32(0); // Item entry + data << uint32(0); // Count + } break; case SPELL_FAILED_MIN_SKILL: - data << uint32(0); // SkillLine.dbc Id - data << uint32(0); // Amount + if (param1 && param2) + { + data << uint32(*param1); + data << uint32(*param2); + } + else + { + data << uint32(0); // SkillLine.dbc Id + data << uint32(0); // Amount + } break; case SPELL_FAILED_FISHING_TOO_LOW: - data << uint32(0); // Skill level + if (param1) + data << uint32(*param1); + else + data << uint32(0); // Skill level break; default: break; } } -void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/) +void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) { if (result == SPELL_CAST_OK) return; WorldPacket data(SMSG_CAST_FAILED, 1 + 4 + 1); - WriteCastResultInfo(data, caster, spellInfo, castCount, result, customError); + WriteCastResultInfo(data, caster, spellInfo, castCount, result, customError, param1, param2); - caster->GetSession()->SendPacket(&data); + caster->SendDirectMessage(&data); } -void Spell::SendCastResult(SpellCastResult result) +void Spell::SendCastResult(SpellCastResult result, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) const { if (result == SPELL_CAST_OK) return; @@ -3814,13 +3923,13 @@ void Spell::SendCastResult(SpellCastResult result) if (m_caster->GetTypeId() != TYPEID_PLAYER) return; - if (m_caster->ToPlayer()->GetSession()->PlayerLoading()) // don't send cast results at loading time + if (m_caster->ToPlayer()->IsLoading()) // don't send cast results at loading time return; if (_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) result = SPELL_FAILED_DONT_REPORT; - SendCastResult(m_caster->ToPlayer(), m_spellInfo, m_cast_count, result, m_customError); + SendCastResult(m_caster->ToPlayer(), m_spellInfo, m_cast_count, result, m_customError, param1, param2); } void Spell::SendPetCastResult(SpellCastResult result) @@ -4469,7 +4578,7 @@ void Spell::TakeAmmo() } } -SpellCastResult Spell::CheckRuneCost(uint32 runeCostID) +SpellCastResult Spell::CheckRuneCost(uint32 runeCostID) const { if (m_spellInfo->PowerType != POWER_RUNE || !runeCostID) return SPELL_CAST_OK; @@ -4494,7 +4603,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 @@ -4730,7 +4839,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))) @@ -4793,13 +4902,15 @@ SpellCastResult Spell::CheckCast(bool strict) bool checkForm = true; // Ignore form req aura Unit::AuraEffectList const& ignore = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT); - for (Unit::AuraEffectList::const_iterator i = ignore.begin(); i != ignore.end(); ++i) + for (AuraEffect const* aurEff : ignore) { - if (!(*i)->IsAffectedOnSpell(m_spellInfo)) + if (!aurEff->IsAffectedOnSpell(m_spellInfo)) continue; + checkForm = false; break; } + if (checkForm) { // Cannot be used in this stance/form @@ -4895,14 +5006,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; @@ -5003,7 +5118,7 @@ SpellCastResult Spell::CheckCast(bool strict) // always (except passive spells) check items (only player related checks) if (!m_spellInfo->IsPassive()) { - castResult = CheckItems(); + castResult = CheckItems(param1, param2); if (castResult != SPELL_CAST_OK) return castResult; } @@ -5023,7 +5138,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURAS)) { - castResult = CheckCasterAuras(); + castResult = CheckCasterAuras(param1); if (castResult != SPELL_CAST_OK) return castResult; } @@ -5037,6 +5152,7 @@ SpellCastResult Spell::CheckCast(bool strict) bool hasNonDispelEffect = false; uint32 dispelMask = 0; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_DISPEL) { if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->HasAttribute(SPELL_ATTR1_MELEE_COMBAT_START)) @@ -5052,6 +5168,7 @@ SpellCastResult Spell::CheckCast(bool strict) hasNonDispelEffect = true; break; } + } if (!hasNonDispelEffect && !hasDispellableAura && dispelMask && !IsTriggered()) { @@ -5166,7 +5283,7 @@ SpellCastResult Spell::CheckCast(bool strict) m_caster->RemoveMovementImpairingAuras(); } - if (m_caster->HasUnitState(UNIT_STATE_ROOT)) + if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURAS) && m_caster->HasUnitState(UNIT_STATE_ROOT)) return SPELL_FAILED_ROOTED; if (GetSpellInfo()->NeedsExplicitUnitTarget()) @@ -5635,139 +5752,114 @@ SpellCastResult Spell::CheckPetCast(Unit* target) return CheckCast(true); } -SpellCastResult Spell::CheckCasterAuras() const +SpellCastResult Spell::CheckCasterAuras(uint32* param1) const { // spells totally immuned to caster auras (wsg flag drop, give marks etc) if (m_spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CASTER_AURAS)) return SPELL_CAST_OK; - uint8 school_immune = 0; - uint32 mechanic_immune = 0; - uint32 dispel_immune = 0; - - // Check if the spell grants school or mechanic immunity. - // We use bitmasks so the loop is done only once and not on every aura check below. - if (m_spellInfo->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)) + bool usableWhileStunned = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED); + bool usableWhileFeared = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED); + bool usableWhileConfused = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED); + if (m_spellInfo->HasAttribute(SPELL_ATTR7_USABLE_IN_STUN_FEAR_CONFUSION)) { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_SCHOOL_IMMUNITY) - school_immune |= uint32(m_spellInfo->Effects[i].MiscValue); - else if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MECHANIC_IMMUNITY) - mechanic_immune |= 1 << uint32(m_spellInfo->Effects[i].MiscValue); - else if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_DISPEL_IMMUNITY) - dispel_immune |= SpellInfo::GetDispelMask(DispelType(m_spellInfo->Effects[i].MiscValue)); - } - // immune movement impairment and loss of control - if (m_spellInfo->Id == 42292 || m_spellInfo->Id == 59752 || m_spellInfo->Id == 19574 || m_spellInfo->Id == 53490) - mechanic_immune = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK; + usableWhileStunned = true; + usableWhileFeared = true; + usableWhileConfused = true; } - bool usableInStun = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED); - // Glyph of Pain Suppression // there is no other way to handle it if (m_spellInfo->Id == 33206 && !m_caster->HasAura(63248)) - usableInStun = false; + usableWhileStunned = false; // Check whether the cast should be prevented by any state you might have. - SpellCastResult prevented_reason = SPELL_CAST_OK; - // Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out - uint32 unitflag = m_caster->GetUInt32Value(UNIT_FIELD_FLAGS); // Get unit state - if (unitflag & UNIT_FLAG_STUNNED) - { - // spell is usable while stunned, check if caster has 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()) + { + if (Unit* charmer = m_caster->GetCharmer()) + if (charmer->GetUnitBeingMoved() != m_caster && CheckCasterNotImmunedCharmAuras(param1)) + result = SPELL_FAILED_CHARMED; + } + else if (unitflag & UNIT_FLAG_STUNNED && !usableWhileStunned && CheckCasterNotImmunedStunAuras(param1)) + result = SPELL_FAILED_STUNNED; + else if (unitflag & UNIT_FLAG_SILENCED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && CheckCasterNotImmunedSilenceAuras(param1)) + result = SPELL_FAILED_SILENCED; + else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && CheckCasterNotImmunedPacifyAuras(param1)) + result = SPELL_FAILED_PACIFIED; + else if (unitflag & UNIT_FLAG_FLEEING && !usableWhileFeared && CheckCasterNotImmunedFearAuras(param1)) + result = SPELL_FAILED_FLEEING; + else if (unitflag & UNIT_FLAG_CONFUSED && !usableWhileConfused && CheckCasterNotImmunedDisorientAuras(param1)) + result = SPELL_FAILED_CONFUSED; // Attr must make flag drop spell totally immune from all effects - if (prevented_reason != SPELL_CAST_OK) + if (result != SPELL_CAST_OK) + return (param1 && *param1) ? SPELL_FAILED_PREVENTED_BY_MECHANIC : result; + + return SPELL_CAST_OK; +} + +// based on sub_00804430 from 12340 client +bool Spell::CheckCasterHasNotImmunedAuraType(AuraType auraType, uint32* param1) const +{ + // Checking auras is needed now, because you are prevented by some state but the spell grants immunity. + Unit::AuraEffectList const& auraEffects = m_caster->GetAuraEffectsByType(auraType); + if (auraEffects.empty()) + return false; + + for (AuraEffect const* aurEff : auraEffects) { - if (school_immune || mechanic_immune || dispel_immune) - { - //Checking auras is needed now, because you are prevented by some state but the spell grants immunity. - Unit::AuraApplicationMap const& auras = m_caster->GetAppliedAuras(); - for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - Aura const* aura = itr->second->GetBase(); - SpellInfo const* auraInfo = aura->GetSpellInfo(); - if (auraInfo->GetAllEffectsMechanicMask() & mechanic_immune) - continue; - if (auraInfo->GetSchoolMask() & school_immune && !auraInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE)) - continue; - if (auraInfo->GetDispelMask() & dispel_immune) - continue; + SpellInfo const* auraInfo = aurEff->GetSpellInfo(); + if (m_spellInfo->CanSpellCastOverrideAuraEffect(auraInfo, aurEff->GetEffIndex())) + continue; - //Make a second check for spell failed so the right SPELL_FAILED message is returned. - //That is needed when your casting is prevented by multiple states and you are only immune to some of them. - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (AuraEffect* part = aura->GetEffect(i)) - { - switch (part->GetAuraType()) - { - case SPELL_AURA_MOD_STUN: - if (!usableInStun || !(auraInfo->GetAllEffectsMechanicMask() & (1<<MECHANIC_STUN))) - return SPELL_FAILED_STUNNED; - break; - case SPELL_AURA_MOD_CONFUSE: - if (!m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED)) - return SPELL_FAILED_CONFUSED; - break; - case SPELL_AURA_MOD_FEAR: - if (!m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED)) - return SPELL_FAILED_FLEEING; - break; - case SPELL_AURA_MOD_SILENCE: - case SPELL_AURA_MOD_PACIFY: - case SPELL_AURA_MOD_PACIFY_SILENCE: - if (m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY) - return SPELL_FAILED_PACIFIED; - else if (m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) - return SPELL_FAILED_SILENCED; - break; - default: break; - } - } - } - } + if (param1) + { + *param1 = auraInfo->Effects[aurEff->GetEffIndex()].Mechanic; + if (!*param1) + *param1 = auraInfo->Mechanic; } - // You are prevented from casting and the spell cast does not grant immunity. Return a failed error. - else - return prevented_reason; + return true; } - return SPELL_CAST_OK; + + return false; +} + +bool Spell::CheckCasterNotImmunedCharmAuras(uint32* param1) const +{ + return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_CHARM, param1) || + CheckCasterHasNotImmunedAuraType(SPELL_AURA_AOE_CHARM, param1) || + CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_POSSESS, param1); +} + +bool Spell::CheckCasterNotImmunedStunAuras(uint32* param1) const +{ + return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_STUN, param1); +} + +bool Spell::CheckCasterNotImmunedSilenceAuras(uint32* param1) const +{ + return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_SILENCE, param1) || + CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_PACIFY_SILENCE, param1); +} + +bool Spell::CheckCasterNotImmunedPacifyAuras(uint32* param1) const +{ + return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_PACIFY, param1) || + CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_PACIFY_SILENCE, param1); +} + +bool Spell::CheckCasterNotImmunedFearAuras(uint32* param1) const +{ + return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_FEAR, param1); +} + +bool Spell::CheckCasterNotImmunedDisorientAuras(uint32* param1) const +{ + return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_CONFUSE, param1); } bool Spell::CanAutoCast(Unit* target) @@ -5826,7 +5918,7 @@ bool Spell::CanAutoCast(Unit* target) return false; } -SpellCastResult Spell::CheckRange(bool strict) +SpellCastResult Spell::CheckRange(bool strict) const { // Don't check for instant cast spells if (!strict && m_casttime == 0) @@ -5856,20 +5948,20 @@ SpellCastResult Spell::CheckRange(bool strict) if (m_targets.HasDst() && !m_targets.HasTraj()) { if (m_caster->GetExactDistSq(m_targets.GetDstPos()) > maxRange) - return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT; + return SPELL_FAILED_OUT_OF_RANGE; if (minRange > 0.0f && m_caster->GetExactDistSq(m_targets.GetDstPos()) < minRange) - return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT; + return SPELL_FAILED_OUT_OF_RANGE; } return SPELL_CAST_OK; } -std::pair<float, float> Spell::GetMinMaxRange(bool strict) +std::pair<float, float> Spell::GetMinMaxRange(bool strict) const { float rangeMod = 0.0f; float minRange = 0.0f; float maxRange = 0.0f; - if (strict && IsNextMeleeSwingSpell()) + if (strict && m_spellInfo->IsNextMeleeSwingSpell()) { maxRange = 100.0f; return std::pair<float, float>(minRange, maxRange); @@ -5911,14 +6003,14 @@ std::pair<float, float> Spell::GetMinMaxRange(bool strict) maxRange *= ranged->GetTemplate()->RangedModRange * 0.01f; if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod<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) @@ -5954,12 +6046,15 @@ SpellCastResult Spell::CheckPower() return SPELL_CAST_OK; } -SpellCastResult Spell::CheckItems() +SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) const { Player* player = m_caster->ToPlayer(); if (!player) return SPELL_CAST_OK; + if (m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_ITEM_CHECK)) + return SPELL_CAST_OK; + if (!m_CastItem) { if (m_castItemGUID) @@ -6035,10 +6130,11 @@ SpellCastResult Spell::CheckItems() // check target item if (m_targets.GetItemTargetGUID()) { - if (!m_targets.GetItemTarget()) + Item* item = m_targets.GetItemTarget(); + if (!item) return SPELL_FAILED_ITEM_GONE; - if (!m_targets.GetItemTarget()->IsFitToSpellRequirements(m_spellInfo)) + if (!item->IsFitToSpellRequirements(m_spellInfo)) return SPELL_FAILED_EQUIPPED_ITEM_CLASS; } // if not item target then required item must be equipped @@ -6088,7 +6184,11 @@ SpellCastResult Spell::CheckItems() } } if (!player->HasItemCount(itemid, itemcount)) + { + if (param1) + *param1 = itemid; return SPELL_FAILED_REAGENTS; + } } } @@ -6292,21 +6392,29 @@ SpellCastResult Spell::CheckItems() } case SPELL_EFFECT_PROSPECTING: { - if (!m_targets.GetItemTarget()) + Item* item = m_targets.GetItemTarget(); + if (!item) return SPELL_FAILED_CANT_BE_PROSPECTED; //ensure item is a prospectable ore - if (!(m_targets.GetItemTarget()->GetTemplate()->Flags & ITEM_FLAG_IS_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; @@ -6315,21 +6423,29 @@ SpellCastResult Spell::CheckItems() } case SPELL_EFFECT_MILLING: { - if (!m_targets.GetItemTarget()) + Item* item = m_targets.GetItemTarget(); + if (!item) return SPELL_FAILED_CANT_BE_MILLED; //ensure item is a millable herb - if (!(m_targets.GetItemTarget()->GetTemplate()->Flags & ITEM_FLAG_IS_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; @@ -6601,14 +6717,14 @@ bool Spell::UpdatePointers() CurrentSpellTypes Spell::GetCurrentContainer() const { - if (IsNextMeleeSwingSpell()) - return(CURRENT_MELEE_SPELL); + if (m_spellInfo->IsNextMeleeSwingSpell()) + return CURRENT_MELEE_SPELL; else if (IsAutoRepeat()) - return(CURRENT_AUTOREPEAT_SPELL); + return CURRENT_AUTOREPEAT_SPELL; else if (m_spellInfo->IsChanneled()) - return(CURRENT_CHANNELED_SPELL); - else - return(CURRENT_GENERIC_SPELL); + return CURRENT_CHANNELED_SPELL; + + return CURRENT_GENERIC_SPELL; } bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* losPosition) const @@ -6687,11 +6803,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? @@ -7069,7 +7180,7 @@ void Spell::SetSpellValue(SpellValueMod mod, int32 value) void Spell::PrepareTargetProcessing() { - CheckEffectExecuteData(); + AssertEffectExecuteData(); } void Spell::FinishTargetProcessing() @@ -7094,7 +7205,7 @@ void Spell::InitEffectExecuteData(uint8 effIndex) } } -void Spell::CheckEffectExecuteData() +void Spell::AssertEffectExecuteData() const { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) ASSERT(!m_effectExecuteData[i]); @@ -7102,29 +7213,20 @@ void Spell::CheckEffectExecuteData() void Spell::LoadScripts() { - sScriptMgr->CreateSpellScripts(m_spellInfo->Id, m_loadedScripts); - for (std::list<SpellScript*>::iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end();) + sScriptMgr->CreateSpellScripts(m_spellInfo->Id, m_loadedScripts, this); + for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr) { - if (!(*itr)->_Load(this)) - { - std::list<SpellScript*>::iterator bitr = itr; - ++itr; - delete (*bitr); - m_loadedScripts.erase(bitr); - continue; - } TC_LOG_DEBUG("spells", "Spell::LoadScripts: Script `%s` for spell `%u` is loaded now", (*itr)->_GetScriptName()->c_str(), m_spellInfo->Id); (*itr)->Register(); - ++itr; } } void Spell::CallScriptBeforeCastHandlers() { - for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_CAST); - std::list<SpellScript::CastHandler>::iterator hookItrEnd = (*scritr)->BeforeCast.end(), hookItr = (*scritr)->BeforeCast.begin(); + auto hookItrEnd = (*scritr)->BeforeCast.end(), hookItr = (*scritr)->BeforeCast.begin(); for (; hookItr != hookItrEnd; ++hookItr) (*hookItr).Call(*scritr); @@ -7134,10 +7236,10 @@ void Spell::CallScriptBeforeCastHandlers() void Spell::CallScriptOnCastHandlers() { - for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_CAST); - std::list<SpellScript::CastHandler>::iterator hookItrEnd = (*scritr)->OnCast.end(), hookItr = (*scritr)->OnCast.begin(); + auto hookItrEnd = (*scritr)->OnCast.end(), hookItr = (*scritr)->OnCast.begin(); for (; hookItr != hookItrEnd; ++hookItr) (*hookItr).Call(*scritr); @@ -7147,10 +7249,10 @@ void Spell::CallScriptOnCastHandlers() void Spell::CallScriptAfterCastHandlers() { - for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_CAST); - std::list<SpellScript::CastHandler>::iterator hookItrEnd = (*scritr)->AfterCast.end(), hookItr = (*scritr)->AfterCast.begin(); + auto hookItrEnd = (*scritr)->AfterCast.end(), hookItr = (*scritr)->AfterCast.begin(); for (; hookItr != hookItrEnd; ++hookItr) (*hookItr).Call(*scritr); @@ -7161,10 +7263,10 @@ void Spell::CallScriptAfterCastHandlers() SpellCastResult Spell::CallScriptCheckCastHandlers() { SpellCastResult retVal = SPELL_CAST_OK; - for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CHECK_CAST); - std::list<SpellScript::CheckCastHandler>::iterator hookItrEnd = (*scritr)->OnCheckCast.end(), hookItr = (*scritr)->OnCheckCast.begin(); + auto hookItrEnd = (*scritr)->OnCheckCast.end(), hookItr = (*scritr)->OnCheckCast.begin(); for (; hookItr != hookItrEnd; ++hookItr) { SpellCastResult tempResult = (*hookItr).Call(*scritr); @@ -7179,7 +7281,7 @@ SpellCastResult Spell::CallScriptCheckCastHandlers() void Spell::PrepareScriptHitHandlers() { - for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) (*scritr)->_InitHit(); } @@ -7187,9 +7289,9 @@ bool Spell::CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMo { // execute script effect handler hooks and check if effects was prevented bool preventDefault = false; - for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { - std::list<SpellScript::EffectHandler>::iterator effItr, effEndItr; + HookList<SpellScript::EffectHandler>::iterator effItr, effEndItr; SpellScriptHookType hookType; switch (mode) { @@ -7233,10 +7335,10 @@ bool Spell::CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMo void Spell::CallScriptSuccessfulDispel(SpellEffIndex effIndex) { - for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_EFFECT_SUCCESSFUL_DISPEL); - std::list<SpellScript::EffectHandler>::iterator hookItrEnd = (*scritr)->OnEffectSuccessfulDispel.end(), hookItr = (*scritr)->OnEffectSuccessfulDispel.begin(); + auto hookItrEnd = (*scritr)->OnEffectSuccessfulDispel.end(), hookItr = (*scritr)->OnEffectSuccessfulDispel.begin(); for (; hookItr != hookItrEnd; ++hookItr) hookItr->Call(*scritr, effIndex); @@ -7246,10 +7348,10 @@ void Spell::CallScriptSuccessfulDispel(SpellEffIndex effIndex) void Spell::CallScriptBeforeHitHandlers() { - for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_HIT); - std::list<SpellScript::HitHandler>::iterator hookItrEnd = (*scritr)->BeforeHit.end(), hookItr = (*scritr)->BeforeHit.begin(); + auto hookItrEnd = (*scritr)->BeforeHit.end(), hookItr = (*scritr)->BeforeHit.begin(); for (; hookItr != hookItrEnd; ++hookItr) (*hookItr).Call(*scritr); @@ -7259,10 +7361,10 @@ void Spell::CallScriptBeforeHitHandlers() void Spell::CallScriptOnHitHandlers() { - for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_HIT); - std::list<SpellScript::HitHandler>::iterator hookItrEnd = (*scritr)->OnHit.end(), hookItr = (*scritr)->OnHit.begin(); + auto hookItrEnd = (*scritr)->OnHit.end(), hookItr = (*scritr)->OnHit.begin(); for (; hookItr != hookItrEnd; ++hookItr) (*hookItr).Call(*scritr); @@ -7272,10 +7374,10 @@ void Spell::CallScriptOnHitHandlers() void Spell::CallScriptAfterHitHandlers() { - for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_HIT); - std::list<SpellScript::HitHandler>::iterator hookItrEnd = (*scritr)->AfterHit.end(), hookItr = (*scritr)->AfterHit.begin(); + auto hookItrEnd = (*scritr)->AfterHit.end(), hookItr = (*scritr)->AfterHit.begin(); for (; hookItr != hookItrEnd; ++hookItr) (*hookItr).Call(*scritr); @@ -7285,10 +7387,10 @@ void Spell::CallScriptAfterHitHandlers() void Spell::CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType) { - for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_AREA_TARGET_SELECT); - std::list<SpellScript::ObjectAreaTargetSelectHandler>::iterator hookItrEnd = (*scritr)->OnObjectAreaTargetSelect.end(), hookItr = (*scritr)->OnObjectAreaTargetSelect.begin(); + auto hookItrEnd = (*scritr)->OnObjectAreaTargetSelect.end(), hookItr = (*scritr)->OnObjectAreaTargetSelect.begin(); for (; hookItr != hookItrEnd; ++hookItr) if (hookItr->IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == hookItr->GetTarget()) hookItr->Call(*scritr, targets); @@ -7299,10 +7401,10 @@ void Spell::CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& ta void Spell::CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType) { - for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT); - std::list<SpellScript::ObjectTargetSelectHandler>::iterator hookItrEnd = (*scritr)->OnObjectTargetSelect.end(), hookItr = (*scritr)->OnObjectTargetSelect.begin(); + auto hookItrEnd = (*scritr)->OnObjectTargetSelect.end(), hookItr = (*scritr)->OnObjectTargetSelect.begin(); for (; hookItr != hookItrEnd; ++hookItr) if (hookItr->IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == hookItr->GetTarget()) hookItr->Call(*scritr, target); @@ -7313,10 +7415,10 @@ void Spell::CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffI void Spell::CallScriptDestinationTargetSelectHandlers(SpellDestination& target, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType) { - for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_DESTINATION_TARGET_SELECT); - std::list<SpellScript::DestinationTargetSelectHandler>::iterator hookItrEnd = (*scritr)->OnDestinationTargetSelect.end(), hookItr = (*scritr)->OnDestinationTargetSelect.begin(); + auto hookItrEnd = (*scritr)->OnDestinationTargetSelect.end(), hookItr = (*scritr)->OnDestinationTargetSelect.begin(); for (; hookItr != hookItrEnd; ++hookItr) if (hookItr->IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == hookItr->GetTarget()) hookItr->Call(*scritr, target); @@ -7331,15 +7433,15 @@ bool Spell::CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToC if (m_loadedScripts.empty()) return true; - for (std::list<SpellScript*>::iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr) + for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr) { - std::list<SpellScript::ObjectTargetSelectHandler>::iterator targetSelectHookEnd = (*itr)->OnObjectTargetSelect.end(), targetSelectHookItr = (*itr)->OnObjectTargetSelect.begin(); + auto targetSelectHookEnd = (*itr)->OnObjectTargetSelect.end(), targetSelectHookItr = (*itr)->OnObjectTargetSelect.begin(); for (; targetSelectHookItr != targetSelectHookEnd; ++targetSelectHookItr) if (((*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && !(*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck)) || (!(*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && (*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck))) return false; - std::list<SpellScript::ObjectAreaTargetSelectHandler>::iterator areaTargetSelectHookEnd = (*itr)->OnObjectAreaTargetSelect.end(), areaTargetSelectHookItr = (*itr)->OnObjectAreaTargetSelect.begin(); + auto areaTargetSelectHookEnd = (*itr)->OnObjectAreaTargetSelect.end(), areaTargetSelectHookItr = (*itr)->OnObjectAreaTargetSelect.begin(); for (; areaTargetSelectHookItr != areaTargetSelectHookEnd; ++areaTargetSelectHookItr) if (((*areaTargetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && !(*areaTargetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck)) || (!(*areaTargetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && (*areaTargetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck))) @@ -7389,25 +7491,24 @@ void Spell::PrepareTriggersExecutedOnHit() // save auras which were present on spell caster on cast, to prevent triggered auras from affecting caster // and to correctly calculate proc chance when combopoints are present Unit::AuraEffectList const& targetTriggers = m_caster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER); - for (Unit::AuraEffectList::const_iterator i = targetTriggers.begin(); i != targetTriggers.end(); ++i) + for (AuraEffect const* aurEff : targetTriggers) { - if (!(*i)->IsAffectedOnSpell(m_spellInfo)) + if (!aurEff->IsAffectedOnSpell(m_spellInfo)) continue; - SpellInfo const* auraSpellInfo = (*i)->GetSpellInfo(); - uint32 auraSpellIdx = (*i)->GetEffIndex(); + + SpellInfo const* auraSpellInfo = aurEff->GetSpellInfo(); + uint32 auraSpellIdx = aurEff->GetEffIndex(); if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(auraSpellInfo->Effects[auraSpellIdx].TriggerSpell)) { // calculate the chance using spell base amount, because aura amount is not updated on combo-points change // this possibly needs fixing - int32 auraBaseAmount = (*i)->GetBaseAmount(); + int32 auraBaseAmount = aurEff->GetBaseAmount(); // proc chance is stored in effect amount - int32 chance = m_caster->CalculateSpellDamage(NULL, auraSpellInfo, auraSpellIdx, &auraBaseAmount); + int32 chance = m_caster->CalculateSpellDamage(nullptr, auraSpellInfo, auraSpellIdx, &auraBaseAmount); + chance *= aurEff->GetBase()->GetStackAmount(); + // build trigger and add to the list - HitTriggerSpell spellTriggerInfo; - spellTriggerInfo.triggeredSpell = spellInfo; - spellTriggerInfo.triggeredByAura = auraSpellInfo; - spellTriggerInfo.chance = chance * (*i)->GetBase()->GetStackAmount(); - m_hitTriggerSpells.push_back(spellTriggerInfo); + m_hitTriggerSpells.emplace_back(spellInfo, auraSpellInfo, chance); } } } diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 5087ececa09..aa3b6ca358a 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,12 +481,14 @@ class TC_GAME_API Spell bool IsAutoRepeat() const { return m_autoRepeat; } void SetAutoRepeat(bool rep) { m_autoRepeat = rep; } void ReSetTimer() { m_timer = m_casttime > 0 ? m_casttime : 0; } - bool IsNextMeleeSwingSpell() const; bool IsTriggered() const { return (_triggeredCastFlags & TRIGGERED_FULL_MASK) != 0; } bool IsIgnoringCooldowns() const { return (_triggeredCastFlags & TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD) != 0; } + bool IsProcDisabled() const { return (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS) != 0; } bool IsChannelActive() const { return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0; } bool IsAutoActionResetSpell() const; + bool IsTriggeredByAura(SpellInfo const* auraSpellInfo) const { return (auraSpellInfo == m_triggeredByAuraSpell); } + bool IsDeletable() const { return !m_referencedFromCurrentSpell && !m_executedCurrently; } void SetReferencedFromCurrent(bool yes) { m_referencedFromCurrentSpell = yes; } bool IsInterruptable() const { return !m_executedCurrently; } @@ -507,7 +517,7 @@ class TC_GAME_API Spell void CancelGlobalCooldown(); void SendLoot(ObjectGuid guid, LootType loottype); - std::pair<float, float> GetMinMaxRange(bool strict); + std::pair<float, float> GetMinMaxRange(bool strict) const; Unit* const m_caster; @@ -636,7 +646,7 @@ class TC_GAME_API Spell // spell execution log void InitEffectExecuteData(uint8 effIndex); - void CheckEffectExecuteData(); + void AssertEffectExecuteData() const; // Scripting system void LoadScripts(); @@ -654,10 +664,13 @@ class TC_GAME_API Spell void CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType); void CallScriptDestinationTargetSelectHandlers(SpellDestination& target, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType); bool CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToCheck); - std::list<SpellScript*> m_loadedScripts; + std::vector<SpellScript*> m_loadedScripts; struct HitTriggerSpell { + HitTriggerSpell(SpellInfo const* spellInfo, SpellInfo const* auraSpellInfo, int32 procChance) : + triggeredSpell(spellInfo), triggeredByAura(auraSpellInfo), chance(procChance) { } + SpellInfo const* triggeredSpell; SpellInfo const* triggeredByAura; // uint8 triggeredByEffIdx This might be needed at a later stage - No need known for now @@ -666,7 +679,7 @@ class TC_GAME_API Spell bool CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura = NULL) const; void PrepareTriggersExecutedOnHit(); - typedef std::list<HitTriggerSpell> HitTriggerSpellList; + typedef std::vector<HitTriggerSpell> HitTriggerSpellList; HitTriggerSpellList m_hitTriggerSpells; // effect helpers diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index f321925aa8c..7afcf52172a 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -292,14 +292,18 @@ void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/) if (!unitTarget || !unitTarget->IsAlive()) return; - uint32 absorb = 0; - uint32 resist = 0; - - m_caster->CalcAbsorbResist(unitTarget, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist, m_spellInfo); - - m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_spellInfo->GetSchoolMask(), absorb, resist, false, 0, false); + // CalcAbsorbResist already in Player::EnvironmentalDamage if (unitTarget->GetTypeId() == TYPEID_PLAYER) unitTarget->ToPlayer()->EnvironmentalDamage(DAMAGE_FIRE, damage); + else + { + DamageInfo damageInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK); + m_caster->CalcAbsorbResist(damageInfo); + + uint32 absorb = damageInfo.GetAbsorb(); + uint32 resist = damageInfo.GetResist(); + m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_spellInfo->GetSchoolMask(), absorb, resist, false, 0, false); + } } void Spell::EffectSchoolDMG(SpellEffIndex effIndex) @@ -395,9 +399,9 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) // Conflagrate - consumes Immolate or Shadowflame else if (m_spellInfo->TargetAuraState == AURA_STATE_CONFLAGRATE) { - AuraEffect const* aura = NULL; // found req. aura for damage calculation + AuraEffect const* aura = nullptr; // found req. aura for damage calculation - Unit::AuraEffectList const &mPeriodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE); + Unit::AuraEffectList const& mPeriodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE); for (Unit::AuraEffectList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i) { // for caster applied auras only @@ -420,15 +424,22 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) // found Immolate or Shadowflame if (aura) { - uint32 pdamage = uint32(std::max(aura->GetAmount(), 0)); - pdamage = m_caster->SpellDamageBonusDone(unitTarget, aura->GetSpellInfo(), pdamage, DOT, aura->GetBase()->GetStackAmount()); - pdamage = unitTarget->SpellDamageBonusTaken(m_caster, aura->GetSpellInfo(), pdamage, DOT, aura->GetBase()->GetStackAmount()); - uint32 pct_dir = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, (effIndex + 1)); - uint8 baseTotalTicks = uint8(m_caster->CalcSpellDuration(aura->GetSpellInfo()) / aura->GetSpellInfo()->Effects[EFFECT_0].Amplitude); - damage += int32(CalculatePct(pdamage * baseTotalTicks, pct_dir)); + // Calculate damage of Immolate/Shadowflame tick + int32 pdamage = (aura->GetAmount() + aura->GetBonusAmount()) * aura->GetDonePct(); + if (Player* modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod<SPELLMOD_DOT>(GetSpellInfo()->Id, pdamage); - uint32 pct_dot = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, (effIndex + 2)) / 3; - m_spellValue->EffectBasePoints[1] = m_spellInfo->Effects[EFFECT_1].CalcBaseValue(int32(CalculatePct(pdamage * baseTotalTicks, pct_dot))); + pdamage = unitTarget->SpellDamageBonusTaken(m_caster, aura->GetSpellInfo(), pdamage, DOT); + + // And multiply by amount of ticks to get damage potential + pdamage *= aura->GetSpellInfo()->GetMaxTicks(); + + int32 pct_dir = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, EFFECT_1); + damage += CalculatePct(pdamage, pct_dir); + + int32 pct_dot = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, EFFECT_2); + int32 const dotBasePoints = CalculatePct(pdamage, pct_dot); + m_spellValue->EffectBasePoints[EFFECT_1] = dotBasePoints / m_spellInfo->GetMaxTicks(); apply_direct_bonus = false; // Glyph of Conflagrate @@ -1393,9 +1404,12 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/) return; } - int32 tickheal = targetAura->GetAmount(); - if (Unit* auraCaster = targetAura->GetCaster()) - tickheal = auraCaster->SpellHealingBonusDone(unitTarget, targetAura->GetSpellInfo(), tickheal, DOT); + int32 tickheal = (targetAura->GetAmount() + targetAura->GetBonusAmount()) * targetAura->GetDonePct(); + if (Player* modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod<SPELLMOD_DOT>(targetAura->GetId(), tickheal); + + unitTarget->SpellHealingBonusTaken(m_caster, targetAura->GetSpellInfo(), tickheal, DOT); + //int32 tickheal = targetAura->GetSpellInfo()->EffectBasePoints[idx] + 1; //It is said that talent bonus should not be included @@ -2103,6 +2117,8 @@ void Spell::EffectSummonChangeItem(SpellEffIndex effIndex) m_castItemEntry = 0; player->StoreItem(dest, pNewItem, true); + player->SendNewItem(pNewItem, 1, true, false); + player->ItemAddedQuestCheck(newitemid, 1); return; } } @@ -2147,6 +2163,8 @@ void Spell::EffectSummonChangeItem(SpellEffIndex effIndex) player->EquipItem(dest, pNewItem, true); player->AutoUnequipOffhandIfNeed(); + player->SendNewItem(pNewItem, 1, true, false); + player->ItemAddedQuestCheck(newitemid, 1); return; } } @@ -3362,8 +3380,10 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) } } - // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage - if (fixed_bonus || spell_bonus) + // if (addPctMods) { percent mods are added in Unit::CalculateDamage } else { percent mods are added in Unit::MeleeDamageBonusDone } + // this distinction is neccessary to properly inform the client about his autoattack damage values from Script_UnitDamage + bool addPctMods = !m_spellInfo->HasAttribute(SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS) && (m_spellSchoolMask & SPELL_SCHOOL_MASK_NORMAL); + if (addPctMods) { UnitMods unitMod; switch (m_attackType) @@ -3374,17 +3394,14 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break; } - float weapon_total_pct = 1.0f; - if (m_spellInfo->SchoolMask & SPELL_SCHOOL_MASK_NORMAL) - weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT); - + float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT); if (fixed_bonus) fixed_bonus = int32(fixed_bonus * weapon_total_pct); if (spell_bonus) spell_bonus = int32(spell_bonus * weapon_total_pct); } - int32 weaponDamage = m_caster->CalculateDamage(m_attackType, normalized, true); + int32 weaponDamage = m_caster->CalculateDamage(m_attackType, normalized, addPctMods); // Sequence is important for (int j = 0; j < MAX_SPELL_EFFECTS; ++j) @@ -3399,17 +3416,14 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) weaponDamage += fixed_bonus; break; case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: - weaponDamage = int32(weaponDamage* weaponDamagePercentMod); + weaponDamage = int32(weaponDamage * weaponDamagePercentMod); default: break; // not weapon damage effect, just skip } } - if (spell_bonus) - weaponDamage += spell_bonus; - - if (totalDamagePercentMod != 1.0f) - weaponDamage = int32(weaponDamage* totalDamagePercentMod); + weaponDamage += spell_bonus; + weaponDamage = int32(weaponDamage * totalDamagePercentMod); // prevent negative damage uint32 eff_damage(std::max(weaponDamage, 0)); @@ -3531,21 +3545,12 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) if (Battleground* bg = player->GetBattleground()) bg->SetDroppedFlagGUID(pGameObj->GetGUID(), player->GetTeam() == ALLIANCE ? TEAM_HORDE: TEAM_ALLIANCE); - if (uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry()) + if (GameObject* linkedTrap = pGameObj->GetLinkedTrap()) { - GameObject* linkedGO = new GameObject(); - if (linkedGO->Create(map->GenerateLowGuid<HighGuid::GameObject>(), linkedEntry, map, m_caster->GetPhaseMask(), Position(x, y, z, target->GetOrientation()), rot, 255, GO_STATE_READY)) - { - linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); - linkedGO->SetSpellId(m_spellInfo->Id); - - ExecuteLogEffectSummonObject(effIndex, linkedGO); + linkedTrap->SetRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0); + linkedTrap->SetSpellId(m_spellInfo->Id); - // Wild object not have owner and check clickable by players - map->AddToMap(linkedGO); - } - else - delete linkedGO; + ExecuteLogEffectSummonObject(effIndex, linkedTrap); } } @@ -5137,26 +5142,14 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) cMap->AddToMap(pGameObj); - if (uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry()) + if (GameObject* linkedTrap = pGameObj->GetLinkedTrap()) { - GameObject* linkedGO = new GameObject; - if (linkedGO->Create(cMap->GenerateLowGuid<HighGuid::GameObject>(), linkedEntry, cMap, m_caster->GetPhaseMask(), pos, rot, 255, GO_STATE_READY)) - { - linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); - //linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); - linkedGO->SetSpellId(m_spellInfo->Id); - linkedGO->SetOwnerGUID(m_caster->GetGUID()); + linkedTrap->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); + //linkedTrap->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); + linkedTrap->SetSpellId(m_spellInfo->Id); + linkedTrap->SetOwnerGUID(m_caster->GetGUID()); - ExecuteLogEffectSummonObject(effIndex, linkedGO); - - linkedGO->GetMap()->AddToMap(linkedGO); - } - else - { - delete linkedGO; - linkedGO = NULL; - return; - } + ExecuteLogEffectSummonObject(effIndex, linkedTrap); } } diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 925d5ec57a3..c0fbdf51889 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -16,6 +16,7 @@ */ #include "SpellAuraDefines.h" +#include "SpellAuras.h" #include "SpellInfo.h" #include "SpellMgr.h" #include "Spell.h" @@ -894,6 +895,31 @@ bool SpellInfo::HasAreaAuraEffect() const return false; } +bool SpellInfo::HasOnlyDamageEffects() const +{ + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (Effects[i].IsEffect()) + { + switch (Effects[i].Effect) + { + case SPELL_EFFECT_WEAPON_DAMAGE: + case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: + case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: + case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: + case SPELL_EFFECT_SCHOOL_DAMAGE: + case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE: + case SPELL_EFFECT_HEALTH_LEECH: + continue; + default: + return false; + } + } + } + + return true; +} + bool SpellInfo::IsExplicitDiscovery() const { return ((Effects[0].Effect == SPELL_EFFECT_CREATE_RANDOM_ITEM @@ -1181,12 +1207,22 @@ bool SpellInfo::IsPositiveEffect(uint8 effIndex) const bool SpellInfo::IsChanneled() const { - return HasAttribute(SPELL_ATTR1_CHANNELED_1) || HasAttribute(SPELL_ATTR1_CHANNELED_2); + return HasAttribute(SpellAttr1(SPELL_ATTR1_CHANNELED_1 | SPELL_ATTR1_CHANNELED_2)); +} + +bool SpellInfo::IsMoveAllowedChannel() const +{ + return IsChanneled() && HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING); } bool SpellInfo::NeedsComboPoints() const { - return HasAttribute(SPELL_ATTR1_REQ_COMBO_POINTS1) || HasAttribute(SPELL_ATTR1_REQ_COMBO_POINTS2); + return HasAttribute(SpellAttr1(SPELL_ATTR1_REQ_COMBO_POINTS1 | SPELL_ATTR1_REQ_COMBO_POINTS2)); +} + +bool SpellInfo::IsNextMeleeSwingSpell() const +{ + return HasAttribute(SpellAttr0(SPELL_ATTR0_ON_NEXT_SWING | SPELL_ATTR0_ON_NEXT_SWING_2)); } bool SpellInfo::IsBreakingStealth() const @@ -1210,6 +1246,20 @@ bool SpellInfo::HasInitialAggro() const return !(HasAttribute(SPELL_ATTR1_NO_THREAT) || HasAttribute(SPELL_ATTR3_NO_INITIAL_AGGRO)); } +bool SpellInfo::IsAffected(uint32 familyName, flag96 const& familyFlags) const +{ + if (!familyName) + return true; + + if (familyName != SpellFamilyName) + return false; + + if (familyFlags && !(familyFlags & SpellFamilyFlags)) + return false; + + return true; +} + bool SpellInfo::IsAffectedBySpellMods() const { return !HasAttribute(SPELL_ATTR3_NO_DONE_BONUS); @@ -1221,42 +1271,41 @@ bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const return false; SpellInfo const* affectSpell = sSpellMgr->GetSpellInfo(mod->spellId); - // False if affect_spell == NULL or spellFamily not equal - if (!affectSpell || affectSpell->SpellFamilyName != SpellFamilyName) + if (!affectSpell) return false; - // true - if (mod->mask & SpellFamilyFlags) - return true; - - return false; + return IsAffected(affectSpell->SpellFamilyName, mod->mask); } -bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const +bool SpellInfo::CanPierceImmuneAura(SpellInfo const* auraSpellInfo) const { - // these spells pierce all avalible spells (Resurrection Sickness for example) + // aura can't be pierced + if (!auraSpellInfo || auraSpellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)) + return false; + + // these spells pierce all available spells (Resurrection Sickness for example) if (HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)) return true; - // these spells (Cyclone for example) can pierce all... // ...but not these (Divine shield, Ice block, Cyclone and Banish for example) - if (HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY || aura->Mechanic == MECHANIC_BANISH))) + // Dispels other auras on immunity, check if this spell makes the unit immune to aura + if (HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) && CanSpellProvideImmunityAgainstAura(auraSpellInfo)) return true; return false; } -bool SpellInfo::CanDispelAura(SpellInfo const* aura) const +bool SpellInfo::CanDispelAura(SpellInfo const* auraSpellInfo) const { - // These spells (like Mass Dispel) can dispell all auras, except death persistent ones (like Dungeon and Battleground Deserter) - if (HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) && !aura->IsDeathPersistent()) - return true; - // These auras (like Divine Shield) can't be dispelled - if (aura->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)) + if (auraSpellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)) return false; + // These spells (like Mass Dispel) can dispel all auras + if (HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)) + return true; + // These auras (Cyclone for example) are not dispelable - if (aura->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE)) + if (auraSpellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) || auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE)) return false; return true; @@ -1411,9 +1460,11 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a // continent limitation (virtual continent) if (HasAttribute(SPELL_ATTR4_CAST_ONLY_IN_OUTLAND)) { - uint32 v_map = GetVirtualMapForMapAndZone(map_id, zone_id); - MapEntry const* mapEntry = sMapStore.LookupEntry(v_map); - if (!mapEntry || mapEntry->addon < 1 || !mapEntry->IsContinent()) + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(area_id); + if (!areaEntry) + areaEntry = sAreaTableStore.LookupEntry(zone_id); + + if (!areaEntry || !areaEntry->IsFlyable() || !player->CanFlyInZone(map_id, zone_id)) return SPELL_FAILED_INCORRECT_AREA; } @@ -1982,9 +2033,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; @@ -2441,6 +2510,437 @@ 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) @@ -2843,8 +3343,16 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const // Special case: effects which determine positivity of whole spell for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { - if (Effects[i].IsAura() && Effects[i].ApplyAuraName == SPELL_AURA_MOD_STEALTH) - return true; + if (Effects[i].IsAura()) + { + switch (Effects[i].ApplyAuraName) + { + case SPELL_AURA_MOD_STEALTH: + return true; + case SPELL_AURA_CHANNEL_DEATH_ITEM: + return false; + } + } } switch (Effects[effIndex].Effect) diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index b2566ecf533..d7b48ddb4d2 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -24,6 +24,8 @@ #include "Object.h" #include "SpellAuraDefines.h" +#include <boost/container/flat_set.hpp> + class Unit; class Player; class Item; @@ -300,6 +302,18 @@ struct TC_GAME_API SpellDiminishInfo int32 DiminishDurationLimit = 0; }; +struct TC_GAME_API ImmunityInfo +{ + uint32 SchoolImmuneMask = 0; + uint32 ApplyHarmfulAuraImmuneMask = 0; + uint32 MechanicImmuneMask = 0; + uint32 DispelImmune = 0; + uint32 DamageSchoolMask = 0; + + boost::container::flat_set<AuraType> AuraTypeImmune; + boost::container::flat_set<SpellEffects> SpellEffectImmune; +}; + class TC_GAME_API SpellInfo { friend class SpellMgr; @@ -388,6 +402,7 @@ class TC_GAME_API SpellInfo bool HasEffect(SpellEffects effect) const; bool HasAura(AuraType aura) const; bool HasAreaAuraEffect() const; + bool HasOnlyDamageEffects() const; inline bool HasAttribute(SpellAttr0 attribute) const { return !!(Attributes & attribute); } inline bool HasAttribute(SpellAttr1 attribute) const { return !!(AttributesEx & attribute); } @@ -429,17 +444,21 @@ class TC_GAME_API SpellInfo 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* aura) const; - bool CanDispelAura(SpellInfo const* aura) const; + bool CanPierceImmuneAura(SpellInfo const* auraSpellInfo) const; + bool CanDispelAura(SpellInfo const* auraSpellInfo) const; bool IsSingleTarget() const; bool IsAuraExclusiveBySpecificWith(SpellInfo const* spellInfo) const; @@ -495,6 +514,11 @@ class TC_GAME_API SpellInfo 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(); @@ -504,6 +528,7 @@ class TC_GAME_API SpellInfo void _LoadSpellSpecific(); void _LoadAuraState(); void _LoadSpellDiminishInfo(); + void _LoadImmunityInfo(); // unloading helpers void _UnloadImplicitTargetConditionLists(); @@ -513,6 +538,8 @@ class TC_GAME_API SpellInfo 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 02584542676..bd13f1b2c7b 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -492,7 +492,7 @@ SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const return NULL; } -bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const +bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) { // proc type doesn't match if (!(eventInfo.GetTypeMask() & procEntry.ProcFlags)) @@ -535,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; } @@ -1524,6 +1517,9 @@ void SpellMgr::LoadSpellProcs() TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `HitMask` set: %u", spellInfo->Id, procEntry.HitMask); if (procEntry.HitMask && !(procEntry.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.ProcFlags & DONE_HIT_PROC_FLAG_MASK && (!procEntry.SpellPhaseMask || procEntry.SpellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH))))) TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `HitMask` value defined, but it will not be used for defined `ProcFlags` and `SpellPhaseMask` values.", spellInfo->Id); + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if ((procEntry.AttributesMask & (PROC_ATTR_DISABLE_EFF_0 << i)) && !spellInfo->Effects[i].IsAura()) + TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has Attribute PROC_ATTR_DISABLE_EFF_%u, but effect %u is not an aura effect", spellInfo->Id, static_cast<uint32>(i), static_cast<uint32>(i)); mSpellProcMap[spellInfo->Id] = procEntry; @@ -1593,6 +1589,8 @@ void SpellMgr::LoadSpellProcs() 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; @@ -1615,9 +1613,14 @@ void SpellMgr::LoadSpellProcs() if (!spellInfo) continue; + // Data already present in DB, overwrites default proc if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end()) continue; + // 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) @@ -1635,15 +1638,27 @@ void SpellMgr::LoadSpellProcs() 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 (!procSpellTypeMask) continue; - if (!spellInfo->ProcFlags) - continue; - SpellProcEntry procEntry; procEntry.SchoolMask = 0; procEntry.ProcFlags = spellInfo->ProcFlags; @@ -2603,6 +2618,8 @@ void SpellMgr::LoadSpellInfoCorrections() case 2895: // Wrath of Air Totem rank 1 (Aura) case 68933: // Wrath of Air Totem rank 2 (Aura) case 29200: // Purify Helboar Meat + case 10872: // Abolish Disease Effect + case 3137: // Abolish Poison Effect spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(); break; @@ -2630,6 +2647,15 @@ void SpellMgr::LoadSpellInfoCorrections() // because of bug in dbc spellInfo->ProcChance = 0; break; + case 51528: // Maelstrom Weapon (Rank 1) + case 51529: // Maelstrom Weapon (Rank 2) + case 51530: // Maelstrom Weapon (Rank 3) + case 51531: // Maelstrom Weapon (Rank 4) + case 51532: // Maelstrom Weapon (Rank 5) + // due to discrepancies between ranks + spellInfo->EquippedItemSubClassMask = 0x0000FC33; + spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED; + break; case 20335: // Heart of the Crusader case 20336: case 20337: @@ -2755,15 +2781,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; @@ -2843,6 +2868,19 @@ void SpellMgr::LoadSpellInfoCorrections() case 27915: // Anchor to Skulls case 27931: // Anchor to Skulls case 27937: // Anchor to Skulls + case 16177: // Ancestral Fortitude (Rank 1) + case 16236: // Ancestral Fortitude (Rank 2) + case 16237: // Ancestral Fortitude (Rank 3) + case 47930: // Grace + case 45145: // Snake Trap Effect (Rank 1) + case 13812: // Explosive Trap Effect (Rank 1) + case 14314: // Explosive Trap Effect (Rank 2) + case 14315: // Explosive Trap Effect (Rank 3) + case 27026: // Explosive Trap Effect (Rank 4) + case 49064: // Explosive Trap Effect (Rank 5) + case 49065: // Explosive Trap Effect (Rank 6) + case 43446: // Explosive Trap Effect (Hexlord Malacrass) + case 68979: // Unleashed Souls spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); break; // target allys instead of enemies, target A is src_caster, spells with effect like that have ally target @@ -2950,9 +2988,6 @@ void SpellMgr::LoadSpellInfoCorrections() case 71839: // Drain Life - Bryntroll Heroic spellInfo->AttributesEx2 |= SPELL_ATTR2_CANT_CRIT; break; - case 34471: // The Beast Within - spellInfo->AttributesEx5 |= SPELL_ATTR5_USABLE_WHILE_CONFUSED | SPELL_ATTR5_USABLE_WHILE_FEARED | SPELL_ATTR5_USABLE_WHILE_STUNNED; - break; case 56606: // Ride Jokkum case 61791: // Ride Vehicle (Yogg-Saron) /// @todo: remove this when basepoints of all Ride Vehicle auras are calculated correctly @@ -3004,6 +3039,10 @@ void SpellMgr::LoadSpellInfoCorrections() 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) @@ -3488,3 +3527,18 @@ void SpellMgr::LoadSpellInfoDiminishing() 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 f119d164789..a08ff921a2e 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -165,9 +165,8 @@ enum ProcFlags | 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, + | 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, @@ -175,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 @@ -238,7 +238,11 @@ enum ProcAttributes PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000001, // requires proc target to give exp or honor for aura proc PROC_ATTR_TRIGGERED_CAN_PROC = 0x0000002, // aura can proc even with triggered spells PROC_ATTR_REQ_MANA_COST = 0x0000004, // requires triggering spell to have a mana cost for aura proc - PROC_ATTR_REQ_SPELLMOD = 0x0000008 // requires triggering spell to be affected by proccing aura to drop charges + PROC_ATTR_REQ_SPELLMOD = 0x0000008, // requires triggering spell to be affected by proccing aura to drop charges + + PROC_ATTR_DISABLE_EFF_0 = 0x0000010, // explicitly disables aura proc from effects, USE ONLY IF 100% SURE AURA SHOULDN'T PROC + PROC_ATTR_DISABLE_EFF_1 = 0x0000020, // used to avoid a console error if the spell has invalid trigger spell and handled elsewhere + PROC_ATTR_DISABLE_EFF_2 = 0x0000040 // or handling not needed }; struct SpellProcEntry @@ -606,7 +610,7 @@ class TC_GAME_API SpellMgr // Spell proc table SpellProcEntry const* GetSpellProcEntry(uint32 spellId) const; - bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const; + static bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo); // Spell bonus data table SpellBonusEntry const* GetSpellBonusData(uint32 spellId) const; @@ -680,6 +684,7 @@ class TC_GAME_API SpellMgr 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 59a1e757183..7bbf73d028d 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1449,12 +1449,12 @@ 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); @@ -1514,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_guild.cpp b/src/server/scripts/Commands/cs_guild.cpp index 98fc852b573..8c4bf73395d 100644 --- a/src/server/scripts/Commands/cs_guild.cpp +++ b/src/server/scripts/Commands/cs_guild.cpp @@ -146,7 +146,8 @@ public: return false; // player's guild membership checked in AddMember before add - return targetGuild->AddMember(targetGuid); + SQLTransaction trans(nullptr); + return targetGuild->AddMember(trans, targetGuid); } static bool HandleGuildUninviteCommand(ChatHandler* handler, char const* args) @@ -164,7 +165,8 @@ public: if (!targetGuild) return false; - targetGuild->DeleteMember(targetGuid, false, true, true); + SQLTransaction trans(nullptr); + targetGuild->DeleteMember(trans, targetGuid, false, true, true); return true; } @@ -191,7 +193,8 @@ public: return false; uint8 newRank = uint8(atoi(rankStr)); - return targetGuild->ChangeMemberRank(targetGuid, newRank); + SQLTransaction trans(nullptr); + return targetGuild->ChangeMemberRank(trans, targetGuid, newRank); } static bool HandleGuildRenameCommand(ChatHandler* handler, char const* _args) diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 16217fbaea6..5487b9c7b2f 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -2268,19 +2268,20 @@ public: // melee damage by specific school if (!spellStr) { - uint32 absorb = 0; - uint32 resist = 0; + Player* attacker = handler->GetSession()->GetPlayer(); + DamageInfo dmgInfo(attacker, target, damage, nullptr, schoolmask, SPELL_DIRECT_DAMAGE, BASE_ATTACK); + attacker->CalcAbsorbResist(dmgInfo); - handler->GetSession()->GetPlayer()->CalcAbsorbResist(target, schoolmask, SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); - - if (damage <= absorb + resist) + if (!dmgInfo.GetDamage()) return true; - damage -= absorb + resist; + damage = dmgInfo.GetDamage(); - handler->GetSession()->GetPlayer()->DealDamageMods(target, damage, &absorb); - handler->GetSession()->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, schoolmask, NULL, false); - handler->GetSession()->GetPlayer()->SendAttackStateUpdate (HITINFO_AFFECTS_VICTIM, target, 1, schoolmask, damage, absorb, resist, VICTIMSTATE_HIT, 0); + uint32 absorb = dmgInfo.GetAbsorb(); + uint32 resist = dmgInfo.GetResist(); + attacker->DealDamageMods(target, damage, &absorb); + attacker->DealDamage(target, damage, nullptr, DIRECT_DAMAGE, schoolmask, nullptr, false); + attacker->SendAttackStateUpdate(HITINFO_AFFECTS_VICTIM, target, 0, schoolmask, damage, absorb, resist, VICTIMSTATE_HIT, 0); return true; } @@ -2288,10 +2289,22 @@ public: // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form uint32 spellid = handler->extractSpellIdFromLink((char*)args); - if (!spellid || !sSpellMgr->GetSpellInfo(spellid)) + if (!spellid) + return false; + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); + if (!spellInfo) return false; - handler->GetSession()->GetPlayer()->SpellNonMeleeDamageLog(target, spellid, damage); + Player* attacker = handler->GetSession()->GetPlayer(); + SpellNonMeleeDamage dmgInfo(attacker, target, spellid, spellInfo->GetSchoolMask()); + damage = attacker->SpellDamageBonusDone(target, spellInfo, damage, SPELL_DIRECT_DAMAGE); + damage = target->SpellDamageBonusTaken(attacker, spellInfo, damage, SPELL_DIRECT_DAMAGE); + + attacker->CalculateSpellDamageTaken(&dmgInfo, damage, spellInfo); + attacker->DealDamageMods(dmgInfo.target, dmgInfo.damage, &dmgInfo.absorb); + attacker->SendSpellNonMeleeDamageLog(&dmgInfo); + attacker->DealSpellDamage(&dmgInfo, true); return true; } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp index a43e2ee37dd..89617a9f4ef 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp @@ -578,7 +578,7 @@ public: bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/) override { - if (player && player->IsAlive()) + if (player->IsAlive()) if (InstanceScript* instance = player->GetInstanceScript()) if (Creature* infiltrator = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_SCARSHIELD_INFILTRATOR))) { diff --git a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp index d0430ebb3e5..67bda699643 100644 --- a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp +++ b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp @@ -54,7 +54,6 @@ enum Yells enum Spells { SPELL_UNLOCK = 6421, - SPELL_DARK_OFFERING = 7154 }; @@ -205,6 +204,123 @@ public: }; +enum ArugalSpells +{ + SPELL_TELE_UPPER = 7587, + SPELL_TELE_SPAWN = 7586, + SPELL_TELE_STAIRS = 7136, + NUM_TELEPORT_SPELLS = 3, + SPELL_ARUGAL_CURSE = 7621, + SPELL_THUNDERSHOCK = 7803, + SPELL_VOIDBOLT = 7588 +}; + +enum ArugalTexts +{ + SAY_AGGRO = 1, // You, too, shall serve! + SAY_TRANSFORM = 2, // Release your rage! + SAY_SLAY = 3 // Another falls! +}; + +enum ArugalEvents +{ + EVENT_VOID_BOLT = 1, + EVENT_TELEPORT, + EVENT_THUNDERSHOCK, + EVENT_CURSE +}; + +class boss_archmage_arugal : public CreatureScript +{ + public: + boss_archmage_arugal() : CreatureScript("boss_archmage_arugal") { } + + struct boss_archmage_arugalAI : public BossAI + { + boss_archmage_arugalAI(Creature* creature) : BossAI(creature, BOSS_ARUGAL) { } + + uint32 teleportSpells[NUM_TELEPORT_SPELLS] = + { + SPELL_TELE_SPAWN, + SPELL_TELE_UPPER, + SPELL_TELE_STAIRS + }; + + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_ARUGAL_CURSE) + Talk(SAY_TRANSFORM); + } + + void EnterCombat(Unit* /*who*/) override + { + _EnterCombat(); + Talk(SAY_AGGRO); + events.ScheduleEvent(EVENT_CURSE, Seconds(7)); + events.ScheduleEvent(EVENT_TELEPORT, Seconds(15)); + events.ScheduleEvent(EVENT_VOID_BOLT, Seconds(1)); + events.ScheduleEvent(EVENT_THUNDERSHOCK, Seconds(10)); + } + + void AttackStart(Unit* who) override + { + AttackStartCaster(who, 100.0f); // void bolt range is 100.f + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CURSE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 30.0f, true)) + DoCast(target, SPELL_ARUGAL_CURSE); + events.Repeat(Seconds(15)); + break; + case EVENT_TELEPORT: + { + // ensure we never cast the same teleport twice in a row + uint8 spellIndex = urand(1, NUM_TELEPORT_SPELLS-1); + std::swap(teleportSpells[0], teleportSpells[spellIndex]); + DoCast(teleportSpells[0]); + events.Repeat(Seconds(20)); + break; + } + case EVENT_THUNDERSHOCK: + DoCastAOE(SPELL_THUNDERSHOCK); + events.Repeat(Seconds(30)); + break; + case EVENT_VOID_BOLT: + DoCastVictim(SPELL_VOIDBOLT); + events.Repeat(Seconds(5)); + break; + } + } + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_archmage_arugalAI>(creature); + } +}; + class spell_shadowfang_keep_haunting_spirits : public SpellScriptLoader { public: @@ -248,5 +364,6 @@ void AddSC_shadowfang_keep() { new npc_shadowfang_prisoner(); new npc_arugal_voidwalker(); + new boss_archmage_arugal(); new spell_shadowfang_keep_haunting_spirits(); } diff --git a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.h b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.h index 88edc3f1ee1..7e508191f69 100644 --- a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.h +++ b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.h @@ -26,8 +26,8 @@ enum DataTypes TYPE_FREE_NPC = 1, TYPE_RETHILGORE = 2, TYPE_FENRUS = 3, - TYPE_NANDOS = 4 + TYPE_NANDOS = 4, + BOSS_ARUGAL = 5 }; #endif - diff --git a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp index adcb4f9fc9a..d9c929794cc 100644 --- a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp +++ b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp @@ -175,7 +175,7 @@ void AddSC_arathi_highlands(); void AddSC_blasted_lands(); void AddSC_burning_steppes(); void AddSC_duskwood(); -void AddSC_eastern_plaguelands(); +//void AddSC_eastern_plaguelands(); void AddSC_ghostlands(); void AddSC_hinterlands(); void AddSC_isle_of_queldanas(); @@ -352,7 +352,7 @@ void AddEasternKingdomsScripts() AddSC_blasted_lands(); AddSC_burning_steppes(); AddSC_duskwood(); - AddSC_eastern_plaguelands(); + //AddSC_eastern_plaguelands(); AddSC_ghostlands(); AddSC_hinterlands(); AddSC_isle_of_queldanas(); diff --git a/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp deleted file mode 100644 index c35c8629cef..00000000000 --- a/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/* ScriptData -SDName: Eastern_Plaguelands -SD%Complete: 100 -SDComment: Quest support: 5211. Special vendor Augustus the Touched -SDCategory: Eastern Plaguelands -EndScriptData */ - -/* ContentData -npc_ghoul_flayer -npc_augustus_the_touched -npc_darrowshire_spirit -EndContentData */ - -#include "ScriptMgr.h" -#include "ScriptedCreature.h" -#include "ScriptedGossip.h" -#include "Player.h" -#include "WorldSession.h" - -class npc_ghoul_flayer : public CreatureScript -{ -public: - npc_ghoul_flayer() : CreatureScript("npc_ghoul_flayer") { } - - struct npc_ghoul_flayerAI : public ScriptedAI - { - npc_ghoul_flayerAI(Creature* creature) : ScriptedAI(creature) { } - - void Reset() override { } - - void EnterCombat(Unit* /*who*/) override { } - - void JustDied(Unit* killer) override - { - if (killer->GetTypeId() == TYPEID_PLAYER) - me->SummonCreature(11064, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_ghoul_flayerAI(creature); - } -}; - -/*###### -## npc_augustus_the_touched -######*/ - -class npc_augustus_the_touched : public CreatureScript -{ -public: - npc_augustus_the_touched() : CreatureScript("npc_augustus_the_touched") { } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - ClearGossipMenuFor(player); - if (action == GOSSIP_ACTION_TRADE) - player->GetSession()->SendListInventory(creature->GetGUID()); - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (creature->IsVendor() && player->GetQuestRewardStatus(6164)) - AddGossipItemFor(player, GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID()); - return true; - } -}; - -/*###### -## npc_darrowshire_spirit -######*/ - -enum DarrowshireSpirit -{ - SPELL_SPIRIT_SPAWNIN = 17321 -}; - -class npc_darrowshire_spirit : public CreatureScript -{ -public: - npc_darrowshire_spirit() : CreatureScript("npc_darrowshire_spirit") { } - - bool OnGossipHello(Player* player, Creature* creature) override - { - SendGossipMenuFor(player, 3873, creature->GetGUID()); - player->TalkedToCreature(creature->GetEntry(), creature->GetGUID()); - creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - return true; - } - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_darrowshire_spiritAI(creature); - } - - struct npc_darrowshire_spiritAI : public ScriptedAI - { - npc_darrowshire_spiritAI(Creature* creature) : ScriptedAI(creature) { } - - void Reset() override - { - DoCast(me, SPELL_SPIRIT_SPAWNIN); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void EnterCombat(Unit* /*who*/) override { } - }; -}; - -void AddSC_eastern_plaguelands() -{ - new npc_ghoul_flayer(); - new npc_augustus_the_touched(); - new npc_darrowshire_spirit(); -} diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp index 5d41908435e..722b7768617 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp @@ -279,7 +279,7 @@ class spell_anetheron_vampiric_aura : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); DamageInfo* damageInfo = eventInfo.GetDamageInfo(); @@ -287,7 +287,7 @@ class spell_anetheron_vampiric_aura : public SpellScriptLoader return; int32 bp = damageInfo->GetDamage() * 3; - eventInfo.GetActor()->CastCustomSpell(SPELL_VAMPIRIC_AURA_HEAL, SPELLVALUE_BASE_POINT0, bp, eventInfo.GetActor(), true); + eventInfo.GetActor()->CastCustomSpell(SPELL_VAMPIRIC_AURA_HEAL, SPELLVALUE_BASE_POINT0, bp, eventInfo.GetActor(), true, nullptr, aurEff); } void Register() 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 3bc3ec45e5f..976ef3e34db 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp @@ -417,8 +417,9 @@ class npc_snobold_vassal : public CreatureScript switch (eventId) { case EVENT_FIRE_BOMB: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, -me->GetVehicleBase()->GetCombatReach(), true)) - me->CastSpell(target, SPELL_FIRE_BOMB); + if (me->GetVehicleBase()) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, -me->GetVehicleBase()->GetCombatReach(), true)) + me->CastSpell(target, SPELL_FIRE_BOMB); _events.Repeat(Seconds(20)); break; case EVENT_HEAD_CRACK: diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 77805dbfcb2..15e4885d4a7 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -1115,7 +1115,7 @@ class spell_putricide_ooze_tank_protection : public SpellScriptLoader PreventDefaultAction(); Unit* actionTarget = eventInfo.GetActionTarget(); - actionTarget->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true); + actionTarget->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index a2348119dff..f3021cdbab5 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -1099,6 +1099,12 @@ class spell_sindragosa_s_fury : public SpellScriptLoader if (!GetHitUnit()->IsAlive() || !_targetCount) return; + if (GetHitUnit()->IsImmunedToDamage(GetSpellInfo())) + { + GetCaster()->SendSpellDamageImmune(GetHitUnit(), GetSpellInfo()->Id); + return; + } + float resistance = float(GetHitUnit()->GetResistance(SpellSchoolMask(GetSpellInfo()->SchoolMask))); uint32 minResistFactor = uint32((resistance / (resistance + 510.0f)) * 10.0f) * 2; uint32 randomResist = urand(0, (9 - minResistFactor) * 100) / 100 + minResistFactor; diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp index b25f7ed3eca..82abb2836ba 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp @@ -222,11 +222,11 @@ class spell_uk_second_wind : public SpellScriptLoader return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN))) != 0; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActionTarget(); - caster->CastSpell(caster, SPELL_SECOND_WIND_TRIGGER, true); + caster->CastSpell(caster, SPELL_SECOND_WIND_TRIGGER, true, nullptr, aurEff); } void Register() override 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_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp index 2effc1d9a2a..54ae9c27aeb 100644 --- a/src/server/scripts/Northrend/zone_storm_peaks.cpp +++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp @@ -281,6 +281,7 @@ public: void UpdateAI(uint32 diff) override { + VehicleAI::UpdateAI(diff); events.Update(diff); switch (events.ExecuteEvent()) diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp index 1b0d5c22833..bcfd40234b7 100644 --- a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp +++ b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp @@ -48,7 +48,7 @@ class spell_mark_of_malice : public SpellScriptLoader if (aurEff->GetBase()->GetCharges() > 1) return; - GetTarget()->CastSpell(GetTarget(), SPELL_MARK_OF_MALICE_TRIGGERED, true); + GetTarget()->CastSpell(GetTarget(), SPELL_MARK_OF_MALICE_TRIGGERED, true, nullptr, aurEff); } void Register() override 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/boss_doomlord_kazzak.cpp b/src/server/scripts/Outland/boss_doomlord_kazzak.cpp index f305c1e47be..daea6d24a4a 100644 --- a/src/server/scripts/Outland/boss_doomlord_kazzak.cpp +++ b/src/server/scripts/Outland/boss_doomlord_kazzak.cpp @@ -239,14 +239,14 @@ class spell_twisted_reflection : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); DamageInfo* damageInfo = eventInfo.GetDamageInfo(); if (!damageInfo || !damageInfo->GetDamage()) return; - eventInfo.GetActionTarget()->CastSpell(eventInfo.GetActor(), SPELL_TWISTED_REFLECTION_HEAL, true); + eventInfo.GetActionTarget()->CastSpell(eventInfo.GetActor(), SPELL_TWISTED_REFLECTION_HEAL, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp index d4faeef73b9..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; }; diff --git a/src/server/scripts/Pet/pet_hunter.cpp b/src/server/scripts/Pet/pet_hunter.cpp index a155dbc36c4..7092300af4d 100644 --- a/src/server/scripts/Pet/pet_hunter.cpp +++ b/src/server/scripts/Pet/pet_hunter.cpp @@ -42,6 +42,10 @@ enum PetSpellsMisc SPELL_PET_GUARD_DOG_HAPPINESS = 54445, SPELL_PET_SILVERBACK_RANK_1 = 62800, SPELL_PET_SILVERBACK_RANK_2 = 62801, + + SPELL_PET_SWOOP = 52825, + SPELL_PET_CHARGE = 61685, + PET_ICON_ID_GROWL = 201, PET_ICON_ID_CLAW = 262, PET_ICON_ID_BITE = 1680, @@ -162,10 +166,29 @@ class spell_pet_charge : public SpellScriptLoader { PrepareAuraScript(spell_pet_charge_AuraScript); - void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_PET_SWOOP) || + !sSpellMgr->GetSpellInfo(SPELL_PET_CHARGE)) + return false; + return true; + } + + void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) { // Prevent console log PreventDefaultAction(); + + // Remove +% AP aura + Unit* pet = eventInfo.GetActor(); + Aura* aura = pet->GetAura(SPELL_PET_SWOOP, pet->GetGUID()); + if (!aura) + aura = pet->GetAura(SPELL_PET_CHARGE, pet->GetGUID()); + + if (!aura) + return; + + aura->DropCharge(AURA_REMOVE_BY_EXPIRE); } void Register() override @@ -213,7 +236,7 @@ class spell_pet_guard_dog : public SpellScriptLoader PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); - caster->CastSpell((Unit*)nullptr, SPELL_PET_GUARD_DOG_HAPPINESS, true); + caster->CastSpell((Unit*)nullptr, SPELL_PET_GUARD_DOG_HAPPINESS, true, nullptr, aurEff); float addThreat = CalculatePct(ASSERT_NOTNULL(eventInfo.GetSpellInfo())->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount()); eventInfo.GetProcTarget()->AddThreat(caster, addThreat); @@ -260,14 +283,14 @@ class spell_pet_silverback : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { static uint32 const triggerSpell[2] = { SPELL_PET_SILVERBACK_RANK_1, SPELL_PET_SILVERBACK_RANK_2 }; PreventDefaultAction(); uint32 spellId = triggerSpell[GetSpellInfo()->GetRank() - 1]; - eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 7cce7e4655e..13eec799493 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -600,7 +600,7 @@ class spell_dk_butchery : public SpellScriptLoader void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastCustomSpell(SPELL_DK_BUTCHERY_RUNIC_POWER, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), (Unit*)nullptr, true); + eventInfo.GetActor()->CastCustomSpell(SPELL_DK_BUTCHERY_RUNIC_POWER, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -1249,10 +1249,10 @@ class spell_dk_glyph_of_scourge_strike : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT, true); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT, true, nullptr, aurEff); } void Register() override @@ -1588,10 +1588,10 @@ class spell_dk_pvp_4p_bonus : public SpellScriptLoader return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_SNARE))) != 0; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActionTarget()->CastSpell((Unit*)nullptr, SPELL_DK_RUNIC_RETURN, true); + eventInfo.GetActionTarget()->CastSpell((Unit*)nullptr, SPELL_DK_RUNIC_RETURN, true, nullptr, aurEff); } void Register() override @@ -1624,10 +1624,10 @@ class spell_dk_mark_of_blood : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_MARK_OF_BLOOD_HEAL, true); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_MARK_OF_BLOOD_HEAL, true, nullptr, aurEff); } void Register() override @@ -1668,7 +1668,7 @@ class spell_dk_necrosis : public SpellScriptLoader return; int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount()); - eventInfo.GetActor()->CastCustomSpell(SPELL_DK_NECROSIS_DAMAGE, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true); + eventInfo.GetActor()->CastCustomSpell(SPELL_DK_NECROSIS_DAMAGE, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, nullptr, aurEff); } void Register() override @@ -2327,7 +2327,7 @@ class spell_dk_sudden_doom : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); @@ -2347,7 +2347,7 @@ class spell_dk_sudden_doom : public SpellScriptLoader if (!spellId) return; - caster->CastSpell(eventInfo.GetProcTarget(), spellId, true); + caster->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); } void Register() override @@ -2424,7 +2424,7 @@ class spell_dk_threat_of_thassarian : public SpellScriptLoader return; spellId = sSpellMgr->GetSpellWithRank(spellId, spellInfo->GetRank()); - caster->CastSpell(eventInfo.GetProcTarget(), spellId, true); + caster->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); } void Register() override @@ -2478,7 +2478,7 @@ class spell_dk_unholy_blight : public SpellScriptLoader // Add remaining ticks to healing done amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_DK_UNHOLY_BLIGHT_DAMAGE, SPELL_AURA_PERIODIC_DAMAGE); - caster->CastCustomSpell(SPELL_DK_UNHOLY_BLIGHT_DAMAGE, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_DK_UNHOLY_BLIGHT_DAMAGE, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -2541,7 +2541,7 @@ class spell_dk_vendetta : public SpellScriptLoader PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); int32 amount = caster->CountPctFromMaxHealth(aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_DK_VENDETTA_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_DK_VENDETTA_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -2586,7 +2586,7 @@ class spell_dk_wandering_plague : public SpellScriptLoader return; int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_DK_WANDERING_PLAGUE_DAMAGE, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_DK_WANDERING_PLAGUE_DAMAGE, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index 49baab54bf0..56624346772 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -486,10 +486,10 @@ class spell_dru_glyph_of_barkskin : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_DRUID_BARKSKIN_01, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_DRUID_BARKSKIN_01, true, nullptr, aurEff); } void Register() override @@ -530,7 +530,7 @@ class spell_dru_glyph_of_innervate : public SpellScriptLoader int32 amount = CalculatePct(static_cast<int32>(caster->GetCreatePowers(POWER_MANA)), aurEff->GetAmount()); amount /= spellInfo->GetMaxTicks(); - caster->CastCustomSpell(SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -567,10 +567,10 @@ class spell_dru_glyph_of_rake : public SpellScriptLoader return eventInfo.GetProcTarget()->GetTypeId() == TYPEID_UNIT; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED, true); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED, true, nullptr, aurEff); } void Register() override @@ -616,7 +616,7 @@ class spell_dru_glyph_of_rejuvenation : public SpellScriptLoader return; int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount()); - eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true); + eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, nullptr, aurEff); } void Register() override @@ -762,10 +762,10 @@ class spell_dru_glyph_of_starfire_dummy : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT, true); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT, true, nullptr, aurEff); } void Register() override @@ -905,7 +905,7 @@ class spell_dru_leader_of_the_pack : public SpellScriptLoader return; int32 amount = caster->CountPctFromMaxHealth(aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_DRUID_IMP_LEADER_OF_THE_PACK_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_DRUID_IMP_LEADER_OF_THE_PACK_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); // Because of how proc system works, we can't store proc cd on db, it would be applied to entire aura // so aura could only proc once per 6 seconds, independently of caster @@ -915,12 +915,11 @@ class spell_dru_leader_of_the_pack : public SpellScriptLoader if (aurEff->GetCasterGUID() != caster->GetGUID()) return; - AuraEffect const* impLotpMana = caster->GetAuraEffectOfRankedSpell(SPELL_DRUID_IMP_LEADER_OF_THE_PACK_R1, EFFECT_1, aurEff->GetCasterGUID()); - if (!impLotpMana) - return; + AuraEffect const* impLotpMana = caster->GetAuraEffectOfRankedSpell(SPELL_DRUID_IMP_LEADER_OF_THE_PACK_R1, EFFECT_0, aurEff->GetCasterGUID()); + ASSERT(impLotpMana); - int32 manaAmount = CalculatePct(static_cast<int32>(caster->GetMaxPower(POWER_MANA)), impLotpMana->GetAmount()); - caster->CastCustomSpell(SPELL_DRUID_IMP_LEADER_OF_THE_PACK_MANA, SPELLVALUE_BASE_POINT0, manaAmount, (Unit*)nullptr, true); + int32 manaAmount = CalculatePct(static_cast<int32>(caster->GetMaxPower(POWER_MANA)), impLotpMana->GetSpellInfo()->Effects[EFFECT_1].CalcValue()); + caster->CastCustomSpell(SPELL_DRUID_IMP_LEADER_OF_THE_PACK_MANA, SPELLVALUE_BASE_POINT0, manaAmount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -1043,7 +1042,7 @@ class spell_dru_living_seed : public SpellScriptLoader return; int32 amount = CalculatePct(healInfo->GetHeal(), aurEff->GetAmount()); - GetTarget()->CastCustomSpell(SPELL_DRUID_LIVING_SEED_PROC, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, NULL, aurEff); + GetTarget()->CastCustomSpell(SPELL_DRUID_LIVING_SEED_PROC, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, nullptr, aurEff); } void Register() override @@ -1162,11 +1161,11 @@ class spell_dru_omen_of_clarity : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) { Unit* target = GetTarget(); if (target->HasAura(SPELL_DRUID_BALANCE_T10_BONUS)) - target->CastSpell((Unit*)nullptr, SPELL_DRUID_BALANCE_T10_BONUS_PROC, true, nullptr); + target->CastSpell((Unit*)nullptr, SPELL_DRUID_BALANCE_T10_BONUS_PROC, true, nullptr, aurEff); } void Register() override @@ -1335,7 +1334,7 @@ class spell_dru_revitalize : public SpellScriptLoader return; } - eventInfo.GetActor()->CastSpell(target, spellId, true); + eventInfo.GetActor()->CastSpell(target, spellId, true, nullptr, aurEff); } void Register() override @@ -1420,7 +1419,7 @@ class spell_dru_savage_defense : public SpellScriptLoader PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); int32 amount = static_cast<int32>(CalculatePct(caster->GetTotalAttackPowerValue(BASE_ATTACK), aurEff->GetAmount())); - caster->CastCustomSpell(GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -1613,7 +1612,7 @@ class spell_dru_survival_instincts : public SpellScriptLoader { Unit* target = GetTarget(); int32 bp0 = target->CountPctFromMaxHealth(aurEff->GetAmount()); - target->CastCustomSpell(target, SPELL_DRUID_SURVIVAL_INSTINCTS, &bp0, NULL, NULL, true); + target->CastCustomSpell(target, SPELL_DRUID_SURVIVAL_INSTINCTS, &bp0, nullptr, nullptr, true, nullptr, aurEff); } void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) @@ -1654,7 +1653,7 @@ class spell_dru_swift_flight_passive : public SpellScriptLoader return GetCaster()->GetTypeId() == TYPEID_PLAYER; } - void CalculateAmount(AuraEffect const* /*aurEff*/, int32 & amount, bool & /*canBeRecalculated*/) + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool & /*canBeRecalculated*/) { if (Player* caster = GetCaster()->ToPlayer()) if (caster->Has310Flyer(false)) @@ -1756,7 +1755,7 @@ class spell_dru_t3_2p_bonus : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* target = eventInfo.GetProcTarget(); @@ -1777,7 +1776,7 @@ class spell_dru_t3_2p_bonus : public SpellScriptLoader return; } - eventInfo.GetActor()->CastSpell(target, spellId, true); + eventInfo.GetActor()->CastSpell(target, spellId, true, nullptr, aurEff); } void Register() override @@ -1810,10 +1809,10 @@ class spell_dru_t3_6p_bonus : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_BLESSING_OF_THE_CLAW, true); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_BLESSING_OF_THE_CLAW, true, nullptr, aurEff); } void Register() override @@ -1854,7 +1853,7 @@ class spell_dru_t3_8p_bonus : public SpellScriptLoader Unit* caster = eventInfo.GetActor(); int32 amount = CalculatePct(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_DRUID_EXHILARATE, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_DRUID_EXHILARATE, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -1887,10 +1886,10 @@ class spell_dru_t4_2p_bonus : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_DRUID_INFUSION, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_DRUID_INFUSION, true, nullptr, aurEff); } void Register() override @@ -1924,7 +1923,7 @@ class spell_dru_item_t6_trinket : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); @@ -1956,7 +1955,7 @@ class spell_dru_item_t6_trinket : public SpellScriptLoader return; if (roll_chance_i(chance)) - eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); } void Register() override @@ -2076,7 +2075,7 @@ class spell_dru_t10_balance_4p_bonus : public SpellScriptLoader // Add remaining ticks to damage done amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_DRUID_LANGUISH, SPELL_AURA_PERIODIC_DAMAGE); - caster->CastCustomSpell(SPELL_DRUID_LANGUISH, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_DRUID_LANGUISH, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -2180,12 +2179,12 @@ class spell_dru_t10_restoration_4p_bonus_dummy : public SpellScriptLoader return caster->GetGroup() || caster != eventInfo.GetProcTarget(); } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); int32 amount = static_cast<int32>(eventInfo.GetHealInfo()->GetHeal()); - eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_REJUVENATION_T10_PROC, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_REJUVENATION_T10_PROC, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index f1eaf45770e..d0fcd1080bb 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -3570,7 +3570,7 @@ class spell_gen_vampiric_touch : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); DamageInfo* damageInfo = eventInfo.GetDamageInfo(); @@ -3579,7 +3579,7 @@ class spell_gen_vampiric_touch : public SpellScriptLoader Unit* caster = eventInfo.GetActor(); int32 bp = damageInfo->GetDamage() / 2; - caster->CastCustomSpell(SPELL_VAMPIRIC_TOUCH_HEAL, SPELLVALUE_BASE_POINT0, bp, caster, true); + caster->CastCustomSpell(SPELL_VAMPIRIC_TOUCH_HEAL, SPELLVALUE_BASE_POINT0, bp, caster, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index 2eba605f8b3..b341c5799ed 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -225,7 +225,7 @@ class spell_hun_chimera_shot : public SpellScriptLoader // first, calculate damage of basic tick (C&P from AuraEffect::HandlePeriodicDamageAurasTick) basePoint = (aurEff->GetAmount() + aurEff->GetBonusAmount()) * aurEff->GetDonePct(); if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod<SPELLMOD_DOT>(aurEff->GetSpellInfo()->Id, basePoint); + modOwner->ApplySpellMod<SPELLMOD_DOT>(aurEff->GetId(), basePoint); basePoint = unitTarget->SpellDamageBonusTaken(caster, aurEff->GetSpellInfo(), basePoint, DOT, aura->GetStackAmount()); // then, multiply to get damage potential @@ -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 { @@ -385,10 +449,10 @@ class spell_hun_glyph_of_mend_pet : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + 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, nullptr, aurEff); } void Register() override @@ -420,10 +484,10 @@ class spell_hun_hunting_party : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true, nullptr, aurEff); } void Register() override @@ -681,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); } @@ -1022,7 +1114,7 @@ class spell_hun_rapid_recuperation_trigger : public SpellScriptLoader } } - void HandleRapidKillingProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleRapidKillingProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { static uint32 const triggerSpells[2] = { SPELL_HUNTER_RAPID_RECUPERATION_MANA_R1, SPELL_HUNTER_RAPID_RECUPERATION_MANA_R2 }; @@ -1035,7 +1127,7 @@ class spell_hun_rapid_recuperation_trigger : public SpellScriptLoader uint8 rank = GetSpellInfo()->GetRank(); uint32 spellId = triggerSpells[rank - 1]; - eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); } void Register() override @@ -1368,7 +1460,7 @@ class spell_hun_thrill_of_the_hunt : public SpellScriptLoader if (!amount) return; - caster->CastCustomSpell(SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -1449,7 +1541,7 @@ class spell_hun_viper_attack_speed : public SpellScriptLoader void OnApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { if (GetTarget()->HasAura(SPELL_HUNTER_ASPECT_OF_THE_VIPER)) - GetTarget()->CastSpell(GetTarget(), SPELL_HUNTER_VICIOUS_VIPER, true, NULL, aurEff); + GetTarget()->CastSpell(GetTarget(), SPELL_HUNTER_VICIOUS_VIPER, true, nullptr, aurEff); } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) @@ -1476,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(); diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index b45df66e0ac..9ef5c5d0b4d 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -148,7 +148,7 @@ class spell_item_alchemists_stone : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); @@ -172,7 +172,7 @@ class spell_item_alchemists_stone : public SpellScriptLoader } int32 amount = CalculatePct(spellInfo->Effects[i].CalcValue(caster), 40); - caster->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } } @@ -220,7 +220,7 @@ class spell_item_anger_capacitor : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); @@ -237,7 +237,7 @@ class spell_item_anger_capacitor : public SpellScriptLoader if (player->GetWeaponForAttack(OFF_ATTACK, true) && urand(0, 1)) spellId = SPELL_MANIFEST_ANGER_OFF_HAND; - caster->CastSpell(target, spellId, true); + caster->CastSpell(target, spellId, true, nullptr, aurEff); } void Register() override @@ -358,7 +358,7 @@ class spell_item_aura_of_madness : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { static std::vector<uint32> const triggeredSpells[MAX_CLASSES] = { @@ -391,7 +391,7 @@ class spell_item_aura_of_madness : public SpellScriptLoader PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); uint32 spellId = Trinity::Containers::SelectRandomContainerElement(triggeredSpells[caster->getClass()]); - caster->CastSpell(caster, spellId, true); + caster->CastSpell(caster, spellId, true, nullptr, aurEff); if (roll_chance_i(10)) caster->Unit::Say(SAY_MADNESS); @@ -427,10 +427,10 @@ class spell_item_dementia : public SpellScriptLoader return true; } - void HandlePeriodicDummy(AuraEffect const* /*aurEff*/) + void HandlePeriodicDummy(AuraEffect const* aurEff) { PreventDefaultAction(); - GetTarget()->CastSpell(GetTarget(), RAND(SPELL_DEMENTIA_POS, SPELL_DEMENTIA_NEG), true); + GetTarget()->CastSpell(GetTarget(), RAND(SPELL_DEMENTIA_POS, SPELL_DEMENTIA_NEG), true, nullptr, aurEff); } void Register() override @@ -490,7 +490,7 @@ class spell_item_blessing_of_ancient_kings : public SpellScriptLoader protEff->GetBase()->RefreshDuration(); } else - GetTarget()->CastCustomSpell(SPELL_PROTECTION_OF_ANCIENT_KINGS, SPELLVALUE_BASE_POINT0, absorb, eventInfo.GetProcTarget(), true, NULL, aurEff); + GetTarget()->CastCustomSpell(SPELL_PROTECTION_OF_ANCIENT_KINGS, SPELLVALUE_BASE_POINT0, absorb, eventInfo.GetProcTarget(), true, nullptr, aurEff); } void Register() override @@ -616,7 +616,7 @@ class spell_item_deathbringers_will : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { static std::vector<uint32> const triggeredSpells[MAX_CLASSES] = { @@ -648,12 +648,12 @@ class spell_item_deathbringers_will : public SpellScriptLoader PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); - auto const& randomSpells = triggeredSpells[caster->getClass()]; + std::vector<uint32> const& randomSpells = triggeredSpells[caster->getClass()]; if (randomSpells.empty()) return; uint32 spellId = Trinity::Containers::SelectRandomContainerElement(randomSpells); - caster->CastSpell(caster, spellId, true); + caster->CastSpell(caster, spellId, true, nullptr, aurEff); } void Register() override @@ -1083,7 +1083,7 @@ class spell_item_frozen_shadoweave : public SpellScriptLoader int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount()); Unit* caster = eventInfo.GetActor(); - caster->CastCustomSpell(SPELL_SHADOWMEND, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_SHADOWMEND, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -1128,9 +1128,9 @@ class spell_item_gnomish_death_ray : public SpellScriptLoader if (Unit* target = GetHitUnit()) { if (urand(0, 99) < 15) - caster->CastSpell(caster, SPELL_GNOMISH_DEATH_RAY_SELF, true, NULL); // failure + caster->CastSpell(caster, SPELL_GNOMISH_DEATH_RAY_SELF, true); // failure else - caster->CastSpell(target, SPELL_GNOMISH_DEATH_RAY_TARGET, true, NULL); + caster->CastSpell(target, SPELL_GNOMISH_DEATH_RAY_TARGET, true); } } @@ -1169,10 +1169,10 @@ class spell_item_healing_touch_refund : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_HEALING_TOUCH_MANA, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_HEALING_TOUCH_MANA, true, nullptr, aurEff); } void Register() override @@ -1226,7 +1226,7 @@ class spell_item_heartpierce : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); @@ -1243,6 +1243,7 @@ class spell_item_heartpierce : public SpellScriptLoader case POWER_RAGE: spellId = Rage; break; + // Death Knights can't use daggers, but oh well case POWER_RUNIC_POWER: spellId = RunicPower; break; @@ -1250,7 +1251,7 @@ class spell_item_heartpierce : public SpellScriptLoader return; } - caster->CastSpell((Unit*)nullptr, spellId, true); + caster->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); } void Register() override @@ -1380,14 +1381,14 @@ class spell_item_mark_of_conquest : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { if (eventInfo.GetTypeMask() & (PROC_FLAG_DONE_RANGED_AUTO_ATTACK | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS)) { // in that case, do not cast heal spell PreventDefaultAction(); // but mana instead - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MARK_OF_CONQUEST_ENERGIZE, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MARK_OF_CONQUEST_ENERGIZE, true, nullptr, aurEff); } } @@ -1546,7 +1547,7 @@ class spell_item_net_o_matic : public SpellScriptLoader else if (roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown) spellId = SPELL_NET_O_MATIC_TRIGGERED2; - GetCaster()->CastSpell(target, spellId, true, NULL); + GetCaster()->CastSpell(target, spellId, true, nullptr); } } @@ -1602,7 +1603,7 @@ class spell_item_noggenfogger_elixir : public SpellScriptLoader case 2: spellId = SPELL_NOGGENFOGGER_ELIXIR_TRIGGERED2; break; } - caster->CastSpell(caster, spellId, true, NULL); + caster->CastSpell(caster, spellId, true, nullptr); } void Register() override @@ -1734,7 +1735,7 @@ class spell_item_pet_healing : public SpellScriptLoader int32 bp = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount()); Unit* caster = eventInfo.GetActor(); - caster->CastCustomSpell(SPELL_HEALTH_LINK, SPELLVALUE_BASE_POINT0, bp, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_HEALTH_LINK, SPELLVALUE_BASE_POINT0, bp, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -2206,7 +2207,7 @@ class spell_item_swift_hand_justice_dummy : public SpellScriptLoader Unit* caster = eventInfo.GetActor(); int32 amount = caster->CountPctFromMaxHealth(aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_SWIFT_HAND_OF_JUSTICE_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_SWIFT_HAND_OF_JUSTICE_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -2244,10 +2245,10 @@ class spell_item_totem_of_flowing_water : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_LESSER_HEALING_WAVE_MANA, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_LESSER_HEALING_WAVE_MANA, true, nullptr, aurEff); } void Register() override @@ -3741,17 +3742,17 @@ class spell_item_shard_of_the_scale : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); Unit* target = eventInfo.GetProcTarget(); if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS) - caster->CastSpell(target, HealProc, true); + caster->CastSpell(target, HealProc, true, nullptr, aurEff); if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG) - caster->CastSpell(target, DamageProc, true); + caster->CastSpell(target, DamageProc, true, nullptr, aurEff); } void Register() override @@ -3887,7 +3888,7 @@ class spell_item_sunwell_neck : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Player* player = eventInfo.GetActor()->ToPlayer(); @@ -3895,10 +3896,10 @@ class spell_item_sunwell_neck : public SpellScriptLoader // Aggression checks are in the spell system... just cast and forget if (player->GetReputationRank(FACTION_ALDOR) == REP_EXALTED) - player->CastSpell(target, Aldors, true); + player->CastSpell(target, Aldors, true, nullptr, aurEff); if (player->GetReputationRank(FACTION_SCRYERS) == REP_EXALTED) - player->CastSpell(target, Scryers, true); + player->CastSpell(target, Scryers, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index 8c37b3ac506..5c496024599 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -114,14 +114,14 @@ class spell_mage_arcane_potency : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { static uint32 const triggerSpell[2] = { SPELL_MAGE_ARCANE_POTENCY_RANK_1, SPELL_MAGE_ARCANE_POTENCY_RANK_2 }; PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); uint32 spellId = triggerSpell[GetSpellInfo()->GetRank() - 1]; - caster->CastSpell(caster, spellId, true); + caster->CastSpell(caster, spellId, true, nullptr, aurEff); } void Register() override @@ -383,11 +383,11 @@ class spell_mage_imp_blizzard : public SpellScriptLoader return true; } - void HandleChill(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleChill(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); uint32 triggerSpellId = sSpellMgr->GetSpellWithRank(SPELL_MAGE_CHILLED, GetSpellInfo()->GetRank()); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), triggerSpellId, true); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), triggerSpellId, true, nullptr, aurEff); } void Register() override @@ -420,10 +420,10 @@ class spell_mage_imp_mana_gems : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MAGE_MANA_SURGE, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MAGE_MANA_SURGE, true, nullptr, aurEff); } void Register() override @@ -836,7 +836,7 @@ class spell_mage_hot_streak : public SpellScriptLoader return; Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, SPELL_MAGE_HOT_STREAK_PROC, true); + caster->CastSpell(caster, SPELL_MAGE_HOT_STREAK_PROC, true, nullptr, aurEff); } // reset counter @@ -1032,7 +1032,7 @@ class spell_mage_magic_absorption : public SpellScriptLoader PreventDefaultAction(); Unit* caster = eventInfo.GetActionTarget(); int32 bp = CalculatePct(static_cast<int32>(caster->GetMaxPower(POWER_MANA)), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_MAGE_MAGIC_ABSORPTION_MANA, SPELLVALUE_BASE_POINT0, bp, caster, true); + caster->CastCustomSpell(SPELL_MAGE_MAGIC_ABSORPTION_MANA, SPELLVALUE_BASE_POINT0, bp, caster, true, nullptr, aurEff); } void Register() override @@ -1080,10 +1080,10 @@ class spell_mage_mana_shield : public SpellScriptLoader } } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { Unit* caster = eventInfo.GetActionTarget(); - caster->CastSpell(caster, SPELL_MAGE_ARCANE_SURGE, true); + caster->CastSpell(caster, SPELL_MAGE_ARCANE_SURGE, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index 20665034298..693990edd0a 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -156,9 +156,16 @@ class spell_pal_ardent_defender : public SpellScriptLoader enum Spell { - PAL_SPELL_ARDENT_DEFENDER_HEAL = 66235, + PAL_SPELL_ARDENT_DEFENDER_HEAL = 66235 }; + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(PAL_SPELL_ARDENT_DEFENDER_HEAL)) + return false; + return true; + } + bool Load() override { healPct = GetSpellInfo()->Effects[EFFECT_1].CalcValue(); @@ -192,7 +199,7 @@ class spell_pal_ardent_defender : public SpellScriptLoader : float(defenseSkillValue) / float(reqDefForMaxHeal); int32 healAmount = int32(victim->CountPctFromMaxHealth(uint32(healPct * pctFromDefense))); - victim->CastCustomSpell(victim, PAL_SPELL_ARDENT_DEFENDER_HEAL, &healAmount, NULL, NULL, true, NULL, aurEff); + victim->CastCustomSpell(PAL_SPELL_ARDENT_DEFENDER_HEAL, SPELLVALUE_BASE_POINT0, healAmount, victim, true, nullptr, aurEff); victim->GetSpellHistory()->AddCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL, 0, std::chrono::minutes(2)); } else if (remainingHealth < int32(allowedHealth)) @@ -824,7 +831,7 @@ class spell_pal_glyph_of_holy_light_dummy : public SpellScriptLoader Unit* target = eventInfo.GetProcTarget(); int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -976,12 +983,12 @@ class spell_pal_heart_of_the_crusader : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_PALADIN_HEART_OF_THE_CRUSADER_EFF_R1, GetSpellInfo()->GetRank()); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); } void Register() override @@ -1385,7 +1392,7 @@ class spell_pal_item_t6_trinket : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); @@ -1411,7 +1418,7 @@ class spell_pal_item_t6_trinket : public SpellScriptLoader return; if (roll_chance_i(chance)) - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); } void Register() override @@ -1542,7 +1549,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 @@ -1586,7 +1593,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 @@ -1655,13 +1662,13 @@ class spell_pal_judgements_of_the_wise : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); - caster->CastSpell((Unit*)nullptr, SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA, true); - caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true); + caster->CastSpell((Unit*)nullptr, SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA, true, nullptr, aurEff); + caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true, nullptr, aurEff); } void Register() override @@ -1782,7 +1789,7 @@ class spell_pal_light_s_beacon : public SpellScriptLoader /// @todo: caster must be the healed unit to perform distance checks correctly /// but that will break animation on clientside /// caster in spell packets must be the healing unit - eventInfo.GetActor()->CastCustomSpell(healSpellId, SPELLVALUE_BASE_POINT0, heal, beaconTarget, true); + eventInfo.GetActor()->CastCustomSpell(healSpellId, SPELLVALUE_BASE_POINT0, heal, beaconTarget, true, nullptr, aurEff); } void Register() override @@ -1896,7 +1903,7 @@ class spell_pal_righteous_vengeance : public SpellScriptLoader // Add remaining ticks to damage done amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_PALADIN_RIGHTEOUS_VENGEANCE_DAMAGE, SPELL_AURA_PERIODIC_DAMAGE); - caster->CastCustomSpell(SPELL_PALADIN_RIGHTEOUS_VENGEANCE_DAMAGE, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_PALADIN_RIGHTEOUS_VENGEANCE_DAMAGE, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -1990,7 +1997,7 @@ class spell_pal_sacred_shield_dummy : public SpellScriptLoader cooldown = Seconds(bonus->GetAmount()); _cooldownEnd = now + cooldown; - caster->CastSpell(eventInfo.GetActionTarget(), SPELL_PALADIN_SACRED_SHIELD_TRIGGER, true); + caster->CastSpell(eventInfo.GetActionTarget(), SPELL_PALADIN_SACRED_SHIELD_TRIGGER, true, nullptr, aurEff); } void Register() override @@ -2092,7 +2099,7 @@ class spell_pal_seal_of_vengeance : public SpellScriptLoader 5 33% 38% */ - void HandleApplyDoT(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleApplyDoT(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); @@ -2100,22 +2107,23 @@ class spell_pal_seal_of_vengeance : public SpellScriptLoader return; // don't cast triggered, spell already has SPELL_ATTR4_CAN_CAST_WHILE_CASTING attr - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), DoTSpell, false); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), DoTSpell, TRIGGERED_DONT_RESET_PERIODIC_TIMER, nullptr, aurEff); } - void HandleSeal(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleSeal(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); Unit* target = eventInfo.GetProcTarget(); - AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PALADIN, 0x00000000, 0x00000800, 0x00000000, caster->GetGUID()); - if (!aurEff) + // get current aura on target, if any + AuraEffect const* sealDot = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PALADIN, 0x00000000, 0x00000800, 0x00000000, caster->GetGUID()); + if (!sealDot) return; - uint8 stacks = aurEff->GetBase()->GetStackAmount(); - uint8 maxStacks = aurEff->GetSpellInfo()->StackAmount; + uint8 const stacks = sealDot->GetBase()->GetStackAmount(); + uint8 const maxStacks = sealDot->GetSpellInfo()->StackAmount; if (stacks < maxStacks && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS)) return; @@ -2125,7 +2133,7 @@ class spell_pal_seal_of_vengeance : public SpellScriptLoader amount *= stacks; amount /= maxStacks; - caster->CastCustomSpell(DamageSpell, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(DamageSpell, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -2209,7 +2217,7 @@ class spell_pal_spiritual_attunement : public SpellScriptLoader HealInfo* healInfo = eventInfo.GetHealInfo(); int32 amount = CalculatePct(static_cast<int32>(healInfo->GetEffectiveHeal()), aurEff->GetAmount()); - eventInfo.GetActionTarget()->CastCustomSpell(SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + eventInfo.GetActionTarget()->CastCustomSpell(SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -2256,10 +2264,10 @@ class spell_pal_sheath_of_light : public SpellScriptLoader SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_PALADIN_SHEATH_OF_LIGHT_HEAL); int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount()); amount /= spellInfo->GetMaxTicks(); - // Add remaining ticks to damage done + // Add remaining ticks to healing done amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_PALADIN_SHEATH_OF_LIGHT_HEAL, SPELL_AURA_PERIODIC_HEAL); - caster->CastCustomSpell(SPELL_PALADIN_SHEATH_OF_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_PALADIN_SHEATH_OF_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -2294,7 +2302,7 @@ class spell_pal_t3_6p_bonus : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); @@ -2325,7 +2333,7 @@ class spell_pal_t3_6p_bonus : public SpellScriptLoader return; } - caster->CastSpell(target, spellId, true); + caster->CastSpell(target, spellId, true, nullptr, aurEff); } void Register() override @@ -2371,10 +2379,10 @@ class spell_pal_t8_2p_bonus : public SpellScriptLoader SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_PALADIN_HOLY_MENDING); int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount()); amount /= spellInfo->GetMaxTicks(); - // Add remaining ticks to damage done + // Add remaining ticks to healing done amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_PALADIN_HOLY_MENDING, SPELL_AURA_PERIODIC_HEAL); - caster->CastCustomSpell(SPELL_PALADIN_HOLY_MENDING, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_PALADIN_HOLY_MENDING, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index 16bf769a9ae..8a4bdeedccc 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -120,7 +120,7 @@ class spell_pri_aq_3p_bonus : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); @@ -132,7 +132,7 @@ class spell_pri_aq_3p_bonus : public SpellScriptLoader return; int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), 10); - caster->CastCustomSpell(SPELL_PRIEST_ORACULAR_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true); + caster->CastCustomSpell(SPELL_PRIEST_ORACULAR_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true, nullptr, aurEff); } void Register() override @@ -236,7 +236,7 @@ class spell_pri_body_and_soul : public SpellScriptLoader return; if (roll_chance_i(aurEff->GetAmount())) - caster->CastSpell(caster, SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER, true); + caster->CastSpell(caster, SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER, true, nullptr, aurEff); } void Register() override @@ -412,7 +412,7 @@ class spell_pri_glyph_of_dispel_magic : public SpellScriptLoader Unit* target = eventInfo.GetProcTarget(); int32 amount = static_cast<int32>(target->CountPctFromMaxHealth(aurEff->GetAmount())); - caster->CastCustomSpell(SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -660,15 +660,15 @@ class spell_pri_item_t6_trinket : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); if (eventInfo.GetSpellTypeMask() & PROC_SPELL_TYPE_HEAL) - caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_BLESSING, true); + caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_BLESSING, true, nullptr, aurEff); if (eventInfo.GetSpellTypeMask() & PROC_SPELL_TYPE_DAMAGE) - caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_WRATH, true); + caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_WRATH, true, nullptr, aurEff); } void Register() override @@ -1091,17 +1091,22 @@ class spell_pri_renew : public SpellScriptLoader void HandleApplyEffect(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { - if (Unit* caster = GetCaster()) + Unit* caster = GetCaster(); + if (!caster) + return; + + // Empowered Renew + if (AuraEffect const* empoweredRenewAurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, PRIEST_ICON_ID_EMPOWERED_RENEW_TALENT, EFFECT_1)) { - // Empowered Renew - if (AuraEffect const* empoweredRenewAurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, PRIEST_ICON_ID_EMPOWERED_RENEW_TALENT, EFFECT_1)) - { - uint32 heal = caster->SpellHealingBonusDone(GetTarget(), GetSpellInfo(), GetEffect(EFFECT_0)->GetAmount(), DOT); - heal = GetTarget()->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT); + int32 heal = (aurEff->GetAmount() + aurEff->GetBonusAmount()) * aurEff->GetDonePct(); + if (Player* modOwner = caster->GetSpellModOwner()) + modOwner->ApplySpellMod<SPELLMOD_DOT>(GetId(), heal); + heal = GetTarget()->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT); - int32 basepoints0 = empoweredRenewAurEff->GetAmount() * GetEffect(EFFECT_0)->GetTotalTicks() * int32(heal) / 100; - caster->CastCustomSpell(GetTarget(), SPELL_PRIEST_EMPOWERED_RENEW, &basepoints0, NULL, NULL, true, NULL, aurEff); - } + heal *= GetSpellInfo()->GetMaxTicks(); + + int32 basepoints0 = CalculatePct(heal, empoweredRenewAurEff->GetAmount()); + caster->CastCustomSpell(SPELL_PRIEST_EMPOWERED_RENEW, SPELLVALUE_BASE_POINT0, basepoints0, GetTarget(), true, nullptr, aurEff); } } @@ -1147,11 +1152,11 @@ class spell_pri_shadowfiend_death : public SpellScriptLoader return shadowfiend->HealthBelowPctDamaged(1, damageInfo->GetDamage()); } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActionTarget()->GetOwner(); - caster->CastSpell(caster, SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA, true); + caster->CastSpell(caster, SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA, true, nullptr, aurEff); } void Register() override @@ -1227,7 +1232,7 @@ class spell_pri_vampiric_embrace : public SpellScriptLoader int32 selfHeal = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount()); int32 partyHeal = selfHeal / 5; Unit* caster = eventInfo.GetActor(); - caster->CastCustomSpell((Unit*)nullptr, SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL, &partyHeal, &selfHeal, nullptr, true); + caster->CastCustomSpell((Unit*)nullptr, SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL, &partyHeal, &selfHeal, nullptr, true, nullptr, aurEff); } void Register() override @@ -1275,16 +1280,16 @@ class spell_pri_vampiric_touch : public SpellScriptLoader { int32 damage = aurEff->GetAmount() * 8; // backfire damage - caster->CastCustomSpell(target, SPELL_PRIEST_VAMPIRIC_TOUCH_DISPEL, &damage, NULL, NULL, true, NULL, aurEff); + caster->CastCustomSpell(SPELL_PRIEST_VAMPIRIC_TOUCH_DISPEL, SPELLVALUE_BASE_POINT0, damage, target, true, nullptr, aurEff); } } } } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true, nullptr, aurEff); } void Register() override @@ -1319,10 +1324,10 @@ class spell_pri_t3_4p_bonus : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_PRIEST_ARMOR_OF_FAITH, true); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_PRIEST_ARMOR_OF_FAITH, true, nullptr, aurEff); } void Register() override @@ -1418,7 +1423,7 @@ class spell_pri_t10_heal_2p_bonus : public SpellScriptLoader Unit* target = eventInfo.GetProcTarget(); amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_PRIEST_BLESSED_HEALING, SPELL_AURA_PERIODIC_HEAL); - caster->CastCustomSpell(SPELL_PRIEST_BLESSED_HEALING, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_PRIEST_BLESSED_HEALING, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index 47c9fa56eae..f3d30af1f84 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -232,10 +232,10 @@ class spell_rog_deadly_brew : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_CRIPPLING_POISON, true); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_CRIPPLING_POISON, true, nullptr, aurEff); } void Register() override @@ -625,7 +625,7 @@ class spell_rog_quick_recovery : public SpellScriptLoader Unit* caster = eventInfo.GetActor(); int32 amount = CalculatePct(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_ROGUE_QUICK_RECOVERY_ENERGY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_ROGUE_QUICK_RECOVERY_ENERGY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -721,10 +721,10 @@ class spell_rog_glyph_of_backstab : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER, true); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 397427b505f..37b08aee7ca 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -119,7 +119,7 @@ class spell_sha_ancestral_awakening : public SpellScriptLoader return; int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount()); - eventInfo.GetActor()->CastCustomSpell(SPELL_SHAMAN_ANCESTRAL_AWAKENING_DUMMY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + eventInfo.GetActor()->CastCustomSpell(SPELL_SHAMAN_ANCESTRAL_AWAKENING_DUMMY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -423,7 +423,7 @@ class spell_sha_earth_shield : public SpellScriptLoader { PreventDefaultAction(); - GetTarget()->CastCustomSpell(SPELL_SHAMAN_EARTH_SHIELD_HEAL, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), GetTarget(), true, NULL, aurEff, GetCasterGUID()); + GetTarget()->CastCustomSpell(SPELL_SHAMAN_EARTH_SHIELD_HEAL, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), GetTarget(), true, nullptr, aurEff, GetCasterGUID()); } void Register() override @@ -732,25 +732,25 @@ class spell_sha_flametongue_weapon : public SpellScriptLoader Item* item = ASSERT_NOTNULL(player->GetWeaponForAttack(attType)); - float basePoints(GetSpellInfo()->Effects[aurEff->GetEffIndex()].CalcValue()); + float const basePoints = GetSpellInfo()->Effects[aurEff->GetEffIndex()].CalcValue(); // Flametongue max damage is normalized based on a 4.0 speed weapon // Tooltip says max damage = BasePoints / 25, so BasePoints / 25 / 4 to get base damage per 1.0s AS float fireDamage = basePoints / 100.0f; - float attackSpeed = player->GetAttackTime(attType) / 1000.f; + float const attackSpeed = player->GetAttackTime(attType) / 1000.f; fireDamage *= attackSpeed; // clip value between (BasePoints / 77) and (BasePoints / 25) as the tooltip indicates RoundToInterval(fireDamage, basePoints / 77.0f, basePoints / 25.0f); // Calculate Spell Power scaling - float spellPowerBonus(player->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE) + target->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_FIRE)); + float spellPowerBonus = player->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE) + target->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_FIRE); float const spCoeff = 0.03811f; spellPowerBonus *= spCoeff * attackSpeed; // All done, now proc damage int32 amount = static_cast<int32>(fireDamage + spellPowerBonus); - player->CastCustomSpell(SPELL_SHAMAN_FLAMETONGUE_ATTACK, SPELLVALUE_BASE_POINT0, amount, target, true, item); + player->CastCustomSpell(SPELL_SHAMAN_FLAMETONGUE_ATTACK, SPELLVALUE_BASE_POINT0, amount, target, true, item, aurEff); } void Register() override @@ -798,7 +798,7 @@ class spell_sha_frozen_power : public SpellScriptLoader if (caster->GetDistance(target) < minDistance) return; - caster->CastSpell(target, SPELL_SHAMAN_FREEZE, true); + caster->CastSpell(target, SPELL_SHAMAN_FREEZE, true, nullptr, aurEff); } void Register() override @@ -881,7 +881,7 @@ class spell_sha_glyph_of_healing_wave : public SpellScriptLoader return; int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_SHAMAN_GLYPH_OF_HEALING_WAVE_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_SHAMAN_GLYPH_OF_HEALING_WAVE_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -941,7 +941,7 @@ class spell_sha_glyph_of_totem_of_wrath : public SpellScriptLoader int32 bp0 = CalculatePct(totemSpell->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount()); int32 bp1 = CalculatePct(totemSpell->Effects[EFFECT_1].CalcValue(caster), aurEff->GetAmount()); - caster->CastCustomSpell((Unit*)nullptr, SPELL_SHAMAN_TOTEM_OF_WRATH_SPELL_POWER, &bp0, &bp1, nullptr, true); + caster->CastCustomSpell((Unit*)nullptr, SPELL_SHAMAN_TOTEM_OF_WRATH_SPELL_POWER, &bp0, &bp1, nullptr, true, nullptr, aurEff); } void Register() override @@ -997,7 +997,8 @@ class spell_sha_healing_stream_totem : public SpellScriptLoader damage = int32(target->SpellHealingBonusTaken(owner, triggeringSpell, damage, HEAL)); } - caster->CastCustomSpell(target, SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL, &damage, 0, 0, true, 0, 0, GetOriginalCaster()->GetGUID()); + + caster->CastCustomSpell(SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL, SPELLVALUE_BASE_POINT0, damage, target, true, nullptr, nullptr, GetOriginalCaster()->GetGUID()); } } } @@ -1044,9 +1045,8 @@ class spell_sha_heroism : public SpellScriptLoader void Register() override { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism_SpellScript::RemoveInvalidTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_RAID); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism_SpellScript::RemoveInvalidTargets, EFFECT_1, TARGET_UNIT_CASTER_AREA_RAID); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism_SpellScript::RemoveInvalidTargets, EFFECT_2, TARGET_UNIT_CASTER_AREA_RAID); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism_SpellScript::RemoveInvalidTargets, EFFECT_ALL, TARGET_UNIT_CASTER_AREA_RAID); + AfterHit += SpellHitFn(spell_sha_heroism_SpellScript::ApplyDebuff); } }; @@ -1091,17 +1091,17 @@ class spell_sha_imp_water_shield : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); // Get Water Shield - AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x00000000, 0x00000020, 0x00000000, caster->GetGUID()); - if (!aurEff) + AuraEffect const* waterShield = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x00000000, 0x00000020, 0x00000000, caster->GetGUID()); + if (!waterShield) return; - uint32 spellId = aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; - caster->CastSpell((Unit*)nullptr, spellId, true); + uint32 spellId = waterShield->GetSpellInfo()->Effects[waterShield->GetEffIndex()].TriggerSpell; + caster->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); } void Register() override @@ -1135,7 +1135,7 @@ class spell_sha_lightning_overload : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); @@ -1161,7 +1161,7 @@ class spell_sha_lightning_overload : public SpellScriptLoader spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_CHAIN_LIGHTNING_OVERLOAD_R1, spellInfo->GetRank()); } - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); } void Register() override @@ -1196,7 +1196,7 @@ class spell_sha_item_lightning_shield : public SpellScriptLoader void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - GetTarget()->CastSpell(eventInfo.GetProcTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD, true, NULL, aurEff); + GetTarget()->CastSpell(eventInfo.GetProcTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD, true, nullptr, aurEff); } void Register() override @@ -1231,7 +1231,7 @@ class spell_sha_item_lightning_shield_trigger : public SpellScriptLoader void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) { PreventDefaultAction(); - GetTarget()->CastSpell(GetTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE, true, NULL, aurEff); + GetTarget()->CastSpell(GetTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE, true, nullptr, aurEff); } void Register() override @@ -1306,7 +1306,7 @@ class spell_sha_item_t6_trinket : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); @@ -1338,7 +1338,7 @@ class spell_sha_item_t6_trinket : public SpellScriptLoader return; if (roll_chance_i(chance)) - eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); } void Register() override @@ -1507,7 +1507,7 @@ class spell_sha_maelstrom_weapon : public SpellScriptLoader if (!aurEff || !roll_chance_i(aurEff->GetAmount())) return; - caster->CastSpell((Unit*)nullptr, SPELL_SHAMAN_MAELSTROM_POWER, true); + caster->CastSpell((Unit*)nullptr, SPELL_SHAMAN_MAELSTROM_POWER, true, nullptr, aurEff); } void Register() override @@ -1593,7 +1593,7 @@ class spell_sha_mana_tide_totem : public SpellScriptLoader effValue += dummy->GetAmount(); // Regenerate 6% of Total Mana Every 3 secs int32 effBasePoints0 = int32(CalculatePct(unitTarget->GetMaxPower(POWER_MANA), effValue)); - caster->CastCustomSpell(unitTarget, SPELL_SHAMAN_MANA_TIDE_TOTEM, &effBasePoints0, NULL, NULL, true, NULL, NULL, GetOriginalCaster()->GetGUID()); + caster->CastCustomSpell(SPELL_SHAMAN_MANA_TIDE_TOTEM, SPELLVALUE_BASE_POINT0, effBasePoints0, unitTarget, true, nullptr, nullptr, GetOriginalCaster()->GetGUID()); } } } @@ -1777,8 +1777,8 @@ class spell_sha_spirit_hunt : public SpellScriptLoader return; int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_SHAMAN_SPIRIT_HUNT_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true); - caster->CastCustomSpell(SPELL_SHAMAN_SPIRIT_HUNT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_SHAMAN_SPIRIT_HUNT_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true, nullptr, aurEff); + caster->CastCustomSpell(SPELL_SHAMAN_SPIRIT_HUNT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -1810,20 +1810,20 @@ class spell_sha_static_shock : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); // Get Lightning Shield - AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x00000400, 0x00000000, 0x00000000, caster->GetGUID()); - if (!aurEff) + AuraEffect const* lightningShield = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x00000400, 0x00000000, 0x00000000, caster->GetGUID()); + if (!lightningShield) return; - uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_LIGHTNING_SHIELD_DAMAGE_R1, aurEff->GetSpellInfo()->GetRank()); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true); - aurEff->GetBase()->DropCharge(); + uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_LIGHTNING_SHIELD_DAMAGE_R1, lightningShield->GetSpellInfo()->GetRank()); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); + lightningShield->GetBase()->DropCharge(); } void Register() override @@ -1919,14 +1919,14 @@ public: return true; } - void HandleDummy(AuraEffect const* /*aurEff*/) + void HandleDummy(AuraEffect const* aurEff) { Unit* target = GetTarget(); for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i) if (!target->m_SummonSlot[i]) return; - target->CastSpell(target, SPELL_SHAMAN_TOTEMIC_MASTERY, true); + target->CastSpell(target, SPELL_SHAMAN_TOTEMIC_MASTERY, true, nullptr, aurEff); PreventDefaultAction(); } @@ -1962,7 +1962,7 @@ class spell_sha_t3_6p_bonus : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); @@ -1993,7 +1993,7 @@ class spell_sha_t3_6p_bonus : public SpellScriptLoader return; } - caster->CastSpell(target, spellId, true); + caster->CastSpell(target, spellId, true, nullptr, aurEff); } void Register() override @@ -2037,12 +2037,12 @@ class spell_sha_t8_elemental_4p_bonus : public SpellScriptLoader int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount()); amount /= spellInfo->GetMaxTicks(); - // Add remaining ticks to healing done + // Add remaining ticks to damage done Unit* caster = eventInfo.GetActor(); Unit* target = eventInfo.GetProcTarget(); amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_SHAMAN_ELECTRIFIED, SPELL_AURA_PERIODIC_DAMAGE); - caster->CastCustomSpell(SPELL_SHAMAN_ELECTRIFIED, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_SHAMAN_ELECTRIFIED, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -2086,12 +2086,12 @@ class spell_sha_t9_elemental_4p_bonus : public SpellScriptLoader int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount()); amount /= spellInfo->GetMaxTicks(); - // Add remaining ticks to healing done + // Add remaining ticks to damage done Unit* caster = eventInfo.GetActor(); Unit* target = eventInfo.GetProcTarget(); amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE, SPELL_AURA_PERIODIC_DAMAGE); - caster->CastCustomSpell(SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -2185,7 +2185,7 @@ class spell_sha_t10_restoration_4p_bonus : public SpellScriptLoader Unit* target = eventInfo.GetProcTarget(); amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_SHAMAN_CHAINED_HEAL, SPELL_AURA_PERIODIC_HEAL); - caster->CastCustomSpell(SPELL_SHAMAN_CHAINED_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_SHAMAN_CHAINED_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -2221,7 +2221,6 @@ class spell_sha_windfury_weapon : public SpellScriptLoader bool CheckProc(ProcEventInfo& eventInfo) { - Player* player = eventInfo.GetActor()->ToPlayer(); if (!player) return false; @@ -2241,7 +2240,7 @@ class spell_sha_windfury_weapon : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); @@ -2281,7 +2280,7 @@ class spell_sha_windfury_weapon : public SpellScriptLoader // Attack twice for (uint8 i = 0; i < 2; ++i) - player->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, item); + player->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, item, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index cccebab6259..1a8252ad7ec 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -596,11 +596,11 @@ class spell_warl_glyph_of_corruption_nightfall : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, SPELL_WARLOCK_SHADOW_TRANCE, true); + caster->CastSpell(caster, SPELL_WARLOCK_SHADOW_TRANCE, true, nullptr, aurEff); } void Register() override @@ -632,11 +632,11 @@ public: return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED, true); + caster->CastSpell(caster, SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED, true, nullptr, aurEff); } void Register() override @@ -1135,7 +1135,7 @@ class spell_warl_seed_of_corruption_dummy : public SpellScriptLoader return; uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1, GetSpellInfo()->GetRank()); - caster->CastSpell(eventInfo.GetActionTarget(), spellId, true); + caster->CastSpell(eventInfo.GetActionTarget(), spellId, true, nullptr, aurEff); } void Register() override @@ -1193,7 +1193,7 @@ class spell_warl_seed_of_corruption_generic : public SpellScriptLoader if (!caster) return; - caster->CastSpell(eventInfo.GetActionTarget(), SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC, true); + caster->CastSpell(eventInfo.GetActionTarget(), SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC, true, nullptr, aurEff); } void Register() override @@ -1344,11 +1344,11 @@ class spell_warl_soul_leech : public SpellScriptLoader uint32 selfSpellId = casterMana[impSoulLeechRank - 1]; uint32 petSpellId = petMana[impSoulLeechRank - 1]; - caster->CastSpell((Unit*)nullptr, selfSpellId, true); - caster->CastSpell((Unit*)nullptr, petSpellId, true); + caster->CastSpell((Unit*)nullptr, selfSpellId, true, nullptr, aurEff); + caster->CastSpell((Unit*)nullptr, petSpellId, true, nullptr, aurEff); if (roll_chance_i(impSoulLeech->GetAmount())) - caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true); + caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true, nullptr, aurEff); } void Register() override @@ -1422,11 +1422,11 @@ class spell_warl_t4_2p_bonus : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, Trigger, true); + caster->CastSpell(caster, Trigger, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 084c0441a0b..81fb4ec2457 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -486,11 +486,11 @@ class spell_warr_glyph_of_blocking : public SpellScriptLoader return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, SPELL_WARRIOR_GLYPH_OF_BLOCKING, true); + caster->CastSpell(caster, SPELL_WARRIOR_GLYPH_OF_BLOCKING, true, nullptr, aurEff); } void Register() override @@ -562,7 +562,7 @@ class spell_warr_improved_spell_reflection : public SpellScriptLoader { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); - caster->CastCustomSpell(SPELL_WARRIOR_IMPROVED_SPELL_REFLECTION_TRIGGER, SPELLVALUE_MAX_TARGETS, aurEff->GetAmount(), caster, true); + caster->CastCustomSpell(SPELL_WARRIOR_IMPROVED_SPELL_REFLECTION_TRIGGER, SPELLVALUE_MAX_TARGETS, aurEff->GetAmount(), caster, true, nullptr, aurEff); } void Register() override @@ -832,14 +832,14 @@ class spell_warr_second_wind : public SpellScriptLoader return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN))) != 0; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { static uint32 const triggeredSpells[2] = { SPELL_WARRIOR_SECOND_WIND_TRIGGER_1, SPELL_WARRIOR_SECOND_WIND_TRIGGER_2 }; PreventDefaultAction(); Unit* caster = eventInfo.GetActionTarget(); uint32 spellId = triggeredSpells[GetSpellInfo()->GetRank() - 1]; - caster->CastSpell(caster, spellId, true); + caster->CastSpell(caster, spellId, true, nullptr, aurEff); } void Register() override 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 |