diff options
Diffstat (limited to 'src')
67 files changed, 1652 insertions, 1403 deletions
diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 1fdd01ad968..4e39ae0aca1 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -130,7 +130,7 @@ int main(int argc, char** argv) TC_LOG_INFO("server.authserver", "<Ctrl-C> to stop.\n"); TC_LOG_INFO("server.authserver", "Using configuration file %s.", configFile); - TC_LOG_WARN("server.authserver", "%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); + TC_LOG_INFO("server.authserver", "%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); // authserver PID file creation std::string pidFile = sConfigMgr->GetStringDefault("PidFile", ""); diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index e36433dd8c0..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; diff --git a/src/server/game/Battlegrounds/ArenaScore.h b/src/server/game/Battlegrounds/ArenaScore.h new file mode 100644 index 00000000000..fdeb13adc3d --- /dev/null +++ b/src/server/game/Battlegrounds/ArenaScore.h @@ -0,0 +1,63 @@ +/* + * 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); + + BuildObjectivesBlock(data); + } + + void BuildObjectivesBlock(WorldPacket& data) final + { + 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; // bgTeamId +}; + +#endif // TRINITY_ARENA_SCORE_H diff --git a/src/server/game/Battlegrounds/ArenaTeam.h b/src/server/game/Battlegrounds/ArenaTeam.h index 85372c35daa..d3b6342b273 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.h +++ b/src/server/game/Battlegrounds/ArenaTeam.h @@ -129,7 +129,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..4e077979b3e 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,9 +167,6 @@ 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; @@ -756,7 +755,7 @@ void Battleground::EndBattleground(uint32 winner) } else { - SetWinner(3); + SetWinner(3); // weird } SetStatus(STATUS_WAIT_LEAVE); @@ -771,49 +770,52 @@ 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); + + // bg team that the client expects is different to TeamId + // alliance 1, horde 0 + uint8 winnerTeam = winner == ALLIANCE ? WINNER_ALLIANCE : WINNER_HORDE; + uint8 loserTeam = winner == ALLIANCE ? WINNER_HORDE : WINNER_ALLIANCE; + + _arenaTeamScores[winnerTeam].Assign(winnerChange, winnerMatchmakerRating, winnerArenaTeam->GetName()); + _arenaTeamScores[loserTeam].Assign(loserChange, loserMatchmakerRating, 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, winnerArenaTeam->GetName()); + _arenaTeamScores[WINNER_HORDE].Assign(ARENA_TIMELIMIT_POINTS_LOSS, loserMatchmakerRating, 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 +960,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 @@ -1099,6 +1101,9 @@ void Battleground::Reset() delete itr->second; PlayerScores.clear(); + for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) + _arenaTeamScores[i].Reset(); + ResetBGSubclass(); } @@ -1349,47 +1354,47 @@ 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; + for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) + _arenaTeamScores[i].BuildRatingInfoBlock(data); + + for (uint8 i = 0; i < BG_TEAMS_COUNT; ++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 +1873,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..2904ec1dc7e 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -22,6 +22,7 @@ #include "Common.h" #include "SharedDefines.h" #include "DBCEnums.h" +#include "WorldPacket.h" class Creature; class GameObject; @@ -32,6 +33,7 @@ class WorldObject; class WorldPacket; class BattlegroundMap; +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,9 +610,54 @@ 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]; + 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); + + // should be old rating, new rating, and client will calculate rating change itself + data << uint32(ratingLost); + data << uint32(ratingWon); + data << uint32(MatchmakerRating); + } + + void BuildTeamInfoBlock(WorldPacket& data) + { + data << TeamName; + } + + void Reset() + { + RatingChange = 0; + MatchmakerRating = 0; + TeamName.clear(); + } + + int32 RatingChange; + uint32 MatchmakerRating; + std::string TeamName; + }; + + ArenaTeamScore _arenaTeamScores[BG_TEAMS_COUNT]; + // Limits uint32 m_LevelMin; uint32 m_LevelMax; 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 046e2588ad3..d9cedbc4546 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -82,7 +82,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..ae65721b516 --- /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*/) = 0; + + // 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 faa71fd2ffa..da0b00af40f 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp @@ -273,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); @@ -314,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/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 8e186e9d094..03180b35cb5 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -326,8 +326,8 @@ enum MapFlags enum AbilytyLearnType { - ABILITY_LEARNED_ON_GET_PROFESSION_SKILL = 1, - ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL = 2 + SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE = 1, // Spell state will update depending on skill value + SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN = 2 // Spell will be learned/removed together with entire skill }; enum ItemEnchantmentType @@ -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 - clientside display flag, real value can be different }; -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, diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 44f03b6978d..e960422cbbc 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) @@ -440,7 +450,7 @@ void LoadDBCStores(const std::string& dataPath) if (spellInfo->spellLevel) continue; - if (skillLine->learnOnGetSkill != ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL) + if (skillLine->AutolearnType != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) continue; sPetFamilySpellsStore[i].insert(spellInfo->Id); @@ -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 ec9d2dafbd2..2b01dfd70bc 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1535,23 +1535,6 @@ struct ScalingStatValuesEntry // uint32 displayOrder; // 19 m_sortIndex //}; -//struct SkillRaceClassInfoEntry{ -// uint32 id; // 0 m_ID -// uint32 skillId; // 1 m_skillID -// uint32 raceMask; // 2 m_raceMask -// uint32 classMask; // 3 m_classMask -// uint32 flags; // 4 m_flags -// uint32 reqLevel; // 5 m_minLevel -// uint32 skillTierId; // 6 m_skillTierID -// uint32 skillCostID; // 7 m_skillCostIndex -//}; - -//struct SkillTiersEntry{ -// uint32 id; // 0 m_ID -// uint32 skillValue[16]; // 1-17 m_cost -// uint32 maxSkillValue[16]; // 18-32 m_valueMax -//}; - struct SkillLineEntry { uint32 id; // 0 m_ID @@ -1578,12 +1561,33 @@ struct SkillLineAbilityEntry //uint32 classmaskNot; // 6 m_excludeClass uint32 req_skill_value; // 7 m_minSkillLineRank uint32 forward_spellid; // 8 m_supercededBySpell - uint32 learnOnGetSkill; // 9 m_acquireMethod + uint32 AutolearnType; // 9 m_acquireMethod uint32 max_value; // 10 m_trivialSkillLineRankHigh uint32 min_value; // 11 m_trivialSkillLineRankLow //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/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index c81ba409495..fd8aaff8159 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) @@ -1463,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); @@ -1527,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); @@ -2268,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_respawnDelay; } uint8 Creature::getLevelForTarget(WorldObject const* target) const @@ -2712,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/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/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index f2823cc1435..6a1c91456e5 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" @@ -1133,7 +1134,8 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) } // original spells - learnDefaultSpells(); + LearnDefaultSkills(); + LearnCustomSpells(); // original action bar for (PlayerCreateInfoActions::const_iterator action_itr = info->action.begin(); action_itr != info->action.end(); ++action_itr) @@ -2920,11 +2922,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*/) @@ -3827,34 +3828,14 @@ bool Player::addSpell(uint32 spellId, bool active, bool learning, bool dependent if (!pSkill) continue; - if (!Has310Flyer(false) && pSkill->id == SKILL_MOUNTS) + if (!HasSkill(pSkill->id)) + LearnDefaultSkill(pSkill->id, 0); + + if (pSkill->id == SKILL_MOUNTS && !Has310Flyer(false)) for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED && spellInfo->Effects[i].CalcValue() == 310) SetHas310Flyer(true); - - if (HasSkill(pSkill->id)) - continue; - - if (_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL || - // lockpicking/runeforging special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL - ((pSkill->id == SKILL_LOCKPICKING || pSkill->id == SKILL_RUNEFORGING) && _spell_idx->second->max_value == 0)) - { - switch (GetSkillRangeType(pSkill, _spell_idx->second->racemask != 0)) - { - case SKILL_RANGE_LANGUAGE: - SetSkill(pSkill->id, GetSkillStep(pSkill->id), 300, 300); - break; - case SKILL_RANGE_LEVEL: - SetSkill(pSkill->id, GetSkillStep(pSkill->id), 1, GetMaxSkillValueForLevel()); - break; - case SKILL_RANGE_MONO: - SetSkill(pSkill->id, GetSkillStep(pSkill->id), 1, 1); - break; - default: - break; - } - } } } @@ -4079,33 +4060,27 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank) // not ranked skills SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spell_id); - for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx) + // most likely will never be used, haven't heard of cases where players unlearn a mount + if (Has310Flyer(false) && spellInfo) { - SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->skillId); - if (!pSkill) - continue; - - if ((_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL && - pSkill->categoryId != SKILL_CATEGORY_CLASS) ||// not unlearn class skills (spellbook/talent pages) - // lockpicking/runeforging special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL - ((pSkill->id == SKILL_LOCKPICKING || pSkill->id == SKILL_RUNEFORGING) && _spell_idx->second->max_value == 0)) + for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx) { - // not reset skills for professions and racial abilities - if ((pSkill->categoryId == SKILL_CATEGORY_SECONDARY || pSkill->categoryId == SKILL_CATEGORY_PROFESSION) && - (IsProfessionSkill(pSkill->id) || _spell_idx->second->racemask != 0)) + SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->skillId); + if (!pSkill) continue; - SetSkill(pSkill->id, GetSkillStep(pSkill->id), 0, 0); - } - - // most likely will never be used, haven't heard of cases where players unlearn a mount - if (Has310Flyer(false) && _spell_idx->second->skillId == SKILL_MOUNTS) - { - if (spellInfo) + if (_spell_idx->second->skillId == SKILL_MOUNTS) + { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED && spellInfo->Effects[i].CalcValue() == 310) + { Has310Flyer(true, spell_id); // with true as first argument its also used to set/remove the flag + break; + } + } + } } } } @@ -6080,9 +6055,6 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step) if (!skill_id) return false; - if (skill_id == SKILL_FIST_WEAPONS) - skill_id = SKILL_UNARMED; - SkillStatusMap::iterator itr = mSkillStatus.find(skill_id); if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return false; @@ -6097,13 +6069,14 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step) if (value < max) { - uint32 new_value = value+step; + uint32 new_value = value + step; if (new_value > max) new_value = max; SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(new_value, max)); if (itr->second.uState != SKILL_NEW) itr->second.uState = SKILL_CHANGED; + UpdateSkillEnchantments(skill_id, value, new_value); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, skill_id); return true; @@ -6277,9 +6250,25 @@ void Player::UpdateWeaponSkill(WeaponAttackType attType) Item* tmpitem = GetWeaponForAttack(attType, true); if (!tmpitem && attType == BASE_ATTACK) + { + // Keep unarmed & fist weapon skills in sync UpdateSkill(SKILL_UNARMED, weapon_skill_gain); + UpdateSkill(SKILL_FIST_WEAPONS, weapon_skill_gain); + } else if (tmpitem && tmpitem->GetTemplate()->SubClass != ITEM_SUBCLASS_WEAPON_FISHING_POLE) - UpdateSkill(tmpitem->GetSkill(), weapon_skill_gain); + { + switch (tmpitem->GetTemplate()->SubClass) + { + case ITEM_SUBCLASS_WEAPON_FISHING_POLE: + break; + case ITEM_SUBCLASS_WEAPON_FIST: + UpdateSkill(SKILL_UNARMED, weapon_skill_gain); + // no break intended + default: + UpdateSkill(tmpitem->GetSkill(), weapon_skill_gain); + break; + } + } UpdateAllCritPercentages(); } @@ -6352,11 +6341,11 @@ void Player::UpdateSkillsForLevel() continue; uint32 pskill = itr->first; - SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(pskill); - if (!pSkill) + SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(pskill, getRace(), getClass()); + if (!rcEntry) continue; - if (GetSkillRangeType(pSkill, false) != SKILL_RANGE_LEVEL) + if (GetSkillRangeType(rcEntry) != SKILL_RANGE_LEVEL) continue; uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos); @@ -8970,9 +8959,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) @@ -8992,12 +8981,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()) @@ -9018,11 +9004,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 @@ -17701,7 +17693,8 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) // after spell and quest load InitTalentForLevel(); - learnDefaultSpells(); + LearnDefaultSkills(); + LearnCustomSpells(); // must be before inventory (some items required reputation check) m_reputationMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_REPUTATION)); @@ -17831,6 +17824,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(); @@ -23072,15 +23068,19 @@ void Player::resetSpells(bool myClassOnly) for (PlayerSpellMap::const_iterator iter = smap.begin(); iter != smap.end(); ++iter) removeSpell(iter->first, false, false); // only iter->first can be accessed, object by iter->second can be deleted already - learnDefaultSpells(); + LearnDefaultSkills(); + LearnCustomSpells(); learnQuestRewardedSpells(); } -void Player::learnDefaultSpells() +void Player::LearnCustomSpells() { + if (!sWorld->getBoolConfig(CONFIG_START_ALL_SPELLS)) + return; + // learn default race/class spells PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass()); - for (PlayerCreateInfoSpells::const_iterator itr = info->spell.begin(); itr != info->spell.end(); ++itr) + for (PlayerCreateInfoSpells::const_iterator itr = info->customSpells.begin(); itr != info->customSpells.end(); ++itr) { uint32 tspell = *itr; TC_LOG_DEBUG("entities.player.loading", "PLAYER (Class: %u Race: %u): Adding initial spell, id = %u", uint32(getClass()), uint32(getRace()), tspell); @@ -23091,6 +23091,63 @@ void Player::learnDefaultSpells() } } +void Player::LearnDefaultSkills() +{ + // learn default race/class skills + PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass()); + for (PlayerCreateInfoSkills::const_iterator itr = info->skills.begin(); itr != info->skills.end(); ++itr) + { + uint32 skillId = itr->SkillId; + if (HasSkill(skillId)) + continue; + + LearnDefaultSkill(skillId, itr->Rank); + } +} + +void Player::LearnDefaultSkill(uint32 skillId, uint16 rank) +{ + SkillRaceClassInfoEntry const* rcInfo = GetSkillRaceClassInfo(skillId, getRace(), getClass()); + if (!rcInfo) + return; + + TC_LOG_DEBUG("entities.player.loading", "PLAYER (Class: %u Race: %u): Adding initial skill, id = %u", uint32(getClass()), uint32(getRace()), skillId); + switch (GetSkillRangeType(rcInfo)) + { + case SKILL_RANGE_LANGUAGE: + SetSkill(skillId, 0, 300, 300); + break; + case SKILL_RANGE_LEVEL: + { + uint16 skillValue = 0; + uint16 maxValue = GetMaxSkillValueForLevel(); + if (rcInfo->Flags & SKILL_FLAG_ALWAYS_MAX_VALUE) + skillValue = maxValue; + else + skillValue = std::min(std::max<uint16>({ 1, uint16((getLevel() - 1) * 5) }), maxValue); + + SetSkill(skillId, 0, skillValue, maxValue); + break; + } + case SKILL_RANGE_MONO: + SetSkill(skillId, 0, 1, 1); + break; + case SKILL_RANGE_RANK: + { + if (!rank) + break; + + SkillTiersEntry const* tier = sSkillTiersStore.LookupEntry(rcInfo->SkillTier); + uint16 maxValue = std::max<uint16>(GetMaxSkillValue(skillId), tier->MaxSkill[std::max<int32>(rank - 1, 0)]); + uint16 skillValue = std::min(std::max<uint16>({ uint16(1), uint16((getLevel() - 1) * 5) }), maxValue); + SetSkill(skillId, rank, skillValue, maxValue); + break; + } + default: + break; + } +} + void Player::learnQuestRewardedSpells(Quest const* quest) { int32 spell_id = quest->GetRewSpellCast(); @@ -23188,29 +23245,35 @@ void Player::learnSkillRewardedSpells(uint32 skill_id, uint32 skill_value) { uint32 raceMask = getRaceMask(); uint32 classMask = getClassMask(); - for (uint32 j=0; j<sSkillLineAbilityStore.GetNumRows(); ++j) + for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) { SkillLineAbilityEntry const* pAbility = sSkillLineAbilityStore.LookupEntry(j); - if (!pAbility || pAbility->skillId != skill_id || pAbility->learnOnGetSkill != ABILITY_LEARNED_ON_GET_PROFESSION_SKILL) + if (!pAbility || pAbility->skillId != skill_id) continue; + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pAbility->spellId); + if (!spellInfo) + continue; + + if (pAbility->AutolearnType != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE && pAbility->AutolearnType != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) + continue; + // Check race if set if (pAbility->racemask && !(pAbility->racemask & raceMask)) continue; + // Check class if set if (pAbility->classmask && !(pAbility->classmask & classMask)) continue; - if (sSpellMgr->GetSpellInfo(pAbility->spellId)) - { - // need unlearn spell - if (skill_value < pAbility->req_skill_value) - removeSpell(pAbility->spellId); - // need learn - else if (!IsInWorld()) - addSpell(pAbility->spellId, true, true, true, false); - else - learnSpell(pAbility->spellId, true); - } + // need unlearn spell + if (skill_value < pAbility->req_skill_value && pAbility->AutolearnType == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE) + removeSpell(pAbility->spellId); + // need learn + else if (!IsInWorld()) + addSpell(pAbility->spellId, true, true, true, false); + else + learnSpell(pAbility->spellId, true); } } @@ -23938,7 +24001,7 @@ bool Player::IsAtRecruitAFriendDistance(WorldObject const* pOther) const return pOther->GetDistance(player) <= sWorld->getFloatConfig(CONFIG_MAX_RECRUIT_A_FRIEND_DISTANCE); } -uint32 Player::GetBaseWeaponSkillValue (WeaponAttackType attType) const +uint32 Player::GetBaseWeaponSkillValue(WeaponAttackType attType) const { Item* item = GetWeaponForAttack(attType, true); @@ -23946,8 +24009,8 @@ uint32 Player::GetBaseWeaponSkillValue (WeaponAttackType attType) const if (attType != BASE_ATTACK && !item) return 0; - // weapon skill or (unarmed for base attack and for fist weapons) - uint32 skill = (item && item->GetSkill() != SKILL_FIST_WEAPONS) ? item->GetSkill() : uint32(SKILL_UNARMED); + // weapon skill or (unarmed for base attack) + uint32 skill = item ? item->GetSkill() : uint32(SKILL_UNARMED); return GetBaseSkillValue(skill); } @@ -24901,15 +24964,15 @@ void Player::_LoadSkills(PreparedQueryResult result) uint16 value = fields[1].GetUInt16(); uint16 max = fields[2].GetUInt16(); - SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(skill); - if (!pSkill) + SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skill, getRace(), getClass()); + if (!rcEntry) { TC_LOG_ERROR("entities.player", "Character %u has skill %u that does not exist.", GetGUIDLow(), skill); continue; } // set fixed skill ranges - switch (GetSkillRangeType(pSkill, false)) + switch (GetSkillRangeType(rcEntry)) { case SKILL_RANGE_LANGUAGE: // 300..300 value = max = 300; @@ -24917,9 +24980,12 @@ void Player::_LoadSkills(PreparedQueryResult result) case SKILL_RANGE_MONO: // 1..1, grey monolite bar value = max = 1; break; + case SKILL_RANGE_LEVEL: + max = GetMaxSkillValueForLevel(); default: break; } + if (value == 0) { TC_LOG_ERROR("entities.player", "Character %u has skill %u with value 0. Will be deleted.", GetGUIDLow(), skill); @@ -24934,11 +25000,20 @@ void Player::_LoadSkills(PreparedQueryResult result) continue; } - // enable unlearn button for primary professions only - if (pSkill->categoryId == SKILL_CATEGORY_PROFESSION) - SetUInt32Value(PLAYER_SKILL_INDEX(count), MAKE_PAIR32(skill, 1)); - else - SetUInt32Value(PLAYER_SKILL_INDEX(count), MAKE_PAIR32(skill, 0)); + uint16 skillStep = 0; + if (SkillTiersEntry const* skillTier = sSkillTiersStore.LookupEntry(rcEntry->SkillTier)) + { + for (uint32 i = 0; i < MAX_SKILL_STEP; ++i) + { + if (skillTier->MaxSkill[skillStep] == max) + { + skillStep = i + 1; + break; + } + } + } + + SetUInt32Value(PLAYER_SKILL_INDEX(count), MAKE_PAIR32(skill, skillStep)); SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(count), MAKE_SKILL_VALUE(value, max)); SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(count), 0); @@ -24964,34 +25039,6 @@ void Player::_LoadSkills(PreparedQueryResult result) SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(count), 0); SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(count), 0); } - - // special settings - if (getClass() == CLASS_DEATH_KNIGHT) - { - uint8 base_level = std::min(getLevel(), uint8(sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL))); - if (base_level < 1) - base_level = 1; - uint16 base_skill = (base_level-1)*5; // 270 at starting level 55 - if (base_skill < 1) - base_skill = 1; // skill mast be known and then > 0 in any case - - if (GetPureSkillValue(SKILL_FIRST_AID) < 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) - SetSkill(SKILL_DEFENSE, 0, base_skill, base_skill); - if (GetPureSkillValue(SKILL_POLEARMS) < base_skill) - SetSkill(SKILL_POLEARMS, 0, base_skill, base_skill); - if (GetPureSkillValue(SKILL_SWORDS) < base_skill) - SetSkill(SKILL_SWORDS, 0, base_skill, base_skill); - if (GetPureSkillValue(SKILL_2H_AXES) < base_skill) - SetSkill(SKILL_2H_AXES, 0, base_skill, base_skill); - if (GetPureSkillValue(SKILL_2H_SWORDS) < base_skill) - SetSkill(SKILL_2H_SWORDS, 0, base_skill, base_skill); - if (GetPureSkillValue(SKILL_UNARMED) < base_skill) - SetSkill(SKILL_UNARMED, 0, base_skill, base_skill); - } } uint32 Player::GetPhaseMaskForSpawn() const diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index fdebbde0ae2..5f500b7f1d8 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -249,6 +249,14 @@ struct PlayerCreateInfoAction typedef std::list<PlayerCreateInfoAction> PlayerCreateInfoActions; +struct PlayerCreateInfoSkill +{ + uint16 SkillId; + uint16 Rank; +}; + +typedef std::list<PlayerCreateInfoSkill> PlayerCreateInfoSkills; + struct PlayerInfo { // existence checked by displayId != 0 @@ -263,8 +271,9 @@ struct PlayerInfo uint16 displayId_m; uint16 displayId_f; PlayerCreateInfoItems item; - PlayerCreateInfoSpells spell; + PlayerCreateInfoSpells customSpells; PlayerCreateInfoActions action; + PlayerCreateInfoSkills skills; PlayerLevelInfo* levelInfo; //[level-1] 0..MaxPlayerLevel-1 }; @@ -1573,7 +1582,9 @@ class Player : public Unit, public GridObject<Player> void learnSpell(uint32 spell_id, bool dependent); void removeSpell(uint32 spell_id, bool disabled = false, bool learn_low_rank = true); void resetSpells(bool myClassOnly = false); - void learnDefaultSpells(); + void LearnCustomSpells(); + void LearnDefaultSkills(); + void LearnDefaultSkill(uint32 skillId, uint16 rank); void learnQuestRewardedSpells(); void learnQuestRewardedSpells(Quest const* quest); void learnSpellHighRank(uint32 spellid); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 5e12022312d..72c1a071487 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" @@ -2833,12 +2834,10 @@ uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target) if (IsInFeralForm()) return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact - // weapon skill or (unarmed for base attack and fist weapons) - uint32 skill; - if (item && item->GetSkill() != SKILL_FIST_WEAPONS) + // weapon skill or (unarmed for base attack) + uint32 skill = SKILL_UNARMED; + if (item) skill = item->GetSkill(); - else - skill = SKILL_UNARMED; // in PvP use full skill instead current skill value value = (target && target->IsControlledByPlayer()) @@ -3845,8 +3844,7 @@ void Unit::RemoveAurasByType(AuraType auraType, uint64 casterGUID, Aura* except, { Aura* aura = (*iter)->GetBase(); AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID()); - if (!aurApp) - continue; + ASSERT(aurApp); ++iter; if (aura != except && (!casterGUID || aura->GetCasterGUID() == casterGUID) @@ -7714,7 +7712,8 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL; // Try handle unknown trigger spells - if (sSpellMgr->GetSpellInfo(trigger_spell_id) == NULL) + // triggered spells exists only in serverside spell_dbc + /// @todo: reverify and move these spells to spellscripts { switch (auraSpellInfo->SpellFamilyName) { @@ -15271,8 +15270,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) @@ -15288,7 +15287,7 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) group->SendLooter(creature, NULL); // Update round robin looter only if the creature had loot - if (!creature->loot.empty()) + if (!loot->empty()) group->UpdateLooterGuid(creature); } } @@ -15391,9 +15390,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.isLooted()) 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 diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index db97ea270ef..4853c9b3ba5 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(); @@ -3322,17 +3322,91 @@ void ObjectMgr::LoadPlayerInfo() } } + + // Load playercreate skills + TC_LOG_INFO("server.loading", "Loading Player Create Skill Data..."); + { + uint32 oldMSTime = getMSTime(); + + QueryResult result = WorldDatabase.PQuery("SELECT raceMask, classMask, skill, rank FROM playercreateinfo_skills"); + + if (!result) + { + TC_LOG_ERROR("server.loading", ">> Loaded 0 player create skills. DB table `playercreateinfo_skills` is empty."); + } + else + { + uint32 count = 0; + + do + { + Field* fields = result->Fetch(); + uint32 raceMask = fields[0].GetUInt32(); + uint32 classMask = fields[1].GetUInt32(); + PlayerCreateInfoSkill skill; + skill.SkillId = fields[2].GetUInt16(); + skill.Rank = fields[3].GetUInt16(); + + if (skill.Rank >= MAX_SKILL_STEP) + { + TC_LOG_ERROR("sql.sql", "Skill rank value %hu set for skill %hu raceMask %u classMask %u is too high, max allowed value is %d", skill.Rank, skill.SkillId, raceMask, classMask, MAX_SKILL_STEP); + continue; + } + + if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE)) + { + TC_LOG_ERROR("sql.sql", "Wrong race mask %u in `playercreateinfo_skills` table, ignoring.", raceMask); + continue; + } + + if (classMask != 0 && !(classMask & CLASSMASK_ALL_PLAYABLE)) + { + TC_LOG_ERROR("sql.sql", "Wrong class mask %u in `playercreateinfo_skills` table, ignoring.", classMask); + continue; + } + + if (!sSkillLineStore.LookupEntry(skill.SkillId)) + { + TC_LOG_ERROR("sql.sql", "Wrong skill id %u in `playercreateinfo_skills` table, ignoring.", skill.SkillId); + continue; + } + + for (uint32 raceIndex = RACE_HUMAN; raceIndex < MAX_RACES; ++raceIndex) + { + if (raceMask == 0 || ((1 << (raceIndex - 1)) & raceMask)) + { + for (uint32 classIndex = CLASS_WARRIOR; classIndex < MAX_CLASSES; ++classIndex) + { + if (classMask == 0 || ((1 << (classIndex - 1)) & classMask)) + { + if (!GetSkillRaceClassInfo(skill.SkillId, raceIndex, classIndex)) + continue; + + if (PlayerInfo* info = _playerInfo[raceIndex][classIndex]) + { + info->skills.push_back(skill); + ++count; + } + } + } + } + } + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u player create skills in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + } + } + // Load playercreate spells TC_LOG_INFO("server.loading", "Loading Player Create Spell Data..."); { uint32 oldMSTime = getMSTime(); - std::string tableName = sWorld->getBoolConfig(CONFIG_START_ALL_SPELLS) ? "playercreateinfo_spell_custom" : "playercreateinfo_spell"; - QueryResult result = WorldDatabase.PQuery("SELECT racemask, classmask, Spell FROM %s", tableName.c_str()); + QueryResult result = WorldDatabase.PQuery("SELECT racemask, classmask, Spell FROM playercreateinfo_spell_custom"); if (!result) { - TC_LOG_ERROR("server.loading", ">> Loaded 0 player create spells. DB table `%s` is empty.", tableName.c_str()); + TC_LOG_ERROR("server.loading", ">> Loaded 0 player create spells. DB table `playercreateinfo_spell_custom` is empty."); } else { @@ -3347,13 +3421,13 @@ void ObjectMgr::LoadPlayerInfo() if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE)) { - TC_LOG_ERROR("sql.sql", "Wrong race mask %u in `%s` table, ignoring.", raceMask, tableName.c_str()); + TC_LOG_ERROR("sql.sql", "Wrong race mask %u in `playercreateinfo_spell_custom` table, ignoring.", raceMask); continue; } if (classMask != 0 && !(classMask & CLASSMASK_ALL_PLAYABLE)) { - TC_LOG_ERROR("sql.sql", "Wrong class mask %u in `%s` table, ignoring.", classMask, tableName.c_str()); + TC_LOG_ERROR("sql.sql", "Wrong class mask %u in `playercreateinfo_spell_custom` table, ignoring.", classMask); continue; } @@ -3367,7 +3441,7 @@ void ObjectMgr::LoadPlayerInfo() { if (PlayerInfo* info = _playerInfo[raceIndex][classIndex]) { - info->spell.push_back(spellId); + info->customSpells.push_back(spellId); ++count; } // We need something better here, the check is not accounting for spells used by multiple races/classes but not all of them. @@ -3381,7 +3455,7 @@ void ObjectMgr::LoadPlayerInfo() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u player create spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u custom player create spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -7808,36 +7882,27 @@ int32 ObjectMgr::GetBaseReputationOf(FactionEntry const* factionEntry, uint8 rac return 0; } -SkillRangeType GetSkillRangeType(SkillLineEntry const* pSkill, bool racial) +SkillRangeType GetSkillRangeType(SkillRaceClassInfoEntry const* rcEntry) { - switch (pSkill->categoryId) + SkillLineEntry const* skill = sSkillLineStore.LookupEntry(rcEntry->SkillId); + if (!skill) + return SKILL_RANGE_NONE; + + if (sSkillTiersStore.LookupEntry(rcEntry->SkillTier)) + return SKILL_RANGE_RANK; + + if (rcEntry->SkillId == SKILL_RUNEFORGING) + return SKILL_RANGE_MONO; + + switch (skill->categoryId) { - case SKILL_CATEGORY_LANGUAGES: return SKILL_RANGE_LANGUAGE; - case SKILL_CATEGORY_WEAPON: - if (pSkill->id != SKILL_FIST_WEAPONS) - return SKILL_RANGE_LEVEL; - else - return SKILL_RANGE_MONO; case SKILL_CATEGORY_ARMOR: - case SKILL_CATEGORY_CLASS: - if (pSkill->id != SKILL_LOCKPICKING) - return SKILL_RANGE_MONO; - else - return SKILL_RANGE_LEVEL; - case SKILL_CATEGORY_SECONDARY: - case SKILL_CATEGORY_PROFESSION: - // not set skills for professions and racial abilities - if (IsProfessionSkill(pSkill->id)) - return SKILL_RANGE_RANK; - else if (racial) - return SKILL_RANGE_NONE; - else - return SKILL_RANGE_MONO; - default: - case SKILL_CATEGORY_ATTRIBUTES: //not found in dbc - case SKILL_CATEGORY_GENERIC: //only GENERIC(DND) - return SKILL_RANGE_NONE; + return SKILL_RANGE_MONO; + case SKILL_CATEGORY_LANGUAGES: + return SKILL_RANGE_LANGUAGE; } + + return SKILL_RANGE_LEVEL; } void ObjectMgr::LoadGameTele() diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 20941901731..3cf0c103452 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -642,7 +642,7 @@ enum SkillRangeType SKILL_RANGE_NONE // 0..0 always }; -SkillRangeType GetSkillRangeType(SkillLineEntry const* pSkill, bool racial); +SkillRangeType GetSkillRangeType(SkillRaceClassInfoEntry const* rcEntry); #define MAX_PLAYER_NAME 12 // max allowed by client name length #define MAX_INTERNAL_PLAYER_NAME 15 // max server internal player name length (> MAX_PLAYER_NAME for support declined names) @@ -1297,6 +1297,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/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/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index c2f93190a05..9ad382b4686 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -750,9 +750,9 @@ void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData) 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); - + // 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. + 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 diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index 61f0b9afce2..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; @@ -348,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..1270f4e6419 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); @@ -315,6 +322,10 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) // If theres is an item, there is a one hour delivery delay if sent to another account's character. uint32 deliver_delay = needItemDelay ? sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0; + // don't ask for COD if there are no items + if (items_count == 0) + COD = 0; + // will delete item or place to receiver mail list draft .AddMoney(money) @@ -338,7 +349,7 @@ void WorldSession::HandleMailMarkAsRead(WorldPacket& recvData) Player* player = _player; Mail* m = player->GetMail(mailId); - if (m) + if (m && m->state != MAIL_STATE_DELETED) { if (player->unReadMails) --player->unReadMails; @@ -462,6 +473,13 @@ void WorldSession::HandleMailTakeItem(WorldPacket& recvData) return; } + // verify that the mail has the item to avoid cheaters taking COD items without paying + if (std::find_if(m->items.begin(), m->items.end(), [itemId](MailItemInfo info){ return info.item_guid == itemId; }) == m->items.end()) + { + player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); + return; + } + // prevent cheating with skip client money check if (!player->HasEnoughMoney(m->COD)) { @@ -710,7 +728,7 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData) Player* player = _player; Mail* m = player->GetMail(mailId); - if (!m || (m->body.empty() && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) + if (!m || (m->body.empty() && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL) || (m->checked & MAIL_CHECK_MASK_COPIED)) { player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); return; 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 9be745e622d..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, @@ -341,6 +343,7 @@ struct Loot gold = 0; unlootedCount = 0; roundRobinPlayer = 0; + loot_type = LOOT_NONE; i_LootValidatorRefManager.clearReferences(); } diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 9967b59ecec..77bc76c6dfd 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -2595,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/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 1240ec545ba..4cb6ec2d7af 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -445,7 +445,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); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 48c2a76578d..0e0443cc675 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)); @@ -2251,7 +2265,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) m_spellAura = NULL; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied //Spells with this flag cannot trigger if effect is cast on self - bool canEffectTrigger = !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_CANT_TRIGGER_PROC) && unitTarget->CanProc() && CanExecuteTriggersOnHit(mask); + bool canEffectTrigger = !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_CANT_TRIGGER_PROC) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2); Unit* spellHitTarget = NULL; if (missInfo == SPELL_MISS_NONE) // In case spell hit target, do all effect on that target @@ -2297,15 +2311,8 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (m_damage > 0) positive = false; else if (!m_healing) - { - for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i) - // If at least one effect negative spell is negative hit - if (mask & (1<<i) && !m_spellInfo->IsPositiveEffect(i)) - { - positive = false; - break; - } - } + positive = m_spellInfo->IsPositive(); + switch (m_spellInfo->DmgClass) { case SPELL_DAMAGE_CLASS_MAGIC: @@ -2383,7 +2390,6 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx); } - m_damage = damageInfo.damage; caster->DealSpellDamage(&damageInfo, true); @@ -2524,9 +2530,14 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA } } + uint8 aura_effmask = 0; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (effectMask & (1 << i) && m_spellInfo->Effects[i].IsUnitOwnedAuraEffect()) + aura_effmask |= 1 << i; + // Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add m_diminishGroup = GetDiminishingReturnsGroupForSpell(m_spellInfo, m_triggeredByAuraSpell); - if (m_diminishGroup) + if (m_diminishGroup && aura_effmask) { m_diminishLevel = unit->GetDiminishing(m_diminishGroup); DiminishingReturnsType type = GetDiminishingReturnsGroupType(m_diminishGroup); @@ -2537,11 +2548,6 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA unit->IncrDiminishing(m_diminishGroup); } - uint8 aura_effmask = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (effectMask & (1 << i) && m_spellInfo->Effects[i].IsUnitOwnedAuraEffect()) - aura_effmask |= 1 << i; - if (aura_effmask) { // Select rank for aura with level requirements only in specific cases diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 9cf0e1ae45c..0a5d265cbfa 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -654,14 +654,6 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) } break; } - case SPELLFAMILY_MAGE: - { - // Deep Freeze should deal damage to permanently stun-immune targets. - if (m_spellInfo->Id == 71757) - if (unitTarget->GetTypeId() != TYPEID_UNIT || !(unitTarget->IsImmunedToSpellEffect(sSpellMgr->GetSpellInfo(44572), 0))) - return; - break; - } } if (m_originalCaster && damage > 0 && apply_direct_bonus) @@ -2608,8 +2600,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*/) @@ -4704,6 +4704,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 4d97dc97e5b..8034002a470 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -967,7 +967,7 @@ bool SpellInfo::IsAbilityLearnedWithProfession() const for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx) { SkillLineAbilityEntry const* pAbility = _spell_idx->second; - if (!pAbility || pAbility->learnOnGetSkill != ABILITY_LEARNED_ON_GET_PROFESSION_SKILL) + if (!pAbility || pAbility->AutolearnType != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE) continue; if (pAbility->req_skill_value > 0) diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 6f56c0ebc40..77450dc859a 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2382,7 +2382,7 @@ void SpellMgr::LoadPetLevelupSpellMap() if (skillLine->skillId != creatureFamily->skillLine[j]) continue; - if (skillLine->learnOnGetSkill != ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL) + if (skillLine->AutolearnType != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) continue; SpellInfo const* spell = GetSpellInfo(skillLine->spellId); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index d917030bb19..48dd6565f95 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1046,6 +1046,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 @@ -1256,7 +1258,9 @@ 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 cdffbf3ee2a..d14d5adf37a 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -331,6 +331,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/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_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp index 12721c61936..03d10149ae5 100644 --- a/src/server/scripts/Commands/cs_learn.cpp +++ b/src/server/scripts/Commands/cs_learn.cpp @@ -332,7 +332,8 @@ public: if (!handler->extractPlayerTarget((char*)args, &target)) return false; - target->learnDefaultSpells(); + target->LearnDefaultSkills(); + target->LearnCustomSpells(); target->learnQuestRewardedSpells(); handler->PSendSysMessage(LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST, handler->GetNameLink(target).c_str()); 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/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/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index f71b7bb8150..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. 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) {} |