diff options
Diffstat (limited to 'src')
149 files changed, 3154 insertions, 2188 deletions
diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp index c7bb600024a..4ddad3e6eb0 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSocket.cpp @@ -715,13 +715,25 @@ bool AuthSocket::_HandleLogonProof() char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; socket().send(data, sizeof(data)); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); uint32 MaxWrongPassCount = sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0); + + // We can not include the failed account login hook. However, this is a workaround to still log this. + if (sConfigMgr->GetBoolDefault("Additional.IP.Based.Login.Logging", false)) + { + PreparedStatement* logstmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FALP_IP_LOGGING); + logstmt->setString(0, _login); + logstmt->setString(1, socket().getRemoteAddress()); + logstmt->setString(2, "Logged on failed AccountLogin due wrong password"); + + LoginDatabase.Execute(logstmt); + } + if (MaxWrongPassCount > 0) { //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP - PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS); stmt->setString(0, _login); LoginDatabase.Execute(stmt); diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist index 83edf9669ac..b7dee9ac08b 100644 --- a/src/server/authserver/authserver.conf.dist +++ b/src/server/authserver/authserver.conf.dist @@ -148,6 +148,13 @@ LoginDatabaseInfo = "127.0.0.1;3306;trinity;trinity;auth" LoginDatabase.WorkerThreads = 1 # +# Wrong.Password.Login.Logging +# Description: Additionally log attempted wrong password logging +# Default: 0 - (Disabled) +# 1 - (Enabled) + +Wrong.Password.Login.Logging = 0 +# ################################################################################################### ################################################################################################### diff --git a/src/server/collision/CMakeLists.txt b/src/server/collision/CMakeLists.txt index a83bb9dad1c..a2024bff7cb 100644 --- a/src/server/collision/CMakeLists.txt +++ b/src/server/collision/CMakeLists.txt @@ -34,6 +34,7 @@ include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include ${CMAKE_SOURCE_DIR}/src/server/shared ${CMAKE_SOURCE_DIR}/src/server/shared/Configuration ${CMAKE_SOURCE_DIR}/src/server/shared/Debugging diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index 7c640f9a66d..8032568434f 100644 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -183,7 +183,11 @@ void PetAI::UpdateAI(uint32 diff) } if (spellInfo->HasEffect(SPELL_EFFECT_JUMP_DEST)) + { + if (!spellUsed) + delete spell; continue; // Pets must only jump to target + } // No enemy, check friendly if (!spellUsed) diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index ecaa20284d7..af47b52f500 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -537,9 +537,9 @@ void SmartAI::JustRespawned() me->SetVisible(true); if (me->getFaction() != me->GetCreatureTemplate()->faction) me->RestoreFaction(); - GetScript()->ProcessEventsFor(SMART_EVENT_RESPAWN); mJustReset = true; JustReachedHome(); + GetScript()->ProcessEventsFor(SMART_EVENT_RESPAWN); mFollowGuid = 0;//do not reset follower on Reset(), we need it after combat evade mFollowDist = 0; mFollowAngle = 0; @@ -944,7 +944,7 @@ class SmartTrigger : public AreaTriggerScript } }; -void AddSC_SmartSCripts() +void AddSC_SmartScripts() { new SmartTrigger(); } diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 2647368559c..114a48c60ca 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -488,9 +488,6 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } case SMART_ACTION_CAST: { - if (!me) - break; - ObjectList* targets = GetTargets(e, unit); if (!targets) break; @@ -502,31 +499,36 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !(*itr)->ToUnit()->HasAura(e.action.cast.spell)) { - if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) - me->InterruptNonMeleeSpells(false); - - if (e.action.cast.flags & SMARTCAST_COMBAT_MOVE) + if (me) { - // If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed - // unless target is outside spell range, out of mana, or LOS. + if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) + me->InterruptNonMeleeSpells(false); - bool _allowMove = false; - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(e.action.cast.spell); - int32 mana = me->GetPower(POWER_MANA); + if (e.action.cast.flags & SMARTCAST_COMBAT_MOVE) + { + // If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed + // unless target is outside spell range, out of mana, or LOS. + + bool _allowMove = false; + SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(e.action.cast.spell); + int32 mana = me->GetPower(POWER_MANA); - if (me->GetDistance(*itr) > spellInfo->GetMaxRange(true) || - me->GetDistance(*itr) < spellInfo->GetMinRange(true) || - !me->IsWithinLOSInMap(*itr) || - mana < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask())) + if (me->GetDistance(*itr) > spellInfo->GetMaxRange(true) || + me->GetDistance(*itr) < spellInfo->GetMinRange(true) || + !me->IsWithinLOSInMap(*itr) || + mana < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask())) _allowMove = true; - CAST_AI(SmartAI, me->AI())->SetCombatMove(_allowMove); - } + CAST_AI(SmartAI, me->AI())->SetCombatMove(_allowMove); + } - me->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); + me->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); + } + else if (go) + go->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); - TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST:: Creature %u casts spell %u on target %u with castflags %u", - me->GetGUIDLow(), e.action.cast.spell, (*itr)->GetGUIDLow(), e.action.cast.flags); + TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST:: %s: %u casts spell %u on target %u with castflags %u", + GetLogNameForGuid(me ? me->GetGUID() : go->GetGUID()), me ? me->GetGUIDLow() : go->GetGUIDLow(), e.action.cast.spell, (*itr)->GetGUIDLow(), e.action.cast.flags); } else TC_LOG_DEBUG("scripts.ai", "Spell %u not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (Guid: " UI64FMTD " Entry: %u Type: %u) already has the aura", e.action.cast.spell, (*itr)->GetGUID(), (*itr)->GetEntry(), uint32((*itr)->GetTypeId())); diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index 773e169e5c2..ff30fe7ba35 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -21,6 +21,7 @@ #include "DatabaseEnv.h" #include "ObjectAccessor.h" #include "Player.h" +#include "ScriptMgr.h" #include "Util.h" #include "SHA1.h" #include "WorldSession.h" @@ -166,10 +167,16 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass std::string username; if (!GetName(accountId, username)) + { + sScriptMgr->OnFailedPasswordChange(accountId); return AOR_NAME_NOT_EXIST; // account doesn't exist + } if (utf8length(newPassword) > MAX_ACCOUNT_STR) + { + sScriptMgr->OnFailedPasswordChange(accountId); return AOR_PASS_TOO_LONG; + } normalizeString(username); normalizeString(newPassword); @@ -189,6 +196,7 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass LoginDatabase.Execute(stmt); + sScriptMgr->OnPasswordChange(accountId); return AOR_OK; } @@ -197,10 +205,16 @@ AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) std::string username; if (!GetName(accountId, username)) + { + sScriptMgr->OnFailedEmailChange(accountId); return AOR_NAME_NOT_EXIST; // account doesn't exist + } if (utf8length(newEmail) > MAX_EMAIL_STR) + { + sScriptMgr->OnFailedEmailChange(accountId); return AOR_EMAIL_TOO_LONG; + } normalizeString(username); normalizeString(newEmail); @@ -212,6 +226,7 @@ AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) LoginDatabase.Execute(stmt); + sScriptMgr->OnEmailChange(accountId); return AOR_OK; } @@ -220,10 +235,16 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai std::string username; if (!GetName(accountId, username)) + { + sScriptMgr->OnFailedEmailChange(accountId); return AOR_NAME_NOT_EXIST; // account doesn't exist + } if (utf8length(newEmail) > MAX_EMAIL_STR) + { + sScriptMgr->OnFailedEmailChange(accountId); return AOR_EMAIL_TOO_LONG; + } normalizeString(username); normalizeString(newEmail); @@ -235,6 +256,7 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai LoginDatabase.Execute(stmt); + sScriptMgr->OnEmailChange(accountId); return AOR_OK; } diff --git a/src/server/game/Battlegrounds/ArenaScore.h b/src/server/game/Battlegrounds/ArenaScore.h new file mode 100644 index 00000000000..7b25427c078 --- /dev/null +++ b/src/server/game/Battlegrounds/ArenaScore.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITY_ARENA_SCORE_H +#define TRINITY_ARENA_SCORE_H + +#include "BattlegroundScore.h" +#include "SharedDefines.h" + +struct ArenaScore : public BattlegroundScore +{ + friend class BattlegroundBE; + friend class BattlegroundDS; + friend class BattlegroundNA; + friend class BattlegroundRL; + friend class BattlegroundRV; + + protected: + ArenaScore(uint64 playerGuid, uint32 team) : BattlegroundScore(playerGuid), TeamId(team == ALLIANCE ? 1 : 0) { } + + void AppendToPacket(WorldPacket& data) final + { + data << uint64(PlayerGuid); + + data << uint32(KillingBlows); + data << uint8(TeamId); + data << uint32(DamageDone); + data << uint32(HealingDone); + data << uint32(0); // Objectives Count + } + + // For Logging purpose + std::string ToString() const override + { + std::ostringstream stream; + stream << "Damage done: " << DamageDone << ", Healing done: " << HealingDone << ", Killing blows: " << KillingBlows; + return stream.str(); + } + + uint8 TeamId; // TEAM_ALLIANCE or TEAM_HORDE +}; + +struct ArenaTeamScore +{ + friend class Battleground; + + protected: + ArenaTeamScore() : RatingChange(0), MatchmakerRating(0) { } + + virtual ~ArenaTeamScore() { } + + void Assign(int32 ratingChange, uint32 matchMakerRating, std::string const& teamName) + { + RatingChange = ratingChange; + MatchmakerRating = matchMakerRating; + TeamName = teamName; + } + + void BuildRatingInfoBlock(WorldPacket& data) + { + uint32 ratingLost = std::abs(std::min(RatingChange, 0)); + uint32 ratingWon = std::max(RatingChange, 0); + + data << uint32(ratingLost); + data << uint32(ratingWon); + data << uint32(MatchmakerRating); + } + + void BuildTeamInfoBlock(WorldPacket& data) + { + data << TeamName; + } + + int32 RatingChange; + uint32 MatchmakerRating; + std::string TeamName; +}; + +#endif // TRINITY_ARENA_SCORE_H diff --git a/src/server/game/Battlegrounds/ArenaTeam.h b/src/server/game/Battlegrounds/ArenaTeam.h index cd9e2be4318..c977a137c2a 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.h +++ b/src/server/game/Battlegrounds/ArenaTeam.h @@ -130,7 +130,7 @@ class ArenaTeam uint8 GetSlot() const { return GetSlotByType(GetType()); } static uint8 GetSlotByType(uint32 type); uint64 GetCaptain() const { return CaptainGuid; } - std::string const& GetName() const { return TeamName; } + std::string const& GetName() const { return TeamName; } const ArenaTeamStats& GetStats() const { return Stats; } uint32 GetRating() const { return Stats.Rating; } diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index ca48ffb3a14..fd3e13cf583 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -16,10 +16,12 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "ArenaScore.h" #include "ArenaTeam.h" #include "ArenaTeamMgr.h" #include "Battleground.h" #include "BattlegroundMgr.h" +#include "BattlegroundScore.h" #include "Creature.h" #include "CreatureTextMgr.h" #include "Chat.h" @@ -165,12 +167,13 @@ Battleground::Battleground() m_ArenaTeamIds[TEAM_ALLIANCE] = 0; m_ArenaTeamIds[TEAM_HORDE] = 0; - m_ArenaTeamRatingChanges[TEAM_ALLIANCE] = 0; - m_ArenaTeamRatingChanges[TEAM_HORDE] = 0; - m_ArenaTeamMMR[TEAM_ALLIANCE] = 0; m_ArenaTeamMMR[TEAM_HORDE] = 0; + // Iterate this way for consistency's sake - client expects it to be sent in this order + for (int8 i = WINNER_ALLIANCE; i >= WINNER_HORDE; --i) + _arenaTeamScores[i] = new ArenaTeamScore(); + m_BgRaids[TEAM_ALLIANCE] = NULL; m_BgRaids[TEAM_HORDE] = NULL; @@ -222,6 +225,10 @@ Battleground::~Battleground() for (BattlegroundScoreMap::const_iterator itr = PlayerScores.begin(); itr != PlayerScores.end(); ++itr) delete itr->second; + + // Iterate this way for consistency's sake - client expects it to be sent in this order + for (int8 i = WINNER_ALLIANCE; i >= WINNER_HORDE; --i) + delete _arenaTeamScores[i]; } void Battleground::Update(uint32 diff) @@ -771,49 +778,50 @@ void Battleground::EndBattleground(uint32 winner) if (winnerArenaTeam && loserArenaTeam && winnerArenaTeam != loserArenaTeam) { + loserTeamRating = loserArenaTeam->GetRating(); + loserMatchmakerRating = GetArenaMatchmakerRating(GetOtherTeam(winner)); + winnerTeamRating = winnerArenaTeam->GetRating(); + winnerMatchmakerRating = GetArenaMatchmakerRating(winner); + if (winner != WINNER_NONE) { - loserTeamRating = loserArenaTeam->GetRating(); - loserMatchmakerRating = GetArenaMatchmakerRating(GetOtherTeam(winner)); - winnerTeamRating = winnerArenaTeam->GetRating(); - winnerMatchmakerRating = GetArenaMatchmakerRating(winner); winnerMatchmakerChange = winnerArenaTeam->WonAgainst(winnerMatchmakerRating, loserMatchmakerRating, winnerChange); loserMatchmakerChange = loserArenaTeam->LostAgainst(loserMatchmakerRating, winnerMatchmakerRating, loserChange); TC_LOG_DEBUG("bg.arena", "match Type: %u --- Winner: old rating: %u, rating gain: %d, old MMR: %u, MMR gain: %d --- Loser: old rating: %u, rating loss: %d, old MMR: %u, MMR loss: %d ---", m_ArenaType, winnerTeamRating, winnerChange, winnerMatchmakerRating, winnerMatchmakerChange, loserTeamRating, loserChange, loserMatchmakerRating, loserMatchmakerChange); SetArenaMatchmakerRating(winner, winnerMatchmakerRating + winnerMatchmakerChange); SetArenaMatchmakerRating(GetOtherTeam(winner), loserMatchmakerRating + loserMatchmakerChange); - SetArenaTeamRatingChangeForTeam(winner, winnerChange); - SetArenaTeamRatingChangeForTeam(GetOtherTeam(winner), loserChange); + + uint8 winnerId = GetWinner(); + uint8 loserId = winnerId == WINNER_ALLIANCE ? uint8(WINNER_HORDE) : winnerId; + + _arenaTeamScores[winnerId]->Assign(winnerChange, winnerMatchmakerRating + winnerMatchmakerChange, winnerArenaTeam->GetName()); + _arenaTeamScores[loserId]->Assign(loserChange, loserMatchmakerRating + loserMatchmakerChange, loserArenaTeam->GetName()); + TC_LOG_DEBUG("bg.arena", "Arena match Type: %u for Team1Id: %u - Team2Id: %u ended. WinnerTeamId: %u. Winner rating: +%d, Loser rating: %d", m_ArenaType, m_ArenaTeamIds[TEAM_ALLIANCE], m_ArenaTeamIds[TEAM_HORDE], winnerArenaTeam->GetId(), winnerChange, loserChange); if (sWorld->getBoolConfig(CONFIG_ARENA_LOG_EXTENDED_INFO)) - for (Battleground::BattlegroundScoreMap::const_iterator itr = GetPlayerScoresBegin(); itr != GetPlayerScoresEnd(); ++itr) - if (Player* player = ObjectAccessor::FindPlayer(itr->first)) + for (auto const& score : PlayerScores) + if (Player* player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(score.first, 0, HIGHGUID_PLAYER))) { - TC_LOG_DEBUG("bg.arena", "Statistics match Type: %u for %s (GUID: " UI64FMTD ", Team: %d, IP: %s): %u damage, %u healing, %u killing blows", - m_ArenaType, player->GetName().c_str(), itr->first, player->GetArenaTeamId(m_ArenaType == 5 ? 2 : m_ArenaType == 3), - player->GetSession()->GetRemoteAddress().c_str(), itr->second->DamageDone, itr->second->HealingDone, - itr->second->KillingBlows); + TC_LOG_DEBUG("bg.arena", "Statistics match Type: %u for %s (GUID: %u, Team: %d, IP: %s): %s", + m_ArenaType, player->GetName().c_str(), score.first, player->GetArenaTeamId(m_ArenaType == 5 ? 2 : m_ArenaType == 3), + player->GetSession()->GetRemoteAddress().c_str(), score.second->ToString().c_str()); } } // Deduct 16 points from each teams arena-rating if there are no winners after 45+2 minutes else { - SetArenaTeamRatingChangeForTeam(ALLIANCE, ARENA_TIMELIMIT_POINTS_LOSS); - SetArenaTeamRatingChangeForTeam(HORDE, ARENA_TIMELIMIT_POINTS_LOSS); + _arenaTeamScores[WINNER_ALLIANCE]->Assign(ARENA_TIMELIMIT_POINTS_LOSS, winnerMatchmakerRating + winnerMatchmakerChange, winnerArenaTeam->GetName()); + _arenaTeamScores[WINNER_HORDE]->Assign(ARENA_TIMELIMIT_POINTS_LOSS, loserMatchmakerRating + loserMatchmakerChange, loserArenaTeam->GetName()); + winnerArenaTeam->FinishGame(ARENA_TIMELIMIT_POINTS_LOSS); loserArenaTeam->FinishGame(ARENA_TIMELIMIT_POINTS_LOSS); } } - else - { - SetArenaTeamRatingChangeForTeam(ALLIANCE, 0); - SetArenaTeamRatingChangeForTeam(HORDE, 0); - } } WorldPacket pvpLogData; - sBattlegroundMgr->BuildPvpLogDataPacket(&pvpLogData, this); + BuildPvPLogDataPacket(pvpLogData); BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType()); @@ -958,7 +966,7 @@ void Battleground::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac participant = true; } - BattlegroundScoreMap::iterator itr2 = PlayerScores.find(guid); + BattlegroundScoreMap::iterator itr2 = PlayerScores.find(GUID_LOPART(guid)); if (itr2 != PlayerScores.end()) { delete itr2->second; // delete player's score @@ -1349,47 +1357,48 @@ bool Battleground::HasFreeSlots() const return GetPlayersSize() < GetMaxPlayers(); } -void Battleground::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) +void Battleground::BuildPvPLogDataPacket(WorldPacket& data) { - //this procedure is called from virtual function implemented in bg subclass - BattlegroundScoreMap::const_iterator itr = PlayerScores.find(Source->GetGUID()); - if (itr == PlayerScores.end()) // player not found... - return; + uint8 type = (isArena() ? 1 : 0); + + data.Initialize(MSG_PVP_LOG_DATA, 1 + 1 + 4 + 40 * GetPlayerScoresSize()); + data << uint8(type); // type (battleground = 0 / arena = 1) - switch (type) + if (type) // arena { - case SCORE_KILLING_BLOWS: // Killing blows - itr->second->KillingBlows += value; - break; - case SCORE_DEATHS: // Deaths - itr->second->Deaths += value; - break; - case SCORE_HONORABLE_KILLS: // Honorable kills - itr->second->HonorableKills += value; - break; - case SCORE_BONUS_HONOR: // Honor bonus - // do not add honor in arenas - if (isBattleground()) - { - // reward honor instantly - if (doAddHonor) - Source->RewardHonor(NULL, 1, value); // RewardHonor calls UpdatePlayerScore with doAddHonor = false - else - itr->second->BonusHonor += value; - } - break; - // used only in EY, but in MSG_PVP_LOG_DATA opcode - case SCORE_DAMAGE_DONE: // Damage Done - itr->second->DamageDone += value; - break; - case SCORE_HEALING_DONE: // Healing Done - itr->second->HealingDone += value; - break; - default: - TC_LOG_ERROR("bg.battleground", "Battleground::UpdatePlayerScore: unknown score type (%u) for BG (map: %u, instance id: %u)!", - type, m_MapId, m_InstanceID); - break; + // it seems this must be according to BG_WINNER_A/H and _NOT_ TEAM_A/H + for (int8 i = WINNER_ALLIANCE; i >= WINNER_HORDE; --i) + _arenaTeamScores[i]->BuildRatingInfoBlock(data); + + for (int8 i = WINNER_ALLIANCE; i >= WINNER_HORDE; --i) + _arenaTeamScores[i]->BuildTeamInfoBlock(data); } + + if (GetStatus() == STATUS_WAIT_LEAVE) + { + data << uint8(1); // bg ended + data << uint8(GetWinner()); // who win + } + else + data << uint8(0); // bg not ended + + data << uint32(GetPlayerScoresSize()); + for (auto const& score : PlayerScores) + score.second->AppendToPacket(data); +} + +bool Battleground::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) +{ + BattlegroundScoreMap::const_iterator itr = PlayerScores.find(player->GetGUIDLow()); + if (itr == PlayerScores.end()) // player not found... + return false; + + itr->second->UpdateScore(type, value); + + if (type == SCORE_BONUS_HONOR && doAddHonor && isBattleground()) + player->RewardHonor(NULL, 1, value); // RewardHonor calls UpdatePlayerScore with doAddHonor = false + + return true; } void Battleground::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid) @@ -1868,7 +1877,7 @@ void Battleground::PlayerAddedToBGCheckIfBGIsRunning(Player* player) BlockMovement(player); - sBattlegroundMgr->BuildPvpLogDataPacket(&data, this); + BuildPvPLogDataPacket(data); player->SendDirectMessage(&data); sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType(), player->GetBGTeam()); diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 4256e2fc094..7d1bf550695 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -32,6 +32,8 @@ class WorldObject; class WorldPacket; class BattlegroundMap; +struct ArenaTeamScore; +struct BattlegroundScore; struct Position; struct PvPDifficultyEntry; struct WorldSafeLocsEntry; @@ -171,34 +173,6 @@ struct BattlegroundObjectInfo uint32 spellid; }; -enum ScoreType -{ - SCORE_KILLING_BLOWS = 1, - SCORE_DEATHS = 2, - SCORE_HONORABLE_KILLS = 3, - SCORE_BONUS_HONOR = 4, - //EY, but in MSG_PVP_LOG_DATA opcode! - SCORE_DAMAGE_DONE = 5, - SCORE_HEALING_DONE = 6, - //WS - SCORE_FLAG_CAPTURES = 7, - SCORE_FLAG_RETURNS = 8, - //AB and IC - SCORE_BASES_ASSAULTED = 9, - SCORE_BASES_DEFENDED = 10, - //AV - SCORE_GRAVEYARDS_ASSAULTED = 11, - SCORE_GRAVEYARDS_DEFENDED = 12, - SCORE_TOWERS_ASSAULTED = 13, - SCORE_TOWERS_DEFENDED = 14, - SCORE_MINES_CAPTURED = 15, - SCORE_LEADERS_KILLED = 16, - SCORE_SECONDARY_OBJECTIVES = 17, - //SOTA - SCORE_DESTROYED_DEMOLISHER = 18, - SCORE_DESTROYED_WALL = 19 -}; - enum ArenaType { ARENA_TYPE_2v2 = 2, @@ -239,22 +213,6 @@ enum BattlegroundStartingEventsIds }; #define BG_STARTING_EVENT_COUNT 4 -struct BattlegroundScore -{ - BattlegroundScore() : KillingBlows(0), Deaths(0), HonorableKills(0), BonusHonor(0), - DamageDone(0), HealingDone(0) - { } - - virtual ~BattlegroundScore() { } //virtual destructor is used when deleting score from scores map - - uint32 KillingBlows; - uint32 Deaths; - uint32 HonorableKills; - uint32 BonusHonor; - uint32 DamageDone; - uint32 HealingDone; -}; - enum BGHonorMode { BG_NORMAL = 0, @@ -369,9 +327,7 @@ class Battleground BattlegroundPlayerMap const& GetPlayers() const { return m_Players; } uint32 GetPlayersSize() const { return m_Players.size(); } - typedef std::map<uint64, BattlegroundScore*> BattlegroundScoreMap; - BattlegroundScoreMap::const_iterator GetPlayerScoresBegin() const { return PlayerScores.begin(); } - BattlegroundScoreMap::const_iterator GetPlayerScoresEnd() const { return PlayerScores.end(); } + typedef std::map<uint32, BattlegroundScore*> BattlegroundScoreMap; uint32 GetPlayerScoresSize() const { return PlayerScores.size(); } uint32 GetReviveQueueSize() const { return m_ReviveQueue.size(); } @@ -443,7 +399,8 @@ class Battleground Group* GetBgRaid(uint32 TeamID) const { return TeamID == ALLIANCE ? m_BgRaids[TEAM_ALLIANCE] : m_BgRaids[TEAM_HORDE]; } void SetBgRaid(uint32 TeamID, Group* bg_raid); - virtual void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true); + void BuildPvPLogDataPacket(WorldPacket& data); + virtual bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true); static TeamId GetTeamIndexByTeamId(uint32 Team) { return Team == ALLIANCE ? TEAM_ALLIANCE : TEAM_HORDE; } uint32 GetPlayersCountByTeam(uint32 Team) const { return m_PlayersCount[GetTeamIndexByTeamId(Team)]; } @@ -460,12 +417,8 @@ class Battleground void SetArenaTeamIdForTeam(uint32 Team, uint32 ArenaTeamId) { m_ArenaTeamIds[GetTeamIndexByTeamId(Team)] = ArenaTeamId; } uint32 GetArenaTeamIdForTeam(uint32 Team) const { return m_ArenaTeamIds[GetTeamIndexByTeamId(Team)]; } uint32 GetArenaTeamIdByIndex(uint32 index) const { return m_ArenaTeamIds[index]; } - void SetArenaTeamRatingChangeForTeam(uint32 Team, int32 RatingChange) { m_ArenaTeamRatingChanges[GetTeamIndexByTeamId(Team)] = RatingChange; } - int32 GetArenaTeamRatingChangeForTeam(uint32 Team) const { return m_ArenaTeamRatingChanges[GetTeamIndexByTeamId(Team)]; } - int32 GetArenaTeamRatingChangeByIndex(uint32 index) const { return m_ArenaTeamRatingChanges[index]; } void SetArenaMatchmakerRating(uint32 Team, uint32 MMR){ m_ArenaTeamMMR[GetTeamIndexByTeamId(Team)] = MMR; } uint32 GetArenaMatchmakerRating(uint32 Team) const { return m_ArenaTeamMMR[GetTeamIndexByTeamId(Team)]; } - uint32 GetArenaMatchmakerRatingByIndex(uint32 index) const { return m_ArenaTeamMMR[index]; } void CheckArenaAfterTimerConditions(); void CheckArenaWinConditions(); void UpdateArenaWorldState(); @@ -657,8 +610,8 @@ class Battleground // Arena team ids by team uint32 m_ArenaTeamIds[BG_TEAMS_COUNT]; - int32 m_ArenaTeamRatingChanges[BG_TEAMS_COUNT]; uint32 m_ArenaTeamMMR[BG_TEAMS_COUNT]; + ArenaTeamScore* _arenaTeamScores[BG_TEAMS_COUNT]; // Limits uint32 m_LevelMin; diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index ab69c950ff4..ef78594626a 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -216,176 +216,6 @@ void BattlegroundMgr::BuildBattlegroundStatusPacket(WorldPacket* data, Battlegro } } -void BattlegroundMgr::BuildPvpLogDataPacket(WorldPacket* data, Battleground* bg) -{ - uint8 type = (bg->isArena() ? 1 : 0); - - data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize())); - *data << uint8(type); // type (battleground=0/arena=1) - - if (type) // arena - { - // it seems this must be according to BG_WINNER_A/H and _NOT_ TEAM_A/H - for (int8 i = 1; i >= 0; --i) - { - int32 rating_change = bg->GetArenaTeamRatingChangeByIndex(i); - - uint32 pointsLost = rating_change < 0 ? -rating_change : 0; - uint32 pointsGained = rating_change > 0 ? rating_change : 0; - uint32 MatchmakerRating = bg->GetArenaMatchmakerRatingByIndex(i); - - *data << uint32(pointsLost); // Rating Lost - *data << uint32(pointsGained); // Rating gained - *data << uint32(MatchmakerRating); // Matchmaking Value - TC_LOG_DEBUG("bg.battleground", "rating change: %d", rating_change); - } - for (int8 i = 1; i >= 0; --i) - { - if (ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(bg->GetArenaTeamIdByIndex(i))) - *data << at->GetName(); - else - *data << uint8(0); - } - } - - if (bg->GetStatus() != STATUS_WAIT_LEAVE) - *data << uint8(0); // bg not ended - else - { - *data << uint8(1); // bg ended - *data << uint8(bg->GetWinner()); // who win - } - - size_t wpos = data->wpos(); - uint32 scoreCount = 0; - *data << uint32(scoreCount); // placeholder - - Battleground::BattlegroundScoreMap::const_iterator itr2 = bg->GetPlayerScoresBegin(); - for (Battleground::BattlegroundScoreMap::const_iterator itr = itr2; itr != bg->GetPlayerScoresEnd();) - { - itr2 = itr++; - BattlegroundScore* score = itr2->second; - if (!bg->IsPlayerInBattleground(itr2->first)) - { - TC_LOG_ERROR("bg.battleground", "Player " UI64FMTD " has scoreboard entry for battleground %u but is not in battleground!", itr->first, bg->GetTypeID(true)); - continue; - } - - *data << uint64(itr2->first); - *data << uint32(score->KillingBlows); - if (type == 0) - { - *data << uint32(score->HonorableKills); - *data << uint32(score->Deaths); - *data << uint32(score->BonusHonor); - } - else - { - Player* player = ObjectAccessor::FindPlayer(itr2->first); - uint32 team = bg->GetPlayerTeam(itr2->first); - if (!team && player) - team = player->GetBGTeam(); - *data << uint8(team == ALLIANCE ? 1 : 0); // green or yellow - } - *data << uint32(score->DamageDone); // damage done - *data << uint32(score->HealingDone); // healing done - switch (bg->GetTypeID(true)) // battleground specific things - { - case BATTLEGROUND_RB: - switch (bg->GetMapId()) - { - case 489: - *data << uint32(0x00000002); // count of next fields - *data << uint32(((BattlegroundWGScore*)score)->FlagCaptures); // flag captures - *data << uint32(((BattlegroundWGScore*)score)->FlagReturns); // flag returns - break; - case 566: - *data << uint32(0x00000001); // count of next fields - *data << uint32(((BattlegroundEYScore*)score)->FlagCaptures); // flag captures - break; - case 529: - *data << uint32(0x00000002); // count of next fields - *data << uint32(((BattlegroundABScore*)score)->BasesAssaulted); // bases asssulted - *data << uint32(((BattlegroundABScore*)score)->BasesDefended); // bases defended - break; - case 30: - *data << uint32(0x00000005); // count of next fields - *data << uint32(((BattlegroundAVScore*)score)->GraveyardsAssaulted); // GraveyardsAssaulted - *data << uint32(((BattlegroundAVScore*)score)->GraveyardsDefended); // GraveyardsDefended - *data << uint32(((BattlegroundAVScore*)score)->TowersAssaulted); // TowersAssaulted - *data << uint32(((BattlegroundAVScore*)score)->TowersDefended); // TowersDefended - *data << uint32(((BattlegroundAVScore*)score)->MinesCaptured); // MinesCaptured - break; - case 607: - *data << uint32(0x00000002); // count of next fields - *data << uint32(((BattlegroundSAScore*)score)->demolishers_destroyed); - *data << uint32(((BattlegroundSAScore*)score)->gates_destroyed); - break; - case 628: // IC - *data << uint32(0x00000002); // count of next fields - *data << uint32(((BattlegroundICScore*)score)->BasesAssaulted); // bases asssulted - *data << uint32(((BattlegroundICScore*)score)->BasesDefended); // bases defended - default: - *data << uint32(0); - break; - } - break; - case BATTLEGROUND_AV: - *data << uint32(0x00000005); // count of next fields - *data << uint32(((BattlegroundAVScore*)score)->GraveyardsAssaulted); // GraveyardsAssaulted - *data << uint32(((BattlegroundAVScore*)score)->GraveyardsDefended); // GraveyardsDefended - *data << uint32(((BattlegroundAVScore*)score)->TowersAssaulted); // TowersAssaulted - *data << uint32(((BattlegroundAVScore*)score)->TowersDefended); // TowersDefended - *data << uint32(((BattlegroundAVScore*)score)->MinesCaptured); // MinesCaptured - break; - case BATTLEGROUND_WS: - *data << uint32(0x00000002); // count of next fields - *data << uint32(((BattlegroundWGScore*)score)->FlagCaptures); // flag captures - *data << uint32(((BattlegroundWGScore*)score)->FlagReturns); // flag returns - break; - case BATTLEGROUND_AB: - *data << uint32(0x00000002); // count of next fields - *data << uint32(((BattlegroundABScore*)score)->BasesAssaulted); // bases assaulted - *data << uint32(((BattlegroundABScore*)score)->BasesDefended); // bases defended - break; - case BATTLEGROUND_EY: - *data << uint32(0x00000001); // count of next fields - *data << uint32(((BattlegroundEYScore*)score)->FlagCaptures); // flag captures - break; - case BATTLEGROUND_SA: - *data << uint32(0x00000002); // count of next fields - *data << uint32(((BattlegroundSAScore*)score)->demolishers_destroyed); - *data << uint32(((BattlegroundSAScore*)score)->gates_destroyed); - break; - case BATTLEGROUND_IC: - *data << uint32(0x00000002); // count of next fields - *data << uint32(((BattlegroundICScore*)score)->BasesAssaulted); // bases assaulted - *data << uint32(((BattlegroundICScore*)score)->BasesDefended); // bases defended - break; - case BATTLEGROUND_NA: - case BATTLEGROUND_BE: - case BATTLEGROUND_AA: - case BATTLEGROUND_RL: - case BATTLEGROUND_DS: - case BATTLEGROUND_RV: - *data << uint32(0); - break; - default: - TC_LOG_DEBUG("network", "Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID()); - *data << uint32(0); - break; - } - // should never happen - if (++scoreCount >= bg->GetMaxPlayers() && itr != bg->GetPlayerScoresEnd()) - { - TC_LOG_ERROR("bg.battleground", "Battleground %u scoreboard has more entries (%u) than allowed players in this bg (%u)", bg->GetTypeID(true), bg->GetPlayerScoresSize(), bg->GetMaxPlayers()); - break; - } - } - - data->put(wpos, scoreCount); -} - void BattlegroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result) { data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4); diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index 786e664c3f3..b57efc045d8 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -79,7 +79,6 @@ class BattlegroundMgr void BuildBattlegroundListPacket(WorldPacket* data, uint64 guid, Player* player, BattlegroundTypeId bgTypeId, uint8 fromWhere); void BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result); void BuildUpdateWorldStatePacket(WorldPacket* data, uint32 field, uint32 value); - void BuildPvpLogDataPacket(WorldPacket* data, Battleground* bg); void BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint8 queueSlot, uint8 statusId, uint32 time1, uint32 time2, uint8 arenaType, uint32 arenaFaction); void BuildPlaySoundPacket(WorldPacket* data, uint32 soundId); void SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, uint64 guid); diff --git a/src/server/game/Battlegrounds/BattlegroundScore.h b/src/server/game/Battlegrounds/BattlegroundScore.h new file mode 100644 index 00000000000..7fedc4dbc4d --- /dev/null +++ b/src/server/game/Battlegrounds/BattlegroundScore.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITY_BATTLEGROUND_SCORE_H +#define TRINITY_BATTLEGROUND_SCORE_H + +#include "WorldPacket.h" + +enum ScoreType +{ + SCORE_KILLING_BLOWS = 1, + SCORE_DEATHS = 2, + SCORE_HONORABLE_KILLS = 3, + SCORE_BONUS_HONOR = 4, + SCORE_DAMAGE_DONE = 5, + SCORE_HEALING_DONE = 6, + + // WS and EY + SCORE_FLAG_CAPTURES = 7, + SCORE_FLAG_RETURNS = 8, + + // AB and IC + SCORE_BASES_ASSAULTED = 9, + SCORE_BASES_DEFENDED = 10, + + // AV + SCORE_GRAVEYARDS_ASSAULTED = 11, + SCORE_GRAVEYARDS_DEFENDED = 12, + SCORE_TOWERS_ASSAULTED = 13, + SCORE_TOWERS_DEFENDED = 14, + SCORE_MINES_CAPTURED = 15, + + // SOTA + SCORE_DESTROYED_DEMOLISHER = 16, + SCORE_DESTROYED_WALL = 17 +}; + +struct BattlegroundScore +{ + friend class Battleground; + + protected: + BattlegroundScore(uint64 playerGuid) : PlayerGuid(playerGuid), KillingBlows(0), Deaths(0), + HonorableKills(0), BonusHonor(0), DamageDone(0), HealingDone(0) { } + + virtual ~BattlegroundScore() { } + + virtual void UpdateScore(uint32 type, uint32 value) + { + switch (type) + { + case SCORE_KILLING_BLOWS: // Killing blows + KillingBlows += value; + break; + case SCORE_DEATHS: // Deaths + Deaths += value; + break; + case SCORE_HONORABLE_KILLS: // Honorable kills + HonorableKills += value; + break; + case SCORE_BONUS_HONOR: // Honor bonus + BonusHonor += value; + break; + case SCORE_DAMAGE_DONE: // Damage Done + DamageDone += value; + break; + case SCORE_HEALING_DONE: // Healing Done + HealingDone += value; + break; + default: + ASSERT(false && "Not implemented Battleground score type!"); + break; + } + } + + virtual void AppendToPacket(WorldPacket& data) + { + data << uint64(PlayerGuid); + + data << uint32(KillingBlows); + data << uint32(HonorableKills); + data << uint32(Deaths); + data << uint32(BonusHonor); + data << uint32(DamageDone); + data << uint32(HealingDone); + + BuildObjectivesBlock(data); + } + + virtual void BuildObjectivesBlock(WorldPacket& /*data*/) { } + + // For Logging purpose + virtual std::string ToString() const { return ""; } + + uint64 PlayerGuid; + + // Default score, present in every type + uint32 KillingBlows; + uint32 Deaths; + uint32 HonorableKills; + uint32 BonusHonor; + uint32 DamageDone; + uint32 HealingDone; +}; + +#endif // TRINITY_BATTLEGROUND_SCORE_H diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp index 38b0e3e084b..2622ab9501f 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp @@ -224,15 +224,11 @@ void BattlegroundAB::StartingEventOpenDoors() void BattlegroundAB::AddPlayer(Player* player) { Battleground::AddPlayer(player); - //create score and add it to map, default values are set in the constructor - BattlegroundABScore* sc = new BattlegroundABScore; - - PlayerScores[player->GetGUID()] = sc; + PlayerScores[player->GetGUIDLow()] = new BattlegroundABScore(player->GetGUID()); } void BattlegroundAB::RemovePlayer(Player* /*player*/, uint64 /*guid*/, uint32 /*team*/) { - } void BattlegroundAB::HandleAreaTrigger(Player* player, uint32 trigger) @@ -696,26 +692,23 @@ WorldSafeLocsEntry const* BattlegroundAB::GetClosestGraveYard(Player* player) return good_entry; } -void BattlegroundAB::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) +bool BattlegroundAB::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) { - BattlegroundScoreMap::iterator itr = PlayerScores.find(Source->GetGUID()); - if (itr == PlayerScores.end()) // player not found... - return; + if (!Battleground::UpdatePlayerScore(player, type, value, doAddHonor)) + return false; switch (type) { case SCORE_BASES_ASSAULTED: - ((BattlegroundABScore*)itr->second)->BasesAssaulted += value; - Source->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AB_OBJECTIVE_ASSAULT_BASE); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AB_OBJECTIVE_ASSAULT_BASE); break; case SCORE_BASES_DEFENDED: - ((BattlegroundABScore*)itr->second)->BasesDefended += value; - Source->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AB_OBJECTIVE_DEFEND_BASE); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AB_OBJECTIVE_DEFEND_BASE); break; default: - Battleground::UpdatePlayerScore(Source, type, value, doAddHonor); break; } + return true; } bool BattlegroundAB::IsAllNodesControlledByTeam(uint32 team) const diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h index 9abc7627b24..a6b4be10fdf 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h @@ -20,6 +20,7 @@ #define __BATTLEGROUNDAB_H #include "Battleground.h" +#include "BattlegroundScore.h" #include "Object.h" enum BG_AB_WorldStates @@ -236,12 +237,38 @@ struct BG_AB_BannerTimer uint8 teamIndex; }; -struct BattlegroundABScore : public BattlegroundScore +struct BattlegroundABScore final : public BattlegroundScore { - BattlegroundABScore(): BasesAssaulted(0), BasesDefended(0) { } - ~BattlegroundABScore() { } - uint32 BasesAssaulted; - uint32 BasesDefended; + friend class BattlegroundAB; + + protected: + BattlegroundABScore(uint64 playerGuid) : BattlegroundScore(playerGuid), BasesAssaulted(0), BasesDefended(0) { } + + void UpdateScore(uint32 type, uint32 value) override + { + switch (type) + { + case SCORE_BASES_ASSAULTED: + BasesAssaulted += value; + break; + case SCORE_BASES_DEFENDED: + BasesDefended += value; + break; + default: + BattlegroundScore::UpdateScore(type, value); + break; + } + } + + void BuildObjectivesBlock(WorldPacket& data) final + { + data << uint32(2); + data << uint32(BasesAssaulted); + data << uint32(BasesDefended); + } + + uint32 BasesAssaulted; + uint32 BasesDefended; }; class BattlegroundAB : public Battleground @@ -261,7 +288,7 @@ class BattlegroundAB : public Battleground WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); /* Scorekeeping */ - void UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor = true); + bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override; void FillInitialWorldStates(WorldPacket& data); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp index 16576aa888e..eafb02f031d 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp @@ -47,7 +47,6 @@ BattlegroundAV::BattlegroundAV() } m_Mine_Timer = 0; - m_MaxLevel = 0; for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i) InitNode(i, 0, false); @@ -60,11 +59,6 @@ BattlegroundAV::BattlegroundAV() BattlegroundAV::~BattlegroundAV() { } -uint16 BattlegroundAV::GetBonusHonor(uint8 kills) /// @todo move this function to Battleground.cpp (needs to find a way to get m_MaxLevel) -{ - return Trinity::Honor::hk_honor_at_level(m_MaxLevel, kills); -} - void BattlegroundAV::HandleKillPlayer(Player* player, Player* killer) { if (GetStatus() != STATUS_IN_PROGRESS) @@ -95,7 +89,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer) { CastSpellOnTeam(23658, HORDE); //this is a spell which finishes a quest where a player has to kill the boss RewardReputationToTeam(729, BG_AV_REP_BOSS, HORDE); - RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_BOSS), HORDE); + RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_BOSS), HORDE); EndBattleground(HORDE); DelCreature(AV_CPLACE_TRIGGER17); } @@ -103,7 +97,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer) { CastSpellOnTeam(23658, ALLIANCE); //this is a spell which finishes a quest where a player has to kill the boss RewardReputationToTeam(730, BG_AV_REP_BOSS, ALLIANCE); - RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_BOSS), ALLIANCE); + RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_BOSS), ALLIANCE); EndBattleground(ALLIANCE); DelCreature(AV_CPLACE_TRIGGER19); } @@ -116,7 +110,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer) } m_CaptainAlive[0]=false; RewardReputationToTeam(729, BG_AV_REP_CAPTAIN, HORDE); - RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_CAPTAIN), HORDE); + RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_CAPTAIN), HORDE); UpdateScore(ALLIANCE, (-1)*BG_AV_RES_CAPTAIN); //spawn destroyed aura for (uint8 i=0; i <= 9; i++) @@ -135,7 +129,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer) } m_CaptainAlive[1]=false; RewardReputationToTeam(730, BG_AV_REP_CAPTAIN, ALLIANCE); - RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_CAPTAIN), ALLIANCE); + RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_CAPTAIN), ALLIANCE); UpdateScore(HORDE, (-1)*BG_AV_RES_CAPTAIN); //spawn destroyed aura for (uint8 i=0; i <= 9; i++) @@ -279,33 +273,24 @@ void BattlegroundAV::UpdateScore(uint16 team, int16 points) Creature* BattlegroundAV::AddAVCreature(uint16 cinfoid, uint16 type) { - uint8 level; bool isStatic = false; Creature* creature = NULL; ASSERT(type <= AV_CPLACE_MAX + AV_STATICCPLACE_MAX); if (type >= AV_CPLACE_MAX) //static { type -= AV_CPLACE_MAX; - cinfoid=uint16(BG_AV_StaticCreaturePos[type][4]); - creature = AddCreature(BG_AV_StaticCreatureInfo[cinfoid][0], - (type+AV_CPLACE_MAX), + cinfoid = uint16(BG_AV_StaticCreaturePos[type][4]); + creature = AddCreature(BG_AV_StaticCreatureInfo[cinfoid], + type + AV_CPLACE_MAX, BG_AV_StaticCreaturePos[type][0], BG_AV_StaticCreaturePos[type][1], BG_AV_StaticCreaturePos[type][2], BG_AV_StaticCreaturePos[type][3]); - level = (BG_AV_StaticCreatureInfo[cinfoid][2] == BG_AV_StaticCreatureInfo[cinfoid][3]) - ? BG_AV_StaticCreatureInfo[cinfoid][2] - : urand(BG_AV_StaticCreatureInfo[cinfoid][2], BG_AV_StaticCreatureInfo[cinfoid][3]); isStatic = true; } else { - creature = AddCreature(BG_AV_CreatureInfo[cinfoid][0], - type, - BG_AV_CreaturePos[type]); - level = (BG_AV_CreatureInfo[cinfoid][2] == BG_AV_CreatureInfo[cinfoid][3]) - ? BG_AV_CreatureInfo[cinfoid][2] - : urand(BG_AV_CreatureInfo[cinfoid][2], BG_AV_CreatureInfo[cinfoid][3]); + creature = AddCreature(BG_AV_CreatureInfo[cinfoid][0], type, BG_AV_CreaturePos[type]); } if (!creature) return NULL; @@ -330,10 +315,6 @@ Creature* BattlegroundAV::AddAVCreature(uint16 cinfoid, uint16 type) //just copied this code from a gm-command } - if (level != 0) - level += m_MaxLevel - 60; //maybe we can do this more generic for custom level-range.. actually it's blizzlike - creature->SetLevel(level); - uint32 triggerSpawnID = 0; uint32 newFaction = 0; if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0]) @@ -358,9 +339,7 @@ Creature* BattlegroundAV::AddAVCreature(uint16 cinfoid, uint16 type) } if (triggerSpawnID && newFaction) { - if (Creature* trigger = AddCreature(WORLD_TRIGGER, - triggerSpawnID, - BG_AV_CreaturePos[triggerSpawnID])) + if (Creature* trigger = AddCreature(WORLD_TRIGGER, triggerSpawnID, BG_AV_CreaturePos[triggerSpawnID])) { trigger->setFaction(newFaction); trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false); @@ -459,11 +438,7 @@ void BattlegroundAV::StartingEventOpenDoors() void BattlegroundAV::AddPlayer(Player* player) { Battleground::AddPlayer(player); - //create score and add it to map, default values are set in constructor - BattlegroundAVScore* sc = new BattlegroundAVScore; - PlayerScores[player->GetGUID()] = sc; - if (m_MaxLevel == 0) - m_MaxLevel=(player->getLevel()%10 == 0)? player->getLevel() : (player->getLevel()-(player->getLevel()%10))+10; /// @todo just look at the code \^_^/ --but queue-info should provide this information.. + PlayerScores[player->GetGUIDLow()] = new BattlegroundAVScore(player->GetGUID()); } void BattlegroundAV::EndBattleground(uint32 winner) @@ -499,7 +474,7 @@ void BattlegroundAV::EndBattleground(uint32 winner) if (rep[i] != 0) RewardReputationToTeam(i == 0 ? 730 : 729, rep[i], i == 0 ? ALLIANCE : HORDE); if (kills[i] != 0) - RewardHonorToTeam(GetBonusHonor(kills[i]), i == 0 ? ALLIANCE : HORDE); + RewardHonorToTeam(GetBonusHonorFromKill(kills[i]), i == 0 ? ALLIANCE : HORDE); } /// @todo add enterevademode for all attacking creatures @@ -553,43 +528,29 @@ void BattlegroundAV::HandleAreaTrigger(Player* player, uint32 trigger) } } -void BattlegroundAV::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) +bool BattlegroundAV::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) { - BattlegroundScoreMap::iterator itr = PlayerScores.find(Source->GetGUID()); - if (itr == PlayerScores.end()) // player not found... - return; + if (!Battleground::UpdatePlayerScore(player, type, value, doAddHonor)) + return false; switch (type) { case SCORE_GRAVEYARDS_ASSAULTED: - ((BattlegroundAVScore*)itr->second)->GraveyardsAssaulted += value; - Source->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_GRAVEYARD); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_GRAVEYARD); break; case SCORE_GRAVEYARDS_DEFENDED: - ((BattlegroundAVScore*)itr->second)->GraveyardsDefended += value; - Source->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_GRAVEYARD); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_GRAVEYARD); break; case SCORE_TOWERS_ASSAULTED: - ((BattlegroundAVScore*)itr->second)->TowersAssaulted += value; - Source->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_TOWER); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_TOWER); break; case SCORE_TOWERS_DEFENDED: - ((BattlegroundAVScore*)itr->second)->TowersDefended += value; - Source->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_TOWER); - break; - case SCORE_MINES_CAPTURED: - ((BattlegroundAVScore*)itr->second)->MinesCaptured += value; - break; - case SCORE_LEADERS_KILLED: - ((BattlegroundAVScore*)itr->second)->LeadersKilled += value; - break; - case SCORE_SECONDARY_OBJECTIVES: - ((BattlegroundAVScore*)itr->second)->SecondaryObjectives += value; + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_TOWER); break; default: - Battleground::UpdatePlayerScore(Source, type, value, doAddHonor); break; } + return true; } void BattlegroundAV::EventPlayerDestroyedPoint(BG_AV_Nodes node) @@ -617,7 +578,7 @@ void BattlegroundAV::EventPlayerDestroyedPoint(BG_AV_Nodes node) UpdateScore((owner == ALLIANCE) ? HORDE : ALLIANCE, -1 * BG_AV_RES_TOWER); RewardReputationToTeam(owner == ALLIANCE ? 730 : 729, BG_AV_REP_TOWER, owner); - RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_TOWER), owner); + RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_TOWER), owner); SpawnBGObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+GetTeamIndexByTeamId(owner)+(2*tmp), RESPAWN_ONE_DAY); SpawnBGObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+GetTeamIndexByTeamId(owner)+(2*tmp), RESPAWN_ONE_DAY); @@ -1222,27 +1183,27 @@ bool BattlegroundAV::SetupBattleground() if (i <= BG_AV_NODES_FROSTWOLF_HUT) { if (!AddObject(i, BG_AV_OBJECTID_BANNER_A_B, - BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3], - 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i], + 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(i+11, BG_AV_OBJECTID_BANNER_CONT_A_B, - BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3], - 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i], + 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(i+33, BG_AV_OBJECTID_BANNER_H_B, - BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3], - 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i], + 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(i+22, BG_AV_OBJECTID_BANNER_CONT_H_B, - BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3], - 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i], + 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY) //aura || !AddObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+i*3, BG_AV_OBJECTID_AURA_N, - BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3], - 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i], + 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+i*3, BG_AV_OBJECTID_AURA_A, - BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3], - 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i], + 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(BG_AV_OBJECT_AURA_H_FIRSTAID_STATION+i*3, BG_AV_OBJECTID_AURA_H, - BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3], - 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY)) + BG_AV_ObjectPos[i], + 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY)) { TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!2"); return false; @@ -1253,23 +1214,23 @@ bool BattlegroundAV::SetupBattleground() if (i <= BG_AV_NODES_STONEHEART_BUNKER) //alliance towers { if (!AddObject(i, BG_AV_OBJECTID_BANNER_A, - BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3], - 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i], + 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(i+22, BG_AV_OBJECTID_BANNER_CONT_H, - BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3], - 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i], + 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_AURA_A, - BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3], - 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i+8], + 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_AURA_N, - BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3], - 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i+8], + 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_TOWER_BANNER_A, - BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3], - 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i+8], + 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_TOWER_BANNER_PH, - BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3], - 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY)) + BG_AV_ObjectPos[i+8], + 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY)) { TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!3"); return false; @@ -1278,23 +1239,23 @@ bool BattlegroundAV::SetupBattleground() else //horde towers { if (!AddObject(i+7, BG_AV_OBJECTID_BANNER_CONT_A, - BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3], - 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i], + 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(i+29, BG_AV_OBJECTID_BANNER_H, - BG_AV_ObjectPos[i][0], BG_AV_ObjectPos[i][1], BG_AV_ObjectPos[i][2], BG_AV_ObjectPos[i][3], - 0, 0, std::sin(BG_AV_ObjectPos[i][3]/2), std::cos(BG_AV_ObjectPos[i][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i], + 0, 0, std::sin(BG_AV_ObjectPos[i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_AURA_N, - BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3], - 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i+8], + 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_AURA_H, - BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3], - 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i+8], + 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_TOWER_BANNER_PA, - BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3], - 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[i+8], + 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)), BG_AV_OBJECTID_TOWER_BANNER_H, - BG_AV_ObjectPos[i+8][0], BG_AV_ObjectPos[i+8][1], BG_AV_ObjectPos[i+8][2], BG_AV_ObjectPos[i+8][3], - 0, 0, std::sin(BG_AV_ObjectPos[i+8][3]/2), std::cos(BG_AV_ObjectPos[i+8][3]/2), RESPAWN_ONE_DAY)) + BG_AV_ObjectPos[i+8], + 0, 0, std::sin(BG_AV_ObjectPos[i+8].GetOrientation()/2), std::cos(BG_AV_ObjectPos[i+8].GetOrientation()/2), RESPAWN_ONE_DAY)) { TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!4"); return false; @@ -1304,14 +1265,11 @@ bool BattlegroundAV::SetupBattleground() { if (!AddObject(BG_AV_OBJECT_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j, BG_AV_OBJECTID_FIRE, - BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][0], - BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][1], - BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][2], - BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3], + BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j], 0, 0, - std::sin(BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3]/2), - std::cos(BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3]/2), + std::sin(BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j].GetOrientation()/2), + std::cos(BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j].GetOrientation()/2), RESPAWN_ONE_DAY)) { TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!5.%i", i); @@ -1328,14 +1286,11 @@ bool BattlegroundAV::SetupBattleground() { if (!AddObject(BG_AV_OBJECT_BURN_BUILDING_ALLIANCE+(i*10)+j, BG_AV_OBJECTID_SMOKE, - BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][0], - BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][1], - BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][2], - BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3], + BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j], 0, 0, - std::sin(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2), - std::cos(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2), + std::sin(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j].GetOrientation()/2), + std::cos(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j].GetOrientation()/2), RESPAWN_ONE_DAY)) { TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!6.%i", i); @@ -1346,14 +1301,11 @@ bool BattlegroundAV::SetupBattleground() { if (!AddObject(BG_AV_OBJECT_BURN_BUILDING_ALLIANCE+(i*10)+j, BG_AV_OBJECTID_FIRE, - BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][0], - BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][1], - BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][2], - BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3], + BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j], 0, 0, - std::sin(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2), - std::cos(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2), + std::sin(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j].GetOrientation()/2), + std::cos(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j].GetOrientation()/2), RESPAWN_ONE_DAY)) { TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!7.%i", i); @@ -1366,14 +1318,11 @@ bool BattlegroundAV::SetupBattleground() { if (!AddObject(BG_AV_OBJECT_MINE_SUPPLY_N_MIN+i, BG_AV_OBJECTID_MINE_N, - BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][0], - BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][1], - BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][2], - BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3], + BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i], 0, 0, - std::sin(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3]/2), - std::cos(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3]/2), + std::sin(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i].GetOrientation()/2), + std::cos(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i].GetOrientation()/2), RESPAWN_ONE_DAY)) { TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some mine supplies Battleground not created!7.5.%i", i); @@ -1384,14 +1333,11 @@ bool BattlegroundAV::SetupBattleground() { if (!AddObject(BG_AV_OBJECT_MINE_SUPPLY_S_MIN+i, BG_AV_OBJECTID_MINE_S, - BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][0], - BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][1], - BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][2], - BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3], + BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i], 0, 0, - std::sin(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3]/2), - std::cos(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3]/2), + std::sin(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i].GetOrientation()/2), + std::cos(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i].GetOrientation()/2), RESPAWN_ONE_DAY)) { TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some mine supplies Battleground not created!7.6.%i", i); @@ -1401,14 +1347,11 @@ bool BattlegroundAV::SetupBattleground() if (!AddObject(BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE, BG_AV_OBJECTID_BANNER_SNOWFALL_N, - BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][0], - BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][1], - BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][2], - BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3], + BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE], 0, 0, - std::sin(BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3]/2), - std::cos(BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3]/2), + std::sin(BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE].GetOrientation()/2), + std::cos(BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE].GetOrientation()/2), RESPAWN_ONE_DAY)) { TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!8"); @@ -1417,17 +1360,17 @@ bool BattlegroundAV::SetupBattleground() for (uint8 i = 0; i < 4; i++) { if (!AddObject(BG_AV_OBJECT_SNOW_EYECANDY_A+i, BG_AV_OBJECTID_SNOWFALL_CANDY_A, - BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3], - 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i], + 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_PA+i, BG_AV_OBJECTID_SNOWFALL_CANDY_PA, - BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3], - 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i], + 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_H+i, BG_AV_OBJECTID_SNOWFALL_CANDY_H, - BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3], - 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY) + BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i], + 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), RESPAWN_ONE_DAY) || !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_PH+i, BG_AV_OBJECTID_SNOWFALL_CANDY_PH, - BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2], BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3], - 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY)) + BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i], + 0, 0, std::sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), std::cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i].GetOrientation()/2), RESPAWN_ONE_DAY)) { TC_LOG_ERROR("bg.battleground", "BatteGroundAV: Failed to spawn some object Battleground not created!9.%i", i); return false; @@ -1591,8 +1534,6 @@ void BattlegroundAV::DefendNode(BG_AV_Nodes node, uint16 team) void BattlegroundAV::ResetBGSubclass() { - m_MaxLevel=0; - for (uint8 i=0; i<2; i++) //forloop for both teams (it just make 0 == alliance and 1 == horde also for both mines 0=north 1=south { for (uint8 j=0; j<9; j++) diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h index 03dd0ffcf5c..feb3c016e55 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h @@ -20,6 +20,7 @@ #define __BATTLEGROUNDAV_H #include "Battleground.h" +#include "BattlegroundScore.h" #include "Object.h" #define LANG_BG_AV_A_CAPTAIN_BUFF "Begone. Uncouth scum! The Alliance shall prevail in Alterac Valley!" @@ -131,10 +132,10 @@ enum BG_AV_ObjectIds BG_AV_OBJECTID_SNOWFALL_CANDY_PH = 179425, //banners on top of towers: - BG_AV_OBJECTID_TOWER_BANNER_A = 178927, //[PH] Alliance A1 Tower Banner BIG - BG_AV_OBJECTID_TOWER_BANNER_H = 178955, //[PH] Horde H1 Tower Banner BIG - BG_AV_OBJECTID_TOWER_BANNER_PA = 179446, //[PH] Alliance H1 Tower Pre-Banner BIG - BG_AV_OBJECTID_TOWER_BANNER_PH = 179436, //[PH] Horde A1 Tower Pre-Banner BIG + BG_AV_OBJECTID_TOWER_BANNER_A = 178927, //[PH] Alliance A1 Tower Banner BIG + BG_AV_OBJECTID_TOWER_BANNER_H = 178955, //[PH] Horde H1 Tower Banner BIG + BG_AV_OBJECTID_TOWER_BANNER_PA = 179446, //[PH] Alliance H1 Tower Pre-Banner BIG + BG_AV_OBJECTID_TOWER_BANNER_PH = 179436, //[PH] Horde A1 Tower Pre-Banner BIG //Auras BG_AV_OBJECTID_AURA_A = 180421, @@ -148,11 +149,11 @@ enum BG_AV_ObjectIds BG_AV_OBJECTID_GATE_H = 180424, //mine supplies - BG_AV_OBJECTID_MINE_N = 178785, - BG_AV_OBJECTID_MINE_S = 178784, + BG_AV_OBJECTID_MINE_N = 178785, + BG_AV_OBJECTID_MINE_S = 178784, BG_AV_OBJECTID_FIRE = 179065, - BG_AV_OBJECTID_SMOKE = 179066 + BG_AV_OBJECTID_SMOKE = 179066 }; enum BG_AV_Nodes @@ -306,58 +307,58 @@ enum BG_AV_ObjectTypes BG_AV_OBJECT_MINE_SUPPLY_S_MIN = 225, BG_AV_OBJECT_MINE_SUPPLY_S_MAX = 236, - BG_AV_OBJECT_MAX = 237 + BG_AV_OBJECT_MAX = 237 }; enum BG_AV_OBJECTS { - AV_OPLACE_FIRSTAID_STATION = 0, - AV_OPLACE_STORMPIKE_GRAVE = 1, - AV_OPLACE_STONEHEART_GRAVE = 2, - AV_OPLACE_SNOWFALL_GRAVE = 3, - AV_OPLACE_ICEBLOOD_GRAVE = 4, - AV_OPLACE_FROSTWOLF_GRAVE = 5, - AV_OPLACE_FROSTWOLF_HUT = 6, - AV_OPLACE_DUNBALDAR_SOUTH = 7, - AV_OPLACE_DUNBALDAR_NORTH = 8, - AV_OPLACE_ICEWING_BUNKER = 9, - AV_OPLACE_STONEHEART_BUNKER = 10, - AV_OPLACE_ICEBLOOD_TOWER = 11, - AV_OPLACE_TOWER_POINT = 12, - AV_OPLACE_FROSTWOLF_ETOWER = 13, - AV_OPLACE_FROSTWOLF_WTOWER = 14, - AV_OPLACE_BIGBANNER_DUNBALDAR_SOUTH = 15, - AV_OPLACE_BIGBANNER_DUNBALDAR_NORTH = 16, - AV_OPLACE_BIGBANNER_ICEWING_BUNKER = 17, - AV_OPLACE_BIGBANNER_STONEHEART_BUNKER = 18, - AV_OPLACE_BIGBANNER_ICEBLOOD_TOWER = 19, - AV_OPLACE_BIGBANNER_TOWER_POINT = 20, - AV_OPLACE_BIGBANNER_FROSTWOLF_ETOWER = 21, - AV_OPLACE_BIGBANNER_FROSTWOLF_WTOWER = 22, - - AV_OPLACE_BURN_DUNBALDAR_SOUTH = 23, - AV_OPLACE_BURN_DUNBALDAR_NORTH = 33, - AV_OPLACE_BURN_ICEWING_BUNKER = 43, - AV_OPLACE_BURN_STONEHEART_BUNKER = 53, - AV_OPLACE_BURN_ICEBLOOD_TOWER = 63, - AV_OPLACE_BURN_TOWER_POINT = 73, - AV_OPLACE_BURN_FROSTWOLF_ETOWER = 83, - AV_OPLACE_BURN_FROSTWOLF_WTOWER = 93, - AV_OPLACE_BURN_BUILDING_A = 103, - AV_OPLACE_BURN_BUILDING_H = 113, - AV_OPLACE_SNOW_1 = 123, - AV_OPLACE_SNOW_2 = 124, - AV_OPLACE_SNOW_3 = 125, - AV_OPLACE_SNOW_4 = 126, - AV_OPLACE_MINE_SUPPLY_N_MIN = 127, - AV_OPLACE_MINE_SUPPLY_N_MAX = 136, - AV_OPLACE_MINE_SUPPLY_S_MIN = 137, - AV_OPLACE_MINE_SUPPLY_S_MAX = 148, - - AV_OPLACE_MAX = 149 + AV_OPLACE_FIRSTAID_STATION = 0, + AV_OPLACE_STORMPIKE_GRAVE = 1, + AV_OPLACE_STONEHEART_GRAVE = 2, + AV_OPLACE_SNOWFALL_GRAVE = 3, + AV_OPLACE_ICEBLOOD_GRAVE = 4, + AV_OPLACE_FROSTWOLF_GRAVE = 5, + AV_OPLACE_FROSTWOLF_HUT = 6, + AV_OPLACE_DUNBALDAR_SOUTH = 7, + AV_OPLACE_DUNBALDAR_NORTH = 8, + AV_OPLACE_ICEWING_BUNKER = 9, + AV_OPLACE_STONEHEART_BUNKER = 10, + AV_OPLACE_ICEBLOOD_TOWER = 11, + AV_OPLACE_TOWER_POINT = 12, + AV_OPLACE_FROSTWOLF_ETOWER = 13, + AV_OPLACE_FROSTWOLF_WTOWER = 14, + AV_OPLACE_BIGBANNER_DUNBALDAR_SOUTH = 15, + AV_OPLACE_BIGBANNER_DUNBALDAR_NORTH = 16, + AV_OPLACE_BIGBANNER_ICEWING_BUNKER = 17, + AV_OPLACE_BIGBANNER_STONEHEART_BUNKER = 18, + AV_OPLACE_BIGBANNER_ICEBLOOD_TOWER = 19, + AV_OPLACE_BIGBANNER_TOWER_POINT = 20, + AV_OPLACE_BIGBANNER_FROSTWOLF_ETOWER = 21, + AV_OPLACE_BIGBANNER_FROSTWOLF_WTOWER = 22, + + AV_OPLACE_BURN_DUNBALDAR_SOUTH = 23, + AV_OPLACE_BURN_DUNBALDAR_NORTH = 33, + AV_OPLACE_BURN_ICEWING_BUNKER = 43, + AV_OPLACE_BURN_STONEHEART_BUNKER = 53, + AV_OPLACE_BURN_ICEBLOOD_TOWER = 63, + AV_OPLACE_BURN_TOWER_POINT = 73, + AV_OPLACE_BURN_FROSTWOLF_ETOWER = 83, + AV_OPLACE_BURN_FROSTWOLF_WTOWER = 93, + AV_OPLACE_BURN_BUILDING_A = 103, + AV_OPLACE_BURN_BUILDING_H = 113, + AV_OPLACE_SNOW_1 = 123, + AV_OPLACE_SNOW_2 = 124, + AV_OPLACE_SNOW_3 = 125, + AV_OPLACE_SNOW_4 = 126, + AV_OPLACE_MINE_SUPPLY_N_MIN = 127, + AV_OPLACE_MINE_SUPPLY_N_MAX = 136, + AV_OPLACE_MINE_SUPPLY_S_MIN = 137, + AV_OPLACE_MINE_SUPPLY_S_MAX = 148, + + AV_OPLACE_MAX = 149 }; -const float BG_AV_ObjectPos[AV_OPLACE_MAX][4] = +Position const BG_AV_ObjectPos[AV_OPLACE_MAX] = { {638.592f, -32.422f, 46.0608f, -1.62316f }, //firstaid station {669.007f, -294.078f, 30.2909f, 2.77507f }, //stormpike @@ -1228,59 +1229,59 @@ const float BG_AV_StaticCreaturePos[AV_STATICCPLACE_MAX][5] = {-1370.9f, -219.793f, 98.4258f, 5.04381f, 47}, //drek thar }; -const uint32 BG_AV_StaticCreatureInfo[51][4] = +const uint32 BG_AV_StaticCreatureInfo[51] = { - { 2225, 1215, 55, 55 }, //Zora Guthrek - { 3343, 1215, 55, 55 }, //Grelkor - { 3625, 1215, 55, 55 }, //Rarck - { 4255, 1217, 55, 55 }, //Brogus Thunderbrew - { 4257, 1217, 55, 55 }, //Lana Thunderbrew - { 5134, 1217, 55, 55 }, //Jonivera Farmountain - { 5135, 1217, 55, 55 }, //Svalbrad Farmountain - { 5139, 1217, 55, 55 }, //Kurdrum Barleybeard - { 10364, 1215, 55, 55 }, //Yaelika Farclaw - { 10367, 1215, 55, 55 }, //Shrye Ragefist - { 10981, 38, 50, 51 }, //Frostwolf - { 10986, 514, 52, 53 }, //Snowblind Harpy - { 10990, 1274, 50, 51 }, //Alterac Ram - { 11675, 514, 53, 53 }, //Snowblind Windcaller - { 11678, 14, 52, 53 }, //Snowblind Ambusher - { 11839, 39, 56, 56 }, //Wildpaw Brute - { 11947, 1214, 61, 61 }, // Captain Galvangar /// @todo: Duplicate ? Check and confirm - { 11948, 1216, 63, 63 }, //Vanndar Stormpike - { 11949, 1216, 61, 61 }, //Captain Balinda Stonehearth - { 11997, 1334, 60, 60 }, //Stormpike Herald - { 12051, 1214, 57, 57 }, //Frostwolf Legionnaire - { 12096, 1217, 55, 55 }, //Stormpike Quartermaster - { 12097, 1215, 55, 55 }, //Frostwolf Quartermaster - { 12127, 1216, 57, 57 }, //Stormpike Guardsman - { 13176, 1215, 60, 60 }, //Smith Regzar - { 13179, 1215, 59, 59 }, //Wing Commander Guse - { 13216, 1217, 58, 58 }, //Gaelden Hammersmith - { 13218, 1215, 58, 58 }, //Grunnda Wolfheart - { 13236, 1214, 60, 60 }, //Primalist Thurloga - { 13257, 1216, 60, 60 }, //Murgot Deepforge - { 13284, 1214, 58, 58 }, //Frostwolf Shaman - { 13438, 1217, 58, 58 }, //Wing Commander Slidore - { 13442, 1216, 60, 60 }, //Arch Druid Renferal - { 13443, 1216, 60, 60 }, //Druid of the Grove - { 13447, 1216, 58, 58 }, //Corporal Noreg Stormpike - { 13577, 1216, 60, 60 }, //Stormpike Ram Rider Commander - { 13617, 1216, 60, 60 }, //Stormpike Stable Master - { 13797, 32, 60, 61 }, //Mountaineer Boombellow - { 13798, 1214, 60, 61 }, //Jotek - { 13816, 1216, 61, 61 }, //Prospector Stonehewer - { 14185, 877, 59, 59 }, //Najak Hexxen - { 14186, 105, 60, 60 }, //Ravak Grimtotem - { 14187, 1594, 60, 60 }, //Athramanis - { 14188, 57, 59, 59 }, //Dirk Swindle - { 14282, 1214, 53, 54 }, //Frostwolf Bloodhound - { 14283, 1216, 53, 54 }, //Stormpike Owl - { 14284, 1216, 61, 61 }, //Stormpike Battleguard - { 11946, 1214, 63, 63 }, //Drek'Thar /// @todo: Correct the level (Level 80 for boss ?) - { 11948, 1216, 63, 63 }, //Vanndar Stormpike - { 11947, 1214, 61, 61 }, //Captain Galvangar - { 11949, 1216, 61, 61 } //Captain Balinda Stonehearth + 2225, // Zora Guthrek + 3343, // Grelkor + 3625, // Rarck + 4255, // Brogus Thunderbrew + 4257, // Lana Thunderbrew + 5134, // Jonivera Farmountain + 5135, // Svalbrad Farmountain + 5139, // Kurdrum Barleybeard + 10364, // Yaelika Farclaw + 10367, // Shrye Ragefist + 10981, // Frostwolf + 10986, // Snowblind Harpy + 10990, // Alterac Ram + 11675, // Snowblind Windcaller + 11678, // Snowblind Ambusher + 11839, // Wildpaw Brute + 11947, // Captain Galvangar + 11948, // Vanndar Stormpike + 11949, // Captain Balinda Stonehearth + 11997, // Stormpike Herald + 12051, // Frostwolf Legionnaire + 12096, // Stormpike Quartermaster + 12097, // Frostwolf Quartermaster + 12127, // Stormpike Guardsman + 13176, // Smith Regzar + 13179, // Wing Commander Guse + 13216, // Gaelden Hammersmith + 13218, // Grunnda Wolfheart + 13236, // Primalist Thurloga + 13257, // Murgot Deepforge + 13284, // Frostwolf Shaman + 13438, // Wing Commander Slidore + 13442, // Arch Druid Renferal + 13443, // Druid of the Grove + 13447, // Corporal Noreg Stormpike + 13577, // Stormpike Ram Rider Commander + 13617, // Stormpike Stable Master + 13797, // Mountaineer Boombellow + 13798, // Jotek + 13816, // Prospector Stonehewer + 14185, // Najak Hexxen + 14186, // Ravak Grimtotem + 14187, // Athramanis + 14188, // Dirk Swindle + 14282, // Frostwolf Bloodhound + 14283, // Stormpike Owl + 14284, // Stormpike Battleguard + 11946, // Drek'Thar + 11948, // Vanndar Stormpike + 11947, // Captain Galvangar + 11949, // Captain Balinda Stonehearth }; enum BG_AV_Graveyards @@ -1525,18 +1526,53 @@ struct BG_AV_NodeInfo inline BG_AV_Nodes &operator++(BG_AV_Nodes &i){ return i = BG_AV_Nodes(i + 1); } -struct BattlegroundAVScore : public BattlegroundScore +struct BattlegroundAVScore final : public BattlegroundScore { - BattlegroundAVScore() : GraveyardsAssaulted(0), GraveyardsDefended(0), TowersAssaulted(0), - TowersDefended(0), MinesCaptured(0), LeadersKilled(0), SecondaryObjectives(0) { } - ~BattlegroundAVScore() { } - uint32 GraveyardsAssaulted; - uint32 GraveyardsDefended; - uint32 TowersAssaulted; - uint32 TowersDefended; - uint32 MinesCaptured; - uint32 LeadersKilled; - uint32 SecondaryObjectives; + friend class BattlegroundAV; + + protected: + BattlegroundAVScore(uint64 playerGuid) : BattlegroundScore(playerGuid), GraveyardsAssaulted(0), GraveyardsDefended(0), TowersAssaulted(0), TowersDefended(0), MinesCaptured(0) { } + + void UpdateScore(uint32 type, uint32 value) override + { + switch (type) + { + case SCORE_GRAVEYARDS_ASSAULTED: + GraveyardsAssaulted += value; + break; + case SCORE_GRAVEYARDS_DEFENDED: + GraveyardsDefended += value; + break; + case SCORE_TOWERS_ASSAULTED: + TowersAssaulted += value; + break; + case SCORE_TOWERS_DEFENDED: + TowersDefended += value; + break; + case SCORE_MINES_CAPTURED: + MinesCaptured += value; + break; + default: + BattlegroundScore::UpdateScore(type, value); + break; + } + } + + void BuildObjectivesBlock(WorldPacket& data) final + { + data << uint32(5); // Objectives Count + data << uint32(GraveyardsAssaulted); + data << uint32(GraveyardsDefended); + data << uint32(TowersAssaulted); + data << uint32(TowersDefended); + data << uint32(MinesCaptured); + } + + uint32 GraveyardsAssaulted; + uint32 GraveyardsDefended; + uint32 TowersAssaulted; + uint32 TowersDefended; + uint32 MinesCaptured; }; class BattlegroundAV : public Battleground @@ -1557,7 +1593,7 @@ class BattlegroundAV : public Battleground /*general stuff*/ void UpdateScore(uint16 team, int16 points); - void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true); + bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override; /*handlestuff*/ //these are functions which get called from extern void EventPlayerClickedOnFlag(Player* source, GameObject* target_obj); @@ -1607,7 +1643,6 @@ class BattlegroundAV : public Battleground /*general */ Creature* AddAVCreature(uint16 cinfoid, uint16 type); - uint16 GetBonusHonor(uint8 kills); /// @todo: Remove this when the core handles this properly /*variables */ int32 m_Team_Scores[2]; @@ -1622,7 +1657,6 @@ class BattlegroundAV : public Battleground uint32 m_CaptainBuffTimer[2]; bool m_CaptainAlive[2]; - uint8 m_MaxLevel; /// @todo: Remove this once battleground->getmaxlevel() returns something usefull/is reworked (?) bool m_IsInformedNearVictory[2]; }; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp index c89fc57b8aa..548e0bf463b 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp @@ -16,6 +16,7 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "ArenaScore.h" #include "BattlegroundBE.h" #include "Language.h" #include "Object.h" @@ -64,7 +65,7 @@ void BattlegroundBE::StartingEventOpenDoors() void BattlegroundBE::AddPlayer(Player* player) { Battleground::AddPlayer(player); - PlayerScores[player->GetGUID()] = new BattlegroundScore; + PlayerScores[player->GetGUIDLow()] = new ArenaScore(player->GetGUID(), player->GetBGTeam()); UpdateArenaWorldState(); } @@ -139,13 +140,3 @@ bool BattlegroundBE::SetupBattleground() return true; } - -void BattlegroundBE::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) -{ - BattlegroundScoreMap::iterator itr = PlayerScores.find(Source->GetGUID()); - if (itr == PlayerScores.end()) // player not found... - return; - - //there is nothing special in this score - Battleground::UpdatePlayerScore(Source, type, value, doAddHonor); -} diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundBE.h b/src/server/game/Battlegrounds/Zones/BattlegroundBE.h index be801dfff2b..6fd4dc37fc8 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundBE.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundBE.h @@ -59,8 +59,5 @@ class BattlegroundBE : public Battleground void Reset(); void FillInitialWorldStates(WorldPacket &d); void HandleKillPlayer(Player* player, Player* killer); - - /* Scorekeeping */ - void UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor = true); }; #endif diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp index 9e9e82b32b8..1d6970f8317 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundDS.cpp @@ -16,6 +16,7 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "ArenaScore.h" #include "BattlegroundDS.h" #include "Creature.h" #include "GameObject.h" @@ -152,7 +153,7 @@ void BattlegroundDS::StartingEventOpenDoors() void BattlegroundDS::AddPlayer(Player* player) { Battleground::AddPlayer(player); - PlayerScores[player->GetGUID()] = new BattlegroundScore; + PlayerScores[player->GetGUIDLow()] = new ArenaScore(player->GetGUID(), player->GetBGTeam()); UpdateArenaWorldState(); } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp index 213a91bea88..ca96140f5da 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp @@ -363,12 +363,9 @@ void BattlegroundEY::UpdatePointsIcons(uint32 Team, uint32 Point) void BattlegroundEY::AddPlayer(Player* player) { Battleground::AddPlayer(player); - //create score and add it to map - BattlegroundEYScore* sc = new BattlegroundEYScore; + PlayerScores[player->GetGUIDLow()] = new BattlegroundEYScore(player->GetGUID()); m_PlayersNearPoint[EY_POINTS_MAX].push_back(player->GetGUID()); - - PlayerScores[player->GetGUID()] = sc; } void BattlegroundEY::RemovePlayer(Player* player, uint64 guid, uint32 /*team*/) @@ -832,22 +829,20 @@ void BattlegroundEY::EventPlayerCapturedFlag(Player* player, uint32 BgObjectType UpdatePlayerScore(player, SCORE_FLAG_CAPTURES, 1); } -void BattlegroundEY::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) +bool BattlegroundEY::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) { - BattlegroundScoreMap::iterator itr = PlayerScores.find(player->GetGUID()); - if (itr == PlayerScores.end()) // player not found - return; + if (!Battleground::UpdatePlayerScore(player, type, value, doAddHonor)) + return false; switch (type) { - case SCORE_FLAG_CAPTURES: // flags captured - ((BattlegroundEYScore*)itr->second)->FlagCaptures += value; + case SCORE_FLAG_CAPTURES: player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, EY_OBJECTIVE_CAPTURE_FLAG); break; default: - Battleground::UpdatePlayerScore(player, type, value, doAddHonor); break; } + return true; } void BattlegroundEY::FillInitialWorldStates(WorldPacket& data) diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h index 9e5088d7ba5..056deb3498b 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h @@ -20,6 +20,7 @@ #define __BATTLEGROUNDEY_H #include "Battleground.h" +#include "BattlegroundScore.h" #include "Language.h" #include "Object.h" @@ -322,11 +323,33 @@ const BattlegroundEYCapturingPointStruct m_CapturingPointTypes[EY_POINTS_MAX] = BattlegroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_TAKEN_A_M_TOWER, BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_TAKEN_H_M_TOWER, EY_GRAVEYARD_MAGE_TOWER) }; -struct BattlegroundEYScore : public BattlegroundScore +struct BattlegroundEYScore final : public BattlegroundScore { - BattlegroundEYScore() : FlagCaptures(0) { } - ~BattlegroundEYScore() { } - uint32 FlagCaptures; + friend class BattlegroundEY; + + protected: + BattlegroundEYScore(uint64 playerGuid) : BattlegroundScore(playerGuid), FlagCaptures(0) { } + + void UpdateScore(uint32 type, uint32 value) override + { + switch (type) + { + case SCORE_FLAG_CAPTURES: // Flags captured + FlagCaptures += value; + break; + default: + BattlegroundScore::UpdateScore(type, value); + break; + } + } + + void BuildObjectivesBlock(WorldPacket& data) final + { + data << uint32(1); // Objectives Count + data << uint32(FlagCaptures); + } + + uint32 FlagCaptures; }; class BattlegroundEY : public Battleground @@ -357,7 +380,7 @@ class BattlegroundEY : public Battleground void Reset(); void UpdateTeamScore(uint32 Team); void EndBattleground(uint32 winner); - void UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor = true); + bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override; void FillInitialWorldStates(WorldPacket& data); void SetDroppedFlagGUID(uint64 guid, int32 /*TeamID*/ = -1) { m_DroppedFlagGUID = guid;} uint64 GetDroppedFlagGUID() const { return m_DroppedFlagGUID;} diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp index 9e9cc6c63ee..da0b00af40f 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp @@ -80,12 +80,11 @@ void BattlegroundIC::DoAction(uint32 action, uint64 var) if (!player) return; - player->SetTransport(player->GetTeamId() == TEAM_ALLIANCE ? gunshipAlliance : gunshipHorde); + (player->GetTeamId() == TEAM_ALLIANCE ? gunshipAlliance : gunshipHorde)->AddPassenger(player); player->m_movementInfo.transport.pos.m_positionX = TransportMovementInfo.GetPositionX(); player->m_movementInfo.transport.pos.m_positionY = TransportMovementInfo.GetPositionY(); player->m_movementInfo.transport.pos.m_positionZ = TransportMovementInfo.GetPositionZ(); - player->m_movementInfo.transport.guid = (player->GetTeamId() == TEAM_ALLIANCE ? gunshipAlliance : gunshipHorde)->GetGUID(); if (player->TeleportTo(GetMapId(), TeleportToTransportPosition.GetPositionX(), TeleportToTransportPosition.GetPositionY(), @@ -274,7 +273,7 @@ void BattlegroundIC::StartingEventOpenDoors() void BattlegroundIC::AddPlayer(Player* player) { Battleground::AddPlayer(player); - PlayerScores[player->GetGUID()] = new BattlegroundICScore; + PlayerScores[player->GetGUIDLow()] = new BattlegroundICScore(player->GetGUID()); if (nodePoint[NODE_TYPE_QUARRY].nodeState == (player->GetTeamId() == TEAM_ALLIANCE ? NODE_STATE_CONTROLLED_A : NODE_STATE_CONTROLLED_H)) player->CastSpell(player, SPELL_QUARRY, true); @@ -315,27 +314,6 @@ void BattlegroundIC::HandleAreaTrigger(Player* player, uint32 trigger) } } -void BattlegroundIC::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) -{ - std::map<uint64, BattlegroundScore*>::iterator itr = PlayerScores.find(player->GetGUID()); - - if (itr == PlayerScores.end()) // player not found... - return; - - switch (type) - { - case SCORE_BASES_ASSAULTED: - ((BattlegroundICScore*)itr->second)->BasesAssaulted += value; - break; - case SCORE_BASES_DEFENDED: - ((BattlegroundICScore*)itr->second)->BasesDefended += value; - break; - default: - Battleground::UpdatePlayerScore(player, type, value, doAddHonor); - break; - } -} - void BattlegroundIC::FillInitialWorldStates(WorldPacket& data) { data << uint32(BG_IC_ALLIANCE_RENFORT_SET) << uint32(1); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h index 091a75e7449..0b317cabef3 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h @@ -20,6 +20,7 @@ #define __BATTLEGROUNDIC_H #include "Battleground.h" +#include "BattlegroundScore.h" #include "Language.h" #include "Object.h" @@ -847,12 +848,38 @@ enum HonorRewards WINNER_HONOR_AMOUNT = 500 }; -struct BattlegroundICScore : public BattlegroundScore +struct BattlegroundICScore final : public BattlegroundScore { - BattlegroundICScore() : BasesAssaulted(0), BasesDefended(0) { } - ~BattlegroundICScore() { } - uint32 BasesAssaulted; - uint32 BasesDefended; + friend class BattlegroundIC; + + protected: + BattlegroundICScore(uint64 playerGuid) : BattlegroundScore(playerGuid), BasesAssaulted(0), BasesDefended(0) { } + + void UpdateScore(uint32 type, uint32 value) override + { + switch (type) + { + case SCORE_BASES_ASSAULTED: + BasesAssaulted += value; + break; + case SCORE_BASES_DEFENDED: + BasesDefended += value; + break; + default: + BattlegroundScore::UpdateScore(type, value); + break; + } + } + + void BuildObjectivesBlock(WorldPacket& data) final + { + data << uint32(2); // Objectives Count + data << uint32(BasesAssaulted); + data << uint32(BasesDefended); + } + + uint32 BasesAssaulted; + uint32 BasesDefended; }; class BattlegroundIC : public Battleground @@ -881,8 +908,6 @@ class BattlegroundIC : public Battleground WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); /* Scorekeeping */ - void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true); - void FillInitialWorldStates(WorldPacket& data); void DoAction(uint32 action, uint64 var); @@ -894,6 +919,7 @@ class BattlegroundIC : public Battleground bool IsAllNodesControlledByTeam(uint32 team) const; bool IsSpellAllowed(uint32 spellId, Player const* player) const; + private: uint32 closeFortressDoorsTimer; bool doorsClosed; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundNA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundNA.cpp index 70a940ec853..82fcb2f6f91 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundNA.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundNA.cpp @@ -16,6 +16,7 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "ArenaScore.h" #include "BattlegroundNA.h" #include "Language.h" #include "Object.h" @@ -61,7 +62,7 @@ void BattlegroundNA::StartingEventOpenDoors() void BattlegroundNA::AddPlayer(Player* player) { Battleground::AddPlayer(player); - PlayerScores[player->GetGUID()] = new BattlegroundScore; + PlayerScores[player->GetGUIDLow()] = new ArenaScore(player->GetGUID(), player->GetBGTeam()); UpdateArenaWorldState(); } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundRL.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundRL.cpp index 5f77c57c064..712d9a6e296 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundRL.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundRL.cpp @@ -16,6 +16,7 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "ArenaScore.h" #include "BattlegroundRL.h" #include "Language.h" #include "Object.h" @@ -61,7 +62,7 @@ void BattlegroundRL::StartingEventOpenDoors() void BattlegroundRL::AddPlayer(Player* player) { Battleground::AddPlayer(player); - PlayerScores[player->GetGUID()] = new BattlegroundScore; + PlayerScores[player->GetGUIDLow()] = new ArenaScore(player->GetGUID(), player->GetBGTeam()); UpdateArenaWorldState(); } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundRV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundRV.cpp index dd61b8b9e6f..1059124d041 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundRV.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundRV.cpp @@ -16,6 +16,7 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "ArenaScore.h" #include "Battleground.h" #include "BattlegroundRV.h" #include "ObjectAccessor.h" @@ -99,7 +100,7 @@ void BattlegroundRV::StartingEventOpenDoors() void BattlegroundRV::AddPlayer(Player* player) { Battleground::AddPlayer(player); - PlayerScores[player->GetGUID()] = new BattlegroundScore; + PlayerScores[player->GetGUIDLow()] = new ArenaScore(player->GetGUID(), player->GetBGTeam()); UpdateWorldState(BG_RV_WORLD_STATE_A, GetAlivePlayersCountByTeam(ALLIANCE)); UpdateWorldState(BG_RV_WORLD_STATE_H, GetAlivePlayersCountByTeam(HORDE)); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp index 0966ddd19bd..7e90c0b3db0 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp @@ -454,9 +454,7 @@ void BattlegroundSA::FillInitialWorldStates(WorldPacket& data) void BattlegroundSA::AddPlayer(Player* player) { Battleground::AddPlayer(player); - //create score and add it to map, default values are set in constructor - BattlegroundSAScore* sc = new BattlegroundSAScore; - PlayerScores[player->GetGUID()] = sc; + PlayerScores[player->GetGUIDLow()] = new BattlegroundSAScore(player->GetGUID()); SendTransportInit(player); @@ -493,20 +491,6 @@ void BattlegroundSA::HandleAreaTrigger(Player* /*Source*/, uint32 /*Trigger*/) return; } -void BattlegroundSA::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) -{ - BattlegroundScoreMap::iterator itr = PlayerScores.find(Source->GetGUID()); - if (itr == PlayerScores.end()) // player not found... - return; - - if (type == SCORE_DESTROYED_DEMOLISHER) - ((BattlegroundSAScore*)itr->second)->demolishers_destroyed += value; - else if (type == SCORE_DESTROYED_WALL) - ((BattlegroundSAScore*)itr->second)->gates_destroyed += value; - else - Battleground::UpdatePlayerScore(Source, type, value, doAddHonor); -} - void BattlegroundSA::TeleportPlayers() { for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h index 880da0735f4..a3947334417 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h @@ -20,16 +20,9 @@ #define __BATTLEGROUNDSA_H #include "Battleground.h" +#include "BattlegroundScore.h" #include "Object.h" -struct BattlegroundSAScore : public BattlegroundScore -{ - BattlegroundSAScore() : demolishers_destroyed(0), gates_destroyed(0) { } - ~BattlegroundSAScore() { } - uint8 demolishers_destroyed; - uint8 gates_destroyed; -}; - #define BG_SA_FLAG_AMOUNT 3 #define BG_SA_DEMOLISHER_AMOUNT 4 @@ -249,7 +242,7 @@ uint32 const BG_SA_NpcEntries[BG_SA_MAXNPC] = NPC_KANRETHAD }; -Position const BG_SA_NpcSpawnlocs[BG_SA_MAXNPC + BG_SA_DEMOLISHER_AMOUNT] = +Position const BG_SA_NpcSpawnlocs[BG_SA_MAXNPC] = { // Cannons { 1436.429f, 110.05f, 41.407f, 5.4f }, @@ -515,6 +508,40 @@ struct BG_SA_RoundScore uint32 time; }; +struct BattlegroundSAScore final : public BattlegroundScore +{ + friend class BattlegroundSA; + + protected: + BattlegroundSAScore(uint64 playerGuid) : BattlegroundScore(playerGuid), DemolishersDestroyed(0), GatesDestroyed(0) { } + + void UpdateScore(uint32 type, uint32 value) override + { + switch (type) + { + case SCORE_DESTROYED_DEMOLISHER: + DemolishersDestroyed += value; + break; + case SCORE_DESTROYED_WALL: + GatesDestroyed += value; + break; + default: + BattlegroundScore::UpdateScore(type, value); + break; + } + } + + void BuildObjectivesBlock(WorldPacket& data) final + { + data << uint32(2); // Objectives Count + data << uint32(DemolishersDestroyed); + data << uint32(GatesDestroyed); + } + + uint32 DemolishersDestroyed; + uint32 GatesDestroyed; +}; + /// Class for manage Strand of Ancient battleground class BattlegroundSA : public Battleground { @@ -568,8 +595,6 @@ class BattlegroundSA : public Battleground void HandleAreaTrigger(Player* Source, uint32 Trigger); /* Scorekeeping */ - /// Update score board - void UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor = true); // Achievement: Not Even a Scratch bool CheckAchievementCriteriaMeet(uint32 criteriaId, Player const* source, Unit const* target = NULL, uint32 miscValue = 0) override; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp index fcd55e2e16a..1faa3361975 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp @@ -229,10 +229,7 @@ void BattlegroundWS::StartingEventOpenDoors() void BattlegroundWS::AddPlayer(Player* player) { Battleground::AddPlayer(player); - //create score and add it to map, default values are set in constructor - BattlegroundWGScore* sc = new BattlegroundWGScore; - - PlayerScores[player->GetGUID()] = sc; + PlayerScores[player->GetGUIDLow()] = new BattlegroundWGScore(player->GetGUID()); } void BattlegroundWS::RespawnFlag(uint32 Team, bool captured) @@ -790,26 +787,23 @@ void BattlegroundWS::HandleKillPlayer(Player* player, Player* killer) Battleground::HandleKillPlayer(player, killer); } -void BattlegroundWS::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) +bool BattlegroundWS::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) { - BattlegroundScoreMap::iterator itr = PlayerScores.find(player->GetGUID()); - if (itr == PlayerScores.end()) // player not found - return; + if (!Battleground::UpdatePlayerScore(player, type, value, doAddHonor)) + return false; switch (type) { case SCORE_FLAG_CAPTURES: // flags captured - ((BattlegroundWGScore*)itr->second)->FlagCaptures += value; player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, WS_OBJECTIVE_CAPTURE_FLAG); break; case SCORE_FLAG_RETURNS: // flags returned - ((BattlegroundWGScore*)itr->second)->FlagReturns += value; player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, WS_OBJECTIVE_RETURN_FLAG); break; default: - Battleground::UpdatePlayerScore(player, type, value, doAddHonor); break; } + return true; } WorldSafeLocsEntry const* BattlegroundWS::GetClosestGraveYard(Player* player) diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h index c6c25ec52de..3d449580fb9 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h @@ -20,6 +20,7 @@ #define __BATTLEGROUNDWS_H #include "Battleground.h" +#include "BattlegroundScore.h" enum BG_WS_TimerOrScore { @@ -146,12 +147,38 @@ enum BG_WS_Objectives #define WS_EVENT_START_BATTLE 8563 -struct BattlegroundWGScore : public BattlegroundScore +struct BattlegroundWGScore final : public BattlegroundScore { - BattlegroundWGScore() : FlagCaptures(0), FlagReturns(0) { } - ~BattlegroundWGScore() { } - uint32 FlagCaptures; - uint32 FlagReturns; + friend class BattlegroundWS; + + protected: + BattlegroundWGScore(uint64 playerGuid) : BattlegroundScore(playerGuid), FlagCaptures(0), FlagReturns(0) { } + + void UpdateScore(uint32 type, uint32 value) override + { + switch (type) + { + case SCORE_FLAG_CAPTURES: // Flags captured + FlagCaptures += value; + break; + case SCORE_FLAG_RETURNS: // Flags returned + FlagReturns += value; + break; + default: + BattlegroundScore::UpdateScore(type, value); + break; + } + } + + void BuildObjectivesBlock(WorldPacket& data) final + { + data << uint32(2); // Objectives Count + data << uint32(FlagCaptures); + data << uint32(FlagReturns); + } + + uint32 FlagCaptures; + uint32 FlagReturns; }; class BattlegroundWS : public Battleground @@ -197,7 +224,7 @@ class BattlegroundWS : public Battleground void UpdateFlagState(uint32 team, uint32 value); void SetLastFlagCapture(uint32 team) { _lastFlagCaptureTeam = team; } void UpdateTeamScore(uint32 team); - void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true); + bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override; void SetDroppedFlagGUID(uint64 guid, int32 team = -1) { if (team == TEAM_ALLIANCE || team == TEAM_HORDE) diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index bf46c1fd7c6..26fd0814dcb 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -103,7 +103,9 @@ set(game_STAT_SRCS include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/SFMT ${CMAKE_SOURCE_DIR}/dep/zlib diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index ec048e167ac..10b7c25bb1f 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -349,21 +349,20 @@ enum ItemLimitCategoryMode ITEM_LIMIT_CATEGORY_MODE_EQUIP = 1 // limit applied to amount equipped items (including used gems) }; -enum SpellCategoryFlags +enum SkillRaceClassInfoFlags { - SPELL_CATEGORY_FLAG_COOLDOWN_SCALES_WITH_WEAPON_SPEED = 0x01, // unused - SPELL_CATEGORY_FLAG_COOLDOWN_STARTS_ON_EVENT = 0x04 + SKILL_FLAG_NO_SKILLUP_MESSAGE = 0x2, + SKILL_FLAG_ALWAYS_MAX_VALUE = 0x10, + SKILL_FLAG_UNLEARNABLE = 0x20, // Skill can be unlearned + SKILL_FLAG_INCLUDE_IN_SORT = 0x80, // Spells belonging to a skill with this flag will additionally compare skill ids when sorting spellbook in client + SKILL_FLAG_NOT_TRAINABLE = 0x100, + SKILL_FLAG_MONO_VALUE = 0x400 // Skill always has value 1 }; -enum TotemCategoryType +enum SpellCategoryFlags { - TOTEM_CATEGORY_TYPE_KNIFE = 1, - TOTEM_CATEGORY_TYPE_TOTEM = 2, - TOTEM_CATEGORY_TYPE_ROD = 3, - TOTEM_CATEGORY_TYPE_PICK = 21, - TOTEM_CATEGORY_TYPE_STONE = 22, - TOTEM_CATEGORY_TYPE_HAMMER = 23, - TOTEM_CATEGORY_TYPE_SPANNER = 24 + SPELL_CATEGORY_FLAG_COOLDOWN_SCALES_WITH_WEAPON_SPEED = 0x01, // unused + SPELL_CATEGORY_FLAG_COOLDOWN_STARTS_ON_EVENT = 0x04 }; // SummonProperties.dbc, col 1 @@ -398,6 +397,17 @@ enum SummonPropFlags SUMMON_PROP_FLAG_UNK16 = 0x00008000 // Light/Dark Bullet, Soul/Fiery Consumption, Twisted Visage, Twilight Whelp. Phase related? }; +enum TotemCategoryType +{ + TOTEM_CATEGORY_TYPE_KNIFE = 1, + TOTEM_CATEGORY_TYPE_TOTEM = 2, + TOTEM_CATEGORY_TYPE_ROD = 3, + TOTEM_CATEGORY_TYPE_PICK = 21, + TOTEM_CATEGORY_TYPE_STONE = 22, + TOTEM_CATEGORY_TYPE_HAMMER = 23, + TOTEM_CATEGORY_TYPE_SPANNER = 24 +}; + enum VehicleSeatFlags { VEHICLE_SEAT_FLAG_HAS_LOWER_ANIM_FOR_ENTER = 0x00000001, @@ -442,6 +452,7 @@ enum VehicleSeatFlagsB VEHICLE_SEAT_FLAG_B_EJECTABLE = 0x00000020, // ejectable VEHICLE_SEAT_FLAG_B_USABLE_FORCED_2 = 0x00000040, VEHICLE_SEAT_FLAG_B_USABLE_FORCED_3 = 0x00000100, + VEHICLE_SEAT_FLAG_B_KEEP_PET = 0x00020000, VEHICLE_SEAT_FLAG_B_USABLE_FORCED_4 = 0x02000000, VEHICLE_SEAT_FLAG_B_CAN_SWITCH = 0x04000000, VEHICLE_SEAT_FLAG_B_VEHICLE_PLAYERFRAME_UI = 0x80000000 // Lua_UnitHasVehiclePlayerFrameUI - actually checked for flagsb &~ 0x80000000 diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 44f03b6978d..92d00b20645 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -151,6 +151,9 @@ DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore(ScalingStatValuesfmt DBCStorage <SkillLineEntry> sSkillLineStore(SkillLinefmt); DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore(SkillLineAbilityfmt); +DBCStorage <SkillRaceClassInfoEntry> sSkillRaceClassInfoStore(SkillRaceClassInfofmt); +SkillRaceClassInfoMap SkillRaceClassInfoBySkill; +DBCStorage <SkillTiersEntry> sSkillTiersStore(SkillTiersfmt); DBCStorage <SoundEntriesEntry> sSoundEntriesStore(SoundEntriesfmt); @@ -409,6 +412,13 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sScalingStatValuesStore, dbcPath, "ScalingStatValues.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sSkillLineStore, dbcPath, "SkillLine.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sSkillLineAbilityStore, dbcPath, "SkillLineAbility.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sSkillRaceClassInfoStore, dbcPath, "SkillRaceClassInfo.dbc"); + for (uint32 i = 0; i < sSkillRaceClassInfoStore.GetNumRows(); ++i) + if (SkillRaceClassInfoEntry const* entry = sSkillRaceClassInfoStore.LookupEntry(i)) + if (sSkillLineStore.LookupEntry(entry->SkillId)) + SkillRaceClassInfoBySkill.emplace(entry->SkillId, entry); + + LoadDBC(availableDbcLocales, bad_dbc_files, sSkillTiersStore, dbcPath, "SkillTiers.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sSoundEntriesStore, dbcPath, "SoundEntries.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sSpellStore, dbcPath, "Spell.dbc", &CustomSpellEntryfmt, &CustomSpellEntryIndex); for (uint32 i = 1; i < sSpellStore.GetNumRows(); ++i) @@ -965,3 +975,19 @@ uint32 GetDefaultMapLight(uint32 mapId) return 0; } + +SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_) +{ + SkillRaceClassInfoBounds bounds = SkillRaceClassInfoBySkill.equal_range(skill); + for (SkillRaceClassInfoMap::iterator itr = bounds.first; itr != bounds.second; ++itr) + { + if (itr->second->RaceMask && !(itr->second->RaceMask & (1 << (race - 1)))) + continue; + if (itr->second->ClassMask && !(itr->second->ClassMask & (1 << (class_ - 1)))) + continue; + + return itr->second; + } + + return NULL; +} diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index fe775dfda19..8b89a86fafe 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -74,6 +74,10 @@ LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty); uint32 GetDefaultMapLight(uint32 mapId); +typedef std::unordered_multimap<uint32, SkillRaceClassInfoEntry const*> SkillRaceClassInfoMap; +typedef std::pair<SkillRaceClassInfoMap::iterator, SkillRaceClassInfoMap::iterator> SkillRaceClassInfoBounds; +SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_); + extern DBCStorage <AchievementEntry> sAchievementStore; extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore; extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions @@ -150,6 +154,7 @@ extern DBCStorage <ScalingStatDistributionEntry> sScalingStatDistributionStore; extern DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore; extern DBCStorage <SkillLineEntry> sSkillLineStore; extern DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore; +extern DBCStorage <SkillTiersEntry> sSkillTiersStore; extern DBCStorage <SoundEntriesEntry> sSoundEntriesStore; extern DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore; extern DBCStorage <SpellCategoryEntry> sSpellCategoryStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 5d6c8c7aa89..2da166fb049 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1584,6 +1584,27 @@ struct SkillLineAbilityEntry //uint32 characterPoints[2]; // 12-13 m_characterPoints[2] }; +struct SkillRaceClassInfoEntry +{ + //uint32 Id; // 0 + uint32 SkillId; // 1 + uint32 RaceMask; // 2 + uint32 ClassMask; // 3 + uint32 Flags; // 4 + //uint32 MinLevel; // 5 + uint32 SkillTier; // 6 + //uint32 SkillCostType; // 7 +}; + +#define MAX_SKILL_STEP 16 + +struct SkillTiersEntry +{ + uint32 Id; // 0 + //uint32 StepCost[MAX_SKILL_STEP]; // 1-16 + uint32 MaxSkill[MAX_SKILL_STEP]; // 17-32 +}; + struct SoundEntriesEntry { uint32 Id; // 0 m_ID diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 222353467f4..a90cc48c5af 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -98,6 +98,8 @@ char const ScalingStatDistributionfmt[] = "niiiiiiiiiiiiiiiiiiiii"; char const ScalingStatValuesfmt[] = "iniiiiiiiiiiiiiiiiiiiiii"; char const SkillLinefmt[] = "nixssssssssssssssssxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxi"; char const SkillLineAbilityfmt[] = "niiiixxiiiiixx"; +char const SkillRaceClassInfofmt[] = "diiiixix"; +char const SkillTiersfmt[] = "nxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiii"; char const SoundEntriesfmt[] = "nxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; char const SpellCastTimefmt[] = "nixx"; char const SpellCategoryfmt[] = "ni"; diff --git a/src/server/game/DungeonFinding/LFGScripts.cpp b/src/server/game/DungeonFinding/LFGScripts.cpp index aadf1529ffd..181e04e04fc 100644 --- a/src/server/game/DungeonFinding/LFGScripts.cpp +++ b/src/server/game/DungeonFinding/LFGScripts.cpp @@ -46,7 +46,7 @@ void LFGPlayerScript::OnLogout(Player* player) } } -void LFGPlayerScript::OnLogin(Player* player) +void LFGPlayerScript::OnLogin(Player* player, bool /*loginFirst*/) { if (!sLFGMgr->isOptionEnabled(LFG_OPTION_ENABLE_DUNGEON_FINDER | LFG_OPTION_ENABLE_RAID_BROWSER)) return; diff --git a/src/server/game/DungeonFinding/LFGScripts.h b/src/server/game/DungeonFinding/LFGScripts.h index 87881ed7524..1ed37bd9d05 100644 --- a/src/server/game/DungeonFinding/LFGScripts.h +++ b/src/server/game/DungeonFinding/LFGScripts.h @@ -36,7 +36,7 @@ class LFGPlayerScript : public PlayerScript // Player Hooks void OnLogout(Player* player); - void OnLogin(Player* player); + void OnLogin(Player* player, bool loginFirst); void OnMapChanged(Player* player); }; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 90527912efd..19d32b41c93 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -142,8 +142,8 @@ bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) } Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(), -lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLowGUID(0), -m_PlayerDamageReq(0), m_lootRecipient(0), m_lootRecipientGroup(0), m_corpseRemoveTime(0), m_respawnTime(0), +m_groupLootTimer(0), lootingGroupLowGUID(0), m_PlayerDamageReq(0), +m_lootRecipient(0), m_lootRecipientGroup(0), _skinner(0), _pickpocketLootRestore(0), m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), @@ -547,6 +547,15 @@ void Creature::Update(uint32 diff) if (!IsAlive()) break; + time_t now = time(NULL); + + // Check if we should refill the pickpocketing loot + if (loot.loot_type == LOOT_PICKPOCKETING && _pickpocketLootRestore && _pickpocketLootRestore <= now) + { + loot.clear(); + _pickpocketLootRestore = 0; + } + if (m_regenTimer > 0) { if (diff >= m_regenTimer) @@ -567,13 +576,13 @@ void Creature::Update(uint32 diff) if (!IsInEvadeMode() && (!bInCombat || IsPolymorphed())) // regenerate health if not in combat or if polymorphed RegenerateHealth(); - if (getPowerType() == POWER_ENERGY) + if (HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER)) { - if (!IsVehicle() || GetVehicleKit()->GetVehicleInfo()->m_powerDisplayId != POWER_PYRITE) + if (getPowerType() == POWER_ENERGY) Regenerate(POWER_ENERGY); + else + RegenerateMana(); } - else - RegenerateMana(); /*if (!bIsPolymorphed) // only increase the timer if not polymorphed m_regenTimer += CREATURE_REGEN_INTERVAL - diff; @@ -1173,14 +1182,22 @@ bool Creature::CreateFromProto(uint32 guidlow, uint32 entry, CreatureData const* SetOriginalEntry(entry); - if (!vehId) - vehId = cinfo->VehicleId; - - Object::_Create(guidlow, entry, vehId ? HIGHGUID_VEHICLE : HIGHGUID_UNIT); + Object::_Create(guidlow, entry, (vehId || cinfo->VehicleId) ? HIGHGUID_VEHICLE : HIGHGUID_UNIT); if (!UpdateEntry(entry, data)) return false; + if (!vehId) + { + if (GetCreatureTemplate()->VehicleId) + { + vehId = GetCreatureTemplate()->VehicleId; + entry = GetCreatureTemplate()->Entry; + } + else + vehId = cinfo->VehicleId; + } + if (vehId) CreateVehicleKit(vehId, entry); @@ -1455,11 +1472,6 @@ void Creature::setDeathState(DeathState s) setActive(false); - if (!IsPet() && GetCreatureTemplate()->SkinLootId) - if (LootTemplates_Skinning.HaveLootFor(GetCreatureTemplate()->SkinLootId)) - if (hasLootRecipient()) - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); - if (HasSearchedAssistance()) { SetNoSearchAssistance(false); @@ -1519,9 +1531,8 @@ void Creature::Respawn(bool force) TC_LOG_DEBUG("entities.unit", "Respawning creature %s (GuidLow: %u, Full GUID: " UI64FMTD " Entry: %u)", GetName().c_str(), GetGUIDLow(), GetGUID(), GetEntry()); m_respawnTime = 0; - lootForPickPocketed = false; - lootForBody = false; - + _pickpocketLootRestore = 0; + loot.clear(); if (m_originalEntry != GetEntry()) UpdateEntry(m_originalEntry); @@ -2260,26 +2271,23 @@ void Creature::GetRespawnPosition(float &x, float &y, float &z, float* ori, floa void Creature::AllLootRemovedFromCorpse() { - if (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE)) - { - time_t now = time(NULL); - if (m_corpseRemoveTime <= now) - return; + if (loot.loot_type != LOOT_SKINNING && !IsPet() && GetCreatureTemplate()->SkinLootId && hasLootRecipient()) + if (LootTemplates_Skinning.HaveLootFor(GetCreatureTemplate()->SkinLootId)) + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); - float decayRate; - CreatureTemplate const* cinfo = GetCreatureTemplate(); + time_t now = time(NULL); + if (m_corpseRemoveTime <= now) + return; - decayRate = sWorld->getRate(RATE_CORPSE_DECAY_LOOTED); - uint32 diff = uint32((m_corpseRemoveTime - now) * decayRate); + float decayRate = sWorld->getRate(RATE_CORPSE_DECAY_LOOTED); - m_respawnTime -= diff; + // corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update + if (loot.loot_type == LOOT_SKINNING) + m_corpseRemoveTime = time(NULL); + else + m_corpseRemoveTime = now + m_corpseDelay * decayRate; - // corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update - if (cinfo && cinfo->SkinLootId) - m_corpseRemoveTime = time(NULL); - else - m_corpseRemoveTime -= diff; - } + m_respawnTime = m_corpseRemoveTime + m_respawnTime; } uint8 Creature::getLevelForTarget(WorldObject const* target) const @@ -2704,3 +2712,8 @@ void Creature::ReleaseFocus(Spell const* focusSpell) ClearUnitState(UNIT_STATE_ROTATING); } +void Creature::StartPickPocketRefillTimer() +{ + _pickpocketLootRestore = time(NULL) + sWorld->getIntConfig(CONFIG_CREATURE_PICKPOCKET_REFILL); +} + diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 9cc08e3b71d..ca536e44e43 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -551,8 +551,10 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject virtual void DeleteFromDB(); // overriden in Pet Loot loot; - bool lootForPickPocketed; - bool lootForBody; + void StartPickPocketRefillTimer(); + void ResetPickPocketRefillTimer() { _pickpocketLootRestore = 0; } + void SetSkinner(uint64 guid) { _skinner = guid; } + uint64 GetSkinner() const { return _skinner; } // Returns the player who skinned this creature Player* GetLootRecipient() const; Group* GetLootRecipientGroup() const; bool hasLootRecipient() const { return m_lootRecipient || m_lootRecipientGroup; } @@ -688,8 +690,10 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject uint64 m_lootRecipient; uint32 m_lootRecipientGroup; + uint64 _skinner; /// Timers + time_t _pickpocketLootRestore; time_t m_corpseRemoveTime; // (msecs)timer for death or corpse disappearance time_t m_respawnTime; // (secs) time of next respawn uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp index 7cc94d992a1..e008146bb85 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp +++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp @@ -48,18 +48,6 @@ DynamicObject::~DynamicObject() delete _removedAura; } -void DynamicObject::CleanupsBeforeDelete(bool finalCleanup /* = true */) -{ - WorldObject::CleanupsBeforeDelete(finalCleanup); - - if (Transport* transport = GetTransport()) - { - transport->RemovePassenger(this); - SetTransport(NULL); - m_movementInfo.transport.Reset(); - } -} - void DynamicObject::AddToWorld() { ///- Register the dynamicObject for guid lookup and for caster @@ -124,14 +112,11 @@ bool DynamicObject::CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spe Transport* transport = caster->GetTransport(); if (transport) { - m_movementInfo.transport.guid = GetGUID(); - float x, y, z, o; pos.GetPosition(x, y, z, o); transport->CalculatePassengerOffset(x, y, z, &o); m_movementInfo.transport.pos.Relocate(x, y, z, o); - SetTransport(transport); // This object must be added to transport before adding to map for the client to properly display it transport->AddPassenger(this); } diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.h b/src/server/game/Entities/DynamicObject/DynamicObject.h index f52c86afdee..c9fd1d29f8b 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.h +++ b/src/server/game/Entities/DynamicObject/DynamicObject.h @@ -41,8 +41,6 @@ class DynamicObject : public WorldObject, public GridObject<DynamicObject>, publ void AddToWorld(); void RemoveFromWorld(); - void CleanupsBeforeDelete(bool finalCleanup = true) override; - bool CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spellId, Position const& pos, float radius, DynamicObjectType type); void Update(uint32 p_time); void Remove(); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 370696474ae..ae08a4251a5 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -98,20 +98,12 @@ std::string GameObject::GetAIName() const return ""; } -void GameObject::CleanupsBeforeDelete(bool /*finalCleanup*/) +void GameObject::CleanupsBeforeDelete(bool finalCleanup) { - if (IsInWorld()) - RemoveFromWorld(); + WorldObject::CleanupsBeforeDelete(finalCleanup); if (m_uint32Values) // field array can be not exist if GameOBject not loaded RemoveFromOwner(); - - if (GetTransport() && !ToTransport()) - { - GetTransport()->RemovePassenger(this); - SetTransport(NULL); - m_movementInfo.transport.Reset(); - } } void GameObject::RemoveFromOwner() @@ -696,12 +688,39 @@ void GameObject::getFishLoot(Loot* fishloot, Player* loot_owner) fishloot->clear(); uint32 zone, subzone; + uint32 defaultzone = 1; GetZoneAndAreaId(zone, subzone); // if subzone loot exist use it - if (!fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner, true, true)) - // else use zone loot (must exist in like case) - fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true); + fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner, true, true); + if (fishloot->empty()) //use this becase if zone or subzone has set LOOT_MODE_JUNK_FISH,Even if no normal drop, fishloot->FillLoot return true. it wrong. + { + //subzone no result,use zone loot + fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true, true); + //use zone 1 as default, somewhere fishing got nothing,becase subzone and zone not set, like Off the coast of Storm Peaks. + if (fishloot->empty()) + fishloot->FillLoot(defaultzone, LootTemplates_Fishing, loot_owner, true, true); + } +} + +void GameObject::getFishLootJunk(Loot* fishloot, Player* loot_owner) +{ + fishloot->clear(); + + uint32 zone, subzone; + uint32 defaultzone = 1; + GetZoneAndAreaId(zone, subzone); + + // if subzone loot exist use it + fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH); + if (fishloot->empty()) //use this becase if zone or subzone has normal mask drop, then fishloot->FillLoot return true. + { + //use zone loot + fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH); + if (fishloot->empty()) + //use zone 1 as default + fishloot->FillLoot(defaultzone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH); + } } void GameObject::SaveToDB() @@ -1416,10 +1435,8 @@ void GameObject::Use(Unit* user) else player->SendLoot(GetGUID(), LOOT_FISHING); } - /// @todo else: junk - else - m_respawnTime = time(NULL); - + else // else: junk + player->SendLoot(GetGUID(), LOOT_FISHING_JUNK); break; } case GO_JUST_DEACTIVATED: // nothing to do, will be deleted at next update @@ -1730,7 +1747,7 @@ void GameObject::Use(Unit* user) CastSpell(user, spellId); } -void GameObject::CastSpell(Unit* target, uint32 spellId) +void GameObject::CastSpell(Unit* target, uint32 spellId, bool triggered /*= true*/) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) @@ -1749,7 +1766,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId) if (self) { if (target) - target->CastSpell(target, spellInfo, true); + target->CastSpell(target, spellInfo, triggered); return; } @@ -1763,14 +1780,14 @@ void GameObject::CastSpell(Unit* target, uint32 spellId) trigger->setFaction(owner->getFaction()); // needed for GO casts for proper target validation checks trigger->SetOwnerGUID(owner->GetGUID()); - trigger->CastSpell(target ? target : trigger, spellInfo, true, 0, 0, owner->GetGUID()); + trigger->CastSpell(target ? target : trigger, spellInfo, triggered, 0, 0, owner->GetGUID()); } else { trigger->setFaction(14); // Set owner guid for target if no owner available - needed by trigger auras // - trigger gets despawned and there's no caster avalible (see AuraEffect::TriggerSpell()) - trigger->CastSpell(target ? target : trigger, spellInfo, true, 0, 0, target ? target->GetGUID() : 0); + trigger->CastSpell(target ? target : trigger, spellInfo, triggered, 0, 0, target ? target->GetGUID() : 0); } } diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index a99c5db93aa..8f70fc0e907 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -713,6 +713,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map void Refresh(); void Delete(); void getFishLoot(Loot* loot, Player* loot_owner); + void getFishLootJunk(Loot* loot, Player* loot_owner); GameobjectTypes GetGoType() const { return GameobjectTypes(GetByteValue(GAMEOBJECT_BYTES_1, 1)); } void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); } GOState GetGoState() const { return GOState(GetByteValue(GAMEOBJECT_BYTES_1, 0)); } @@ -790,7 +791,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map GameObject* LookupFishingHoleAround(float range); - void CastSpell(Unit* target, uint32 spell); + void CastSpell(Unit* target, uint32 spell, bool triggered = true); void SendCustomAnim(uint32 anim); bool IsInRange(float x, float y, float z, float radius) const; diff --git a/src/server/game/Entities/Item/ItemPrototype.h b/src/server/game/Entities/Item/ItemPrototype.h index cc477c5bd37..bdf956f8921 100644 --- a/src/server/game/Entities/Item/ItemPrototype.h +++ b/src/server/game/Entities/Item/ItemPrototype.h @@ -734,7 +734,7 @@ struct ItemTemplate default: break; } - return itemLevel; + return std::max<float>(0.f, itemLevel); } bool IsPotion() const { return Class == ITEM_CLASS_CONSUMABLE && SubClass == ITEM_SUBCLASS_POTION; } diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index f2215fa2d6d..4ff0153dea8 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1163,6 +1163,9 @@ void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/) { if (IsInWorld()) RemoveFromWorld(); + + if (Transport* transport = GetTransport()) + transport->RemovePassenger(this); } void WorldObject::_Create(uint32 guidlow, HighGuid guidhigh, uint32 phaseMask) @@ -1215,7 +1218,7 @@ bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool float sizefactor = GetObjectSize() + obj->GetObjectSize(); float maxdist = dist2compare + sizefactor; - if (m_transport && obj->GetTransport() && obj->GetTransport()->GetGUIDLow() == m_transport->GetGUIDLow()) + if (GetTransport() && obj->GetTransport() && obj->GetTransport()->GetGUIDLow() == GetTransport()->GetGUIDLow()) { float dtx = m_movementInfo.transport.pos.m_positionX - obj->m_movementInfo.transport.pos.m_positionX; float dty = m_movementInfo.transport.pos.m_positionY - obj->m_movementInfo.transport.pos.m_positionY; diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 768f5907c19..cc199969174 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -1916,6 +1916,8 @@ bool Pet::Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 Entry, uint3 if (!InitEntry(Entry)) return false; + // Force regen flag for player pets, just like we do for players themselves + SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER); SetSheath(SHEATH_STATE_MELEE); return true; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index c7f36aff92b..8653106a865 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -26,6 +26,7 @@ #include "BattlefieldWG.h" #include "Battleground.h" #include "BattlegroundMgr.h" +#include "BattlegroundScore.h" #include "CellImpl.h" #include "Channel.h" #include "ChannelMgr.h" @@ -2131,11 +2132,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati { TC_LOG_DEBUG("maps", "Player %s using client without required expansion tried teleport to non accessible map %u", GetName().c_str(), mapid); - if (GetTransport()) + if (Transport* transport = GetTransport()) { - m_transport->RemovePassenger(this); - m_transport = NULL; - m_movementInfo.transport.Reset(); + transport->RemovePassenger(this); RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :) } @@ -2153,16 +2152,12 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati SetUnitMovementFlags(GetUnitMovementFlags() & MOVEMENTFLAG_MASK_HAS_PLAYER_STATUS_OPCODE); DisableSpline(); - if (m_transport) + if (Transport* transport = GetTransport()) { if (options & TELE_TO_NOT_LEAVE_TRANSPORT) AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); else - { - m_transport->RemovePassenger(this); - m_transport = NULL; - m_movementInfo.transport.Reset(); - } + transport->RemovePassenger(this); } // The player was ported to another map and loses the duel immediately. @@ -2297,8 +2292,8 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati // send transfer packets WorldPacket data(SMSG_TRANSFER_PENDING, 4 + 4 + 4); data << uint32(mapid); - if (m_transport) - data << m_transport->GetEntry() << GetMapId(); + if (Transport* transport = GetTransport()) + data << transport->GetEntry() << GetMapId(); GetSession()->SendPacket(&data); } @@ -2316,7 +2311,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati { WorldPacket data(SMSG_NEW_WORLD, 4 + 4 + 4 + 4 + 4); data << uint32(mapid); - if (m_transport) + if (GetTransport()) data << m_movementInfo.transport.pos.PositionXYZOStream(); else data << m_teleport_dest.PositionXYZOStream(); @@ -2926,11 +2921,10 @@ void Player::UninviteFromGroup() void Player::RemoveFromGroup(Group* group, uint64 guid, RemoveMethod method /* = GROUP_REMOVEMETHOD_DEFAULT*/, uint64 kicker /* = 0 */, const char* reason /* = NULL */) { - if (group) - { - group->RemoveMember(guid, method, kicker, reason); - group = NULL; - } + if (!group) + return; + + group->RemoveMember(guid, method, kicker, reason); } void Player::SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 BonusXP, bool recruitAFriend, float /*group_rate*/) @@ -6435,7 +6429,7 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal) if (newVal < currVal) UpdateSkillEnchantments(id, currVal, newVal); // update step - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos), MAKE_PAIR32(id, step)); + SetUInt32Value(PLAYER_SKILL_INDEX(itr->second.pos), MAKE_PAIR32(id, step)); // update value SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos), MAKE_SKILL_VALUE(newVal, maxVal)); if (itr->second.uState != SKILL_NEW) @@ -8790,7 +8784,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type) // not check distance for GO in case owned GO (fishing bobber case, for example) // And permit out of range GO with no owner in case fishing hole - if (!go || (loot_type != LOOT_FISHINGHOLE && (loot_type != LOOT_FISHING || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this, INTERACTION_DISTANCE)) || (loot_type == LOOT_CORPSE && go->GetRespawnTime() && go->isSpawnedByDefault())) + if (!go || (loot_type != LOOT_FISHINGHOLE && ((loot_type != LOOT_FISHING && loot_type != LOOT_FISHING_JUNK) || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this, INTERACTION_DISTANCE)) || (loot_type == LOOT_CORPSE && go->GetRespawnTime() && go->isSpawnedByDefault())) { SendLootRelease(guid); return; @@ -8828,6 +8822,8 @@ void Player::SendLoot(uint64 guid, LootType loot_type) if (loot_type == LOOT_FISHING) go->getFishLoot(loot, this); + else if (loot_type == LOOT_FISHING_JUNK) + go->getFishLootJunk(loot, this); if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules) { @@ -8974,9 +8970,9 @@ void Player::SendLoot(uint64 guid, LootType loot_type) if (loot_type == LOOT_PICKPOCKETING) { - if (!creature->lootForPickPocketed) + if (loot->loot_type != LOOT_PICKPOCKETING) { - creature->lootForPickPocketed = true; + creature->StartPickPocketRefillTimer(); loot->clear(); if (uint32 lootid = creature->GetCreatureTemplate()->pickpocketLootId) @@ -8996,12 +8992,9 @@ void Player::SendLoot(uint64 guid, LootType loot_type) if (!recipient) return; - if (!creature->lootForBody) + if (loot->loot_type == LOOT_NONE) { - creature->lootForBody = true; - // for creature, loot is filled when creature is killed. - if (Group* group = recipient->GetGroup()) { switch (group->GetLootMethod()) @@ -9022,11 +9015,17 @@ void Player::SendLoot(uint64 guid, LootType loot_type) } } - // possible only if creature->lootForBody && loot->empty() at spell cast check - if (loot_type == LOOT_SKINNING) + // if loot is already skinning loot then don't do anything else + if (loot->loot_type == LOOT_SKINNING) + { + loot_type = LOOT_SKINNING; + permission = creature->GetSkinner() == GetGUID() ? OWNER_PERMISSION : NONE_PERMISSION; + } + else if (loot_type == LOOT_SKINNING) { loot->clear(); loot->FillLoot(creature->GetCreatureTemplate()->SkinLootId, LootTemplates_Skinning, this, true); + creature->SetSkinner(GetGUID()); permission = OWNER_PERMISSION; } // set group rights only for loot_type != LOOT_SKINNING @@ -9070,6 +9069,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type) { case LOOT_INSIGNIA: loot_type = LOOT_SKINNING; break; case LOOT_FISHINGHOLE: loot_type = LOOT_FISHING; break; + case LOOT_FISHING_JUNK: loot_type = LOOT_FISHING; break; default: break; } @@ -17398,15 +17398,15 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) { uint64 transGUID = MAKE_NEW_GUID(transLowGUID, 0, HIGHGUID_MO_TRANSPORT); + Transport* transport = NULL; if (GameObject* go = HashMapHolder<GameObject>::Find(transGUID)) - m_transport = go->ToTransport(); + transport = go->ToTransport(); - if (m_transport) + if (transport) { - m_movementInfo.transport.guid = transGUID; float x = fields[26].GetFloat(), y = fields[27].GetFloat(), z = fields[28].GetFloat(), o = fields[29].GetFloat(); m_movementInfo.transport.pos.Relocate(x, y, z, o); - m_transport->CalculatePassengerPosition(x, y, z, &o); + transport->CalculatePassengerPosition(x, y, z, &o); if (!Trinity::IsValidMapCoord(x, y, z, o) || // transport size limited @@ -17417,7 +17417,6 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) TC_LOG_ERROR("entities.player", "Player (guidlow %d) have invalid transport coordinates (X: %f Y: %f Z: %f O: %f). Teleport to bind location.", guid, x, y, z, o); - m_transport = NULL; m_movementInfo.transport.Reset(); RelocateToHomebind(); @@ -17425,10 +17424,9 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) else { Relocate(x, y, z, o); - mapId = m_transport->GetMapId(); + mapId = transport->GetMapId(); - m_transport->AddPassenger(this); - AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + transport->AddPassenger(this); } } else @@ -17836,6 +17834,9 @@ bool Player::isAllowedToLoot(const Creature* creature) if (loot->isLooted()) // nothing to loot or everything looted. return false; + if (loot->loot_type == LOOT_SKINNING) + return creature->GetSkinner() == GetGUID(); + Group* thisGroup = GetGroup(); if (!thisGroup) return this == creature->GetLootRecipient(); @@ -24981,7 +24982,7 @@ void Player::_LoadSkills(PreparedQueryResult result) base_skill = 1; // skill mast be known and then > 0 in any case if (GetPureSkillValue(SKILL_FIRST_AID) < base_skill) - SetSkill(SKILL_FIRST_AID, 0, base_skill, base_skill); + SetSkill(SKILL_FIRST_AID, 4 /*artisan*/, base_skill, 300); if (GetPureSkillValue(SKILL_AXES) < base_skill) SetSkill(SKILL_AXES, 0, base_skill, base_skill); if (GetPureSkillValue(SKILL_DEFENSE) < base_skill) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index aeac9db98aa..fdebbde0ae2 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -918,7 +918,7 @@ class PlayerTaxi bool SetTaximaskNode(uint32 nodeidx) { uint8 field = uint8((nodeidx - 1) / 32); - uint32 submask = 1 << ((nodeidx-1) % 32); + uint32 submask = 1 << ((nodeidx - 1) % 32); if ((m_taximask[field] & submask) != submask) { m_taximask[field] |= submask; @@ -951,7 +951,7 @@ class PlayerTaxi std::deque<uint32> m_TaxiDestinations; }; -std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi); +std::ostringstream& operator << (std::ostringstream& ss, PlayerTaxi const& taxi); class Player; @@ -2635,8 +2635,8 @@ class Player : public Unit, public GridObject<Player> uint32 _activeCheats; }; -void AddItemsSetItem(Player*player, Item* item); -void RemoveItemsSetItem(Player*player, ItemTemplate const* proto); +void AddItemsSetItem(Player* player, Item* item); +void RemoveItemsSetItem(Player* player, ItemTemplate const* proto); // "the bodies of template functions must be made available in a header file" template <class T> T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell* spell) diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 8bc07732bb6..d907274f8d1 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -35,7 +35,7 @@ Transport::Transport() : GameObject(), _transportInfo(NULL), _isMoving(true), _pendingStop(false), - _triggeredArrivalEvent(false), _triggeredDepartureEvent(false) + _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), _passengerTeleportItr(_passengers.begin()) { m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION; } @@ -107,9 +107,6 @@ void Transport::CleanupsBeforeDelete(bool finalCleanup /*= true*/) while (!_passengers.empty()) { WorldObject* obj = *_passengers.begin(); - obj->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); - obj->m_movementInfo.transport.Reset(); - obj->SetTransport(NULL); RemovePassenger(obj); } @@ -231,6 +228,9 @@ void Transport::AddPassenger(WorldObject* passenger) if (_passengers.insert(passenger).second) { + passenger->SetTransport(this); + passenger->m_movementInfo.AddMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + passenger->m_movementInfo.transport.guid = GetGUID(); TC_LOG_DEBUG("entities.transport", "Object %s boarded transport %s.", passenger->GetName().c_str(), GetName().c_str()); if (Player* plr = passenger->ToPlayer()) @@ -240,8 +240,27 @@ void Transport::AddPassenger(WorldObject* passenger) void Transport::RemovePassenger(WorldObject* passenger) { - if (_passengers.erase(passenger) || _staticPassengers.erase(passenger)) // static passenger can remove itself in case of grid unload + bool erased = false; + if (_passengerTeleportItr != _passengers.end()) { + PassengerSet::iterator itr = _passengers.find(passenger); + if (itr != _passengers.end()) + { + if (itr == _passengerTeleportItr) + ++_passengerTeleportItr; + + _passengers.erase(itr); + erased = true; + } + } + else + erased = _passengers.erase(passenger) > 0; + + if (erased || _staticPassengers.erase(passenger)) // static passenger can remove itself in case of grid unload + { + passenger->SetTransport(NULL); + passenger->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + passenger->m_movementInfo.transport.Reset(); TC_LOG_DEBUG("entities.transport", "Object %s removed from transport %s.", passenger->GetName().c_str(), GetName().c_str()); if (Player* plr = passenger->ToPlayer()) @@ -570,9 +589,9 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl GetMap()->RemoveFromMap<Transport>(this, false); SetMap(newMap); - for (std::set<WorldObject*>::iterator itr = _passengers.begin(); itr != _passengers.end();) + for (_passengerTeleportItr = _passengers.begin(); _passengerTeleportItr != _passengers.end();) { - WorldObject* obj = (*itr++); + WorldObject* obj = (*_passengerTeleportItr++); float destX, destY, destZ, destO; obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO); @@ -595,7 +614,7 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl } case TYPEID_PLAYER: if (!obj->ToPlayer()->TeleportTo(newMapid, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT)) - _passengers.erase(obj); + RemovePassenger(obj); break; case TYPEID_DYNAMICOBJECT: obj->AddObjectToRemoveList(); @@ -613,7 +632,7 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl else { // Teleport players, they need to know it - for (std::set<WorldObject*>::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr) + for (PassengerSet::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr) { if ((*itr)->GetTypeId() == TYPEID_PLAYER) { @@ -630,9 +649,9 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl } } -void Transport::UpdatePassengerPositions(std::set<WorldObject*>& passengers) +void Transport::UpdatePassengerPositions(PassengerSet& passengers) { - for (std::set<WorldObject*>::iterator itr = passengers.begin(); itr != passengers.end(); ++itr) + for (PassengerSet::iterator itr = passengers.begin(); itr != passengers.end(); ++itr) { WorldObject* passenger = *itr; // transport teleported but passenger not yet (can happen for players) diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h index 293d4334a2e..e644417f1ac 100644 --- a/src/server/game/Entities/Transport/Transport.h +++ b/src/server/game/Entities/Transport/Transport.h @@ -31,6 +31,8 @@ class Transport : public GameObject, public TransportBase Transport(); public: + typedef std::set<WorldObject*> PassengerSet; + ~Transport(); bool Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress); @@ -42,7 +44,7 @@ class Transport : public GameObject, public TransportBase void AddPassenger(WorldObject* passenger); void RemovePassenger(WorldObject* passenger); - std::set<WorldObject*> const& GetPassengers() const { return _passengers; } + PassengerSet const& GetPassengers() const { return _passengers; } Creature* CreateNPCPassenger(uint32 guid, CreatureData const* data); GameObject* CreateGOPassenger(uint32 guid, GameObjectData const* data); @@ -99,7 +101,7 @@ class Transport : public GameObject, public TransportBase void MoveToNextWaypoint(); float CalculateSegmentPos(float perc); bool TeleportTransport(uint32 newMapid, float x, float y, float z, float o); - void UpdatePassengerPositions(std::set<WorldObject*>& passengers); + void UpdatePassengerPositions(PassengerSet& passengers); void DoEventIfAny(KeyFrame const& node, bool departure); //! Helpers to know if stop frame was reached @@ -118,8 +120,9 @@ class Transport : public GameObject, public TransportBase bool _triggeredArrivalEvent; bool _triggeredDepartureEvent; - std::set<WorldObject*> _passengers; - std::set<WorldObject*> _staticPassengers; + PassengerSet _passengers; + PassengerSet::iterator _passengerTeleportItr; + PassengerSet _staticPassengers; }; #endif diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 2b6cb9dd8ba..ca4780b787e 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -21,6 +21,7 @@ #include "Battlefield.h" #include "BattlefieldMgr.h" #include "Battleground.h" +#include "BattlegroundScore.h" #include "CellImpl.h" #include "ConditionMgr.h" #include "CreatureAI.h" @@ -3352,7 +3353,7 @@ void Unit::_ApplyAuraEffect(Aura* aura, uint8 effIndex) AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID()); ASSERT(aurApp); if (!aurApp->GetEffectMask()) - _ApplyAura(aurApp, 1<<effIndex); + _ApplyAura(aurApp, 1 << effIndex); else aurApp->_HandleEffect(effIndex, true); } @@ -3390,7 +3391,7 @@ void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask) // apply effects of the aura for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { - if (effMask & 1<<i && (!aurApp->GetRemoveMode())) + if (effMask & 1 << i && (!aurApp->GetRemoveMode())) aurApp->_HandleEffect(i, true); } } @@ -3503,6 +3504,19 @@ void Unit::_RemoveNoStackAurasDueToAura(Aura* aura) if (spellProto->IsPassiveStackableWithRanks()) return; + if (!IsHighestExclusiveAura(aura)) + { + if (!aura->GetSpellInfo()->IsAffectingArea()) + { + Unit* caster = aura->GetCaster(); + if (caster && caster->GetTypeId() == TYPEID_PLAYER) + Spell::SendCastResult(caster->ToPlayer(), aura->GetSpellInfo(), 1, SPELL_FAILED_AURA_BOUNCED); + } + + RemoveAura(aura); + return; + } + bool remove = false; for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i) { @@ -3832,6 +3846,7 @@ void Unit::RemoveAurasByType(AuraType auraType, uint64 casterGUID, Aura* except, { Aura* aura = (*iter)->GetBase(); AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID()); + ASSERT(aurApp); ++iter; if (aura != except && (!casterGUID || aura->GetCasterGUID() == casterGUID) @@ -6036,11 +6051,11 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = 34299; if (triggeredByAura->GetCasterGUID() != GetGUID()) break; - int32 basepoints1 = triggerAmount * 2; + int32 basepoints1 = CalculatePct(GetMaxPower(Powers(POWER_MANA)), triggerAmount * 2); // Improved Leader of the Pack // Check cooldown of heal spell cooldown if (GetTypeId() == TYPEID_PLAYER && !ToPlayer()->HasSpellCooldown(34299)) - CastCustomSpell(this, 60889, &basepoints1, 0, 0, true, 0, triggeredByAura); + CastCustomSpell(this, 68285, &basepoints1, 0, 0, true, 0, triggeredByAura); break; } // Healing Touch (Dreamwalker Raiment set) @@ -8645,25 +8660,30 @@ void Unit::setPowerType(Powers new_powertype) } } + float powerMultiplier = 1.0f; + if (!IsPet()) + if (Creature* creature = ToCreature()) + powerMultiplier = creature->GetCreatureTemplate()->ModMana; + switch (new_powertype) { default: case POWER_MANA: break; case POWER_RAGE: - SetMaxPower(POWER_RAGE, GetCreatePowers(POWER_RAGE)); + SetMaxPower(POWER_RAGE, uint32(std::ceil(GetCreatePowers(POWER_RAGE) * powerMultiplier))); SetPower(POWER_RAGE, 0); break; case POWER_FOCUS: - SetMaxPower(POWER_FOCUS, GetCreatePowers(POWER_FOCUS)); - SetPower(POWER_FOCUS, GetCreatePowers(POWER_FOCUS)); + SetMaxPower(POWER_FOCUS, uint32(std::ceil(GetCreatePowers(POWER_FOCUS) * powerMultiplier))); + SetPower(POWER_FOCUS, uint32(std::ceil(GetCreatePowers(POWER_FOCUS) * powerMultiplier))); break; case POWER_ENERGY: - SetMaxPower(POWER_ENERGY, GetCreatePowers(POWER_ENERGY)); + SetMaxPower(POWER_ENERGY, uint32(std::ceil(GetCreatePowers(POWER_ENERGY) * powerMultiplier))); break; case POWER_HAPPINESS: - SetMaxPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS)); - SetPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS)); + SetMaxPower(POWER_HAPPINESS, uint32(std::ceil(GetCreatePowers(POWER_HAPPINESS) * powerMultiplier))); + SetPower(POWER_HAPPINESS, uint32(std::ceil(GetCreatePowers(POWER_HAPPINESS) * powerMultiplier))); break; } } @@ -10486,17 +10506,21 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto { if (!((*i)->IsAffectedOnSpell(spellProto))) continue; - int32 modChance = 0; + switch ((*i)->GetMiscValue()) { - // Shatter - case 911: modChance+= 16; - case 910: modChance+= 17; - case 849: modChance+= 17; - if (!victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) - break; - crit_chance+=modChance; + case 911: // Shatter (Rank 1) + if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) + crit_chance += 17; break; + case 910: // Shatter (Rank 2) + if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) + crit_chance += 34; + break; + case 849: // Shatter (Rank 3) + if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) + crit_chance += 50; + break; case 7917: // Glyph of Shadowburn if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this)) crit_chance+=(*i)->GetAmount(); @@ -10516,7 +10540,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto case SPELLFAMILY_MAGE: // Glyph of Fire Blast if (spellProto->SpellFamilyFlags[0] == 0x2 && spellProto->SpellIconID == 12) - if (victim->HasAuraWithMechanic((1<<MECHANIC_STUN) | (1<<MECHANIC_KNOCKOUT))) + if (victim->HasAuraWithMechanic((1 << MECHANIC_STUN) | (1 << MECHANIC_KNOCKOUT))) if (AuraEffect const* aurEff = GetAuraEffect(56369, EFFECT_0)) crit_chance += aurEff->GetAmount(); break; @@ -10537,7 +10561,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto crit_chance += aurEff->GetAmount(); break; } - break; + break; case SPELLFAMILY_ROGUE: // Shiv-applied poisons can't crit if (FindCurrentSpellBySpellId(5938)) @@ -10559,7 +10583,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto return 100.0f; break; } - break; + break; case SPELLFAMILY_SHAMAN: // Lava Burst if (spellProto->SpellFamilyFlags[1] & 0x00001000) @@ -10569,7 +10593,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto return 100.0f; break; } - break; + break; } } break; @@ -10590,17 +10614,17 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto crit_chance += rendAndTear->GetAmount(); break; } - break; + break; case SPELLFAMILY_WARRIOR: - // Victory Rush - if (spellProto->SpellFamilyFlags[1] & 0x100) - { - // Glyph of Victory Rush - if (AuraEffect const* aurEff = GetAuraEffect(58382, 0)) - crit_chance += aurEff->GetAmount(); - break; - } - break; + // Victory Rush + if (spellProto->SpellFamilyFlags[1] & 0x100) + { + // Glyph of Victory Rush + if (AuraEffect const* aurEff = GetAuraEffect(58382, 0)) + crit_chance += aurEff->GetAmount(); + break; + } + break; } } /// Intentional fallback. Calculate critical strike chance for both Ranged and Melee spells @@ -12883,19 +12907,24 @@ int32 Unit::ModSpellDuration(SpellInfo const* spellProto, Unit const* target, in return std::max(duration, 0); } -void Unit::ModSpellCastTime(SpellInfo const* spellProto, int32 & castTime, Spell* spell) +void Unit::ModSpellCastTime(SpellInfo const* spellInfo, int32 & castTime, Spell* spell) { - if (!spellProto || castTime < 0) + if (!spellInfo || castTime < 0) + return; + + if (spellInfo->IsChanneled() && !(spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION)) return; + // called from caster if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CASTING_TIME, castTime, spell); + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell); - if (!(spellProto->Attributes & (SPELL_ATTR0_ABILITY|SPELL_ATTR0_TRADESPELL)) && ((GetTypeId() == TYPEID_PLAYER && spellProto->SpellFamilyName) || GetTypeId() == TYPEID_UNIT)) + if (!((spellInfo->Attributes & (SPELL_ATTR0_ABILITY | SPELL_ATTR0_TRADESPELL)) || (spellInfo->AttributesEx3 & SPELL_ATTR3_NO_DONE_BONUS)) && + ((GetTypeId() == TYPEID_PLAYER && spellInfo->SpellFamilyName) || GetTypeId() == TYPEID_UNIT)) castTime = int32(float(castTime) * GetFloatValue(UNIT_MOD_CAST_SPEED)); - else if (spellProto->Attributes & SPELL_ATTR0_REQ_AMMO && !(spellProto->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG)) + else if (spellInfo->Attributes & SPELL_ATTR0_REQ_AMMO && !(spellInfo->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG)) castTime = int32(float(castTime) * m_modAttackSpeedPct[RANGED_ATTACK]); - else if (spellProto->SpellVisual[0] == 3881 && HasAura(67556)) // cooking with Chef Hat. + else if (spellInfo->SpellVisual[0] == 3881 && HasAura(67556)) // cooking with Chef Hat. castTime = 500; } @@ -13550,12 +13579,7 @@ void Unit::CleanupsBeforeDelete(bool finalCleanup) { CleanupBeforeRemoveFromMap(finalCleanup); - if (GetTransport()) - { - GetTransport()->RemovePassenger(this); - SetTransport(NULL); - m_movementInfo.transport.Reset(); - } + WorldObject::CleanupsBeforeDelete(finalCleanup); } void Unit::UpdateCharmAI() @@ -15247,8 +15271,8 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) if (creature) { Loot* loot = &creature->loot; - if (creature->lootForPickPocketed) - creature->lootForPickPocketed = false; + if (creature->loot.loot_type == LOOT_PICKPOCKETING) + creature->ResetPickPocketRefillTimer(); loot->clear(); if (uint32 lootid = creature->GetCreatureTemplate()->lootid) @@ -15367,9 +15391,12 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) if (!creature->IsPet()) { creature->DeleteThreatList(); - CreatureTemplate const* cInfo = creature->GetCreatureTemplate(); - if (cInfo && (cInfo->lootid || cInfo->maxgold > 0)) + + // must be after setDeathState which resets dynamic flags + if (!creature->loot.empty()) creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + else + creature->AllLootRemovedFromCorpse(); } // Call KilledUnit for creatures, this needs to be called after the lootable flag is set @@ -16354,19 +16381,25 @@ void Unit::SetPhaseMask(uint32 newPhaseMask, bool update) } } - WorldObject::SetPhaseMask(newPhaseMask, update); + // Phase player, dont update + WorldObject::SetPhaseMask(newPhaseMask, false); - if (!IsInWorld()) - return; + // Phase pets and summons + if (IsInWorld()) + { + for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) + if ((*itr)->GetTypeId() == TYPEID_UNIT) + (*itr)->SetPhaseMask(newPhaseMask, true); - for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) - if ((*itr)->GetTypeId() == TYPEID_UNIT) - (*itr)->SetPhaseMask(newPhaseMask, true); + for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i) + if (m_SummonSlot[i]) + if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i])) + summon->SetPhaseMask(newPhaseMask, true); + } - for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i) - if (m_SummonSlot[i]) - if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i])) - summon->SetPhaseMask(newPhaseMask, true); + // Update visibility after phasing pets and summons so they wont despawn + if (update) + UpdateObjectVisibility(); } void Unit::UpdateObjectVisibility(bool forced) @@ -17742,3 +17775,73 @@ void Unit::BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns c data << uint32(itr->second); } } + +int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const +{ + int32 val = 0; + SpellSpellGroupMapBounds spellGroup = sSpellMgr->GetSpellSpellGroupMapBounds(aurEff->GetSpellInfo()->GetFirstRankSpell()->Id); + for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second ; ++itr) + { + if (sSpellMgr->GetSpellGroupStackRule(itr->second) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT) + { + AuraEffectList const& auraEffList = GetAuraEffectsByType(auraType); + for (AuraEffectList::const_iterator auraItr = auraEffList.begin(); auraItr != auraEffList.end(); ++auraItr) + { + if (aurEff != (*auraItr) && (!checkMiscValue || (*auraItr)->GetMiscValue() == miscValue) && + sSpellMgr->IsSpellMemberOfSpellGroup((*auraItr)->GetSpellInfo()->Id, itr->second)) + { + // absolute value only + if (abs(val) < abs((*auraItr)->GetAmount())) + val = (*auraItr)->GetAmount(); + } + } + } + } + return val; +} + +bool Unit::IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications /*= false*/) +{ + for (uint32 i = 0 ; i < MAX_SPELL_EFFECTS; ++i) + { + if (AuraEffect const* aurEff = aura->GetEffect(i)) + { + AuraType const auraType = AuraType(aura->GetSpellInfo()->Effects[i].ApplyAuraName); + AuraEffectList const& auras = GetAuraEffectsByType(auraType); + for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();) + { + AuraEffect const* existingAurEff = (*itr); + ++itr; + + if (sSpellMgr->CheckSpellGroupStackRules(aura->GetSpellInfo(), existingAurEff->GetSpellInfo()) + == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST) + { + int32 diff = abs(aurEff->GetAmount()) - abs(existingAurEff->GetAmount()); + if (!diff) + diff = int32(aura->GetEffectMask()) - int32(existingAurEff->GetBase()->GetEffectMask()); + + if (diff > 0) + { + Aura const* base = existingAurEff->GetBase(); + // no removing of area auras from the original owner, as that completely cancels them + if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this)) + { + if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID())) + { + bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType); + uint32 removedAuras = m_removedAurasCount; + RemoveAura(aurApp); + if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1) + itr = auras.begin(); + } + } + } + else if (diff < 0) + return false; + } + } + } + } + + return true; +} diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index dbb463585f0..535d75af204 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1289,7 +1289,7 @@ class Unit : public WorldObject void RemoveFromWorld(); void CleanupBeforeRemoveFromMap(bool finalCleanup); - void CleanupsBeforeDelete(bool finalCleanup = true); // used in ~Creature/~Player (or before mass creature delete to remove cross-references to already deleted units) + void CleanupsBeforeDelete(bool finalCleanup = true) override; // used in ~Creature/~Player (or before mass creature delete to remove cross-references to already deleted units) DiminishingLevels GetDiminishing(DiminishingGroup group); void IncrDiminishing(DiminishingGroup group); @@ -2155,6 +2155,9 @@ class Unit : public WorldObject time_t GetLastDamagedTime() const { return _lastDamagedTime; } void SetLastDamagedTime(time_t val) { _lastDamagedTime = val; } + int32 GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue = false, int32 miscValue = 0) const; + bool IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications = false); + protected: explicit Unit (bool isWorldObject); diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index 4c3724a8860..915e6016e22 100755 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -77,8 +77,12 @@ Vehicle::~Vehicle() void Vehicle::Install() { if (_me->GetTypeId() == TYPEID_UNIT) + { if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(_vehicleInfo->m_powerDisplayId)) _me->setPowerType(Powers(powerDisplay->PowerType)); + else if (_me->getClass() == CLASS_ROGUE) + _me->setPowerType(POWER_ENERGY); + } _status = STATUS_INSTALLED; if (GetBase()->GetTypeId() == TYPEID_UNIT) @@ -775,6 +779,8 @@ bool VehicleJoinEvent::Execute(uint64, uint32) Passenger->InterruptNonMeleeSpells(false); Passenger->RemoveAurasByType(SPELL_AURA_MOUNTED); + VehicleSeatEntry const* veSeat = Seat->second.SeatInfo; + Player* player = Passenger->ToPlayer(); if (player) { @@ -785,14 +791,14 @@ bool VehicleJoinEvent::Execute(uint64, uint32) player->StopCastingCharm(); player->StopCastingBindSight(); player->SendOnCancelExpectedVehicleRideAura(); - player->UnsummonPetTemporaryIfAny(); + if (!(veSeat->m_flagsB & VEHICLE_SEAT_FLAG_B_KEEP_PET)) + player->UnsummonPetTemporaryIfAny(); } if (Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE) Passenger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); Passenger->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); - VehicleSeatEntry const* veSeat = Seat->second.SeatInfo; Passenger->m_movementInfo.transport.pos.Relocate(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ); Passenger->m_movementInfo.transport.time = 0; Passenger->m_movementInfo.transport.seat = Seat->first; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 207f80eabe7..9eb7d5ec1bf 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -1668,7 +1668,7 @@ void ObjectMgr::LoadCreatures() } // Skip spawnMask check for transport maps - if (!_transportMaps.count(data.mapid) && data.spawnMask & ~spawnMasks[data.mapid]) + if (!IsTransportMap(data.mapid) && data.spawnMask & ~spawnMasks[data.mapid]) TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u) that have wrong spawn mask %u including not supported difficulty modes for map (Id: %u).", guid, data.spawnMask, data.mapid); bool ok = true; @@ -2003,7 +2003,7 @@ void ObjectMgr::LoadGameobjects() data.spawnMask = fields[14].GetUInt8(); - if (!_transportMaps.count(data.mapid) && data.spawnMask & ~spawnMasks[data.mapid]) + if (!IsTransportMap(data.mapid) && data.spawnMask & ~spawnMasks[data.mapid]) TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) that has wrong spawn mask %u including not supported difficulty modes for map (Id: %u), skip", guid, data.id, data.spawnMask, data.mapid); data.phaseMask = fields[15].GetUInt32(); @@ -2951,32 +2951,32 @@ void ObjectMgr::LoadVehicleTemplateAccessories() { Field* fields = result->Fetch(); - uint32 uiEntry = fields[0].GetUInt32(); - uint32 uiAccessory = fields[1].GetUInt32(); - int8 uiSeat = int8(fields[2].GetInt8()); - bool bMinion = fields[3].GetBool(); - uint8 uiSummonType = fields[4].GetUInt8(); - uint32 uiSummonTimer= fields[5].GetUInt32(); + uint32 entry = fields[0].GetUInt32(); + uint32 accessory = fields[1].GetUInt32(); + int8 seatId = fields[2].GetInt8(); + bool isMinion = fields[3].GetBool(); + uint8 summonType = fields[4].GetUInt8(); + uint32 summonTimer = fields[5].GetUInt32(); - if (!sObjectMgr->GetCreatureTemplate(uiEntry)) + if (!sObjectMgr->GetCreatureTemplate(entry)) { - TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u does not exist.", uiEntry); + TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u does not exist.", entry); continue; } - if (!sObjectMgr->GetCreatureTemplate(uiAccessory)) + if (!sObjectMgr->GetCreatureTemplate(accessory)) { - TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: Accessory %u does not exist.", uiAccessory); + TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: Accessory %u does not exist.", accessory); continue; } - if (_spellClickInfoStore.find(uiEntry) == _spellClickInfoStore.end()) + if (_spellClickInfoStore.find(entry) == _spellClickInfoStore.end()) { - TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u has no data in npc_spellclick_spells", uiEntry); + TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u has no data in npc_spellclick_spells", entry); continue; } - _vehicleTemplateAccessoryStore[uiEntry].push_back(VehicleAccessory(uiAccessory, uiSeat, bMinion, uiSummonType, uiSummonTimer)); + _vehicleTemplateAccessoryStore[entry].push_back(VehicleAccessory(accessory, seatId, isMinion, summonType, summonTimer)); ++count; } diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index ba5940d7e12..e5e55b847d3 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1293,6 +1293,8 @@ class ObjectMgr void LoadFactionChangeSpells(); void LoadFactionChangeTitles(); + bool IsTransportMap(uint32 mapId) const { return _transportMaps.count(mapId); } + private: // first free id for selected id type uint32 _auctionId; diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp index 472497ea5f2..270d598d53a 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -35,7 +35,8 @@ void VisibleNotifier::SendToSelf() // at this moment i_clientGUIDs have guids that not iterate at grid level checks // but exist one case when this possible and object not out of range: transports if (Transport* transport = i_player.GetTransport()) - for (std::set<WorldObject*>::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end();++itr) + { + for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr) { if (vis_guids.find((*itr)->GetGUID()) != vis_guids.end()) { @@ -54,11 +55,15 @@ void VisibleNotifier::SendToSelf() case TYPEID_UNIT: i_player.UpdateVisibilityOf((*itr)->ToCreature(), i_data, i_visibleNow); break; + case TYPEID_DYNAMICOBJECT: + i_player.UpdateVisibilityOf((*itr)->ToDynObject(), i_data, i_visibleNow); + break; default: break; } } } + } for (Player::ClientGUIDs::const_iterator it = vis_guids.begin();it != vis_guids.end(); ++it) { diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 113df993f81..45ecbf0c3df 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -1572,7 +1572,7 @@ void Group::UpdatePlayerOutOfRange(Player* player) for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) { member = itr->GetSource(); - if (member && !member->IsWithinDist(player, member->GetSightRange(), false)) + if (member && member != player && (!member->IsInMap(player) || !member->IsWithinDist(player, member->GetSightRange(), false))) member->GetSession()->SendPacket(&data); } } diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp index 0dfe396b65a..7def6b0f467 100644 --- a/src/server/game/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -309,7 +309,7 @@ void WorldSession::HandlePVPLogDataOpcode(WorldPacket & /*recvData*/) return; WorldPacket data; - sBattlegroundMgr->BuildPvpLogDataPacket(&data, bg); + bg->BuildPvPLogDataPacket(data); SendPacket(&data); TC_LOG_DEBUG("network", "WORLD: Sent MSG_PVP_LOG_DATA Message"); diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp index 0a797f0e008..dd654fb3ad0 100644 --- a/src/server/game/Handlers/CalendarHandler.cpp +++ b/src/server/game/Handlers/CalendarHandler.cpp @@ -260,26 +260,43 @@ void WorldSession::HandleCalendarAddEvent(WorldPacket& recvData) } else { + // client limits the amount of players to be invited to 100 + const uint32 MaxPlayerInvites = 100; + uint32 inviteCount; - recvData >> inviteCount; + uint64 invitee[MaxPlayerInvites]; + uint8 status[MaxPlayerInvites]; + uint8 rank[MaxPlayerInvites]; + + memset(invitee, 0, sizeof(invitee)); + memset(status, 0, sizeof(status)); + memset(rank, 0, sizeof(rank)); + + try + { + recvData >> inviteCount; + + for (uint32 i = 0; i < inviteCount && i < MaxPlayerInvites; ++i) + { + recvData.readPackGUID(invitee[i]); + recvData >> status[i] >> rank[i]; + } + } + catch (ByteBufferException const&) + { + delete calendarEvent; + calendarEvent = NULL; + throw; + } SQLTransaction trans; if (inviteCount > 1) trans = CharacterDatabase.BeginTransaction(); - // client limits the amount of players to be invited to 100 - const uint32 MaxPlayerInvites = 100; - for (uint32 i = 0; i < inviteCount && i < MaxPlayerInvites; ++i) { - uint64 invitee = 0; - uint8 status = 0; - uint8 rank = 0; - recvData.readPackGUID(invitee); - recvData >> status >> rank; - // 946684800 is 01/01/2000 00:00:00 - default response time - CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), calendarEvent->GetEventId(), invitee, guid, 946684800, CalendarInviteStatus(status), CalendarModerationRank(rank), ""); + CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), calendarEvent->GetEventId(), invitee[i], guid, 946684800, CalendarInviteStatus(status[i]), CalendarModerationRank(rank[i]), ""); sCalendarMgr->AddInvite(calendarEvent, invite, trans); } diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index d4af17ca78b..9ad382b4686 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -696,10 +696,15 @@ void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData) { uint64 guid; recvData >> guid; + // Initiating + uint32 initAccountId = GetAccountId(); // can't delete loaded character if (ObjectAccessor::FindPlayer(guid)) + { + sScriptMgr->OnPlayerFailedDelete(guid, initAccountId); return; + } uint32 accountId = 0; uint8 level = 0; @@ -708,6 +713,7 @@ void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData) // is guild leader if (sGuildMgr->GetGuildByLeader(guid)) { + sScriptMgr->OnPlayerFailedDelete(guid, initAccountId); WorldPacket data(SMSG_CHAR_DELETE, 1); data << uint8(CHAR_DELETE_FAILED_GUILD_LEADER); SendPacket(&data); @@ -717,6 +723,7 @@ void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData) // is arena team captain if (sArenaTeamMgr->GetArenaTeamByCaptain(guid)) { + sScriptMgr->OnPlayerFailedDelete(guid, initAccountId); WorldPacket data(SMSG_CHAR_DELETE, 1); data << uint8(CHAR_DELETE_FAILED_ARENA_CAPTAIN); SendPacket(&data); @@ -735,12 +742,18 @@ void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData) } // prevent deleting other players' characters using cheating tools - if (accountId != GetAccountId()) + if (accountId != initAccountId) + { + sScriptMgr->OnPlayerFailedDelete(guid, initAccountId); return; + } std::string IP_str = GetRemoteAddress(); TC_LOG_INFO("entities.player.character", "Account: %d, IP: %s deleted character: %s, GUID: %u, Level: %u", accountId, IP_str.c_str(), name.c_str(), GUID_LOPART(guid), level); - sScriptMgr->OnPlayerDelete(guid); + + // To prevent hook failure, place hook before removing reference from DB + sScriptMgr->OnPlayerDelete(guid, initAccountId); // To prevent race conditioning, but as it also makes sense, we hand the accountId over for successful delete. + // Shouldn't interfere with character deletion though if (sLog->ShouldLog("entities.player.dump", LOG_LEVEL_INFO)) // optimize GetPlayerDump call { @@ -1001,7 +1014,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) SendNotification(LANG_RESET_TALENTS); } - if (pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST)) + bool firstLogin = pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST); + if (firstLogin) pCurrChar->RemoveAtLoginFlag(AT_LOGIN_FIRST); // show time before shutdown if shutdown planned. @@ -1026,7 +1040,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) // Handle Login-Achievements (should be handled after loading) _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN, 1); - sScriptMgr->OnPlayerLogin(pCurrChar); + sScriptMgr->OnPlayerLogin(pCurrChar, firstLogin); + delete holder; } diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 3ef99cc2fc1..60966ace011 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -1443,6 +1443,10 @@ void WorldSession::HandleItemRefund(WorldPacket &recvData) return; } + // Don't try to refund item currently being disenchanted + if (_player->GetLootGUID() == guid) + return; + GetPlayer()->RefundItem(item); } diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index f92c6e08e31..b9c6f349ac3 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -81,7 +81,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData) { Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); - bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); + bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING); if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) { @@ -148,7 +148,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/) case HIGHGUID_VEHICLE: { Creature* creature = player->GetMap()->GetCreature(guid); - bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); + bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING); if (lootAllowed && creature->IsWithinDistInMap(player, INTERACTION_DISTANCE)) { loot = &creature->loot; @@ -338,7 +338,8 @@ void WorldSession::DoLootRelease(uint64 lguid) } else { - if (pItem->loot.isLooted()) // Only delete item if no loot or money (unlooted loot is saved to db) + // Only delete item if no loot or money (unlooted loot is saved to db) or if it isn't an openable item + if (pItem->loot.isLooted() || !(proto->Flags & ITEM_PROTO_FLAG_OPENABLE)) player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); } return; // item can be looted only single player @@ -347,18 +348,19 @@ void WorldSession::DoLootRelease(uint64 lguid) { Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); - bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); + bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING); if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) return; loot = &creature->loot; if (loot->isLooted()) { + creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + // skip pickpocketing loot for speed, skinning timer reduction is no-op in fact if (!creature->IsAlive()) creature->AllLootRemovedFromCorpse(); - creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); loot->clear(); } else diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index 10ef7810d1d..326d198903e 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -131,6 +131,13 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) uint32 reqmoney = cost + money; + // Check for overflow + if (reqmoney < money) + { + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); + return; + } + if (!player->HasEnoughMoney(reqmoney) && !player->IsGameMaster()) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index cef414163bd..6fedc481a14 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -285,7 +285,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) } /* handle special cases */ - if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) + if (movementInfo.HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT)) { // transports size limited // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) @@ -308,27 +308,15 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) if (!plrMover->GetTransport()) { if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid)) - { - plrMover->m_transport = transport; transport->AddPassenger(plrMover); - } } else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid) { - bool foundNewTransport = false; - plrMover->m_transport->RemovePassenger(plrMover); + plrMover->GetTransport()->RemovePassenger(plrMover); if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid)) - { - foundNewTransport = true; - plrMover->m_transport = transport; transport->AddPassenger(plrMover); - } - - if (!foundNewTransport) - { - plrMover->m_transport = NULL; + else movementInfo.transport.Reset(); - } } } @@ -336,13 +324,12 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) { GameObject* go = mover->GetMap()->GetGameObject(movementInfo.transport.guid); if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) - movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; + movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); } } else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave { - plrMover->m_transport->RemovePassenger(plrMover); - plrMover->m_transport = NULL; + plrMover->GetTransport()->RemovePassenger(plrMover); movementInfo.transport.Reset(); } diff --git a/src/server/game/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp index f90dfef2684..8a94753b692 100644 --- a/src/server/game/Handlers/SkillHandler.cpp +++ b/src/server/game/Handlers/SkillHandler.cpp @@ -98,7 +98,8 @@ void WorldSession::HandleUnlearnSkillOpcode(WorldPacket& recvData) uint32 skillId; recvData >> skillId; - if (!IsPrimaryProfessionSkill(skillId)) + SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skillId, GetPlayer()->getRace(), GetPlayer()->getClass()); + if (!rcEntry || !(rcEntry->Flags & SKILL_FLAG_UNLEARNABLE)) return; GetPlayer()->SetSkill(skillId, 0, 0, 0); diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index ed0f3b9717b..cb3b9082c20 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -76,6 +76,8 @@ enum PermissionTypes enum LootType { + LOOT_NONE = 0, + LOOT_CORPSE = 1, LOOT_PICKPOCKETING = 2, LOOT_FISHING = 3, @@ -86,7 +88,8 @@ enum LootType LOOT_MILLING = 8, LOOT_FISHINGHOLE = 20, // unsupported by client, sending LOOT_FISHING instead - LOOT_INSIGNIA = 21 // unsupported by client, sending LOOT_CORPSE instead + LOOT_INSIGNIA = 21, // unsupported by client, sending LOOT_CORPSE instead + LOOT_FISHING_JUNK = 22 // unsupported by client, sending LOOT_FISHING instead }; // type of Loot Item in Loot View @@ -340,6 +343,7 @@ struct Loot gold = 0; unlootedCount = 0; roundRobinPlayer = 0; + loot_type = LOOT_NONE; i_LootValidatorRefManager.clearReferences(); } diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index d3be33cb441..01e3af149dc 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2506,15 +2506,9 @@ void Map::SendInitSelf(Player* player) // build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map if (Transport* transport = player->GetTransport()) - { - for (std::set<WorldObject*>::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr) - { + for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr) if (player != (*itr) && player->HaveAtClient(*itr)) - { (*itr)->BuildCreateUpdateBlockForPlayer(&data, player); - } - } - } WorldPacket packet; data.BuildPacket(&packet); diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 34871085157..3a680e30217 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1224,7 +1224,8 @@ enum TrinityStrings LANG_BAN_ACCOUNT_YOUBANNEDMESSAGE_WORLD = 11006, LANG_BAN_ACCOUNT_YOUPERMBANNEDMESSAGE_WORLD = 11007, - LANG_NPCINFO_INHABIT_TYPE = 11008 + LANG_NPCINFO_INHABIT_TYPE = 11008, + LANG_NPCINFO_FLAGS_EXTRA = 11009 // NOT RESERVED IDS 12000-1999999999 // `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID) diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 4ec1d5750a4..77bc76c6dfd 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -41,7 +41,8 @@ enum LootModes LOOT_MODE_HARD_MODE_1 = 0x2, LOOT_MODE_HARD_MODE_2 = 0x4, LOOT_MODE_HARD_MODE_3 = 0x8, - LOOT_MODE_HARD_MODE_4 = 0x10 + LOOT_MODE_HARD_MODE_4 = 0x10, + LOOT_MODE_JUNK_FISH = 0x8000 }; enum Expansions @@ -396,7 +397,7 @@ enum SpellAttr3 SPELL_ATTR3_MAIN_HAND = 0x00000400, // 10 Main hand weapon required SPELL_ATTR3_BATTLEGROUND = 0x00000800, // 11 Can only be cast in battleground SPELL_ATTR3_ONLY_TARGET_GHOSTS = 0x00001000, // 12 - SPELL_ATTR3_UNK13 = 0x00002000, // 13 + SPELL_ATTR3_DONT_DISPLAY_CHANNEL_BAR = 0x00002000, // 13 Clientside attribute - will not display channeling bar SPELL_ATTR3_IS_HONORLESS_TARGET = 0x00004000, // 14 "Honorless Target" only this spells have this flag SPELL_ATTR3_UNK15 = 0x00008000, // 15 Auto Shoot, Shoot, Throw, - this is autoshot flag SPELL_ATTR3_CANT_TRIGGER_PROC = 0x00010000, // 16 confirmed with many patchnotes @@ -543,7 +544,7 @@ enum SpellAttr7 SPELL_ATTR7_UNK13 = 0x00002000, // 13 Not set in 3.2.2a. SPELL_ATTR7_UNK14 = 0x00004000, // 14 Only 52150 (Raise Dead - Pet) spell. SPELL_ATTR7_UNK15 = 0x00008000, // 15 Exorcism. Usable on players? 100% crit chance on undead and demons? - SPELL_ATTR7_UNK16 = 0x00010000, // 16 Druid spells (29166, 54833, 64372, 68285). + SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER = 0x00010000, // 16 These spells can replenish a powertype, which is not the current powertype. SPELL_ATTR7_UNK17 = 0x00020000, // 17 Only 27965 (Suicide) spell. SPELL_ATTR7_HAS_CHARGE_EFFECT = 0x00040000, // 18 Only spells that have Charge among effects. SPELL_ATTR7_ZONE_TELEPORT = 0x00080000, // 19 Teleports to specific zones. @@ -2594,7 +2595,7 @@ enum CreatureTypeFlags CREATURE_TYPEFLAGS_EXOTIC = 0x00010000, // Can be tamed by hunter as exotic pet CREATURE_TYPEFLAGS_UNK17 = 0x00020000, // ? Related to vehicles/pvp? CREATURE_TYPEFLAGS_UNK18 = 0x00040000, // ? Related to vehicle/siege weapons? - CREATURE_TYPEFLAGS_UNK19 = 0x00080000, + CREATURE_TYPEFLAGS_PROJECTILE_COLLISION = 0x00080000, // Projectiles can collide with this creature - interacts with TARGET_DEST_TRAJ CREATURE_TYPEFLAGS_UNK20 = 0x00100000, CREATURE_TYPEFLAGS_UNK21 = 0x00200000, CREATURE_TYPEFLAGS_UNK22 = 0x00400000, diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index c181750a414..246d4682739 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -191,6 +191,10 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 di } else { + // Set home position at place on waypoint movement. + if (!creature->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) || !creature->GetTransGUID()) + creature->SetHomePosition(creature->GetPosition()); + if (creature->IsStopped()) Stop(STOP_TIME_FOR_PLAYER); else if (creature->movespline->Finalized()) diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 7365d592a62..f1359b70aa6 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -16,6 +16,7 @@ */ #include "ScriptLoader.h" +#include "World.h" //examples void AddSC_example_creature(); @@ -41,7 +42,7 @@ void AddSC_item_spell_scripts(); void AddSC_example_spell_scripts(); void AddSC_holiday_spell_scripts(); -void AddSC_SmartSCripts(); +void AddSC_SmartScripts(); //Commands void AddSC_account_commandscript(); @@ -97,6 +98,7 @@ void AddSC_npc_innkeeper(); void AddSC_npcs_special(); void AddSC_npc_taxi(); void AddSC_achievement_scripts(); +void AddSC_action_ip_logger(); //eastern kingdoms void AddSC_alterac_valley(); //Alterac Valley @@ -469,7 +471,6 @@ void AddSC_boss_xt002(); void AddSC_boss_kologarn(); void AddSC_boss_assembly_of_iron(); void AddSC_boss_general_vezax(); -void AddSC_ulduar_teleporter(); void AddSC_boss_mimiron(); void AddSC_boss_hodir(); void AddSC_boss_freya(); @@ -696,6 +697,7 @@ void AddSC_outdoorpvp_zm(); // player void AddSC_chat_log(); +void AddSC_action_ip_logger(); #endif @@ -703,7 +705,7 @@ void AddScripts() { AddExampleScripts(); AddSpellScripts(); - AddSC_SmartSCripts(); + AddSC_SmartScripts(); AddCommandScripts(); #ifdef SCRIPTS AddWorldScripts(); @@ -804,7 +806,10 @@ void AddWorldScripts() AddSC_npcs_special(); AddSC_npc_taxi(); AddSC_achievement_scripts(); - AddSC_chat_log(); + AddSC_chat_log(); // location: scripts\World\chat_log.cpp + // To avoid duplicate code, we check once /*ONLY*/ if logging is permitted or not. + if (sWorld->getBoolConfig(CONFIG_IP_BASED_ACTION_LOGGING)) + AddSC_action_ip_logger(); // location: scripts\World\action_ip_logger.cpp #endif } @@ -1309,7 +1314,6 @@ void AddNorthrendScripts() AddSC_boss_general_vezax(); AddSC_boss_assembly_of_iron(); AddSC_boss_kologarn(); - AddSC_ulduar_teleporter(); AddSC_boss_mimiron(); AddSC_boss_hodir(); AddSC_boss_freya(); diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 94cf1047dfb..83f401d4e79 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -224,6 +224,7 @@ void ScriptMgr::Unload() SCR_CLEAR(TransportScript); SCR_CLEAR(AchievementCriteriaScript); SCR_CLEAR(PlayerScript); + SCR_CLEAR(AccountScript); SCR_CLEAR(GuildScript); SCR_CLEAR(GroupScript); SCR_CLEAR(UnitScript); @@ -1242,9 +1243,9 @@ void ScriptMgr::OnPlayerSpellCast(Player* player, Spell* spell, bool skipCheck) FOREACH_SCRIPT(PlayerScript)->OnSpellCast(player, spell, skipCheck); } -void ScriptMgr::OnPlayerLogin(Player* player) +void ScriptMgr::OnPlayerLogin(Player* player, bool firstLogin) { - FOREACH_SCRIPT(PlayerScript)->OnLogin(player); + FOREACH_SCRIPT(PlayerScript)->OnLogin(player, firstLogin); } void ScriptMgr::OnPlayerLogout(Player* player) @@ -1257,9 +1258,14 @@ void ScriptMgr::OnPlayerCreate(Player* player) FOREACH_SCRIPT(PlayerScript)->OnCreate(player); } -void ScriptMgr::OnPlayerDelete(uint64 guid) +void ScriptMgr::OnPlayerDelete(uint64 guid, uint32 accountId) { - FOREACH_SCRIPT(PlayerScript)->OnDelete(guid); + FOREACH_SCRIPT(PlayerScript)->OnDelete(guid, accountId); +} + +void ScriptMgr::OnPlayerFailedDelete(uint64 guid, uint32 accountId) +{ + FOREACH_SCRIPT(PlayerScript)->OnFailedDelete(guid, accountId); } void ScriptMgr::OnPlayerSave(Player* player) @@ -1277,6 +1283,37 @@ void ScriptMgr::OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newAre FOREACH_SCRIPT(PlayerScript)->OnUpdateZone(player, newZone, newArea); } +// Account +void ScriptMgr::OnAccountLogin(uint32 accountId) +{ + FOREACH_SCRIPT(AccountScript)->OnAccountLogin(accountId); +} + +void ScriptMgr::OnFailedAccountLogin(uint32 accountId) +{ + FOREACH_SCRIPT(AccountScript)->OnFailedAccountLogin(accountId); +} + +void ScriptMgr::OnEmailChange(uint32 accountId) +{ + FOREACH_SCRIPT(AccountScript)->OnEmailChange(accountId); +} + +void ScriptMgr::OnFailedEmailChange(uint32 accountId) +{ + FOREACH_SCRIPT(AccountScript)->OnFailedEmailChange(accountId); +} + +void ScriptMgr::OnPasswordChange(uint32 accountId) +{ + FOREACH_SCRIPT(AccountScript)->OnPasswordChange(accountId); +} + +void ScriptMgr::OnFailedPasswordChange(uint32 accountId) +{ + FOREACH_SCRIPT(AccountScript)->OnFailedPasswordChange(accountId); +} + // Guild void ScriptMgr::OnGuildAddMember(Guild* guild, Player* player, uint8& plRank) { @@ -1539,6 +1576,12 @@ PlayerScript::PlayerScript(const char* name) ScriptRegistry<PlayerScript>::AddScript(this); } +AccountScript::AccountScript(const char* name) + : ScriptObject(name) +{ + ScriptRegistry<AccountScript>::AddScript(this); +} + GuildScript::GuildScript(const char* name) : ScriptObject(name) { @@ -1581,6 +1624,7 @@ template class ScriptRegistry<PlayerScript>; template class ScriptRegistry<GuildScript>; template class ScriptRegistry<GroupScript>; template class ScriptRegistry<UnitScript>; +template class ScriptRegistry<AccountScript>; // Undefine utility macros. #undef GET_SCRIPT_RET diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index bc84192eca9..ee95759c72e 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -29,6 +29,7 @@ #include "World.h" #include "Weather.h" +class AccountMgr; class AuctionHouseObject; class AuraScript; class Battleground; @@ -744,7 +745,7 @@ class PlayerScript : public UnitScript virtual void OnSpellCast(Player* /*player*/, Spell* /*spell*/, bool /*skipCheck*/) { } // Called when a player logs in. - virtual void OnLogin(Player* /*player*/) { } + virtual void OnLogin(Player* /*player*/, bool /*firstLogin*/) { } // Called when a player logs out. virtual void OnLogout(Player* /*player*/) { } @@ -753,7 +754,10 @@ class PlayerScript : public UnitScript virtual void OnCreate(Player* /*player*/) { } // Called when a player is deleted. - virtual void OnDelete(uint64 /*guid*/) { } + virtual void OnDelete(uint64 /*guid*/, uint32 /*accountId*/) { } + + // Called when a player delete failed + virtual void OnFailedDelete(uint64 /*guid*/, uint32 /*accountId*/) { } // Called when a player is about to be saved. virtual void OnSave(Player* /*player*/) { } @@ -768,6 +772,33 @@ class PlayerScript : public UnitScript virtual void OnMapChanged(Player* /*player*/) { } }; +class AccountScript : public ScriptObject +{ + protected: + + AccountScript(const char* name); + + public: + + // Called when an account logged in succesfully + virtual void OnAccountLogin(uint32 /*accountId*/) {} + + // Called when an account login failed + virtual void OnFailedAccountLogin(uint32 /*accountId*/) {} + + // Called when Email is successfully changed for Account + virtual void OnEmailChange(uint32 /*accountId*/) {} + + // Called when Email failed to change for Account + virtual void OnFailedEmailChange(uint32 /*accountId*/) {} + + // Called when Password is successfully changed for Account + virtual void OnPasswordChange(uint32 /*accountId*/) {} + + // Called when Password failed to change for Account + virtual void OnFailedPasswordChange(uint32 /*accountId*/) {} +}; + class GuildScript : public ScriptObject { protected: @@ -1034,14 +1065,24 @@ class ScriptMgr void OnPlayerEmote(Player* player, uint32 emote); void OnPlayerTextEmote(Player* player, uint32 textEmote, uint32 emoteNum, uint64 guid); void OnPlayerSpellCast(Player* player, Spell* spell, bool skipCheck); - void OnPlayerLogin(Player* player); + void OnPlayerLogin(Player* player, bool firstLogin); void OnPlayerLogout(Player* player); void OnPlayerCreate(Player* player); - void OnPlayerDelete(uint64 guid); + void OnPlayerDelete(uint64 guid, uint32 accountId); + void OnPlayerFailedDelete(uint64 guid, uint32 accountId); void OnPlayerSave(Player* player); void OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent); void OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newArea); + public: /* AccountScript */ + + void OnAccountLogin(uint32 accountId); + void OnFailedAccountLogin(uint32 accountId); + void OnEmailChange(uint32 accountId); + void OnFailedEmailChange(uint32 accountId); + void OnPasswordChange(uint32 accountId); + void OnFailedPasswordChange(uint32 accountId); + public: /* GuildScript */ void OnGuildAddMember(Guild* guild, Player* player, uint8& plRank); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 3ac31da3eb1..9f8b3785e92 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -1260,15 +1260,13 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co } // Check if player is flooding some packets - if (++packetCounter.amountCounter > maxPacketCounterAllowed) - { - TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, Ping: %u, Character: %s, flooding packet (opc: %s (0x%X), count: %u)", - Session->GetAccountId(), Session->GetRemoteAddress().c_str(), Session->GetLatency(), Session->GetPlayerName().c_str(), - opcodeTable[p.GetOpcode()].name, p.GetOpcode(), packetCounter.amountCounter); - } - + if (++packetCounter.amountCounter <= maxPacketCounterAllowed) return true; + TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, Ping: %u, Character: %s, flooding packet (opc: %s (0x%X), count: %u)", + Session->GetAccountId(), Session->GetRemoteAddress().c_str(), Session->GetLatency(), Session->GetPlayerName().c_str(), + opcodeTable[p.GetOpcode()].name, p.GetOpcode(), packetCounter.amountCounter); + switch (_policy) { case POLICY_LOG: diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 61d2fa6d106..c8c81a415e1 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -444,7 +444,6 @@ class WorldSession void HandleForceSpeedChangeAck(WorldPacket& recvData); void HandlePingOpcode(WorldPacket& recvPacket); - void HandleAuthSessionOpcode(WorldPacket& recvPacket); void HandleRepopRequestOpcode(WorldPacket& recvPacket); void HandleAutostoreLootItemOpcode(WorldPacket& recvPacket); void HandleLootMoneyOpcode(WorldPacket& recvPacket); @@ -979,10 +978,11 @@ class WorldSession // characters who failed on Player::BuildEnumData shouldn't login std::set<uint32> _legitCharacters; - uint32 m_GUIDLow; // set loggined or recently logout player (while m_playerRecentlyLogout set) + uint32 m_GUIDLow; // set logined or recently logout player (while m_playerRecentlyLogout set) Player* _player; WorldSocket* m_Socket; - std::string m_Address; + std::string m_Address; // Current Remote Address + // std::string m_LAddress; // Last Attempted Remote Adress - we can not set attempted ip for a non-existing session! AccountTypes _security; uint32 _accountId; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 605b863bfa1..d35ee80099d 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -263,7 +263,7 @@ int WorldSocket::open (void *a) return 0; } -int WorldSocket::close (u_long) +int WorldSocket::close(u_long) { shutdown(); @@ -274,7 +274,7 @@ int WorldSocket::close (u_long) return 0; } -int WorldSocket::handle_input (ACE_HANDLE) +int WorldSocket::handle_input(ACE_HANDLE) { if (closing_) return -1; @@ -310,7 +310,7 @@ int WorldSocket::handle_input (ACE_HANDLE) ACE_NOTREACHED(return -1); } -int WorldSocket::handle_output (ACE_HANDLE) +int WorldSocket::handle_output(ACE_HANDLE) { ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); @@ -356,7 +356,7 @@ int WorldSocket::handle_output (ACE_HANDLE) ACE_NOTREACHED (return 0); } -int WorldSocket::handle_output_queue (GuardType& g) +int WorldSocket::handle_output_queue(GuardType& g) { if (msg_queue()->is_empty()) return cancel_wakeup_output(g); @@ -417,7 +417,7 @@ int WorldSocket::handle_output_queue (GuardType& g) ACE_NOTREACHED(return -1); } -int WorldSocket::handle_close (ACE_HANDLE h, ACE_Reactor_Mask) +int WorldSocket::handle_close(ACE_HANDLE h, ACE_Reactor_Mask) { // Critical section { @@ -617,7 +617,7 @@ int WorldSocket::handle_input_missing_data (void) return size_t(n) == recv_size ? 1 : 2; } -int WorldSocket::cancel_wakeup_output (GuardType& g) +int WorldSocket::cancel_wakeup_output(GuardType& g) { if (!m_OutActive) return 0; @@ -637,7 +637,7 @@ int WorldSocket::cancel_wakeup_output (GuardType& g) return 0; } -int WorldSocket::schedule_wakeup_output (GuardType& g) +int WorldSocket::schedule_wakeup_output(GuardType& g) { if (m_OutActive) return 0; @@ -758,6 +758,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) uint64 unk4; WorldPacket packet, SendAddonPacked; BigNumber k; + bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED); if (sWorld->IsClosed()) { @@ -795,6 +796,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // Stop if the account is not found if (!result) { + // We can not log here, as we do not know the account. Thus, no accountId. SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); return -1; @@ -807,19 +809,34 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) if (expansion > world_expansion) expansion = world_expansion; + // For hook purposes, we get Remoteaddress at this point. + std::string address = GetRemoteAddress(); + + // As we don't know if attempted login process by ip works, we update last_attempt_ip right away + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP); + + stmt->setString(0, address); + stmt->setString(1, account); + + LoginDatabase.Execute(stmt); + // This also allows to check for possible "hack" attempts on account + + // id has to be fetched at this point, so that first actual account response that fails can be logged + id = fields[0].GetUInt32(); + ///- Re-check ip locking (same check as in realmd). if (fields[3].GetUInt8() == 1) // if ip is locked { - if (strcmp (fields[2].GetCString(), GetRemoteAddress().c_str())) + if (strcmp (fields[2].GetCString(), address.c_str())) { SendAuthResponseError(AUTH_FAILED); - TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)."); + TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: %s, new IP: %s).", fields[2].GetCString(), address.c_str()); + // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well + sScriptMgr->OnFailedAccountLogin(id); return -1; } } - id = fields[0].GetUInt32(); - k.SetHexStr(fields[1].GetCString()); int64 mutetime = fields[5].GetInt64(); @@ -844,10 +861,10 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) std::string os = fields[8].GetString(); // Must be done before WorldSession is created - if (sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED) && os != "Win" && os != "OSX") + if (wardenActive && os != "Win" && os != "OSX") { SendAuthResponseError(AUTH_REJECT); - TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", GetRemoteAddress().c_str(), os.c_str()); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), os.c_str()); return -1; } @@ -871,7 +888,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BANS); stmt->setUInt32(0, id); - stmt->setString(1, GetRemoteAddress()); + stmt->setString(1, address); PreparedQueryResult banresult = LoginDatabase.Query(stmt); @@ -879,6 +896,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) { SendAuthResponseError(AUTH_BANNED); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); + sScriptMgr->OnFailedAccountLogin(id); return -1; } @@ -889,6 +907,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) { SendAuthResponseError(AUTH_UNAVAILABLE); TC_LOG_INFO("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough"); + sScriptMgr->OnFailedAccountLogin(id); return -1; } @@ -903,8 +922,6 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) sha.UpdateBigNumbers(&k, NULL); sha.Finalize(); - std::string address = GetRemoteAddress(); - if (memcmp(sha.GetDigest(), digest, 20)) { SendAuthResponseError(AUTH_FAILED); @@ -927,8 +944,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) if (result) isRecruiter = true; - // Update the last_ip in the database - + // Update the last_ip in the database as it was successful for login stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP); stmt->setString(0, address); @@ -946,8 +962,11 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) m_Session->ReadAddonsInfo(recvPacket); m_Session->LoadPermissions(); + // At this point, we can safely hook a successful login + sScriptMgr->OnAccountLogin(id); + // Initialize Warden system only if it is enabled by config - if (sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED)) + if (wardenActive) m_Session->InitWarden(&k, os); // Sleep this Network thread for @@ -958,7 +977,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) return 0; } -int WorldSocket::HandlePing (WorldPacket& recvPacket) +int WorldSocket::HandlePing(WorldPacket& recvPacket) { uint32 ping; uint32 latency; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index a0883c895d3..152dc903825 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -379,8 +379,9 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= AuraEffect::AuraEffect(Aura* base, uint8 effIndex, int32 *baseAmount, Unit* caster): m_base(base), m_spellInfo(base->GetSpellInfo()), m_baseAmount(baseAmount ? *baseAmount : m_spellInfo->Effects[effIndex].BasePoints), +m_damage(0), m_critChance(0.0f), m_donePct(1.0f), m_spellmod(NULL), m_periodicTimer(0), m_tickNumber(0), m_effIndex(effIndex), -m_canBeRecalculated(true), m_damage(0), m_critChance(0.0f), m_donePct(1.0f), m_isPeriodic(false) +m_canBeRecalculated(true), m_isPeriodic(false) { CalculatePeriodic(caster, true, false); @@ -3493,11 +3494,23 @@ void AuraEffect::HandleModResistancePercent(AuraApplication const* aurApp, uint8 return; Unit* target = aurApp->GetTarget(); + int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_RESISTANCE_PCT); + if (abs(spellGroupVal) >= abs(GetAmount())) + return; for (int8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) { if (GetMiscValue() & int32(1<<i)) { + if (spellGroupVal) + { + target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, (float)spellGroupVal, !apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) + { + target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), true, (float)spellGroupVal, !apply); + target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), false, (float)spellGroupVal, !apply); + } + } target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(GetAmount()), apply); if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) { @@ -3557,19 +3570,29 @@ void AuraEffect::HandleAuraModStat(AuraApplication const* aurApp, uint8 mode, bo if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; - Unit* target = aurApp->GetTarget(); - if (GetMiscValue() < -2 || GetMiscValue() > 4) { TC_LOG_ERROR("spells", "WARNING: Spell %u effect %u has an unsupported misc value (%i) for SPELL_AURA_MOD_STAT ", GetId(), GetEffIndex(), GetMiscValue()); return; } + Unit* target = aurApp->GetTarget(); + int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_STAT, true, GetMiscValue()); + if (abs(spellGroupVal) >= abs(GetAmount())) + return; + for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) { // -1 or -2 is all stats (misc < -2 checked in function beginning) if (GetMiscValue() < 0 || GetMiscValue() == i) { + if (spellGroupVal) + { + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(spellGroupVal), !apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) + target->ApplyStatBuffMod(Stats(i), float(spellGroupVal), !apply); + } + //target->ApplyStatMod(Stats(i), m_amount, apply); target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply); if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) @@ -3681,14 +3704,30 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; - Unit* target = aurApp->GetTarget(); - if (GetMiscValue() < -1 || GetMiscValue() > 4) { TC_LOG_ERROR("spells", "WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid"); return; } + Unit* target = aurApp->GetTarget(); + int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, true, -1); + if (abs(spellGroupVal) >= abs(GetAmount())) + return; + + if (spellGroupVal) + { + for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) + { + if (GetMiscValue() == i || GetMiscValue() == -1) // affect the same stats + { + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(spellGroupVal), !apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) + target->ApplyStatPercentBuffMod(Stats(i), float(spellGroupVal), !apply); + } + } + } + // save current health state float healthPct = target->GetHealthPct(); bool alive = target->IsAlive(); @@ -3697,6 +3736,17 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 { if (GetMiscValue() == i || GetMiscValue() == -1) { + int32 spellGroupVal2 = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, true, i); + if (abs(spellGroupVal2) >= abs(GetAmount())) + continue; + + if (spellGroupVal2) + { + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(spellGroupVal2), !apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) + target->ApplyStatPercentBuffMod(Stats(i), float(spellGroupVal2), !apply); + } + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(GetAmount()), apply); if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) target->ApplyStatPercentBuffMod(Stats(i), float(GetAmount()), apply); @@ -4095,7 +4145,17 @@ void AuraEffect::HandleModCombatSpeedPct(AuraApplication const* aurApp, uint8 mo return; Unit* target = aurApp->GetTarget(); + int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MELEE_SLOW); + if (abs(spellGroupVal) >= abs(GetAmount())) + return; + if (spellGroupVal) + { + target->ApplyCastTimePercentMod(float(spellGroupVal), !apply); + target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply); + target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply); + target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(spellGroupVal), !apply); + } target->ApplyCastTimePercentMod(float(m_amount), apply); target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply); target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply); @@ -4119,7 +4179,15 @@ void AuraEffect::HandleModMeleeSpeedPct(AuraApplication const* aurApp, uint8 mod return; Unit* target = aurApp->GetTarget(); + int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_MELEE_HASTE); + if (abs(spellGroupVal) >= abs(GetAmount())) + return; + if (spellGroupVal) + { + target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply); + target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply); + } target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply); target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply); } @@ -4356,7 +4424,8 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 return; Unit* target = aurApp->GetTarget(); - if (!target) + int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + if (abs(spellGroupVal) >= abs(GetAmount())) return; if (target->GetTypeId() == TYPEID_PLAYER) @@ -4368,12 +4437,23 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) && (GetSpellInfo()->EquippedItemClass == -1 || target->GetTypeId() != TYPEID_PLAYER)) { + if (spellGroupVal) + { + target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(spellGroupVal), !apply); + target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(spellGroupVal), !apply); + target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(spellGroupVal), !apply); + } target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(GetAmount()), apply); target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply); target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(GetAmount()), apply); - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float (GetAmount()), apply); + if (Player* player = target->ToPlayer()) + { + if (spellGroupVal) + player->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float(spellGroupVal), !apply); + + player->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float(GetAmount()), apply); + } } else { @@ -4520,28 +4600,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool // AT APPLY if (apply) { - // Overpower - if (caster && m_spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && - m_spellInfo->SpellFamilyFlags[0] & 0x4) - { - // In addition, if you strike a player.. - if (target->GetTypeId() != TYPEID_PLAYER) - return; - // ..while they are casting - if (target->IsNonMeleeSpellCast(false, false, true, false, true)) - if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARRIOR, 2775, 0)) - switch (aurEff->GetId()) - { - // Unrelenting Assault, rank 1 - case 46859: - target->CastSpell(target, 64849, true, NULL, aurEff); - break; - // Unrelenting Assault, rank 2 - case 46860: - target->CastSpell(target, 64850, true, NULL, aurEff); - break; - } - } switch (GetId()) { case 1515: // Tame beast @@ -6242,6 +6300,9 @@ void AuraEffect::HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) cons { Powers powerType = Powers(GetMiscValue()); + if (target->GetTypeId() == TYPEID_PLAYER && target->getPowerType() != powerType && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER)) + return; + if (!target->IsAlive() || !target->GetMaxPower(powerType)) return; diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 683059b8e99..75dbd457b91 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -539,6 +539,9 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) || !CanBeAppliedOn(itr->first)) addUnit = false; + if (addUnit && !itr->first->IsHighestExclusiveAura(this, true)) + addUnit = false; + if (addUnit) { // persistent area aura does not hit flying targets @@ -691,21 +694,12 @@ void Aura::Update(uint32 diff, Unit* caster) if (int32(caster->GetHealth()) > manaPerSecond) caster->ModifyHealth(-manaPerSecond); else - { Remove(); - return; - } } + else if (int32(caster->GetPower(powertype)) >= manaPerSecond) + caster->ModifyPower(powertype, -manaPerSecond); else - { - if (int32(caster->GetPower(powertype)) >= manaPerSecond) - caster->ModifyPower(powertype, -manaPerSecond); - else - { - Remove(); - return; - } - } + Remove(); } } } @@ -731,17 +725,17 @@ int32 Aura::CalcMaxDuration(Unit* caster) const // IsPermanent() checks max duration (which we are supposed to calculate here) if (maxDuration != -1 && modOwner) modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, maxDuration); + return maxDuration; } void Aura::SetDuration(int32 duration, bool withMods) { if (withMods) - { if (Unit* caster = GetCaster()) if (Player* modOwner = caster->GetSpellModOwner()) modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, duration); - } + m_duration = duration; SetNeedClientUpdateForTargets(); } @@ -779,6 +773,7 @@ void Aura::SetCharges(uint8 charges) { if (m_procCharges == charges) return; + m_procCharges = charges; m_isUsingCharges = m_procCharges != 0; SetNeedClientUpdateForTargets(); @@ -793,6 +788,7 @@ uint8 Aura::CalcMaxCharges(Unit* caster) const if (caster) if (Player* modOwner = caster->GetSpellModOwner()) modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, maxProcCharges); + return maxProcCharges; } @@ -815,6 +811,7 @@ bool Aura::ModCharges(int32 num, AuraRemoveMode removeMode) SetCharges(charges); } + return false; } @@ -883,6 +880,7 @@ bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode) if (SpellModifier* mod = aurEff->GetSpellModifier()) mod->charges = GetCharges(); } + SetNeedClientUpdateForTargets(); return false; } @@ -894,13 +892,22 @@ void Aura::RefreshSpellMods() player->RestoreAllSpellMods(0, this); } +bool Aura::HasMoreThanOneEffectForType(AuraType auraType) const +{ + uint32 count = 0; + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (HasEffect(i) && AuraType(GetSpellInfo()->Effects[i].ApplyAuraName) == auraType) + ++count; + + return count > 1; +} + bool Aura::IsArea() const { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { if (HasEffect(i) && GetSpellInfo()->Effects[i].IsAreaAuraEffect()) return true; - } + return false; } @@ -1699,7 +1706,7 @@ void Aura::HandleAuraSpecificPeriodics(AuraApplication const* aurApp, Unit* cast break; } default: - break; + break; } } } @@ -1758,13 +1765,19 @@ bool Aura::CanStackWith(Aura const* existingAura) const return false; // check spell group stack rules - SpellGroupStackRule stackRule = sSpellMgr->CheckSpellGroupStackRules(m_spellInfo, existingSpellInfo); - if (stackRule) + switch (sSpellMgr->CheckSpellGroupStackRules(m_spellInfo, existingSpellInfo)) { - if (stackRule == SPELL_GROUP_STACK_RULE_EXCLUSIVE) - return false; - if (sameCaster && stackRule == SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER) + case SPELL_GROUP_STACK_RULE_EXCLUSIVE: + case SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST: // if it reaches this point, existing aura is lower/equal return false; + case SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER: + if (sameCaster) + return false; + break; + case SPELL_GROUP_STACK_RULE_DEFAULT: + case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT: + default: + break; } if (m_spellInfo->SpellFamilyName != existingSpellInfo->SpellFamilyName) diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 669d2a529a1..8c426ea2175 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -149,6 +149,7 @@ class Aura uint8 GetCasterLevel() const { return m_casterLevel; } + bool HasMoreThanOneEffectForType(AuraType auraType) const; bool IsArea() const; bool IsPassive() const; bool IsDeathPersistent() const; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index ca170187e82..9086a304e1c 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1514,10 +1514,24 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex) std::list<WorldObject*>::const_iterator itr = targets.begin(); for (; itr != targets.end(); ++itr) { + if (!m_caster->HasInLine(*itr, 5.0f)) + continue; + + if (m_spellInfo->CheckTarget(m_caster, *itr, true) != SPELL_CAST_OK) + continue; + if (Unit* unitTarget = (*itr)->ToUnit()) - if (m_caster == *itr || m_caster->IsOnVehicle(unitTarget) || (unitTarget)->GetVehicle())//(*itr)->IsOnVehicle(m_caster)) + { + if (m_caster == *itr || m_caster->IsOnVehicle(unitTarget) || unitTarget->GetVehicle()) continue; + if (Creature* creatureTarget = unitTarget->ToCreature()) + { + if (!(creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPEFLAGS_PROJECTILE_COLLISION)) + continue; + } + } + const float size = std::max((*itr)->GetObjectSize() * 0.7f, 1.0f); // 1/sqrt(3) /// @todo all calculation should be based on src instead of m_caster const float objDist2d = m_targets.GetSrcPos()->GetExactDist2d(*itr) * std::cos(m_targets.GetSrcPos()->GetRelativeAngle(*itr)); @@ -2607,10 +2621,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA // Haste modifies duration of channeled spells if (m_spellInfo->IsChanneled()) - { - if (m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION) - m_originalCaster->ModSpellCastTime(aurSpellInfo, duration, this); - } + m_originalCaster->ModSpellCastTime(aurSpellInfo, duration, this); // and duration of auras affected by SPELL_AURA_PERIODIC_HASTE else if (m_originalCaster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, aurSpellInfo) || m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION) duration = int32(duration * m_originalCaster->GetFloatValue(UNIT_MOD_CAST_SPEED)); @@ -3234,9 +3245,9 @@ void Spell::handle_immediate() // Apply duration mod if (Player* modOwner = m_caster->GetSpellModOwner()) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); + // Apply haste mods - if (m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION) - m_caster->ModSpellCastTime(m_spellInfo, duration, this); + m_caster->ModSpellCastTime(m_spellInfo, duration, this); m_spellState = SPELL_STATE_CASTING; m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags); @@ -3765,7 +3776,7 @@ void Spell::SendSpellStart() castFlags |= CAST_FLAG_POWER_LEFT_SELF; if (m_spellInfo->RuneCostID && m_spellInfo->PowerType == POWER_RUNE) - castFlags |= CAST_FLAG_UNKNOWN_19; + castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2)); if (m_CastItem) @@ -3821,21 +3832,22 @@ void Spell::SendSpellGo() if ((m_caster->GetTypeId() == TYPEID_PLAYER) && (m_caster->getClass() == CLASS_DEATH_KNIGHT) && m_spellInfo->RuneCostID - && m_spellInfo->PowerType == POWER_RUNE) + && m_spellInfo->PowerType == POWER_RUNE + && !(_triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST)) { - castFlags |= CAST_FLAG_UNKNOWN_19; // same as in SMSG_SPELL_START + castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list } if (m_spellInfo->HasEffect(SPELL_EFFECT_ACTIVATE_RUNE)) - { castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list - castFlags |= CAST_FLAG_UNKNOWN_19; // same as in SMSG_SPELL_START - } if (m_targets.HasTraj()) castFlags |= CAST_FLAG_ADJUST_MISSILE; + if (!m_spellInfo->StartRecoveryTime) + castFlags |= CAST_FLAG_NO_GCD; + WorldPacket data(SMSG_SPELL_GO, 50); // guess size if (m_CastItem) diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 341867ff787..584c20fdfb3 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -57,7 +57,7 @@ enum SpellCastFlags CAST_FLAG_UNKNOWN_16 = 0x00008000, CAST_FLAG_UNKNOWN_17 = 0x00010000, CAST_FLAG_ADJUST_MISSILE = 0x00020000, - CAST_FLAG_UNKNOWN_19 = 0x00040000, + CAST_FLAG_NO_GCD = 0x00040000, // no GCD for spell casts from charm/summon (vehicle spells is an example) CAST_FLAG_VISUAL_CHAIN = 0x00080000, CAST_FLAG_UNKNOWN_21 = 0x00100000, CAST_FLAG_RUNE_LIST = 0x00200000, diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 48c73cf39ca..606851bf8f1 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -836,10 +836,10 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex) { // remove all harmful spells on you... SpellInfo const* spell = iter->second->GetBase()->GetSpellInfo(); - if ((spell->DmgClass == SPELL_DAMAGE_CLASS_MAGIC // only affect magic spells - || ((spell->GetDispelMask()) & dispelMask)) + if (((spell->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && spell->GetSchoolMask() != SPELL_SCHOOL_MASK_NORMAL) // only affect magic spells + || (spell->GetDispelMask() & dispelMask)) && // ignore positive and passive auras - && !iter->second->IsPositive() && !iter->second->GetBase()->IsPassive()) + !iter->second->IsPositive() && !iter->second->GetBase()->IsPassive()) { m_caster->RemoveAura(iter); } @@ -1751,6 +1751,12 @@ void Spell::EffectEnergize(SpellEffIndex effIndex) Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue); + if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER)) + return; + + if (unitTarget->GetMaxPower(power) == 0) + return; + // Some level depends spells int level_multiplier = 0; int level_diff = 0; @@ -1796,9 +1802,6 @@ void Spell::EffectEnergize(SpellEffIndex effIndex) if (damage < 0) return; - if (unitTarget->GetMaxPower(power) == 0) - return; - m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, damage, power); // Mad Alchemist's Potion @@ -1863,6 +1866,9 @@ void Spell::EffectEnergizePct(SpellEffIndex effIndex) Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue); + if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER)) + return; + uint32 maxPower = unitTarget->GetMaxPower(power); if (maxPower == 0) return; @@ -2602,8 +2608,16 @@ void Spell::EffectLearnSkill(SpellEffIndex effIndex) return; uint32 skillid = m_spellInfo->Effects[effIndex].MiscValue; + SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skillid, unitTarget->getRace(), unitTarget->getClass()); + if (!rcEntry) + return; + + SkillTiersEntry const* tier = sSkillTiersStore.LookupEntry(rcEntry->SkillTier); + if (!tier) + return; + uint16 skillval = unitTarget->ToPlayer()->GetPureSkillValue(skillid); - unitTarget->ToPlayer()->SetSkill(skillid, m_spellInfo->Effects[effIndex].CalcValue(), skillval?skillval:1, damage*75); + unitTarget->ToPlayer()->SetSkill(skillid, m_spellInfo->Effects[effIndex].CalcValue(), std::max<uint16>(skillval, 1), tier->MaxSkill[damage - 1]); } void Spell::EffectAddHonor(SpellEffIndex /*effIndex*/) @@ -4049,51 +4063,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) } break; } - case SPELLFAMILY_DEATHKNIGHT: - { - // Pestilence - if (m_spellInfo->SpellFamilyFlags[1]&0x10000) - { - // Get diseases on target of spell - if (m_targets.GetUnitTarget() && // Glyph of Disease - cast on unit target too to refresh aura - (m_targets.GetUnitTarget() != unitTarget || m_caster->HasAura(63334))) - { - // And spread them on target - // Blood Plague - if (m_targets.GetUnitTarget()->HasAura(55078)) - { - AuraEffect* aurEffOld = m_targets.GetUnitTarget()->GetAura(55078)->GetEffect(0); - float donePct = aurEffOld->GetDonePct(); - float critChance = aurEffOld->GetCritChance(); - - m_caster->CastSpell(unitTarget, 55078, true); - - if (unitTarget->HasAura(55078)) - if (AuraEffect* aurEffNew = unitTarget->GetAura(55078)->GetEffect(0)) - { - aurEffNew->SetCritChance(critChance); // Blood Plague can crit if caster has T9. - aurEffNew->SetDonePct(donePct); - aurEffNew->SetDamage(m_caster->SpellDamageBonusDone(unitTarget, aurEffNew->GetSpellInfo(), std::max(aurEffNew->GetAmount(), 0), DOT) * donePct); - } - } - // Frost Fever - if (m_targets.GetUnitTarget()->HasAura(55095)) - { - float donePct = m_targets.GetUnitTarget()->GetAura(55095)->GetEffect(0)->GetDonePct(); - - m_caster->CastSpell(unitTarget, 55095, true); - - if (unitTarget->HasAura(55095)) - if (AuraEffect* aurEffNew = unitTarget->GetAura(55095)->GetEffect(0)) - { - aurEffNew->SetDonePct(donePct); - aurEffNew->SetDamage(m_caster->SpellDamageBonusDone(unitTarget, aurEffNew->GetSpellInfo(), std::max(aurEffNew->GetAmount(), 0), DOT) * donePct); - } - } - } - } - break; - } } // normal DB scripted effect @@ -4743,6 +4712,7 @@ void Spell::EffectSkinning(SpellEffIndex /*effIndex*/) m_caster->ToPlayer()->SendLoot(creature->GetGUID(), LOOT_SKINNING); creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); + creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5; diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index ba4c3deca85..4d97dc97e5b 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1207,10 +1207,8 @@ bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const if (Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) return true; - // these spells (Cyclone for example) can pierce all... - if ((AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) - // ...but not these (Divine shield for example) - && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY))) + // these spells (Cyclone for example) can pierce all... // ...but not these (Divine shield, Ice block, Cyclone and Banish for example) + if ((AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY || aura->Mechanic == MECHANIC_BANISH))) return true; return false; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 75243139fec..e954b9173ad 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -765,6 +765,15 @@ SpellGroupStackRule SpellMgr::CheckSpellGroupStackRules(SpellInfo const* spellIn return rule; } +SpellGroupStackRule SpellMgr::GetSpellGroupStackRule(SpellGroup group) const +{ + SpellGroupStackMap::const_iterator itr = mSpellGroupStack.find(group); + if (itr != mSpellGroupStack.end()) + return itr->second; + + return SPELL_GROUP_STACK_RULE_DEFAULT; +} + SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const { SpellProcEventMap::const_iterator itr = mSpellProcEventMap.find(spellId); diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 7b54aca3759..757bd813613 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -349,14 +349,14 @@ typedef std::pair<SpellGroupSpellMap::const_iterator, SpellGroupSpellMap::const_ enum SpellGroupStackRule { - SPELL_GROUP_STACK_RULE_DEFAULT = 0, - SPELL_GROUP_STACK_RULE_EXCLUSIVE = 1, - SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER = 2, - SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT = 3 + SPELL_GROUP_STACK_RULE_DEFAULT, + SPELL_GROUP_STACK_RULE_EXCLUSIVE, + SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER, + SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT, + SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST, + SPELL_GROUP_STACK_RULE_MAX }; -#define SPELL_GROUP_STACK_RULE_MAX 4 - typedef std::map<SpellGroup, SpellGroupStackRule> SpellGroupStackMap; struct SpellThreatEntry @@ -655,6 +655,7 @@ class SpellMgr // Spell Group Stack Rules table bool AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, int32 amount, std::map<SpellGroup, int32>& groups) const; SpellGroupStackRule CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const; + SpellGroupStackRule GetSpellGroupStackRule(SpellGroup groupid) const; // Spell proc event table SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index e40e2f7e6d1..78470d4e790 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1044,6 +1044,8 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN] = sConfigMgr->GetBoolDefault("OffhandCheckAtSpellUnlearn", true); + m_int_configs[CONFIG_CREATURE_PICKPOCKET_REFILL] = sConfigMgr->GetIntDefault("Creature.PickPocketRefillDelay", 10 * MINUTE); + if (int32 clientCacheId = sConfigMgr->GetIntDefault("ClientCacheVersion", 0)) { // overwrite DB/old value @@ -1253,6 +1255,10 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_BIRTHDAY_TIME] = sConfigMgr->GetIntDefault("BirthdayTime", 1222964635); + m_bool_configs[CONFIG_IP_BASED_ACTION_LOGGING] = sConfigMgr->GetBoolDefault("Allow.IP.Based.Action.Logging", false); + + m_bool_configs[CONFIG_IP_BASED_LOGIN_LOGGING] = sConfigMgr->GetBoolDefault("Wrong.Password.Login.Logging", false); + // call ScriptMgr if we're reloading the configuration if (reload) sScriptMgr->OnConfigLoad(reload); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 9bac3032161..61acdc37b07 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -154,6 +154,8 @@ enum WorldBoolConfigs CONFIG_EVENT_ANNOUNCE, CONFIG_STATS_LIMITS_ENABLE, CONFIG_INSTANCES_RESET_ANNOUNCE, + CONFIG_IP_BASED_ACTION_LOGGING, + CONFIG_IP_BASED_LOGIN_LOGGING, BOOL_CONFIG_VALUE_COUNT }; @@ -331,6 +333,7 @@ enum WorldIntConfigs CONFIG_BG_REWARD_LOSER_HONOR_FIRST, CONFIG_BG_REWARD_LOSER_HONOR_LAST, CONFIG_BIRTHDAY_TIME, + CONFIG_CREATURE_PICKPOCKET_REFILL, INT_CONFIG_VALUE_COUNT }; diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index c1a9435de52..938520209a0 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -47,7 +47,9 @@ message("") include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/SFMT ${CMAKE_SOURCE_DIR}/dep/zlib diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index 3c9714ca55a..1121e4d0a2f 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -377,6 +377,7 @@ public: if (!AccountMgr::CheckEmail(handler->GetSession()->GetAccountId(), std::string(oldEmail))) { handler->SendSysMessage(LANG_COMMAND_WRONGEMAIL); + sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId()); handler->SetSentErrorMessage(true); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change email, but the provided email [%s] is not equal to registration email [%s].", handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), @@ -388,6 +389,7 @@ public: if (!AccountMgr::CheckPassword(handler->GetSession()->GetAccountId(), std::string(password))) { handler->SendSysMessage(LANG_COMMAND_WRONGOLDPASSWORD); + sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId()); handler->SetSentErrorMessage(true); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change email, but the provided password is wrong.", handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), @@ -398,6 +400,7 @@ public: if (strcmp(email, oldEmail) == 0) { handler->SendSysMessage(LANG_OLD_EMAIL_IS_NEW_EMAIL); + sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId()); handler->SetSentErrorMessage(true); return false; } @@ -405,6 +408,7 @@ public: if (strcmp(email, emailConfirmation) != 0) { handler->SendSysMessage(LANG_NEW_EMAILS_NOT_MATCH); + sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId()); handler->SetSentErrorMessage(true); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change email, but the provided password is wrong.", handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), @@ -418,6 +422,7 @@ public: { case AOR_OK: handler->SendSysMessage(LANG_COMMAND_EMAIL); + sScriptMgr->OnEmailChange(handler->GetSession()->GetAccountId()); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Changed Email from [%s] to [%s].", handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow(), @@ -425,6 +430,7 @@ public: break; case AOR_EMAIL_TOO_LONG: handler->SendSysMessage(LANG_EMAIL_TOO_LONG); + sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId()); handler->SetSentErrorMessage(true); return false; default: @@ -469,6 +475,7 @@ public: if (!AccountMgr::CheckPassword(handler->GetSession()->GetAccountId(), std::string(oldPassword))) { handler->SendSysMessage(LANG_COMMAND_WRONGOLDPASSWORD); + sScriptMgr->OnFailedPasswordChange(handler->GetSession()->GetAccountId()); handler->SetSentErrorMessage(true); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change password, but the provided old password is wrong.", handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), @@ -481,6 +488,7 @@ public: && !AccountMgr::CheckEmail(handler->GetSession()->GetAccountId(), std::string(emailConfirmation))) // ... and returns false if the comparison fails. { handler->SendSysMessage(LANG_COMMAND_WRONGEMAIL); + sScriptMgr->OnFailedPasswordChange(handler->GetSession()->GetAccountId()); handler->SetSentErrorMessage(true); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change password, but the entered email [%s] is wrong.", handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), @@ -493,6 +501,7 @@ public: if (strcmp(newPassword, passwordConfirmation) != 0) { handler->SendSysMessage(LANG_NEW_PASSWORDS_NOT_MATCH); + sScriptMgr->OnFailedPasswordChange(handler->GetSession()->GetAccountId()); handler->SetSentErrorMessage(true); return false; } @@ -503,12 +512,14 @@ public: { case AOR_OK: handler->SendSysMessage(LANG_COMMAND_PASSWORD); + sScriptMgr->OnPasswordChange(handler->GetSession()->GetAccountId()); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Changed Password.", handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow()); break; case AOR_PASS_TOO_LONG: handler->SendSysMessage(LANG_PASSWORD_TOO_LONG); + sScriptMgr->OnFailedPasswordChange(handler->GetSession()->GetAccountId()); handler->SetSentErrorMessage(true); return false; default: diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp index 3c1fa973cd8..44ebb1ea4e0 100644 --- a/src/server/scripts/Commands/cs_go.cpp +++ b/src/server/scripts/Commands/cs_go.cpp @@ -29,6 +29,7 @@ EndScriptData */ #include "Chat.h" #include "Language.h" #include "Player.h" +#include "Transport.h" class go_commandscript : public CommandScript { @@ -132,21 +133,24 @@ public: float x = fields[0].GetFloat(); float y = fields[1].GetFloat(); float z = fields[2].GetFloat(); - float ort = fields[3].GetFloat(); - int mapId = fields[4].GetUInt16(); + float o = fields[3].GetFloat(); + uint32 mapId = fields[4].GetUInt16(); uint32 guid = fields[5].GetUInt32(); uint32 id = fields[6].GetUInt32(); - // if creature is in same map with caster go at its current location - if (Creature* creature = sObjectAccessor->GetCreature(*player, MAKE_NEW_GUID(guid, id, HIGHGUID_UNIT))) + Transport* transport = NULL; + + if (Creature* creature = ObjectAccessor::GetObjectInWorld(MAKE_NEW_GUID(guid, id, HIGHGUID_UNIT), (Creature*)NULL)) { x = creature->GetPositionX(); y = creature->GetPositionY(); z = creature->GetPositionZ(); - ort = creature->GetOrientation(); + o = creature->GetOrientation(); + mapId = creature->GetMapId(); + transport = creature->GetTransport(); } - if (!MapManager::IsValidMapCoord(mapId, x, y, z, ort)) + if (!MapManager::IsValidMapCoord(mapId, x, y, z, o) || sObjectMgr->IsTransportMap(mapId)) { handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, x, y, mapId); handler->SetSentErrorMessage(true); @@ -163,7 +167,11 @@ public: else player->SaveRecallPosition(); - player->TeleportTo(mapId, x, y, z, ort); + if (player->TeleportTo(mapId, x, y, z, o)) + { + if (transport) + transport->AddPassenger(player); + } return true; } @@ -274,8 +282,8 @@ public: if (!guid) return false; - float x, y, z, ort; - int mapId; + float x, y, z, o; + uint32 mapId; // by DB guid if (GameObjectData const* goData = sObjectMgr->GetGOData(guid)) @@ -283,7 +291,7 @@ public: x = goData->posX; y = goData->posY; z = goData->posZ; - ort = goData->orientation; + o = goData->orientation; mapId = goData->mapid; } else @@ -293,7 +301,7 @@ public: return false; } - if (!MapManager::IsValidMapCoord(mapId, x, y, z, ort)) + if (!MapManager::IsValidMapCoord(mapId, x, y, z, o) || sObjectMgr->IsTransportMap(mapId)) { handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, x, y, mapId); handler->SetSentErrorMessage(true); @@ -310,7 +318,7 @@ public: else player->SaveRecallPosition(); - player->TeleportTo(mapId, x, y, z, ort); + player->TeleportTo(mapId, x, y, z, o); return true; } diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 28d49fe11aa..9cf8c041883 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -43,6 +43,7 @@ struct EnumName #define CREATE_NAMED_ENUM(VALUE) { VALUE, STRINGIZE(VALUE) } #define NPCFLAG_COUNT 24 +#define FLAGS_EXTRA_COUNT 16 EnumName<NPCFlags, int32> const npcFlagTexts[NPCFLAG_COUNT] = { @@ -144,6 +145,26 @@ EnumName<UnitFlags> const unitFlags[MAX_UNIT_FLAGS] = CREATE_NAMED_ENUM(UNIT_FLAG_UNK_31) }; +EnumName<CreatureFlagsExtra> const flagsExtra[FLAGS_EXTRA_COUNT] = +{ + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_INSTANCE_BIND), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_CIVILIAN), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PARRY), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_BLOCK), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_CRUSH), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_XP_AT_KILL), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TRIGGER), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_TAUNT), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_WORLDEVENT), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_GUARD), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_CRIT), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_SKILLGAIN), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TAUNT_DIMINISH), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_ALL_DIMINISH), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_DUNGEON_BOSS) +}; + class npc_commandscript : public CommandScript { public: @@ -730,6 +751,10 @@ public: handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor()); handler->PSendSysMessage(LANG_NPCINFO_POSITION, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()); handler->PSendSysMessage(LANG_NPCINFO_AIINFO, target->GetAIName().c_str(), target->GetScriptName().c_str()); + handler->PSendSysMessage(LANG_NPCINFO_FLAGS_EXTRA, cInfo->flags_extra); + for (uint8 i = 0; i < FLAGS_EXTRA_COUNT; ++i) + if (cInfo->flags_extra & flagsExtra[i].Value) + handler->PSendSysMessage("%s (0x%X)", flagsExtra[i].Name, flagsExtra[i].Value); for (uint8 i = 0; i < NPCFLAG_COUNT; i++) if (npcflags & npcFlagTexts[i].Value) diff --git a/src/server/scripts/Custom/CMakeLists.txt b/src/server/scripts/Custom/CMakeLists.txt index 78db719ae6e..80ebe36b555 100644 --- a/src/server/scripts/Custom/CMakeLists.txt +++ b/src/server/scripts/Custom/CMakeLists.txt @@ -8,8 +8,11 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# file(GLOB_RECURSE sources_Custom Custom/*.cpp Custom/*.h) + set(scripts_STAT_SRCS ${scripts_STAT_SRCS} +# ${sources_Custom} ) message(" -> Prepared: Custom") diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp index 2a473754ce6..f9757997731 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp @@ -144,7 +144,7 @@ class npc_core_rager : public CreatureScript if (HealthAbovePct(50) || !instance) return; - if (Creature* pGolemagg = instance->instance->GetCreature(instance->GetData64(BOSS_GOLEMAGG_THE_INCINERATOR))) + if (Creature* pGolemagg = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_GOLEMAGG_THE_INCINERATOR))) { if (pGolemagg->IsAlive()) { diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp index 3c4b372808b..7944011c7a0 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp @@ -150,14 +150,14 @@ public: Phase = 0; - instance->SetData(DATA_KAELTHAS_EVENT, NOT_STARTED); + instance->SetBossState(DATA_KAELTHAS, NOT_STARTED); } void JustDied(Unit* /*killer*/) override { Talk(SAY_DEATH); - instance->SetData(DATA_KAELTHAS_EVENT, DONE); + instance->SetBossState(DATA_KAELTHAS, DONE); // Enable the Translocation Orb Exit if (GameObject* escapeOrb = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_ESCAPE_ORB))) @@ -172,7 +172,7 @@ public: void EnterCombat(Unit* /*who*/) override { - instance->SetData(DATA_KAELTHAS_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_KAELTHAS, IN_PROGRESS); } void MoveInLineOfSight(Unit* who) override @@ -515,7 +515,7 @@ public: return; } //Don't really die in all phases of Kael'Thas - if (instance->GetData(DATA_KAELTHAS_EVENT) == 0) + if (instance->GetBossState(DATA_KAELTHAS) == 0) { //prevent death damage = 0; diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp index 8dc8ff799ba..2af9d9b1567 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp @@ -153,7 +153,7 @@ public: //this mean she at some point evaded void JustReachedHome() override { - instance->SetData(DATA_DELRISSA_EVENT, FAIL); + instance->SetBossState(DATA_DELRISSA, FAIL); } void EnterCombat(Unit* who) override @@ -172,7 +172,7 @@ public: } } - instance->SetData(DATA_DELRISSA_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_DELRISSA, IN_PROGRESS); } void InitializeLackeys() @@ -240,7 +240,7 @@ public: Talk(SAY_DEATH); if (instance->GetData(DATA_DELRISSA_DEATH_COUNT) == MAX_ACTIVE_LACKEY) - instance->SetData(DATA_DELRISSA_EVENT, DONE); + instance->SetBossState(DATA_DELRISSA, DONE); else { if (me->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE)) @@ -434,7 +434,7 @@ struct boss_priestess_lackey_commonAI : public ScriptedAI if (!pDelrissa->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE)) pDelrissa->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - instance->SetData(DATA_DELRISSA_EVENT, DONE); + instance->SetBossState(DATA_DELRISSA, DONE); } } } diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp index d77f5db9cea..d6c0f95f967 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp @@ -119,7 +119,7 @@ public: } // Set Inst data for encounter - instance->SetData(DATA_SELIN_EVENT, NOT_STARTED); + instance->SetBossState(DATA_SELIN, NOT_STARTED); DrainLifeTimer = urand(3000, 7000); DrainManaTimer = DrainLifeTimer + 5000; @@ -194,7 +194,7 @@ public: void EnterCombat(Unit* /*who*/) override { Talk(SAY_AGGRO); - instance->SetData(DATA_SELIN_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_SELIN, IN_PROGRESS); } void KilledUnit(Unit* /*victim*/) override @@ -228,7 +228,7 @@ public: { Talk(SAY_DEATH); - instance->SetData(DATA_SELIN_EVENT, DONE); // Encounter complete! + instance->SetBossState(DATA_SELIN, DONE); // Encounter complete! ShatterRemainingCrystals(); } @@ -351,7 +351,7 @@ public: } } } - } else TC_LOG_ERROR("scripts", ERROR_INST_DATA); + } } }; }; diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp index 58b9ef12095..b9930820303 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -16,13 +15,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Vexallus -SD%Complete: 90 -SDComment: Heroic and Normal support. Needs further testing. -SDCategory: Magister's Terrace -EndScriptData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "magisters_terrace.h" @@ -41,26 +33,22 @@ enum Yells enum Spells { - // Pure energy spell info - SPELL_ENERGY_BOLT = 46156, - SPELL_ENERGY_FEEDBACK = 44335, - - // Vexallus spell info SPELL_CHAIN_LIGHTNING = 44318, - SPELL_H_CHAIN_LIGHTNING = 46380, // heroic spell SPELL_OVERLOAD = 44353, SPELL_ARCANE_SHOCK = 44319, - SPELL_H_ARCANE_SHOCK = 46381, // heroic spell SPELL_SUMMON_PURE_ENERGY = 44322, // mod scale -10 H_SPELL_SUMMON_PURE_ENERGY1 = 46154, // mod scale -5 H_SPELL_SUMMON_PURE_ENERGY2 = 46159 // mod scale -5 - }; -enum Creatures +enum Events { - NPC_PURE_ENERGY = 24745, + EVENT_ENERGY_BOLT = 1, + EVENT_ENERGY_FEEDBACK, + EVENT_CHAIN_LIGHTNING, + EVENT_OVERLOAD, + EVENT_ARCANE_SHOCK }; enum Misc @@ -71,170 +59,160 @@ enum Misc class boss_vexallus : public CreatureScript { -public: - boss_vexallus() : CreatureScript("boss_vexallus") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<boss_vexallusAI>(creature); - }; - - struct boss_vexallusAI : public BossAI - { - boss_vexallusAI(Creature* creature) : BossAI(creature, DATA_VEXALLUS_EVENT) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; + public: + boss_vexallus() : CreatureScript("boss_vexallus") { } - uint32 ChainLightningTimer; - uint32 ArcaneShockTimer; - uint32 OverloadTimer; - uint32 IntervalHealthAmount; - bool Enraged; - - void Reset() override + struct boss_vexallusAI : public BossAI { - summons.DespawnAll(); - ChainLightningTimer = 8000; - ArcaneShockTimer = 5000; - OverloadTimer = 1200; - IntervalHealthAmount = 1; - Enraged = false; - - instance->SetData(DATA_VEXALLUS_EVENT, NOT_STARTED); - } + boss_vexallusAI(Creature* creature) : BossAI(creature, DATA_VEXALLUS) + { + _intervalHealthAmount = 1; + _enraged = false; + } - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_KILL); - } + void Reset() override + { + _Reset(); + _intervalHealthAmount = 1; + _enraged = false; + } - void JustDied(Unit* /*killer*/) override - { - summons.DespawnAll(); - instance->SetData(DATA_VEXALLUS_EVENT, DONE); - } + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_KILL); + } - void EnterCombat(Unit* /*who*/) override - { - Talk(SAY_AGGRO); + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + } - instance->SetData(DATA_VEXALLUS_EVENT, IN_PROGRESS); - } + void EnterCombat(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + _EnterCombat(); - void JustSummoned(Creature* summoned) override - { - if (Unit* temp = SelectTarget(SELECT_TARGET_RANDOM, 0)) - summoned->GetMotionMaster()->MoveFollow(temp, 0, 0); + events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 8000); + events.ScheduleEvent(EVENT_ARCANE_SHOCK, 5000); + } - //spells are SUMMON_TYPE_GUARDIAN, so using setOwner should be ok - summoned->CastSpell(summoned, SPELL_ENERGY_BOLT, false, 0, 0, me->GetGUID()); - } + void JustSummoned(Creature* summoned) override + { + if (Unit* temp = SelectTarget(SELECT_TARGET_RANDOM, 0)) + summoned->GetMotionMaster()->MoveFollow(temp, 0, 0); - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + summons.Summon(summoned); + } - if (!Enraged) + void DamageTaken(Unit* /*who*/, uint32& /*damage*/) override { - //used for check, when Vexallus cast adds 85%, 70%, 55%, 40%, 25% - if (!HealthAbovePct(100 - INTERVAL_MODIFIER * IntervalHealthAmount)) + if (_enraged) + return; + + // 85%, 70%, 55%, 40%, 25% + if (!HealthAbovePct(100 - INTERVAL_MODIFIER * _intervalHealthAmount)) { - //increase amount, unless we're at 10%, then we switch and return - if (IntervalHealthAmount == INTERVAL_SWITCH) + // increase amount, unless we're at 10%, then we switch and return + if (_intervalHealthAmount == INTERVAL_SWITCH) { - Enraged = true; + _enraged = true; + events.Reset(); + events.ScheduleEvent(EVENT_OVERLOAD, 1200); return; } else - ++IntervalHealthAmount; + ++_intervalHealthAmount; Talk(SAY_ENERGY); Talk(EMOTE_DISCHARGE_ENERGY); if (IsHeroic()) { - DoCast(me, H_SPELL_SUMMON_PURE_ENERGY1, false); - DoCast(me, H_SPELL_SUMMON_PURE_ENERGY2, false); + DoCast(me, H_SPELL_SUMMON_PURE_ENERGY1); + DoCast(me, H_SPELL_SUMMON_PURE_ENERGY2); } else - DoCast(me, SPELL_SUMMON_PURE_ENERGY, false); - - //below are workaround summons, remove when summoning spells w/implicitTarget 73 implemented in the core - me->SummonCreature(NPC_PURE_ENERGY, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); - - if (IsHeroic()) - me->SummonCreature(NPC_PURE_ENERGY, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + DoCast(me, SPELL_SUMMON_PURE_ENERGY); } + } - if (ChainLightningTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_CHAIN_LIGHTNING); + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - ChainLightningTimer = 8000; - } else ChainLightningTimer -= diff; + events.Update(diff); - if (ArcaneShockTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - if (target) - DoCast(target, SPELL_ARCANE_SHOCK); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - ArcaneShockTimer = 8000; - } else ArcaneShockTimer -= diff; - } - else - { - if (OverloadTimer <= diff) + while (uint32 eventId = events.ExecuteEvent()) { - DoCastVictim(SPELL_OVERLOAD); + switch (eventId) + { + case EVENT_CHAIN_LIGHTNING: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_CHAIN_LIGHTNING); + events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 8000); + break; + case EVENT_ARCANE_SHOCK: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 20.0f, true)) + DoCast(target, SPELL_ARCANE_SHOCK); + events.ScheduleEvent(EVENT_ARCANE_SHOCK, 8000); + break; + case EVENT_OVERLOAD: + DoCastVictim(SPELL_OVERLOAD); + events.ScheduleEvent(EVENT_OVERLOAD, 2000); + break; + default: + break; + } + } - OverloadTimer = 2000; - } else OverloadTimer -= diff; + DoMeleeAttackIfReady(); } - DoMeleeAttackIfReady(); - } - }; + private: + uint32 _intervalHealthAmount; + bool _enraged; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_vexallusAI>(creature); + }; }; -class npc_pure_energy : public CreatureScript +enum NpcPureEnergy { -public: - npc_pure_energy() : CreatureScript("npc_pure_energy") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_pure_energyAI(creature); - }; - - struct npc_pure_energyAI : public ScriptedAI - { - npc_pure_energyAI(Creature* creature) : ScriptedAI(creature) - { - me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); - } + SPELL_ENERGY_BOLT = 46156, + SPELL_ENERGY_FEEDBACK = 44335, + SPELL_PURE_ENERGY_PASSIVE = 44326 +}; - void Reset() override { } +class npc_pure_energy : public CreatureScript +{ + public: + npc_pure_energy() : CreatureScript("npc_pure_energy") { } - void JustDied(Unit* slayer) override + struct npc_pure_energyAI : public ScriptedAI { - if (Unit* temp = me->GetOwner()) + npc_pure_energyAI(Creature* creature) : ScriptedAI(creature) { - if (temp && temp->IsAlive()) - slayer->CastSpell(slayer, SPELL_ENERGY_FEEDBACK, true, 0, 0, temp->GetGUID()); + me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); } - } - void EnterCombat(Unit* /*who*/) override { } - void MoveInLineOfSight(Unit* /*who*/) override { } + void JustDied(Unit* killer) override + { + killer->CastSpell(killer, SPELL_ENERGY_FEEDBACK, true); + me->RemoveAurasDueToSpell(SPELL_PURE_ENERGY_PASSIVE); + } + }; - void AttackStart(Unit* /*who*/) override { } - }; + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_pure_energyAI(creature); + }; }; void AddSC_boss_vexallus() diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp index daea647609d..e0050420a08 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -16,19 +15,10 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Instance_Magisters_Terrace -SD%Complete: 60 -SDComment: Designed only for Selin Fireheart -SDCategory: Magister's Terrace -EndScriptData */ - #include "ScriptMgr.h" #include "InstanceScript.h" #include "magisters_terrace.h" -#define MAX_ENCOUNTER 4 - /* 0 - Selin Fireheart 1 - Vexallus @@ -36,281 +26,239 @@ EndScriptData */ 3 - Kael'thas Sunstrider */ -enum Creatures +DoorData const doorData[] = { - NPC_SELIN = 24723, - NPC_DELRISSA = 24560, - NPC_FELCRYSTALS = 24722 -}; - -enum GameObjects -{ - GO_VEXALLUS_DOOR = 187896, - GO_SELIN_DOOR = 187979, - GO_SELIN_ENCOUNTER_DOOR = 188065, - GO_DELRISSA_DOOR = 187770, - GO_KAEL_DOOR = 188064, - GO_KAEL_STATUE_1 = 188165, - GO_KAEL_STATUE_2 = 188166, - GO_ESCAPE_ORB = 188173 + { GO_SELIN_DOOR, DATA_SELIN, DOOR_TYPE_PASSAGE, BOUNDARY_NONE }, + { GO_SELIN_ENCOUNTER_DOOR, DATA_SELIN, DOOR_TYPE_ROOM, BOUNDARY_NONE }, + { GO_VEXALLUS_DOOR, DATA_VEXALLUS, DOOR_TYPE_PASSAGE, BOUNDARY_NONE }, + { GO_DELRISSA_DOOR, DATA_DELRISSA, DOOR_TYPE_PASSAGE, BOUNDARY_NONE }, + { GO_KAEL_DOOR, DATA_KAELTHAS, DOOR_TYPE_ROOM, BOUNDARY_NONE }, + { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } // END }; class instance_magisters_terrace : public InstanceMapScript { -public: - instance_magisters_terrace() : InstanceMapScript("instance_magisters_terrace", 585) { } - - struct instance_magisters_terrace_InstanceMapScript : public InstanceScript - { - instance_magisters_terrace_InstanceMapScript(Map* map) : InstanceScript(map) { } - - uint32 Encounter[MAX_ENCOUNTER]; - uint32 DelrissaDeathCount; + public: + instance_magisters_terrace() : InstanceMapScript("instance_magisters_terrace", 585) { } - std::vector<uint64> FelCrystals; - - uint64 SelinGUID; - uint64 DelrissaGUID; - uint64 VexallusDoorGUID; - uint64 SelinDoorGUID; - uint64 SelinEncounterDoorGUID; - uint64 DelrissaDoorGUID; - uint64 KaelDoorGUID; - uint64 KaelStatue[2]; - uint64 EscapeOrbGUID; - uint32 StatuesState; - uint8 felCristalIndex; - - void Initialize() override + struct instance_magisters_terrace_InstanceMapScript : public InstanceScript { - memset(&Encounter, 0, sizeof(Encounter)); - - FelCrystals.clear(); + instance_magisters_terrace_InstanceMapScript(Map* map) : InstanceScript(map) + { + SetBossNumber(EncounterCount); + LoadDoorData(doorData); - DelrissaDeathCount = 0; + FelCrystals.clear(); + DelrissaDeathCount = 0; - SelinGUID = 0; - DelrissaGUID = 0; - VexallusDoorGUID = 0; - SelinDoorGUID = 0; - SelinEncounterDoorGUID = 0; - DelrissaDoorGUID = 0; - KaelDoorGUID = 0; - KaelStatue[0] = 0; - KaelStatue[1] = 0; - EscapeOrbGUID = 0; - StatuesState = 0; - felCristalIndex = 0; - } + SelinGUID = 0; + DelrissaGUID = 0; + EscapeOrbGUID = 0; + FelCristalIndex = 0; - bool IsEncounterInProgress() const override - { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (Encounter[i] == IN_PROGRESS) - return true; - return false; - } + memset(KaelStatue, 0, 2 * sizeof(uint64)); + } - uint32 GetData(uint32 identifier) const - { - switch (identifier) + uint32 GetData(uint32 type) const override { - case DATA_SELIN_EVENT: - return Encounter[0]; - case DATA_VEXALLUS_EVENT: - return Encounter[1]; - case DATA_DELRISSA_EVENT: - return Encounter[2]; - case DATA_KAELTHAS_EVENT: - return Encounter[3]; - case DATA_DELRISSA_DEATH_COUNT: - return DelrissaDeathCount; - case DATA_FEL_CRYSTAL_SIZE: - return FelCrystals.size(); + switch (type) + { + case DATA_DELRISSA_DEATH_COUNT: + return DelrissaDeathCount; + case DATA_FEL_CRYSTAL_SIZE: + return uint32(FelCrystals.size()); + default: + break; + } + return 0; } - return 0; - } - void SetData(uint32 identifier, uint32 data) - { - switch (identifier) + void SetData(uint32 type, uint32 data) override { - case DATA_SELIN_EVENT: - if (data == DONE) - { - HandleGameObject(SelinEncounterDoorGUID, true); - HandleGameObject(SelinDoorGUID, true); - } - else if (data == IN_PROGRESS) - HandleGameObject(SelinEncounterDoorGUID, false); - else if (data == NOT_STARTED) - HandleGameObject(SelinEncounterDoorGUID, true); - - Encounter[0] = data; - break; - case DATA_VEXALLUS_EVENT: - if (data == DONE) - HandleGameObject(VexallusDoorGUID, true); - Encounter[1] = data; - break; - case DATA_DELRISSA_EVENT: - if (data == DONE) - HandleGameObject(DelrissaDoorGUID, true); - if (data == IN_PROGRESS) - DelrissaDeathCount = 0; - Encounter[2] = data; - break; - case DATA_KAELTHAS_EVENT: - if (data == NOT_STARTED || data == DONE) - HandleGameObject(KaelDoorGUID, true); - else if (data == IN_PROGRESS) - HandleGameObject(KaelDoorGUID, false); - Encounter[3] = data; - break; - case DATA_DELRISSA_DEATH_COUNT: - if (data == SPECIAL) - ++DelrissaDeathCount; - else - DelrissaDeathCount = 0; - break; - case DATA_KAELTHAS_STATUES: - HandleGameObject(KaelStatue[0], data); - HandleGameObject(KaelStatue[1], data); - StatuesState = data; - break; + switch (type) + { + case DATA_DELRISSA_DEATH_COUNT: + if (data == SPECIAL) + ++DelrissaDeathCount; + else + DelrissaDeathCount = 0; + break; + case DATA_KAELTHAS_STATUES: + HandleGameObject(KaelStatue[0], data); + HandleGameObject(KaelStatue[1], data); + break; + default: + break; + } } - SaveToDB(); - } - - void OnCreatureCreate(Creature* creature) override - { - switch (creature->GetEntry()) + void OnCreatureCreate(Creature* creature) override { - case NPC_SELIN: - SelinGUID = creature->GetGUID(); - break; - case NPC_DELRISSA: - DelrissaGUID = creature->GetGUID(); - break; - case NPC_FELCRYSTALS: - FelCrystals.push_back(creature->GetGUID()); - break; + switch (creature->GetEntry()) + { + case NPC_SELIN: + SelinGUID = creature->GetGUID(); + break; + case NPC_DELRISSA: + DelrissaGUID = creature->GetGUID(); + break; + case NPC_FELCRYSTALS: + FelCrystals.push_back(creature->GetGUID()); + break; + default: + break; + } } - } - void OnGameObjectCreate(GameObject* go) override - { - switch (go->GetEntry()) + void OnGameObjectCreate(GameObject* go) override { - case GO_VEXALLUS_DOOR: - VexallusDoorGUID = go->GetGUID(); - break; - case GO_SELIN_DOOR: - SelinDoorGUID = go->GetGUID(); - break; - case GO_SELIN_ENCOUNTER_DOOR: - SelinEncounterDoorGUID = go->GetGUID(); - break; - case GO_DELRISSA_DOOR: - DelrissaDoorGUID = go->GetGUID(); - break; - case GO_KAEL_DOOR: - KaelDoorGUID = go->GetGUID(); - break; - case GO_KAEL_STATUE_1: - KaelStatue[0] = go->GetGUID(); - break; - case GO_KAEL_STATUE_2: - KaelStatue[1] = go->GetGUID(); - break; - case GO_ESCAPE_ORB: - EscapeOrbGUID = go->GetGUID(); - break; + switch (go->GetEntry()) + { + case GO_VEXALLUS_DOOR: + case GO_SELIN_DOOR: + case GO_SELIN_ENCOUNTER_DOOR: + case GO_DELRISSA_DOOR: + case GO_KAEL_DOOR: + AddDoor(go, true); + break; + case GO_KAEL_STATUE_1: + KaelStatue[0] = go->GetGUID(); + break; + case GO_KAEL_STATUE_2: + KaelStatue[1] = go->GetGUID(); + break; + case GO_ESCAPE_ORB: + EscapeOrbGUID = go->GetGUID(); + break; + default: + break; + } } - } - - std::string GetSaveData() override - { - OUT_SAVE_INST_DATA; - - std::ostringstream saveStream; - saveStream << Encounter[0] << ' ' << Encounter[1] << ' ' << Encounter[2] << ' ' << Encounter[3] << ' ' << StatuesState; - OUT_SAVE_INST_DATA_COMPLETE; - return saveStream.str(); - } + void OnGameObjectRemove(GameObject* go) override + { + switch (go->GetEntry()) + { + case GO_VEXALLUS_DOOR: + case GO_SELIN_DOOR: + case GO_SELIN_ENCOUNTER_DOOR: + case GO_DELRISSA_DOOR: + case GO_KAEL_DOOR: + AddDoor(go, false); + break; + default: + break; + } + } - void Load(const char* str) override - { - if (!str) + bool SetBossState(uint32 type, EncounterState state) override { - OUT_LOAD_INST_DATA_FAIL; - return; + if (!InstanceScript::SetBossState(type, state)) + return false; + + switch (type) + { + case DATA_DELRISSA: + if (type == IN_PROGRESS) + DelrissaDeathCount = 0; + break; + default: + break; + } + return true; } - OUT_LOAD_INST_DATA(str); + std::string GetSaveData() override + { + OUT_SAVE_INST_DATA; - std::istringstream loadStream(str); + std::ostringstream saveStream; + saveStream << "M T " << GetBossSaveData(); - for (uint32 i = 0; i < MAX_ENCOUNTER; ++i) - { - uint32 tmpState; - loadStream >> tmpState; - if (tmpState == IN_PROGRESS || tmpState > SPECIAL) - tmpState = NOT_STARTED; - SetData(i, tmpState); + OUT_SAVE_INST_DATA_COMPLETE; + return saveStream.str(); } - loadStream >> StatuesState; - SetData(DATA_KAELTHAS_STATUES, StatuesState); + void Load(const char* str) override + { + if (!str) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } - OUT_LOAD_INST_DATA_COMPLETE; - } + OUT_LOAD_INST_DATA(str); - uint64 GetData64(uint32 identifier) const - { - switch (identifier) - { - case DATA_SELIN: - return SelinGUID; - case DATA_DELRISSA: - return DelrissaGUID; - case DATA_VEXALLUS_DOOR: - return VexallusDoorGUID; - case DATA_DELRISSA_DOOR: - return DelrissaDoorGUID; - case DATA_KAEL_DOOR: - return KaelDoorGUID; - case DATA_KAEL_STATUE_LEFT: - return KaelStatue[0]; - case DATA_KAEL_STATUE_RIGHT: - return KaelStatue[1]; - case DATA_ESCAPE_ORB: - return EscapeOrbGUID; - case DATA_FEL_CRYSTAL: - if (FelCrystals.size() < felCristalIndex) + char dataHead1, dataHead2; + + std::istringstream loadStream(str); + loadStream >> dataHead1 >> dataHead2; + if (dataHead1 == 'M' && dataHead2 == 'T') + { + for (uint32 i = 0; i < EncounterCount; ++i) { - TC_LOG_ERROR("scripts", "Magisters Terrace: No Fel Crystals loaded in Inst Data"); - return 0; + uint32 tmpState; + loadStream >> tmpState; + if (tmpState == IN_PROGRESS || tmpState > SPECIAL) + tmpState = NOT_STARTED; + SetBossState(i, EncounterState(tmpState)); } + } + else + OUT_LOAD_INST_DATA_FAIL; - return FelCrystals.at(felCristalIndex); + OUT_LOAD_INST_DATA_COMPLETE; + } + + uint64 GetData64(uint32 type) const override + { + switch (type) + { + case DATA_SELIN: + return SelinGUID; + case DATA_DELRISSA: + return DelrissaGUID; + case DATA_KAEL_STATUE_LEFT: + return KaelStatue[0]; + case DATA_KAEL_STATUE_RIGHT: + return KaelStatue[1]; + case DATA_ESCAPE_ORB: + return EscapeOrbGUID; + case DATA_FEL_CRYSTAL: + if (FelCrystals.size() < FelCristalIndex) + { + TC_LOG_ERROR("scripts", "Magisters Terrace: No Fel Crystals loaded in Inst Data"); + return 0; + } + + return FelCrystals.at(FelCristalIndex); + default: + break; + } + return 0; } - return 0; - } - void SetData64(uint32 identifier, uint64 value) + void SetData64(uint32 type, uint64 value) override + { + if (type == DATA_FEL_CRYSTAL) + FelCristalIndex = value; + } + + protected: + std::vector<uint64> FelCrystals; + + uint64 SelinGUID; + uint64 DelrissaGUID; + uint64 KaelStatue[2]; + uint64 EscapeOrbGUID; + uint32 DelrissaDeathCount; + uint8 FelCristalIndex; + }; + + InstanceScript* GetInstanceScript(InstanceMap* map) const override { - if (identifier == DATA_FEL_CRYSTAL) - felCristalIndex = value; + return new instance_magisters_terrace_InstanceMapScript(map); } - }; - - InstanceScript* GetInstanceScript(InstanceMap* map) const override - { - return new instance_magisters_terrace_InstanceMapScript(map); - } }; void AddSC_instance_magisters_terrace() diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h index ddfaa91bc98..d3517dfccf6 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h @@ -19,24 +19,17 @@ #ifndef DEF_MAGISTERS_TERRACE_H #define DEF_MAGISTERS_TERRACE_H -#define ERROR_INST_DATA "TSCR Error: Instance Data not set properly for Magister's Terrace instance (map 585). Encounters will be buggy." +uint32 const EncounterCount = 4; -enum Data +enum DataTypes { - DATA_SELIN_EVENT, - DATA_VEXALLUS_EVENT, - DATA_DELRISSA_EVENT, - DATA_KAELTHAS_EVENT, - DATA_SELIN, - DATA_FEL_CRYSTAL, - DATA_FEL_CRYSTAL_SIZE, - - DATA_VEXALLUS_DOOR, + DATA_VEXALLUS, DATA_DELRISSA, - DATA_DELRISSA_DOOR, + DATA_KAELTHAS, - DATA_KAEL_DOOR, + DATA_FEL_CRYSTAL, + DATA_FEL_CRYSTAL_SIZE, DATA_KAEL_STATUE_LEFT, DATA_KAEL_STATUE_RIGHT, @@ -45,4 +38,23 @@ enum Data DATA_ESCAPE_ORB }; +enum CreatureIds +{ + NPC_SELIN = 24723, + NPC_DELRISSA = 24560, + NPC_FELCRYSTALS = 24722 +}; + +enum GameObjectIds +{ + GO_VEXALLUS_DOOR = 187896, + GO_SELIN_DOOR = 187979, + GO_SELIN_ENCOUNTER_DOOR = 188065, + GO_DELRISSA_DOOR = 187770, + GO_KAEL_DOOR = 188064, + GO_KAEL_STATUE_1 = 188165, + GO_KAEL_STATUE_2 = 188166, + GO_ESCAPE_ORB = 188173 +}; + #endif diff --git a/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp b/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp index 8c612a11621..bc4fff4da7b 100644 --- a/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp +++ b/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp @@ -190,6 +190,9 @@ enum InfusedCrystal // Quest QUEST_POWERING_OUR_DEFENSES = 8490, + // Quest Credit + QUEST_POD_CREDIT = 16364, + // Says EMOTE = 0, @@ -266,24 +269,17 @@ public: summoned->AI()->AttackStart(me); } - void JustDied(Unit* /*killer*/) override - { - if (PlayerGUID && !Completed) - if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID)) - player->FailQuest(QUEST_POWERING_OUR_DEFENSES); - } - void UpdateAI(uint32 diff) override { if (EndTimer < diff && Progress) { - Talk(EMOTE); Completed = true; if (PlayerGUID) if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID)) - player->CompleteQuest(QUEST_POWERING_OUR_DEFENSES); - - me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + { + Talk(EMOTE, player); + player->KilledMonsterCredit(QUEST_POD_CREDIT); + } me->RemoveCorpse(); } else EndTimer -= diff; diff --git a/src/server/scripts/Events/CMakeLists.txt b/src/server/scripts/Events/CMakeLists.txt index e45bc585007..3bdb6e6eac2 100644 --- a/src/server/scripts/Events/CMakeLists.txt +++ b/src/server/scripts/Events/CMakeLists.txt @@ -8,9 +8,11 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +file(GLOB_RECURSE sources_Events Events/*.cpp Events/*.h) + set(scripts_STAT_SRCS ${scripts_STAT_SRCS} - Events/childrens_week.cpp + ${sources_Events} ) message(" -> Prepared: Events") diff --git a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp index aa9774bfd62..ee244e51b09 100644 --- a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp +++ b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp @@ -133,106 +133,6 @@ class npc_risen_husk_spirit : public CreatureScript }; /*###### -## npc_theramor_guard -######*/ - -enum TheramoreGuard -{ - QUEST_DISCREDITING_THE_DESERTERS = 11133, - - NPC_THERAMORE_GUARD = 4979, - - SPELL_DOCTORED_LEAFLET = 42725, - SPELL_PROPAGANDIZED = 42246, - - SAY_QUEST1 = 0, - SAY_QUEST2 = 1, - SAY_QUEST3 = 2 -}; - -#define GOSSIP_ITEM_THERAMORE_GUARD "You look like an intelligent person. Why don't you read one of these leaflets and give it some thought?" - -class npc_theramore_guard : public CreatureScript -{ -public: - npc_theramore_guard() : CreatureScript("npc_theramore_guard") { } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (player->GetQuestStatus(QUEST_DISCREDITING_THE_DESERTERS) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_THERAMORE_GUARD, GOSSIP_SENDER_MAIN, GOSSIP_SENDER_INFO); - - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - - return true; - } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - - if (action == GOSSIP_SENDER_INFO) - { - player->CLOSE_GOSSIP_MENU(); - player->KilledMonsterCredit(NPC_THERAMORE_GUARD, 0); - creature->AI()->Talk(SAY_QUEST1); - creature->CastSpell(creature, SPELL_DOCTORED_LEAFLET, false); - creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - CAST_AI(npc_theramore_guard::npc_theramore_guardAI, creature->AI())->YellTimer = 4000; - CAST_AI(npc_theramore_guard::npc_theramore_guardAI, creature->AI())->bYellTimer = true; - } - - return true; - } - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_theramore_guardAI(creature); - } - - struct npc_theramore_guardAI : public ScriptedAI - { - npc_theramore_guardAI(Creature* creature) : ScriptedAI(creature) { } - - uint32 YellTimer; - uint32 Step; - bool bYellTimer; - - void Reset() override - { - bYellTimer = false; - Step = 0; - } - - void UpdateAI(uint32 Diff) override - { - if (!me->HasAura(SPELL_PROPAGANDIZED)) - me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - - if (bYellTimer && YellTimer <= Diff) - { - switch (Step) - { - case 0: - Talk(SAY_QUEST2); - YellTimer = 3000; - ++Step; - break; - case 1: - Talk(SAY_QUEST3); - me->HandleEmoteCommand(EMOTE_ONESHOT_LAUGH); - Step = 0; - bYellTimer = false; - break; - } - } - else - YellTimer -= Diff; - } - }; -}; - -/*###### ## npc_lady_jaina_proudmoore ######*/ @@ -772,7 +672,6 @@ void AddSC_dustwallow_marsh() new npc_private_hendel(); new npc_zelfrax(); new npc_stinky(); - new npc_theramore_guard(); new spell_ooze_zap(); new spell_ooze_zap_channel_end(); new spell_energize_aoe(); diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp index 4aa59e72556..bf7b4355ea6 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp @@ -141,9 +141,9 @@ class instance_ahnkahet : public InstanceMapScript SwitchTrigger = data; break; case DATA_JEDOGA_RESET_INITIANDS: - for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + for (uint64 guid : InitiandGUIDs) { - if (Creature* creature = instance->GetCreature(*itr)) + if (Creature* creature = instance->GetCreature(guid)) { creature->Respawn(); if (!creature->IsInEvadeMode()) @@ -164,9 +164,9 @@ class instance_ahnkahet : public InstanceMapScript case DATA_SPHERE_2: return SpheresState[type - DATA_SPHERE_1]; case DATA_ALL_INITIAND_DEAD: - for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + for (uint64 guid : InitiandGUIDs) { - Creature* cr = instance->GetCreature(*itr); + Creature* cr = instance->GetCreature(guid); if (!cr || cr->IsAlive()) return 0; } @@ -214,11 +214,11 @@ class instance_ahnkahet : public InstanceMapScript { std::vector<uint64> vInitiands; vInitiands.clear(); - for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + for (uint64 guid : InitiandGUIDs) { - Creature* cr = instance->GetCreature(*itr); + Creature* cr = instance->GetCreature(guid); if (cr && cr->IsAlive()) - vInitiands.push_back(*itr); + vInitiands.push_back(guid); } if (vInitiands.empty()) return 0; @@ -245,9 +245,9 @@ class instance_ahnkahet : public InstanceMapScript case DATA_JEDOGA_SHADOWSEEKER: if (state == DONE) { - for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + for (uint64 guid : InitiandGUIDs) { - if (Creature* cr = instance->GetCreature(*itr)) + if (Creature* cr = instance->GetCreature(guid)) cr->DespawnOrUnsummon(); } } diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt index aff3c0a9528..8401ea4b9a5 100644 --- a/src/server/scripts/Northrend/CMakeLists.txt +++ b/src/server/scripts/Northrend/CMakeLists.txt @@ -20,7 +20,6 @@ set(scripts_STAT_SRCS Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp Northrend/Ulduar/HallsOfLightning/boss_loken.cpp Northrend/Ulduar/Ulduar/boss_general_vezax.cpp - Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp Northrend/Ulduar/Ulduar/boss_thorim.cpp Northrend/Ulduar/Ulduar/boss_ignis.cpp Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp index f352b4faace..43c295d5f64 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -855,7 +855,6 @@ class npc_halion_controller : public CreatureScript { if (Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetData64(itr))) { - RemoveCorporeality(halion, itr == DATA_TWILIGHT_HALION); halion->CastSpell(halion, GetSpell(_materialCorporealityValue, itr == DATA_TWILIGHT_HALION), true); if (itr == DATA_TWILIGHT_HALION) @@ -866,19 +865,6 @@ class npc_halion_controller : public CreatureScript } } - void RemoveCorporeality(Creature* who, bool isTwilight = false) - { - for (uint8 i = 0; i < MAX_CORPOREALITY_STATE; i++) - { - uint32 spellID = (isTwilight ? _corporealityReference[i].twilightRealmSpell : _corporealityReference[i].materialRealmSpell); - if (who->HasAura(spellID)) - { - who->RemoveAurasDueToSpell(spellID); - break; - } - } - } - uint32 GetSpell(uint8 pctValue, bool isTwilight = false) const { CorporealityEntry entry = _corporealityReference[pctValue]; diff --git a/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp b/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp index 63b1359a406..4e9462a447f 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp +++ b/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp @@ -208,7 +208,7 @@ public: { for (uint8 i = 0; i < 4; i++) if (uint64 guid = instance->GetData64(summoners[i].data)) - if (Creature* crystalChannelTarget = instance->instance->GetCreature(guid)) + if (Creature* crystalChannelTarget = ObjectAccessor::GetCreature(*me, guid)) { if (active) crystalChannelTarget->AI()->SetData(summoners[i].spell, summoners[i].timer); @@ -221,7 +221,7 @@ public: { for (uint8 i = 0; i < 4; i++) if (uint64 guid = instance->GetData64(DATA_NOVOS_CRYSTAL_1 + i)) - if (GameObject* crystal = instance->instance->GetGameObject(guid)) + if (GameObject* crystal = ObjectAccessor::GetGameObject(*me, guid)) SetCrystalStatus(crystal, active); } @@ -241,7 +241,7 @@ public: { for (uint8 i = 0; i < 4; i++) if (uint64 guid = instance->GetData64(DATA_NOVOS_CRYSTAL_1 + i)) - if (GameObject* crystal = instance->instance->GetGameObject(guid)) + if (GameObject* crystal = ObjectAccessor::GetGameObject(*me, guid)) if (crystal->GetGoState() == GO_STATE_ACTIVE) { SetCrystalStatus(crystal, false); @@ -258,7 +258,7 @@ public: events.ScheduleEvent(EVENT_SUMMON_MINIONS, 15000); } else if (uint64 guid = instance->GetData64(DATA_NOVOS_SUMMONER_4)) - if (Creature* crystalChannelTarget = instance->instance->GetCreature(guid)) + if (Creature* crystalChannelTarget = ObjectAccessor::GetCreature(*me, guid)) crystalChannelTarget->AI()->SetData(SPELL_SUMMON_CRYSTAL_HANDLER, 15000); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index 16d1531e890..e1658e564ec 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -1227,9 +1227,9 @@ class spell_deathbringer_blood_nova_targeting : public SpellScriptLoader if (targets.empty()) return; - // select one random target, with preference of ranged targets + // select one random target, preferring ranged targets uint32 targetsAtRange = 0; - uint32 const minTargets = uint32(GetCaster()->GetMap()->GetSpawnMode() & 1 ? 10 : 4); + uint32 const minTargets = uint32(GetCaster()->GetMap()->Is25ManRaid() ? 10 : 4); targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), false)); // get target count at range @@ -1237,18 +1237,12 @@ class spell_deathbringer_blood_nova_targeting : public SpellScriptLoader if ((*itr)->GetDistance(GetCaster()) < 12.0f) break; - // set the upper cap + // If not enough ranged targets are present just select anyone if (targetsAtRange < minTargets) - targetsAtRange = std::min<uint32>(targets.size() - 1, minTargets); - - if (!targetsAtRange) - { - targets.clear(); - return; - } + targetsAtRange = uint32(targets.size()); std::list<WorldObject*>::const_iterator itr = targets.begin(); - std::advance(itr, urand(0, targetsAtRange)); + std::advance(itr, urand(0, targetsAtRange - 1)); target = *itr; targets.clear(); targets.push_back(target); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index 223f3731032..b72b953efb4 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -559,6 +559,11 @@ class boss_the_lich_king : public CreatureScript Trinity::GameObjectWorker<FrozenThroneResetWorker> worker(me, reset); me->VisitNearbyGridObject(333.0f, worker); + // Restore Tirion's gossip only after The Lich King fully resets to prevent + // restarting the encounter while LK still runs back to spawn point + if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) + tirion->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + // Reset any light override me->GetMap()->SetZoneOverrideLight(AREA_THE_FROZEN_THRONE, 0, 5000); } @@ -1201,11 +1206,6 @@ class npc_tirion_fordring_tft : public CreatureScript void JustReachedHome() override { me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - - if (_instance->GetBossState(DATA_THE_LICH_KING) == DONE) - return; - - me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp index d3b4a285af6..d4f00414b7d 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp @@ -120,7 +120,6 @@ public: } void MoveInLineOfSight(Unit* who) override - { if (!hasTaunted && me->IsWithinDistInMap(who, 60.0f) && who->GetTypeId() == TYPEID_PLAYER) { diff --git a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp index 02bafa8d10d..3d42827c0a8 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp @@ -84,7 +84,6 @@ class boss_faerlina : public CreatureScript } void MoveInLineOfSight(Unit* who) override - { if (!_introDone && who->GetTypeId() == TYPEID_PLAYER) { diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp index 3a0e3ce7c73..381be8d5cd1 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp @@ -70,7 +70,6 @@ public: } void MoveInLineOfSight(Unit* who) override - { if (who->GetEntry() == NPC_ZOMBIE && me->IsWithinDistInMap(who, 7)) { diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index 1331c25de17..e8ed181da5a 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -368,9 +368,9 @@ class instance_naxxramas : public InstanceMapScript if (i == section) continue; - for (std::set<uint64>::const_iterator itr = HeiganEruptionGUID[i].begin(); itr != HeiganEruptionGUID[i].end(); ++itr) + for (uint64 guid : HeiganEruptionGUID[i]) { - if (GameObject* heiganEruption = instance->GetGameObject(*itr)) + if (GameObject* heiganEruption = instance->GetGameObject(guid)) { heiganEruption->SendCustomAnim(heiganEruption->GetGoAnimProgress()); heiganEruption->CastSpell(NULL, SPELL_ERUPTION); diff --git a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp index bf84a267a27..2b15ddf32c4 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp @@ -281,8 +281,8 @@ class instance_oculus : public InstanceMapScript void GreaterWhelps() { - for (std::list<uint64>::const_iterator itr = GreaterWhelpList.begin(); itr != GreaterWhelpList.end(); ++itr) - if (Creature* gwhelp = instance->GetCreature(*itr)) + for (uint64 guid : GreaterWhelpList) + if (Creature* gwhelp = instance->GetCreature(guid)) gwhelp->SetPhaseMask(1, true); } diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp index 24d145f097f..13ea815febc 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp @@ -164,11 +164,9 @@ public: for (uint8 i = 0; i < 2; ++i) { - if (Creature* pStormforgedLieutenant = (ObjectAccessor::GetCreature((*me), m_auiStormforgedLieutenantGUID[i]))) - { + if (Creature* pStormforgedLieutenant = ObjectAccessor::GetCreature(*me, m_auiStormforgedLieutenantGUID[i])) if (!pStormforgedLieutenant->IsAlive()) pStormforgedLieutenant->Respawn(); - } } if (m_uiStance != STANCE_DEFENSIVE) @@ -411,7 +409,7 @@ public: void EnterCombat(Unit* who) override { - if (Creature* pBjarngrim = instance->instance->GetCreature(instance->GetData64(DATA_BJARNGRIM))) + if (Creature* pBjarngrim = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_BJARNGRIM))) { if (pBjarngrim->IsAlive() && !pBjarngrim->GetVictim()) pBjarngrim->AI()->AttackStart(who); @@ -434,7 +432,7 @@ public: if (m_uiRenewSteel_Timer <= uiDiff) { - if (Creature* pBjarngrim = instance->instance->GetCreature(instance->GetData64(DATA_BJARNGRIM))) + if (Creature* pBjarngrim = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_BJARNGRIM))) { if (pBjarngrim->IsAlive()) DoCast(pBjarngrim, SPELL_RENEW_STEEL_N); diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp index aac315cda0d..83082b18d73 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp @@ -165,9 +165,9 @@ public: Position pos = me->GetPosition(); - for (std::list<uint64>::const_iterator itr = lSparkList.begin(); itr != lSparkList.end(); ++itr) + for (uint64 guid : lSparkList) { - if (Creature* pSpark = ObjectAccessor::GetCreature(*me, *itr)) + if (Creature* pSpark = ObjectAccessor::GetCreature(*me, guid)) { if (pSpark->IsAlive()) { diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp index d0b8f75e711..b424ce01b06 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp @@ -162,13 +162,11 @@ public: if (m_lGolemGUIDList.empty()) return; - for (std::list<uint64>::const_iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr) + for (uint64 guid : m_lGolemGUIDList) { - if (Creature* temp = ObjectAccessor::GetCreature(*me, *itr)) - { + if (Creature* temp = ObjectAccessor::GetCreature(*me, guid)) if (temp->IsAlive()) temp->DespawnOrUnsummon(); - } } m_lGolemGUIDList.clear(); @@ -179,9 +177,9 @@ public: if (m_lGolemGUIDList.empty()) return; - for (std::list<uint64>::const_iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr) + for (uint64 guid : m_lGolemGUIDList) { - if (Creature* temp = ObjectAccessor::GetCreature(*me, *itr)) + if (Creature* temp = ObjectAccessor::GetCreature(*me, guid)) { // Only shatter brittle golems if (temp->IsAlive() && temp->GetEntry() == NPC_BRITTLE_GOLEM) diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp index eec08c3c429..796299cc952 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp @@ -37,7 +37,7 @@ enum Spells enum Events { - EVENT_PARTING_SORROW = 1, + EVENT_PARTING_SORROW = 1, EVENT_STORM_OF_GRIEF, EVENT_SHOCK_OF_SORROW, EVENT_PILLAR_OF_WOE diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 67500382758..595dcecd554 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -334,7 +334,7 @@ class boss_algalon_the_observer : public CreatureScript { case ACTION_START_INTRO: { - me->SetFlag(UNIT_FIELD_FLAGS_2, 0x20); + me->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_INSTANTLY_APPEAR_MODEL); me->SetDisableGravity(true); DoCast(me, SPELL_ARRIVAL, true); DoCast(me, SPELL_RIDE_THE_LIGHTNING, true); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index 4dfa38abae5..257518d998b 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -18,9 +18,10 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "InstanceScript.h" -#include "ulduar.h" #include "Player.h" #include "WorldPacket.h" +#include "SpellScript.h" +#include "ulduar.h" static DoorData const doorData[] = { @@ -1161,7 +1162,43 @@ class instance_ulduar : public InstanceMapScript } }; +class spell_ulduar_teleporter : public SpellScriptLoader +{ + public: + spell_ulduar_teleporter() : SpellScriptLoader("spell_ulduar_teleporter") { } + + class spell_ulduar_teleporter_SpellScript : public SpellScript + { + PrepareSpellScript(spell_ulduar_teleporter_SpellScript); + + SpellCastResult CheckRequirement() + { + if (GetExplTargetUnit()->GetTypeId() != TYPEID_PLAYER) + return SPELL_FAILED_DONT_REPORT; + + if (GetExplTargetUnit()->IsInCombat()) + { + Spell::SendCastResult(GetExplTargetUnit()->ToPlayer(), GetSpellInfo(), 0, SPELL_FAILED_AFFECTING_COMBAT); + return SPELL_FAILED_AFFECTING_COMBAT; + } + + return SPELL_CAST_OK; + } + + void Register() override + { + OnCheckCast += SpellCheckCastFn(spell_ulduar_teleporter_SpellScript::CheckRequirement); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_ulduar_teleporter_SpellScript(); + } +}; + void AddSC_instance_ulduar() { new instance_ulduar(); + new spell_ulduar_teleporter(); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp deleted file mode 100644 index 9fc0e4056fa..00000000000 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "ScriptMgr.h" -#include "ScriptedGossip.h" -#include "InstanceScript.h" -#include "Player.h" -#include "ulduar.h" - -/* -The teleporter appears to be active and stable. - -- Expedition Base Camp -- Formation Grounds -- Colossal Forge -- Scrapyard -- Antechamber of Ulduar -- Shattered Walkway -- Conservatory of Life -*/ - -enum UlduarTeleporter -{ - BASE_CAMP = 200, - GROUNDS = 201, - FORGE = 202, - SCRAPYARD = 203, - ANTECHAMBER = 204, - WALKWAY = 205, - CONSERVATORY = 206, -}; - -class ulduar_teleporter : public GameObjectScript -{ - public: - ulduar_teleporter() : GameObjectScript("ulduar_teleporter") { } - - bool OnGossipSelect(Player* player, GameObject* /*gameObject*/, uint32 sender, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - if (sender != GOSSIP_SENDER_MAIN) - return false; - if (!player->getAttackers().empty()) - return false; - - switch (action) - { - case BASE_CAMP: - player->TeleportTo(603, -706.122f, -92.6024f, 429.876f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case GROUNDS: - player->TeleportTo(603, 131.248f, -35.3802f, 409.804f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case FORGE: - player->TeleportTo(603, 553.233f, -12.3247f, 409.679f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case SCRAPYARD: - player->TeleportTo(603, 926.292f, -11.4635f, 418.595f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case ANTECHAMBER: - player->TeleportTo(603, 1498.09f, -24.246f, 420.967f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case WALKWAY: - player->TeleportTo(603, 1859.45f, -24.1f, 448.9f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case CONSERVATORY: - player->TeleportTo(603, 2086.27f, -24.3134f, 421.239f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - } - - return true; - } - - bool OnGossipHello(Player* player, GameObject* gameObject) override - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Expedition Base Camp", GOSSIP_SENDER_MAIN, BASE_CAMP); - if (InstanceScript* instance = gameObject->GetInstanceScript()) - { - if (instance->GetData(DATA_COLOSSUS) == 2) //count of 2 collossus death - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Formation Grounds", GOSSIP_SENDER_MAIN, GROUNDS); - if (instance->GetBossState(BOSS_LEVIATHAN) == DONE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Colossal Forge", GOSSIP_SENDER_MAIN, FORGE); - if (instance->GetBossState(BOSS_XT002) == DONE) - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Scrapyard", GOSSIP_SENDER_MAIN, SCRAPYARD); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Antechamber of Ulduar", GOSSIP_SENDER_MAIN, ANTECHAMBER); - } - if (instance->GetBossState(BOSS_KOLOGARN) == DONE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Shattered Walkway", GOSSIP_SENDER_MAIN, WALKWAY); - if (instance->GetBossState(BOSS_AURIAYA) == DONE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Conservatory of Life", GOSSIP_SENDER_MAIN, CONSERVATORY); - } - - player->SEND_GOSSIP_MENU(gameObject->GetGOInfo()->GetGossipMenuId(), gameObject->GetGUID()); - return true; - } -}; - -void AddSC_ulduar_teleporter() -{ - new ulduar_teleporter(); -} diff --git a/src/server/scripts/Northrend/zone_crystalsong_forest.cpp b/src/server/scripts/Northrend/zone_crystalsong_forest.cpp index e4bd9c469fb..7d680ecd071 100644 --- a/src/server/scripts/Northrend/zone_crystalsong_forest.cpp +++ b/src/server/scripts/Northrend/zone_crystalsong_forest.cpp @@ -76,20 +76,18 @@ public: GetCreatureListWithEntryInGrid(orbList, me, NPC_TRANSITUS_SHIELD_DUMMY, 32.0f); if (!orbList.empty()) { - for (std::list<Creature*>::const_iterator itr = orbList.begin(); itr != orbList.end(); ++itr) + for (Creature* orb : orbList) { - if (Creature* pOrb = *itr) + if (orb->GetPositionY() < 1000) { - if (pOrb->GetPositionY() < 1000) - { - targetGUID = pOrb->GetGUID(); - break; - } + targetGUID = orb->GetGUID(); + break; } } } } - }else + } + else { if (!targetGUID) if (Creature* pOrb = GetClosestCreatureWithEntry(me, NPC_TRANSITUS_SHIELD_DUMMY, 32.0f)) diff --git a/src/server/scripts/Northrend/zone_dalaran.cpp b/src/server/scripts/Northrend/zone_dalaran.cpp index 21fc93578ae..1e8da70bbbf 100644 --- a/src/server/scripts/Northrend/zone_dalaran.cpp +++ b/src/server/scripts/Northrend/zone_dalaran.cpp @@ -73,7 +73,6 @@ public: void AttackStart(Unit* /*who*/) override { } void MoveInLineOfSight(Unit* who) override - { if (!who || !who->IsInWorld() || who->GetZoneId() != 4395) return; diff --git a/src/server/scripts/Northrend/zone_dragonblight.cpp b/src/server/scripts/Northrend/zone_dragonblight.cpp index bda6d953d9f..59c9b21a220 100644 --- a/src/server/scripts/Northrend/zone_dragonblight.cpp +++ b/src/server/scripts/Northrend/zone_dragonblight.cpp @@ -246,13 +246,10 @@ class npc_commander_eligor_dawnbringer : public CreatureScript { std::list<Creature*> creatureList; GetCreatureListWithEntryInGrid(creatureList, me, AudienceMobs[ii], 15.0f); - for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) + for (Creature* creature : creatureList) { - if (Creature* creatureList = *itr) - { - audienceList[creaturecount] = creatureList->GetGUID(); - ++creaturecount; - } + audienceList[creaturecount] = creature->GetGUID(); + ++creaturecount; } } diff --git a/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp b/src/server/scripts/Outland/BlackTemple/boss_gurtogg_bloodboil.cpp index 0004df68016..f03caa37cb2 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_gurtogg_bloodboil.cpp @@ -17,14 +17,14 @@ */ /* ScriptData -SDName: Boss_Bloodboil -SD%Complete: 80 -SDComment: Bloodboil not working correctly, missing enrage -SDCategory: Black Temple +Name: Boss_Bloodboil +Complete: 80 +Category: Black Temple EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellScript.h" #include "black_temple.h" enum Bloodboil @@ -54,9 +54,6 @@ enum Bloodboil SPELL_BERSERK = 45078 }; - -//This is used to sort the players by distance in preparation for the Bloodboil cast. - class boss_gurtogg_bloodboil : public CreatureScript { public: @@ -137,51 +134,6 @@ public: Talk(SAY_DEATH); } - // Note: This seems like a very complicated fix. The fix needs to be handled by the core, as implementation of limited-target AoE spells are still not limited. - void CastBloodboil() - { - // Get the Threat List - std::list<HostileReference*> m_threatlist = me->getThreatManager().getThreatList(); - - if (m_threatlist.empty()) // He doesn't have anyone in his threatlist, useless to continue - return; - - std::list<Unit*> targets; - std::list<HostileReference*>::const_iterator itr = m_threatlist.begin(); - for (; itr!= m_threatlist.end(); ++itr) //store the threat list in a different container - { - Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); - //only on alive players - if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER) - targets.push_back(target); - } - - //Sort the list of players - targets.sort(Trinity::ObjectDistanceOrderPred(me, false)); - //Resize so we only get top 5 - targets.resize(5); - - //Aura each player in the targets list with Bloodboil. Aura code copied+pasted from Aura command in Level3.cpp - /*SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_BLOODBOIL); - if (spellInfo) - { - for (std::list<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr) - { - Unit* target = *itr; - if (!target) return; - for (uint32 i = 0; i<3; ++i) - { - uint8 eff = spellInfo->Effect[i]; - if (eff >= TOTAL_SPELL_EFFECTS) - continue; - - Aura* Aur = new Aura(spellInfo, i, target, target, target); - target->AddAura(Aur); - } - } - }*/ - } - void RevertThreatOnTarget(uint64 guid) { if (Unit* unit = ObjectAccessor::GetUnit(*me, guid)) @@ -247,8 +199,7 @@ public: { if (BloodboilCount < 5) // Only cast it five times. { - //CastBloodboil(); // Causes issues on windows, so is commented out. - DoCastVictim(SPELL_BLOODBOIL); + DoCastAOE(SPELL_BLOODBOIL); ++BloodboilCount; BloodboilTimer = 10000*BloodboilCount; } @@ -274,7 +225,7 @@ public: { if (Phase1) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) { Phase1 = false; @@ -327,7 +278,41 @@ public: }; +// 42005 - Bloodboil +class spell_gurtogg_bloodboil_bloodboil : public SpellScriptLoader +{ + public: + spell_gurtogg_bloodboil_bloodboil() : SpellScriptLoader("spell_gurtogg_bloodboil_bloodboil") { } + + class spell_gurtogg_bloodboil_bloodboil_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gurtogg_bloodboil_bloodboil_SpellScript); + + void FilterTargets(std::list<WorldObject*>& targets) + { + if (targets.size() <= 5) + return; + + // Sort the list of players + targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), false)); + // Resize so we only get top 5 + targets.resize(5); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gurtogg_bloodboil_bloodboil_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_gurtogg_bloodboil_bloodboil_SpellScript(); + } +}; + void AddSC_boss_gurtogg_bloodboil() { new boss_gurtogg_bloodboil(); + new spell_gurtogg_bloodboil_bloodboil(); } diff --git a/src/server/scripts/Outland/CMakeLists.txt b/src/server/scripts/Outland/CMakeLists.txt index 414a3bce14a..0c69a236ef8 100644 --- a/src/server/scripts/Outland/CMakeLists.txt +++ b/src/server/scripts/Outland/CMakeLists.txt @@ -112,7 +112,7 @@ set(scripts_STAT_SRCS Outland/BlackTemple/instance_black_temple.cpp Outland/BlackTemple/boss_reliquary_of_souls.cpp Outland/BlackTemple/boss_warlord_najentus.cpp - Outland/BlackTemple/boss_bloodboil.cpp + Outland/BlackTemple/boss_gurtogg_bloodboil.cpp Outland/BlackTemple/boss_illidan.cpp Outland/zone_shadowmoon_valley.cpp Outland/zone_blades_edge_mountains.cpp diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 5ae0e1601c5..245ec7e88cf 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -39,9 +39,11 @@ enum DeathKnightSpells SPELL_DK_DEATH_COIL_DAMAGE = 47632, SPELL_DK_DEATH_COIL_HEAL = 47633, SPELL_DK_DEATH_STRIKE_HEAL = 45470, + SPELL_DK_FROST_FEVER = 55095, SPELL_DK_FROST_PRESENCE = 48263, SPELL_DK_FROST_PRESENCE_TRIGGERED = 61261, SPELL_DK_GHOUL_EXPLODE = 47496, + SPELL_DK_GLYPH_OF_DISEASE = 63334, SPELL_DK_GLYPH_OF_ICEBOUND_FORTITUDE = 58625, SPELL_DK_IMPROVED_BLOOD_PRESENCE_R1 = 50365, SPELL_DK_IMPROVED_FROST_PRESENCE_R1 = 50384, @@ -51,6 +53,7 @@ enum DeathKnightSpells SPELL_DK_ITEM_SIGIL_VENGEFUL_HEART = 64962, SPELL_DK_ITEM_T8_MELEE_4P_BONUS = 64736, SPELL_DK_MASTER_OF_GHOULS = 52143, + SPELL_DK_BLOOD_PLAGUE = 55078, SPELL_DK_RAISE_DEAD_USE_REAGENT = 48289, SPELL_DK_RUNIC_POWER_ENERGIZE = 49088, SPELL_DK_SCENT_OF_BLOOD = 50422, @@ -933,6 +936,91 @@ class spell_dk_improved_unholy_presence : public SpellScriptLoader } }; +// ID - 50842 Pestilence +class spell_dk_pestilence : public SpellScriptLoader +{ + public: + spell_dk_pestilence() : SpellScriptLoader("spell_dk_pestilence") { } + + class spell_dk_pestilence_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dk_pestilence_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_DK_GLYPH_OF_DISEASE) + || !sSpellMgr->GetSpellInfo(SPELL_DK_BLOOD_PLAGUE) + || !sSpellMgr->GetSpellInfo(SPELL_DK_FROST_FEVER)) + return false; + return true; + } + + void OnHit(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + Unit* hitUnit = GetHitUnit(); + Unit* victim = GetExplTargetUnit(); + + if (!victim) + return; + + if (victim != hitUnit || caster->HasAura(SPELL_DK_GLYPH_OF_DISEASE)) + { + if (Aura* aurOld = victim->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID())) // Check Blood Plague application on victim. + { + if (AuraEffect* aurEffOld = aurOld->GetEffect(EFFECT_0)) + { + float donePct = aurEffOld->GetDonePct(); + float critChance = aurEffOld->GetCritChance(); + + caster->CastSpell(hitUnit, SPELL_DK_BLOOD_PLAGUE, true); // Spread the disease to hitUnit. + + if (Aura* aurNew = hitUnit->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID())) // Check Blood Plague application on hitUnit. + { + if (AuraEffect* aurEffNew = aurNew->GetEffect(EFFECT_0)) + { + aurEffNew->SetCritChance(critChance); // Blood Plague can crit if caster has T9. + aurEffNew->SetDonePct(donePct); + aurEffNew->SetDamage(caster->SpellDamageBonusDone(hitUnit, aurEffNew->GetSpellInfo(), std::max(aurEffNew->GetAmount(), 0), DOT) * donePct); + } + } + } + } + + if (Aura* aurOld = victim->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID())) // Check Frost Fever application on victim. + { + if (AuraEffect* aurEffOld = aurOld->GetEffect(EFFECT_0)) + { + float donePct = aurEffOld->GetDonePct(); + + caster->CastSpell(hitUnit, SPELL_DK_FROST_FEVER, true); // Spread the disease to hitUnit. + + if (Aura* aurNew = hitUnit->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID())) // Check Frost Fever application on hitUnit. + { + if (AuraEffect* aurEffNew = aurNew->GetEffect(EFFECT_0)) + { + aurEffNew->SetDonePct(donePct); + aurEffNew->SetDamage(caster->SpellDamageBonusDone(hitUnit, aurEffNew->GetSpellInfo(), std::max(aurEffNew->GetAmount(), 0), DOT) * donePct); + } + } + } + } + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_dk_pestilence_SpellScript::OnHit, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_dk_pestilence_SpellScript(); + } +}; + + // 48266 - Blood Presence // 48263 - Frost Presence // 48265 - Unholy Presence @@ -1467,6 +1555,7 @@ void AddSC_deathknight_spell_scripts() new spell_dk_improved_blood_presence(); new spell_dk_improved_frost_presence(); new spell_dk_improved_unholy_presence(); + new spell_dk_pestilence(); new spell_dk_presence(); new spell_dk_raise_dead(); new spell_dk_rune_tap_party(); diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index 3f935077b22..4571798506e 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -518,7 +518,7 @@ class spell_warl_haunt : public SpellScriptLoader { PrepareSpellScript(spell_warl_haunt_SpellScript); - void HandleOnHit() + void HandleAfterHit() { if (Aura* aura = GetHitAura()) if (AuraEffect* aurEff = aura->GetEffect(EFFECT_1)) @@ -527,7 +527,7 @@ class spell_warl_haunt : public SpellScriptLoader void Register() override { - OnHit += SpellHitFn(spell_warl_haunt_SpellScript::HandleOnHit); + AfterHit += SpellHitFn(spell_warl_haunt_SpellScript::HandleAfterHit); } }; diff --git a/src/server/scripts/World/CMakeLists.txt b/src/server/scripts/World/CMakeLists.txt index 7d1b46732cf..56a0a1eb4c7 100644 --- a/src/server/scripts/World/CMakeLists.txt +++ b/src/server/scripts/World/CMakeLists.txt @@ -8,20 +8,11 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +file(GLOB_RECURSE sources_World World/*.cpp World/*.h) + set(scripts_STAT_SRCS ${scripts_STAT_SRCS} - World/achievement_scripts.cpp - World/areatrigger_scripts.cpp - World/boss_emerald_dragons.cpp - World/chat_log.cpp - World/go_scripts.cpp - World/guards.cpp - World/item_scripts.cpp - World/mob_generic_creature.cpp - World/npc_innkeeper.cpp - World/npc_professions.cpp - World/npc_taxi.cpp - World/npcs_special.cpp + ${sources_World} ) message(" -> Prepared: World") diff --git a/src/server/scripts/World/action_ip_logger.cpp b/src/server/scripts/World/action_ip_logger.cpp new file mode 100644 index 00000000000..057f3d6ee36 --- /dev/null +++ b/src/server/scripts/World/action_ip_logger.cpp @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "Channel.h" +#include "Guild.h" +#include "Group.h" + +enum IPLoggingTypes +{ + + // AccountActionIpLogger(); + ACCOUNT_LOGIN = 0, + ACCOUNT_FAIL_LOGIN = 1, + ACCOUNT_CHANGE_PW = 2, + ACCOUNT_CHANGE_PW_FAIL = 3, // Only two types of account changes exist... + ACCOUNT_CHANGE_EMAIL = 4, + ACCOUNT_CHANGE_EMAIL_FAIL = 5, // ...so we log them individually + // OBSOLETE - ACCOUNT_LOGOUT = 6, /* Can not be logged. We still keep the type however */ + // CharacterActionIpLogger(); + CHARACTER_CREATE = 7, + CHARACTER_LOGIN = 8, + CHARACTER_LOGOUT = 9, + // CharacterDeleteActionIpLogger(); + CHARACTER_DELETE = 10, + CHARACTER_FAILED_DELETE = 11, + // AccountActionIpLogger(), CharacterActionIpLogger(), CharacterActionIpLogger(); + UNKNOWN_ACTION = 12 +}; + +class AccountActionIpLogger : public AccountScript +{ + public: + AccountActionIpLogger() : AccountScript("AccountActionIpLogger") { } + + // We log last_ip instead of last_attempt_ip, as login was successful + // ACCOUNT_LOGIN = 0 + void OnAccountLogin(uint32 accountId) override + { + AccountIPLogAction(accountId, ACCOUNT_LOGIN); + } + + // We log last_attempt_ip instead of last_ip, as failed login doesn't necessarily mean approperiate user + // ACCOUNT_FAIL_LOGIN = 1 + void OnFailedAccountLogin(uint32 accountId) override + { + AccountIPLogAction(accountId, ACCOUNT_FAIL_LOGIN); + } + + // ACCOUNT_CHANGE_PW = 2 + void OnPasswordChange(uint32 accountId) override + { + AccountIPLogAction(accountId, ACCOUNT_CHANGE_PW); + } + + // ACCOUNT_CHANGE_PW_FAIL = 3 + void OnFailedPasswordChange(uint32 accountId) override + { + AccountIPLogAction(accountId, ACCOUNT_CHANGE_PW_FAIL); + } + + // Registration Email can NOT be changed apart from GM level users. Thus, we do not require to log them... + // ACCOUNT_CHANGE_EMAIL = 4 + void OnEmailChange(uint32 accountId) override + { + AccountIPLogAction(accountId, ACCOUNT_CHANGE_EMAIL); // ... they get logged by gm command logger anyway + } + + // ACCOUNT_CHANGE_EMAIL_FAIL = 5 + void OnFailedEmailChange(uint32 accountId) override + { + AccountIPLogAction(accountId, ACCOUNT_CHANGE_EMAIL_FAIL); + } + + /* It's impossible to log the account logout process out of character selection - shouldn't matter anyway, + * as ip doesn't change through playing (obviously).*/ + // ACCOUNT_LOGOUT = 6 + void AccountIPLogAction(uint32 accountId, IPLoggingTypes aType) + { + // Action IP Logger is only intialized if config is set up + // Else, this script isn't loaded in the first place: We require no config check. + + // We declare all the required variables + uint32 playerGuid = accountId; + uint32 characterGuid = 0; + std::string systemNote = "ERROR"; // "ERROR" is a placeholder here. We change it later. + + // With this switch, we change systemNote so that we have a more accurate phrasing of what type it is. + // Avoids Magicnumbers in SQL table + switch (aType) + { + case ACCOUNT_LOGIN: + systemNote = "Logged on Successful AccountLogin"; + break; + case ACCOUNT_FAIL_LOGIN: + systemNote = "Logged on Failed AccountLogin"; + break; + case ACCOUNT_CHANGE_PW: + systemNote = "Logged on Successful Account Password Change"; + break; + case ACCOUNT_CHANGE_PW_FAIL: + systemNote = "Logged on Failed Account Password Change"; + break; + case ACCOUNT_CHANGE_EMAIL: + systemNote = "Logged on Successful Account Email Change"; + break; + case ACCOUNT_CHANGE_EMAIL_FAIL: + systemNote = "Logged on Failed Account Email Change"; + break; + /*case ACCOUNT_LOGOUT: + systemNote = "Logged on AccountLogout"; //Can not be logged + break;*/ + // Neither should happen. Ever. Period. If it does, call Ghostbusters and all your local software defences to investigate. + case UNKNOWN_ACTION: + default: + systemNote = "ERROR! Unknown action!"; + break; + } + + // Once we have done everything, we can insert the new log. + // Seeing as the time differences should be minimal, we do not get unixtime and the timestamp right now; + // Rather, we let it be added with the SQL query. + if (aType != ACCOUNT_FAIL_LOGIN) + { + // As we can assume most account actions are NOT failed login, so this is the more accurate check. + // For those, we need last_ip... + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ALDL_IP_LOGGING); + + stmt->setUInt32(0, playerGuid); + stmt->setUInt32(1, characterGuid); + stmt->setUInt8(2, aType); + stmt->setUInt32(3, playerGuid); + stmt->setString(4, systemNote.c_str()); + LoginDatabase.Execute(stmt); + } + else // ... but for failed login, we query last_attempt_ip from account table. Which we do with an unique query + { + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FACL_IP_LOGGING); + + stmt->setUInt32(0, playerGuid); + stmt->setUInt32(1, characterGuid); + stmt->setUInt8(2, aType); + stmt->setUInt32(3, playerGuid); + stmt->setString(4, systemNote.c_str()); + LoginDatabase.Execute(stmt); + } + return; + } +}; + +class CharacterActionIpLogger : public PlayerScript +{ + public: + CharacterActionIpLogger() : PlayerScript("CharacterActionIpLogger") { } + + // CHARACTER_CREATE = 7 + void OnCreate(Player* player) override + { + CharacterIPLogAction(player, CHARACTER_CREATE); + } + + // CHARACTER_LOGIN = 8 + void OnLogin(Player* player, bool /*firstLogin*/) override + { + CharacterIPLogAction(player, CHARACTER_LOGIN); + } + + // CHARACTER_LOGOUT = 9 + void OnLogout(Player* player) override + { + CharacterIPLogAction(player, CHARACTER_LOGOUT); + } + + // CHARACTER_DELETE = 10 + // CHARACTER_FAILED_DELETE = 11 + // We don't log either here - they require a guid + + // UNKNOWN_ACTION = 12 + // There is no real hook we could use for that. + // Shouldn't happen anyway, should it ? Nothing to see here. + + /// Logs a number of actions done by players with an IP + void CharacterIPLogAction(Player* player, IPLoggingTypes aType) + { + // Action IP Logger is only intialized if config is set up + // Else, this script isn't loaded in the first place: We require no config check. + + // We declare all the required variables + uint32 playerGuid = player->GetSession()->GetAccountId(); + uint32 characterGuid = player->GetGUIDLow(); + const std::string currentIp = player->GetSession()->GetRemoteAddress(); + std::string systemNote = "ERROR"; // "ERROR" is a placeholder here. We change it... + + // ... with this switch, so that we have a more accurate phrasing of what type it is + switch (aType) + { + case CHARACTER_CREATE: + systemNote = "Logged on CharacterCreate"; + break; + case CHARACTER_LOGIN: + systemNote = "Logged on CharacterLogin"; + break; + case CHARACTER_LOGOUT: + systemNote = "Logged on CharacterLogout"; + break; + case CHARACTER_DELETE: + systemNote = "Logged on CharacterDelete"; + break; + case CHARACTER_FAILED_DELETE: + systemNote = "Logged on Failed CharacterDelete"; + break; + // Neither should happen. Ever. Period. If it does, call Mythbusters. + case UNKNOWN_ACTION: + default: + systemNote = "ERROR! Unknown action!"; + break; + } + + // Once we have done everything, we can insert the new log. + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_CHAR_IP_LOGGING); + + stmt->setUInt32(0, playerGuid); + stmt->setUInt32(1, characterGuid); + stmt->setUInt8(2, aType); + stmt->setString(3, currentIp.c_str()); // We query the ip here. + stmt->setString(4, systemNote.c_str()); + // Seeing as the time differences should be minimal, we do not get unixtime and the timestamp right now; + // Rather, we let it be added with the SQL query. + + LoginDatabase.Execute(stmt); + return; + } +}; + +class CharacterDeleteActionIpLogger : public PlayerScript +{ +public: + CharacterDeleteActionIpLogger() : PlayerScript("CharacterDeleteActionIpLogger") { } + + // CHARACTER_DELETE = 10 + void OnDelete(uint64 guid, uint32 accountId) override + { + DeleteIPLogAction(guid, accountId, CHARACTER_DELETE); + } + + // CHARACTER_FAILED_DELETE = 11 + void OnFailedDelete(uint64 guid, uint32 accountId) override + { + DeleteIPLogAction(guid, accountId, CHARACTER_FAILED_DELETE); + } + + void DeleteIPLogAction(uint64 guid, uint32 playerGuid, IPLoggingTypes aType) + { + // Action IP Logger is only intialized if config is set up + // Else, this script isn't loaded in the first place: We require no config check. + + // We declare all the required variables + uint32 characterGuid = GUID_LOPART(guid); // We have no access to any member function of Player* or WorldSession*. So use old-fashioned way. + // Query playerGuid/accountId, as we only have characterGuid + std::string systemNote = "ERROR"; // "ERROR" is a placeholder here. We change it later. + + // With this switch, we change systemNote so that we have a more accurate phrasing of what type it is. + // Avoids Magicnumbers in SQL table + switch (aType) + { + case CHARACTER_DELETE: + systemNote = "Logged on CharacterDelete"; + break; + case CHARACTER_FAILED_DELETE: + systemNote = "Logged on Failed CharacterDelete"; + break; + // Neither should happen. Ever. Period. If it does, call to whatever god you have for mercy and guidance. + case UNKNOWN_ACTION: + default: + systemNote = "ERROR! Unknown action!"; + break; + } + + // Once we have done everything, we can insert the new log. + PreparedStatement* stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_INS_ALDL_IP_LOGGING); + + stmt2->setUInt32(0, playerGuid); + stmt2->setUInt32(1, characterGuid); + stmt2->setUInt8(2, aType); + stmt2->setUInt32(3, playerGuid); + stmt2->setString(4, systemNote.c_str()); + // Seeing as the time differences should be minimal, we do not get unixtime and the timestamp right now; + // Rather, we let it be added with the SQL query. + + LoginDatabase.Execute(stmt2); + return; + } +}; + + +void AddSC_action_ip_logger() +{ + new AccountActionIpLogger(); + new CharacterActionIpLogger(); + new CharacterDeleteActionIpLogger(); +} diff --git a/src/server/scripts/World/areatrigger_scripts.cpp b/src/server/scripts/World/areatrigger_scripts.cpp index fb438c38efb..4393f72eb1b 100644 --- a/src/server/scripts/World/areatrigger_scripts.cpp +++ b/src/server/scripts/World/areatrigger_scripts.cpp @@ -51,11 +51,7 @@ enum CoilfangGOs class AreaTrigger_at_coilfang_waterfall : public AreaTriggerScript { public: - - AreaTrigger_at_coilfang_waterfall() - : AreaTriggerScript("at_coilfang_waterfall") - { - } + AreaTrigger_at_coilfang_waterfall() : AreaTriggerScript("at_coilfang_waterfall") { } bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override { @@ -83,11 +79,7 @@ enum LegionTeleporter class AreaTrigger_at_legion_teleporter : public AreaTriggerScript { public: - - AreaTrigger_at_legion_teleporter() - : AreaTriggerScript("at_legion_teleporter") - { - } + AreaTrigger_at_legion_teleporter() : AreaTriggerScript("at_legion_teleporter") { } bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override { @@ -125,11 +117,7 @@ enum StormwrightShelf class AreaTrigger_at_stormwright_shelf : public AreaTriggerScript { public: - - AreaTrigger_at_stormwright_shelf() - : AreaTriggerScript("at_stormwright_shelf") - { - } + AreaTrigger_at_stormwright_shelf() : AreaTriggerScript("at_stormwright_shelf") { } bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override { @@ -153,11 +141,7 @@ enum ScentLarkorwi class AreaTrigger_at_scent_larkorwi : public AreaTriggerScript { public: - - AreaTrigger_at_scent_larkorwi() - : AreaTriggerScript("at_scent_larkorwi") - { - } + AreaTrigger_at_scent_larkorwi() : AreaTriggerScript("at_scent_larkorwi") { } bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override { @@ -184,11 +168,7 @@ enum AtLastRites class AreaTrigger_at_last_rites : public AreaTriggerScript { public: - - AreaTrigger_at_last_rites() - : AreaTriggerScript("at_last_rites") - { - } + AreaTrigger_at_last_rites() : AreaTriggerScript("at_last_rites") { } bool OnTrigger(Player* player, AreaTriggerEntry const* trigger) override { @@ -246,7 +226,6 @@ enum Waygate class AreaTrigger_at_sholazar_waygate : public AreaTriggerScript { public: - AreaTrigger_at_sholazar_waygate() : AreaTriggerScript("at_sholazar_waygate") { } bool OnTrigger(Player* player, AreaTriggerEntry const* trigger) override diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp index ca00b0fc352..4bb88a560bb 100644 --- a/src/server/scripts/World/go_scripts.cpp +++ b/src/server/scripts/World/go_scripts.cpp @@ -118,7 +118,8 @@ public: enum GildedBrazier { - NPC_STILLBLADE = 17716, + NPC_STILLBLADE = 17716, + QUEST_THE_FIRST_TRIAL = 9678 }; class go_gilded_brazier : public GameObjectScript @@ -130,7 +131,7 @@ public: { if (go->GetGoType() == GAMEOBJECT_TYPE_GOOBER) { - if (player->GetQuestStatus(9678) == QUEST_STATUS_INCOMPLETE) + if (player->GetQuestStatus(QUEST_THE_FIRST_TRIAL) == QUEST_STATUS_INCOMPLETE) { if (Creature* Stillblade = player->SummonCreature(NPC_STILLBLADE, 8106.11f, -7542.06f, 151.775f, 3.02598f, TEMPSUMMON_DEAD_DESPAWN, 60000)) Stillblade->AI()->AttackStart(player); diff --git a/src/server/scripts/World/guards.cpp b/src/server/scripts/World/guards.cpp index 21a81d37868..a156a41fcef 100644 --- a/src/server/scripts/World/guards.cpp +++ b/src/server/scripts/World/guards.cpp @@ -387,7 +387,7 @@ public: void AddSC_guards() { - new guard_generic; - new guard_shattrath_aldor; - new guard_shattrath_scryer; + new guard_generic(); + new guard_shattrath_aldor(); + new guard_shattrath_scryer(); } diff --git a/src/server/scripts/World/mob_generic_creature.cpp b/src/server/scripts/World/mob_generic_creature.cpp index 30666d5d2ea..2eb91b7b8fe 100644 --- a/src/server/scripts/World/mob_generic_creature.cpp +++ b/src/server/scripts/World/mob_generic_creature.cpp @@ -229,6 +229,6 @@ public: void AddSC_generic_creature() { //new generic_creature; - new trigger_periodic; + new trigger_periodic(); //new trigger_death; } diff --git a/src/server/scripts/World/npc_innkeeper.cpp b/src/server/scripts/World/npc_innkeeper.cpp index b647cccf8ea..be56e57cc9d 100644 --- a/src/server/scripts/World/npc_innkeeper.cpp +++ b/src/server/scripts/World/npc_innkeeper.cpp @@ -134,6 +134,6 @@ public: void AddSC_npc_innkeeper() { - new npc_innkeeper; + new npc_innkeeper(); } diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index c32edff09bc..e67823a2939 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -185,7 +185,6 @@ public: } void MoveInLineOfSight(Unit* who) override - { if (!SpawnAssoc) return; @@ -1520,7 +1519,10 @@ class npc_brewfest_reveler : public CreatureScript enum TrainingDummy { NPC_ADVANCED_TARGET_DUMMY = 2674, - NPC_TARGET_DUMMY = 2673 + NPC_TARGET_DUMMY = 2673, + + EVENT_TD_CHECK_COMBAT = 1, + EVENT_TD_DESPAWN = 2 }; class npc_training_dummy : public CreatureScript @@ -1533,20 +1535,22 @@ public: npc_training_dummyAI(Creature* creature) : ScriptedAI(creature) { SetCombatMovement(false); - entry = creature->GetEntry(); } - uint32 entry; - uint32 resetTimer; - uint32 despawnTimer; + EventMap _events; + std::unordered_map<uint64, time_t> _damageTimes; void Reset() override { me->SetControlled(true, UNIT_STATE_STUNNED);//disable rotate me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);//imune to knock aways like blast wave - resetTimer = 5000; - despawnTimer = 15000; + _events.Reset(); + _damageTimes.clear(); + if (me->GetEntry() != NPC_ADVANCED_TARGET_DUMMY && me->GetEntry() != NPC_TARGET_DUMMY) + _events.ScheduleEvent(EVENT_TD_CHECK_COMBAT, 1000); + else + _events.ScheduleEvent(EVENT_TD_DESPAWN, 15000); } void EnterEvadeMode() override @@ -1557,37 +1561,52 @@ public: Reset(); } - void DamageTaken(Unit* /*doneBy*/, uint32& damage) override + void DamageTaken(Unit* doneBy, uint32& damage) override { - resetTimer = 5000; + me->AddThreat(doneBy, float(damage)); // just to create threat reference + _damageTimes[doneBy->GetGUID()] = time(NULL); damage = 0; } void UpdateAI(uint32 diff) override { - if (!UpdateVictim()) + if (!me->IsInCombat()) return; if (!me->HasUnitState(UNIT_STATE_STUNNED)) me->SetControlled(true, UNIT_STATE_STUNNED);//disable rotate - if (entry != NPC_ADVANCED_TARGET_DUMMY && entry != NPC_TARGET_DUMMY) + _events.Update(diff); + + if (uint32 eventId = _events.ExecuteEvent()) { - if (resetTimer <= diff) + switch (eventId) { - EnterEvadeMode(); - resetTimer = 5000; + case EVENT_TD_CHECK_COMBAT: + { + time_t now = time(NULL); + for (std::unordered_map<uint64, time_t>::iterator itr = _damageTimes.begin(); itr != _damageTimes.end();) + { + // If unit has not dealt damage to training dummy for 5 seconds, remove him from combat + if (itr->second < now - 5) + { + if (Unit* unit = ObjectAccessor::GetUnit(*me, itr->first)) + unit->getHostileRefManager().deleteReference(me); + + itr = _damageTimes.erase(itr); + } + else + ++itr; + } + _events.ScheduleEvent(EVENT_TD_CHECK_COMBAT, 1000); + break; + } + case EVENT_TD_DESPAWN: + me->DespawnOrUnsummon(1); + break; + default: + break; } - else - resetTimer -= diff; - return; - } - else - { - if (despawnTimer <= diff) - me->DespawnOrUnsummon(); - else - despawnTimer -= diff; } } diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index de1e5b992e6..488ff18dca4 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -69,6 +69,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_UPD_MUTE_TIME, "UPDATE account SET mutetime = ? , mutereason = ? , muteby = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_MUTE_TIME_LOGIN, "UPDATE account SET mutetime = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_LAST_IP, "UPDATE account SET last_ip = ? WHERE username = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_UPD_LAST_ATTEMPT_IP, "UPDATE account SET last_attempt_ip = ? WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_ACCOUNT_ONLINE, "UPDATE account SET online = 1 WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_UPTIME_PLAYERS, "UPDATE uptime SET uptime = ?, maxplayers = ? WHERE realmid = ? AND starttime = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_OLD_LOGS, "DELETE FROM logs WHERE (time + ?) < ?", CONNECTION_ASYNC); @@ -90,12 +91,21 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_ACCOUNT_RECRUITER, "SELECT 1 FROM account WHERE recruiter = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_BANS, "SELECT 1 FROM account_banned WHERE id = ? AND active = 1 UNION SELECT 1 FROM ip_banned WHERE ip = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_WHOIS, "SELECT username, email, last_ip FROM account WHERE id = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_LAST_ATTEMPT_IP, "SELECT last_attempt_ip FROM account WHERE id = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_LAST_IP, "SELECT last_ip FROM account WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL, "SELECT allowedSecurityLevel from realmlist WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_DEL_ACCOUNT, "DELETE FROM account WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_IP2NATION_COUNTRY, "SELECT c.country FROM ip2nationCountries c, ip2nation i WHERE i.ip < ? AND c.code = i.country ORDER BY i.ip DESC LIMIT 0,1", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_AUTOBROADCAST, "SELECT id, weight, text FROM autobroadcast WHERE realmid = ? OR realmid = -1", CONNECTION_SYNCH); PrepareStatement(LOGIN_GET_EMAIL_BY_ID, "SELECT email FROM account WHERE id = ?", CONNECTION_SYNCH); - + // 0: uint32, 1: uint32, 2: uint8, 3: uint32, 4: string // Complete name: "Login_Insert_AccountLoginDeLete_IP_Logging" + PrepareStatement(LOGIN_INS_ALDL_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, (SELECT last_ip FROM account WHERE id = ?), ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC); + // 0: uint32, 1: uint32, 2: uint8, 3: uint32, 4: string // Complete name: "Login_Insert_FailedAccountLogin_IP_Logging" + PrepareStatement(LOGIN_INS_FACL_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, (SELECT last_attempt_ip FROM account WHERE id = ?), ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC); + // 0: uint32, 1: uint32, 2: uint8, 3: string, 4: string // Complete name: "Login_Insert_CharacterDelete_IP_Logging" + PrepareStatement(LOGIN_INS_CHAR_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC); + // 0: string, 1: string, 2: string // Complete name: "Login_Insert_Failed_Account_Login_due_password_IP_Logging" + PrepareStatement(LOGIN_INS_FALP_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES ((SELECT id FROM account WHERE username = ?), 0, 1, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS_BY_ID, "SELECT gmlevel, RealmID FROM account_access WHERE id = ? and (RealmID = ? OR RealmID = -1) ORDER BY gmlevel desc", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_SYNCH); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index 01f9fd973b6..604e9d39551 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -89,6 +89,7 @@ enum LoginDatabaseStatements LOGIN_UPD_MUTE_TIME, LOGIN_UPD_MUTE_TIME_LOGIN, LOGIN_UPD_LAST_IP, + LOGIN_UPD_LAST_ATTEMPT_IP, LOGIN_UPD_ACCOUNT_ONLINE, LOGIN_UPD_UPTIME_PLAYERS, LOGIN_DEL_OLD_LOGS, @@ -114,7 +115,13 @@ enum LoginDatabaseStatements LOGIN_DEL_ACCOUNT, LOGIN_SEL_IP2NATION_COUNTRY, LOGIN_SEL_AUTOBROADCAST, + LOGIN_SEL_LAST_ATTEMPT_IP, + LOGIN_SEL_LAST_IP, LOGIN_GET_EMAIL_BY_ID, + LOGIN_INS_ALDL_IP_LOGGING, + LOGIN_INS_FACL_IP_LOGGING, + LOGIN_INS_CHAR_IP_LOGGING, + LOGIN_INS_FALP_IP_LOGGING, LOGIN_SEL_ACCOUNT_ACCESS_BY_ID, LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp index 81825c9055b..350a258f455 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.cpp +++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp @@ -60,6 +60,7 @@ HANDLE WheatyExceptionReport::m_hReportFile; HANDLE WheatyExceptionReport::m_hDumpFile; HANDLE WheatyExceptionReport::m_hProcess; SymbolPairs WheatyExceptionReport::symbols; +std::stack<SymbolDetail> WheatyExceptionReport::symbolDetails; // Declare global instance of class WheatyExceptionReport g_WheatyExceptionReport; @@ -767,18 +768,21 @@ ULONG /*SymbolSize*/, PVOID UserContext) { - char szBuffer[1024 * 64]; + char szBuffer[WER_LARGE_BUFFER_SIZE]; + memset(szBuffer, 0, sizeof(szBuffer)); __try { ClearSymbols(); if (FormatSymbolValue(pSymInfo, (STACKFRAME64*)UserContext, szBuffer, sizeof(szBuffer))) - _tprintf(_T("\t%s\r\n"), szBuffer); + _tprintf(_T("%s"), szBuffer); } __except (EXCEPTION_EXECUTE_HANDLER) { - _tprintf(_T("punting on symbol %s\r\n"), pSymInfo->Name); + _tprintf(_T("punting on symbol %s, partial output:\r\n"), pSymInfo->Name); + if (szBuffer[0] != '\0') + _tprintf(_T("%s"), szBuffer); } return TRUE; @@ -797,12 +801,6 @@ unsigned /*cbBuffer*/) { char * pszCurrBuffer = pszBuffer; - // Indicate if the variable is a local or parameter - if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER) - pszCurrBuffer += sprintf(pszCurrBuffer, "Parameter "); - else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL) - pszCurrBuffer += sprintf(pszCurrBuffer, "Local "); - // If it's a function, don't do anything. if (pSym->Tag == SymTagFunction) // SymTagFunction from CVCONST.H from the DIA SDK return false; @@ -824,19 +822,25 @@ unsigned /*cbBuffer*/) // return false; } else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER) - { return false; // Don't try to report register variable - } else { pVariable = (DWORD_PTR)pSym->Address; // It must be a global variable } + pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); + + // Indicate if the variable is a local or parameter + if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER) + symbolDetails.top().Prefix = "Parameter "; + else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL) + symbolDetails.top().Prefix = "Local "; + // Determine if the variable is a user defined type (UDT). IF so, bHandled // will return true. bool bHandled; pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, pSym->ModBase, pSym->TypeIndex, - 0, pVariable, bHandled, pSym->Name, ""); + 0, pVariable, bHandled, pSym->Name, "", false, true); if (!bHandled) { @@ -844,15 +848,19 @@ unsigned /*cbBuffer*/) // variable. Based on the size, we're assuming it's a char, WORD, or // DWORD. BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase); - pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); + if (symbolDetails.top().Type.empty()) + symbolDetails.top().Type = rgBaseType[basicType]; // Emit the variable name - pszCurrBuffer += sprintf(pszCurrBuffer, "\'%s\'", pSym->Name); + if (pSym->Name[0] != '\0') + symbolDetails.top().Name = pSym->Name; - pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, pSym->Size, - (PVOID)pVariable); + char buffer[50]; + FormatOutputValue(buffer, basicType, pSym->Size, (PVOID)pVariable, sizeof(buffer)); + symbolDetails.top().Value = buffer; } + pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); return true; } @@ -868,13 +876,15 @@ DWORD dwTypeIndex, unsigned nestingLevel, DWORD_PTR offset, bool & bHandled, -char* Name, -char* suffix) +const char* Name, +char* /*suffix*/, +bool newSymbol, +bool logChildren) { bHandled = false; - if (!StoreSymbol(dwTypeIndex, offset)) - return pszCurrBuffer; + if (newSymbol) + pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); DWORD typeTag; if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag)) @@ -890,19 +900,39 @@ char* suffix) if (wcscmp(pwszTypeName, L"std::basic_string<char,std::char_traits<char>,std::allocator<char> >") == 0) { LocalFree(pwszTypeName); - pszCurrBuffer += sprintf(pszCurrBuffer, " %s", "std::string"); - pszCurrBuffer = FormatOutputValue(pszCurrBuffer, btStdString, 0, (PVOID)offset); - pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); + symbolDetails.top().Type = "std::string"; + char buffer[50]; + FormatOutputValue(buffer, btStdString, 0, (PVOID)offset, sizeof(buffer)); + symbolDetails.top().Value = buffer; + if (Name != NULL && Name[0] != '\0') + symbolDetails.top().Name = Name; bHandled = true; return pszCurrBuffer; } - pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName); + char buffer[200]; + wcstombs(buffer, pwszTypeName, sizeof(buffer)); + buffer[199] = '\0'; + if (Name != NULL && Name[0] != '\0') + { + symbolDetails.top().Type = buffer; + symbolDetails.top().Name = Name; + } + else if (buffer[0] != '\0') + symbolDetails.top().Name = buffer; + LocalFree(pwszTypeName); } + else if (Name != NULL && Name[0] != '\0') + symbolDetails.top().Name = Name; - if (strlen(suffix) > 0) - pszCurrBuffer += sprintf(pszCurrBuffer, "%s", suffix); + if (!StoreSymbol(dwTypeIndex, offset)) + { + // Skip printing address and base class if it has been printed already + if (typeTag == SymTagBaseClass) + bHandled = true; + return pszCurrBuffer; + } DWORD innerTypeID; switch (typeTag) @@ -910,11 +940,9 @@ char* suffix) case SymTagPointerType: if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID)) { -#define MAX_NESTING_LEVEL 5 - if (nestingLevel >= MAX_NESTING_LEVEL) - break; + if (Name != NULL && Name[0] != '\0') + symbolDetails.top().Name = Name; - pszCurrBuffer += sprintf(pszCurrBuffer, " %s", Name); BOOL isReference; SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference); @@ -922,44 +950,56 @@ char* suffix) memset(addressStr, 0, sizeof(addressStr)); if (isReference) - addressStr[0] = '&'; + symbolDetails.top().Suffix += "&"; else - addressStr[0] = '*'; + symbolDetails.top().Suffix += "*"; - DWORD_PTR address = *(PDWORD_PTR)offset; - if (address == NULL) - { - pwszTypeName; - if (SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMNAME, - &pwszTypeName)) - { - pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName); - LocalFree(pwszTypeName); - } + // Try to dereference the pointer in a try/except block since it might be invalid + DWORD_PTR address = DereferenceUnsafePointer(offset); - pszCurrBuffer += sprintf(pszCurrBuffer, "%s = NULL\r\n", addressStr); + char buffer[50]; + FormatOutputValue(buffer, btVoid, sizeof(PVOID), (PVOID)offset, sizeof(buffer)); + symbolDetails.top().Value = buffer; - bHandled = true; - return pszCurrBuffer; - } - else - { - FormatOutputValue(&addressStr[1], btVoid, sizeof(PVOID), (PVOID)offset); - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, - address, bHandled, "", addressStr); + if (nestingLevel >= WER_MAX_NESTING_LEVEL) + logChildren = false; + + // no need to log any children since the address is invalid anyway + if (address == NULL || address == DWORD_PTR(-1)) + logChildren = false; + + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + address, bHandled, Name, addressStr, false, logChildren); - if (!bHandled) + if (!bHandled) + { + BasicType basicType = GetBasicType(dwTypeIndex, modBase); + if (symbolDetails.top().Type.empty()) + symbolDetails.top().Type = rgBaseType[basicType]; + + if (address == NULL) + symbolDetails.top().Value = "NULL"; + else if (address == DWORD_PTR(-1)) + symbolDetails.top().Value = "<Unable to read memory>"; + else { - BasicType basicType = GetBasicType(dwTypeIndex, modBase); - pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); // Get the size of the child member ULONG64 length; SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length); - pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, length, (PVOID)address); - pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); - bHandled = true; - return pszCurrBuffer; + char buffer[50]; + FormatOutputValue(buffer, basicType, length, (PVOID)address, sizeof(buffer)); + symbolDetails.top().Value = buffer; } + bHandled = true; + return pszCurrBuffer; + } + else if (address == NULL) + symbolDetails.top().Value = "NULL"; + else if (address == DWORD_PTR(-1)) + { + symbolDetails.top().Value = "<Unable to read memory>"; + bHandled = true; + return pszCurrBuffer; } } break; @@ -970,13 +1010,80 @@ char* suffix) if (!SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag)) break; - if (innerTypeTag == SymTagPointerType) + switch (innerTypeTag) { - pszCurrBuffer += sprintf(pszCurrBuffer, " %s", Name); + case SymTagUDT: + if (nestingLevel >= WER_MAX_NESTING_LEVEL) + logChildren = false; + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); + break; + case SymTagPointerType: + if (Name != NULL && Name[0] != '\0') + symbolDetails.top().Name = Name; + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); + break; + case SymTagArrayType: + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); + break; + default: + break; + } + } + break; + case SymTagArrayType: + if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID)) + { + symbolDetails.top().HasChildren = true; + + BasicType basicType = btNoType; + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + offset, bHandled, Name, "", false, false); + + // Set Value back to an empty string since the Array object itself has no value, only its elements have + symbolDetails.top().Value = ""; + + DWORD elementsCount; + if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount)) + symbolDetails.top().Suffix += "[" + std::to_string(elementsCount) + "]"; + else + symbolDetails.top().Suffix += "[<unknown count>]"; - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, - offset, bHandled, "", ""); + if (!bHandled) + { + basicType = GetBasicType(dwTypeIndex, modBase); + if (symbolDetails.top().Type.empty()) + symbolDetails.top().Type = rgBaseType[basicType]; + bHandled = true; + } + + // Get the size of the child member + ULONG64 length; + SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length); + + char buffer[50]; + switch (basicType) + { + case btChar: + case btStdString: + FormatOutputValue(buffer, basicType, length, (PVOID)offset, sizeof(buffer)); + symbolDetails.top().Value = buffer; + break; + default: + for (DWORD index = 0; index < elementsCount && index < WER_MAX_ARRAY_ELEMENTS_COUNT; index++) + { + pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); + symbolDetails.top().Suffix += "[" + std::to_string(index) + "]"; + FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index), sizeof(buffer)); + symbolDetails.top().Value = buffer; + pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); + } + break; } + + return pszCurrBuffer; } break; case SymTagBaseType: @@ -1013,26 +1120,37 @@ char* suffix) return pszCurrBuffer; } - // Append a line feed - pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); - // Iterate through each of the children for (unsigned i = 0; i < dwChildrenCount; i++) { DWORD symTag; SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_SYMTAG, &symTag); - if (symTag == SymTagFunction || symTag == SymTagTypedef) + if (symTag == SymTagFunction || + symTag == SymTagEnum || + symTag == SymTagTypedef || + symTag == SymTagVTable) continue; - // Add appropriate indentation level (since this routine is recursive) - for (unsigned j = 0; j <= nestingLevel+1; j++) - pszCurrBuffer += sprintf(pszCurrBuffer, "\t"); + // Ignore static fields + DWORD dataKind; + SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_DATAKIND, &dataKind); + if (dataKind == DataIsStaticLocal || + dataKind == DataIsGlobal || + dataKind == DataIsStaticMember) + continue; + + + symbolDetails.top().HasChildren = true; + if (!logChildren) + { + bHandled = false; + return pszCurrBuffer; + } // Recurse for each of the child types bool bHandled2; BasicType basicType = GetBasicType(children.ChildId[i], modBase); - pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); // Get the offset of the child member, relative to its parent DWORD dwMemberOffset; @@ -1044,11 +1162,14 @@ char* suffix) pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, children.ChildId[i], nestingLevel+1, - dwFinalOffset, bHandled2, ""/*Name */, ""); + dwFinalOffset, bHandled2, ""/*Name */, "", true, true); // If the child wasn't a UDT, format it appropriately if (!bHandled2) { + if (symbolDetails.top().Type.empty()) + symbolDetails.top().Type = rgBaseType[basicType]; + // Get the real "TypeId" of the child. We need this for the // SymGetTypeInfo(TI_GET_TYPEID) call below. DWORD typeId; @@ -1059,75 +1180,75 @@ char* suffix) ULONG64 length; SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH, &length); - pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, - length, (PVOID)dwFinalOffset); - - pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); + char buffer[50]; + FormatOutputValue(buffer, basicType, length, (PVOID)dwFinalOffset, sizeof(buffer)); + symbolDetails.top().Value = buffer; } + + pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); } bHandled = true; return pszCurrBuffer; } -char * WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer, +void WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, -PVOID pAddress) +PVOID pAddress, +size_t bufferSize) { __try { switch (basicType) { case btChar: - pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%s\"", pAddress); + { + if (strlen((char*)pAddress) > bufferSize - 6) + pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, (char*)pAddress); + else + pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", (char*)pAddress); break; + } case btStdString: - pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%s\"", static_cast<std::string*>(pAddress)->c_str()); + { + std::string* value = static_cast<std::string*>(pAddress); + if (value->length() > bufferSize - 6) + pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, value->c_str()); + else + pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", value->c_str()); break; + } default: // Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!) if (length == 1) - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PBYTE)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PBYTE)pAddress); else if (length == 2) - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PWORD)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PWORD)pAddress); else if (length == 4) { if (basicType == btFloat) - { - pszCurrBuffer += sprintf(pszCurrBuffer, " = %f", *(PFLOAT)pAddress); - } - else if (basicType == btChar) - { - if (!IsBadStringPtr(*(PSTR*)pAddress, 32)) - { - pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%.31s\"", - *(PSTR*)pAddress); - } - else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", - *(PDWORD)pAddress); - } + pszCurrBuffer += sprintf(pszCurrBuffer, "%f", *(PFLOAT)pAddress); else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PDWORD)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PDWORD)pAddress); } else if (length == 8) { if (basicType == btFloat) { - pszCurrBuffer += sprintf(pszCurrBuffer, " = %lf", + pszCurrBuffer += sprintf(pszCurrBuffer, "%lf", *(double *)pAddress); } else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X", + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X", *(DWORD64*)pAddress); } else { #if _WIN64 - pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X", (DWORD64*)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X", (DWORD64*)pAddress); #else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", (PDWORD)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", (PDWORD)pAddress); #endif } break; @@ -1136,13 +1257,11 @@ PVOID pAddress) __except (EXCEPTION_EXECUTE_HANDLER) { #if _WIN64 - pszCurrBuffer += sprintf(pszCurrBuffer, " <Unable to read memory> = %I64X", (DWORD64*)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X <Unable to read memory>", (DWORD64*)pAddress); #else - pszCurrBuffer += sprintf(pszCurrBuffer, " <Unable to read memory> = %X", (PDWORD)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X <Unable to read memory>", (PDWORD)pAddress); #endif } - - return pszCurrBuffer; } BasicType @@ -1170,13 +1289,25 @@ WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase) return btNoType; } +DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer(DWORD_PTR address) +{ + __try + { + return *(PDWORD_PTR)address; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return DWORD_PTR(-1); + } +} + //============================================================================ // Helper function that writes to the report file, and allows the user to use // printf style formating //============================================================================ int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...) { - TCHAR szBuff[1024 * 64]; + TCHAR szBuff[WER_LARGE_BUFFER_SIZE]; int retValue; DWORD cbWritten; va_list argptr; @@ -1198,6 +1329,41 @@ bool WheatyExceptionReport::StoreSymbol(DWORD type, DWORD_PTR offset) void WheatyExceptionReport::ClearSymbols() { symbols.clear(); + while (!symbolDetails.empty()) + symbolDetails.pop(); +} + +char* WheatyExceptionReport::PushSymbolDetail(char* pszCurrBuffer) +{ + // Log current symbol and then add another to the stack to keep the hierarchy format + pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer); + symbolDetails.emplace(); + return pszCurrBuffer; +} + +char* WheatyExceptionReport::PopSymbolDetail(char* pszCurrBuffer) +{ + pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer); + symbolDetails.pop(); + return pszCurrBuffer; +} + +char* WheatyExceptionReport::PrintSymbolDetail(char* pszCurrBuffer) +{ + if (symbolDetails.empty()) + return pszCurrBuffer; + + // Don't log anything if has been logged already or if it's empty + if (symbolDetails.top().Logged || symbolDetails.top().empty()) + return pszCurrBuffer; + + // Add appropriate indentation level (since this routine is recursive) + for (size_t i = 0; i < symbolDetails.size(); i++) + pszCurrBuffer += sprintf(pszCurrBuffer, "\t"); + + pszCurrBuffer += sprintf(pszCurrBuffer, "%s\r\n", symbolDetails.top().ToString().c_str()); + + return pszCurrBuffer; } #endif // _WIN32 diff --git a/src/server/shared/Debugging/WheatyExceptionReport.h b/src/server/shared/Debugging/WheatyExceptionReport.h index e1cc3050929..9137b91aac9 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.h +++ b/src/server/shared/Debugging/WheatyExceptionReport.h @@ -5,12 +5,13 @@ #include <dbghelp.h> #include <set> -#if _MSC_VER < 1400 -# define countof(array) (sizeof(array) / sizeof(array[0])) -#else -# include <stdlib.h> -# define countof _countof -#endif // _MSC_VER < 1400 +#include <stdlib.h> +#include <stack> +#define countof _countof + +#define WER_MAX_ARRAY_ELEMENTS_COUNT 10 +#define WER_MAX_NESTING_LEVEL 5 +#define WER_LARGE_BUFFER_SIZE 1024 * 128 enum BasicType // Stolen from CVCONST.H in the DIA 2.0 SDK { @@ -37,40 +38,54 @@ enum BasicType // Stolen from CVCON btStdString = 101 }; +enum DataKind // Stolen from CVCONST.H in the DIA 2.0 SDK +{ + DataIsUnknown, + DataIsLocal, + DataIsStaticLocal, + DataIsParam, + DataIsObjectPtr, + DataIsFileStatic, + DataIsGlobal, + DataIsMember, + DataIsStaticMember, + DataIsConstant +}; + const char* const rgBaseType[] = { - " <user defined> ", // btNoType = 0, - " void ", // btVoid = 1, - " char* ", // btChar = 2, - " wchar_t* ", // btWChar = 3, - " signed char ", - " unsigned char ", - " int ", // btInt = 6, - " unsigned int ", // btUInt = 7, - " float ", // btFloat = 8, - " <BCD> ", // btBCD = 9, - " bool ", // btBool = 10, - " short ", - " unsigned short ", - " long ", // btLong = 13, - " unsigned long ", // btULong = 14, - " __int8 ", - " __int16 ", - " __int32 ", - " __int64 ", - " __int128 ", - " unsigned __int8 ", - " unsigned __int16 ", - " unsigned __int32 ", - " unsigned __int64 ", - " unsigned __int128 ", - " <currency> ", // btCurrency = 25, - " <date> ", // btDate = 26, - " VARIANT ", // btVariant = 27, - " <complex> ", // btComplex = 28, - " <bit> ", // btBit = 29, - " BSTR ", // btBSTR = 30, - " HRESULT " // btHresult = 31 + "<user defined>", // btNoType = 0, + "void", // btVoid = 1, + "char",//char* // btChar = 2, + "wchar_t*", // btWChar = 3, + "signed char", + "unsigned char", + "int", // btInt = 6, + "unsigned int", // btUInt = 7, + "float", // btFloat = 8, + "<BCD>", // btBCD = 9, + "bool", // btBool = 10, + "short", + "unsigned short", + "long", // btLong = 13, + "unsigned long", // btULong = 14, + "int8", + "int16", + "int32", + "int64", + "int128", + "uint8", + "uint16", + "uint32", + "uint64", + "uint128", + "<currency>", // btCurrency = 25, + "<date>", // btDate = 26, + "VARIANT", // btVariant = 27, + "<complex>", // btComplex = 28, + "<bit>", // btBit = 29, + "BSTR", // btBSTR = 30, + "HRESULT" // btHresult = 31 }; struct SymbolPair @@ -92,6 +107,39 @@ struct SymbolPair }; typedef std::set<SymbolPair> SymbolPairs; +struct SymbolDetail +{ + SymbolDetail() : Prefix(), Type(), Suffix(), Name(), Value(), Logged(false), HasChildren(false) {} + + std::string ToString() + { + Logged = true; + std::string formatted = Prefix + Type + Suffix; + if (!Name.empty()) + { + if (!formatted.empty()) + formatted += " "; + formatted += Name; + } + if (!Value.empty()) + formatted += " = " + Value; + return formatted; + } + + bool empty() const + { + return Value.empty() && !HasChildren; + } + + std::string Prefix; + std::string Type; + std::string Suffix; + std::string Name; + std::string Value; + bool Logged; + bool HasChildren; +}; + class WheatyExceptionReport { public: @@ -122,11 +170,12 @@ class WheatyExceptionReport static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME64 *, char * pszBuffer, unsigned cbBuffer); - static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, char*, char*); + static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, const char*, char*, bool, bool); - static char * FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress); + static void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize); static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase); + static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address); static int __cdecl _tprintf(const TCHAR * format, ...); @@ -141,6 +190,12 @@ class WheatyExceptionReport static HANDLE m_hDumpFile; static HANDLE m_hProcess; static SymbolPairs symbols; + static std::stack<SymbolDetail> symbolDetails; + + static char* PushSymbolDetail(char* pszCurrBuffer); + static char* PopSymbolDetail(char* pszCurrBuffer); + static char* PrintSymbolDetail(char* pszCurrBuffer); + }; extern WheatyExceptionReport g_WheatyExceptionReport; // global instance of class diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp index ffef61557fc..28bbe831a69 100644 --- a/src/server/shared/Utilities/Util.cpp +++ b/src/server/shared/Utilities/Util.cpp @@ -547,3 +547,12 @@ std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse return ss.str(); } + +uint32 EventMap::GetTimeUntilEvent(uint32 eventId) const +{ + for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr) + if (eventId == (itr->second & 0x0000FFFF)) + return itr->first - _time; + + return std::numeric_limits<uint32>::max(); +} diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h index d6ead607c55..648edf39abe 100644 --- a/src/server/shared/Utilities/Util.h +++ b/src/server/shared/Utilities/Util.h @@ -866,14 +866,7 @@ class EventMap * @param Id of the event. * @return Time of next event. */ - uint32 GetTimeUntilEvent(uint32 eventId) const - { - for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr) - if (eventId == (itr->second & 0x0000FFFF)) - return itr->first - _time; - - return std::numeric_limits<uint32>::max(); - } + uint32 GetTimeUntilEvent(uint32 eventId) const; private: /** diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index d1d2ef11848..78a29dbedf6 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -45,6 +45,7 @@ include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include ${CMAKE_SOURCE_DIR}/dep/gsoap ${CMAKE_SOURCE_DIR}/dep/sockets/include ${CMAKE_SOURCE_DIR}/dep/SFMT diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index f71ef5d064b..90f330bac42 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -1353,6 +1353,14 @@ Rate.Creature.Elite.RAREELITE.HP = 1 Rate.Creature.Elite.WORLDBOSS.HP = 1 # +# Creature.PickPocketRefillDelay +# Description: Time in seconds that the server will wait before refilling the pickpocket loot +# for a creature +# Default: 600 + +Creature.PickPocketRefillDelay = 600 + +# # ListenRange.Say # Description: Distance in which players can read say messages from creatures or # gameobjects. @@ -2735,6 +2743,13 @@ Logger.sql.sql=5,Console DBErrors Log.Async.Enable = 0 # +# Allow.IP.Based.Action.Logging +# Description: Logs actions, e.g. account login and logout to name a few, based on IP of current session. +# Default: 0 - (Disabled) +# 1 - (Enabled) + +Allow.IP.Based.Action.Logging = 0 +# ################################################################################################### ################################################################################################### diff --git a/src/tools/mmaps_generator/CMakeLists.txt b/src/tools/mmaps_generator/CMakeLists.txt index 591e0cc8e98..c0268680657 100644 --- a/src/tools/mmaps_generator/CMakeLists.txt +++ b/src/tools/mmaps_generator/CMakeLists.txt @@ -18,7 +18,9 @@ set(mmap_gen_Includes ${CMAKE_SOURCE_DIR}/dep/bzip2 ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include ${CMAKE_SOURCE_DIR}/src/server/shared ${CMAKE_SOURCE_DIR}/src/server/game/Conditions ${CMAKE_SOURCE_DIR}/src/server/collision diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp index cc24035b05e..131041e0cd2 100644 --- a/src/tools/mmaps_generator/MapBuilder.cpp +++ b/src/tools/mmaps_generator/MapBuilder.cpp @@ -77,8 +77,8 @@ namespace MMAP { for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it) { - (*it).second->clear(); - delete (*it).second; + (*it).m_tiles->clear(); + delete (*it).m_tiles; } delete m_terrainBuilder; @@ -97,9 +97,9 @@ namespace MMAP for (uint32 i = 0; i < files.size(); ++i) { mapID = uint32(atoi(files[i].substr(0,3).c_str())); - if (m_tiles.find(mapID) == m_tiles.end()) + if (std::find(m_tiles.begin(), m_tiles.end(), mapID) == m_tiles.end()) { - m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, new std::set<uint32>)); + m_tiles.emplace_back(MapTiles(mapID, new std::set<uint32>)); count++; } } @@ -109,8 +109,11 @@ namespace MMAP for (uint32 i = 0; i < files.size(); ++i) { mapID = uint32(atoi(files[i].substr(0,3).c_str())); - m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, new std::set<uint32>)); - count++; + if (std::find(m_tiles.begin(), m_tiles.end(), mapID) == m_tiles.end()) + { + m_tiles.emplace_back(MapTiles(mapID, new std::set<uint32>)); + count++; + } } printf("found %u.\n", count); @@ -118,8 +121,8 @@ namespace MMAP printf("Discovering tiles... "); for (TileList::iterator itr = m_tiles.begin(); itr != m_tiles.end(); ++itr) { - std::set<uint32>* tiles = (*itr).second; - mapID = (*itr).first; + std::set<uint32>* tiles = (*itr).m_tiles; + mapID = (*itr).m_mapId; sprintf(filter, "%03u*.vmtile", mapID); files.clear(); @@ -153,12 +156,12 @@ namespace MMAP /**************************************************************************/ std::set<uint32>* MapBuilder::getTileList(uint32 mapID) { - TileList::iterator itr = m_tiles.find(mapID); + TileList::iterator itr = std::find(m_tiles.begin(), m_tiles.end(), mapID); if (itr != m_tiles.end()) - return (*itr).second; + return (*itr).m_tiles; std::set<uint32>* tiles = new std::set<uint32>(); - m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, tiles)); + m_tiles.emplace_back(MapTiles(mapID, tiles)); return tiles; } @@ -169,9 +172,14 @@ namespace MMAP BuilderThreadPool* pool = threads > 0 ? new BuilderThreadPool() : NULL; + m_tiles.sort([](MapTiles a, MapTiles b) + { + return a.m_tiles->size() > b.m_tiles->size(); + }); + for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it) { - uint32 mapID = it->first; + uint32 mapID = it->m_mapId; if (!shouldSkipMap(mapID)) { if (threads > 0) diff --git a/src/tools/mmaps_generator/MapBuilder.h b/src/tools/mmaps_generator/MapBuilder.h index 86a6db2077c..08b87324d01 100644 --- a/src/tools/mmaps_generator/MapBuilder.h +++ b/src/tools/mmaps_generator/MapBuilder.h @@ -22,6 +22,7 @@ #include <vector> #include <set> #include <map> +#include <list> #include "TerrainBuilder.h" #include "IntermediateValues.h" @@ -39,7 +40,24 @@ using namespace VMAP; namespace MMAP { - typedef std::map<uint32, std::set<uint32>*> TileList; + struct MapTiles + { + MapTiles() : m_mapId(uint32(-1)), m_tiles(NULL) {} + + MapTiles(uint32 id, std::set<uint32>* tiles) : m_mapId(id), m_tiles(tiles) {} + ~MapTiles() {} + + uint32 m_mapId; + std::set<uint32>* m_tiles; + + bool operator==(uint32 id) + { + return m_mapId == id; + } + }; + + typedef std::list<MapTiles> TileList; + struct Tile { Tile() : chf(NULL), solid(NULL), cset(NULL), pmesh(NULL), dmesh(NULL) {} |