feat(Core/Battleground): split Arena and Battleground score (#10616)

This commit is contained in:
Kargatum
2022-02-18 05:20:04 +07:00
committed by GitHub
parent dbd7680f5b
commit 5143872aed
41 changed files with 1750 additions and 1766 deletions

View File

@@ -26,7 +26,9 @@
#include "BattlegroundRL.h"
#include "BattlegroundRV.h"
#include "Chat.h"
#include "ChatTextBuilder.h"
#include "Creature.h"
#include "CreatureTextMgr.h"
#include "Formulas.h"
#include "GameGraveyard.h"
#include "GridNotifiersImpl.h"
@@ -118,6 +120,20 @@ void Battleground::BroadcastWorker(Do& _do)
_do(itr->second);
}
void BattlegroundScore::AppendToPacket(WorldPacket& data)
{
data << PlayerGuid;
data << uint32(KillingBlows);
data << uint32(HonorableKills);
data << uint32(Deaths);
data << uint32(BonusHonor);
data << uint32(DamageDone);
data << uint32(HealingDone);
BuildObjectivesBlock(data);
}
Battleground::Battleground()
{
m_RealTypeID = BATTLEGROUND_TYPE_NONE;
@@ -129,7 +145,7 @@ Battleground::Battleground()
m_LastResurrectTime = 0;
m_ArenaType = 0;
m_IsArena = false;
m_WinnerId = TEAM_NEUTRAL;
m_WinnerId = PVP_TEAM_NEUTRAL;
m_StartTime = 0;
m_ResetStatTimer = 0;
m_ValidStartPositionTimer = 0;
@@ -138,7 +154,6 @@ Battleground::Battleground()
m_IsRated = false;
m_BuffChange = false;
m_IsRandom = false;
m_Name = "";
m_LevelMin = 0;
m_LevelMax = 0;
m_SetDeleteThis = false;
@@ -151,24 +166,9 @@ Battleground::Battleground()
m_StartMaxDist = 0.0f;
ScriptId = 0;
m_TeamStartLocX[TEAM_ALLIANCE] = 0;
m_TeamStartLocX[TEAM_HORDE] = 0;
m_TeamStartLocY[TEAM_ALLIANCE] = 0;
m_TeamStartLocY[TEAM_HORDE] = 0;
m_TeamStartLocZ[TEAM_ALLIANCE] = 0;
m_TeamStartLocZ[TEAM_HORDE] = 0;
m_TeamStartLocO[TEAM_ALLIANCE] = 0;
m_TeamStartLocO[TEAM_HORDE] = 0;
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;
@@ -193,11 +193,11 @@ Battleground::Battleground()
StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_1M;
StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_30S;
StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
//we must set to some default existing values
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES;
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN;
StartMessageIds[BG_STARTING_EVENT_FIRST] = BG_TEXT_START_TWO_MINUTES;
StartMessageIds[BG_STARTING_EVENT_SECOND] = BG_TEXT_START_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_THIRD] = BG_TEXT_START_HALF_MINUTE;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = BG_TEXT_BATTLE_HAS_BEGUN;
// pussywizard:
m_UpdateTimer = 0;
@@ -205,6 +205,8 @@ Battleground::Battleground()
Battleground::~Battleground()
{
LOG_DEBUG("bg.battleground", "> Remove Battleground {} {} {}", GetName(), GetBgTypeID(), GetInstanceID());
_reviveEvents.KillAllEvents(false);
// remove objects and creatures
@@ -229,8 +231,8 @@ Battleground::~Battleground()
m_Map = nullptr;
}
for (BattlegroundScoreMap::const_iterator itr = PlayerScores.begin(); itr != PlayerScores.end(); ++itr)
delete itr->second;
for (auto const& itr : PlayerScores)
delete itr.second;
}
void Battleground::Update(uint32 diff)
@@ -267,8 +269,7 @@ void Battleground::Update(uint32 diff)
{
if (GetStartTime() >= 46 * MINUTE * IN_MILLISECONDS) // pussywizard: 1min startup + 45min allowed duration
{
UpdateArenaWorldState();
CheckArenaAfterTimerConditions();
EndBattleground(PVP_TEAM_NEUTRAL);
return;
}
}
@@ -304,19 +305,20 @@ inline void Battleground::_CheckSafePositions(uint32 diff)
return;
m_ValidStartPositionTimer += diff;
if (m_ValidStartPositionTimer >= CHECK_PLAYER_POSITION_INVERVAL)
{
m_ValidStartPositionTimer = 0;
float x, y, z, o;
for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
for (auto const& [playerGuid, player] : GetPlayers())
{
Position pos = itr->second->GetPosition();
GetTeamStartLoc(itr->second->GetBgTeamId(), x, y, z, o);
if (pos.GetExactDistSq(x, y, z) > maxDist)
Position pos = player->GetPosition();
Position const* startPos = GetTeamStartPosition(player->GetBgTeamId());
if (pos.GetExactDistSq(startPos) > maxDist)
{
LOG_DEBUG("bg.battleground", "BATTLEGROUND: Sending {} back to start location (map: {}) (possible exploit)", itr->second->GetName(), GetMapId());
itr->second->TeleportTo(GetMapId(), x, y, z, o);
LOG_DEBUG("bg.battleground", "BATTLEGROUND: Sending {} back to start location (map: {}) (possible exploit)", player->GetName(), GetMapId());
player->TeleportTo(GetMapId(), startPos->GetPositionX(), startPos->GetPositionY(), startPos->GetPositionZ(), startPos->GetOrientation());
}
}
}
@@ -465,20 +467,26 @@ inline void Battleground::_ProcessJoin(uint32 diff)
StartingEventCloseDoors();
SetStartDelayTime(StartDelayTimes[BG_STARTING_EVENT_FIRST]);
// First start warning - 2 or 1 minute
SendMessageToAll(StartMessageIds[BG_STARTING_EVENT_FIRST], CHAT_MSG_BG_SYSTEM_NEUTRAL);
if (StartMessageIds[BG_STARTING_EVENT_FIRST])
SendBroadcastText(StartMessageIds[BG_STARTING_EVENT_FIRST], CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
// After 1 minute or 30 seconds, warning is signaled
else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_SECOND] && !(m_Events & BG_STARTING_EVENT_2))
{
m_Events |= BG_STARTING_EVENT_2;
SendMessageToAll(StartMessageIds[BG_STARTING_EVENT_SECOND], CHAT_MSG_BG_SYSTEM_NEUTRAL);
if (StartMessageIds[BG_STARTING_EVENT_SECOND])
SendBroadcastText(StartMessageIds[BG_STARTING_EVENT_SECOND], CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
// After 30 or 15 seconds, warning is signaled
else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_THIRD] && !(m_Events & BG_STARTING_EVENT_3))
{
m_Events |= BG_STARTING_EVENT_3;
SendMessageToAll(StartMessageIds[BG_STARTING_EVENT_THIRD], CHAT_MSG_BG_SYSTEM_NEUTRAL);
if (StartMessageIds[BG_STARTING_EVENT_THIRD])
SendBroadcastText(StartMessageIds[BG_STARTING_EVENT_THIRD], CHAT_MSG_BG_SYSTEM_NEUTRAL);
if (isArena())
switch (GetBgTypeID())
@@ -514,7 +522,9 @@ inline void Battleground::_ProcessJoin(uint32 diff)
StartingEventOpenDoors();
SendWarningToAll(StartMessageIds[BG_STARTING_EVENT_FOURTH]);
if (StartMessageIds[BG_STARTING_EVENT_FOURTH])
SendBroadcastText(StartMessageIds[BG_STARTING_EVENT_FOURTH], CHAT_MSG_BG_SYSTEM_NEUTRAL);
SetStatus(STATUS_IN_PROGRESS);
SetStartDelayTime(StartDelayTimes[BG_STARTING_EVENT_FOURTH]);
@@ -556,7 +566,7 @@ inline void Battleground::_ProcessJoin(uint32 diff)
for (SpectatorList::const_iterator itr = m_Spectators.begin(); itr != m_Spectators.end(); ++itr)
ArenaSpectator::HandleResetCommand(*itr);
CheckArenaWinConditions();
CheckWinConditions();
// pussywizard: arena spectator stuff
if (GetStatus() == STATUS_IN_PROGRESS)
@@ -591,7 +601,7 @@ inline void Battleground::_ProcessJoin(uint32 diff)
// Announce BG starting
if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE))
sWorld->SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, GetName(), std::min(GetMinLevel(), (uint32)80), std::min(GetMaxLevel(), (uint32)80));
sWorld->SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, GetName().c_str(), std::min(GetMinLevel(), (uint32)80), std::min(GetMaxLevel(), (uint32)80));
sScriptMgr->OnBattlegroundStart(this);
}
@@ -618,12 +628,16 @@ inline void Battleground::_ProcessLeave(uint32 diff)
}
}
void Battleground::SetTeamStartLoc(TeamId teamId, float X, float Y, float Z, float O)
void Battleground::SetTeamStartPosition(TeamId teamId, Position const& pos)
{
m_TeamStartLocX[teamId] = X;
m_TeamStartLocY[teamId] = Y;
m_TeamStartLocZ[teamId] = Z;
m_TeamStartLocO[teamId] = O;
ASSERT(teamId < TEAM_NEUTRAL);
_startPosition[teamId] = pos;
}
Position const* Battleground::GetTeamStartPosition(TeamId teamId) const
{
ASSERT(teamId < TEAM_NEUTRAL);
return &_startPosition[teamId];
}
void Battleground::SendPacketToAll(WorldPacket const* packet)
@@ -639,6 +653,24 @@ void Battleground::SendPacketToTeam(TeamId teamId, WorldPacket const* packet, Pl
itr->second->GetSession()->SendPacket(packet);
}
void Battleground::SendChatMessage(Creature* source, uint8 textId, WorldObject* target /*= nullptr*/)
{
sCreatureTextMgr->SendChat(source, textId, target);
}
void Battleground::SendBroadcastText(uint32 id, ChatMsg msgType, WorldObject const* target)
{
if (!sObjectMgr->GetBroadcastText(id))
{
LOG_ERROR("bg.battleground", "Battleground::SendBroadcastText: `broadcast_text` (ID: {}) was not found", id);
return;
}
Acore::BroadcastTextBuilder builder(nullptr, msgType, id, GENDER_MALE, target);
Acore::LocalizedPacketDo<Acore::BroadcastTextBuilder> localizer(builder);
BroadcastWorker(localizer);
}
void Battleground::PlaySoundToAll(uint32 soundID)
{
WorldPacket data;
@@ -728,7 +760,7 @@ void Battleground::UpdateWorldState(uint32 variable, uint32 value)
SendPacketToAll(worldstate.Write());
}
void Battleground::EndBattleground(TeamId winnerTeamId)
void Battleground::EndBattleground(PvPTeamId winnerTeamId)
{
// xinef: if this is true, it means that endbattleground is called second time
// skip to avoid double rating reduce / add
@@ -736,35 +768,23 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
// set as fast as possible
if (GetStatus() == STATUS_WAIT_LEAVE)
return;
uint32 startDelay = GetStartDelayTime();
bool bValidArena = isArena() && isRated() && GetStatus() == STATUS_IN_PROGRESS && GetStartTime() >= startDelay + 15000; // pussywizard: only if arena lasted at least 15 secs
SetStatus(STATUS_WAIT_LEAVE);
ArenaTeam* winnerArenaTeam = nullptr;
ArenaTeam* loserArenaTeam = nullptr;
uint32 loserTeamRating = 0;
uint32 loserMatchmakerRating = 0;
int32 loserChange = 0;
int32 loserMatchmakerChange = 0;
uint32 winnerTeamRating = 0;
uint32 winnerMatchmakerRating = 0;
int32 winnerChange = 0;
int32 winnerMatchmakerChange = 0;
int32 winmsg_id = 0;
SetWinner(winnerTeamId);
if (winnerTeamId == TEAM_ALLIANCE)
if (winnerTeamId == PVP_TEAM_ALLIANCE)
{
winmsg_id = isBattleground() ? LANG_BG_A_WINS : LANG_ARENA_GOLD_WINS;
PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound
if (isBattleground())
SendBroadcastText(BG_TEXT_ALLIANCE_WINS, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound
}
else if (winnerTeamId == TEAM_HORDE)
else if (winnerTeamId == PVP_TEAM_HORDE)
{
winmsg_id = isBattleground() ? LANG_BG_H_WINS : LANG_ARENA_GREEN_WINS;
PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound
if (isBattleground())
SendBroadcastText(BG_TEXT_HORDE_WINS, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound
}
CharacterDatabasePreparedStatement* stmt = nullptr;
@@ -782,7 +802,7 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_BATTLEGROUND);
stmt->SetData(0, battlegroundId);
stmt->SetData(1, GetPvPTeamId(GetWinner()));
stmt->SetData(1, GetWinner());
stmt->SetData(2, GetUniqueBracketId());
stmt->SetData(3, GetBgTypeID(true));
CharacterDatabase.Execute(stmt);
@@ -791,151 +811,17 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
//we must set it this way, because end time is sent in packet!
m_EndTime = TIME_TO_AUTOREMOVE;
// arena rating calculation
if (isArena() && isRated())
{
winnerArenaTeam = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(winnerTeamId == TEAM_NEUTRAL ? TEAM_HORDE : winnerTeamId));
loserArenaTeam = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(winnerTeamId == TEAM_NEUTRAL ? TEAM_ALLIANCE : GetOtherTeamId(winnerTeamId)));
if (winnerArenaTeam && loserArenaTeam && winnerArenaTeam != loserArenaTeam)
{
if (winnerTeamId != TEAM_NEUTRAL)
{
loserTeamRating = loserArenaTeam->GetRating();
loserMatchmakerRating = GetArenaMatchmakerRating(GetOtherTeamId(winnerTeamId));
winnerTeamRating = winnerArenaTeam->GetRating();
winnerMatchmakerRating = GetArenaMatchmakerRating(winnerTeamId);
winnerMatchmakerChange = bValidArena ? winnerArenaTeam->WonAgainst(winnerMatchmakerRating, loserMatchmakerRating, winnerChange, GetBgMap()) : 0;
loserMatchmakerChange = loserArenaTeam->LostAgainst(loserMatchmakerRating, winnerMatchmakerRating, loserChange, GetBgMap());
sScriptMgr->OnAfterArenaRatingCalculation(this, winnerMatchmakerChange, loserMatchmakerChange, winnerChange, loserChange);
SetArenaMatchmakerRating(winnerTeamId, winnerMatchmakerRating + winnerMatchmakerChange);
SetArenaMatchmakerRating(GetOtherTeamId(winnerTeamId), loserMatchmakerRating + loserMatchmakerChange);
SetArenaTeamRatingChangeForTeam(winnerTeamId, winnerChange);
SetArenaTeamRatingChangeForTeam(GetOtherTeamId(winnerTeamId), loserChange);
// pussywizard: arena logs in database
uint32 fightId = sArenaTeamMgr->GetNextArenaLogId();
uint32 currOnline = (uint32)(sWorld->GetActiveSessionCount());
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
CharacterDatabasePreparedStatement* stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_LOG_FIGHT);
stmt2->SetData(0, fightId);
stmt2->SetData(1, m_ArenaType);
stmt2->SetData(2, ((GetStartTime() <= startDelay ? 0 : GetStartTime() - startDelay) / 1000));
stmt2->SetData(3, winnerArenaTeam->GetId());
stmt2->SetData(4, loserArenaTeam->GetId());
stmt2->SetData(5, (uint16)winnerTeamRating);
stmt2->SetData(6, (uint16)winnerMatchmakerRating);
stmt2->SetData(7, (int16)winnerChange);
stmt2->SetData(8, (uint16)loserTeamRating);
stmt2->SetData(9, (uint16)loserMatchmakerRating);
stmt2->SetData(10, (int16)loserChange);
stmt2->SetData(11, currOnline);
trans->Append(stmt2);
uint8 memberId = 0;
for (Battleground::ArenaLogEntryDataMap::const_iterator itr = ArenaLogEntries.begin(); itr != ArenaLogEntries.end(); ++itr)
{
stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_LOG_MEMBERSTATS);
stmt2->SetData(0, fightId);
stmt2->SetData(1, ++memberId);
stmt2->SetData(2, itr->second.Name);
stmt2->SetData(3, itr->second.Guid);
stmt2->SetData(4, itr->second.ArenaTeamId);
stmt2->SetData(5, itr->second.Acc);
stmt2->SetData(6, itr->second.IP);
stmt2->SetData(7, itr->second.DamageDone);
stmt2->SetData(8, itr->second.HealingDone);
stmt2->SetData(9, itr->second.KillingBlows);
trans->Append(stmt2);
}
CharacterDatabase.CommitTransaction(trans);
}
// Deduct 16 points from each teams arena-rating if there are no winners after 45+2 minutes
else
{
// pussywizard: in case of a draw, the following is always true:
// winnerArenaTeam => TEAM_HORDE, loserArenaTeam => TEAM_ALLIANCE
winnerTeamRating = winnerArenaTeam->GetRating();
winnerMatchmakerRating = GetArenaMatchmakerRating(TEAM_HORDE);
loserTeamRating = loserArenaTeam->GetRating();
loserMatchmakerRating = GetArenaMatchmakerRating(TEAM_ALLIANCE);
winnerMatchmakerChange = 0;
loserMatchmakerChange = 0;
winnerChange = ARENA_TIMELIMIT_POINTS_LOSS;
loserChange = ARENA_TIMELIMIT_POINTS_LOSS;
SetArenaTeamRatingChangeForTeam(TEAM_ALLIANCE, ARENA_TIMELIMIT_POINTS_LOSS);
SetArenaTeamRatingChangeForTeam(TEAM_HORDE, ARENA_TIMELIMIT_POINTS_LOSS);
winnerArenaTeam->FinishGame(ARENA_TIMELIMIT_POINTS_LOSS, GetBgMap());
loserArenaTeam->FinishGame(ARENA_TIMELIMIT_POINTS_LOSS, GetBgMap());
// pussywizard: arena logs in database
uint32 fightId = sArenaTeamMgr->GetNextArenaLogId();
uint32 currOnline = (uint32)(sWorld->GetActiveSessionCount());
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
CharacterDatabasePreparedStatement* stmt3 = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_LOG_FIGHT);
stmt3->SetData(0, fightId);
stmt3->SetData(1, m_ArenaType);
stmt3->SetData(2, ((GetStartTime() <= startDelay ? 0 : GetStartTime() - startDelay) / 1000));
stmt3->SetData(3, winnerArenaTeam->GetId());
stmt3->SetData(4, loserArenaTeam->GetId());
stmt3->SetData(5, (uint16)winnerTeamRating);
stmt3->SetData(6, (uint16)winnerMatchmakerRating);
stmt3->SetData(7, (int16)winnerChange);
stmt3->SetData(8, (uint16)loserTeamRating);
stmt3->SetData(9, (uint16)loserMatchmakerRating);
stmt3->SetData(10, (int16)loserChange);
stmt3->SetData(11, currOnline);
trans->Append(stmt3);
uint8 memberId = 0;
for (Battleground::ArenaLogEntryDataMap::const_iterator itr = ArenaLogEntries.begin(); itr != ArenaLogEntries.end(); ++itr)
{
stmt3 = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_LOG_MEMBERSTATS);
stmt3->SetData(0, fightId);
stmt3->SetData(1, ++memberId);
stmt3->SetData(2, itr->second.Name);
stmt3->SetData(3, itr->second.Guid);
stmt3->SetData(4, itr->second.ArenaTeamId);
stmt3->SetData(5, itr->second.Acc);
stmt3->SetData(6, itr->second.IP);
stmt3->SetData(7, itr->second.DamageDone);
stmt3->SetData(8, itr->second.HealingDone);
stmt3->SetData(9, itr->second.KillingBlows);
trans->Append(stmt3);
}
CharacterDatabase.CommitTransaction(trans);
}
}
else
{
SetArenaTeamRatingChangeForTeam(TEAM_ALLIANCE, 0);
SetArenaTeamRatingChangeForTeam(TEAM_HORDE, 0);
}
}
WorldPacket pvpLogData;
sBattlegroundMgr->BuildPvpLogDataPacket(&pvpLogData, this);
BuildPvPLogDataPacket(pvpLogData);
uint8 aliveWinners = GetAlivePlayersCountByTeam(winnerTeamId);
for (BattlegroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
for (auto const& [playerGuid, player] : m_Players)
{
Player* player = itr->second;
TeamId bgTeamId = player->GetBgTeamId();
// should remove spirit of redemption
if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
// Last standing - Rated 5v5 arena & be solely alive player
if (bgTeamId == winnerTeamId && isArena() && isRated() && GetArenaType() == ARENA_TYPE_5v5 && aliveWinners == 1 && player->IsAlive() && bValidArena)
player->CastSpell(player, SPELL_THE_LAST_STANDING, true);
if (!player->IsAlive())
{
player->ResurrectPlayer(1.0f);
@@ -948,38 +834,12 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
player->getHostileRefMgr().deleteReferences();
}
// per player calculation
if (isArena() && isRated() && winnerArenaTeam && loserArenaTeam && winnerArenaTeam != loserArenaTeam)
{
if (bgTeamId == winnerTeamId)
{
if (bValidArena)
{
// update achievement BEFORE personal rating update
uint32 rating = player->GetArenaPersonalRating(winnerArenaTeam->GetSlot());
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA, rating ? rating : 1);
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA, GetMapId());
winnerArenaTeam->MemberWon(player, loserMatchmakerRating, winnerMatchmakerChange);
}
}
else
{
loserArenaTeam->MemberLost(player, winnerMatchmakerRating, loserMatchmakerChange);
// Arena lost => reset the win_rated_arena having the "no_lose" condition
player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE, 0);
}
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA, GetMapId());
}
uint32 winner_kills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_FIRST);
uint32 loser_kills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_FIRST);
uint32 winner_arena = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_FIRST);
// Reward winner team
if (bgTeamId == winnerTeamId)
if (bgTeamId == GetTeamId(winnerTeamId))
{
if (IsRandom() || BattlegroundMgr::IsBGWeekend(GetBgTypeID(true)))
{
@@ -1001,7 +861,7 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
UpdatePlayerScore(player, SCORE_BONUS_HONOR, GetBonusHonorFromKill(loser_kills));
}
sScriptMgr->OnBattlegroundEndReward(this, player, winnerTeamId);
sScriptMgr->OnBattlegroundEndReward(this, player, GetTeamId(winnerTeamId));
player->ResetAllPowers();
player->CombatStopWithPets(true);
@@ -1013,11 +873,11 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
if (isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE))
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_PLAYER);
BattlegroundScoreMap::const_iterator score = PlayerScores.find(player->GetGUID());
auto const& score = PlayerScores.find(player->GetGUID().GetCounter());
stmt->SetData(0, battlegroundId);
stmt->SetData(1, player->GetGUID().GetCounter());
stmt->SetData(2, bgTeamId == winnerTeamId);
stmt->SetData(2, bgTeamId == GetTeamId(winnerTeamId));
stmt->SetData(3, score->second->GetKillingBlows());
stmt->SetData(4, score->second->GetDeaths());
stmt->SetData(5, score->second->GetHonorableKills());
@@ -1040,21 +900,7 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, player->GetMapId());
}
if (isArena() && isRated() && winnerArenaTeam && loserArenaTeam && winnerArenaTeam != loserArenaTeam)
{
// save the stat changes
if (bValidArena) winnerArenaTeam->SaveToDB();
loserArenaTeam->SaveToDB();
// send updated arena team stats to players
// this way all arena team members will get notified, not only the ones who participated in this match
if (bValidArena) winnerArenaTeam->NotifyStatsChanged();
loserArenaTeam->NotifyStatsChanged();
}
if (winmsg_id)
SendMessageToAll(winmsg_id, CHAT_MSG_BG_SYSTEM_NEUTRAL);
sScriptMgr->OnBattlegroundEnd(this, winnerTeamId);
sScriptMgr->OnBattlegroundEnd(this, GetTeamId(winnerTeamId));
}
uint32 Battleground::GetBonusHonorFromKill(uint32 kills) const
@@ -1084,7 +930,7 @@ void Battleground::RemovePlayerAtLeave(Player* player)
}
// delete player score if exists
BattlegroundScoreMap::iterator itr2 = PlayerScores.find(player->GetGUID());
auto const& itr2 = PlayerScores.find(player->GetGUID().GetCounter());
if (itr2 != PlayerScores.end())
{
delete itr2->second;
@@ -1115,15 +961,6 @@ void Battleground::RemovePlayerAtLeave(Player* player)
player->ClearAfkReports();
//left a rated match in progress, consider as loser
if (isArena() && isRated() && status == STATUS_IN_PROGRESS && teamId != TEAM_NEUTRAL)
{
ArenaTeam* winnerArenaTeam = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeamId(teamId)));
ArenaTeam* loserArenaTeam = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(teamId));
if (winnerArenaTeam && loserArenaTeam && winnerArenaTeam != loserArenaTeam)
loserArenaTeam->MemberLost(player, GetArenaMatchmakerRating(GetOtherTeamId(teamId)));
}
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetCurrentBattlegroundQueueSlot(), STATUS_NONE, 0, 0, 0, TEAM_NEUTRAL);
player->GetSession()->SendPacket(&data);
@@ -1157,7 +994,7 @@ void Battleground::RemovePlayerAtLeave(Player* player)
// this method is called when creating bg
void Battleground::Init()
{
SetWinner(TEAM_NEUTRAL);
SetWinner(PVP_TEAM_NEUTRAL);
SetStatus(STATUS_WAIT_QUEUE);
SetStartTime(0);
SetEndTime(0);
@@ -1176,10 +1013,14 @@ void Battleground::Init()
m_Players.clear();
for (BattlegroundScoreMap::const_iterator itr = PlayerScores.begin(); itr != PlayerScores.end(); ++itr)
delete itr->second;
for (auto const& itr : PlayerScores)
delete itr.second;
PlayerScores.clear();
for (auto& itr : _arenaTeamScores)
itr.Reset();
ResetBGSubclass();
}
@@ -1220,27 +1061,12 @@ void Battleground::AddPlayer(Player* player)
// add arena specific auras
if (isArena())
{
player->RemoveArenaEnchantments(TEMP_ENCHANTMENT_SLOT);
if (teamId == TEAM_ALLIANCE) // gold
{
if (player->GetTeamId() == TEAM_HORDE)
player->CastSpell(player, SPELL_HORDE_GOLD_FLAG, true);
else
player->CastSpell(player, SPELL_ALLIANCE_GOLD_FLAG, true);
}
else // green
{
if (player->GetTeamId() == TEAM_HORDE)
player->CastSpell(player, SPELL_HORDE_GREEN_FLAG, true);
else
player->CastSpell(player, SPELL_ALLIANCE_GREEN_FLAG, true);
}
// restore pets health before remove
if (Pet* pet = player->GetPet())
if (pet->IsAlive())
pet->SetHealth(pet->GetMaxHealth());
player->RemoveArenaEnchantments(TEMP_ENCHANTMENT_SLOT);
player->DestroyConjuredItems(true);
player->UnsummonPetTemporaryIfAny();
@@ -1360,7 +1186,7 @@ bool Battleground::HasFreeSlots() const
{
if (GetStatus() != STATUS_WAIT_JOIN && GetStatus() != STATUS_IN_PROGRESS)
return false;
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i)
for (uint8 i = 0; i < PVP_TEAMS_COUNT; ++i)
if (GetFreeSlotsForTeam((TeamId)i) > 0)
return true;
return false;
@@ -1388,65 +1214,48 @@ void Battleground::ReadyMarkerClicked(Player* p)
}
}
void Battleground::UpdatePlayerScore(Player* player, 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(player->GetGUID());
if (itr == PlayerScores.end()) // player not found...
return;
uint8 type = (isArena() ? 1 : 0);
switch (type)
data.Initialize(MSG_PVP_LOG_DATA, 1 + 1 + 4 + 40 * GetPlayerScores()->size());
data << uint8(type); // type (battleground = 0 / arena = 1)
if (type) // arena
{
case SCORE_KILLING_BLOWS: // Killing blows
itr->second->KillingBlows += value;
if (isArena() && isRated())
{
ArenaLogEntryDataMap::iterator itr2 = ArenaLogEntries.find(player->GetGUID());
if (itr2 != ArenaLogEntries.end())
itr2->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)
player->RewardHonor(nullptr, 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;
if (isArena() && isRated() && GetStatus() == STATUS_IN_PROGRESS)
{
ArenaLogEntryDataMap::iterator itr2 = ArenaLogEntries.find(player->GetGUID());
if (itr2 != ArenaLogEntries.end())
itr2->second.DamageDone += value;
}
break;
case SCORE_HEALING_DONE: // Healing Done
itr->second->HealingDone += value;
if (isArena() && isRated() && GetStatus() == STATUS_IN_PROGRESS)
{
ArenaLogEntryDataMap::iterator itr2 = ArenaLogEntries.find(player->GetGUID());
if (itr2 != ArenaLogEntries.end())
itr2->second.HealingDone += value;
}
break;
default:
LOG_ERROR("bg.battleground", "Battleground::UpdatePlayerScore: unknown score type ({}) for BG (map: {}, instance id: {})!",
type, m_MapId, m_InstanceID);
break;
for (uint8 i = 0; i < PVP_TEAMS_COUNT; ++i)
_arenaTeamScores[i].BuildRatingInfoBlock(data);
for (uint8 i = 0; i < PVP_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(GetPlayerScores()->size());
for (auto const& score : PlayerScores)
score.second->AppendToPacket(data);
}
bool Battleground::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
{
auto const& itr = PlayerScores.find(player->GetGUID().GetCounter());
if (itr == PlayerScores.end()) // player not found...
return false;
if (type == SCORE_BONUS_HONOR && doAddHonor && isBattleground())
player->RewardHonor(nullptr, 1, value); // RewardHonor calls UpdatePlayerScore with doAddHonor = false
else
itr->second->UpdateScore(type, value);
return true;
}
void Battleground::AddPlayerToResurrectQueue(ObjectGuid npc_guid, ObjectGuid player_guid)
@@ -1678,7 +1487,7 @@ Creature* Battleground::AddCreature(uint32 entry, uint32 type, float x, float y,
if (creature->IsVehicle())
creature->SetPvP(true);
return creature;
return creature;
}
bool Battleground::DelCreature(uint32 type)
@@ -1920,7 +1729,7 @@ void Battleground::PlayerAddedToBGCheckIfBGIsRunning(Player* player)
WorldPacket data;
BlockMovement(player);
sBattlegroundMgr->BuildPvpLogDataPacket(&data, this);
BuildPvPLogDataPacket(data);
player->GetSession()->SendPacket(&data);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetCurrentBattlegroundQueueSlot(), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType(), player->GetBgTeamId());
@@ -1954,31 +1763,6 @@ int32 Battleground::GetObjectType(ObjectGuid guid)
return -1;
}
void Battleground::HandleKillUnit(Creature* /*victim*/, Player* /*killer*/)
{
}
void Battleground::CheckArenaAfterTimerConditions()
{
EndBattleground(TEAM_NEUTRAL);
}
void Battleground::CheckArenaWinConditions()
{
if (isArena() && GetStatus() <= STATUS_WAIT_JOIN) // pussywizard
return;
if (!GetAlivePlayersCountByTeam(TEAM_ALLIANCE) && GetPlayersCountByTeam(TEAM_HORDE))
EndBattleground(TEAM_HORDE);
else if (GetPlayersCountByTeam(TEAM_ALLIANCE) && !GetAlivePlayersCountByTeam(TEAM_HORDE))
EndBattleground(TEAM_ALLIANCE);
}
void Battleground::UpdateArenaWorldState()
{
UpdateWorldState(0xe10, GetAlivePlayersCountByTeam(TEAM_HORDE));
UpdateWorldState(0xe11, GetAlivePlayersCountByTeam(TEAM_ALLIANCE));
}
void Battleground::SetBgRaid(TeamId teamId, Group* bg_raid)
{
Group*& old_raid = m_BgRaids[teamId];