diff options
46 files changed, 2050 insertions, 275 deletions
diff --git a/src/cmake/ac_macros.cmake b/src/cmake/ac_macros.cmake index 838210ed92..623fc30613 100644 --- a/src/cmake/ac_macros.cmake +++ b/src/cmake/ac_macros.cmake @@ -6,6 +6,22 @@ MACRO(AC_ADD_SCRIPT path) ENDMACRO() # +# AC_ADD_SCRIPTS +# +# This macro can be used to automatically load scripts for the ScriptMgr +# from a specified folder, instead of manually list them within the cmake +# NOTE: you must still manually specify the script loader header +# + +MACRO(AC_ADD_SCRIPTS path) +CU_SUBDIRLIST(sub_DIRS ${path} TRUE TRUE) +FOREACH(subdir ${sub_DIRS}) + file(GLOB sources "${subdir}/*.cpp" "${subdir}/*.h") + CU_LIST_ADD_CACHE(scripts_STAT_SRCS "${sources}") +ENDFOREACH() +ENDMACRO() + +# # AC_ADD_SCRIPT_LOADER # MACRO(AC_ADD_SCRIPT_LOADER script_dec include) diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 07a3936f2d..d65587338c 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -828,6 +828,8 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui if (!achievementCriteriaList) return; + sScriptMgr->OnBeforeCheckCriteria(this, achievementCriteriaList); + for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList->begin(); i != achievementCriteriaList->end(); ++i) { AchievementCriteriaEntry const* achievementCriteria = (*i); @@ -838,6 +840,9 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui if (!CanUpdateCriteria(achievementCriteria, achievement)) continue; + if (!sScriptMgr->CanCheckCriteria(this, achievementCriteria)) + continue; + switch (type) { // std. case: increment at 1 @@ -1762,6 +1767,9 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve if (!progress) return false; + if (!sScriptMgr->IsCompletedCriteria(this, achievementCriteria, achievement, progress)) + return false; + switch (achievementCriteria->requiredType) { case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: @@ -2394,6 +2402,9 @@ bool AchievementGlobalMgr::IsRealmCompleted(AchievementEntry const* achievement) if (itr->second == std::chrono::system_clock::time_point::min()) return false; + if (!sScriptMgr->IsRealmCompleted(this, achievement, itr->second)) + return false; + if (itr->second == std::chrono::system_clock::time_point::max()) return true; @@ -2403,6 +2414,8 @@ bool AchievementGlobalMgr::IsRealmCompleted(AchievementEntry const* achievement) if (achievement->flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL) return (std::chrono::system_clock::now() - itr->second) > std::chrono::minutes(1); + sScriptMgr->SetRealmCompleted(achievement); + return true; } diff --git a/src/server/game/Battlegrounds/ArenaTeam.cpp b/src/server/game/Battlegrounds/ArenaTeam.cpp index b0e2bbada8..09b83c3e7a 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.cpp +++ b/src/server/game/Battlegrounds/ArenaTeam.cpp @@ -101,6 +101,9 @@ bool ArenaTeam::AddMember(uint64 playerGuid) playerClass = playerData->playerClass; } + if (!sScriptMgr->CanAddMember(this, playerGuid)) + return false; + // Check if player is already in a similar arena team if ((player && player->GetArenaTeamId(GetSlot())) || Player::GetArenaTeamIdFromStorage(GUID_LOPART(playerGuid), GetSlot()) != 0) { @@ -610,27 +613,24 @@ void ArenaTeam::MassInviteToEvent(WorldSession* session) uint8 ArenaTeam::GetSlotByType(uint32 type) { uint8 slot = 0xFF; - switch (type) + + auto const& itr = ArenaSlotByType.find(type); + if (itr == ArenaSlotByType.end()) { - case ARENA_TEAM_2v2: - slot = 0; - break; - case ARENA_TEAM_3v3: - slot = 1; - break; - case ARENA_TEAM_5v5: - slot = 2; - break; - default: - break; + sLog->outError("FATAL: Unknown arena team type %u for some arena team", type); + return slot; } - //Get the changed slot type + + slot = ArenaSlotByType.at(type); + + // Get the changed slot type sScriptMgr->OnGetSlotByType(type, slot); if (slot != 0xFF) { return slot; } + sLog->outError("FATAL: Unknown arena team type %u for some arena team", type); return 0xFF; } @@ -868,12 +868,14 @@ void ArenaTeam::MemberWon(Player* player, uint32 againstMatchmakerRating, int32 { // update personal rating int32 mod = GetRatingMod(itr->PersonalRating, againstMatchmakerRating, true); + sScriptMgr->OnBeforeUpdatingPersonalRating(mod, GetType()); itr->ModifyPersonalRating(player, mod, GetType()); // update matchmaker rating (pussywizard: but don't allow it to go over team rating) if (itr->MatchMakerRating < Stats.Rating) { mod = std::min(MatchmakerRatingChange, Stats.Rating - itr->MatchMakerRating); + sScriptMgr->OnBeforeUpdatingPersonalRating(mod, GetType()); itr->ModifyMatchmakerRating(mod, GetSlot()); } @@ -922,6 +924,9 @@ void ArenaTeam::UpdateArenaPointsHelper(std::map<uint32, uint32>& playerPoints) void ArenaTeam::SaveToDB() { + if (!sScriptMgr->CanSaveToDB(this)) + return; + // Save team and member stats to db // Called after a match has ended or when calculating arena_points @@ -997,3 +1002,83 @@ ArenaTeamMember* ArenaTeam::GetMember(uint64 guid) return nullptr; } + +uint8 ArenaTeam::GetReqPlayersForType(uint32 type) +{ + auto const& itr = ArenaReqPlayersForType.find(type); + if (itr == ArenaReqPlayersForType.end()) + { + sLog->outError("FATAL: Unknown arena type %u!", type); + return 0xFF; + } + + return ArenaReqPlayersForType.at(type); +} + +void ArenaTeam::CreateTempArenaTeam(std::vector<Player*> playerList, uint8 type, std::string const& teamName) +{ + auto playerCountInTeam = static_cast<uint32>(playerList.size()); + + ASSERT(playerCountInTeam == GetReqPlayersForType(type)); + + // Generate new arena team id + TeamId = sArenaTeamMgr->GenerateTempArenaTeamId(); + + // Assign member variables + CaptainGuid = playerList[0]->GetGUID(); + Type = type; + TeamName = teamName; + + BackgroundColor = 0; + EmblemStyle = 0; + EmblemColor = 0; + BorderStyle = 0; + BorderColor = 0; + + Stats.WeekGames = 0; + Stats.SeasonGames = 0; + Stats.Rating = 0; + Stats.WeekWins = 0; + Stats.SeasonWins = 0; + + for (auto const& _player : playerList) + { + ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(_player->GetArenaTeamId(GetSlotByType(type))); + if (!team) + continue; + + ArenaTeamMember newMember; + for (auto const& itr : Members) + newMember = itr; + + Stats.WeekGames += team->Stats.WeekGames; + Stats.SeasonGames += team->Stats.SeasonGames; + Stats.Rating += team->GetRating(); + Stats.WeekWins += team->Stats.WeekWins; + Stats.SeasonWins += team->Stats.SeasonWins; + + Members.push_back(newMember); + } + + Stats.WeekGames /= playerCountInTeam; + Stats.SeasonGames /= playerCountInTeam; + Stats.Rating /= playerCountInTeam; + Stats.WeekWins /= playerCountInTeam; + Stats.SeasonWins /= playerCountInTeam; +} + +// init/update unordered_map ArenaSlotByType +std::unordered_map<uint32, uint8> ArenaTeam::ArenaSlotByType = +{ + { ARENA_TEAM_2v2, ARENA_SLOT_2v2}, + { ARENA_TEAM_3v3, ARENA_SLOT_3v3}, + { ARENA_TEAM_5v5, ARENA_SLOT_5v5} +}; + +// init/update unordered_map ArenaReqPlayersForType +std::unordered_map<uint8, uint8> ArenaTeam::ArenaReqPlayersForType = +{ + { ARENA_TYPE_2v2, 4}, + { ARENA_TYPE_3v3, 6}, + { ARENA_TYPE_5v5, 10} +}; diff --git a/src/server/game/Battlegrounds/ArenaTeam.h b/src/server/game/Battlegrounds/ArenaTeam.h index 3bd6ec29c1..2fd3c9d5bd 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.h +++ b/src/server/game/Battlegrounds/ArenaTeam.h @@ -58,6 +58,19 @@ enum ArenaTeamEvents ERR_ARENA_TEAM_DISBANDED_S = 8 // captain name + arena team name }; +// PLAYER_FIELD_ARENA_TEAM_INFO_1_1 offsets +enum ArenaTeamInfoType +{ + ARENA_TEAM_ID = 0, + ARENA_TEAM_TYPE = 1, // new in 3.2 - team type? + ARENA_TEAM_MEMBER = 2, // 0 - captain, 1 - member + ARENA_TEAM_GAMES_WEEK = 3, + ARENA_TEAM_GAMES_SEASON = 4, + ARENA_TEAM_WINS_SEASON = 5, + ARENA_TEAM_PERSONAL_RATING = 6, + ARENA_TEAM_END = 7 +}; + /* need info how to send these ones: ERR_ARENA_TEAM_YOU_JOIN_S - client show it automatically when accept invite @@ -73,6 +86,13 @@ enum ArenaTeamTypes ARENA_TEAM_5v5 = 5 }; +enum ArenaSlot +{ + ARENA_SLOT_2v2, + ARENA_SLOT_3v3, + ARENA_SLOT_5v5 +}; + struct ArenaTeamMember { uint64 Guid; @@ -118,9 +138,11 @@ public: [[nodiscard]] uint32 GetType() const { return Type; } [[nodiscard]] uint8 GetSlot() const { return GetSlotByType(GetType()); } static uint8 GetSlotByType(uint32 type); + static uint8 GetReqPlayersForType(uint32 type); [[nodiscard]] uint64 GetCaptain() const { return CaptainGuid; } [[nodiscard]] std::string const& GetName() const { return TeamName; } [[nodiscard]] const ArenaTeamStats& GetStats() const { return Stats; } + void SetArenaTeamStats(ArenaTeamStats& stats) { Stats = stats; } [[nodiscard]] uint32 GetRating() const { return Stats.Rating; } uint32 GetAverageMMR(Group* group) const; @@ -137,6 +159,7 @@ public: [[nodiscard]] bool Empty() const { return Members.empty(); } MemberList::iterator m_membersBegin() { return Members.begin(); } MemberList::iterator m_membersEnd() { return Members.end(); } + MemberList& GetMembers() { return Members; } [[nodiscard]] bool IsMember(uint64 guid) const; ArenaTeamMember* GetMember(uint64 guid); @@ -174,6 +197,12 @@ public: void FinishWeek(); void FinishGame(int32 mod, const Map* bgMap); + void CreateTempArenaTeam(std::vector<Player*> playerList, uint8 type, std::string const& teamName); + + // Containers + static std::unordered_map<uint32, uint8> ArenaSlotByType; // Slot -> Type + static std::unordered_map<uint8, uint8> ArenaReqPlayersForType; // Type -> Players count + protected: uint32 TeamId; uint8 Type; diff --git a/src/server/game/Battlegrounds/ArenaTeamMgr.cpp b/src/server/game/Battlegrounds/ArenaTeamMgr.cpp index 8a0015f11f..770b8655e6 100644 --- a/src/server/game/Battlegrounds/ArenaTeamMgr.cpp +++ b/src/server/game/Battlegrounds/ArenaTeamMgr.cpp @@ -14,10 +14,14 @@ #include "ScriptMgr.h" #include "World.h" +constexpr uint32 MAX_ARENA_TEAM_ID = 0xFFF00000; +constexpr uint32 MAX_TEMP_ARENA_TEAM_ID = 0xFFFFFFFE; + ArenaTeamMgr::ArenaTeamMgr() { NextArenaTeamId = 1; LastArenaLogId = 0; + NextTempArenaTeamId = 0xFFF00000; } ArenaTeamMgr::~ArenaTeamMgr() @@ -114,14 +118,23 @@ void ArenaTeamMgr::RemoveArenaTeam(uint32 arenaTeamId) uint32 ArenaTeamMgr::GenerateArenaTeamId() { - if (NextArenaTeamId >= 0xFFFFFFFE) + if (NextArenaTeamId >= MAX_ARENA_TEAM_ID) { sLog->outError("Arena team ids overflow!! Can't continue, shutting down server. "); World::StopNow(ERROR_EXIT_CODE); } + return NextArenaTeamId++; } +uint32 ArenaTeamMgr::GenerateTempArenaTeamId() +{ + if (NextTempArenaTeamId >= MAX_TEMP_ARENA_TEAM_ID) + NextTempArenaTeamId = MAX_ARENA_TEAM_ID; + + return NextTempArenaTeamId++; +} + void ArenaTeamMgr::LoadArenaTeams() { uint32 oldMSTime = getMSTime(); diff --git a/src/server/game/Battlegrounds/ArenaTeamMgr.h b/src/server/game/Battlegrounds/ArenaTeamMgr.h index 6195cf822c..b2363b9b81 100644 --- a/src/server/game/Battlegrounds/ArenaTeamMgr.h +++ b/src/server/game/Battlegrounds/ArenaTeamMgr.h @@ -31,6 +31,7 @@ public: ArenaTeamContainer::iterator GetArenaTeamMapBegin() { return ArenaTeamStore.begin(); } ArenaTeamContainer::iterator GetArenaTeamMapEnd() { return ArenaTeamStore.end(); } + ArenaTeamContainer& GetArenaTeams() { return ArenaTeamStore; } void DistributeArenaPoints(); @@ -40,8 +41,11 @@ public: uint32 GetNextArenaLogId() { return ++LastArenaLogId; } void SetLastArenaLogId(uint32 id) { LastArenaLogId = id; } + uint32 GenerateTempArenaTeamId(); + protected: uint32 NextArenaTeamId; + uint32 NextTempArenaTeamId; ArenaTeamContainer ArenaTeamStore; uint32 LastArenaLogId; }; diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 5fed74091f..16311747f4 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -1382,7 +1382,7 @@ void Battleground::ReadyMarkerClicked(Player* p) return; readyMarkerClickedSet.insert(p->GetGUIDLow()); uint32 count = readyMarkerClickedSet.size(); - uint32 req = GetArenaType() * 2; + uint32 req = ArenaTeam::GetReqPlayersForType(GetArenaType()); p->GetSession()->SendNotification("You are marked as ready %u/%u", count, req); if (count == req) { diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index 38afda5c8b..f8402de489 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -468,19 +468,7 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId original // Set up correct min/max player counts for scoreboards if (bg->isArena()) { - uint32 maxPlayersPerTeam = 0; - switch (arenaType) - { - case ARENA_TYPE_2v2: - maxPlayersPerTeam = 2; - break; - case ARENA_TYPE_3v3: - maxPlayersPerTeam = 3; - break; - case ARENA_TYPE_5v5: - maxPlayersPerTeam = 5; - break; - } + uint32 maxPlayersPerTeam = ArenaTeam::GetReqPlayersForType(arenaType) / 2; sScriptMgr->OnSetArenaMaxPlayersPerTeam(arenaType, maxPlayersPerTeam); bg->SetMaxPlayersPerTeam(maxPlayersPerTeam); } @@ -748,31 +736,24 @@ bool BattlegroundMgr::IsArenaType(BattlegroundTypeId bgTypeId) BattlegroundQueueTypeId BattlegroundMgr::BGQueueTypeId(BattlegroundTypeId bgTypeId, uint8 arenaType) { - if (arenaType) { - uint32 queueTypeID = BATTLEGROUND_QUEUE_NONE; - switch (arenaType) { - case ARENA_TYPE_2v2: - queueTypeID = BATTLEGROUND_QUEUE_2v2; - break; - case ARENA_TYPE_3v3: - queueTypeID = BATTLEGROUND_QUEUE_3v3; - break; - case ARENA_TYPE_5v5: - queueTypeID = BATTLEGROUND_QUEUE_5v5; - break; - default: - break; + uint32 queueTypeID = BATTLEGROUND_QUEUE_NONE; + + if (arenaType) + { + if (BattlegroundMgr::ArenaTypeToQueue.find(arenaType) != BattlegroundMgr::ArenaTypeToQueue.end()) + { + queueTypeID = BattlegroundMgr::ArenaTypeToQueue.at(arenaType); } + sScriptMgr->OnArenaTypeIDToQueueID(bgTypeId, arenaType, queueTypeID); - return BattlegroundQueueTypeId(queueTypeID); } - if (BattlegroundMgr::bgToQueue.find(bgTypeId) == BattlegroundMgr::bgToQueue.end()) + if (BattlegroundMgr::bgToQueue.find(bgTypeId) != BattlegroundMgr::bgToQueue.end()) { - return BATTLEGROUND_QUEUE_NONE; + queueTypeID = BattlegroundMgr::bgToQueue.at(bgTypeId); } - return BattlegroundMgr::bgToQueue[bgTypeId]; + return static_cast<BattlegroundQueueTypeId>(queueTypeID); } BattlegroundTypeId BattlegroundMgr::BGTemplateId(BattlegroundQueueTypeId bgQueueTypeId) @@ -788,21 +769,14 @@ BattlegroundTypeId BattlegroundMgr::BGTemplateId(BattlegroundQueueTypeId bgQueue uint8 BattlegroundMgr::BGArenaType(BattlegroundQueueTypeId bgQueueTypeId) { uint8 arenaType = 0; - switch (bgQueueTypeId) + + if (BattlegroundMgr::QueueToArenaType.find(bgQueueTypeId) != BattlegroundMgr::QueueToArenaType.end()) { - case BATTLEGROUND_QUEUE_2v2: - arenaType = ARENA_TYPE_2v2; - break; - case BATTLEGROUND_QUEUE_3v3: - arenaType = ARENA_TYPE_3v3; - break; - case BATTLEGROUND_QUEUE_5v5: - arenaType = ARENA_TYPE_5v5; - break; - default: - break; + arenaType = BattlegroundMgr::QueueToArenaType.at(bgQueueTypeId); } + sScriptMgr->OnArenaQueueIdToArenaType(bgQueueTypeId, arenaType); + return arenaType; } @@ -1166,3 +1140,17 @@ std::unordered_map<int, bgTypeRef> BattlegroundMgr::getBgFromTypeID = } } }; + +std::unordered_map<uint32, BattlegroundQueueTypeId> BattlegroundMgr::ArenaTypeToQueue = +{ + { ARENA_TYPE_2v2, BATTLEGROUND_QUEUE_2v2 }, + { ARENA_TYPE_3v3, BATTLEGROUND_QUEUE_3v3 }, + { ARENA_TYPE_5v5, BATTLEGROUND_QUEUE_5v5 } +}; + +std::unordered_map<uint32, ArenaType> BattlegroundMgr::QueueToArenaType = +{ + { BATTLEGROUND_QUEUE_2v2, ARENA_TYPE_2v2 }, + { BATTLEGROUND_QUEUE_3v3, ARENA_TYPE_3v3 }, + { BATTLEGROUND_QUEUE_5v5, ARENA_TYPE_5v5 } +}; diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index 350b26c130..7eb9d7ae65 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -127,6 +127,8 @@ public: static std::unordered_map<int, bgRef> bgTypeToTemplate; // BattlegroundTypeId -> bgRef static std::unordered_map<int, bgMapRef> getBgFromMap; // BattlegroundMapID -> bgMapRef static std::unordered_map<int, bgTypeRef> getBgFromTypeID; // BattlegroundTypeID -> bgTypeRef + static std::unordered_map<uint32, BattlegroundQueueTypeId> ArenaTypeToQueue; // ArenaType -> BattlegroundQueueTypeId + static std::unordered_map<uint32, ArenaType> QueueToArenaType; // BattlegroundQueueTypeId -> ArenaType private: bool CreateBattleground(CreateBattlegroundData& data); diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.cpp b/src/server/game/Battlegrounds/BattlegroundQueue.cpp index 3e870dc0d1..9dee21b767 100644 --- a/src/server/game/Battlegrounds/BattlegroundQueue.cpp +++ b/src/server/game/Battlegrounds/BattlegroundQueue.cpp @@ -152,9 +152,7 @@ GroupQueueInfo* BattlegroundQueue::AddGroup(Player* leader, Group* grp, PvPDiffi ginfo->_groupType = index; // announce world (this doesn't need mutex) - if (isRated && sWorld->getBoolConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE)) - if (ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(arenateamid)) - sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, team->GetName().c_str(), ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating); + SendMessageArenaQueue(ginfo, true); //add players from group to ginfo if (grp) @@ -185,7 +183,7 @@ GroupQueueInfo* BattlegroundQueue::AddGroup(Player* leader, Group* grp, PvPDiffi return ginfo; if (!isRated && !isPremade && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE)) - SendMessageQueue(leader, bg, bracketEntry); + SendMessageBGQueue(leader, bg, bracketEntry); return ginfo; } @@ -298,9 +296,7 @@ void BattlegroundQueue::RemovePlayer(uint64 guid, bool sentToBg, uint32 playerQu m_QueuedPlayers.erase(itr); // announce to world if arena team left queue for rated match, show only once - if (groupInfo->ArenaType && groupInfo->IsRated && groupInfo->Players.empty() && sWorld->getBoolConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE)) - if (ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(groupInfo->ArenaTeamId)) - sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, team->GetName().c_str(), groupInfo->ArenaType, groupInfo->ArenaType, groupInfo->ArenaTeamRating); + SendMessageArenaQueue(groupInfo, false); // if player leaves queue and he is invited to a rated arena match, then count it as he lost if (groupInfo->IsInvitedToBGInstanceGUID && groupInfo->IsRated && !sentToBg) @@ -726,6 +722,8 @@ void BattlegroundQueue::BattlegroundQueueUpdate(BattlegroundBracketId bracket_id MaxPlayersPerTeam = m_arenaType; } + sScriptMgr->OnQueueUpdate(this, bracket_id, isRated, arenaRatedTeamId); + // check if can start new premade battleground if (bg_template->isBattleground() && m_bgTypeId != BATTLEGROUND_RB) if (CheckPremadeMatch(bracket_id, MinPlayersPerTeam, MaxPlayersPerTeam)) @@ -963,9 +961,9 @@ bool BattlegroundQueue::IsAllQueuesEmpty(BattlegroundBracketId bracket_id) return queueEmptyCount == BG_QUEUE_MAX; } -void BattlegroundQueue::SendMessageQueue(Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry) +void BattlegroundQueue::SendMessageBGQueue(Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry) { - if (!sScriptMgr->CanSendMessageQueue(this, leader, bg, bracketEntry)) + if (!sScriptMgr->CanSendMessageBGQueue(this, leader, bg, bracketEntry)) return; BattlegroundBracketId bracketId = bracketEntry->GetBracketId(); @@ -1004,6 +1002,32 @@ void BattlegroundQueue::SendMessageQueue(Player* leader, Battleground* bg, PvPDi } } +void BattlegroundQueue::SendMessageArenaQueue(GroupQueueInfo* ginfo, bool IsJoin) +{ + if (!sWorld->getBoolConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE)) + return; + + if (!sScriptMgr->CanSendMessageArenaQueue(this, ginfo, IsJoin)) + return; + + ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(ginfo->ArenaTeamId); + if (!team) + return; + + if (!ginfo->IsRated) + return; + + uint8 ArenaType = ginfo->ArenaType; + uint32 ArenaTeamRating = ginfo->ArenaTeamRating; + std::string TeamName = team->GetName(); + + if (IsJoin) + sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, TeamName.c_str(), ArenaType, ArenaType, ArenaTeamRating); + + if (!IsJoin && ArenaType && ginfo->Players.empty()) + sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, TeamName.c_str(), ArenaType, ArenaType, ArenaTeamRating); +} + /*********************************************************/ /*** BATTLEGROUND QUEUE EVENTS ***/ /*********************************************************/ diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.h b/src/server/game/Battlegrounds/BattlegroundQueue.h index d755426545..4e6ec9d5fb 100644 --- a/src/server/game/Battlegrounds/BattlegroundQueue.h +++ b/src/server/game/Battlegrounds/BattlegroundQueue.h @@ -71,7 +71,8 @@ public: uint32 GetAverageQueueWaitTime(GroupQueueInfo* ginfo) const; uint32 GetPlayersCountInGroupsQueue(BattlegroundBracketId bracketId, BattlegroundQueueGroupTypes bgqueue); bool IsAllQueuesEmpty(BattlegroundBracketId bracket_id); - void SendMessageQueue(Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry); + void SendMessageBGQueue(Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry); + void SendMessageArenaQueue(GroupQueueInfo* ginfo, bool IsJoin); void SetBgTypeIdAndArenaType(BattlegroundTypeId b, uint8 a) { m_bgTypeId = b; m_arenaType = ArenaType(a); } // pussywizard void AddEvent(BasicEvent* Event, uint64 e_time); @@ -110,6 +111,9 @@ public: //one selection pool for horde, other one for alliance SelectionPool m_SelectionPools[BG_TEAMS_COUNT]; + + ArenaType GetArenaType() { return m_arenaType; } + BattlegroundTypeId GetBGTypeID() { return m_bgTypeId; } private: BattlegroundTypeId m_bgTypeId; ArenaType m_arenaType; diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 89a659e740..3bfd1b7823 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -456,7 +456,7 @@ namespace lfg } } - sScriptMgr->OnInitializeLockedDungeons(player, level, lockData); + sScriptMgr->OnInitializeLockedDungeons(player, level, lockData, dungeon); /* TODO VoA closed if WG is not under team control (LFG_LOCKSTATUS_RAID_LOCKED) lockData = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE; @@ -500,6 +500,9 @@ namespace lfg if (grp && (grp->isBGGroup() || grp->isBFGroup())) return; + if (!sScriptMgr->CanJoinLfg(player, roles, dungeons, comment)) + return; + // pussywizard: can't join LFG/LFR while using LFR if (GetState(player->GetGUID()) == LFG_STATE_RAIDBROWSER) { diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp index cb49e7f47d..d9a498cb4b 100644 --- a/src/server/game/Entities/Creature/GossipDef.cpp +++ b/src/server/game/Entities/Creature/GossipDef.cpp @@ -11,6 +11,8 @@ #include "QuestDef.h" #include "WorldPacket.h" #include "WorldSession.h" +#include "Formulas.h" +#include "Player.h" GossipMenu::GossipMenu() { @@ -420,7 +422,7 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, uint64 npcGUID, } data << uint32(quest->GetRewOrReqMoney()); - data << uint32(quest->XPValue(_session->GetPlayer()) * sWorld->getRate(RATE_XP_QUEST)); + data << uint32(quest->XPValue(_session->GetPlayer()) * _session->GetPlayer()->GetQuestRate()); } // rewarded honor points. Multiply with 10 to satisfy client @@ -650,7 +652,7 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, uint64 npcGUID, b } data << uint32(quest->GetRewOrReqMoney()); - data << uint32(quest->XPValue(_session->GetPlayer()) * sWorld->getRate(RATE_XP_QUEST)); + data << uint32(quest->XPValue(_session->GetPlayer()) * _session->GetPlayer()->GetQuestRate()); // rewarded honor points. Multiply with 10 to satisfy client data << uint32(10 * quest->CalculateHonorGain(_session->GetPlayer()->GetQuestLevel(quest))); diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index bd9185ba07..246c5353ba 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -91,7 +91,11 @@ void AddItemsSetItem(Player* player, Item* item) } // spell casted only if fit form requirement, in other case will casted at form change - player->ApplyEquipSpell(spellInfo, nullptr, true); + if (sScriptMgr->CanItemApplyEquipSpell(player, item)) + { + player->ApplyEquipSpell(spellInfo, nullptr, true); + } + eff->spells[y] = spellInfo; break; } @@ -266,6 +270,7 @@ bool Item::Create(uint32 guidlow, uint32 itemid, Player const* owner) SetUInt32Value(ITEM_FIELD_DURATION, itemProto->Duration); SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, 0); + sScriptMgr->OnItemCreate(this, itemProto, owner); return true; } @@ -423,7 +428,7 @@ bool Item::LoadFromDB(uint32 guid, uint64 owner_guid, Field* fields, uint32 entr SetUInt32Value(ITEM_FIELD_FLAGS, fields[5].GetUInt32()); // Remove bind flag for items vs NO_BIND set - if (IsSoulBound() && proto->Bonding == NO_BIND) + if (IsSoulBound() && proto->Bonding == NO_BIND && sScriptMgr->CanApplySoulboundFlag(this, proto)) { ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND, false); need_save = true; diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index ba1677de7e..d535ac571f 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -87,6 +87,8 @@ Object::Object() : m_PackGUID(sizeof(uint64) + 1) m_objectUpdated = false; m_PackGUID.appendPackGUID(0); + + sScriptMgr->OnConstructObject(this); } WorldObject::~WorldObject() @@ -110,6 +112,8 @@ WorldObject::~WorldObject() Object::~Object() { + sScriptMgr->OnDestructObject(this); + if (IsInWorld()) { sLog->outCrash("Object::~Object - guid=" UI64FMTD ", typeid=%d, entry=%u deleted but still in world!!", GetGUID(), GetTypeId(), GetEntry()); diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index a968352744..ffbe5bf1f1 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -15,6 +15,7 @@ #include "Log.h" #include "ObjectMgr.h" #include "Pet.h" +#include "ScriptMgr.h" #include "SpellAuraEffects.h" #include "SpellAuras.h" #include "SpellMgr.h" @@ -1073,6 +1074,8 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) } } + sScriptMgr->OnInitStatsForLevel(this, petlevel); + UpdateAllStats(); SetFullHealth(); @@ -1585,7 +1588,7 @@ void Pet::InitLevelupSpellsForLevel() for (PetLevelupSpellSet::const_reverse_iterator itr = levelupSpells->rbegin(); itr != levelupSpells->rend(); ++itr) { // will called first if level down - if (itr->first > level) + if (itr->first > level && sScriptMgr->CanUnlearnSpellSet(this, itr->first, itr->second)) unlearnSpell(itr->second, true); // will learn prev rank if any // will called if level up else @@ -1605,7 +1608,7 @@ void Pet::InitLevelupSpellsForLevel() continue; // will called first if level down - if (spellEntry->SpellLevel > level) + if (spellEntry->SpellLevel > level && sScriptMgr->CanUnlearnSpellDefault(this, spellEntry)) unlearnSpell(spellEntry->Id, true); // will called if level up else @@ -1710,6 +1713,9 @@ bool Pet::resetTalents() if (!owner || owner->GetTypeId() != TYPEID_PLAYER) return false; + if (!sScriptMgr->CanResetTalents(this)) + return false; + // not need after this call if (owner->ToPlayer()->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) owner->ToPlayer()->RemoveAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS, true); @@ -1863,16 +1869,17 @@ void Pet::InitTalentForLevel() { uint8 level = getLevel(); uint32 talentPointsForLevel = GetMaxTalentPointsForLevel(level); + + Unit* owner = GetOwner(); + if (!owner || owner->GetTypeId() != TYPEID_PLAYER) + return; + // Reset talents in case low level (on level down) or wrong points for level (hunter can unlearn TP increase talent) if (talentPointsForLevel == 0 || m_usedTalentCount > talentPointsForLevel) resetTalents(); // Remove all talent points SetFreeTalentPoints(talentPointsForLevel - m_usedTalentCount); - Unit* owner = GetOwner(); - if (!owner || owner->GetTypeId() != TYPEID_PLAYER) - return; - if (!m_loading) owner->ToPlayer()->SendTalentsInfoData(true); } @@ -1883,6 +1890,9 @@ uint8 Pet::GetMaxTalentPointsForLevel(uint8 level) // Mod points from owner SPELL_AURA_MOD_PET_TALENT_POINTS if (Unit* owner = GetOwner()) points += owner->GetTotalAuraModifier(SPELL_AURA_MOD_PET_TALENT_POINTS); + + sScriptMgr->OnCalculateMaxTalentPointsForLevel(this, level, points); + return points; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index c12fbdae1d..304246f28b 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -611,9 +611,9 @@ void KillRewarder::_RewardPlayer(Player* player, bool isDungeon) // Give reputation and kill credit only in PvE. if (!_isPvP || _isBattleGround) { - const float rate = _group ? - _groupRate * float(player->getLevel()) / _sumLevel : // Group rate depends on summary level. - 1.0f; // Personal rate is 100%. + float rate = _group ? _groupRate * float(player->getLevel()) / _sumLevel : /*Personal rate is 100%.*/ 1.0f; // Group rate depends on summary level. + + sScriptMgr->OnRewardKillRewarder(player, isDungeon, rate); // Personal rate is 100%. if (_xp) // 4.2. Give XP. _RewardXP(player, rate); @@ -976,10 +976,14 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this) m_applyResilience = true; m_isInstantFlightOn = true; + + sScriptMgr->OnConstructPlayer(this); } Player::~Player() { + sScriptMgr->OnDestructPlayer(this); + // it must be unloaded already in PlayerLogout and accessed only for loggined player //m_social = nullptr; @@ -3389,7 +3393,8 @@ void Player::GiveLevel(uint8 level) if (Pet* pet = GetPet()) pet->SynchronizeLevelWithOwner(); - if (MailLevelReward const* mailReward = sObjectMgr->GetMailLevelReward(level, getRaceMask())) + MailLevelReward const* mailReward = sObjectMgr->GetMailLevelReward(level, getRaceMask()); + if (mailReward && sScriptMgr->CanGiveMailRewardAtGiveLevel(this, level)) { //- TODO: Poor design of mail system SQLTransaction trans = CharacterDatabase.BeginTransaction(); @@ -5144,6 +5149,8 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC stmt->setUInt32(0, guid); trans->Append(stmt); + sScriptMgr->OnDeleteFromDB(trans, guid); + CharacterDatabase.CommitTransaction(trans); break; } @@ -5713,6 +5720,9 @@ void Player::RepopAtGraveyard() AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetAreaId()); + if (!sScriptMgr->CanRepopAtGraveyard(this)) + return; + // Such zones are considered unreachable as a ghost and the player must be automatically revived // Xinef: Get Transport Check is not needed if ((!IsAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) /*|| GetTransport()*/ || GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY())) @@ -6803,6 +6813,7 @@ uint16 Player::GetMaxSkillValue(uint32 skill) const uint32 bonus = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos)); int32 result = int32(SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos)))); + sScriptMgr->OnGetMaxSkillValue(const_cast<Player*>(this), skill, result, false); result += SKILL_TEMP_BONUS(bonus); result += SKILL_PERM_BONUS(bonus); return result < 0 ? 0 : result; @@ -6817,7 +6828,11 @@ uint16 Player::GetPureMaxSkillValue(uint32 skill) const if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return 0; - return SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos))); + int32 result = int32(SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos)))); + + sScriptMgr->OnGetMaxSkillValue(const_cast<Player*>(this), skill, result, true); + + return result < 0 ? 0 : result; } uint16 Player::GetBaseSkillValue(uint32 skill) const @@ -7075,6 +7090,9 @@ void Player::CheckAreaExploreAndOutdoor() if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !isOutdoor) RemoveAurasWithAttribute(SPELL_ATTR0_OUTDOORS_ONLY); + if (!sScriptMgr->CanAreaExploreAndOutdoor(this)) + return; + if (!areaId) return; @@ -7466,6 +7484,8 @@ bool Player::RewardHonor(Unit* uVictim, uint32 groupsize, int32 honor, bool awar // [29..38] Other title and player name // [39+] Nothing uint32 victim_title = victim->GetUInt32Value(PLAYER_CHOSEN_TITLE); + uint32 killer_title = 0; + sScriptMgr->OnVictimRewardBefore(this, victim, killer_title, victim_title); // Get Killer titles, CharTitlesEntry::bit_index // Ranks: // title[1..14] -> rank[5..18] @@ -7492,6 +7512,7 @@ bool Player::RewardHonor(Unit* uVictim, uint32 groupsize, int32 honor, bool awar UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA, GetAreaId()); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL, 1, 0, victim); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL, 1, 0, victim); + sScriptMgr->OnVictimRewardAfter(this, victim, killer_title, victim_rank, honor_f); } else { @@ -7646,14 +7667,6 @@ uint32 Player::GetArenaTeamIdFromStorage(uint32 guid, uint8 slot) return 0; } -void Player::SetArenaTeamInfoField(uint8 slot, ArenaTeamInfoType type, uint32 value) -{ - if (slot < MAX_ARENA_SLOT) - { - SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + type, value); - } -} - uint32 Player::GetArenaTeamIdFromDB(uint64 guid, uint8 type) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ARENA_TEAM_ID_BY_PLAYER_GUID); @@ -8081,6 +8094,12 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply // req. check at equip, but allow use for extended range if range limit max level, set proper level uint32 ssd_level = getLevel(); + uint32 CustomScalingStatValue = 0; + + sScriptMgr->OnCustomScalingStatValueBefore(this, proto, slot, apply, CustomScalingStatValue); + + uint32 ScalingStatValue = proto->ScalingStatValue > 0 ? proto->ScalingStatValue : CustomScalingStatValue; + if (ssd && ssd_level > ssd->MaxLevel) ssd_level = ssd->MaxLevel; @@ -8093,17 +8112,30 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply uint32 statType = 0; int32 val = 0; // If set ScalingStatDistribution need get stats and values from it - if (ssd && ssv) + if (ssv) { - if (ssd->StatMod[i] < 0) - continue; - statType = ssd->StatMod[i]; - val = (ssv->getssdMultiplier(proto->ScalingStatValue) * ssd->Modifier[i]) / 10000; + if (ssd) + { + if (ssd->StatMod[i] < 0) + continue; + + statType = ssd->StatMod[i]; + val = (ssv->getssdMultiplier(ScalingStatValue) * ssd->Modifier[i]) / 10000; + } + else + { + if (i >= proto->StatsCount) + continue; + + // OnCustomScalingStatValue(Player* player, ItemTemplate const* proto, uint32& statType, int32& val, uint8 itemProtoStatNumber, uint32 ScalingStatValue, ScalingStatValuesEntry const* ssv) + sScriptMgr->OnCustomScalingStatValue(this, proto, statType, val, i, ScalingStatValue, ssv); + } } else { if (i >= proto->StatsCount) continue; + statType = proto->ItemStat[i].ItemStatType; val = proto->ItemStat[i].ItemStatValue; } @@ -8262,15 +8294,16 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply // Apply Spell Power from ScalingStatValue if set if (ssv) - if (int32 spellbonus = ssv->getSpellBonus(proto->ScalingStatValue)) + if (int32 spellbonus = ssv->getSpellBonus(ScalingStatValue)) ApplySpellPowerBonus(spellbonus, apply); // If set ScalingStatValue armor get it or use item armor uint32 armor = proto->Armor; if (ssv) { - if (uint32 ssvarmor = ssv->getArmorMod(proto->ScalingStatValue)) - armor = ssvarmor; + if (uint32 ssvarmor = ssv->getArmorMod(ScalingStatValue)) + if (proto->ScalingStatValue > 0 || ssvarmor < proto->Armor) //Check to avoid higher values than stat itself (heirloom OR items with correct armor value) + armor = ssvarmor; } else if (armor && proto->ArmorDamageModifier) armor -= uint32(proto->ArmorDamageModifier); @@ -8295,7 +8328,7 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply } // Add armor bonus from ArmorDamageModifier if > 0 - if (proto->ArmorDamageModifier > 0) + if (proto->ArmorDamageModifier > 0 && sScriptMgr->CanArmorDamageModifier(this)) HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(proto->ArmorDamageModifier), apply); if (proto->Block) @@ -8342,11 +8375,12 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply int32 feral_bonus = 0; if (ssv) { - dpsMod = ssv->getDPSMod(proto->ScalingStatValue); - feral_bonus += ssv->getFeralBonus(proto->ScalingStatValue); + dpsMod = ssv->getDPSMod(ScalingStatValue); + feral_bonus += ssv->getFeralBonus(ScalingStatValue); } feral_bonus += proto->getFeralBonus(dpsMod); + sScriptMgr->OnGetFeralApBonus(this, feral_bonus, dpsMod, proto, ssv); if (feral_bonus) ApplyFeralAPBonus(feral_bonus, apply); } @@ -8354,6 +8388,27 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingStatValuesEntry const* ssv, bool apply) { + uint32 CustomScalingStatValue = 0; + + sScriptMgr->OnCustomScalingStatValueBefore(this, proto, slot, apply, CustomScalingStatValue); + + uint32 ScalingStatValue = proto->ScalingStatValue > 0 ? proto->ScalingStatValue : CustomScalingStatValue; + + // following part fix disarm issue + // that doesn't apply the scaling after disarmed + if (!ssv) + { + ScalingStatDistributionEntry const* ssd = proto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution) : nullptr; + + // req. check at equip, but allow use for extended range if range limit max level, set proper level + uint32 ssd_level = getLevel(); + + if (ssd && ssd_level > ssd->MaxLevel) + ssd_level = ssd->MaxLevel; + + ssv = ScalingStatValue ? sScalingStatValuesStore.LookupEntry(ssd_level) : nullptr; + } + WeaponAttackType attType = BASE_ATTACK; float damage = 0.0f; @@ -8374,7 +8429,7 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt // If set dpsMod in ScalingStatValue use it for min (70% from average), max (130% from average) damage if (ssv) { - int32 extraDPS = ssv->getDPSMod(proto->ScalingStatValue); + int32 extraDPS = ssv->getDPSMod(ScalingStatValue); if (extraDPS) { float average = extraDPS * proto->Delay / 1000.0f; @@ -8438,6 +8493,9 @@ void Player::_ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attac if (aura->GetSpellInfo()->EquippedItemClass == -1) return; + if (!sScriptMgr->CanApplyWeaponDependentAuraDamageMod(this, item, attackType, aura, apply)) + return; + BaseModGroup mod = BASEMOD_END; switch (attackType) { @@ -8548,6 +8606,9 @@ void Player::ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply, { if (apply) { + if (!sScriptMgr->CanApplyEquipSpell(this, spellInfo, item, apply, form_change)) + return; + // Cannot be used in this stance/form if (spellInfo->CheckShapeshift(GetShapeshiftForm()) != SPELL_CAST_OK) return; @@ -8619,6 +8680,8 @@ void Player::UpdateEquipSpellsAtFormChange() continue; ApplyEquipSpell(spellInfo, nullptr, false, true); // remove spells that not fit to form + if (!sScriptMgr->CanApplyEquipSpellsItemSet(this, eff)) + break; ApplyEquipSpell(spellInfo, nullptr, true, true); // add spells that fit form but not active } } @@ -8671,6 +8734,9 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto) { + if (!sScriptMgr->CanCastItemCombatSpell(this, target, attType, procVictim, procEx, item, proto)) + return; + // Can do effect if any damage done to target if (procVictim & PROC_FLAG_TAKEN_DAMAGE) //if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE) @@ -8794,6 +8860,9 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 cast_count, uint32 glyphIndex) { + if (!sScriptMgr->CanCastItemUseSpell(this, item, targets, cast_count, glyphIndex)) + return; + ItemTemplate const* proto = item->GetTemplate(); // special learning case if (proto->Spells[0].SpellId == 483 || proto->Spells[0].SpellId == 55884) @@ -9056,6 +9125,8 @@ void Player::_ApplyAmmoBonuses() else currentAmmoDPS = (ammo_proto->Damage[0].DamageMin + ammo_proto->Damage[0].DamageMax) / 2; + sScriptMgr->OnApplyAmmoBonuses(this, ammo_proto, currentAmmoDPS); + if (currentAmmoDPS == GetAmmoDPS()) return; @@ -12047,6 +12118,9 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16& dest, Item* pItem, bool ItemTemplate const* pProto = pItem->GetTemplate(); if (pProto) { + if (!sScriptMgr->CanEquipItem(const_cast<Player*>(this), slot, dest, pItem, swap, not_loading)) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; + // item used if (pItem->m_lootGenerated) return EQUIP_ERR_ALREADY_LOOTED; @@ -12208,6 +12282,9 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16& dest, Item* pItem, bool InventoryResult Player::CanUnequipItem(uint16 pos, bool swap) const { + if (!sScriptMgr->CanUnequipItem(const_cast<Player*>(this), pos, swap)) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; + // Applied only to equipped items and bank bags if (!IsEquipmentPos(pos) && !IsBagPos(pos)) return EQUIP_ERR_OK; @@ -12529,6 +12606,11 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const if (proto->RequiredSpell != 0 && !HasSpell(proto->RequiredSpell)) return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + InventoryResult result = EQUIP_ERR_OK; + + if (!sScriptMgr->CanUseItem(const_cast<Player*>(this), proto, result)) + return result; + if (getLevel() < proto->RequiredLevel) return EQUIP_ERR_CANT_EQUIP_LEVEL_I; @@ -12872,7 +12954,11 @@ Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool Item* Player::EquipNewItem(uint16 pos, uint32 item, bool update) { - if (Item* pItem = Item::CreateItem(item, 1, this)) + Item* _item = Item::CreateItem(item, 1, this); + if (!_item) + return nullptr; + + if (!IsEquipmentPos(pos) || sScriptMgr->CanSaveEquipNewItem(this, _item, pos, update)) { // pussywizard: obtaining blue or better items saves to db if (ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item)) @@ -12881,10 +12967,9 @@ Item* Player::EquipNewItem(uint16 pos, uint32 item, bool update) ItemAddedQuestCheck(item, 1); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, item, 1); - return EquipItem(pos, pItem, update); } - return nullptr; + return EquipItem(pos, _item, update); } Item* Player::EquipItem(uint16 pos, Item* pItem, bool update) @@ -14497,6 +14582,9 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool if (pEnchant->requiredSkill > 0 && pEnchant->requiredSkillValue > GetSkillValue(pEnchant->requiredSkill)) return; + if (!sScriptMgr->CanApplyEnchantment(this, item, slot, apply, apply_dur, ignore_condition)) + return; + // If we're dealing with a gem inside a prismatic socket we need to check the prismatic socket requirements // rather than the gem requirements itself. If the socket has no color it is a prismatic socket. if ((slot == SOCK_ENCHANTMENT_SLOT || slot == SOCK_ENCHANTMENT_SLOT_2 || slot == SOCK_ENCHANTMENT_SLOT_3) @@ -16096,7 +16184,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, bool rewarded = IsQuestRewarded(quest_id) && !quest->IsDFQuest(); // Not give XP in case already completed once repeatable quest - uint32 XP = rewarded ? 0 : uint32(quest->XPValue(this) * sWorld->getRate(RATE_XP_QUEST)); + uint32 XP = rewarded ? 0 : uint32(quest->XPValue(this) * GetQuestRate()); // handle SPELL_AURA_MOD_XP_QUEST_PCT auras Unit::AuraEffectList const& ModXPPctAuras = GetAuraEffectsByType(SPELL_AURA_MOD_XP_QUEST_PCT); @@ -17252,6 +17340,9 @@ void Player::KilledMonsterCredit(uint32 entry, uint64 guid) if (q_status.Status == QUEST_STATUS_INCOMPLETE && (!GetGroup() || !GetGroup()->isRaidGroup() || qInfo->IsAllowedInRaid(GetMap()->GetDifficulty()) || (qInfo->IsPVPQuest() && (GetGroup()->isBFGroup() || GetGroup()->isBGGroup())))) { + if (!sScriptMgr->PassedQuestKilledMonsterCredit(this, qInfo, entry, real_entry, guid)) + continue; + if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL) /*&& !qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_CAST)*/) { for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j) @@ -17801,8 +17892,8 @@ void Player::_LoadArenaTeamInfo() { memset((void*)&m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1], 0, sizeof(uint32) * MAX_ARENA_SLOT * ARENA_TEAM_END); - for (uint8 slot = 0; slot < MAX_ARENA_SLOT; ++slot) - if (uint32 arenaTeamId = Player::GetArenaTeamIdFromStorage(GetGUIDLow(), slot)) + for (auto const& itr : ArenaTeam::ArenaSlotByType) + if (uint32 arenaTeamId = Player::GetArenaTeamIdFromStorage(GetGUIDLow(), itr.second)) { ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId); if (!arenaTeam) // some shit, should be assert, but just ignore @@ -17811,6 +17902,8 @@ void Player::_LoadArenaTeamInfo() if (!member) // some shit, should be assert, but just ignore continue; + uint8 slot = itr.second; + SetArenaTeamInfoField(slot, ARENA_TEAM_ID, arenaTeamId); SetArenaTeamInfoField(slot, ARENA_TEAM_TYPE, arenaTeam->GetType()); SetArenaTeamInfoField(slot, ARENA_TEAM_MEMBER, (arenaTeam->GetCaptain() == GetGUID()) ? 0 : 1); @@ -18874,7 +18967,8 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) else if (IsEquipmentPos(INVENTORY_SLOT_BAG_0, slot)) { uint16 dest; - err = CanEquipItem(slot, dest, item, false, false); + if (sScriptMgr->CheckItemInSlotAtLoadInventory(this, item, slot, err, dest)) + err = CanEquipItem(slot, dest, item, false, false); if (err == EQUIP_ERR_OK) QuickEquipItem(dest, item); } @@ -19858,6 +19952,9 @@ bool Player::Satisfy(DungeonProgressionRequirements const* ar, uint32 target_map || missingPlayerItems.size() || missingPlayerQuests.size() || missingPlayerAchievements.size() || missingLeaderItems.size() || missingLeaderQuests.size() || missingLeaderAchievements.size()) { + if (!sScriptMgr->NotAvoidSatisfy(partyLeader, ar, target_map, report)) + return true; + if (report) { uint8 requirementPrintMode = sWorld->getIntConfig(CONFIG_DUNGEON_ACCESS_REQUIREMENTS_PRINT_MODE); @@ -22020,36 +22117,6 @@ void Player::LeaveAllArenaTeams(uint64 guid) } while (result->NextRow()); } -uint32 Player::GetArenaTeamId(uint8 slot) const -{ - uint32 rtVal = 0; - if (slot >= MAX_ARENA_SLOT) - { - sScriptMgr->GetCustomGetArenaTeamId(this, slot, rtVal); - } - else - { - rtVal = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + ARENA_TEAM_ID); - } - - return rtVal; -} - -uint32 Player::GetArenaPersonalRating(uint8 slot) const -{ - uint32 rtVal = 0; - if (slot >= MAX_ARENA_SLOT) - { - sScriptMgr->GetCustomGetArenaTeamId(this, slot, rtVal); - } - else - { - rtVal = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + ARENA_TEAM_PERSONAL_RATING); - } - - return rtVal; -} - void Player::SetRestBonus(float rest_bonus_new) { // Prevent resting on max level @@ -22492,9 +22559,9 @@ inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 c } } - Item* it = bStore ? - StoreNewItem(vDest, item, true) : - EquipNewItem(uiDest, item, true); + sScriptMgr->OnBeforeStoreOrEquipNewItem(this, vendorslot, item, count, bag, slot, pProto, pVendor, crItem, bStore); + + Item* it = bStore ? StoreNewItem(vDest, item, true) : EquipNewItem(uiDest, item, true); if (it) { uint32 new_count = pVendor->UpdateVendorItemCurrentCount(crItem, pProto->BuyCount * count); @@ -22520,6 +22587,9 @@ inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 c AddRefundReference(it->GetGUIDLow()); } } + + sScriptMgr->OnAfterStoreOrEquipNewItem(this, vendorslot, it, count, bag, slot, pProto, pVendor, crItem, bStore); + return true; } @@ -23371,6 +23441,9 @@ bool Player::IsVisibleGloballyFor(Player const* u) const if (!AccountMgr::IsPlayerAccount(u->GetSession()->GetSecurity())) return GetSession()->GetSecurity() <= u->GetSession()->GetSecurity(); + if (!sScriptMgr->NotVisibleGloballyFor(const_cast<Player*>(this), u)) + return true; + // non faction visibility non-breakable for non-GMs return false; } @@ -28457,3 +28530,77 @@ void Player::RemoveRestFlag(RestFlag restFlag) RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); } } + +void Player::SetArenaTeamInfoField(uint8 slot, ArenaTeamInfoType type, uint32 value) +{ + if (sScriptMgr->NotSetArenaTeamInfoField(this, slot, type, value)) + SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + type, value); +} + +uint32 Player::GetArenaPersonalRating(uint8 slot) const +{ + uint32 result = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + ARENA_TEAM_PERSONAL_RATING); + + sScriptMgr->OnGetArenaPersonalRating(const_cast<Player*>(this), slot, result); + + return result; +} + +uint32 Player::GetArenaTeamId(uint8 slot) const +{ + uint32 result = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + ARENA_TEAM_ID); + + sScriptMgr->OnGetArenaTeamId(const_cast<Player*>(this), slot, result); + + return result; +} + +bool Player::IsFFAPvP() +{ + bool result = Unit::IsFFAPvP(); + + sScriptMgr->OnIsFFAPvP(this, result); + + return result; +} + +bool Player::IsPvP() +{ + bool result = Unit::IsPvP(); + + sScriptMgr->OnIsPvP(this, result); + + return result; +} + +uint16 Player::GetMaxSkillValueForLevel() const +{ + uint16 result = Unit::GetMaxSkillValueForLevel(); + + sScriptMgr->OnGetMaxSkillValueForLevel(const_cast<Player*>(this), result); + + return result; +} + +float Player::GetQuestRate() +{ + float result = sWorld->getRate(RATE_XP_QUEST); + + sScriptMgr->OnGetQuestRate(this, result); + + return result; +} + +void Player::SetServerSideVisibility(ServerSideVisibilityType type, AccountTypes sec) +{ + sScriptMgr->OnSetServerSideVisibility(this, type, sec); + + m_serverSideVisibility.SetValue(type, sec); +} + +void Player::SetServerSideVisibilityDetect(ServerSideVisibilityType type, AccountTypes sec) +{ + sScriptMgr->OnSetServerSideVisibilityDetect(this, type, sec); + + m_serverSideVisibilityDetect.SetValue(type, sec); +} diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 051a0c8760..802556dbe7 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -11,6 +11,7 @@ #include "DBCStores.h" #include "GroupReference.h" #include "InstanceSaveMgr.h" +#include "ArenaTeam.h" #include "Item.h" #include "MapReference.h" #include "ObjectMgr.h" @@ -705,19 +706,6 @@ enum InstanceResetWarningType RAID_INSTANCE_EXPIRED = 5 }; -// PLAYER_FIELD_ARENA_TEAM_INFO_1_1 offsets -enum ArenaTeamInfoType -{ - ARENA_TEAM_ID = 0, - ARENA_TEAM_TYPE = 1, // new in 3.2 - team type? - ARENA_TEAM_MEMBER = 2, // 0 - captain, 1 - member - ARENA_TEAM_GAMES_WEEK = 3, - ARENA_TEAM_GAMES_SEASON = 4, - ARENA_TEAM_WINS_SEASON = 5, - ARENA_TEAM_PERSONAL_RATING = 6, - ARENA_TEAM_END = 7 -}; - class InstanceSave; enum RestFlag @@ -1466,7 +1454,7 @@ public: void RemoveRewardedQuest(uint32 questId, bool update = true); void SendQuestUpdate(uint32 questId); QuestGiverStatus GetQuestDialogStatus(Object* questGiver); - + float GetQuestRate(); void SetDailyQuestStatus(uint32 quest_id); bool IsDailyQuestDone(uint32 quest_id); void SetWeeklyQuestStatus(uint32 quest_id); @@ -1616,6 +1604,7 @@ public: [[nodiscard]] RewardedQuestSet const& getRewardedQuests() const { return m_RewardedQuests; } QuestStatusMap& getQuestStatusMap() { return m_QuestStatus; } + QuestStatusSaveMap& GetQuestStatusSaveMap() { return m_QuestStatusSave; } [[nodiscard]] size_t GetRewardedQuestCount() const { return m_RewardedQuests.size(); } [[nodiscard]] bool IsQuestRewarded(uint32 quest_id) const @@ -1915,10 +1904,10 @@ public: SetArenaTeamInfoField(slot, ARENA_TEAM_TYPE, type); } void SetArenaTeamInfoField(uint8 slot, ArenaTeamInfoType type, uint32 value); + uint32 GetArenaPersonalRating(uint8 slot) const; static uint32 GetArenaTeamIdFromDB(uint64 guid, uint8 slot); static void LeaveAllArenaTeams(uint64 guid); [[nodiscard]] uint32 GetArenaTeamId(uint8 slot) const; - [[nodiscard]] uint32 GetArenaPersonalRating(uint8 slot) const; void SetArenaTeamIdInvited(uint32 ArenaTeamId) { m_ArenaTeamIdInvited = ArenaTeamId; } uint32 GetArenaTeamIdInvited() { return m_ArenaTeamIdInvited; } @@ -2443,6 +2432,10 @@ public: void SendCinematicStart(uint32 CinematicSequenceId); void SendMovieStart(uint32 MovieId); + uint16 GetMaxSkillValueForLevel() const; + bool IsFFAPvP(); + bool IsPvP(); + /*********************************************************/ /*** INSTANCE SYSTEM ***/ /*********************************************************/ @@ -2619,6 +2612,9 @@ public: [[nodiscard]] uint32 GetNextSave() const { return m_nextSave; } [[nodiscard]] SpellModList const& GetSpellModList(uint32 type) const { return m_spellMods[type]; } + void SetServerSideVisibility(ServerSideVisibilityType type, AccountTypes sec); + void SetServerSideVisibilityDetect(ServerSideVisibilityType type, AccountTypes sec); + static std::unordered_map<int, bgZoneRef> bgZoneIdToFillWorldStates; // zoneId -> FillInitialWorldStates // Cinematic camera data and remote sight functions diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index b65b14e37b..c219cfc1f9 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -4363,6 +4363,8 @@ void Unit::RemoveAura(AuraApplicationMap::iterator& i, AuraRemoveMode mode) // Remove aura - for Area and Target auras if (aura->GetOwner() == this) aura->Remove(mode); + + sScriptMgr->OnAuraRemove(this, aurApp, mode); } void Unit::RemoveAura(uint32 spellId, uint64 caster, uint8 reqEffMask, AuraRemoveMode removeMode) @@ -9687,6 +9689,11 @@ ReputationRank Unit::GetReactionTo(Unit const* target) const } } } + + ReputationRank repRank = REP_HATED; + + if (!sScriptMgr->IfNormalReaction(this, target, repRank)) + return ReputationRank(repRank); // do checks dependant only on our faction return GetFactionReactionTo(GetFactionTemplateEntry(), target); } @@ -10782,6 +10789,9 @@ float Unit::SpellPctDamageModsDone(Unit* victim, SpellInfo const* spellProto, Da if (!spellProto->ValidateAttribute6SpellDamageMods(this, *i, damagetype == DOT)) continue; + if (!sScriptMgr->IsNeedModSpellDamagePercent(this, *i, DoneTotalMod, spellProto)) + continue; + if ((*i)->GetMiscValue() & spellProto->GetSchoolMask()) { if ((*i)->GetSpellInfo()->EquippedItemClass == -1) @@ -11784,8 +11794,13 @@ float Unit::SpellPctHealingModsDone(Unit* victim, SpellInfo const* spellProto, D // Healing done percent AuraEffectList const& mHealingDonePct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT); - for (AuraEffectList::const_iterator i = mHealingDonePct.begin(); i != mHealingDonePct.end(); ++i) - AddPct(DoneTotalMod, (*i)->GetAmount()); + for (auto const& auraEff : mHealingDonePct) + { + if (!sScriptMgr->IsNeedModHealPercent(this, auraEff, DoneTotalMod, spellProto)) + continue; + + AddPct(DoneTotalMod, auraEff->GetAmount()); + } // done scripted mod (take it from owner) Unit* owner = GetOwner() ? GetOwner() : this; @@ -12400,6 +12415,9 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType if (!spellProto->ValidateAttribute6SpellDamageMods(this, *i, false)) continue; + if (!sScriptMgr->IsNeedModMeleeDamagePercent(this, *i, DoneTotalMod, spellProto)) + continue; + if (((*i)->GetMiscValue() & spellProto->GetSchoolMask()) && !((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) { if ((*i)->GetSpellInfo()->EquippedItemClass == -1) @@ -18230,6 +18248,9 @@ void Unit::SetPhaseMask(uint32 newPhaseMask, bool update) // pussywizard: goign to other phase (valithria, algalon) should not remove such auras //RemoveNotOwnSingleTargetAuras(newPhaseMask, true); // we can lost access to caster or target + if (!sScriptMgr->CanSetPhaseMask(this, newPhaseMask, update)) + return; + // modify hostile references for new phasemask, some special cases deal with hostile references themselves if (GetTypeId() == TYPEID_UNIT || (!ToPlayer()->IsGameMaster() && !ToPlayer()->GetSession()->PlayerLogout())) { @@ -20077,7 +20098,10 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) fieldBuffer << (uint32)target->getFaction(); } else - fieldBuffer << m_uint32Values[index]; + if (!sScriptMgr->IsCustomBuildValuesUpdate(this, updateType, fieldBuffer, target, index)) + { + fieldBuffer << m_uint32Values[index]; + } } else // send in current format (float as float, uint32 as uint32) diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 72fd3cb72e..05db6332a0 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -59,10 +59,13 @@ Group::Group() : m_leaderGuid(0), m_leaderName(""), m_groupType(GROUPTYPE_NORMAL { for (uint8 i = 0; i < TARGETICONCOUNT; ++i) m_targetIcons[i] = 0; + sScriptMgr->OnConstructGroup(this); } Group::~Group() { + sScriptMgr->OnDestructGroup(this); + if (m_bgGroup) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) @@ -142,6 +145,8 @@ bool Group::Create(Player* leader) CharacterDatabase.Execute(stmt); ASSERT(AddMember(leader)); // If the leader can't be added to a new group because it appears full, something is clearly wrong. + + sScriptMgr->OnCreate(this, leader); } else if (!AddMember(leader)) return false; @@ -1840,6 +1845,9 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const* if (!member) return ERR_BATTLEGROUND_JOIN_FAILED; + if (!sScriptMgr->CanGroupJoinBattlegroundQueue(this, member, bgTemplate, MinPlayerCount, isRated, arenaSlot)) + return ERR_BATTLEGROUND_JOIN_FAILED; + // don't allow cross-faction groups to join queue if (member->GetTeamId() != teamId) return ERR_BATTLEGROUND_JOIN_TIMED_OUT; diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 450b14b39f..b45c2fb12d 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -2875,6 +2875,9 @@ void Guild::_BroadcastEvent(GuildEvents guildEvent, uint64 guid, const char* par void Guild::_SendBankList(WorldSession* session /* = nullptr*/, uint8 tabId /*= 0*/, bool sendAllSlots /*= false*/, SlotIds* slots /*= nullptr*/) const { + if (!sScriptMgr->CanGuildSendBankList(this, session, tabId, sendAllSlots)) + return; + WorldPacket data(SMSG_GUILD_BANK_LIST, 500); data << uint64(m_bankMoney); data << uint8(tabId); diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index e351546d30..4fb8426ce2 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -756,6 +756,9 @@ public: void ResetTimes(); + [[nodiscard]] bool ModifyBankMoney(SQLTransaction& trans, const uint64& amount, bool add) { return _ModifyBankMoney(trans, amount, add); } + [[nodiscard]] uint32 GetMemberSize() const { return m_members.size(); } + protected: uint32 m_id; std::string m_name; diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp index d4d698553e..a3241a4a7e 100644 --- a/src/server/game/Handlers/AuctionHouseHandler.cpp +++ b/src/server/game/Handlers/AuctionHouseHandler.cpp @@ -12,6 +12,7 @@ #include "Log.h" #include "ObjectMgr.h" #include "Opcodes.h" +#include "ScriptMgr.h" #include "Player.h" #include "UpdateMask.h" #include "Util.h" @@ -50,6 +51,9 @@ void WorldSession::SendAuctionHello(uint64 guid, Creature* unit) return; } + if (!sScriptMgr->CanSendAuctionHello(this, guid, unit)) + return; + AuctionHouseEntry const* ahEntry = AuctionHouseMgr::GetAuctionHouseEntry(unit->getFaction()); if (!ahEntry) return; diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp index ccfd82efaa..1fde7b10ab 100644 --- a/src/server/game/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -388,6 +388,9 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData) BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, arenaType); BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); + if (!sScriptMgr->CanBattleFieldPort(_player, arenaType, bgTypeId, action)) + return; + // get group info from queue GroupQueueInfo ginfo; if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) @@ -658,6 +661,14 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData) // queue result (default ok) GroupJoinBattlegroundResult err = GroupJoinBattlegroundResult(bgt->GetBgTypeID()); + if (!sScriptMgr->CanJoinInArenaQueue(_player, guid, arenaslot, bgTypeId, asGroup, isRated, err) && err <= 0) + { + WorldPacket data; + sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); + SendPacket(&data); + return; + } + // check if player can queue: if (!asGroup) { diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp index e28dfac518..0920474e6d 100644 --- a/src/server/game/Handlers/GroupHandler.cpp +++ b/src/server/game/Handlers/GroupHandler.cpp @@ -14,6 +14,7 @@ #include "Opcodes.h" #include "Pet.h" #include "Player.h" +#include "ScriptMgr.h" #include "SocialMgr.h" #include "SpellAuras.h" #include "Util.h" @@ -74,6 +75,9 @@ void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData) return; } + if (!sScriptMgr->CanGroupInvite(GetPlayer(), membername)) + return; + if (GetPlayer()->IsSpectator() || player->IsSpectator()) { SendPartyResult(PARTY_OP_INVITE, membername, ERR_INVITE_RESTRICTED); @@ -224,6 +228,9 @@ void WorldSession::HandleGroupAcceptOpcode(WorldPacket& recvData) return; } + if (!sScriptMgr->CanGroupAccept(GetPlayer(), group)) + return; + if (group->GetLeaderGUID() == GetPlayer()->GetGUID()) { sLog->outError("HandleGroupAcceptOpcode: player %s(%d) tried to accept an invite to his own group", GetPlayer()->GetName().c_str(), GetPlayer()->GetGUIDLow()); diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index b88c60acff..205c73ba4e 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -11,6 +11,7 @@ #include "ObjectMgr.h" #include "Opcodes.h" #include "Player.h" +#include "ScriptMgr.h" #include "SpellInfo.h" #include "UpdateData.h" #include "WorldPacket.h" @@ -660,6 +661,9 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData) Item* pItem = _player->GetItemByGuid(itemguid); if (pItem) { + if (!sScriptMgr->CanSellItem(_player, pItem, creature)) + return; + // prevent sell not owner item if (_player->GetGUID() != pItem->GetOwnerGUID()) { diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index 0b27534585..81e370eed7 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -14,6 +14,7 @@ #include "ObjectMgr.h" #include "Opcodes.h" #include "Player.h" +#include "ScriptMgr.h" #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" @@ -196,9 +197,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) } }*/ - uint32 rc_account = receive - ? receive->GetSession()->GetAccountId() - : sObjectMgr->GetPlayerAccountIdByGUID(rc); + uint32 rc_account = receive ? receive->GetSession()->GetAccountId() : sObjectMgr->GetPlayerAccountIdByGUID(rc); if (/*!accountBound*/ GetAccountId() != rc_account && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && player->GetTeamId() != rc_teamId && AccountMgr::IsPlayerAccount(GetSecurity())) { @@ -255,6 +254,9 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) return; } + if (!sScriptMgr->CanSendMail(player, rc, mailbox, subject, body, money, COD, item)) + return; + items[i] = item; } diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index fce810b9c6..6f06b9b3d2 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -1019,6 +1019,8 @@ void WorldSession::HandleRepairItemOpcode(WorldPacket& recvData) // reputation discount float discountMod = _player->GetReputationPriceDiscount(unit); + sScriptMgr->OnBeforePlayerDurabilityRepair(_player, npcGUID, itemGUID, discountMod, guildBank); + if (itemGUID) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) diff --git a/src/server/game/Handlers/PetitionsHandler.cpp b/src/server/game/Handlers/PetitionsHandler.cpp index bfcfcb3f56..dda123537e 100644 --- a/src/server/game/Handlers/PetitionsHandler.cpp +++ b/src/server/game/Handlers/PetitionsHandler.cpp @@ -15,22 +15,12 @@ #include "ObjectMgr.h" #include "Opcodes.h" #include "PetitionMgr.h" +#include "ScriptMgr.h" #include "SocialMgr.h" #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" -#define CHARTER_DISPLAY_ID 16161 - -// Charters ID in item_template -enum CharterItemIDs -{ - GUILD_CHARTER = 5863, - ARENA_TEAM_CHARTER_2v2 = 23560, - ARENA_TEAM_CHARTER_3v3 = 23561, - ARENA_TEAM_CHARTER_5v5 = 23562 -}; - void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) @@ -136,6 +126,8 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData) } } + sScriptMgr->PetitionBuy(_player, creature, charterid, cost, type); + if (type == GUILD_CHARTER_TYPE) { if (sGuildMgr->GetGuildByName(name)) @@ -880,38 +872,65 @@ void WorldSession::SendPetitionShowList(uint64 guid) WorldPacket data(SMSG_PETITION_SHOWLIST, 8 + 1 + 4 * 6); data << guid; // npc guid + // For guild default + uint32 CharterEntry = GUILD_CHARTER; + uint32 CharterDispayID = CHARTER_DISPLAY_ID; + uint32 CharterCost = sWorld->getIntConfig(CONFIG_CHARTER_COST_GUILD); + if (creature->IsTabardDesigner()) { + sScriptMgr->PetitionShowList(_player, creature, CharterEntry, CharterDispayID, CharterCost); + data << uint8(1); // count data << uint32(1); // index - data << uint32(GUILD_CHARTER); // charter entry - data << uint32(CHARTER_DISPLAY_ID); // charter display id - data << uint32(sWorld->getIntConfig(CONFIG_CHARTER_COST_GUILD)); // charter cost + data << CharterEntry; // charter entry + data << CharterDispayID; // charter display id + data << CharterCost; // charter cost data << uint32(0); // unknown data << uint32(sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS)); // required signs } else { - data << uint8(3); // count + // For 2v2 default + CharterEntry = ARENA_TEAM_CHARTER_2v2; + CharterDispayID = CHARTER_DISPLAY_ID; + CharterCost = sWorld->getIntConfig(CONFIG_CHARTER_COST_ARENA_2v2); + // 2v2 + data << uint8(3); // count + sScriptMgr->PetitionShowList(_player, creature, CharterEntry, CharterDispayID, CharterCost); data << uint32(1); // index - data << uint32(ARENA_TEAM_CHARTER_2v2); // charter entry - data << uint32(CHARTER_DISPLAY_ID); // charter display id - data << uint32(sWorld->getIntConfig(CONFIG_CHARTER_COST_ARENA_2v2)); // charter cost + data << CharterEntry; // charter entry + data << CharterDispayID; // charter display id + data << CharterCost; // charter cost data << uint32(2); // unknown data << uint32(2); // required signs? + + // For 3v3 default + CharterEntry = ARENA_TEAM_CHARTER_3v3; + CharterDispayID = CHARTER_DISPLAY_ID; + CharterCost = sWorld->getIntConfig(CONFIG_CHARTER_COST_ARENA_3v3); + // 3v3 + sScriptMgr->PetitionShowList(_player, creature, CharterEntry, CharterDispayID, CharterCost); data << uint32(2); // index - data << uint32(ARENA_TEAM_CHARTER_3v3); // charter entry - data << uint32(CHARTER_DISPLAY_ID); // charter display id - data << uint32(sWorld->getIntConfig(CONFIG_CHARTER_COST_ARENA_3v3)); // charter cost + data << CharterEntry; // charter entry + data << CharterDispayID; // charter display id + data << CharterCost; // charter cost data << uint32(3); // unknown data << uint32(3); // required signs? + + // For 3v3 default + CharterEntry = ARENA_TEAM_CHARTER_5v5; + CharterDispayID = CHARTER_DISPLAY_ID; + CharterCost = sWorld->getIntConfig(CONFIG_CHARTER_COST_ARENA_5v5); + // 5v5 + sScriptMgr->PetitionShowList(_player, creature, CharterEntry, CharterDispayID, CharterCost); data << uint32(3); // index - data << uint32(ARENA_TEAM_CHARTER_5v5); // charter entry - data << uint32(CHARTER_DISPLAY_ID); // charter display id - data << uint32(sWorld->getIntConfig(CONFIG_CHARTER_COST_ARENA_5v5)); // charter cost + data << CharterEntry; // charter entry + data << CharterDispayID; // charter display id + data << CharterCost; // charter cost data << uint32(5); // unknown data << uint32(5); // required signs? } diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 1ffdf10081..4b5bc5285f 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -15,6 +15,7 @@ #include "ScriptMgr.h" #include "Spell.h" #include "SpellAuraEffects.h" +#include "ScriptMgr.h" #include "SpellAuras.h" #include "SpellMgr.h" #include "TemporarySummon.h" @@ -343,6 +344,8 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) uint8 castCount, castFlags; recvPacket >> castCount >> spellId >> castFlags; + uint32 oldSpellId = spellId; + #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: got cast spell packet, castCount: %u, spellId: %u, castFlags: %u, data length = %u", castCount, spellId, castFlags, (uint32)recvPacket.size()); #endif @@ -404,6 +407,11 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) } } + sScriptMgr->ValidateSpellAtCastSpell(_player, oldSpellId, spellId, castCount, castFlags); + + if (oldSpellId != spellId) + spellInfo = sSpellMgr->GetSpellInfo(spellId); + // Client is resending autoshot cast opcode when other spell is casted during shoot rotation // Skip it to prevent "interrupt" message if (spellInfo->IsAutoRepeatRangedSpell() && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) @@ -443,6 +451,9 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) } Spell* spell = new Spell(mover, spellInfo, TRIGGERED_NONE, 0, false); + + sScriptMgr->ValidateSpellAtCastSpellResult(_player, mover, spell, oldSpellId, spellId); + spell->m_cast_count = castCount; // set count of casts spell->prepare(&targets); } diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp index 7734f5bbef..ea93790f33 100644 --- a/src/server/game/Handlers/TradeHandler.cpp +++ b/src/server/game/Handlers/TradeHandler.cpp @@ -12,6 +12,7 @@ #include "ObjectAccessor.h" #include "Opcodes.h" #include "Player.h" +#include "ScriptMgr.h" #include "SocialMgr.h" #include "Spell.h" #include "World.h" @@ -640,6 +641,9 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) return; } + if (!sScriptMgr->CanInitTrade(_player, pOther)) + return; + // OK start trade _player->m_trade = new TradeData(_player, pOther); pOther->m_trade = new TradeData(pOther, _player); diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index fbba193363..1d23fe4317 100644 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -134,11 +134,14 @@ bool InstanceSaveManager::DeleteInstanceSaveIfNeeded(InstanceSave* save, bool sk InstanceSave::InstanceSave(uint16 MapId, uint32 InstanceId, Difficulty difficulty, time_t resetTime, time_t extendedResetTime) : m_resetTime(resetTime), m_extendedResetTime(extendedResetTime), m_instanceid(InstanceId), m_mapid(MapId), m_difficulty(IsSharedDifficultyMap(MapId) ? Difficulty(difficulty % 2) : difficulty), m_canReset(true), m_instanceData(""), m_completedEncounterMask(0) { + sScriptMgr->OnConstructInstanceSave(this); } InstanceSave::~InstanceSave() { ASSERT(m_playerList.empty()); + + sScriptMgr->OnDestructInstanceSave(this); } void InstanceSave::InsertToDB() @@ -169,6 +172,8 @@ void InstanceSave::InsertToDB() stmt->setUInt32(4, completedEncounters); stmt->setString(5, data); CharacterDatabase.Execute(stmt); + + sScriptMgr->OnInstanceSave(this); } time_t InstanceSave::GetResetTimeForDB() diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 662419ef0d..c40916dab3 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -503,6 +503,8 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo tab->Process(*this, store, lootMode, lootOwner); // Processing is done there, callback via Loot::AddItem() + sScriptMgr->OnAfterLootTemplateProcess(this, tab, store, lootOwner, personal, noEmptyError, lootMode); + // Setting access rights for group loot case Group* group = lootOwner->GetGroup(); if (!personal && group) diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index 818d196967..d05378a422 100644 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -22,6 +22,7 @@ #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Opcodes.h" +#include "ScriptMgr.h" #include "Player.h" #include "Transport.h" #include "World.h" @@ -153,6 +154,9 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck) char const* mapName = entry->name[player->GetSession()->GetSessionDbcLocale()]; + if (!sScriptMgr->CanEnterMap(player, entry, instance, mapDiff, loginCheck)) + return false; + Group* group = player->GetGroup(); if (entry->IsRaid()) { diff --git a/src/server/game/Petitions/PetitionMgr.h b/src/server/game/Petitions/PetitionMgr.h index 1401ea735b..175f1223d3 100644 --- a/src/server/game/Petitions/PetitionMgr.h +++ b/src/server/game/Petitions/PetitionMgr.h @@ -8,6 +8,17 @@ Xinef #include "Common.h" #include <map> +#define CHARTER_DISPLAY_ID 16161 + +// Charters ID in item_template +enum CharterItemIDs +{ + GUILD_CHARTER = 5863, + ARENA_TEAM_CHARTER_2v2 = 23560, + ARENA_TEAM_CHARTER_3v3 = 23561, + ARENA_TEAM_CHARTER_5v5 = 23562 +}; + typedef std::map<uint32, uint32> SignatureMap; struct Petition diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 2dda13f032..2a691b7ffd 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -64,6 +64,11 @@ template class ScriptRegistry<SpellSC>; template class ScriptRegistry<AccountScript>; template class ScriptRegistry<GameEventScript>; template class ScriptRegistry<MailScript>; +template class ScriptRegistry<AchievementScript>; +template class ScriptRegistry<MiscScript>; +template class ScriptRegistry<PetScript>; +template class ScriptRegistry<ArenaScript>; +template class ScriptRegistry<CommandSC>; #include "ScriptMgrMacros.h" @@ -124,10 +129,15 @@ void ScriptMgr::Unload() SCR_CLEAR(GlobalScript); SCR_CLEAR(ModuleScript); SCR_CLEAR(BGScript); + SCR_CLEAR(AchievementScript); SCR_CLEAR(ArenaTeamScript); SCR_CLEAR(SpellSC); SCR_CLEAR(GameEventScript); SCR_CLEAR(MailScript); + SCR_CLEAR(MiscScript); + SCR_CLEAR(PetScript); + SCR_CLEAR(ArenaScript); + SCR_CLEAR(CommandSC); #undef SCR_CLEAR } @@ -198,8 +208,13 @@ void ScriptMgr::CheckIfScriptsInDatabaseExist() !ScriptRegistry<PlayerScript>::GetScriptById(sid) && !ScriptRegistry<GuildScript>::GetScriptById(sid) && !ScriptRegistry<BGScript>::GetScriptById(sid) && + !ScriptRegistry<AchievementScript>::GetScriptById(sid) && !ScriptRegistry<ArenaTeamScript>::GetScriptById(sid) && !ScriptRegistry<SpellSC>::GetScriptById(sid) && + !ScriptRegistry<MiscScript>::GetScriptById(sid) && + !ScriptRegistry<PetScript>::GetScriptById(sid) && + !ScriptRegistry<CommandSC>::GetScriptById(sid) && + !ScriptRegistry<ArenaScript>::GetScriptById(sid) && !ScriptRegistry<GroupScript>::GetScriptById(sid)) sLog->outErrorDb("Script named '%s' is assigned in the database, but has no code!", (*itr).c_str()); } @@ -347,6 +362,11 @@ void ScriptMgr::CreateSpellScriptLoaders(uint32 spellId, std::vector<std::pair<S } } +void ScriptMgr::OnBeforePlayerDurabilityRepair(Player* player, uint64 npcGUID, uint64 itemGUID, float& discountMod, uint8 guildBank) +{ + FOREACH_SCRIPT(PlayerScript)->OnBeforeDurabilityRepair(player, npcGUID, itemGUID, discountMod, guildBank); +} + void ScriptMgr::OnNetworkStart() { FOREACH_SCRIPT(ServerScript)->OnNetworkStart(); @@ -1961,9 +1981,9 @@ void ScriptMgr::OnItemRoll(Player const* player, LootStoreItem const* LootStoreI FOREACH_SCRIPT(GlobalScript)->OnItemRoll(player, LootStoreItem, chance, loot, store); } -void ScriptMgr::OnInitializeLockedDungeons(Player* player, uint8& level, uint32& lockData) +void ScriptMgr::OnInitializeLockedDungeons(Player* player, uint8& level, uint32& lockData, lfg::LFGDungeonData const* dungeon) { - FOREACH_SCRIPT(GlobalScript)->OnInitializeLockedDungeons(player, level, lockData); + FOREACH_SCRIPT(GlobalScript)->OnInitializeLockedDungeons(player, level, lockData, dungeon); } void ScriptMgr::OnAfterInitializeLockedDungeons(Player* player) @@ -2037,7 +2057,7 @@ void ScriptMgr::OnBeforeBuyItemFromVendor(Player* player, uint64 vendorguid, uin FOREACH_SCRIPT(PlayerScript)->OnBeforeBuyItemFromVendor(player, vendorguid, vendorslot, item, count, bag, slot); } -void ScriptMgr::OnAfterStoreOrEquipNewItem(Player* player, uint32 vendorslot, uint32& item, uint8 count, uint8 bag, uint8 slot, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore) +void ScriptMgr::OnAfterStoreOrEquipNewItem(Player* player, uint32 vendorslot, Item* item, uint8 count, uint8 bag, uint8 slot, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore) { FOREACH_SCRIPT(PlayerScript)->OnAfterStoreOrEquipNewItem(player, vendorslot, item, count, bag, slot, pProto, pVendor, crItem, bStore); } @@ -2136,17 +2156,6 @@ void ScriptMgr::OnCheckNormalMatch(BattlegroundQueue* queue, uint32& Coef, Battl FOREACH_SCRIPT(BGScript)->OnCheckNormalMatch(queue, Coef, bgTemplate, bracket_id, minPlayers, maxPlayers); } -bool ScriptMgr::CanSendMessageQueue(BattlegroundQueue* queue, Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry) -{ - bool ret = true; - - FOR_SCRIPTS_RET(BGScript, itr, end, ret) // return true by default if not scripts - if (!itr->second->CanSendMessageQueue(queue, leader, bg, bracketEntry)) - ret = false; // we change ret value only when scripts return false - - return ret; -} - void ScriptMgr::OnGetSlotByType(const uint32 type, uint8& slot) { FOREACH_SCRIPT(ArenaTeamScript)->OnGetSlotByType(type, slot); @@ -2200,6 +2209,851 @@ void ScriptMgr::OnBeforeMailDraftSendMailTo(MailDraft* mailDraft, MailReceiver c FOREACH_SCRIPT(MailScript)->OnBeforeMailDraftSendMailTo(mailDraft, receiver, sender, checked, deliver_delay, custom_expiration, deleteMailItemsFromDB, sendMail); } +void ScriptMgr::OnBeforeUpdatingPersonalRating(int32& mod, uint32 type) +{ + FOREACH_SCRIPT(FormulaScript)->OnBeforeUpdatingPersonalRating(mod, type); +} + +bool ScriptMgr::OnBeforePlayerQuestComplete(Player* player, uint32 quest_id) +{ + bool ret=true; + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->OnBeforeQuestComplete(player, quest_id)) + ret=false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::OnBeforeStoreOrEquipNewItem(Player* player, uint32 vendorslot, uint32& item, uint8 count, uint8 bag, uint8 slot, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore) +{ + FOREACH_SCRIPT(PlayerScript)->OnBeforeStoreOrEquipNewItem(player, vendorslot, item, count, bag, slot, pProto, pVendor, crItem, bStore); +} + +bool ScriptMgr::CanJoinInArenaQueue(Player* player, uint64 BattlemasterGuid, uint8 arenaslot, BattlegroundTypeId BGTypeID, uint8 joinAsGroup, uint8 IsRated, GroupJoinBattlegroundResult& err) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanJoinInArenaQueue(player, BattlemasterGuid, arenaslot, BGTypeID, joinAsGroup, IsRated, err)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanBattleFieldPort(Player* player, uint8 arenaType, BattlegroundTypeId BGTypeID, uint8 action) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanBattleFieldPort(player, arenaType, BGTypeID, action)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanGroupInvite(Player* player, std::string& membername) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanGroupInvite(player, membername)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanGroupAccept(Player* player, Group* group) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanGroupAccept(player, group)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanSellItem(Player* player, Item* item, Creature* creature) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanSellItem(player, item, creature)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanSendMail(Player* player, uint64 receiverGuid, uint64 mailbox, std::string& subject, std::string& body, uint32 money, uint32 COD, Item* item) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanSendMail(player, receiverGuid, mailbox, subject, body, money, COD, item)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::PetitionBuy(Player* player, Creature* creature, uint32& charterid, uint32& cost, uint32& type) +{ + FOREACH_SCRIPT(PlayerScript)->PetitionBuy(player, creature, charterid, cost, type); +} + +void ScriptMgr::PetitionShowList(Player* player, Creature* creature, uint32& CharterEntry, uint32& CharterDispayID, uint32& CharterCost) +{ + FOREACH_SCRIPT(PlayerScript)->PetitionShowList(player, creature, CharterEntry, CharterDispayID, CharterCost); +} + +void ScriptMgr::OnRewardKillRewarder(Player* player, bool isDungeon, float& rate) +{ + FOREACH_SCRIPT(PlayerScript)->OnRewardKillRewarder(player, isDungeon, rate); +} + +bool ScriptMgr::CanGiveMailRewardAtGiveLevel(Player* player, uint8 level) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanGiveMailRewardAtGiveLevel(player, level)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::OnDeleteFromDB(SQLTransaction& trans, uint32 guid) +{ + FOREACH_SCRIPT(PlayerScript)->OnDeleteFromDB(trans, guid); +} + +bool ScriptMgr::CanRepopAtGraveyard(Player* player) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanRepopAtGraveyard(player)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, bool IsPure) +{ + FOREACH_SCRIPT(PlayerScript)->OnGetMaxSkillValue(player, skill, result, IsPure); +} + +bool ScriptMgr::CanAreaExploreAndOutdoor(Player* player) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanAreaExploreAndOutdoor(player)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::OnVictimRewardBefore(Player* player, Player* victim, uint32& killer_title, uint32& victim_title) +{ + FOREACH_SCRIPT(PlayerScript)->OnVictimRewardBefore(player, victim, killer_title, victim_title); +} + +void ScriptMgr::OnVictimRewardAfter(Player* player, Player* victim, uint32& killer_title, uint32& victim_rank, float& honor_f) +{ + FOREACH_SCRIPT(PlayerScript)->OnVictimRewardAfter(player, victim, killer_title, victim_rank, honor_f); +} + +void ScriptMgr::OnCustomScalingStatValueBefore(Player* player, ItemTemplate const* proto, uint8 slot, bool apply, uint32& CustomScalingStatValue) +{ + FOREACH_SCRIPT(PlayerScript)->OnCustomScalingStatValueBefore(player, proto, slot, apply, CustomScalingStatValue); +} + +void ScriptMgr::OnCustomScalingStatValue(Player* player, ItemTemplate const* proto, uint32& statType, int32& val, uint8 itemProtoStatNumber, uint32 ScalingStatValue, ScalingStatValuesEntry const* ssv) +{ + FOREACH_SCRIPT(PlayerScript)->OnCustomScalingStatValue(player, proto, statType, val, itemProtoStatNumber, ScalingStatValue, ssv); +} + +bool ScriptMgr::CanArmorDamageModifier(Player* player) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanArmorDamageModifier(player)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::OnGetFeralApBonus(Player* player, int32& feral_bonus, int32 dpsMod, ItemTemplate const* proto, ScalingStatValuesEntry const* ssv) +{ + FOREACH_SCRIPT(PlayerScript)->OnGetFeralApBonus(player, feral_bonus, dpsMod, proto, ssv); +} + +bool ScriptMgr::CanApplyWeaponDependentAuraDamageMod(Player* player, Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanApplyWeaponDependentAuraDamageMod(player, item, attackType, aura, apply)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanApplyEquipSpell(Player* player, SpellInfo const* spellInfo, Item* item, bool apply, bool form_change) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanApplyEquipSpell(player, spellInfo, item, apply, form_change)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanApplyEquipSpellsItemSet(Player* player, ItemSetEffect* eff) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanApplyEquipSpellsItemSet(player, eff)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanCastItemCombatSpell(Player* player, Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanCastItemCombatSpell(player, target, attType, procVictim, procEx, item, proto)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanCastItemUseSpell(Player* player, Item* item, SpellCastTargets const& targets, uint8 cast_count, uint32 glyphIndex) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanCastItemUseSpell(player, item, targets, cast_count, glyphIndex)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::OnApplyAmmoBonuses(Player* player, ItemTemplate const* proto, float& currentAmmoDPS) +{ + FOREACH_SCRIPT(PlayerScript)->OnApplyAmmoBonuses(player, proto, currentAmmoDPS); +} + +bool ScriptMgr::CanEquipItem(Player* player, uint8 slot, uint16& dest, Item* pItem, bool swap, bool not_loading) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanEquipItem(player, slot, dest, pItem, swap, not_loading)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanUnequipItem(Player* player, uint16 pos, bool swap) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanUnequipItem(player, pos, swap)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanUseItem(Player* player, ItemTemplate const* proto, InventoryResult& result) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanUseItem(player, proto, result)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanSaveEquipNewItem(Player* player, Item* item, uint16 pos, bool update) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanSaveEquipNewItem(player, item, pos, update)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanApplyEnchantment(Player* player, Item* item, EnchantmentSlot slot, bool apply, bool apply_dur, bool ignore_condition) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanApplyEnchantment(player, item, slot, apply, apply_dur, ignore_condition)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::OnGetQuestRate(Player* player, float& result) +{ + FOREACH_SCRIPT(PlayerScript)->OnGetQuestRate(player, result); +} + +bool ScriptMgr::PassedQuestKilledMonsterCredit(Player* player, Quest const* qinfo, uint32 entry, uint32 real_entry, uint64 guid) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->PassedQuestKilledMonsterCredit(player, qinfo, entry, real_entry, guid)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CheckItemInSlotAtLoadInventory(Player* player, Item* item, uint8 slot, uint8& err, uint16& dest) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CheckItemInSlotAtLoadInventory(player, item, slot, err, dest)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::NotAvoidSatisfy(Player* player, DungeonProgressionRequirements const* ar, uint32 target_map, bool report) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->NotAvoidSatisfy(player, ar, target_map, report)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::NotVisibleGloballyFor(Player* player, Player const* u) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->NotVisibleGloballyFor(player, u)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::OnGetArenaPersonalRating(Player* player, uint8 slot, uint32& result) +{ + FOREACH_SCRIPT(PlayerScript)->OnGetArenaPersonalRating(player, slot, result); +} + +void ScriptMgr::OnGetArenaTeamId(Player* player, uint8 slot, uint32& result) +{ + FOREACH_SCRIPT(PlayerScript)->OnGetArenaTeamId(player, slot, result); +} + +void ScriptMgr::OnIsFFAPvP(Player* player, bool& result) +{ + FOREACH_SCRIPT(PlayerScript)->OnIsFFAPvP(player, result); +} + +void ScriptMgr::OnIsPvP(Player* player, bool& result) +{ + FOREACH_SCRIPT(PlayerScript)->OnIsPvP(player, result); +} + +void ScriptMgr::OnGetMaxSkillValueForLevel(Player* player, uint16& result) +{ + FOREACH_SCRIPT(PlayerScript)->OnGetMaxSkillValueForLevel(player, result); +} + +bool ScriptMgr::NotSetArenaTeamInfoField(Player* player, uint8 slot, ArenaTeamInfoType type, uint32 value) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->NotSetArenaTeamInfoField(player, slot, type, value)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanJoinLfg(Player* player, uint8 roles, lfg::LfgDungeonSet& dungeons, const std::string& comment) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanJoinLfg(player, roles, dungeons, comment)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanEnterMap(Player* player, MapEntry const* entry, InstanceTemplate const* instance, MapDifficulty const* mapDiff, bool loginCheck) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanEnterMap(player, entry, instance, mapDiff, loginCheck)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanInitTrade(Player* player, Player* target) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanInitTrade(player, target)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::OnSetServerSideVisibility(Player* player, ServerSideVisibilityType& type, AccountTypes& sec) +{ + FOREACH_SCRIPT(PlayerScript)->OnSetServerSideVisibility(player, type, sec); +} + +void ScriptMgr::OnSetServerSideVisibilityDetect(Player* player, ServerSideVisibilityType& type, AccountTypes& sec) +{ + FOREACH_SCRIPT(PlayerScript)->OnSetServerSideVisibilityDetect(player, type, sec); +} + +bool ScriptMgr::CanGuildSendBankList(Guild const* guild, WorldSession* session, uint8 tabId, bool sendAllSlots) +{ + bool ret = true; + + FOR_SCRIPTS_RET(GuildScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanGuildSendBankList(guild, session, tabId, sendAllSlots)) + ret = false; // we change ret value only when scripts return true + + return ret; +} + +bool ScriptMgr::CanGroupJoinBattlegroundQueue(Group const* group, Player* member, Battleground const* bgTemplate, uint32 MinPlayerCount, bool isRated, uint32 arenaSlot) +{ + bool ret = true; + + FOR_SCRIPTS_RET(GroupScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanGroupJoinBattlegroundQueue(group, member, bgTemplate, MinPlayerCount, isRated, arenaSlot)) + ret = false; // we change ret value only when scripts return true + + return ret; +} + +void ScriptMgr::OnCreate(Group* group, Player* leader) +{ + FOREACH_SCRIPT(GroupScript)->OnCreate(group, leader); +} + +void ScriptMgr::OnAuraRemove(Unit* unit, AuraApplication* aurApp, AuraRemoveMode mode) +{ + FOREACH_SCRIPT(UnitScript)->OnAuraRemove(unit, aurApp, mode); +} + +bool ScriptMgr::IfNormalReaction(Unit const* unit, Unit const* target, ReputationRank& repRank) +{ + bool ret = true; + + FOR_SCRIPTS_RET(UnitScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->IfNormalReaction(unit, target, repRank)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::IsNeedModSpellDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto) +{ + bool ret = true; + + FOR_SCRIPTS_RET(UnitScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->IsNeedModSpellDamagePercent(unit, auraEff, doneTotalMod, spellProto)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::IsNeedModMeleeDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto) +{ + bool ret = true; + + FOR_SCRIPTS_RET(UnitScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->IsNeedModMeleeDamagePercent(unit, auraEff, doneTotalMod, spellProto)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::IsNeedModHealPercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto) +{ + bool ret = true; + + FOR_SCRIPTS_RET(UnitScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->IsNeedModHealPercent(unit, auraEff, doneTotalMod, spellProto)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanSetPhaseMask(Unit const* unit, uint32 newPhaseMask, bool update) +{ + bool ret = true; + + FOR_SCRIPTS_RET(UnitScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanSetPhaseMask(unit, newPhaseMask, update)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::IsCustomBuildValuesUpdate(Unit const* unit, uint8 updateType, ByteBuffer& fieldBuffer, Player const* target, uint16 index) +{ + bool ret = false; + + FOR_SCRIPTS_RET(UnitScript, itr, end, ret) // return true by default if not scripts + if (itr->second->IsCustomBuildValuesUpdate(unit, updateType, fieldBuffer, target, index)) + ret = true; // we change ret value only when scripts return true + + return ret; +} + +void ScriptMgr::OnQueueUpdate(BattlegroundQueue* queue, BattlegroundBracketId bracket_id, bool isRated, uint32 arenaRatedTeamId) +{ + FOREACH_SCRIPT(BGScript)->OnQueueUpdate(queue, bracket_id, isRated, arenaRatedTeamId); +} + +bool ScriptMgr::CanSendMessageBGQueue(BattlegroundQueue* queue, Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry) +{ + bool ret = true; + + FOR_SCRIPTS_RET(BGScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanSendMessageBGQueue(queue, leader, bg, bracketEntry)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanSendMessageArenaQueue(BattlegroundQueue* queue, GroupQueueInfo* ginfo, bool IsJoin) +{ + bool ret = true; + + FOR_SCRIPTS_RET(BGScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanSendMessageArenaQueue(queue, ginfo, IsJoin)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanModAuraEffectDamageDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply) +{ + bool ret = true; + + FOR_SCRIPTS_RET(SpellSC, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanModAuraEffectDamageDone(auraEff, target, aurApp, mode, apply)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanModAuraEffectModDamagePercentDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply) +{ + bool ret = true; + + FOR_SCRIPTS_RET(SpellSC, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanModAuraEffectModDamagePercentDone(auraEff, target, aurApp, mode, apply)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::OnSpellCheckCast(Spell* spell, bool strict, SpellCastResult& res) +{ + FOREACH_SCRIPT(SpellSC)->OnSpellCheckCast(spell, strict, res); +} + +bool ScriptMgr::CanPrepare(Spell* spell, SpellCastTargets const* targets, AuraEffect const* triggeredByAura) +{ + bool ret = true; + + FOR_SCRIPTS_RET(SpellSC, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanPrepare(spell, targets, triggeredByAura)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanScalingEverything(Spell* spell) +{ + bool ret = false; + + FOR_SCRIPTS_RET(SpellSC, itr, end, ret) // return true by default if not scripts + if (itr->second->CanScalingEverything(spell)) + ret = true; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanSelectSpecTalent(Spell* spell) +{ + bool ret = true; + + FOR_SCRIPTS_RET(SpellSC, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanSelectSpecTalent(spell)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::OnScaleAuraUnitAdd(Spell* spell, Unit* target, uint32 effectMask, bool checkIfValid, bool implicit, uint8 auraScaleMask, TargetInfo& targetInfo) +{ + FOREACH_SCRIPT(SpellSC)->OnScaleAuraUnitAdd(spell, target, effectMask, checkIfValid, implicit, auraScaleMask, targetInfo); +} + +void ScriptMgr::OnRemoveAuraScaleTargets(Spell* spell, TargetInfo& targetInfo, uint8 auraScaleMask, bool& needErase) +{ + FOREACH_SCRIPT(SpellSC)->OnRemoveAuraScaleTargets(spell, targetInfo, auraScaleMask, needErase); +} + +void ScriptMgr::OnBeforeAuraRankForLevel(SpellInfo const* spellInfo, SpellInfo const* latestSpellInfo, uint8 level) +{ + FOREACH_SCRIPT(SpellSC)->OnBeforeAuraRankForLevel(spellInfo, latestSpellInfo, level); +} + +void ScriptMgr::SetRealmCompleted(AchievementEntry const* achievement) +{ + FOREACH_SCRIPT(AchievementScript)->SetRealmCompleted(achievement); +} + +bool ScriptMgr::IsCompletedCriteria(AchievementMgr* mgr, AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement, CriteriaProgress const* progress) +{ + bool ret = true; + + FOR_SCRIPTS_RET(AchievementScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->IsCompletedCriteria(mgr, achievementCriteria, achievement, progress)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::IsRealmCompleted(AchievementGlobalMgr const* globalmgr, AchievementEntry const* achievement, std::chrono::system_clock::time_point completionTime) +{ + bool ret = true; + + FOR_SCRIPTS_RET(AchievementScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->IsRealmCompleted(globalmgr, achievement, completionTime)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::OnBeforeCheckCriteria(AchievementMgr* mgr, AchievementCriteriaEntryList const* achievementCriteriaList) +{ + FOREACH_SCRIPT(AchievementScript)->OnBeforeCheckCriteria(mgr, achievementCriteriaList); +} + +bool ScriptMgr::CanCheckCriteria(AchievementMgr* mgr, AchievementCriteriaEntry const* achievementCriteria) +{ + bool ret = true; + + FOR_SCRIPTS_RET(AchievementScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanCheckCriteria(mgr, achievementCriteria)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::OnInitStatsForLevel(Guardian* guardian, uint8 petlevel) +{ + FOREACH_SCRIPT(PetScript)->OnInitStatsForLevel(guardian, petlevel); +} + +void ScriptMgr::OnCalculateMaxTalentPointsForLevel(Pet* pet, uint8 level, uint8& points) +{ + FOREACH_SCRIPT(PetScript)->OnCalculateMaxTalentPointsForLevel(pet, level, points); +} + +bool ScriptMgr::CanUnlearnSpellSet(Pet* pet, uint32 level, uint32 spell) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PetScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanUnlearnSpellSet(pet, level, spell)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanUnlearnSpellDefault(Pet* pet, SpellInfo const* spellEntry) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PetScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanUnlearnSpellDefault(pet, spellEntry)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanResetTalents(Pet* pet) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PetScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanResetTalents(pet)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanAddMember(ArenaTeam* team, uint64 PlayerGuid) +{ + bool ret = true; + + FOR_SCRIPTS_RET(ArenaScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanAddMember(team, PlayerGuid)) + ret = false; // we change ret value only when scripts return true + + return ret; +} + +void ScriptMgr::OnGetPoints(ArenaTeam* team, uint32 memberRating, float& points) +{ + FOREACH_SCRIPT(ArenaScript)->OnGetPoints(team, memberRating, points); +} + +bool ScriptMgr::CanSaveToDB(ArenaTeam* team) +{ + bool ret = true; + + FOR_SCRIPTS_RET(ArenaScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanSaveToDB(team)) + ret = false; // we change ret value only when scripts return true + + return ret; +} + +void ScriptMgr::OnItemCreate(Item* item, ItemTemplate const* itemProto, Player const* owner) +{ + FOREACH_SCRIPT(MiscScript)->OnItemCreate(item, itemProto, owner); +} + +bool ScriptMgr::CanApplySoulboundFlag(Item* item, ItemTemplate const* proto) +{ + bool ret = true; + + FOR_SCRIPTS_RET(MiscScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanApplySoulboundFlag(item, proto)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::OnConstructObject(Object* origin) +{ + FOREACH_SCRIPT(MiscScript)->OnConstructObject(origin); +} + +void ScriptMgr::OnDestructObject(Object* origin) +{ + FOREACH_SCRIPT(MiscScript)->OnDestructObject(origin); +} + +void ScriptMgr::OnConstructPlayer(Player* origin) +{ + FOREACH_SCRIPT(MiscScript)->OnConstructPlayer(origin); +} + +void ScriptMgr::OnDestructPlayer(Player* origin) +{ + FOREACH_SCRIPT(MiscScript)->OnDestructPlayer(origin); +} + +void ScriptMgr::OnConstructGroup(Group* origin) +{ + FOREACH_SCRIPT(MiscScript)->OnConstructGroup(origin); +} + +void ScriptMgr::OnDestructGroup(Group* origin) +{ + FOREACH_SCRIPT(MiscScript)->OnDestructGroup(origin); +} + +void ScriptMgr::OnConstructInstanceSave(InstanceSave* origin) +{ + FOREACH_SCRIPT(MiscScript)->OnConstructInstanceSave(origin); +} + +void ScriptMgr::OnDestructInstanceSave(InstanceSave* origin) +{ + FOREACH_SCRIPT(MiscScript)->OnDestructInstanceSave(origin); +} + +bool ScriptMgr::CanItemApplyEquipSpell(Player* player, Item* item) +{ + bool ret = true; + + FOR_SCRIPTS_RET(MiscScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanItemApplyEquipSpell(player, item)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +bool ScriptMgr::CanSendAuctionHello(WorldSession const* session, uint64 guid, Creature* creature) +{ + bool ret = true; + + FOR_SCRIPTS_RET(MiscScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->CanSendAuctionHello(session, guid, creature)) + ret = false; // we change ret value only when scripts return false + + return ret; +} + +void ScriptMgr::ValidateSpellAtCastSpell(Player* player, uint32& oldSpellId, uint32& spellId, uint8& castCount, uint8& castFlags) +{ + FOREACH_SCRIPT(MiscScript)->ValidateSpellAtCastSpell(player, oldSpellId, spellId, castCount, castFlags); +} + +void ScriptMgr::ValidateSpellAtCastSpellResult(Player* player, Unit* mover, Spell* spell, uint32 oldSpellId, uint32 spellId) +{ + FOREACH_SCRIPT(MiscScript)->ValidateSpellAtCastSpellResult(player, mover, spell, oldSpellId, spellId); +} + +void ScriptMgr::OnAfterLootTemplateProcess(Loot* loot, LootTemplate const* tab, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError, uint16 lootMode) +{ + FOREACH_SCRIPT(MiscScript)->OnAfterLootTemplateProcess(loot, tab, store, lootOwner, personal, noEmptyError, lootMode); +} + +void ScriptMgr::OnInstanceSave(InstanceSave* instanceSave) +{ + FOREACH_SCRIPT(MiscScript)->OnInstanceSave(instanceSave); +} + +void ScriptMgr::OnPlayerSetPhase(const AuraEffect* auraEff, AuraApplication const* aurApp, uint8 mode, bool apply, uint32& newPhase) +{ + FOREACH_SCRIPT(MiscScript)->OnPlayerSetPhase(auraEff, aurApp, mode, apply, newPhase); +} + +void ScriptMgr::OnHandleDevCommand(Player* player, std::string& argstr) +{ + FOREACH_SCRIPT(CommandSC)->OnHandleDevCommand(player, argstr); +} + +///- AllMapScript::AllMapScript(const char* name) : ScriptObject(name) { @@ -2416,3 +3270,33 @@ MailScript::MailScript(const char* name) { ScriptRegistry<MailScript>::AddScript(this); } + +AchievementScript::AchievementScript(const char* name) + : ScriptObject(name) +{ + ScriptRegistry<AchievementScript>::AddScript(this); +} + +PetScript::PetScript(const char* name) + : ScriptObject(name) +{ + ScriptRegistry<PetScript>::AddScript(this); +} + +ArenaScript::ArenaScript(const char* name) + : ScriptObject(name) +{ + ScriptRegistry<ArenaScript>::AddScript(this); +} + +MiscScript::MiscScript(const char* name) + : ScriptObject(name) +{ + ScriptRegistry<MiscScript>::AddScript(this); +} + +CommandSC::CommandSC(const char* name) + : ScriptObject(name) +{ + ScriptRegistry<CommandSC>::AddScript(this); +} diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 54703587e7..9359026a3f 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -15,6 +15,7 @@ #include "DBCStores.h" #include "DynamicObject.h" #include "GameEventMgr.h" +#include "LFGMgr.h" #include "ObjectMgr.h" #include "PetDefines.h" #include "QuestDef.h" @@ -63,9 +64,11 @@ struct AchievementCriteriaData; struct AuctionEntry; struct ConditionSourceInfo; struct Condition; +struct DungeonProgressionRequirements; struct ItemTemplate; struct OutdoorPvPData; struct GroupQueueInfo; +struct TargetInfo; #define VISIBLE_RANGE 166.0f //MAX visible range (size of grid) @@ -287,6 +290,9 @@ public: // Called after calculating arena rating changes virtual void OnAfterArenaRatingCalculation(Battleground* const /*bg*/, int32& /*winnerMatchmakerChange*/, int32& /*loserMatchmakerChange*/, int32& /*winnerChange*/, int32& /*loserChange*/) { }; + + // Called before modifying a player's personal rating + virtual void OnBeforeUpdatingPersonalRating(int32& /*mod*/, uint32 /*type*/) { } }; template<class TMap> class MapScript : public UpdatableScript<TMap> @@ -397,19 +403,19 @@ public: [[nodiscard]] bool IsDatabaseBound() const override { return true; } // Called when a player accepts a quest from the item. - virtual bool OnQuestAccept(Player* /*player*/, Item* /*item*/, Quest const* /*quest*/) { return false; } + [[nodiscard]] virtual bool OnQuestAccept(Player* /*player*/, Item* /*item*/, Quest const* /*quest*/) { return false; } // Called when a player uses the item. - virtual bool OnUse(Player* /*player*/, Item* /*item*/, SpellCastTargets const& /*targets*/) { return false; } + [[nodiscard]] virtual bool OnUse(Player* /*player*/, Item* /*item*/, SpellCastTargets const& /*targets*/) { return false; } // Called when the item is destroyed. - virtual bool OnRemove(Player* /*player*/, Item* /*item*/) { return false; } + [[nodiscard]] virtual bool OnRemove(Player* /*player*/, Item* /*item*/) { return false; } // Called before casting a combat spell from this item (chance on hit spells of item template, can be used to prevent cast if returning false) - virtual bool OnCastItemCombatSpell(Player* /*player*/, Unit* /*victim*/, SpellInfo const* /*spellInfo*/, Item* /*item*/) { return true; } + [[nodiscard]] virtual bool OnCastItemCombatSpell(Player* /*player*/, Unit* /*victim*/, SpellInfo const* /*spellInfo*/, Item* /*item*/) { return true; } // Called when the item expires (is destroyed). - virtual bool OnExpire(Player* /*player*/, ItemTemplate const* /*proto*/) { return false; } + [[nodiscard]] virtual bool OnExpire(Player* /*player*/, ItemTemplate const* /*proto*/) { return false; } // Called when a player selects an option in an item gossip window virtual void OnGossipSelect(Player* /*player*/, Item* /*item*/, uint32 /*sender*/, uint32 /*action*/) { } @@ -447,6 +453,20 @@ public: virtual uint32 DealDamage(Unit* /*AttackerUnit*/, Unit* /*pVictim*/, uint32 damage, DamageEffectType /*damagetype*/) { return damage; } virtual void OnBeforeRollMeleeOutcomeAgainst(const Unit* /*attacker*/, const Unit* /*victim*/, WeaponAttackType /*attType*/, int32& /*attackerMaxSkillValueForLevel*/, int32& /*victimMaxSkillValueForLevel*/, int32& /*attackerWeaponSkill*/, int32& /*victimDefenseSkill*/, int32& /*crit_chance*/, int32& /*miss_chance*/, int32& /*dodge_chance*/, int32& /*parry_chance*/, int32& /*block_chance*/ ) { }; + + virtual void OnAuraRemove(Unit* /*unit*/, AuraApplication* /*aurApp*/, AuraRemoveMode /*mode*/) { } + + [[nodiscard]] virtual bool IfNormalReaction(Unit const* /*unit*/, Unit const* /*target*/, ReputationRank& /*repRank*/) { return true; } + + [[nodiscard]] virtual bool IsNeedModSpellDamagePercent(Unit const* /*unit*/, AuraEffect* /*auraEff*/, float& /*doneTotalMod*/, SpellInfo const* /*spellProto*/) { return true; } + + [[nodiscard]] virtual bool IsNeedModMeleeDamagePercent(Unit const* /*unit*/, AuraEffect* /*auraEff*/, float& /*doneTotalMod*/, SpellInfo const* /*spellProto*/) { return true; } + + [[nodiscard]] virtual bool IsNeedModHealPercent(Unit const* /*unit*/, AuraEffect* /*auraEff*/, float& /*doneTotalMod*/, SpellInfo const* /*spellProto*/) { return true; } + + [[nodiscard]] virtual bool CanSetPhaseMask(Unit const* /*unit*/, uint32 /*newPhaseMask*/, bool /*update*/) { return true; } + + [[nodiscard]] virtual bool IsCustomBuildValuesUpdate(Unit const* /*unit*/, uint8 /*updateType*/, ByteBuffer& /*fieldBuffer*/, Player const* /*target*/, uint16 /*index*/) { return false; } }; class MovementHandlerScript : public ScriptObject @@ -494,25 +514,25 @@ public: [[nodiscard]] bool IsDatabaseBound() const override { return true; } // Called when a player opens a gossip dialog with the creature. - virtual bool OnGossipHello(Player* /*player*/, Creature* /*creature*/) { return false; } + [[nodiscard]] virtual bool OnGossipHello(Player* /*player*/, Creature* /*creature*/) { return false; } // Called when a player selects a gossip item in the creature's gossip menu. - virtual bool OnGossipSelect(Player* /*player*/, Creature* /*creature*/, uint32 /*sender*/, uint32 /*action*/) { return false; } + [[nodiscard]] virtual bool OnGossipSelect(Player* /*player*/, Creature* /*creature*/, uint32 /*sender*/, uint32 /*action*/) { return false; } // Called when a player selects a gossip with a code in the creature's gossip menu. - virtual bool OnGossipSelectCode(Player* /*player*/, Creature* /*creature*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/) { return false; } + [[nodiscard]] virtual bool OnGossipSelectCode(Player* /*player*/, Creature* /*creature*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/) { return false; } // Called when a player accepts a quest from the creature. - virtual bool OnQuestAccept(Player* /*player*/, Creature* /*creature*/, Quest const* /*quest*/) { return false; } + [[nodiscard]] virtual bool OnQuestAccept(Player* /*player*/, Creature* /*creature*/, Quest const* /*quest*/) { return false; } // Called when a player selects a quest in the creature's quest menu. - virtual bool OnQuestSelect(Player* /*player*/, Creature* /*creature*/, Quest const* /*quest*/) { return false; } + [[nodiscard]] virtual bool OnQuestSelect(Player* /*player*/, Creature* /*creature*/, Quest const* /*quest*/) { return false; } // Called when a player completes a quest with the creature. - virtual bool OnQuestComplete(Player* /*player*/, Creature* /*creature*/, Quest const* /*quest*/) { return false; } + [[nodiscard]] virtual bool OnQuestComplete(Player* /*player*/, Creature* /*creature*/, Quest const* /*quest*/) { return false; } // Called when a player selects a quest reward. - virtual bool OnQuestReward(Player* /*player*/, Creature* /*creature*/, Quest const* /*quest*/, uint32 /*opt*/) { return false; } + [[nodiscard]] virtual bool OnQuestReward(Player* /*player*/, Creature* /*creature*/, Quest const* /*quest*/, uint32 /*opt*/) { return false; } // Called when the dialog status between a player and the creature is requested. virtual uint32 GetDialogStatus(Player* /*player*/, Creature* /*creature*/) { return DIALOG_STATUS_SCRIPTED_NO_STATUS; } @@ -530,19 +550,19 @@ public: [[nodiscard]] bool IsDatabaseBound() const override { return true; } // Called when a player opens a gossip dialog with the gameobject. - virtual bool OnGossipHello(Player* /*player*/, GameObject* /*go*/) { return false; } + [[nodiscard]] virtual bool OnGossipHello(Player* /*player*/, GameObject* /*go*/) { return false; } // Called when a player selects a gossip item in the gameobject's gossip menu. - virtual bool OnGossipSelect(Player* /*player*/, GameObject* /*go*/, uint32 /*sender*/, uint32 /*action*/) { return false; } + [[nodiscard]] virtual bool OnGossipSelect(Player* /*player*/, GameObject* /*go*/, uint32 /*sender*/, uint32 /*action*/) { return false; } // Called when a player selects a gossip with a code in the gameobject's gossip menu. - virtual bool OnGossipSelectCode(Player* /*player*/, GameObject* /*go*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/) { return false; } + [[nodiscard]] virtual bool OnGossipSelectCode(Player* /*player*/, GameObject* /*go*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/) { return false; } // Called when a player accepts a quest from the gameobject. - virtual bool OnQuestAccept(Player* /*player*/, GameObject* /*go*/, Quest const* /*quest*/) { return false; } + [[nodiscard]] virtual bool OnQuestAccept(Player* /*player*/, GameObject* /*go*/, Quest const* /*quest*/) { return false; } // Called when a player selects a quest reward. - virtual bool OnQuestReward(Player* /*player*/, GameObject* /*go*/, Quest const* /*quest*/, uint32 /*opt*/) { return false; } + [[nodiscard]] virtual bool OnQuestReward(Player* /*player*/, GameObject* /*go*/, Quest const* /*quest*/, uint32 /*opt*/) { return false; } // Called when the dialog status between a player and the gameobject is requested. virtual uint32 GetDialogStatus(Player* /*player*/, GameObject* /*go*/) { return DIALOG_STATUS_SCRIPTED_NO_STATUS; } @@ -572,7 +592,7 @@ public: [[nodiscard]] bool IsDatabaseBound() const override { return true; } // Called when the area trigger is activated by a player. - virtual bool OnTrigger(Player* /*player*/, AreaTrigger const* /*trigger*/) { return false; } + [[nodiscard]] virtual bool OnTrigger(Player* /*player*/, AreaTrigger const* /*trigger*/) { return false; } }; class BattlegroundScript : public ScriptObject @@ -670,7 +690,7 @@ public: [[nodiscard]] bool IsDatabaseBound() const override { return true; } // Called when a single condition is checked for a player. - virtual bool OnConditionCheck(Condition* /*condition*/, ConditionSourceInfo& /*sourceInfo*/) { return true; } + [[nodiscard]] virtual bool OnConditionCheck(Condition* /*condition*/, ConditionSourceInfo& /*sourceInfo*/) { return true; } }; class VehicleScript : public ScriptObject @@ -734,7 +754,7 @@ public: [[nodiscard]] bool IsDatabaseBound() const override { return true; } // deprecated/legacy - virtual bool OnCheck(Player* /*source*/, Unit* /*target*/) { return true; }; + [[nodiscard]] virtual bool OnCheck(Player* /*source*/, Unit* /*target*/) { return true; }; }; class PlayerScript : public ScriptObject @@ -860,7 +880,7 @@ public: virtual void OnMapChanged(Player* /*player*/) { } // Called before a player is being teleported to new coords - virtual bool OnBeforeTeleport(Player* /*player*/, uint32 /*mapid*/, float /*x*/, float /*y*/, float /*z*/, float /*orientation*/, uint32 /*options*/, Unit* /*target*/) { return true; } + [[nodiscard]] virtual bool OnBeforeTeleport(Player* /*player*/, uint32 /*mapid*/, float /*x*/, float /*y*/, float /*z*/, float /*orientation*/, uint32 /*options*/, Unit* /*target*/) { return true; } // Called when team/faction is set on player virtual void OnUpdateFaction(Player* /*player*/) { } @@ -922,14 +942,23 @@ public: //After creating item (eg profession item creation) virtual void OnCreateItem(Player* /*player*/, Item* /*item*/, uint32 /*count*/) { } - //After receiving item as a quest reward + // After receiving item as a quest reward virtual void OnQuestRewardItem(Player* /*player*/, Item* /*item*/, uint32 /*count*/) { } + // After completed a quest + [[nodiscard]] virtual bool OnBeforeQuestComplete(Player* /*player*/, uint32 /*quest_id*/) { return true; } + + // Before durability repair action, you can even modify the discount value + virtual void OnBeforeDurabilityRepair(Player* /*player*/, uint64 /*npcGUID*/, uint64 /*itemGUID*/, float&/*discountMod*/, uint8 /*guildBank*/) { } + //Before buying something from any vendor virtual void OnBeforeBuyItemFromVendor(Player* /*player*/, uint64 /*vendorguid*/, uint32 /*vendorslot*/, uint32& /*item*/, uint8 /*count*/, uint8 /*bag*/, uint8 /*slot*/) { }; //Before buying something from any vendor - virtual void OnAfterStoreOrEquipNewItem(Player* /*player*/, uint32 /*vendorslot*/, uint32& /*item*/, uint8 /*count*/, uint8 /*bag*/, uint8 /*slot*/, ItemTemplate const* /*pProto*/, Creature* /*pVendor*/, VendorItem const* /*crItem*/, bool /*bStore*/) { }; + virtual void OnBeforeStoreOrEquipNewItem(Player* /*player*/, uint32 /*vendorslot*/, uint32& /*item*/, uint8 /*count*/, uint8 /*bag*/, uint8 /*slot*/, ItemTemplate const* /*pProto*/, Creature* /*pVendor*/, VendorItem const* /*crItem*/, bool /*bStore*/) { }; + + //After buying something from any vendor + virtual void OnAfterStoreOrEquipNewItem(Player* /*player*/, uint32 /*vendorslot*/, Item* /*item*/, uint8 /*count*/, uint8 /*bag*/, uint8 /*slot*/, ItemTemplate const* /*pProto*/, Creature* /*pVendor*/, VendorItem const* /*crItem*/, bool /*bStore*/) { }; virtual void OnAfterUpdateMaxPower(Player* /*player*/, Powers& /*power*/, float& /*value*/) { } @@ -942,7 +971,7 @@ public: virtual void OnFirstLogin(Player* /*player*/) { } - virtual bool CanJoinInBattlegroundQueue(Player* /*player*/, uint64 /*BattlemasterGuid*/, BattlegroundTypeId /*BGTypeID*/, uint8 /*joinAsGroup*/, GroupJoinBattlegroundResult& /*err*/) { return true; } + [[nodiscard]] virtual bool CanJoinInBattlegroundQueue(Player* /*player*/, uint64 /*BattlemasterGuid*/, BattlegroundTypeId /*BGTypeID*/, uint8 /*joinAsGroup*/, GroupJoinBattlegroundResult& /*err*/) { return true; } virtual bool ShouldBeRewardedWithMoneyInsteadOfExp(Player* /*player*/) { return false; } // Called before the player's temporary summoned creature has initialized it's stats @@ -956,6 +985,100 @@ public: // Called before loading a player's pet from the DB virtual void OnBeforeLoadPetFromDB(Player* /*player*/, uint32& /*petentry*/, uint32& /*petnumber*/, bool& /*current*/, bool& /*forceLoadFromDB*/) { } + + [[nodiscard]] virtual bool CanJoinInArenaQueue(Player* /*player*/, uint64 /*BattlemasterGuid*/, uint8 /*arenaslot*/, BattlegroundTypeId /*BGTypeID*/, uint8 /*joinAsGroup*/, uint8 /*IsRated*/, GroupJoinBattlegroundResult& /*err*/) { return true; } + + [[nodiscard]] virtual bool CanBattleFieldPort(Player* /*player*/, uint8 /*arenaType*/, BattlegroundTypeId /*BGTypeID*/, uint8 /*action*/) { return true; } + + [[nodiscard]] virtual bool CanGroupInvite(Player* /*player*/, std::string& /*membername*/) { return true; } + + [[nodiscard]] virtual bool CanGroupAccept(Player* /*player*/, Group* /*group*/) { return true; } + + [[nodiscard]] virtual bool CanSellItem(Player* /*player*/, Item* /*item*/, Creature* /*creature*/) { return true; } + + [[nodiscard]] virtual bool CanSendMail(Player* /*player*/, uint64 /*receiverGuid*/, uint64 /*mailbox*/, std::string& /*subject*/, std::string& /*body*/, uint32 /*money*/, uint32 /*COD*/, Item* /*item*/) { return true; } + + virtual void PetitionBuy(Player* /*player*/, Creature* /*creature*/, uint32& /*charterid*/, uint32& /*cost*/, uint32& /*type*/) { } + + virtual void PetitionShowList(Player* /*player*/, Creature* /*creature*/, uint32& /*CharterEntry*/, uint32& /*CharterDispayID*/, uint32& /*CharterCost*/) { } + + virtual void OnRewardKillRewarder(Player* /*player*/, bool /*isDungeon*/, float& /*rate*/) { } + + [[nodiscard]] virtual bool CanGiveMailRewardAtGiveLevel(Player* /*player*/, uint8 /*level*/) { return true; } + + virtual void OnDeleteFromDB(SQLTransaction& /*trans*/, uint32 /*guid*/) { } + + [[nodiscard]] virtual bool CanRepopAtGraveyard(Player* /*player*/) { return true; } + + virtual void OnGetMaxSkillValue(Player* /*player*/, uint32 /*skill*/, int32& /*result*/, bool /*IsPure*/) { } + + [[nodiscard]] virtual bool CanAreaExploreAndOutdoor(Player* /*player*/) { return true; } + + virtual void OnVictimRewardBefore(Player* /*player*/, Player* /*victim*/, uint32& /*killer_title*/, uint32& /*victim_title*/) { } + + virtual void OnVictimRewardAfter(Player* /*player*/, Player* /*victim*/, uint32& /*killer_title*/, uint32& /*victim_rank*/, float& /*honor_f*/) { } + + virtual void OnCustomScalingStatValueBefore(Player* /*player*/, ItemTemplate const* /*proto*/, uint8 /*slot*/, bool /*apply*/, uint32& /*CustomScalingStatValue*/) { } + + virtual void OnCustomScalingStatValue(Player* /*player*/, ItemTemplate const* /*proto*/, uint32& /*statType*/, int32& /*val*/, uint8 /*itemProtoStatNumber*/, uint32 /*ScalingStatValue*/, ScalingStatValuesEntry const* /*ssv*/) { } + + [[nodiscard]] virtual bool CanArmorDamageModifier(Player* /*player*/) { return true; } + + virtual void OnGetFeralApBonus(Player* /*player*/, int32& /*feral_bonus*/, int32 /*dpsMod*/, ItemTemplate const* /*proto*/, ScalingStatValuesEntry const* /*ssv*/) { } + + [[nodiscard]] virtual bool CanApplyWeaponDependentAuraDamageMod(Player* /*player*/, Item* /*item*/, WeaponAttackType /*attackType*/, AuraEffect const* /*aura*/, bool /*apply*/) { return true; } + + [[nodiscard]] virtual bool CanApplyEquipSpell(Player* /*player*/, SpellInfo const* /*spellInfo*/, Item* /*item*/, bool /*apply*/, bool /*form_change*/) { return true; } + + [[nodiscard]] virtual bool CanApplyEquipSpellsItemSet(Player* /*player*/, ItemSetEffect* /*eff*/) { return true; } + + [[nodiscard]] virtual bool CanCastItemCombatSpell(Player* /*player*/, Unit* /*target*/, WeaponAttackType /*attType*/, uint32 /*procVictim*/, uint32 /*procEx*/, Item* /*item*/, ItemTemplate const* /*proto*/) { return true; } + + [[nodiscard]] virtual bool CanCastItemUseSpell(Player* /*player*/, Item* /*item*/, SpellCastTargets const& /*targets*/, uint8 /*cast_count*/, uint32 /*glyphIndex*/) { return true; } + + virtual void OnApplyAmmoBonuses(Player* /*player*/, ItemTemplate const* /*proto*/, float& /*currentAmmoDPS*/) { } + + [[nodiscard]] virtual bool CanEquipItem(Player* /*player*/, uint8 /*slot*/, uint16& /*dest*/, Item* /*pItem*/, bool /*swap*/, bool /*not_loading*/) { return true; } + + [[nodiscard]] virtual bool CanUnequipItem(Player* /*player*/, uint16 /*pos*/, bool /*swap*/) { return true; } + + [[nodiscard]] virtual bool CanUseItem(Player* /*player*/, ItemTemplate const* /*proto*/, InventoryResult& /*result*/) { return true; } + + [[nodiscard]] virtual bool CanSaveEquipNewItem(Player* /*player*/, Item* /*item*/, uint16 /*pos*/, bool /*update*/) { return true; } + + [[nodiscard]] virtual bool CanApplyEnchantment(Player* /*player*/, Item* /*item*/, EnchantmentSlot /*slot*/, bool /*apply*/, bool /*apply_dur*/, bool /*ignore_condition*/) { return true; } + + virtual void OnGetQuestRate(Player* /*player*/, float& /*result*/) { } + + [[nodiscard]] virtual bool PassedQuestKilledMonsterCredit(Player* /*player*/, Quest const* /*qinfo*/, uint32 /*entry*/, uint32 /*real_entry*/, uint64 /*guid*/) { return true; } + + [[nodiscard]] virtual bool CheckItemInSlotAtLoadInventory(Player* /*player*/, Item* /*item*/, uint8 /*slot*/, uint8& /*err*/, uint16& /*dest*/) { return true; } + + [[nodiscard]] virtual bool NotAvoidSatisfy(Player* /*player*/, DungeonProgressionRequirements const* /*ar*/, uint32 /*target_map*/, bool /*report*/) { return true; } + + [[nodiscard]] virtual bool NotVisibleGloballyFor(Player* /*player*/, Player const* /*u*/) { return true; } + + virtual void OnGetArenaPersonalRating(Player* /*player*/, uint8 /*slot*/, uint32& /*result*/) { } + + virtual void OnGetArenaTeamId(Player* /*player*/, uint8 /*slot*/, uint32& /*result*/) { } + + virtual void OnIsFFAPvP(Player* /*player*/, bool& /*result*/) { } + + virtual void OnIsPvP(Player* /*player*/, bool& /*result*/) { } + + virtual void OnGetMaxSkillValueForLevel(Player* /*player*/, uint16& /*result*/) { } + + [[nodiscard]] virtual bool NotSetArenaTeamInfoField(Player* /*player*/, uint8 /*slot*/, ArenaTeamInfoType /*type*/, uint32 /*value*/) { return true; } + + [[nodiscard]] virtual bool CanJoinLfg(Player* /*player*/, uint8 /*roles*/, lfg::LfgDungeonSet& /*dungeons*/, const std::string& /*comment*/) { return true; } + + [[nodiscard]] virtual bool CanEnterMap(Player* /*player*/, MapEntry const* /*entry*/, InstanceTemplate const* /*instance*/, MapDifficulty const* /*mapDiff*/, bool /*loginCheck*/) { return true; } + + [[nodiscard]] virtual bool CanInitTrade(Player* /*player*/, Player* /*target*/) { return true; } + + virtual void OnSetServerSideVisibility(Player* /*player*/, ServerSideVisibilityType& /*type*/, AccountTypes& /*sec*/) { } + + virtual void OnSetServerSideVisibilityDetect(Player* /*player*/, ServerSideVisibilityType& /*type*/, AccountTypes& /*sec*/) { } }; class AccountScript : public ScriptObject @@ -1025,6 +1148,8 @@ public: virtual void OnEvent(Guild* /*guild*/, uint8 /*eventType*/, uint32 /*playerGuid1*/, uint32 /*playerGuid2*/, uint8 /*newRank*/) { } virtual void OnBankEvent(Guild* /*guild*/, uint8 /*eventType*/, uint8 /*tabId*/, uint32 /*playerGuid*/, uint32 /*itemOrMoney*/, uint16 /*itemStackCount*/, uint8 /*destTabId*/) { } + + [[nodiscard]] virtual bool CanGuildSendBankList(Guild const* /*guild*/, WorldSession* /*session*/, uint8 /*tabId*/, bool /*sendAllSlots*/) { return true; } }; class GroupScript : public ScriptObject @@ -1049,6 +1174,10 @@ public: // Called when a group is disbanded. virtual void OnDisband(Group* /*group*/) { } + + [[nodiscard]] virtual bool CanGroupJoinBattlegroundQueue(Group const* /*group*/, Player* /*member*/, Battleground const* /*bgTemplate*/, uint32 /*MinPlayerCount*/, bool /*isRated*/, uint32 /*arenaSlot*/) { return true; } + + virtual void OnCreate(Group* /*group*/, Player* /*leader*/) { } }; // following hooks can be used anywhere and are not db bounded @@ -1067,7 +1196,7 @@ public: virtual void OnBeforeDropAddItem(Player const* /*player*/, Loot& /*loot*/, bool /*canRate*/, uint16 /*lootMode*/, LootStoreItem* /*LootStoreItem*/, LootStore const& /*store*/) { } virtual void OnItemRoll(Player const* /*player*/, LootStoreItem const* /*LootStoreItem*/, float& /*chance*/, Loot& /*loot*/, LootStore const& /*store*/) { }; - virtual void OnInitializeLockedDungeons(Player* /*player*/, uint8& /*level*/, uint32& /*lockData*/) { } + virtual void OnInitializeLockedDungeons(Player* /*player*/, uint8& /*level*/, uint32& /*lockData*/, lfg::LFGDungeonData const* /*dungeon*/) { } virtual void OnAfterInitializeLockedDungeons(Player* /*player*/) { } // On Before arena points distribution @@ -1106,16 +1235,20 @@ public: // Remove player at leave BG virtual void OnBattlegroundRemovePlayerAtLeave(Battleground* /*bg*/, Player* /*player*/) { } + virtual void OnQueueUpdate(BattlegroundQueue* /*queue*/, BattlegroundBracketId /*bracket_id*/, bool /*isRated*/, uint32 /*arenaRatedTeamId*/) { } + virtual void OnAddGroup(BattlegroundQueue* /*queue*/, GroupQueueInfo* /*ginfo*/, uint32& /*index*/, Player* /*leader*/, Group* /*grp*/, PvPDifficultyEntry const* /*bracketEntry*/, bool /*isPremade*/) { } - virtual bool CanFillPlayersToBG(BattlegroundQueue* /*queue*/, Battleground* /*bg*/, const int32 /*aliFree*/, const int32 /*hordeFree*/, BattlegroundBracketId /*bracket_id*/) { return true; } + [[nodiscard]] virtual bool CanFillPlayersToBG(BattlegroundQueue* /*queue*/, Battleground* /*bg*/, const int32 /*aliFree*/, const int32 /*hordeFree*/, BattlegroundBracketId /*bracket_id*/) { return true; } - virtual bool CanFillPlayersToBGWithSpecific(BattlegroundQueue* /*queue*/, Battleground* /*bg*/, const int32 /*aliFree*/, const int32 /*hordeFree*/, + [[nodiscard]] virtual bool CanFillPlayersToBGWithSpecific(BattlegroundQueue* /*queue*/, Battleground* /*bg*/, const int32 /*aliFree*/, const int32 /*hordeFree*/, BattlegroundBracketId /*thisBracketId*/, BattlegroundQueue* /*specificQueue*/, BattlegroundBracketId /*specificBracketId*/) { return true; } virtual void OnCheckNormalMatch(BattlegroundQueue* /*queue*/, uint32& /*Coef*/, Battleground* /*bgTemplate*/, BattlegroundBracketId /*bracket_id*/, uint32& /*minPlayers*/, uint32& /*maxPlayers*/) { } - virtual bool CanSendMessageQueue(BattlegroundQueue* /*queue*/, Player* /*leader*/, Battleground* /*bg*/, PvPDifficultyEntry const* /*bracketEntry*/) { return true; } + [[nodiscard]] virtual bool CanSendMessageBGQueue(BattlegroundQueue* /*queue*/, Player* /*leader*/, Battleground* /*bg*/, PvPDifficultyEntry const* /*bracketEntry*/) { return true; } + + [[nodiscard]] virtual bool CanSendMessageArenaQueue(BattlegroundQueue* /*queue*/, GroupQueueInfo* /*ginfo*/, bool /*IsJoin*/) { return true; } }; class ArenaTeamScript : public ScriptObject @@ -1143,6 +1276,24 @@ public: // Calculate max duration in applying aura virtual void OnCalcMaxDuration(Aura const* /*aura*/, int32& /*maxDuration*/) { } + + [[nodiscard]] virtual bool CanModAuraEffectDamageDone(AuraEffect const* /*auraEff*/, Unit* /*target*/, AuraApplication const* /*aurApp*/, uint8 /*mode*/, bool /*apply*/) { return true; } + + [[nodiscard]] virtual bool CanModAuraEffectModDamagePercentDone(AuraEffect const* /*auraEff*/, Unit* /*target*/, AuraApplication const* /*aurApp*/, uint8 /*mode*/, bool /*apply*/) { return true; } + + virtual void OnSpellCheckCast(Spell* /*spell*/, bool /*strict*/, SpellCastResult& /*res*/) { } + + [[nodiscard]] virtual bool CanPrepare(Spell* /*spell*/, SpellCastTargets const* /*targets*/, AuraEffect const* /*triggeredByAura*/) { return true; } + + [[nodiscard]] virtual bool CanScalingEverything(Spell* /*spell*/) { return false; } + + [[nodiscard]] virtual bool CanSelectSpecTalent(Spell* /*spell*/) { return true; } + + virtual void OnScaleAuraUnitAdd(Spell* /*spell*/, Unit* /*target*/, uint32 /*effectMask*/, bool /*checkIfValid*/, bool /*implicit*/, uint8 /*auraScaleMask*/, TargetInfo& /*targetInfo*/) { } + + virtual void OnRemoveAuraScaleTargets(Spell* /*spell*/, TargetInfo& /*targetInfo*/, uint8 /*auraScaleMask*/, bool& /*needErase*/) { } + + virtual void OnBeforeAuraRankForLevel(SpellInfo const* /*spellInfo*/, SpellInfo const* /*latestSpellInfo*/, uint8 /*level*/) { } }; // this class can be used to be extended by Modules @@ -1176,6 +1327,124 @@ public: virtual void OnBeforeMailDraftSendMailTo(MailDraft* /*mailDraft*/, MailReceiver const& /*receiver*/, MailSender const& /*sender*/, MailCheckMask& /*checked*/, uint32& /*deliver_delay*/, uint32& /*custom_expiration*/, bool& /*deleteMailItemsFromDB*/, bool& /*sendMail*/) { } }; +class AchievementScript : public ScriptObject +{ +protected: + + AchievementScript(const char* name); + +public: + + bool IsDatabaseBound() const { return false; } + + // After complete global acvievement + virtual void SetRealmCompleted(AchievementEntry const* /*achievement*/) { } + + [[nodiscard]] virtual bool IsCompletedCriteria(AchievementMgr* /*mgr*/, AchievementCriteriaEntry const* /*achievementCriteria*/, AchievementEntry const* /*achievement*/, CriteriaProgress const* /*progress*/) { return true; } + + [[nodiscard]] virtual bool IsRealmCompleted(AchievementGlobalMgr const* /*globalmgr*/, AchievementEntry const* /*achievement*/, std::chrono::system_clock::time_point /*completionTime*/) { return true; } + + virtual void OnBeforeCheckCriteria(AchievementMgr* /*mgr*/, AchievementCriteriaEntryList const* /*achievementCriteriaList*/) { } + + [[nodiscard]] virtual bool CanCheckCriteria(AchievementMgr* /*mgr*/, AchievementCriteriaEntry const* /*achievementCriteria*/) { return true; } +}; + +class PetScript : public ScriptObject +{ +protected: + + PetScript(const char* name); + +public: + + bool IsDatabaseBound() const { return false; } + + virtual void OnInitStatsForLevel(Guardian* /*guardian*/, uint8 /*petlevel*/) { } + + virtual void OnCalculateMaxTalentPointsForLevel(Pet* /*pet*/, uint8 /*level*/, uint8& /*points*/) { } + + [[nodiscard]] virtual bool CanUnlearnSpellSet(Pet* /*pet*/, uint32 /*level*/, uint32 /*spell*/) { return true; } + + [[nodiscard]] virtual bool CanUnlearnSpellDefault(Pet* /*pet*/, SpellInfo const* /*spellEntry*/) { return true; } + + [[nodiscard]] virtual bool CanResetTalents(Pet* /*pet*/) { return true; } +}; + +class ArenaScript : public ScriptObject +{ +protected: + + ArenaScript(const char* name); + +public: + + bool IsDatabaseBound() const { return false; } + + [[nodiscard]] virtual bool CanAddMember(ArenaTeam* /*team*/, uint64 /*PlayerGuid*/) { return true; } + + virtual void OnGetPoints(ArenaTeam* /*team*/, uint32 /*memberRating*/, float& /*points*/) { } + + [[nodiscard]] virtual bool CanSaveToDB(ArenaTeam* /*team*/) { return true; } +}; + +class MiscScript : public ScriptObject +{ +protected: + + MiscScript(const char* name); + +public: + + bool IsDatabaseBound() const { return false; } + + virtual void OnConstructObject(Object* /*origin*/) { } + + virtual void OnDestructObject(Object* /*origin*/) { } + + virtual void OnConstructPlayer(Player* /*origin*/) { } + + virtual void OnDestructPlayer(Player* /*origin*/) { } + + virtual void OnConstructGroup(Group* /*origin*/) { } + + virtual void OnDestructGroup(Group* /*origin*/) { } + + virtual void OnConstructInstanceSave(InstanceSave* /*origin*/) { } + + virtual void OnDestructInstanceSave(InstanceSave* /*origin*/) { } + + virtual void OnItemCreate(Item* /*item*/, ItemTemplate const* /*itemProto*/, Player const* /*owner*/) { } + + [[nodiscard]] virtual bool CanApplySoulboundFlag(Item* /*item*/, ItemTemplate const* /*proto*/) { return true; } + + [[nodiscard]] virtual bool CanItemApplyEquipSpell(Player* /*player*/, Item* /*item*/) { return true; } + + [[nodiscard]] virtual bool CanSendAuctionHello(WorldSession const* /*session*/, uint64 /*guid*/, Creature* /*creature*/) { return true; } + + virtual void ValidateSpellAtCastSpell(Player* /*player*/, uint32& /*oldSpellId*/, uint32& /*spellId*/, uint8& /*castCount*/, uint8& /*castFlags*/) { } + + virtual void ValidateSpellAtCastSpellResult(Player* /*player*/, Unit* /*mover*/, Spell* /*spell*/, uint32 /*oldSpellId*/, uint32 /*spellId*/) { } + + virtual void OnAfterLootTemplateProcess(Loot* /*loot*/, LootTemplate const* /*tab*/, LootStore const& /*store*/, Player* /*lootOwner*/, bool /*personal*/, bool /*noEmptyError*/, uint16 /*lootMode*/) { } + + virtual void OnPlayerSetPhase(const AuraEffect* /*auraEff*/, AuraApplication const* /*aurApp*/, uint8 /*mode*/, bool /*apply*/, uint32& /*newPhase*/) { } + + virtual void OnInstanceSave(InstanceSave* /*instanceSave*/) { } +}; + +class CommandSC : public ScriptObject +{ +protected: + + CommandSC(const char* name); + +public: + + bool IsDatabaseBound() const { return false; } + + virtual void OnHandleDevCommand(Player* /*player*/, std::string& /*argstr*/) { } +}; + // Manages registration, loading, and execution of scripts. class ScriptMgr { @@ -1234,6 +1503,7 @@ public: /* FormulaScript */ void OnGainCalculation(uint32& gain, Player* player, Unit* unit); void OnGroupRateCalculation(float& rate, uint32 count, bool isRaid); void OnAfterArenaRatingCalculation(Battleground* const bg, int32& winnerMatchmakerChange, int32& loserMatchmakerChange, int32& winnerChange, int32& loserChange); + void OnBeforeUpdatingPersonalRating(int32& mod, uint32 type); public: /* MapScript */ void OnCreateMap(Map* map); @@ -1396,8 +1666,11 @@ public: /* PlayerScript */ void OnLootItem(Player* player, Item* item, uint32 count, uint64 lootguid); void OnCreateItem(Player* player, Item* item, uint32 count); void OnQuestRewardItem(Player* player, Item* item, uint32 count); + bool OnBeforePlayerQuestComplete(Player* player, uint32 quest_id); + void OnBeforePlayerDurabilityRepair(Player* player, uint64 npcGUID, uint64 itemGUID, float& discountMod, uint8 guildBank); void OnBeforeBuyItemFromVendor(Player* player, uint64 vendorguid, uint32 vendorslot, uint32& item, uint8 count, uint8 bag, uint8 slot); - void OnAfterStoreOrEquipNewItem(Player* player, uint32 vendorslot, uint32& item, uint8 count, uint8 bag, uint8 slot, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore); + void OnBeforeStoreOrEquipNewItem(Player* player, uint32 vendorslot, uint32& item, uint8 count, uint8 bag, uint8 slot, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore); + void OnAfterStoreOrEquipNewItem(Player* player, uint32 vendorslot, Item* item, uint8 count, uint8 bag, uint8 slot, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore); void OnAfterUpdateMaxPower(Player* player, Powers& power, float& value); void OnAfterUpdateMaxHealth(Player* player, float& value); void OnBeforeUpdateAttackPowerAndDamage(Player* player, float& level, float& val2, bool ranged); @@ -1412,6 +1685,53 @@ public: /* PlayerScript */ void OnBeforeGuardianInitStatsForLevel(Player* player, Guardian* guardian, CreatureTemplate const* cinfo, PetType& petType); void OnAfterGuardianInitStatsForLevel(Player* player, Guardian* guardian); void OnBeforeLoadPetFromDB(Player* player, uint32& petentry, uint32& petnumber, bool& current, bool& forceLoadFromDB); + bool CanJoinInArenaQueue(Player* player, uint64 BattlemasterGuid, uint8 arenaslot, BattlegroundTypeId BGTypeID, uint8 joinAsGroup, uint8 IsRated, GroupJoinBattlegroundResult& err); + bool CanBattleFieldPort(Player* player, uint8 arenaType, BattlegroundTypeId BGTypeID, uint8 action); + bool CanGroupInvite(Player* player, std::string& membername); + bool CanGroupAccept(Player* player, Group* group); + bool CanSellItem(Player* player, Item* item, Creature* creature); + bool CanSendMail(Player* player, uint64 receiverGuid, uint64 mailbox, std::string& subject, std::string& body, uint32 money, uint32 COD, Item* item); + void PetitionBuy(Player* player, Creature* creature, uint32& charterid, uint32& cost, uint32& type); + void PetitionShowList(Player* player, Creature* creature, uint32& CharterEntry, uint32& CharterDispayID, uint32& CharterCost); + void OnRewardKillRewarder(Player* player, bool isDungeon, float& rate); + bool CanGiveMailRewardAtGiveLevel(Player* player, uint8 level); + void OnDeleteFromDB(SQLTransaction& trans, uint32 guid); + bool CanRepopAtGraveyard(Player* player); + void OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, bool IsPure); + bool CanAreaExploreAndOutdoor(Player* player); + void OnVictimRewardBefore(Player* player, Player* victim, uint32& killer_title, uint32& victim_title); + void OnVictimRewardAfter(Player* player, Player* victim, uint32& killer_title, uint32& victim_rank, float& honor_f); + void OnCustomScalingStatValueBefore(Player* player, ItemTemplate const* proto, uint8 slot, bool apply, uint32& CustomScalingStatValue); + void OnCustomScalingStatValue(Player* player, ItemTemplate const* proto, uint32& statType, int32& val, uint8 itemProtoStatNumber, uint32 ScalingStatValue, ScalingStatValuesEntry const* ssv); + bool CanArmorDamageModifier(Player* player); + void OnGetFeralApBonus(Player* player, int32& feral_bonus, int32 dpsMod, ItemTemplate const* proto, ScalingStatValuesEntry const* ssv); + bool CanApplyWeaponDependentAuraDamageMod(Player* player, Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply); + bool CanApplyEquipSpell(Player* player, SpellInfo const* spellInfo, Item* item, bool apply, bool form_change); + bool CanApplyEquipSpellsItemSet(Player* player, ItemSetEffect* eff); + bool CanCastItemCombatSpell(Player* player, Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto); + bool CanCastItemUseSpell(Player* player, Item* item, SpellCastTargets const& targets, uint8 cast_count, uint32 glyphIndex); + void OnApplyAmmoBonuses(Player* player, ItemTemplate const* proto, float& currentAmmoDPS); + bool CanEquipItem(Player* player, uint8 slot, uint16& dest, Item* pItem, bool swap, bool not_loading); + bool CanUnequipItem(Player* player, uint16 pos, bool swap); + bool CanUseItem(Player* player, ItemTemplate const* proto, InventoryResult& result); + bool CanSaveEquipNewItem(Player* player, Item* item, uint16 pos, bool update); + bool CanApplyEnchantment(Player* player, Item* item, EnchantmentSlot slot, bool apply, bool apply_dur, bool ignore_condition); + void OnGetQuestRate(Player* player, float& result); + bool PassedQuestKilledMonsterCredit(Player* player, Quest const* qinfo, uint32 entry, uint32 real_entry, uint64 guid); + bool CheckItemInSlotAtLoadInventory(Player* player, Item* item, uint8 slot, uint8& err, uint16& dest); + bool NotAvoidSatisfy(Player* player, DungeonProgressionRequirements const* ar, uint32 target_map, bool report); + bool NotVisibleGloballyFor(Player* player, Player const* u); + void OnGetArenaPersonalRating(Player* player, uint8 slot, uint32& result); + void OnGetArenaTeamId(Player* player, uint8 slot, uint32& result); + void OnIsFFAPvP(Player* player, bool& result); + void OnIsPvP(Player* player, bool& result); + void OnGetMaxSkillValueForLevel(Player* player, uint16& result); + bool NotSetArenaTeamInfoField(Player* player, uint8 slot, ArenaTeamInfoType type, uint32 value); + bool CanJoinLfg(Player* player, uint8 roles, lfg::LfgDungeonSet& dungeons, const std::string& comment); + bool CanEnterMap(Player* player, MapEntry const* entry, InstanceTemplate const* instance, MapDifficulty const* mapDiff, bool loginCheck); + bool CanInitTrade(Player* player, Player* target); + void OnSetServerSideVisibility(Player* player, ServerSideVisibilityType& type, AccountTypes& sec); + void OnSetServerSideVisibilityDetect(Player* player, ServerSideVisibilityType& type, AccountTypes& sec); public: /* AccountScript */ void OnAccountLogin(uint32 accountId); @@ -1435,6 +1755,7 @@ public: /* GuildScript */ bool isDestBank, uint8 destContainer, uint8 destSlotId); void OnGuildEvent(Guild* guild, uint8 eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank); void OnGuildBankEvent(Guild* guild, uint8 eventType, uint8 tabId, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId); + bool CanGuildSendBankList(Guild const* guild, WorldSession* session, uint8 tabId, bool sendAllSlots); public: /* GroupScript */ void OnGroupAddMember(Group* group, uint64 guid); @@ -1442,6 +1763,8 @@ public: /* GroupScript */ void OnGroupRemoveMember(Group* group, uint64 guid, RemoveMethod method, uint64 kicker, const char* reason); void OnGroupChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid); void OnGroupDisband(Group* group); + bool CanGroupJoinBattlegroundQueue(Group const* group, Player* member, Battleground const* bgTemplate, uint32 MinPlayerCount, bool isRated, uint32 arenaSlot); + void OnCreate(Group* group, Player* leader); public: /* GlobalScript */ void OnGlobalItemDelFromDB(SQLTransaction& trans, uint32 itemGuid); @@ -1450,7 +1773,7 @@ public: /* GlobalScript */ void OnAfterRefCount(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, uint32& maxcount, LootStore const& store); void OnBeforeDropAddItem(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, LootStore const& store); void OnItemRoll(Player const* player, LootStoreItem const* LootStoreItem, float& chance, Loot& loot, LootStore const& store); - void OnInitializeLockedDungeons(Player* player, uint8& level, uint32& lockData); + void OnInitializeLockedDungeons(Player* player, uint8& level, uint32& lockData, lfg::LFGDungeonData const* dungeon); void OnAfterInitializeLockedDungeons(Player* player); void OnAfterUpdateEncounterState(Map* map, EncounterCreditType type, uint32 creditEntry, Unit* source, Difficulty difficulty_fixed, DungeonEncounterList const* encounters, uint32 dungeonCompleted, bool updated); void OnBeforeWorldObjectSetPhaseMask(WorldObject const* worldObject, uint32& oldPhaseMask, uint32& newPhaseMask, bool& useCombinedPhases, bool& update); @@ -1470,6 +1793,13 @@ public: /* UnitScript */ void ModifyHealRecieved(Unit* target, Unit* attacker, uint32& addHealth); uint32 DealDamage(Unit* AttackerUnit, Unit* pVictim, uint32 damage, DamageEffectType damagetype); void OnBeforeRollMeleeOutcomeAgainst(const Unit* attacker, const Unit* victim, WeaponAttackType attType, int32& attackerMaxSkillValueForLevel, int32& victimMaxSkillValueForLevel, int32& attackerWeaponSkill, int32& victimDefenseSkill, int32& crit_chance, int32& miss_chance, int32& dodge_chance, int32& parry_chance, int32& block_chance); + void OnAuraRemove(Unit* unit, AuraApplication* aurApp, AuraRemoveMode mode); + bool IfNormalReaction(Unit const* unit, Unit const* target, ReputationRank& repRank); + bool IsNeedModSpellDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto); + bool IsNeedModMeleeDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto); + bool IsNeedModHealPercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto); + bool CanSetPhaseMask(Unit const* unit, uint32 newPhaseMask, bool update); + bool IsCustomBuildValuesUpdate(Unit const* unit, uint8 updateType, ByteBuffer& fieldBuffer, Player const* target, uint16 index); public: /* MovementHandlerScript */ void OnPlayerMove(Player* player, MovementInfo movementInfo, uint32 opcode); @@ -1491,12 +1821,14 @@ public: /* BGScript */ void OnBattlegroundAddPlayer(Battleground* bg, Player* player); void OnBattlegroundBeforeAddPlayer(Battleground* bg, Player* player); void OnBattlegroundRemovePlayerAtLeave(Battleground* bg, Player* player); + void OnQueueUpdate(BattlegroundQueue* queue, BattlegroundBracketId bracket_id, bool isRated, uint32 arenaRatedTeamId); void OnAddGroup(BattlegroundQueue* queue, GroupQueueInfo* ginfo, uint32& index, Player* leader, Group* grp, PvPDifficultyEntry const* bracketEntry, bool isPremade); bool CanFillPlayersToBG(BattlegroundQueue* queue, Battleground* bg, const int32 aliFree, const int32 hordeFree, BattlegroundBracketId bracket_id); bool CanFillPlayersToBGWithSpecific(BattlegroundQueue* queue, Battleground* bg, const int32 aliFree, const int32 hordeFree, BattlegroundBracketId thisBracketId, BattlegroundQueue* specificQueue, BattlegroundBracketId specificBracketId); void OnCheckNormalMatch(BattlegroundQueue* queue, uint32& Coef, Battleground* bgTemplate, BattlegroundBracketId bracket_id, uint32& minPlayers, uint32& maxPlayers); - bool CanSendMessageQueue(BattlegroundQueue* queue, Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry); + bool CanSendMessageBGQueue(BattlegroundQueue* queue, Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry); + bool CanSendMessageArenaQueue(BattlegroundQueue* queue, GroupQueueInfo* ginfo, bool IsJoin); public: /* Arena Team Script */ void OnGetSlotByType(const uint32 type, uint8& slot); @@ -1507,6 +1839,15 @@ public: /* Arena Team Script */ public: /* SpellSC */ void OnCalcMaxDuration(Aura const* aura, int32& maxDuration); + bool CanModAuraEffectDamageDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply); + bool CanModAuraEffectModDamagePercentDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply); + void OnSpellCheckCast(Spell* spell, bool strict, SpellCastResult& res); + bool CanPrepare(Spell* spell, SpellCastTargets const* targets, AuraEffect const* triggeredByAura); + bool CanScalingEverything(Spell* spell); + bool CanSelectSpecTalent(Spell* spell); + void OnScaleAuraUnitAdd(Spell* spell, Unit* target, uint32 effectMask, bool checkIfValid, bool implicit, uint8 auraScaleMask, TargetInfo& targetInfo); + void OnRemoveAuraScaleTargets(Spell* spell, TargetInfo& targetInfo, uint8 auraScaleMask, bool& needErase); + void OnBeforeAuraRankForLevel(SpellInfo const* spellInfo, SpellInfo const* latestSpellInfo, uint8 level); public: /* GameEventScript */ void OnGameEventStart(uint16 EventID); @@ -1515,6 +1856,52 @@ public: /* GameEventScript */ public: /* MailScript */ void OnBeforeMailDraftSendMailTo(MailDraft* mailDraft, MailReceiver const& receiver, MailSender const& sender, MailCheckMask& checked, uint32& deliver_delay, uint32& custom_expiration, bool& deleteMailItemsFromDB, bool& sendMail); +public: /* AchievementScript */ + + void SetRealmCompleted(AchievementEntry const* achievement); + bool IsCompletedCriteria(AchievementMgr* mgr, AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement, CriteriaProgress const* progress); + bool IsRealmCompleted(AchievementGlobalMgr const* globalmgr, AchievementEntry const* achievement, std::chrono::system_clock::time_point completionTime); + void OnBeforeCheckCriteria(AchievementMgr* mgr, AchievementCriteriaEntryList const* achievementCriteriaList); + bool CanCheckCriteria(AchievementMgr* mgr, AchievementCriteriaEntry const* achievementCriteria); + + public: /* PetScript */ + + void OnInitStatsForLevel(Guardian* guardian, uint8 petlevel); + void OnCalculateMaxTalentPointsForLevel(Pet* pet, uint8 level, uint8& points); + bool CanUnlearnSpellSet(Pet* pet, uint32 level, uint32 spell); + bool CanUnlearnSpellDefault(Pet* pet, SpellInfo const* spellEntry); + bool CanResetTalents(Pet* pet); + + public: /* ArenaScript */ + + bool CanAddMember(ArenaTeam* team, uint64 PlayerGuid); + void OnGetPoints(ArenaTeam* team, uint32 memberRating, float& points); + bool CanSaveToDB(ArenaTeam* team); + + public: /* MiscScript */ + + void OnConstructObject(Object* origin); + void OnDestructObject(Object* origin); + void OnConstructPlayer(Player* origin); + void OnDestructPlayer(Player* origin); + void OnConstructGroup(Group* origin); + void OnDestructGroup(Group* origin); + void OnConstructInstanceSave(InstanceSave* origin); + void OnDestructInstanceSave(InstanceSave* origin); + void OnItemCreate(Item* item, ItemTemplate const* itemProto, Player const* owner); + bool CanApplySoulboundFlag(Item* item, ItemTemplate const* proto); + bool CanItemApplyEquipSpell(Player* player, Item* item); + bool CanSendAuctionHello(WorldSession const* session, uint64 guid, Creature* creature); + void ValidateSpellAtCastSpell(Player* player, uint32& oldSpellId, uint32& spellId, uint8& castCount, uint8& castFlags); + void OnPlayerSetPhase(const AuraEffect* auraEff, AuraApplication const* aurApp, uint8 mode, bool apply, uint32& newPhase); + void ValidateSpellAtCastSpellResult(Player* player, Unit* mover, Spell* spell, uint32 oldSpellId, uint32 spellId); + void OnAfterLootTemplateProcess(Loot* loot, LootTemplate const* tab, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError, uint16 lootMode); + void OnInstanceSave(InstanceSave* instanceSave); + + public: /* CommandSC */ + + void OnHandleDevCommand(Player* player, std::string& argstr); + private: uint32 _scriptCount; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 5ef3ab3620..b7b7ebc594 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -4726,7 +4726,7 @@ void AuraEffect::HandleModDamageDone(AuraApplication const* aurApp, uint8 mode, // with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask // GetMiscValue() comparison with item generated damage types - if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0) + if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0 && sScriptMgr->CanModAuraEffectDamageDone(this, target, aurApp, mode, apply)) { // apply generic physical damage bonuses including wand case if (GetSpellInfo()->EquippedItemClass == -1 || target->GetTypeId() != TYPEID_PLAYER) @@ -4796,6 +4796,9 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 if (!target) return; + if (!sScriptMgr->CanModAuraEffectModDamagePercentDone(this, target, aurApp, mode, apply)) + return; + if (target->GetTypeId() == TYPEID_PLAYER) { for (int i = 0; i < MAX_ATTACK; ++i) diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 92f9ceaf19..54141478d9 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -836,19 +836,21 @@ void Spell::SelectSpellTargets() else if (m_auraScaleMask) { bool checkLvl = !m_UniqueTargetInfo.empty(); - for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end();) + for (std::list<TargetInfo>::iterator itr = m_UniqueTargetInfo.begin(); itr != m_UniqueTargetInfo.end(); ++itr) { // remove targets which did not pass min level check - if (m_auraScaleMask && ihit->effectMask == m_auraScaleMask) + if (m_auraScaleMask && itr->effectMask == m_auraScaleMask) { - // Do not check for selfcast - if (!ihit->scaleAura && ihit->targetGUID != m_caster->GetGUID()) - { - m_UniqueTargetInfo.erase(ihit++); - continue; - } + bool needErase = false; + + if (!itr->scaleAura && itr->targetGUID != m_caster->GetGUID()) + needErase = true; + + sScriptMgr->OnRemoveAuraScaleTargets(this, *itr, m_auraScaleMask, needErase); + + if (needErase) + m_UniqueTargetInfo.erase(itr); } - ++ihit; } if (checkLvl && m_UniqueTargetInfo.empty()) { @@ -2154,6 +2156,8 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= if (uint32(target->getLevel() + 10) >= auraSpell->SpellLevel) ihit->scaleAura = true; } + + sScriptMgr->OnScaleAuraUnitAdd(this, target, effectMask, checkIfValid, implicit, m_auraScaleMask, *ihit); return; } } @@ -2176,6 +2180,8 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= targetInfo.scaleAura = true; } + sScriptMgr->OnScaleAuraUnitAdd(this, target, effectMask, checkIfValid, implicit, m_auraScaleMask, targetInfo); + // Calculate hit result if (m_originalCaster) { @@ -3163,8 +3169,14 @@ SpellCastResult Spell::prepare(SpellCastTargets const* targets, AuraEffect const InitExplicitTargets(*targets); + if (!sScriptMgr->CanPrepare(this, targets, triggeredByAura)) + { + finish(false); + return SPELL_FAILED_UNKNOWN; + } + // Fill aura scaling information - if (m_caster->IsTotem() || (m_caster->IsControlledByPlayer() && !m_spellInfo->IsPassive() && m_spellInfo->SpellLevel && !m_spellInfo->IsChanneled() && !(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_SCALING))) + if (sScriptMgr->CanScalingEverything(this) || m_caster->IsTotem() || (m_caster->IsControlledByPlayer() && !m_spellInfo->IsPassive() && m_spellInfo->SpellLevel && !m_spellInfo->IsChanneled() && !(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_SCALING))) { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { @@ -5140,6 +5152,13 @@ SpellCastResult Spell::CheckCast(bool strict) if (((const Player*)m_caster)->IsSpectator() && m_spellInfo->Id != SPECTATOR_SPELL_BINDSIGHT) return SPELL_FAILED_NOT_HERE; + SpellCastResult res = SPELL_CAST_OK; + + sScriptMgr->OnSpellCheckCast(this, strict, res); + + if (res != SPELL_CAST_OK) + return res; + // check cooldowns to prevent cheating if (!m_spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE)) { @@ -5969,6 +5988,8 @@ SpellCastResult Spell::CheckCast(bool strict) break; } case SPELL_EFFECT_TALENT_SPEC_SELECT: + if (!sScriptMgr->CanSelectSpecTalent(this)) + return SPELL_FAILED_DONT_REPORT; // can't change during already started arena/battleground if (m_caster->GetTypeId() == TYPEID_PLAYER) if (Battleground const* bg = m_caster->ToPlayer()->GetBattleground()) diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 68317b3937..ffe17b604f 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -234,6 +234,21 @@ struct ChannelTargetData SpellDestination spellDst; }; + // Targets store structures and data +struct TargetInfo +{ + uint64 targetGUID; + uint64 timeDelay; + SpellMissInfo missCondition:8; + SpellMissInfo reflectResult:8; + uint8 effectMask:8; + bool processed:1; + bool alive:1; + bool crit:1; + bool scaleAura:1; + int32 damage; +}; + static const uint32 SPELL_INTERRUPT_NONPLAYER = 32747; class Spell @@ -241,6 +256,9 @@ class Spell friend void Unit::SetCurrentCastedSpell(Spell* pSpell); friend class SpellScript; public: + Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, uint64 originalCasterGUID = 0, bool skipCheck = false); + ~Spell(); + void EffectNULL(SpellEffIndex effIndex); void EffectUnused(SpellEffIndex effIndex); void EffectDistract(SpellEffIndex effIndex); @@ -369,9 +387,6 @@ public: typedef std::set<Aura*> UsedSpellMods; - Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, uint64 originalCasterGUID = 0, bool skipCheck = false); - ~Spell(); - void InitExplicitTargets(SpellCastTargets const& targets); void SelectExplicitTargets(); @@ -473,7 +488,7 @@ public: void HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOTarget, uint32 i, SpellEffectHandleMode mode); void HandleThreatSpells(); - SpellInfo const* const m_spellInfo; + SpellInfo const* m_spellInfo; Item* m_CastItem; uint64 m_castItemGUID; uint8 m_cast_count; @@ -511,6 +526,7 @@ public: Unit* GetCaster() const { return m_caster; } Unit* GetOriginalCaster() const { return m_originalCaster; } SpellInfo const* GetSpellInfo() const { return m_spellInfo; } + void SetSpellInfo(SpellInfo const* info) { m_spellInfo = info; } int32 GetPowerCost() const { return m_powerCost; } bool UpdatePointers(); // must be used at call Spell code after time delay (non triggered spell cast/update spell call/etc) @@ -522,21 +538,6 @@ public: // xinef: moved to public void LoadScripts(); - - // Targets store structures and data - struct TargetInfo - { - uint64 targetGUID; - uint64 timeDelay; - SpellMissInfo missCondition: 8; - SpellMissInfo reflectResult: 8; - uint8 effectMask: 8; - bool processed: 1; - bool alive: 1; - bool crit: 1; - bool scaleAura: 1; - int32 damage; - }; std::list<TargetInfo>* GetUniqueTargetInfo() { return &m_UniqueTargetInfo; } protected: bool HasGlobalCooldown() const; diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index a109f86267..513f73c355 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -9,6 +9,7 @@ #include "ConditionMgr.h" #include "DBCStores.h" #include "Player.h" +#include "ScriptMgr.h" #include "Spell.h" #include "SpellAuraDefines.h" #include "SpellAuraEffects.h" @@ -2487,7 +2488,14 @@ SpellInfo const* SpellInfo::GetAuraRankForLevel(uint8 level) const if (!needRankSelection) return this; - for (SpellInfo const* nextSpellInfo = this; nextSpellInfo != nullptr; nextSpellInfo = nextSpellInfo->GetPrevRankSpell()) + SpellInfo const* nextSpellInfo = nullptr; + + sScriptMgr->OnBeforeAuraRankForLevel(this, nextSpellInfo, level); + + if (nextSpellInfo != nullptr) + return nextSpellInfo; + + for (nextSpellInfo = this; nextSpellInfo != nullptr; nextSpellInfo = nextSpellInfo->GetPrevRankSpell()) { // if found appropriate level if (uint32(level + 10) >= nextSpellInfo->SpellLevel) diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 7839fa1728..944ba22c90 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -347,12 +347,14 @@ public: { player->SetDeveloper(true); handler->GetSession()->SendNotification(LANG_DEV_ON); + sScriptMgr->OnHandleDevCommand(handler->GetSession()->GetPlayer(), enablestr); return true; } else if (enablestr == "off") { player->SetDeveloper(false); handler->GetSession()->SendNotification(LANG_DEV_OFF); + sScriptMgr->OnHandleDevCommand(handler->GetSession()->GetPlayer(), enablestr); return true; } diff --git a/src/server/scripts/Outland/BlackTemple/boss_mother_shahraz.cpp b/src/server/scripts/Outland/BlackTemple/boss_mother_shahraz.cpp index 7753f111b6..7b888c8255 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_mother_shahraz.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_mother_shahraz.cpp @@ -265,8 +265,8 @@ public: void SetDest(SpellDestination& dest) { - std::list<Spell::TargetInfo> const* targetsInfo = GetSpell()->GetUniqueTargetInfo(); - for (std::list<Spell::TargetInfo>::const_iterator ihit = targetsInfo->begin(); ihit != targetsInfo->end(); ++ihit) + std::list<TargetInfo> const* targetsInfo = GetSpell()->GetUniqueTargetInfo(); + for (std::list<TargetInfo>::const_iterator ihit = targetsInfo->begin(); ihit != targetsInfo->end(); ++ihit) if (Unit* target = ObjectAccessor::GetUnit(*GetCaster(), ihit->targetGUID)) { dest.Relocate(*target); diff --git a/src/server/scripts/Outland/BlackTemple/illidari_council.cpp b/src/server/scripts/Outland/BlackTemple/illidari_council.cpp index 1de9f2f5f9..96f0f33a39 100644 --- a/src/server/scripts/Outland/BlackTemple/illidari_council.cpp +++ b/src/server/scripts/Outland/BlackTemple/illidari_council.cpp @@ -613,8 +613,8 @@ public: } float pct = (_sharedHealth / _sharedHealthMax) * 100.0f; - std::list<Spell::TargetInfo> const* targetsInfo = GetSpell()->GetUniqueTargetInfo(); - for (std::list<Spell::TargetInfo>::const_iterator ihit = targetsInfo->begin(); ihit != targetsInfo->end(); ++ihit) + std::list<TargetInfo> const* targetsInfo = GetSpell()->GetUniqueTargetInfo(); + for (std::list<TargetInfo>::const_iterator ihit = targetsInfo->begin(); ihit != targetsInfo->end(); ++ihit) if (Creature* target = ObjectAccessor::GetCreature(*GetCaster(), ihit->targetGUID)) { target->LowerPlayerDamageReq(target->GetMaxHealth()); diff --git a/src/server/scripts/Pet/pet_generic.cpp b/src/server/scripts/Pet/pet_generic.cpp index 7372126909..b73967bb29 100644 --- a/src/server/scripts/Pet/pet_generic.cpp +++ b/src/server/scripts/Pet/pet_generic.cpp @@ -606,8 +606,8 @@ public: { if (GetHitUnit() != GetCaster()) { - std::list<Spell::TargetInfo>* targetsInfo = GetSpell()->GetUniqueTargetInfo(); - for (std::list<Spell::TargetInfo>::iterator ihit = targetsInfo->begin(); ihit != targetsInfo->end(); ++ihit) + std::list<TargetInfo>* targetsInfo = GetSpell()->GetUniqueTargetInfo(); + for (std::list<TargetInfo>::iterator ihit = targetsInfo->begin(); ihit != targetsInfo->end(); ++ihit) if (ihit->targetGUID == GetCaster()->GetGUID()) ihit->damage = -int32(GetHitDamage() * 0.25f); } diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 1ddfd1757f..7678b6df0a 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -430,8 +430,8 @@ public: { if (Unit* target = GetExplTargetUnit()) { - std::list<Spell::TargetInfo> const* targetsInfo = GetSpell()->GetUniqueTargetInfo(); - for (std::list<Spell::TargetInfo>::const_iterator ihit = targetsInfo->begin(); ihit != targetsInfo->end(); ++ihit) + std::list<TargetInfo> const* targetsInfo = GetSpell()->GetUniqueTargetInfo(); + for (std::list<TargetInfo>::const_iterator ihit = targetsInfo->begin(); ihit != targetsInfo->end(); ++ihit) if (ihit->missCondition == SPELL_MISS_NONE && ihit->targetGUID == target->GetGUID()) GetCaster()->CastSpell(target, 55095 /*SPELL_FROST_FEVER*/, true); } @@ -610,8 +610,8 @@ public: void RecalculateDamage() { - std::list<Spell::TargetInfo>* targetsInfo = GetSpell()->GetUniqueTargetInfo(); - for (std::list<Spell::TargetInfo>::iterator ihit = targetsInfo->begin(); ihit != targetsInfo->end(); ++ihit) + std::list<TargetInfo>* targetsInfo = GetSpell()->GetUniqueTargetInfo(); + for (std::list<TargetInfo>::iterator ihit = targetsInfo->begin(); ihit != targetsInfo->end(); ++ihit) if (ihit->targetGUID == GetCaster()->GetGUID()) ihit->crit = roll_chance_f(GetCaster()->GetFloatValue(PLAYER_CRIT_PERCENTAGE)); } |