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
@@ -0,0 +1,8 @@
INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1645123941917942700');
DELETE FROM `acore_string` WHERE `entry` BETWEEN 600 AND 704;
DELETE FROM `acore_string` WHERE `entry` BETWEEN 724 AND 726;
DELETE FROM `acore_string` WHERE `entry` BETWEEN 753 AND 755;
DELETE FROM `acore_string` WHERE `entry` BETWEEN 1205 AND 1299;
DELETE FROM `acore_string` WHERE `entry` BETWEEN 1326 AND 1330;
DELETE FROM `acore_string` WHERE `entry` = 1333;
@@ -442,7 +442,7 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un
return false; return false;
} }
TeamId winnerTeam = bg->GetWinner(); TeamId winnerTeam = GetTeamId(bg->GetWinner());
if (winnerTeam == TEAM_NEUTRAL) if (winnerTeam == TEAM_NEUTRAL)
{ {
return false; return false;
+9 -9
View File
@@ -231,7 +231,7 @@ void Battlefield::InvitePlayerToQueue(Player* player)
void Battlefield::InvitePlayersInQueueToWar() void Battlefield::InvitePlayersInQueueToWar()
{ {
for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
{ {
GuidUnorderedSet copy(m_PlayersInQueue[team]); GuidUnorderedSet copy(m_PlayersInQueue[team]);
for (GuidUnorderedSet::const_iterator itr = copy.begin(); itr != copy.end(); ++itr) for (GuidUnorderedSet::const_iterator itr = copy.begin(); itr != copy.end(); ++itr)
@@ -252,7 +252,7 @@ void Battlefield::InvitePlayersInQueueToWar()
void Battlefield::InvitePlayersInZoneToWar() void Battlefield::InvitePlayersInZoneToWar()
{ {
for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
for (GuidUnorderedSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) for (GuidUnorderedSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
{ {
if (Player* player = ObjectAccessor::FindPlayer(*itr)) if (Player* player = ObjectAccessor::FindPlayer(*itr))
@@ -310,7 +310,7 @@ void Battlefield::InitStalker(uint32 entry, float x, float y, float z, float o)
void Battlefield::KickAfkPlayers() void Battlefield::KickAfkPlayers()
{ {
// xinef: optimization, dont lookup player twice // xinef: optimization, dont lookup player twice
for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
for (GuidUnorderedSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr) for (GuidUnorderedSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr)
if (Player* player = ObjectAccessor::FindPlayer(*itr)) if (Player* player = ObjectAccessor::FindPlayer(*itr))
if (player->isAFK() && player->GetZoneId() == GetZoneId() && !player->IsGameMaster()) if (player->isAFK() && player->GetZoneId() == GetZoneId() && !player->IsGameMaster())
@@ -331,7 +331,7 @@ void Battlefield::StartBattle()
if (m_isActive) if (m_isActive)
return; return;
for (int team = 0; team < BG_TEAMS_COUNT; team++) for (int team = 0; team < PVP_TEAMS_COUNT; team++)
{ {
m_PlayersInWar[team].clear(); m_PlayersInWar[team].clear();
m_Groups[team].clear(); m_Groups[team].clear();
@@ -378,7 +378,7 @@ void Battlefield::DoPlaySoundToAll(uint32 SoundID)
data.Initialize(SMSG_PLAY_SOUND, 4); data.Initialize(SMSG_PLAY_SOUND, 4);
data << uint32(SoundID); data << uint32(SoundID);
for (int team = 0; team < BG_TEAMS_COUNT; team++) for (int team = 0; team < PVP_TEAMS_COUNT; team++)
for (GuidUnorderedSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr) for (GuidUnorderedSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr)
if (Player* player = ObjectAccessor::FindPlayer(*itr)) if (Player* player = ObjectAccessor::FindPlayer(*itr))
player->GetSession()->SendPacket(&data); player->GetSession()->SendPacket(&data);
@@ -449,7 +449,7 @@ void Battlefield::TeamCastSpell(TeamId team, int32 spellId)
void Battlefield::BroadcastPacketToZone(WorldPacket& data) const void Battlefield::BroadcastPacketToZone(WorldPacket& data) const
{ {
for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
for (GuidUnorderedSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) for (GuidUnorderedSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
if (Player* player = ObjectAccessor::FindPlayer(*itr)) if (Player* player = ObjectAccessor::FindPlayer(*itr))
player->GetSession()->SendPacket(&data); player->GetSession()->SendPacket(&data);
@@ -457,7 +457,7 @@ void Battlefield::BroadcastPacketToZone(WorldPacket& data) const
void Battlefield::BroadcastPacketToQueue(WorldPacket& data) const void Battlefield::BroadcastPacketToQueue(WorldPacket& data) const
{ {
for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
for (GuidUnorderedSet::const_iterator itr = m_PlayersInQueue[team].begin(); itr != m_PlayersInQueue[team].end(); ++itr) for (GuidUnorderedSet::const_iterator itr = m_PlayersInQueue[team].begin(); itr != m_PlayersInQueue[team].end(); ++itr)
if (Player* player = ObjectAccessor::FindPlayer(*itr)) if (Player* player = ObjectAccessor::FindPlayer(*itr))
player->GetSession()->SendPacket(&data); player->GetSession()->SendPacket(&data);
@@ -465,7 +465,7 @@ void Battlefield::BroadcastPacketToQueue(WorldPacket& data) const
void Battlefield::BroadcastPacketToWar(WorldPacket& data) const void Battlefield::BroadcastPacketToWar(WorldPacket& data) const
{ {
for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
for (GuidUnorderedSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr) for (GuidUnorderedSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr)
if (Player* player = ObjectAccessor::FindPlayer(*itr)) if (Player* player = ObjectAccessor::FindPlayer(*itr))
player->GetSession()->SendPacket(&data); player->GetSession()->SendPacket(&data);
@@ -487,7 +487,7 @@ void Battlefield::SendWarningToPlayer(Player* player, uint32 entry)
void Battlefield::SendUpdateWorldState(uint32 field, uint32 value) void Battlefield::SendUpdateWorldState(uint32 field, uint32 value)
{ {
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) for (uint8 i = 0; i < PVP_TEAMS_COUNT; ++i)
for (GuidUnorderedSet::iterator itr = m_players[i].begin(); itr != m_players[i].end(); ++itr) for (GuidUnorderedSet::iterator itr = m_players[i].begin(); itr != m_players[i].end(); ++itr)
if (Player* player = ObjectAccessor::FindPlayer(*itr)) if (Player* player = ObjectAccessor::FindPlayer(*itr))
player->SendUpdateWorldState(field, value); player->SendUpdateWorldState(field, value);
+7 -7
View File
@@ -57,7 +57,7 @@ enum BattlefieldSounds
constexpr auto BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL = 1000; constexpr auto BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL = 1000;
const uint32 BattlefieldFactions[BG_TEAMS_COUNT] = const uint32 BattlefieldFactions[PVP_TEAMS_COUNT] =
{ {
1732, // Alliance 1732, // Alliance
1735 // Horde 1735 // Horde
@@ -372,11 +372,11 @@ protected:
BfCapturePointVector m_capturePoints; BfCapturePointVector m_capturePoints;
// Players info maps // Players info maps
GuidUnorderedSet m_players[BG_TEAMS_COUNT]; // Players in zone GuidUnorderedSet m_players[PVP_TEAMS_COUNT]; // Players in zone
GuidUnorderedSet m_PlayersInQueue[BG_TEAMS_COUNT]; // Players in the queue GuidUnorderedSet m_PlayersInQueue[PVP_TEAMS_COUNT]; // Players in the queue
GuidUnorderedSet m_PlayersInWar[BG_TEAMS_COUNT]; // Players in WG combat GuidUnorderedSet m_PlayersInWar[PVP_TEAMS_COUNT]; // Players in WG combat
PlayerTimerMap m_InvitedPlayers[BG_TEAMS_COUNT]; PlayerTimerMap m_InvitedPlayers[PVP_TEAMS_COUNT];
PlayerTimerMap m_PlayersWillBeKick[BG_TEAMS_COUNT]; PlayerTimerMap m_PlayersWillBeKick[PVP_TEAMS_COUNT];
// Variables that must exist for each battlefield // Variables that must exist for each battlefield
uint32 m_TypeId; // See enum BattlefieldTypes uint32 m_TypeId; // See enum BattlefieldTypes
@@ -403,7 +403,7 @@ protected:
uint32 m_StartGroupingTimer; // Timer for invite players in area 15 minute before start battle uint32 m_StartGroupingTimer; // Timer for invite players in area 15 minute before start battle
bool m_StartGrouping; // bool for know if all players in area has been invited bool m_StartGrouping; // bool for know if all players in area has been invited
GuidUnorderedSet m_Groups[BG_TEAMS_COUNT]; // Contain different raid group GuidUnorderedSet m_Groups[PVP_TEAMS_COUNT]; // Contain different raid group
std::vector<uint64> m_Data64; std::vector<uint64> m_Data64;
std::vector<uint32> m_Data32; std::vector<uint32> m_Data32;
@@ -315,7 +315,7 @@ void BattlefieldWG::UpdateCounterVehicle(bool init)
// Update vehicle count WorldState to player // Update vehicle count WorldState to player
void BattlefieldWG::UpdateVehicleCountWG() void BattlefieldWG::UpdateVehicleCountWG()
{ {
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) for (uint8 i = 0; i < PVP_TEAMS_COUNT; ++i)
for (GuidUnorderedSet::iterator itr = m_players[i].begin(); itr != m_players[i].end(); ++itr) for (GuidUnorderedSet::iterator itr = m_players[i].begin(); itr != m_players[i].end(); ++itr)
if (Player* player = ObjectAccessor::FindPlayer(*itr)) if (Player* player = ObjectAccessor::FindPlayer(*itr))
{ {
@@ -328,7 +328,7 @@ void BattlefieldWG::UpdateVehicleCountWG()
void BattlefieldWG::CapturePointTaken(uint32 areaId) void BattlefieldWG::CapturePointTaken(uint32 areaId)
{ {
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) for (uint8 i = 0; i < PVP_TEAMS_COUNT; ++i)
for (GuidUnorderedSet::iterator itr = m_players[i].begin(); itr != m_players[i].end(); ++itr) for (GuidUnorderedSet::iterator itr = m_players[i].begin(); itr != m_players[i].end(); ++itr)
if (Player* player = ObjectAccessor::FindPlayer(*itr)) if (Player* player = ObjectAccessor::FindPlayer(*itr))
if (player->GetAreaId() == areaId) if (player->GetAreaId() == areaId)
+328
View File
@@ -0,0 +1,328 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Arena.h"
#include "ArenaTeamMgr.h"
#include "Log.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "World.h"
#include "WorldSession.h"
#include "Pet.h"
#include "ScriptMgr.h"
//#include "WorldStatePackets.h"
void ArenaScore::AppendToPacket(WorldPacket& data)
{
data << PlayerGuid;
data << uint32(KillingBlows);
data << uint8(PvPTeamId);
data << uint32(DamageDone);
data << uint32(HealingDone);
BuildObjectivesBlock(data);
}
void ArenaScore::BuildObjectivesBlock(WorldPacket& data)
{
data << uint32(0); // Objectives Count
}
void ArenaTeamScore::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 ArenaTeamScore::BuildTeamInfoBlock(WorldPacket& data)
{
data << TeamName;
}
Arena::Arena()
{
StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
StartMessageIds[BG_STARTING_EVENT_FIRST] = ARENA_TEXT_START_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_SECOND] = ARENA_TEXT_START_THIRTY_SECONDS;
StartMessageIds[BG_STARTING_EVENT_THIRD] = ARENA_TEXT_START_FIFTEEN_SECONDS;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = ARENA_TEXT_START_BATTLE_HAS_BEGUN;
}
void Arena::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
PlayerScores.emplace(player->GetGUID().GetCounter(), new ArenaScore(player->GetGUID(), player->GetBgTeamId()));
if (player->GetBgTeamId() == 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);
}
UpdateArenaWorldState();
}
void Arena::RemovePlayer(Player* /*player*/)
{
if (GetStatus() == STATUS_WAIT_LEAVE)
return;
UpdateArenaWorldState();
CheckWinConditions();
}
void Arena::FillInitialWorldStates(WorldPacket& data)
{
data << uint32(ARENA_WORLD_STATE_ALIVE_PLAYERS_GREEN) << uint32(GetAlivePlayersCountByTeam(TEAM_HORDE));
data << uint32(ARENA_WORLD_STATE_ALIVE_PLAYERS_GOLD) << uint32(GetAlivePlayersCountByTeam(TEAM_ALLIANCE));
}
void Arena::UpdateArenaWorldState()
{
UpdateWorldState(ARENA_WORLD_STATE_ALIVE_PLAYERS_GREEN, GetAlivePlayersCountByTeam(TEAM_HORDE));
UpdateWorldState(ARENA_WORLD_STATE_ALIVE_PLAYERS_GOLD, GetAlivePlayersCountByTeam(TEAM_ALLIANCE));
}
void Arena::HandleKillPlayer(Player* player, Player* killer)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
Battleground::HandleKillPlayer(player, killer);
UpdateArenaWorldState();
CheckWinConditions();
}
void Arena::RemovePlayerAtLeave(Player* player)
{
if (isRated() && GetStatus() == STATUS_IN_PROGRESS)
{
if (auto const& member = Acore::Containers::MapGetValuePtr(m_Players, player->GetGUID()))
{
// if the player was a match participant, calculate rating
auto teamId = member->GetBgTeamId();
ArenaTeam* winnerArenaTeam = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeamId(teamId)));
ArenaTeam* loserArenaTeam = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(teamId));
if (winnerArenaTeam && loserArenaTeam && winnerArenaTeam != loserArenaTeam)
loserArenaTeam->MemberLost(player, GetArenaMatchmakerRating(GetOtherTeamId(teamId)));
}
}
// remove player
Battleground::RemovePlayerAtLeave(player);
}
void Arena::CheckWinConditions()
{
if (!GetAlivePlayersCountByTeam(TEAM_ALLIANCE) && GetPlayersCountByTeam(TEAM_HORDE))
EndBattleground(TEAM_HORDE);
else if (GetPlayersCountByTeam(TEAM_ALLIANCE) && !GetAlivePlayersCountByTeam(TEAM_HORDE))
EndBattleground(TEAM_ALLIANCE);
}
void Arena::EndBattleground(TeamId winnerTeamId)
{
if (isRated())
{
uint32 startDelay = GetStartDelayTime();
bool bValidArena = GetStatus() == STATUS_IN_PROGRESS && GetStartTime() >= startDelay + 15000; // pussywizard: only if arena lasted at least 15 secs
uint32 loserTeamRating = 0;
uint32 loserMatchmakerRating = 0;
int32 loserChange = 0;
int32 loserMatchmakerChange = 0;
uint32 winnerTeamRating = 0;
uint32 winnerMatchmakerRating = 0;
int32 winnerChange = 0;
int32 winnerMatchmakerChange = 0;
ArenaTeam* winnerArenaTeam = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(winnerTeamId == TEAM_NEUTRAL ? TEAM_HORDE : winnerTeamId));
ArenaTeam* loserArenaTeam = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(winnerTeamId == TEAM_NEUTRAL ? TEAM_ALLIANCE : GetOtherTeamId(winnerTeamId)));
auto SaveArenaLogs = [&]()
{
// pussywizard: arena logs in database
uint32 fightId = sArenaTeamMgr->GetNextArenaLogId();
uint32 currOnline = sWorld->GetActiveSessionCount();
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
CharacterDatabasePreparedStatement* stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_LOG_FIGHT);
stmt2->SetData(0, fightId);
stmt2->SetData(1, GetArenaType());
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 (auto const& [playerGuid, arenaLogEntryData] : ArenaLogEntries)
{
stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_LOG_MEMBERSTATS);
stmt2->SetData(0, fightId);
stmt2->SetData(1, ++memberId);
stmt2->SetData(2, arenaLogEntryData.Name);
stmt2->SetData(3, arenaLogEntryData.Guid);
stmt2->SetData(4, arenaLogEntryData.ArenaTeamId);
stmt2->SetData(5, arenaLogEntryData.Acc);
stmt2->SetData(6, arenaLogEntryData.IP);
stmt2->SetData(7, arenaLogEntryData.DamageDone);
stmt2->SetData(8, arenaLogEntryData.HealingDone);
stmt2->SetData(9, arenaLogEntryData.KillingBlows);
trans->Append(stmt2);
}
CharacterDatabase.CommitTransaction(trans);
};
if (winnerArenaTeam && loserArenaTeam && winnerArenaTeam != loserArenaTeam)
{
loserTeamRating = loserArenaTeam->GetRating();
loserMatchmakerRating = GetArenaMatchmakerRating(GetOtherTeamId(winnerTeamId));
winnerTeamRating = winnerArenaTeam->GetRating();
winnerMatchmakerRating = GetArenaMatchmakerRating(winnerTeamId);
if (winnerTeamId != TEAM_NEUTRAL)
{
winnerMatchmakerChange = bValidArena ? winnerArenaTeam->WonAgainst(winnerMatchmakerRating, loserMatchmakerRating, winnerChange, GetBgMap()) : 0;
loserMatchmakerChange = loserArenaTeam->LostAgainst(loserMatchmakerRating, winnerMatchmakerRating, loserChange, GetBgMap());
sScriptMgr->OnAfterArenaRatingCalculation(this, winnerMatchmakerChange, loserMatchmakerChange, winnerChange, loserChange);
LOG_DEBUG("bg.arena", "match Type: {} --- Winner: old rating: {}, rating gain: {}, old MMR: {}, MMR gain: {} --- Loser: old rating: {}, rating loss: {}, old MMR: {}, MMR loss: {} ---",
GetArenaType(), winnerTeamRating, winnerChange, winnerMatchmakerRating, winnerMatchmakerChange,
loserTeamRating, loserChange, loserMatchmakerRating, loserMatchmakerChange);
SetArenaMatchmakerRating(winnerTeamId, winnerMatchmakerRating + winnerMatchmakerChange);
SetArenaMatchmakerRating(GetOtherTeamId(winnerTeamId), loserMatchmakerRating + loserMatchmakerChange);
// bg team that the client expects is different to TeamId
// alliance 1, horde 0
uint8 winnerTeam = winnerTeamId == TEAM_ALLIANCE ? PVP_TEAM_ALLIANCE : PVP_TEAM_HORDE;
uint8 loserTeam = winnerTeamId == TEAM_ALLIANCE ? PVP_TEAM_HORDE : PVP_TEAM_ALLIANCE;
_arenaTeamScores[winnerTeam].Assign(winnerChange, winnerMatchmakerRating, winnerArenaTeam->GetName());
_arenaTeamScores[loserTeam].Assign(loserChange, loserMatchmakerRating, loserArenaTeam->GetName());
LOG_DEBUG("bg.arena", "Arena match Type: {} for Team1Id: {} - Team2Id: {} ended. WinnerTeamId: {}. Winner rating: +{}, Loser rating: {}",
GetArenaType(), GetArenaTeamIdForTeam(TEAM_ALLIANCE), GetArenaTeamIdForTeam(TEAM_HORDE), winnerArenaTeam->GetId(), winnerChange, loserChange);
}
else // Deduct 16 points from each teams arena-rating if there are no winners after 45+2 minutes
{
// 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;
_arenaTeamScores[PVP_TEAM_ALLIANCE].Assign(ARENA_TIMELIMIT_POINTS_LOSS, winnerMatchmakerRating, winnerArenaTeam->GetName());
_arenaTeamScores[PVP_TEAM_HORDE].Assign(ARENA_TIMELIMIT_POINTS_LOSS, loserMatchmakerRating, loserArenaTeam->GetName());
winnerArenaTeam->FinishGame(ARENA_TIMELIMIT_POINTS_LOSS, GetBgMap());
loserArenaTeam->FinishGame(ARENA_TIMELIMIT_POINTS_LOSS, GetBgMap());
}
}
SaveArenaLogs();
uint8 aliveWinners = GetAlivePlayersCountByTeam(winnerTeamId);
for (auto const& [playerGuid, player] : GetPlayers())
{
auto const& bgTeamId = player->GetBgTeamId();
// per player calculation
if (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());
// Last standing - Rated 5v5 arena & be solely alive player
if (GetArenaType() == ARENA_TYPE_5v5 && aliveWinners == 1 && player->IsAlive())
{
player->CastSpell(player, SPELL_LAST_MAN_STANDING, true);
}
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());
}
}
// save the stat changes
if (bValidArena)
{
winnerArenaTeam->SaveToDB();
winnerArenaTeam->NotifyStatsChanged();
}
loserArenaTeam->SaveToDB();
loserArenaTeam->NotifyStatsChanged();
}
// end battleground
Battleground::EndBattleground(winnerTeamId);
}
+66
View File
@@ -0,0 +1,66 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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 _ARENA_H
#define _ARENA_H
#include "Battleground.h"
enum ArenaBroadcastTexts
{
ARENA_TEXT_START_ONE_MINUTE = 15740,
ARENA_TEXT_START_THIRTY_SECONDS = 15741,
ARENA_TEXT_START_FIFTEEN_SECONDS = 15739,
ARENA_TEXT_START_BATTLE_HAS_BEGUN = 15742,
};
enum ArenaSpellIds
{
SPELL_ALLIANCE_GOLD_FLAG = 32724,
SPELL_ALLIANCE_GREEN_FLAG = 32725,
SPELL_HORDE_GOLD_FLAG = 35774,
SPELL_HORDE_GREEN_FLAG = 35775,
SPELL_LAST_MAN_STANDING = 26549 // Achievement Credit
};
enum ArenaWorldStates
{
ARENA_WORLD_STATE_ALIVE_PLAYERS_GREEN = 3600,
ARENA_WORLD_STATE_ALIVE_PLAYERS_GOLD = 3601
};
class AC_GAME_API Arena : public Battleground
{
protected:
Arena();
void AddPlayer(Player* player) override;
void RemovePlayer(Player* /*player*/) override;
void FillInitialWorldStates(WorldPacket& data) override;
void UpdateArenaWorldState();
void HandleKillPlayer(Player* player, Player* killer) override;
private:
void RemovePlayerAtLeave(Player* player) override;
void CheckWinConditions() override;
void EndBattleground(TeamId winnerTeamId) override;
};
#endif // WARHEAD_ARENA_H
@@ -0,0 +1,75 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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 _ARENA_SCORE_H
#define _ARENA_SCORE_H
#include "BattlegroundScore.h"
#include "StringFormat.h"
struct AC_GAME_API ArenaScore : public BattlegroundScore
{
friend class Arena;
protected:
ArenaScore(ObjectGuid playerGuid, TeamId team) :
BattlegroundScore(playerGuid), PvPTeamId(team == TEAM_ALLIANCE ? PVP_TEAM_ALLIANCE : PVP_TEAM_HORDE) { }
void AppendToPacket(WorldPacket& data) final override;
void BuildObjectivesBlock(WorldPacket& data) final override;
// For Logging purpose
std::string ToString() const override
{
return Acore::StringFormatFmt("Damage done: {}, Healing done: {}, Killing blows: {}", DamageDone, HealingDone, KillingBlows);
}
uint8 PvPTeamId;
};
struct AC_GAME_API ArenaTeamScore
{
friend class Arena;
friend class Battleground;
protected:
ArenaTeamScore() = default;
virtual ~ArenaTeamScore() = default;
void Reset()
{
RatingChange = 0;
MatchmakerRating = 0;
TeamName = {};
}
void Assign(int32 ratingChange, uint32 matchMakerRating, std::string_view teamName)
{
RatingChange = ratingChange;
MatchmakerRating = matchMakerRating;
TeamName = teamName;
}
void BuildRatingInfoBlock(WorldPacket& data);
void BuildTeamInfoBlock(WorldPacket& data);
int32 RatingChange = 0;
uint32 MatchmakerRating = 0;
std::string TeamName{};
};
#endif // WARHEAD_ARENA_SCORE_H
+147 -363
View File
@@ -26,7 +26,9 @@
#include "BattlegroundRL.h" #include "BattlegroundRL.h"
#include "BattlegroundRV.h" #include "BattlegroundRV.h"
#include "Chat.h" #include "Chat.h"
#include "ChatTextBuilder.h"
#include "Creature.h" #include "Creature.h"
#include "CreatureTextMgr.h"
#include "Formulas.h" #include "Formulas.h"
#include "GameGraveyard.h" #include "GameGraveyard.h"
#include "GridNotifiersImpl.h" #include "GridNotifiersImpl.h"
@@ -118,6 +120,20 @@ void Battleground::BroadcastWorker(Do& _do)
_do(itr->second); _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() Battleground::Battleground()
{ {
m_RealTypeID = BATTLEGROUND_TYPE_NONE; m_RealTypeID = BATTLEGROUND_TYPE_NONE;
@@ -129,7 +145,7 @@ Battleground::Battleground()
m_LastResurrectTime = 0; m_LastResurrectTime = 0;
m_ArenaType = 0; m_ArenaType = 0;
m_IsArena = false; m_IsArena = false;
m_WinnerId = TEAM_NEUTRAL; m_WinnerId = PVP_TEAM_NEUTRAL;
m_StartTime = 0; m_StartTime = 0;
m_ResetStatTimer = 0; m_ResetStatTimer = 0;
m_ValidStartPositionTimer = 0; m_ValidStartPositionTimer = 0;
@@ -138,7 +154,6 @@ Battleground::Battleground()
m_IsRated = false; m_IsRated = false;
m_BuffChange = false; m_BuffChange = false;
m_IsRandom = false; m_IsRandom = false;
m_Name = "";
m_LevelMin = 0; m_LevelMin = 0;
m_LevelMax = 0; m_LevelMax = 0;
m_SetDeleteThis = false; m_SetDeleteThis = false;
@@ -151,24 +166,9 @@ Battleground::Battleground()
m_StartMaxDist = 0.0f; m_StartMaxDist = 0.0f;
ScriptId = 0; 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_ALLIANCE] = 0;
m_ArenaTeamIds[TEAM_HORDE] = 0; m_ArenaTeamIds[TEAM_HORDE] = 0;
m_ArenaTeamRatingChanges[TEAM_ALLIANCE] = 0;
m_ArenaTeamRatingChanges[TEAM_HORDE] = 0;
m_ArenaTeamMMR[TEAM_ALLIANCE] = 0; m_ArenaTeamMMR[TEAM_ALLIANCE] = 0;
m_ArenaTeamMMR[TEAM_HORDE] = 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_SECOND] = BG_START_DELAY_1M;
StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_30S; StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_30S;
StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; 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_FIRST] = BG_TEXT_START_TWO_MINUTES;
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE; StartMessageIds[BG_STARTING_EVENT_SECOND] = BG_TEXT_START_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE; StartMessageIds[BG_STARTING_EVENT_THIRD] = BG_TEXT_START_HALF_MINUTE;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN; StartMessageIds[BG_STARTING_EVENT_FOURTH] = BG_TEXT_BATTLE_HAS_BEGUN;
// pussywizard: // pussywizard:
m_UpdateTimer = 0; m_UpdateTimer = 0;
@@ -205,6 +205,8 @@ Battleground::Battleground()
Battleground::~Battleground() Battleground::~Battleground()
{ {
LOG_DEBUG("bg.battleground", "> Remove Battleground {} {} {}", GetName(), GetBgTypeID(), GetInstanceID());
_reviveEvents.KillAllEvents(false); _reviveEvents.KillAllEvents(false);
// remove objects and creatures // remove objects and creatures
@@ -229,8 +231,8 @@ Battleground::~Battleground()
m_Map = nullptr; m_Map = nullptr;
} }
for (BattlegroundScoreMap::const_iterator itr = PlayerScores.begin(); itr != PlayerScores.end(); ++itr) for (auto const& itr : PlayerScores)
delete itr->second; delete itr.second;
} }
void Battleground::Update(uint32 diff) 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 if (GetStartTime() >= 46 * MINUTE * IN_MILLISECONDS) // pussywizard: 1min startup + 45min allowed duration
{ {
UpdateArenaWorldState(); EndBattleground(PVP_TEAM_NEUTRAL);
CheckArenaAfterTimerConditions();
return; return;
} }
} }
@@ -304,19 +305,20 @@ inline void Battleground::_CheckSafePositions(uint32 diff)
return; return;
m_ValidStartPositionTimer += diff; m_ValidStartPositionTimer += diff;
if (m_ValidStartPositionTimer >= CHECK_PLAYER_POSITION_INVERVAL) if (m_ValidStartPositionTimer >= CHECK_PLAYER_POSITION_INVERVAL)
{ {
m_ValidStartPositionTimer = 0; m_ValidStartPositionTimer = 0;
float x, y, z, o; for (auto const& [playerGuid, player] : GetPlayers())
for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
{ {
Position pos = itr->second->GetPosition(); Position pos = player->GetPosition();
GetTeamStartLoc(itr->second->GetBgTeamId(), x, y, z, o); Position const* startPos = GetTeamStartPosition(player->GetBgTeamId());
if (pos.GetExactDistSq(x, y, z) > maxDist)
if (pos.GetExactDistSq(startPos) > maxDist)
{ {
LOG_DEBUG("bg.battleground", "BATTLEGROUND: Sending {} back to start location (map: {}) (possible exploit)", itr->second->GetName(), GetMapId()); LOG_DEBUG("bg.battleground", "BATTLEGROUND: Sending {} back to start location (map: {}) (possible exploit)", player->GetName(), GetMapId());
itr->second->TeleportTo(GetMapId(), x, y, z, o); player->TeleportTo(GetMapId(), startPos->GetPositionX(), startPos->GetPositionY(), startPos->GetPositionZ(), startPos->GetOrientation());
} }
} }
} }
@@ -465,20 +467,26 @@ inline void Battleground::_ProcessJoin(uint32 diff)
StartingEventCloseDoors(); StartingEventCloseDoors();
SetStartDelayTime(StartDelayTimes[BG_STARTING_EVENT_FIRST]); SetStartDelayTime(StartDelayTimes[BG_STARTING_EVENT_FIRST]);
// First start warning - 2 or 1 minute // 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 // After 1 minute or 30 seconds, warning is signaled
else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_SECOND] && !(m_Events & BG_STARTING_EVENT_2)) else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_SECOND] && !(m_Events & BG_STARTING_EVENT_2))
{ {
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 // After 30 or 15 seconds, warning is signaled
else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_THIRD] && !(m_Events & BG_STARTING_EVENT_3)) else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_THIRD] && !(m_Events & BG_STARTING_EVENT_3))
{ {
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()) if (isArena())
switch (GetBgTypeID()) switch (GetBgTypeID())
@@ -514,7 +522,9 @@ inline void Battleground::_ProcessJoin(uint32 diff)
StartingEventOpenDoors(); 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); SetStatus(STATUS_IN_PROGRESS);
SetStartDelayTime(StartDelayTimes[BG_STARTING_EVENT_FOURTH]); 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) for (SpectatorList::const_iterator itr = m_Spectators.begin(); itr != m_Spectators.end(); ++itr)
ArenaSpectator::HandleResetCommand(*itr); ArenaSpectator::HandleResetCommand(*itr);
CheckArenaWinConditions(); CheckWinConditions();
// pussywizard: arena spectator stuff // pussywizard: arena spectator stuff
if (GetStatus() == STATUS_IN_PROGRESS) if (GetStatus() == STATUS_IN_PROGRESS)
@@ -591,7 +601,7 @@ inline void Battleground::_ProcessJoin(uint32 diff)
// Announce BG starting // Announce BG starting
if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE)) 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); 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; ASSERT(teamId < TEAM_NEUTRAL);
m_TeamStartLocY[teamId] = Y; _startPosition[teamId] = pos;
m_TeamStartLocZ[teamId] = Z; }
m_TeamStartLocO[teamId] = O;
Position const* Battleground::GetTeamStartPosition(TeamId teamId) const
{
ASSERT(teamId < TEAM_NEUTRAL);
return &_startPosition[teamId];
} }
void Battleground::SendPacketToAll(WorldPacket const* packet) void Battleground::SendPacketToAll(WorldPacket const* packet)
@@ -639,6 +653,24 @@ void Battleground::SendPacketToTeam(TeamId teamId, WorldPacket const* packet, Pl
itr->second->GetSession()->SendPacket(packet); 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) void Battleground::PlaySoundToAll(uint32 soundID)
{ {
WorldPacket data; WorldPacket data;
@@ -728,7 +760,7 @@ void Battleground::UpdateWorldState(uint32 variable, uint32 value)
SendPacketToAll(worldstate.Write()); 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 // xinef: if this is true, it means that endbattleground is called second time
// skip to avoid double rating reduce / add // skip to avoid double rating reduce / add
@@ -736,35 +768,23 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
// set as fast as possible // set as fast as possible
if (GetStatus() == STATUS_WAIT_LEAVE) if (GetStatus() == STATUS_WAIT_LEAVE)
return; 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); 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); SetWinner(winnerTeamId);
if (winnerTeamId == TEAM_ALLIANCE) if (winnerTeamId == PVP_TEAM_ALLIANCE)
{ {
winmsg_id = isBattleground() ? LANG_BG_A_WINS : LANG_ARENA_GOLD_WINS; if (isBattleground())
PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound 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; if (isBattleground())
PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound SendBroadcastText(BG_TEXT_HORDE_WINS, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound
} }
CharacterDatabasePreparedStatement* stmt = nullptr; CharacterDatabasePreparedStatement* stmt = nullptr;
@@ -782,7 +802,7 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_BATTLEGROUND); stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_BATTLEGROUND);
stmt->SetData(0, battlegroundId); stmt->SetData(0, battlegroundId);
stmt->SetData(1, GetPvPTeamId(GetWinner())); stmt->SetData(1, GetWinner());
stmt->SetData(2, GetUniqueBracketId()); stmt->SetData(2, GetUniqueBracketId());
stmt->SetData(3, GetBgTypeID(true)); stmt->SetData(3, GetBgTypeID(true));
CharacterDatabase.Execute(stmt); 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! //we must set it this way, because end time is sent in packet!
m_EndTime = TIME_TO_AUTOREMOVE; 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; WorldPacket pvpLogData;
sBattlegroundMgr->BuildPvpLogDataPacket(&pvpLogData, this); BuildPvPLogDataPacket(pvpLogData);
uint8 aliveWinners = GetAlivePlayersCountByTeam(winnerTeamId); for (auto const& [playerGuid, player] : m_Players)
for (BattlegroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{ {
Player* player = itr->second;
TeamId bgTeamId = player->GetBgTeamId(); TeamId bgTeamId = player->GetBgTeamId();
// should remove spirit of redemption // should remove spirit of redemption
if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); 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()) if (!player->IsAlive())
{ {
player->ResurrectPlayer(1.0f); player->ResurrectPlayer(1.0f);
@@ -948,38 +834,12 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
player->getHostileRefMgr().deleteReferences(); 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 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 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); uint32 winner_arena = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_FIRST);
// Reward winner team // Reward winner team
if (bgTeamId == winnerTeamId) if (bgTeamId == GetTeamId(winnerTeamId))
{ {
if (IsRandom() || BattlegroundMgr::IsBGWeekend(GetBgTypeID(true))) if (IsRandom() || BattlegroundMgr::IsBGWeekend(GetBgTypeID(true)))
{ {
@@ -1001,7 +861,7 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
UpdatePlayerScore(player, SCORE_BONUS_HONOR, GetBonusHonorFromKill(loser_kills)); UpdatePlayerScore(player, SCORE_BONUS_HONOR, GetBonusHonorFromKill(loser_kills));
} }
sScriptMgr->OnBattlegroundEndReward(this, player, winnerTeamId); sScriptMgr->OnBattlegroundEndReward(this, player, GetTeamId(winnerTeamId));
player->ResetAllPowers(); player->ResetAllPowers();
player->CombatStopWithPets(true); player->CombatStopWithPets(true);
@@ -1013,11 +873,11 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
if (isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE)) if (isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE))
{ {
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_PLAYER); 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(0, battlegroundId);
stmt->SetData(1, player->GetGUID().GetCounter()); 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(3, score->second->GetKillingBlows());
stmt->SetData(4, score->second->GetDeaths()); stmt->SetData(4, score->second->GetDeaths());
stmt->SetData(5, score->second->GetHonorableKills()); stmt->SetData(5, score->second->GetHonorableKills());
@@ -1040,21 +900,7 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, player->GetMapId()); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, player->GetMapId());
} }
if (isArena() && isRated() && winnerArenaTeam && loserArenaTeam && winnerArenaTeam != loserArenaTeam) sScriptMgr->OnBattlegroundEnd(this, GetTeamId(winnerTeamId));
{
// 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);
} }
uint32 Battleground::GetBonusHonorFromKill(uint32 kills) const uint32 Battleground::GetBonusHonorFromKill(uint32 kills) const
@@ -1084,7 +930,7 @@ void Battleground::RemovePlayerAtLeave(Player* player)
} }
// delete player score if exists // delete player score if exists
BattlegroundScoreMap::iterator itr2 = PlayerScores.find(player->GetGUID()); auto const& itr2 = PlayerScores.find(player->GetGUID().GetCounter());
if (itr2 != PlayerScores.end()) if (itr2 != PlayerScores.end())
{ {
delete itr2->second; delete itr2->second;
@@ -1115,15 +961,6 @@ void Battleground::RemovePlayerAtLeave(Player* player)
player->ClearAfkReports(); 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); sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetCurrentBattlegroundQueueSlot(), STATUS_NONE, 0, 0, 0, TEAM_NEUTRAL);
player->GetSession()->SendPacket(&data); player->GetSession()->SendPacket(&data);
@@ -1157,7 +994,7 @@ void Battleground::RemovePlayerAtLeave(Player* player)
// this method is called when creating bg // this method is called when creating bg
void Battleground::Init() void Battleground::Init()
{ {
SetWinner(TEAM_NEUTRAL); SetWinner(PVP_TEAM_NEUTRAL);
SetStatus(STATUS_WAIT_QUEUE); SetStatus(STATUS_WAIT_QUEUE);
SetStartTime(0); SetStartTime(0);
SetEndTime(0); SetEndTime(0);
@@ -1176,10 +1013,14 @@ void Battleground::Init()
m_Players.clear(); m_Players.clear();
for (BattlegroundScoreMap::const_iterator itr = PlayerScores.begin(); itr != PlayerScores.end(); ++itr) for (auto const& itr : PlayerScores)
delete itr->second; delete itr.second;
PlayerScores.clear(); PlayerScores.clear();
for (auto& itr : _arenaTeamScores)
itr.Reset();
ResetBGSubclass(); ResetBGSubclass();
} }
@@ -1220,27 +1061,12 @@ void Battleground::AddPlayer(Player* player)
// add arena specific auras // add arena specific auras
if (isArena()) 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 // restore pets health before remove
if (Pet* pet = player->GetPet()) if (Pet* pet = player->GetPet())
if (pet->IsAlive()) if (pet->IsAlive())
pet->SetHealth(pet->GetMaxHealth()); pet->SetHealth(pet->GetMaxHealth());
player->RemoveArenaEnchantments(TEMP_ENCHANTMENT_SLOT);
player->DestroyConjuredItems(true); player->DestroyConjuredItems(true);
player->UnsummonPetTemporaryIfAny(); player->UnsummonPetTemporaryIfAny();
@@ -1360,7 +1186,7 @@ bool Battleground::HasFreeSlots() const
{ {
if (GetStatus() != STATUS_WAIT_JOIN && GetStatus() != STATUS_IN_PROGRESS) if (GetStatus() != STATUS_WAIT_JOIN && GetStatus() != STATUS_IN_PROGRESS)
return false; 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) if (GetFreeSlotsForTeam((TeamId)i) > 0)
return true; return true;
return false; 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 uint8 type = (isArena() ? 1 : 0);
BattlegroundScoreMap::const_iterator itr = PlayerScores.find(player->GetGUID());
if (itr == PlayerScores.end()) // player not found...
return;
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 for (uint8 i = 0; i < PVP_TEAMS_COUNT; ++i)
itr->second->KillingBlows += value; _arenaTeamScores[i].BuildRatingInfoBlock(data);
if (isArena() && isRated())
{ for (uint8 i = 0; i < PVP_TEAMS_COUNT; ++i)
ArenaLogEntryDataMap::iterator itr2 = ArenaLogEntries.find(player->GetGUID()); _arenaTeamScores[i].BuildTeamInfoBlock(data);
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;
} }
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) 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()) if (creature->IsVehicle())
creature->SetPvP(true); creature->SetPvP(true);
return creature; return creature;
} }
bool Battleground::DelCreature(uint32 type) bool Battleground::DelCreature(uint32 type)
@@ -1920,7 +1729,7 @@ void Battleground::PlayerAddedToBGCheckIfBGIsRunning(Player* player)
WorldPacket data; WorldPacket data;
BlockMovement(player); BlockMovement(player);
sBattlegroundMgr->BuildPvpLogDataPacket(&data, this); BuildPvPLogDataPacket(data);
player->GetSession()->SendPacket(&data); player->GetSession()->SendPacket(&data);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetCurrentBattlegroundQueueSlot(), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType(), player->GetBgTeamId()); 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; 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) void Battleground::SetBgRaid(TeamId teamId, Group* bg_raid)
{ {
Group*& old_raid = m_BgRaids[teamId]; Group*& old_raid = m_BgRaids[teamId];
+78 -133
View File
@@ -18,6 +18,7 @@
#ifndef __BATTLEGROUND_H #ifndef __BATTLEGROUND_H
#define __BATTLEGROUND_H #define __BATTLEGROUND_H
#include "ArenaScore.h"
#include "Common.h" #include "Common.h"
#include "DBCEnums.h" #include "DBCEnums.h"
#include "GameObject.h" #include "GameObject.h"
@@ -53,6 +54,17 @@ enum BattlegroundDesertionType
BG_DESERTION_TYPE_INVITE_LOGOUT = 4, // player is invited to join and logs out BG_DESERTION_TYPE_INVITE_LOGOUT = 4, // player is invited to join and logs out
}; };
enum BattlegroundBroadcastTexts
{
BG_TEXT_ALLIANCE_WINS = 10633,
BG_TEXT_HORDE_WINS = 10634,
BG_TEXT_START_TWO_MINUTES = 18193,
BG_TEXT_START_ONE_MINUTE = 18194,
BG_TEXT_START_HALF_MINUTE = 18195,
BG_TEXT_BATTLE_HAS_BEGUN = 18196,
};
enum BattlegroundSounds enum BattlegroundSounds
{ {
SOUND_HORDE_WINS = 8454, SOUND_HORDE_WINS = 8454,
@@ -111,17 +123,12 @@ enum BattlegroundSpells
SPELL_SPIRIT_HEAL = 22012, // Spirit Heal SPELL_SPIRIT_HEAL = 22012, // Spirit Heal
SPELL_RESURRECTION_VISUAL = 24171, // Resurrection Impact Visual SPELL_RESURRECTION_VISUAL = 24171, // Resurrection Impact Visual
SPELL_ARENA_PREPARATION = 32727, // use this one, 32728 not correct SPELL_ARENA_PREPARATION = 32727, // use this one, 32728 not correct
SPELL_ALLIANCE_GOLD_FLAG = 32724,
SPELL_ALLIANCE_GREEN_FLAG = 32725,
SPELL_HORDE_GOLD_FLAG = 35774,
SPELL_HORDE_GREEN_FLAG = 35775,
SPELL_PREPARATION = 44521, // Preparation SPELL_PREPARATION = 44521, // Preparation
SPELL_SPIRIT_HEAL_MANA = 44535, // Spirit Heal SPELL_SPIRIT_HEAL_MANA = 44535, // Spirit Heal
SPELL_RECENTLY_DROPPED_FLAG = 42792, // Recently Dropped Flag SPELL_RECENTLY_DROPPED_FLAG = 42792, // Recently Dropped Flag
SPELL_AURA_PLAYER_INACTIVE = 43681, // Inactive SPELL_AURA_PLAYER_INACTIVE = 43681, // Inactive
SPELL_HONORABLE_DEFENDER_25Y = 68652, // +50% honor when standing at a capture point that you control, 25yards radius (added in 3.2) SPELL_HONORABLE_DEFENDER_25Y = 68652, // +50% honor when standing at a capture point that you control, 25yards radius (added in 3.2)
SPELL_HONORABLE_DEFENDER_60Y = 66157, // +50% honor when standing at a capture point that you control, 60yards radius (added in 3.2), probably for 40+ player battlegrounds SPELL_HONORABLE_DEFENDER_60Y = 66157 // +50% honor when standing at a capture point that you control, 60yards radius (added in 3.2), probably for 40+ player battlegrounds
SPELL_THE_LAST_STANDING = 26549, // Arena achievement related
}; };
enum BattlegroundReputations enum BattlegroundReputations
@@ -180,11 +187,6 @@ enum BattlegroundStatus
STATUS_WAIT_LEAVE = 4 // means some faction has won BG and it is ending STATUS_WAIT_LEAVE = 4 // means some faction has won BG and it is ending
}; };
enum BattlegroundTeams
{
BG_TEAMS_COUNT = 2
};
struct BattlegroundObjectInfo struct BattlegroundObjectInfo
{ {
BattlegroundObjectInfo() = default; BattlegroundObjectInfo() = default;
@@ -194,35 +196,7 @@ struct BattlegroundObjectInfo
uint32 spellid{0}; uint32 spellid{0};
}; };
enum ScoreType enum ArenaType : uint8
{
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, ARENA_TYPE_2v2 = 2,
ARENA_TYPE_3v3 = 3, ARENA_TYPE_3v3 = 3,
@@ -251,43 +225,15 @@ enum BattlegroundStartingEventsIds
BG_STARTING_EVENT_THIRD = 2, BG_STARTING_EVENT_THIRD = 2,
BG_STARTING_EVENT_FOURTH = 3 BG_STARTING_EVENT_FOURTH = 3
}; };
#define BG_STARTING_EVENT_COUNT 4
struct BattlegroundScore constexpr auto BG_STARTING_EVENT_COUNT = 4;
{
BattlegroundScore(Player* player) : KillingBlows(0), Deaths(0), HonorableKills(0), BonusHonor(0),
DamageDone(0), HealingDone(0), player(player)
{ }
virtual ~BattlegroundScore() = default; //virtual destructor is used when deleting score from scores map
uint32 KillingBlows;
uint32 Deaths;
uint32 HonorableKills;
uint32 BonusHonor;
uint32 DamageDone;
uint32 HealingDone;
Player* player;
[[nodiscard]] uint32 GetKillingBlows() const { return KillingBlows; }
[[nodiscard]] uint32 GetDeaths() const { return Deaths; }
[[nodiscard]] uint32 GetHonorableKills() const { return HonorableKills; }
[[nodiscard]] uint32 GetBonusHonor() const { return BonusHonor; }
[[nodiscard]] uint32 GetDamageDone() const { return DamageDone; }
[[nodiscard]] uint32 GetHealingDone() const { return HealingDone; }
[[nodiscard]] virtual uint32 GetAttr1() const { return 0; }
[[nodiscard]] virtual uint32 GetAttr2() const { return 0; }
[[nodiscard]] virtual uint32 GetAttr3() const { return 0; }
[[nodiscard]] virtual uint32 GetAttr4() const { return 0; }
[[nodiscard]] virtual uint32 GetAttr5() const { return 0; }
};
class ArenaLogEntryData class ArenaLogEntryData
{ {
public: public:
ArenaLogEntryData() = default; ArenaLogEntryData() = default;
void Fill(const char* name, ObjectGuid::LowType guid, uint32 acc, uint32 arenaTeamId, std::string ip)
void Fill(std::string_view name, ObjectGuid::LowType guid, uint32 acc, uint32 arenaTeamId, std::string ip)
{ {
Name = std::string(name); Name = std::string(name);
Guid = guid; Guid = guid;
@@ -296,11 +242,11 @@ public:
IP = ip; IP = ip;
} }
std::string Name; std::string Name{};
ObjectGuid::LowType Guid{0}; ObjectGuid::LowType Guid{0};
uint32 Acc; uint32 Acc{0};
uint32 ArenaTeamId{0}; uint32 ArenaTeamId{0};
std::string IP; std::string IP{};
uint32 DamageDone{0}; uint32 DamageDone{0};
uint32 HealingDone{0}; uint32 HealingDone{0};
uint32 KillingBlows{0}; uint32 KillingBlows{0};
@@ -318,11 +264,11 @@ enum BGHonorMode
#define ARENA_READY_MARKER_ENTRY 301337 #define ARENA_READY_MARKER_ENTRY 301337
/* /*
This class is used to: This class is used to:
1. Add player to battleground 1. Add player to battleground
2. Remove player from battleground 2. Remove player from battleground
3. some certain cases, same for all battlegrounds 3. some certain cases, same for all battlegrounds
4. It has properties same for all battlegrounds 4. It has properties same for all battlegrounds
*/ */
enum BattlegroundQueueInvitationType enum BattlegroundQueueInvitationType
@@ -344,6 +290,7 @@ public:
{ {
return true; return true;
} }
virtual void Init(); virtual void Init();
virtual void StartingEventCloseDoors() { } virtual void StartingEventCloseDoors() { }
virtual void StartingEventOpenDoors() { } virtual void StartingEventOpenDoors() { }
@@ -357,7 +304,7 @@ public:
/* Battleground */ /* Battleground */
// Get methods: // Get methods:
[[nodiscard]] char const* GetName() const { return m_Name; } [[nodiscard]] std::string GetName() const { return m_Name; }
[[nodiscard]] BattlegroundTypeId GetBgTypeID(bool GetRandom = false) const { return GetRandom ? m_RandomTypeID : m_RealTypeID; } [[nodiscard]] BattlegroundTypeId GetBgTypeID(bool GetRandom = false) const { return GetRandom ? m_RandomTypeID : m_RealTypeID; }
[[nodiscard]] uint32 GetInstanceID() const { return m_InstanceID; } [[nodiscard]] uint32 GetInstanceID() const { return m_InstanceID; }
[[nodiscard]] BattlegroundStatus GetStatus() const { return m_Status; } [[nodiscard]] BattlegroundStatus GetStatus() const { return m_Status; }
@@ -374,29 +321,29 @@ public:
[[nodiscard]] int32 GetStartDelayTime() const { return m_StartDelayTime; } [[nodiscard]] int32 GetStartDelayTime() const { return m_StartDelayTime; }
[[nodiscard]] uint8 GetArenaType() const { return m_ArenaType; } [[nodiscard]] uint8 GetArenaType() const { return m_ArenaType; }
[[nodiscard]] TeamId GetWinner() const { return m_WinnerId; } [[nodiscard]] PvPTeamId GetWinner() const { return m_WinnerId; }
[[nodiscard]] uint32 GetScriptId() const { return ScriptId; } [[nodiscard]] uint32 GetScriptId() const { return ScriptId; }
[[nodiscard]] uint32 GetBonusHonorFromKill(uint32 kills) const; [[nodiscard]] uint32 GetBonusHonorFromKill(uint32 kills) const;
bool IsRandom() { return m_IsRandom; } bool IsRandom() { return m_IsRandom; }
// Set methods: // Set methods:
void SetName(char const* Name) { m_Name = Name; } void SetName(std::string_view name) { m_Name = std::string(name); }
void SetBgTypeID(BattlegroundTypeId TypeID) { m_RealTypeID = TypeID; } void SetBgTypeID(BattlegroundTypeId TypeID) { m_RealTypeID = TypeID; }
void SetRandomTypeID(BattlegroundTypeId TypeID) { m_RandomTypeID = TypeID; } void SetRandomTypeID(BattlegroundTypeId TypeID) { m_RandomTypeID = TypeID; }
void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; } void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; }
void SetStatus(BattlegroundStatus Status) { m_Status = Status; } void SetStatus(BattlegroundStatus Status) { m_Status = Status; }
void SetClientInstanceID(uint32 InstanceID) { m_ClientInstanceID = InstanceID; } void SetClientInstanceID(uint32 InstanceID) { m_ClientInstanceID = InstanceID; }
void SetStartTime(uint32 Time) { m_StartTime = Time; } void SetStartTime(uint32 Time) { m_StartTime = Time; }
void SetEndTime(uint32 Time) { m_EndTime = Time; } void SetEndTime(uint32 Time) { m_EndTime = Time; }
void SetLastResurrectTime(uint32 Time) { m_LastResurrectTime = Time; } void SetLastResurrectTime(uint32 Time) { m_LastResurrectTime = Time; }
void SetLevelRange(uint32 min, uint32 max) { m_LevelMin = min; m_LevelMax = max; } void SetLevelRange(uint32 min, uint32 max) { m_LevelMin = min; m_LevelMax = max; }
void SetRated(bool state) { m_IsRated = state; } void SetRated(bool state) { m_IsRated = state; }
void SetArenaType(uint8 type) { m_ArenaType = type; } void SetArenaType(uint8 type) { m_ArenaType = type; }
void SetArenaorBGType(bool _isArena) { m_IsArena = _isArena; } void SetArenaorBGType(bool _isArena) { m_IsArena = _isArena; }
void SetWinner(TeamId winner) { m_WinnerId = winner; } void SetWinner(PvPTeamId winner) { m_WinnerId = winner; }
void SetScriptId(uint32 scriptId) { ScriptId = scriptId; } void SetScriptId(uint32 scriptId) { ScriptId = scriptId; }
void SetRandom(bool isRandom) { m_IsRandom = isRandom; } void SetRandom(bool isRandom) { m_IsRandom = isRandom; }
void ModifyStartDelayTime(int32 diff) { m_StartDelayTime -= diff; } void ModifyStartDelayTime(int32 diff) { m_StartDelayTime -= diff; }
void SetStartDelayTime(int32 Time) { m_StartDelayTime = Time; } void SetStartDelayTime(int32 Time) { m_StartDelayTime = Time; }
@@ -433,12 +380,11 @@ public:
void ReadyMarkerClicked(Player* p); // pussywizard void ReadyMarkerClicked(Player* p); // pussywizard
GuidSet readyMarkerClickedSet; // pussywizard GuidSet readyMarkerClickedSet; // pussywizard
typedef std::map<ObjectGuid, BattlegroundScore*> BattlegroundScoreMap; typedef std::unordered_map<ObjectGuid::LowType, BattlegroundScore*> BattlegroundScoreMap;
typedef std::map<ObjectGuid, ArenaLogEntryData> ArenaLogEntryDataMap;// pussywizard typedef std::unordered_map<ObjectGuid, ArenaLogEntryData> ArenaLogEntryDataMap; // pussywizard
ArenaLogEntryDataMap ArenaLogEntries; // pussywizard ArenaLogEntryDataMap ArenaLogEntries; // pussywizard
[[nodiscard]] BattlegroundScoreMap::const_iterator GetPlayerScoresBegin() const { return PlayerScores.begin(); } [[nodiscard]] BattlegroundScoreMap const* GetPlayerScores() const { return &PlayerScores; }
[[nodiscard]] BattlegroundScoreMap::const_iterator GetPlayerScoresEnd() const { return PlayerScores.end(); } [[nodiscard]] std::size_t GetPlayerScoresSize() const { return PlayerScores.size(); }
[[nodiscard]] uint32 GetPlayerScoresSize() const { return PlayerScores.size(); }
[[nodiscard]] uint32 GetReviveQueueSize() const { return m_ReviveQueue.size(); } [[nodiscard]] uint32 GetReviveQueueSize() const { return m_ReviveQueue.size(); }
@@ -462,25 +408,22 @@ public:
[[nodiscard]] BattlegroundMap* GetBgMap() const { ASSERT(m_Map); return m_Map; } [[nodiscard]] BattlegroundMap* GetBgMap() const { ASSERT(m_Map); return m_Map; }
[[nodiscard]] BattlegroundMap* FindBgMap() const { return m_Map; } [[nodiscard]] BattlegroundMap* FindBgMap() const { return m_Map; }
void SetTeamStartLoc(TeamId teamId, float X, float Y, float Z, float O); void SetTeamStartPosition(TeamId teamId, Position const& pos);
void GetTeamStartLoc(TeamId teamId, float& X, float& Y, float& Z, float& O) const Position const* GetTeamStartPosition(TeamId teamId) const;
{
X = m_TeamStartLocX[teamId];
Y = m_TeamStartLocY[teamId];
Z = m_TeamStartLocZ[teamId];
O = m_TeamStartLocO[teamId];
}
void SetStartMaxDist(float startMaxDist) { m_StartMaxDist = startMaxDist; } void SetStartMaxDist(float startMaxDist) { m_StartMaxDist = startMaxDist; }
[[nodiscard]] float GetStartMaxDist() const { return m_StartMaxDist; } [[nodiscard]] float GetStartMaxDist() const { return m_StartMaxDist; }
// Packet Transfer // Packet Transfer
// method that should fill worldpacket with actual world states (not yet implemented for all battlegrounds!) // method that should fill worldpacket with actual world states (not yet implemented for all battlegrounds!)
virtual void FillInitialWorldStates(WorldPacket& /*data*/) {} virtual void FillInitialWorldStates(WorldPacket& /*data*/) { }
void SendPacketToTeam(TeamId teamId, WorldPacket const* packet, Player* sender = nullptr, bool self = true); void SendPacketToTeam(TeamId teamId, WorldPacket const* packet, Player* sender = nullptr, bool self = true);
void SendPacketToAll(WorldPacket const* packet); void SendPacketToAll(WorldPacket const* packet);
void YellToAll(Creature* creature, const char* text, uint32 language); void YellToAll(Creature* creature, const char* text, uint32 language);
void SendChatMessage(Creature* source, uint8 textId, WorldObject* target = nullptr);
void SendBroadcastText(uint32 id, ChatMsg msgType, WorldObject const* target = nullptr);
template<class Do> template<class Do>
void BroadcastWorker(Do& _do); void BroadcastWorker(Do& _do);
@@ -493,7 +436,14 @@ public:
void UpdateWorldState(uint32 variable, uint32 value); void UpdateWorldState(uint32 variable, uint32 value);
virtual void EndBattleground(TeamId winnerTeamId); void EndBattleground(PvPTeamId winnerTeamId);
// deprecated, need delete
virtual void EndBattleground(TeamId winnerTeamId)
{
EndBattleground(GetPvPTeamId(winnerTeamId));
}
void BlockMovement(Player* player); void BlockMovement(Player* player);
void SendWarningToAll(uint32 entry, ...); void SendWarningToAll(uint32 entry, ...);
@@ -507,7 +457,8 @@ public:
[[nodiscard]] Group* GetBgRaid(TeamId teamId) const { return m_BgRaids[teamId]; } [[nodiscard]] Group* GetBgRaid(TeamId teamId) const { return m_BgRaids[teamId]; }
void SetBgRaid(TeamId teamId, Group* bg_raid); void SetBgRaid(TeamId 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);
[[nodiscard]] uint32 GetPlayersCountByTeam(TeamId teamId) const { return m_PlayersCount[teamId]; } [[nodiscard]] uint32 GetPlayersCountByTeam(TeamId teamId) const { return m_PlayersCount[teamId]; }
[[nodiscard]] uint32 GetAlivePlayersCountByTeam(TeamId teamId) const; // used in arenas to correctly handle death in spirit of redemption / last stand etc. (killer = killed) cases [[nodiscard]] uint32 GetAlivePlayersCountByTeam(TeamId teamId) const; // used in arenas to correctly handle death in spirit of redemption / last stand etc. (killer = killed) cases
@@ -519,23 +470,20 @@ public:
++m_PlayersCount[teamId]; ++m_PlayersCount[teamId];
} }
virtual void CheckWinConditions() { }
// used for rated arena battles // used for rated arena battles
void SetArenaTeamIdForTeam(TeamId teamId, uint32 ArenaTeamId) { m_ArenaTeamIds[teamId] = ArenaTeamId; } void SetArenaTeamIdForTeam(TeamId teamId, uint32 ArenaTeamId) { m_ArenaTeamIds[teamId] = ArenaTeamId; }
[[nodiscard]] uint32 GetArenaTeamIdForTeam(TeamId teamId) const { return m_ArenaTeamIds[teamId]; } [[nodiscard]] uint32 GetArenaTeamIdForTeam(TeamId teamId) const { return m_ArenaTeamIds[teamId]; }
void SetArenaTeamRatingChangeForTeam(TeamId teamId, int32 RatingChange) { m_ArenaTeamRatingChanges[teamId] = RatingChange; } void SetArenaMatchmakerRating(TeamId teamId, uint32 MMR) { m_ArenaTeamMMR[teamId] = MMR; }
[[nodiscard]] int32 GetArenaTeamRatingChangeForTeam(TeamId teamId) const { return m_ArenaTeamRatingChanges[teamId]; } [[nodiscard]] uint32 GetArenaMatchmakerRating(TeamId teamId) const { return m_ArenaTeamMMR[teamId]; }
void SetArenaMatchmakerRating(TeamId teamId, uint32 MMR) { m_ArenaTeamMMR[teamId] = MMR; }
[[nodiscard]] uint32 GetArenaMatchmakerRating(TeamId teamId) const { return m_ArenaTeamMMR[teamId]; }
void CheckArenaAfterTimerConditions();
void CheckArenaWinConditions();
virtual void UpdateArenaWorldState();
// Triggers handle // Triggers handle
// must be implemented in BG subclass // must be implemented in BG subclass
virtual void HandleAreaTrigger(Player* /*player*/, uint32 /*trigger*/) {} virtual void HandleAreaTrigger(Player* /*player*/, uint32 /*trigger*/) {}
// must be implemented in BG subclass if need AND call base class generic code // must be implemented in BG subclass if need AND call base class generic code
virtual void HandleKillPlayer(Player* player, Player* killer); virtual void HandleKillPlayer(Player* player, Player* killer);
virtual void HandleKillUnit(Creature* /*unit*/, Player* /*killer*/); virtual void HandleKillUnit(Creature* /*unit*/, Player* /*killer*/) { }
// Battleground events // Battleground events
virtual void EventPlayerDroppedFlag(Player* /*player*/) {} virtual void EventPlayerDroppedFlag(Player* /*player*/) {}
@@ -555,7 +503,7 @@ public:
void AddOrSetPlayerToCorrectBgGroup(Player* player, TeamId teamId); void AddOrSetPlayerToCorrectBgGroup(Player* player, TeamId teamId);
void RemovePlayerAtLeave(Player* player); virtual void RemovePlayerAtLeave(Player* player);
// can be extended in in BG subclass // can be extended in in BG subclass
void HandleTriggerBuff(GameObject* gameObject); void HandleTriggerBuff(GameObject* gameObject);
@@ -659,11 +607,13 @@ protected:
// this must be filled in constructors! // this must be filled in constructors!
uint32 StartMessageIds[BG_STARTING_EVENT_COUNT]; uint32 StartMessageIds[BG_STARTING_EVENT_COUNT];
bool m_BuffChange; bool m_BuffChange;
bool m_IsRandom; bool m_IsRandom;
BGHonorMode m_HonorMode; BGHonorMode m_HonorMode;
int32 m_TeamScores[BG_TEAMS_COUNT]; int32 m_TeamScores[PVP_TEAMS_COUNT];
ArenaTeamScore _arenaTeamScores[PVP_TEAMS_COUNT];
// pussywizard: // pussywizard:
uint32 m_UpdateTimer; uint32 m_UpdateTimer;
@@ -685,12 +635,12 @@ private:
uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5 uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5
bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave
bool m_IsArena; bool m_IsArena;
TeamId m_WinnerId; PvPTeamId m_WinnerId;
int32 m_StartDelayTime; int32 m_StartDelayTime;
bool m_IsRated; // is this battle rated? bool m_IsRated; // is this battle rated?
bool m_PrematureCountDown; bool m_PrematureCountDown;
uint32 m_PrematureCountDownTimer; uint32 m_PrematureCountDownTimer;
char const* m_Name; std::string m_Name{};
/* Pre- and post-update hooks */ /* Pre- and post-update hooks */
@@ -729,22 +679,20 @@ private:
// Invited counters are useful for player invitation to BG - do not allow, if BG is started to one faction to have 2 more players than another faction // Invited counters are useful for player invitation to BG - do not allow, if BG is started to one faction to have 2 more players than another faction
// Invited counters will be changed only when removing already invited player from queue, removing player from battleground and inviting player to BG // Invited counters will be changed only when removing already invited player from queue, removing player from battleground and inviting player to BG
// Invited players counters // Invited players counters
uint32 m_BgInvitedPlayers[BG_TEAMS_COUNT]; uint32 m_BgInvitedPlayers[PVP_TEAMS_COUNT];
// Raid Group // Raid Group
Group* m_BgRaids[BG_TEAMS_COUNT]; // 0 - alliance, 1 - horde Group* m_BgRaids[PVP_TEAMS_COUNT]; // 0 - alliance, 1 - horde
SpectatorList m_Spectators; SpectatorList m_Spectators;
ToBeTeleportedMap m_ToBeTeleported; ToBeTeleportedMap m_ToBeTeleported;
// Players count by team // Players count by team
uint32 m_PlayersCount[BG_TEAMS_COUNT]; uint32 m_PlayersCount[PVP_TEAMS_COUNT];
// Arena team ids by team // Arena team ids by team
uint32 m_ArenaTeamIds[BG_TEAMS_COUNT]; uint32 m_ArenaTeamIds[PVP_TEAMS_COUNT];
uint32 m_ArenaTeamMMR[PVP_TEAMS_COUNT];
int32 m_ArenaTeamRatingChanges[BG_TEAMS_COUNT];
uint32 m_ArenaTeamMMR[BG_TEAMS_COUNT];
// Limits // Limits
uint32 m_LevelMin; uint32 m_LevelMin;
@@ -755,11 +703,8 @@ private:
// Start location // Start location
uint32 m_MapId; uint32 m_MapId;
BattlegroundMap* m_Map; BattlegroundMap* m_Map;
float m_TeamStartLocX[BG_TEAMS_COUNT];
float m_TeamStartLocY[BG_TEAMS_COUNT];
float m_TeamStartLocZ[BG_TEAMS_COUNT];
float m_TeamStartLocO[BG_TEAMS_COUNT];
float m_StartMaxDist; float m_StartMaxDist;
std::array<Position, PVP_TEAMS_COUNT> _startPosition;
uint32 ScriptId; uint32 ScriptId;
}; };
#endif #endif
+22 -255
View File
@@ -204,179 +204,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 (TeamId iTeamId = TEAM_ALLIANCE; iTeamId <= TEAM_HORDE; iTeamId = TeamId(iTeamId + 1))
{
// Xinef: oryginally this was looping in reverse order, loop order was changed so we have to change checked teamId
int32 rating_change = bg->GetArenaTeamRatingChangeForTeam(Battleground::GetOtherTeamId(iTeamId));
uint32 pointsLost = rating_change < 0 ? -rating_change : 0;
uint32 pointsGained = rating_change > 0 ? rating_change : 0;
uint32 MatchmakerRating = bg->GetArenaMatchmakerRating(Battleground::GetOtherTeamId(iTeamId));
*data << uint32(pointsLost); // Rating Lost
*data << uint32(pointsGained); // Rating gained
*data << uint32(MatchmakerRating); // Matchmaking Value
}
for (TeamId iTeamId = TEAM_ALLIANCE; iTeamId <= TEAM_HORDE; iTeamId = TeamId(iTeamId + 1))
{
if (ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(bg->GetArenaTeamIdForTeam(Battleground::GetOtherTeamId(iTeamId))))
* 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(GetPvPTeamId(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++;
if (!bg->IsPlayerInBattleground(itr2->first))
{
LOG_ERROR("bg.battleground", "Player {} has scoreboard entry for battleground {} but is not in battleground!", itr->first.ToString(), bg->GetBgTypeID());
continue;
}
*data << itr2->first;
*data << uint32(itr2->second->KillingBlows);
if (type == 0)
{
*data << uint32(itr2->second->HonorableKills);
*data << uint32(itr2->second->Deaths);
*data << uint32(itr2->second->BonusHonor);
}
else
{
*data << uint8(itr2->second->player->GetBgTeamId() == TEAM_ALLIANCE ? 1 : 0); // green or yellow
}
*data << uint32(itr2->second->DamageDone); // damage done
*data << uint32(itr2->second->HealingDone); // healing done
BattlegroundTypeId bgTypeId = bg->GetBgTypeID();
switch (bgTypeId) // battleground specific things
{
case BATTLEGROUND_RB:
switch (bg->GetMapId())
{
case 489:
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundWGScore*)itr2->second)->FlagCaptures); // flag captures
*data << uint32(((BattlegroundWGScore*)itr2->second)->FlagReturns); // flag returns
break;
case 566:
*data << uint32(0x00000001); // count of next fields
*data << uint32(((BattlegroundEYScore*)itr2->second)->FlagCaptures); // flag captures
break;
case 529:
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundABScore*)itr2->second)->BasesAssaulted); // bases asssulted
*data << uint32(((BattlegroundABScore*)itr2->second)->BasesDefended); // bases defended
break;
case 30:
*data << uint32(0x00000005); // count of next fields
*data << uint32(((BattlegroundAVScore*)itr2->second)->GraveyardsAssaulted); // GraveyardsAssaulted
*data << uint32(((BattlegroundAVScore*)itr2->second)->GraveyardsDefended); // GraveyardsDefended
*data << uint32(((BattlegroundAVScore*)itr2->second)->TowersAssaulted); // TowersAssaulted
*data << uint32(((BattlegroundAVScore*)itr2->second)->TowersDefended); // TowersDefended
*data << uint32(((BattlegroundAVScore*)itr2->second)->MinesCaptured); // MinesCaptured
break;
case 607:
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundSAScore*)itr2->second)->demolishers_destroyed);
*data << uint32(((BattlegroundSAScore*)itr2->second)->gates_destroyed);
break;
case 628: // IC
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundICScore*)itr2->second)->BasesAssaulted); // bases asssulted
*data << uint32(((BattlegroundICScore*)itr2->second)->BasesDefended); // bases defended
[[fallthrough]]; // TODO: Not sure whether the fallthrough was a mistake (forgetting a break) or intended. This should be double-checked.
default:
if (BattlegroundMgr::getBgFromMap.find(bg->GetMapId()) != BattlegroundMgr::getBgFromMap.end())
BattlegroundMgr::getBgFromMap[bg->GetMapId()](data, itr2);
else
*data << uint32(0);
break;
}
break;
case BATTLEGROUND_AV:
*data << uint32(0x00000005); // count of next fields
*data << uint32(((BattlegroundAVScore*)itr2->second)->GraveyardsAssaulted); // GraveyardsAssaulted
*data << uint32(((BattlegroundAVScore*)itr2->second)->GraveyardsDefended); // GraveyardsDefended
*data << uint32(((BattlegroundAVScore*)itr2->second)->TowersAssaulted); // TowersAssaulted
*data << uint32(((BattlegroundAVScore*)itr2->second)->TowersDefended); // TowersDefended
*data << uint32(((BattlegroundAVScore*)itr2->second)->MinesCaptured); // MinesCaptured
break;
case BATTLEGROUND_WS:
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundWGScore*)itr2->second)->FlagCaptures); // flag captures
*data << uint32(((BattlegroundWGScore*)itr2->second)->FlagReturns); // flag returns
break;
case BATTLEGROUND_AB:
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundABScore*)itr2->second)->BasesAssaulted); // bases asssulted
*data << uint32(((BattlegroundABScore*)itr2->second)->BasesDefended); // bases defended
break;
case BATTLEGROUND_EY:
*data << uint32(0x00000001); // count of next fields
*data << uint32(((BattlegroundEYScore*)itr2->second)->FlagCaptures); // flag captures
break;
case BATTLEGROUND_SA:
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundSAScore*)itr2->second)->demolishers_destroyed);
*data << uint32(((BattlegroundSAScore*)itr2->second)->gates_destroyed);
break;
case BATTLEGROUND_IC:
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundICScore*)itr2->second)->BasesAssaulted); // bases assaulted
*data << uint32(((BattlegroundICScore*)itr2->second)->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:
if (BattlegroundMgr::getBgFromTypeID.find(bgTypeId) != BattlegroundMgr::getBgFromTypeID.end())
BattlegroundMgr::getBgFromTypeID[bgTypeId](data, itr2, bg);
else
*data << uint32(0);
break;
}
// should never happen
if (++scoreCount >= bg->GetMaxPlayersPerTeam() * 2 && itr != bg->GetPlayerScoresEnd())
{
LOG_INFO("misc", "Battleground {} scoreboard has more entries ({}) than allowed players in this bg ({})", bgTypeId, bg->GetPlayerScoresSize(), bg->GetMaxPlayersPerTeam() * 2);
break;
}
}
data->put(wpos, scoreCount);
}
void BattlegroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result) void BattlegroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result)
{ {
data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4); data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
@@ -495,8 +322,8 @@ bool BattlegroundMgr::CreateBattleground(CreateBattlegroundData& data)
bg->SetMinPlayersPerTeam(data.MinPlayersPerTeam); bg->SetMinPlayersPerTeam(data.MinPlayersPerTeam);
bg->SetMaxPlayersPerTeam(data.MaxPlayersPerTeam); bg->SetMaxPlayersPerTeam(data.MaxPlayersPerTeam);
bg->SetName(data.BattlegroundName); bg->SetName(data.BattlegroundName);
bg->SetTeamStartLoc(TEAM_ALLIANCE, data.Team1StartLocX, data.Team1StartLocY, data.Team1StartLocZ, data.Team1StartLocO); bg->SetTeamStartPosition(TEAM_ALLIANCE, data.StartLocation[TEAM_ALLIANCE]);
bg->SetTeamStartLoc(TEAM_HORDE, data.Team2StartLocX, data.Team2StartLocY, data.Team2StartLocZ, data.Team2StartLocO); bg->SetTeamStartPosition(TEAM_HORDE, data.StartLocation[TEAM_HORDE]);
bg->SetStartMaxDist(data.StartMaxDist); bg->SetStartMaxDist(data.StartMaxDist);
bg->SetLevelRange(data.LevelMin, data.LevelMax); bg->SetLevelRange(data.LevelMin, data.LevelMax);
bg->SetScriptId(data.scriptId); bg->SetScriptId(data.scriptId);
@@ -559,55 +386,38 @@ void BattlegroundMgr::CreateInitialBattlegrounds()
if (data.MaxPlayersPerTeam == 0 || data.MinPlayersPerTeam > data.MaxPlayersPerTeam) if (data.MaxPlayersPerTeam == 0 || data.MinPlayersPerTeam > data.MaxPlayersPerTeam)
{ {
LOG_ERROR("bg.battleground", "Table `battleground_template` for id {} has bad values for MinPlayersPerTeam ({}) and MaxPlayersPerTeam({})", LOG_ERROR("bg.battleground", "Table `battleground_template` for id {} has bad values for MinPlayersPerTeam ({}) and MaxPlayersPerTeam({})",
data.bgTypeId, data.MinPlayersPerTeam, data.MaxPlayersPerTeam); data.bgTypeId, data.MinPlayersPerTeam, data.MaxPlayersPerTeam);
continue; continue;
} }
if (data.LevelMin == 0 || data.LevelMax == 0 || data.LevelMin > data.LevelMax) if (data.LevelMin == 0 || data.LevelMax == 0 || data.LevelMin > data.LevelMax)
{ {
LOG_ERROR("bg.battleground", "Table `battleground_template` for id {} has bad values for LevelMin ({}) and LevelMax({})", LOG_ERROR("bg.battleground", "Table `battleground_template` for id {} has bad values for LevelMin ({}) and LevelMax({})",
data.bgTypeId, data.LevelMin, data.LevelMax); data.bgTypeId, data.LevelMin, data.LevelMax);
continue; continue;
} }
if (data.bgTypeId == BATTLEGROUND_AA || data.bgTypeId == BATTLEGROUND_RB) if (data.bgTypeId != BATTLEGROUND_AA && data.bgTypeId != BATTLEGROUND_RB)
{
data.Team1StartLocX = 0;
data.Team1StartLocY = 0;
data.Team1StartLocZ = 0;
data.Team1StartLocO = fields[6].Get<float>();
data.Team2StartLocX = 0;
data.Team2StartLocY = 0;
data.Team2StartLocZ = 0;
data.Team2StartLocO = fields[8].Get<float>();
}
else
{ {
uint32 startId = fields[5].Get<uint32>(); uint32 startId = fields[5].Get<uint32>();
if (GraveyardStruct const* start = sGraveyard->GetGraveyard(startId)) if (GraveyardStruct const* start = sGraveyard->GetGraveyard(startId))
{ {
data.Team1StartLocX = start->x; data.StartLocation[TEAM_ALLIANCE].Relocate(start->x, start->y, start->z, fields[6].Get<float>());
data.Team1StartLocY = start->y;
data.Team1StartLocZ = start->z;
data.Team1StartLocO = fields[6].Get<float>();
} }
else else
{ {
LOG_ERROR("bg.battleground", "Table `battleground_template` for id {} have non-existed `game_graveyard` table id {} in field `AllianceStartLoc`. BG not created.", data.bgTypeId, startId); LOG_ERROR("sql.sql", "Table `battleground_template` for id %u contains a non-existing WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", data.bgTypeId, startId);
continue; continue;
} }
startId = fields[7].Get<uint32>(); startId = fields[7].Get<uint32>();
if (GraveyardStruct const* start = sGraveyard->GetGraveyard(startId)) if (GraveyardStruct const* start = sGraveyard->GetGraveyard(startId))
{ {
data.Team2StartLocX = start->x; data.StartLocation[TEAM_HORDE].Relocate(start->x, start->y, start->z, fields[8].Get<float>());
data.Team2StartLocY = start->y;
data.Team2StartLocZ = start->z;
data.Team2StartLocO = fields[8].Get<float>();
} }
else else
{ {
LOG_ERROR("bg.battleground", "Table `battleground_template` for id {} have non-existed `game_graveyard` table id {} in field `HordeStartLoc`. BG not created.", data.bgTypeId, startId); LOG_ERROR("sql.sql", "Table `battleground_template` for id %u contains a non-existing WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", data.bgTypeId, startId);
continue; continue;
} }
} }
@@ -708,13 +518,19 @@ void BattlegroundMgr::BuildBattlegroundListPacket(WorldPacket* data, ObjectGuid
} }
} }
void BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, BattlegroundTypeId /*bgTypeId*/) void BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, BattlegroundTypeId bgTypeId)
{ {
if (Battleground* bg = GetBattleground(instanceId)) if (Battleground* bg = GetBattleground(instanceId))
{ {
float x, y, z, o; uint32 mapid = bg->GetMapId();
bg->GetTeamStartLoc(player->GetBgTeamId(), x, y, z, o); Position const* pos = bg->GetTeamStartPosition(player->GetBgTeamId());
player->TeleportTo(bg->GetMapId(), x, y, z, o);
LOG_DEBUG("bg.battleground", "BattlegroundMgr::SendToBattleground: Sending {} to map {}, {} (bgType {})", player->GetName(), mapid, pos->ToString(), bgTypeId);
player->TeleportTo(mapid, pos->GetPositionX(), pos->GetPositionY(), pos->GetPositionZ(), pos->GetOrientation());
}
else
{
LOG_ERROR("bg.battleground", "BattlegroundMgr::SendToBattleground: Instance {} (bgType {}) not found while trying to teleport player {}", instanceId, bgTypeId, player->GetName());
} }
} }
@@ -999,60 +815,11 @@ void BattlegroundMgr::RemoveBattleground(BattlegroundTypeId bgTypeId, uint32 ins
m_Battlegrounds.erase(instanceId); m_Battlegrounds.erase(instanceId);
} }
void BattlegroundMgr::InviteGroupToBG(GroupQueueInfo* ginfo, Battleground* bg, TeamId teamId) void BattlegroundMgr::DoForAllBattlegrounds(std::function<void(Battleground*)> const& worker)
{ {
if (ginfo->IsInvitedToBGInstanceGUID) for (auto const& [_, bg] : m_Battlegrounds)
return;
// set side if needed
if (teamId != TEAM_NEUTRAL)
ginfo->teamId = teamId;
// set invitation
ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(ginfo->BgTypeId, ginfo->ArenaType);
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
// set ArenaTeamId for rated matches
if (bg->isArena() && bg->isRated())
bg->SetArenaTeamIdForTeam(ginfo->teamId, ginfo->ArenaTeamId);
ginfo->RemoveInviteTime = GameTime::GetGameTimeMS().count() + INVITE_ACCEPT_WAIT_TIME;
// loop through the players
for (auto& itr : ginfo->Players)
{ {
// get the player worker(bg);
Player* player = ObjectAccessor::FindConnectedPlayer(itr);
if (!player)
continue;
// update average wait time
bgQueue.PlayerInvitedToBGUpdateAverageWaitTime(ginfo);
// increase invited counter for each invited player
bg->IncreaseInvitedCount(ginfo->teamId);
// create remind invite events
BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(player->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, ginfo->BgTypeId, ginfo->ArenaType, ginfo->RemoveInviteTime);
bgQueue.AddEvent(inviteEvent, INVITATION_REMIND_TIME);
// create automatic remove events
BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(player->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgQueueTypeId, ginfo->RemoveInviteTime);
bgQueue.AddEvent(removeEvent, INVITE_ACCEPT_WAIT_TIME);
// Check queueSlot
uint32 queueSlot = player->GetBattlegroundQueueIndex(bgQueueTypeId);
ASSERT(queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES);
// send status packet
WorldPacket data;
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, ginfo->ArenaType, TEAM_NEUTRAL, bg->isRated(), ginfo->BgTypeId);
player->GetSession()->SendPacket(&data);
// pussywizard:
if (bg->isArena() && bg->isRated())
bg->ArenaLogEntries[player->GetGUID()].Fill(player->GetName().c_str(), player->GetGUID().GetCounter(), player->GetSession()->GetAccountId(), ginfo->ArenaTeamId, player->GetSession()->GetRemoteAddress());
} }
} }
@@ -24,6 +24,7 @@
#include "CreatureAIImpl.h" #include "CreatureAIImpl.h"
#include "DBCEnums.h" #include "DBCEnums.h"
#include <unordered_map> #include <unordered_map>
#include <functional>
typedef std::map<uint32, Battleground*> BattlegroundContainer; typedef std::map<uint32, Battleground*> BattlegroundContainer;
typedef std::unordered_map<uint32, BattlegroundTypeId> BattleMastersMap; typedef std::unordered_map<uint32, BattlegroundTypeId> BattleMastersMap;
@@ -42,15 +43,8 @@ struct CreateBattlegroundData
uint32 LevelMax; uint32 LevelMax;
char const* BattlegroundName; char const* BattlegroundName;
uint32 MapID; uint32 MapID;
float Team1StartLocX;
float Team1StartLocY;
float Team1StartLocZ;
float Team1StartLocO;
float Team2StartLocX;
float Team2StartLocY;
float Team2StartLocZ;
float Team2StartLocO;
float StartMaxDist; float StartMaxDist;
std::array<Position, PVP_TEAMS_COUNT> StartLocation;
uint32 scriptId; uint32 scriptId;
uint8 Weight; uint8 Weight;
}; };
@@ -73,7 +67,6 @@ public:
void BuildPlayerLeftBattlegroundPacket(WorldPacket* data, ObjectGuid guid); void BuildPlayerLeftBattlegroundPacket(WorldPacket* data, ObjectGuid guid);
void BuildBattlegroundListPacket(WorldPacket* data, ObjectGuid guid, Player* player, BattlegroundTypeId bgTypeId, uint8 fromWhere); void BuildBattlegroundListPacket(WorldPacket* data, ObjectGuid guid, Player* player, BattlegroundTypeId bgTypeId, uint8 fromWhere);
void BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result); void BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result);
void BuildPvpLogDataPacket(WorldPacket* data, Battleground* bg);
void BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint8 queueSlot, uint8 statusId, uint32 time1, uint32 time2, uint8 arenaType, TeamId teamId, bool isRated = false, BattlegroundTypeId forceBgTypeId = BATTLEGROUND_TYPE_NONE); void BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint8 queueSlot, uint8 statusId, uint32 time1, uint32 time2, uint8 arenaType, TeamId teamId, bool isRated = false, BattlegroundTypeId forceBgTypeId = BATTLEGROUND_TYPE_NONE);
void BuildPlaySoundPacket(WorldPacket* data, uint32 soundid); void BuildPlaySoundPacket(WorldPacket* data, uint32 soundid);
void SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, ObjectGuid guid); void SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, ObjectGuid guid);
@@ -96,8 +89,6 @@ public:
void ScheduleArenaQueueUpdate(uint32 arenaRatedTeamId, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundBracketId bracket_id); void ScheduleArenaQueueUpdate(uint32 arenaRatedTeamId, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundBracketId bracket_id);
uint32 GetPrematureFinishTime() const; uint32 GetPrematureFinishTime() const;
static void InviteGroupToBG(GroupQueueInfo* ginfo, Battleground* bg, TeamId teamId);
void ToggleArenaTesting(); void ToggleArenaTesting();
void ToggleTesting(); void ToggleTesting();
@@ -138,6 +129,8 @@ public:
static std::unordered_map<uint32, BattlegroundQueueTypeId> ArenaTypeToQueue; // ArenaType -> BattlegroundQueueTypeId static std::unordered_map<uint32, BattlegroundQueueTypeId> ArenaTypeToQueue; // ArenaType -> BattlegroundQueueTypeId
static std::unordered_map<uint32, ArenaType> QueueToArenaType; // BattlegroundQueueTypeId -> ArenaType static std::unordered_map<uint32, ArenaType> QueueToArenaType; // BattlegroundQueueTypeId -> ArenaType
void DoForAllBattlegrounds(std::function<void(Battleground*)> const& worker);
private: private:
bool CreateBattleground(CreateBattlegroundData& data); bool CreateBattleground(CreateBattlegroundData& data);
uint32 GetNextClientVisibleInstanceId(); uint32 GetNextClientVisibleInstanceId();
@@ -37,7 +37,7 @@
BattlegroundQueue::BattlegroundQueue() : m_bgTypeId(BATTLEGROUND_TYPE_NONE), m_arenaType(ArenaType(0)) BattlegroundQueue::BattlegroundQueue() : m_bgTypeId(BATTLEGROUND_TYPE_NONE), m_arenaType(ArenaType(0))
{ {
for (uint32 i = 0; i < BG_TEAMS_COUNT; ++i) for (uint32 i = 0; i < PVP_TEAMS_COUNT; ++i)
{ {
for (uint32 j = 0; j < MAX_BATTLEGROUND_BRACKETS; ++j) for (uint32 j = 0; j < MAX_BATTLEGROUND_BRACKETS; ++j)
{ {
@@ -87,7 +87,7 @@ bool BattlegroundQueue::SelectionPool::KickGroup(const uint32 size)
// find last group with proper size or largest // find last group with proper size or largest
bool foundProper = false; bool foundProper = false;
auto groupToKick = SelectedGroups.begin(); auto groupToKick = SelectedGroups.begin();
for (auto itr = groupToKick; itr != SelectedGroups.end(); ++itr) for (auto& itr = groupToKick; itr != SelectedGroups.end(); ++itr)
{ {
// if proper size - overwrite to kick last one // if proper size - overwrite to kick last one
if (std::abs(int32((*itr)->Players.size()) - (int32)size) <= 1) if (std::abs(int32((*itr)->Players.size()) - (int32)size) <= 1)
@@ -154,7 +154,7 @@ GroupQueueInfo* BattlegroundQueue::AddGroup(Player* leader, Group* grp, PvPDiffi
uint32 index = 0; uint32 index = 0;
if (!isRated && !isPremade) if (!isRated && !isPremade)
index += BG_TEAMS_COUNT; index += PVP_TEAMS_COUNT;
if (ginfo->teamId == TEAM_HORDE) if (ginfo->teamId == TEAM_HORDE)
index++; index++;
@@ -453,88 +453,6 @@ void BattlegroundQueue::FillPlayersToBG(Battleground* bg, const int32 aliFree, c
} }
} }
void BattlegroundQueue::FillPlayersToBGWithSpecific(Battleground* bg, const int32 aliFree, const int32 hordeFree, BattlegroundBracketId thisBracketId, BattlegroundQueue* specificQueue, BattlegroundBracketId specificBracketId)
{
if (!sScriptMgr->CanFillPlayersToBGWithSpecific(this, bg, aliFree, hordeFree, thisBracketId, specificQueue, specificBracketId))
return;
// clear selection pools
m_SelectionPools[TEAM_ALLIANCE].Init();
m_SelectionPools[TEAM_HORDE].Init();
// quick check if nothing we can do:
if (!sBattlegroundMgr->isTesting())
if ((m_QueuedGroups[thisBracketId][BG_QUEUE_NORMAL_ALLIANCE].empty() && specificQueue->m_QueuedGroups[specificBracketId][BG_QUEUE_NORMAL_ALLIANCE].empty()) ||
(m_QueuedGroups[thisBracketId][BG_QUEUE_NORMAL_HORDE].empty() && specificQueue->m_QueuedGroups[specificBracketId][BG_QUEUE_NORMAL_HORDE].empty()))
return;
// copy groups from both queues to new joined container
GroupsQueueType m_QueuedBoth[BG_TEAMS_COUNT];
m_QueuedBoth[TEAM_ALLIANCE].insert(m_QueuedBoth[TEAM_ALLIANCE].end(), specificQueue->m_QueuedGroups[specificBracketId][BG_QUEUE_NORMAL_ALLIANCE].begin(), specificQueue->m_QueuedGroups[specificBracketId][BG_QUEUE_NORMAL_ALLIANCE].end());
m_QueuedBoth[TEAM_ALLIANCE].insert(m_QueuedBoth[TEAM_ALLIANCE].end(), m_QueuedGroups[thisBracketId][BG_QUEUE_NORMAL_ALLIANCE].begin(), m_QueuedGroups[thisBracketId][BG_QUEUE_NORMAL_ALLIANCE].end());
m_QueuedBoth[TEAM_HORDE].insert(m_QueuedBoth[TEAM_HORDE].end(), specificQueue->m_QueuedGroups[specificBracketId][BG_QUEUE_NORMAL_HORDE].begin(), specificQueue->m_QueuedGroups[specificBracketId][BG_QUEUE_NORMAL_HORDE].end());
m_QueuedBoth[TEAM_HORDE].insert(m_QueuedBoth[TEAM_HORDE].end(), m_QueuedGroups[thisBracketId][BG_QUEUE_NORMAL_HORDE].begin(), m_QueuedGroups[thisBracketId][BG_QUEUE_NORMAL_HORDE].end());
// ally: at first fill as much as possible
auto Ali_itr = m_QueuedBoth[TEAM_ALLIANCE].begin();
for (; Ali_itr != m_QueuedBoth[TEAM_ALLIANCE].end() && m_SelectionPools[TEAM_ALLIANCE].AddGroup((*Ali_itr), aliFree); ++Ali_itr);
// horde: at first fill as much as possible
auto Horde_itr = m_QueuedBoth[TEAM_HORDE].begin();
for (; Horde_itr != m_QueuedBoth[TEAM_HORDE].end() && m_SelectionPools[TEAM_HORDE].AddGroup((*Horde_itr), hordeFree); ++Horde_itr);
// calculate free space after adding
int32 aliDiff = aliFree - int32(m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount());
int32 hordeDiff = hordeFree - int32(m_SelectionPools[TEAM_HORDE].GetPlayerCount());
int32 invType = sWorld->getIntConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE);
int32 invDiff = 0;
// check balance configuration and set the max difference between teams
switch (invType)
{
case BG_QUEUE_INVITATION_TYPE_NO_BALANCE:
return;
case BG_QUEUE_INVITATION_TYPE_BALANCED:
invDiff = 1;
break;
case BG_QUEUE_INVITATION_TYPE_EVEN:
break;
default:
return;
}
// if free space differs too much, ballance
while (std::abs(aliDiff - hordeDiff) > invDiff && (m_SelectionPools[TEAM_HORDE].GetPlayerCount() > 0 || m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() > 0))
{
// if results in more alliance players than horde:
if (aliDiff < hordeDiff)
{
// no more alliance in pool, invite whatever we can from horde
if (!m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount())
break;
// kick alliance, returns true if kicked more than needed, so then try to fill up
if (m_SelectionPools[TEAM_ALLIANCE].KickGroup(hordeDiff - aliDiff))
for (; Ali_itr != m_QueuedBoth[TEAM_ALLIANCE].end() && m_SelectionPools[TEAM_ALLIANCE].AddGroup((*Ali_itr), aliFree >= hordeDiff ? aliFree - hordeDiff : 0); ++Ali_itr);
}
else // if results in more horde players than alliance:
{
// no more horde in pool, invite whatever we can from alliance
if (!m_SelectionPools[TEAM_HORDE].GetPlayerCount())
break;
// kick horde, returns true if kicked more than needed, so then try to fill up
if (m_SelectionPools[TEAM_HORDE].KickGroup(aliDiff - hordeDiff))
for (; Horde_itr != m_QueuedBoth[TEAM_HORDE].end() && m_SelectionPools[TEAM_HORDE].AddGroup((*Horde_itr), hordeFree >= aliDiff ? hordeFree - aliDiff : 0); ++Horde_itr);
}
// recalculate free space after adding
aliDiff = aliFree - static_cast<int32>(m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount());
hordeDiff = hordeFree - static_cast<int32>(m_SelectionPools[TEAM_HORDE].GetPlayerCount());
}
}
// this method checks if premade versus premade battleground is possible // this method checks if premade versus premade battleground is possible
// then after 30 mins (default) in queue it moves premade group to normal queue // then after 30 mins (default) in queue it moves premade group to normal queue
bool BattlegroundQueue::CheckPremadeMatch(BattlegroundBracketId bracket_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam) bool BattlegroundQueue::CheckPremadeMatch(BattlegroundBracketId bracket_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam)
@@ -573,7 +491,7 @@ bool BattlegroundQueue::CheckPremadeMatch(BattlegroundBracketId bracket_id, uint
uint32 premade_time = sWorld->getIntConfig(CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH); uint32 premade_time = sWorld->getIntConfig(CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH);
uint32 time_before = GameTime::GetGameTimeMS().count() >= premade_time ? GameTime::GetGameTimeMS().count() - premade_time : 0; uint32 time_before = GameTime::GetGameTimeMS().count() >= premade_time ? GameTime::GetGameTimeMS().count() - premade_time : 0;
for (uint32 i = 0; i < BG_TEAMS_COUNT; i++) for (uint32 i = 0; i < PVP_TEAMS_COUNT; i++)
if (!m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty()) if (!m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty())
for (auto itr = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].begin(); itr != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].end(); ) for (auto itr = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].begin(); itr != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].end(); )
{ {
@@ -624,7 +542,7 @@ bool BattlegroundQueue::CheckNormalMatch(Battleground* bgTemplate, BattlegroundB
// this method will check if we can invite players to same faction skirmish match // this method will check if we can invite players to same faction skirmish match
bool BattlegroundQueue::CheckSkirmishForSameFaction(BattlegroundBracketId bracket_id, uint32 minPlayersPerTeam) bool BattlegroundQueue::CheckSkirmishForSameFaction(BattlegroundBracketId bracket_id, uint32 minPlayersPerTeam)
{ {
for (uint32 i = 0; i < BG_TEAMS_COUNT; i++) for (uint32 i = 0; i < PVP_TEAMS_COUNT; i++)
if (!m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].empty()) if (!m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].empty())
{ {
// clear selection pools // clear selection pools
@@ -633,7 +551,7 @@ bool BattlegroundQueue::CheckSkirmishForSameFaction(BattlegroundBracketId bracke
// fill one queue to both selection pools // fill one queue to both selection pools
for (auto itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr) for (auto itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr)
for (uint32 j = 0; j < BG_TEAMS_COUNT; j++) // try to add this group to both pools for (uint32 j = 0; j < PVP_TEAMS_COUNT; j++) // try to add this group to both pools
if (m_SelectionPools[TEAM_ALLIANCE + j].GetPlayerCount() < minPlayersPerTeam) // if this pool is not full if (m_SelectionPools[TEAM_ALLIANCE + j].GetPlayerCount() < minPlayersPerTeam) // if this pool is not full
if (m_SelectionPools[TEAM_ALLIANCE + j].AddGroup((*itr), minPlayersPerTeam)) // successfully added if (m_SelectionPools[TEAM_ALLIANCE + j].AddGroup((*itr), minPlayersPerTeam)) // successfully added
{ {
@@ -676,9 +594,6 @@ void BattlegroundQueue::UpdateEvents(uint32 diff)
m_events.Update(diff); m_events.Update(diff);
} }
struct BgEmptinessComp { bool operator()(Battleground* const& bg1, Battleground* const& bg2) const { return ((float)bg1->GetMaxFreeSlots() / (float)bg1->GetMaxPlayersPerTeam()) > ((float)bg2->GetMaxFreeSlots() / (float)bg2->GetMaxPlayersPerTeam()); } };
typedef std::set<Battleground*, BgEmptinessComp> BattlegroundNeedSet;
void BattlegroundQueue::BattlegroundQueueUpdate(uint32 diff, BattlegroundBracketId bracket_id, bool isRated, uint32 arenaRatedTeamId) void BattlegroundQueue::BattlegroundQueueUpdate(uint32 diff, BattlegroundBracketId bracket_id, bool isRated, uint32 arenaRatedTeamId)
{ {
// if no players in queue - do nothing // if no players in queue - do nothing
@@ -696,28 +611,35 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 diff, BattlegroundBracket
// battlegrounds with free slots should be populated first using players in queue // battlegrounds with free slots should be populated first using players in queue
if (!BattlegroundMgr::IsArenaType(m_bgTypeId)) if (!BattlegroundMgr::IsArenaType(m_bgTypeId))
{ {
const BattlegroundContainer& bgList = sBattlegroundMgr->GetBattlegroundList(); std::vector<Battleground*> bgsToCheck;
BattlegroundNeedSet bgsToCheck;
// sort from most needing (most empty) to least needing using a std::set with functor // sort from most needing (most empty) to least needing using a std::set with functor
for (auto itr : bgList) sBattlegroundMgr->DoForAllBattlegrounds([&](Battleground* bg)
{ {
Battleground* bg = itr.second; if (!BattlegroundMgr::IsArenaType(bg->GetBgTypeID()) &&
if (!BattlegroundMgr::IsArenaType(bg->GetBgTypeID()) && (bg->GetBgTypeID(true) == m_bgTypeId || m_bgTypeId == BATTLEGROUND_RB) && (bg->GetBgTypeID(true) == m_bgTypeId || m_bgTypeId == BATTLEGROUND_RB) &&
bg->HasFreeSlots() && bg->GetMinLevel() <= bracketEntry->minLevel && bg->GetMaxLevel() >= bracketEntry->maxLevel) bg->HasFreeSlots() && bg->GetMinLevel() <= bracketEntry->minLevel &&
bgsToCheck.insert(bg); bg->GetMaxLevel() >= bracketEntry->maxLevel)
} {
bgsToCheck.emplace_back(bg);
}
});
std::sort(bgsToCheck.begin(), bgsToCheck.end(), [](Battleground* const& bg1, Battleground* const& bg2)
{
return ((float)bg1->GetMaxFreeSlots() / (float)bg1->GetMaxPlayersPerTeam()) > ((float)bg2->GetMaxFreeSlots() / (float)bg2->GetMaxPlayersPerTeam());
});
// now iterate needing battlegrounds // now iterate needing battlegrounds
for (auto bg : bgsToCheck) for (auto const& bg : bgsToCheck)
{ {
// call a function that fills whatever we can from normal queues // call a function that fills whatever we can from normal queues
FillPlayersToBG(bg, bg->GetFreeSlotsForTeam(TEAM_ALLIANCE), bg->GetFreeSlotsForTeam(TEAM_HORDE), bracket_id); FillPlayersToBG(bg, bg->GetFreeSlotsForTeam(TEAM_ALLIANCE), bg->GetFreeSlotsForTeam(TEAM_HORDE), bracket_id);
// invite players // invite players
for (uint32 i = 0; i < BG_TEAMS_COUNT; i++) for (uint32 i = 0; i < PVP_TEAMS_COUNT; i++)
for (auto itr : m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups) for (auto itr : m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups)
BattlegroundMgr::InviteGroupToBG(itr, bg, itr->RealTeamID); InviteGroupToBG(itr, bg, itr->RealTeamID);
} }
// prevent new BGs to be created if there are some non-empty BGs running // prevent new BGs to be created if there are some non-empty BGs running
@@ -751,9 +673,9 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 diff, BattlegroundBracket
return; return;
// invite players // invite players
for (uint32 i = 0; i < BG_TEAMS_COUNT; i++) for (uint32 i = 0; i < PVP_TEAMS_COUNT; i++)
for (auto& SelectedGroup : m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups) for (auto& SelectedGroup : m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups)
BattlegroundMgr::InviteGroupToBG(SelectedGroup, bg, SelectedGroup->teamId); InviteGroupToBG(SelectedGroup, bg, SelectedGroup->teamId);
bg->StartBattleground(); bg->StartBattleground();
@@ -764,9 +686,9 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 diff, BattlegroundBracket
FillPlayersToBG(bg, bg->GetFreeSlotsForTeam(TEAM_ALLIANCE), bg->GetFreeSlotsForTeam(TEAM_HORDE), bracket_id); FillPlayersToBG(bg, bg->GetFreeSlotsForTeam(TEAM_ALLIANCE), bg->GetFreeSlotsForTeam(TEAM_HORDE), bracket_id);
// invite players // invite players
for (uint32 i = 0; i < BG_TEAMS_COUNT; i++) for (uint32 i = 0; i < PVP_TEAMS_COUNT; i++)
for (auto& SelectedGroup : m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups) for (auto& SelectedGroup : m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups)
BattlegroundMgr::InviteGroupToBG(SelectedGroup, bg, SelectedGroup->teamId); InviteGroupToBG(SelectedGroup, bg, SelectedGroup->teamId);
} }
} }
@@ -786,9 +708,9 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 diff, BattlegroundBracket
return; return;
// invite players // invite players
for (uint32 i = 0; i < BG_TEAMS_COUNT; i++) for (uint32 i = 0; i < PVP_TEAMS_COUNT; i++)
for (auto& SelectedGroup : m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups) for (auto& SelectedGroup : m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups)
BattlegroundMgr::InviteGroupToBG(SelectedGroup, bg, SelectedGroup->teamId); InviteGroupToBG(SelectedGroup, bg, SelectedGroup->teamId);
bg->StartBattleground(); bg->StartBattleground();
} }
@@ -804,7 +726,7 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 diff, BattlegroundBracket
const uint32 maxCountedMMR = 2500; const uint32 maxCountedMMR = 2500;
// we need to find 2 teams which will play next game // we need to find 2 teams which will play next game
GroupsQueueType::iterator itr_teams[BG_TEAMS_COUNT]; GroupsQueueType::iterator itr_teams[PVP_TEAMS_COUNT];
bool increaseItr = true; bool increaseItr = true;
bool reverse1 = urand(0, 1) != 0; bool reverse1 = urand(0, 1) != 0;
@@ -937,8 +859,8 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 diff, BattlegroundBracket
arena->SetArenaMatchmakerRating(TEAM_ALLIANCE, aTeam->ArenaMatchmakerRating); arena->SetArenaMatchmakerRating(TEAM_ALLIANCE, aTeam->ArenaMatchmakerRating);
arena->SetArenaMatchmakerRating(TEAM_HORDE, hTeam->ArenaMatchmakerRating); arena->SetArenaMatchmakerRating(TEAM_HORDE, hTeam->ArenaMatchmakerRating);
BattlegroundMgr::InviteGroupToBG(aTeam, arena, TEAM_ALLIANCE); InviteGroupToBG(aTeam, arena, TEAM_ALLIANCE);
BattlegroundMgr::InviteGroupToBG(hTeam, arena, TEAM_HORDE); InviteGroupToBG(hTeam, arena, TEAM_HORDE);
arena->StartBattleground(); arena->StartBattleground();
} }
@@ -980,12 +902,12 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 diff, BattlegroundBracket
{ {
_queueAnnouncementTimer[bracket_id] = -1; _queueAnnouncementTimer[bracket_id] = -1;
char const* bgName = bg_template->GetName(); auto bgName = bg_template->GetName();
uint32 MaxPlayers = bg_template->GetMinPlayersPerTeam() * 2; uint32 MaxPlayers = bg_template->GetMinPlayersPerTeam() * 2;
uint32 q_min_level = std::min(bracketEntry->minLevel, (uint32) 80); uint32 q_min_level = std::min(bracketEntry->minLevel, (uint32) 80);
uint32 q_max_level = std::min(bracketEntry->maxLevel, (uint32) 80); uint32 q_max_level = std::min(bracketEntry->maxLevel, (uint32) 80);
sWorld->SendWorldTextOptional(LANG_BG_QUEUE_ANNOUNCE_WORLD, ANNOUNCER_FLAG_DISABLE_BG_QUEUE, bgName, q_min_level, q_max_level, qPlayers, MaxPlayers); sWorld->SendWorldTextOptional(LANG_BG_QUEUE_ANNOUNCE_WORLD, ANNOUNCER_FLAG_DISABLE_BG_QUEUE, bgName.c_str(), q_min_level, q_max_level, qPlayers, MaxPlayers);
} }
else else
{ {
@@ -1031,7 +953,7 @@ void BattlegroundQueue::SendMessageBGQueue(Player* leader, Battleground* bg, PvP
} }
BattlegroundBracketId bracketId = bracketEntry->GetBracketId(); BattlegroundBracketId bracketId = bracketEntry->GetBracketId();
char const* bgName = bg->GetName(); auto bgName = bg->GetName();
uint32 MinPlayers = bg->GetMinPlayersPerTeam(); uint32 MinPlayers = bg->GetMinPlayersPerTeam();
uint32 MaxPlayers = MinPlayers * 2; uint32 MaxPlayers = MinPlayers * 2;
uint32 q_min_level = std::min(bracketEntry->minLevel, (uint32)80); uint32 q_min_level = std::min(bracketEntry->minLevel, (uint32)80);
@@ -1046,12 +968,9 @@ void BattlegroundQueue::SendMessageBGQueue(Player* leader, Battleground* bg, PvP
// Show queue status to player only (when joining battleground queue or Arena and arena world announcer is disabled) // Show queue status to player only (when joining battleground queue or Arena and arena world announcer is disabled)
if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY)) if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
{ {
ChatHandler(leader->GetSession()).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF, bgName, q_min_level, q_max_level, ChatHandler(leader->GetSession()).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF, bgName.c_str(), q_min_level, q_max_level,
qAlliance, qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0,
(MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
qHorde,
(MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0
);
} }
else // Show queue status to server (when joining battleground queue) else // Show queue status to server (when joining battleground queue)
{ {
@@ -1069,7 +988,7 @@ void BattlegroundQueue::SendMessageBGQueue(Player* leader, Battleground* bg, PvP
return; return;
} }
sWorld->SendWorldTextOptional(LANG_BG_QUEUE_ANNOUNCE_WORLD, ANNOUNCER_FLAG_DISABLE_BG_QUEUE, bgName, q_min_level, q_max_level, qAlliance + qHorde, MaxPlayers); sWorld->SendWorldTextOptional(LANG_BG_QUEUE_ANNOUNCE_WORLD, ANNOUNCER_FLAG_DISABLE_BG_QUEUE, bgName.c_str(), q_min_level, q_max_level, qAlliance + qHorde, MaxPlayers);
} }
} }
} }
@@ -1120,7 +1039,7 @@ void BattlegroundQueue::SendJoinMessageArenaQueue(Player* leader, GroupQueueInfo
return; return;
} }
sWorld->SendWorldTextOptional(LANG_ARENA_QUEUE_ANNOUNCE_WORLD, ANNOUNCER_FLAG_DISABLE_ARENA_QUEUE, bgName, arenatype.c_str(), q_min_level, q_max_level, qPlayers, playersNeed); sWorld->SendWorldTextOptional(LANG_ARENA_QUEUE_ANNOUNCE_WORLD, ANNOUNCER_FLAG_DISABLE_ARENA_QUEUE, bgName.c_str(), arenatype.c_str(), q_min_level, q_max_level, qPlayers, playersNeed);
} }
} }
else else
@@ -1175,6 +1094,63 @@ int32 BattlegroundQueue::GetQueueAnnouncementTimer(uint32 bracketId) const
return _queueAnnouncementTimer[bracketId]; return _queueAnnouncementTimer[bracketId];
} }
void BattlegroundQueue::InviteGroupToBG(GroupQueueInfo* ginfo, Battleground* bg, TeamId teamId)
{
if (ginfo->IsInvitedToBGInstanceGUID)
return;
// set side if needed
if (teamId != TEAM_NEUTRAL)
ginfo->teamId = teamId;
// set invitation
ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(ginfo->BgTypeId, ginfo->ArenaType);
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
// set ArenaTeamId for rated matches
if (bg->isArena() && bg->isRated())
bg->SetArenaTeamIdForTeam(ginfo->teamId, ginfo->ArenaTeamId);
ginfo->RemoveInviteTime = GameTime::GetGameTimeMS().count() + INVITE_ACCEPT_WAIT_TIME;
// loop through the players
for (auto const& itr : ginfo->Players)
{
// get the player
Player* player = ObjectAccessor::FindConnectedPlayer(itr);
if (!player)
continue;
// update average wait time
bgQueue.PlayerInvitedToBGUpdateAverageWaitTime(ginfo);
// increase invited counter for each invited player
bg->IncreaseInvitedCount(ginfo->teamId);
// create remind invite events
BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(player->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, ginfo->BgTypeId, ginfo->ArenaType, ginfo->RemoveInviteTime);
bgQueue.AddEvent(inviteEvent, INVITATION_REMIND_TIME);
// create automatic remove events
BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(player->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgQueueTypeId, ginfo->RemoveInviteTime);
bgQueue.AddEvent(removeEvent, INVITE_ACCEPT_WAIT_TIME);
// Check queueSlot
uint32 queueSlot = player->GetBattlegroundQueueIndex(bgQueueTypeId);
ASSERT(queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES);
// send status packet
WorldPacket data;
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, ginfo->ArenaType, TEAM_NEUTRAL, bg->isRated(), ginfo->BgTypeId);
player->GetSession()->SendPacket(&data);
// pussywizard:
if (bg->isArena() && bg->isRated())
bg->ArenaLogEntries[player->GetGUID()].Fill(player->GetName().c_str(), player->GetGUID().GetCounter(), player->GetSession()->GetAccountId(), ginfo->ArenaTeamId, player->GetSession()->GetRemoteAddress());
}
}
/*********************************************************/ /*********************************************************/
/*** BATTLEGROUND QUEUE EVENTS ***/ /*** BATTLEGROUND QUEUE EVENTS ***/
/*********************************************************/ /*********************************************************/
@@ -72,7 +72,6 @@ public:
void UpdateEvents(uint32 diff); void UpdateEvents(uint32 diff);
void FillPlayersToBG(Battleground* bg, int32 aliFree, int32 hordeFree, BattlegroundBracketId bracket_id); void FillPlayersToBG(Battleground* bg, int32 aliFree, int32 hordeFree, BattlegroundBracketId bracket_id);
void FillPlayersToBGWithSpecific(Battleground* bg, int32 aliFree, int32 hordeFree, BattlegroundBracketId thisBracketId, BattlegroundQueue* specificQueue, BattlegroundBracketId specificBracketId);
bool CheckPremadeMatch(BattlegroundBracketId bracket_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam); bool CheckPremadeMatch(BattlegroundBracketId bracket_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam);
bool CheckNormalMatch(Battleground* bgTemplate, BattlegroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers); bool CheckNormalMatch(Battleground* bgTemplate, BattlegroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers);
bool CheckSkirmishForSameFaction(BattlegroundBracketId bracket_id, uint32 minPlayersPerTeam); bool CheckSkirmishForSameFaction(BattlegroundBracketId bracket_id, uint32 minPlayersPerTeam);
@@ -83,6 +82,7 @@ public:
bool GetPlayerGroupInfoData(ObjectGuid guid, GroupQueueInfo* ginfo); bool GetPlayerGroupInfoData(ObjectGuid guid, GroupQueueInfo* ginfo);
void PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo); void PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo);
uint32 GetAverageQueueWaitTime(GroupQueueInfo* ginfo) const; uint32 GetAverageQueueWaitTime(GroupQueueInfo* ginfo) const;
void InviteGroupToBG(GroupQueueInfo* ginfo, Battleground* bg, TeamId teamId);
[[nodiscard]] uint32 GetPlayersCountInGroupsQueue(BattlegroundBracketId bracketId, BattlegroundQueueGroupTypes bgqueue); [[nodiscard]] uint32 GetPlayersCountInGroupsQueue(BattlegroundBracketId bracketId, BattlegroundQueueGroupTypes bgqueue);
[[nodiscard]] bool IsAllQueuesEmpty(BattlegroundBracketId bracket_id); [[nodiscard]] bool IsAllQueuesEmpty(BattlegroundBracketId bracket_id);
void SendMessageBGQueue(Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry); void SendMessageBGQueue(Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry);
@@ -125,7 +125,7 @@ public:
}; };
//one selection pool for horde, other one for alliance //one selection pool for horde, other one for alliance
SelectionPool m_SelectionPools[BG_TEAMS_COUNT]; SelectionPool m_SelectionPools[PVP_TEAMS_COUNT];
ArenaType GetArenaType() { return m_arenaType; } ArenaType GetArenaType() { return m_arenaType; }
BattlegroundTypeId GetBGTypeID() { return m_bgTypeId; } BattlegroundTypeId GetBGTypeID() { return m_bgTypeId; }
@@ -136,8 +136,8 @@ public:
private: private:
BattlegroundTypeId m_bgTypeId; BattlegroundTypeId m_bgTypeId;
ArenaType m_arenaType; ArenaType m_arenaType;
uint32 m_WaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME]; uint32 m_WaitTimes[PVP_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME];
uint32 m_WaitTimeLastIndex[BG_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS]; uint32 m_WaitTimeLastIndex[PVP_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS];
// Event handler // Event handler
EventProcessor m_events; EventProcessor m_events;
@@ -0,0 +1,125 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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 _BATTLEGROUND_SCORE_H
#define _BATTLEGROUND_SCORE_H
#include "Errors.h"
#include "ObjectGuid.h"
#include "SharedDefines.h"
class WorldPacket;
enum ScoreType
{
SCORE_KILLING_BLOWS = 1,
SCORE_DEATHS,
SCORE_HONORABLE_KILLS,
SCORE_BONUS_HONOR,
SCORE_DAMAGE_DONE,
SCORE_HEALING_DONE,
// WS and EY
SCORE_FLAG_CAPTURES,
SCORE_FLAG_RETURNS,
// AB and IC
SCORE_BASES_ASSAULTED,
SCORE_BASES_DEFENDED,
// AV
SCORE_GRAVEYARDS_ASSAULTED,
SCORE_GRAVEYARDS_DEFENDED,
SCORE_TOWERS_ASSAULTED,
SCORE_TOWERS_DEFENDED,
SCORE_MINES_CAPTURED,
//SCORE_LEADERS_KILLED,
//SCORE_SECONDARY_OBJECTIVES,
// SOTA
SCORE_DESTROYED_DEMOLISHER,
SCORE_DESTROYED_WALL
};
struct AC_GAME_API BattlegroundScore
{
friend class Arena;
friend class Battleground;
protected:
BattlegroundScore(ObjectGuid playerGuid) : PlayerGuid(playerGuid) { }
virtual ~BattlegroundScore() = default;
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:
ABORT("Not implemented Battleground score type!");
break;
}
}
virtual void AppendToPacket(WorldPacket& data);
virtual void BuildObjectivesBlock(WorldPacket& /*data*/) = 0;
// For Logging purpose
virtual std::string ToString() const { return ""; }
[[nodiscard]] uint32 GetKillingBlows() const { return KillingBlows; }
[[nodiscard]] uint32 GetDeaths() const { return Deaths; }
[[nodiscard]] uint32 GetHonorableKills() const { return HonorableKills; }
[[nodiscard]] uint32 GetBonusHonor() const { return BonusHonor; }
[[nodiscard]] uint32 GetDamageDone() const { return DamageDone; }
[[nodiscard]] uint32 GetHealingDone() const { return HealingDone; }
[[nodiscard]] virtual uint32 GetAttr1() const { return 0; }
[[nodiscard]] virtual uint32 GetAttr2() const { return 0; }
[[nodiscard]] virtual uint32 GetAttr3() const { return 0; }
[[nodiscard]] virtual uint32 GetAttr4() const { return 0; }
[[nodiscard]] virtual uint32 GetAttr5() const { return 0; }
ObjectGuid PlayerGuid;
// Default score, present in every type
uint32 KillingBlows = 0;
uint32 Deaths = 0;
uint32 HonorableKills = 0;
uint32 BonusHonor = 0;
uint32 DamageDone = 0;
uint32 HealingDone = 0;
};
#endif // TRINITY_BATTLEGROUND_SCORE_H
@@ -25,6 +25,13 @@
#include "WorldPacket.h" #include "WorldPacket.h"
#include "WorldSession.h" #include "WorldSession.h"
void BattlegroundABScore::BuildObjectivesBlock(WorldPacket& data)
{
data << uint32(2);
data << uint32(BasesAssaulted);
data << uint32(BasesDefended);
}
BattlegroundAB::BattlegroundAB() BattlegroundAB::BattlegroundAB()
{ {
m_BuffChange = true; m_BuffChange = true;
@@ -37,11 +44,6 @@ BattlegroundAB::BattlegroundAB()
_teamScores500Disadvantage[TEAM_HORDE] = false; _teamScores500Disadvantage[TEAM_HORDE] = false;
_honorTics = 0; _honorTics = 0;
_reputationTics = 0; _reputationTics = 0;
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_AB_START_TWO_MINUTES;
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AB_START_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AB_START_HALF_MINUTE;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AB_HAS_BEGUN;
} }
BattlegroundAB::~BattlegroundAB() = default; BattlegroundAB::~BattlegroundAB() = default;
@@ -78,8 +80,17 @@ void BattlegroundAB::PostUpdateImpl(uint32 diff)
NodeOccupied(node); NodeOccupied(node);
SendNodeUpdate(node); SendNodeUpdate(node);
SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN, teamId == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE, nullptr, teamId == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE, LANG_BG_AB_NODE_STABLES + node); if (teamId == TEAM_ALLIANCE)
PlaySoundToAll(teamId == TEAM_ALLIANCE ? BG_AB_SOUND_NODE_CAPTURED_ALLIANCE : BG_AB_SOUND_NODE_CAPTURED_HORDE); {
SendBroadcastText(ABNodes[node].TextAllianceTaken, CHAT_MSG_BG_SYSTEM_ALLIANCE);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
}
else
{
SendBroadcastText(ABNodes[node].TextHordeTaken, CHAT_MSG_BG_SYSTEM_HORDE);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
}
break; break;
} }
case BG_AB_EVENT_ALLIANCE_TICK: case BG_AB_EVENT_ALLIANCE_TICK:
@@ -108,12 +119,12 @@ void BattlegroundAB::PostUpdateImpl(uint32 diff)
{ {
if (teamId == TEAM_ALLIANCE) if (teamId == TEAM_ALLIANCE)
{ {
SendMessageToAll(LANG_BG_AB_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); SendBroadcastText(BG_AB_TEXT_ALLIANCE_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY_ALLIANCE); PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY_ALLIANCE);
} }
else else
{ {
SendMessageToAll(LANG_BG_AB_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); SendBroadcastText(BG_AB_TEXT_HORDE_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY_HORDE); PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY_HORDE);
} }
} }
@@ -165,7 +176,7 @@ void BattlegroundAB::StartingEventOpenDoors()
void BattlegroundAB::AddPlayer(Player* player) void BattlegroundAB::AddPlayer(Player* player)
{ {
Battleground::AddPlayer(player); Battleground::AddPlayer(player);
PlayerScores[player->GetGUID()] = new BattlegroundABScore(player); PlayerScores.emplace(player->GetGUID().GetCounter(), new BattlegroundABScore(player->GetGUID()));
} }
void BattlegroundAB::RemovePlayer(Player* player) void BattlegroundAB::RemovePlayer(Player* player)
@@ -309,8 +320,8 @@ void BattlegroundAB::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb
player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
uint32 sound = 0; uint32 sound = 0;
uint32 message = 0; TeamId teamid = player->GetTeamId();
uint32 message2 = 0;
DeleteBanner(node); DeleteBanner(node);
CreateBanner(node, true); CreateBanner(node, true);
@@ -322,8 +333,15 @@ void BattlegroundAB::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb
_capturePointInfo[node]._ownerTeamId = TEAM_NEUTRAL; _capturePointInfo[node]._ownerTeamId = TEAM_NEUTRAL;
_bgEvents.RescheduleEvent(BG_AB_EVENT_CAPTURE_STABLE + node, BG_AB_FLAG_CAPTURING_TIME); _bgEvents.RescheduleEvent(BG_AB_EVENT_CAPTURE_STABLE + node, BG_AB_FLAG_CAPTURING_TIME);
sound = BG_AB_SOUND_NODE_CLAIMED; sound = BG_AB_SOUND_NODE_CLAIMED;
message = LANG_BG_AB_NODE_CLAIMED;
message2 = player->GetTeamId() == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE; if (teamid == TEAM_ALLIANCE)
{
SendBroadcastText(ABNodes[node].TextAllianceClaims, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
}
else
{
SendBroadcastText(ABNodes[node].TextHordeClaims, CHAT_MSG_BG_SYSTEM_HORDE, player);
}
} }
else if (_capturePointInfo[node]._state == BG_AB_NODE_STATE_ALLY_CONTESTED || _capturePointInfo[node]._state == BG_AB_NODE_STATE_HORDE_CONTESTED) else if (_capturePointInfo[node]._state == BG_AB_NODE_STATE_ALLY_CONTESTED || _capturePointInfo[node]._state == BG_AB_NODE_STATE_HORDE_CONTESTED)
{ {
@@ -334,7 +352,15 @@ void BattlegroundAB::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb
_capturePointInfo[node]._state = static_cast<uint8>(BG_AB_NODE_STATE_ALLY_CONTESTED) + player->GetTeamId(); _capturePointInfo[node]._state = static_cast<uint8>(BG_AB_NODE_STATE_ALLY_CONTESTED) + player->GetTeamId();
_capturePointInfo[node]._ownerTeamId = TEAM_NEUTRAL; _capturePointInfo[node]._ownerTeamId = TEAM_NEUTRAL;
_bgEvents.RescheduleEvent(BG_AB_EVENT_CAPTURE_STABLE + node, BG_AB_FLAG_CAPTURING_TIME); _bgEvents.RescheduleEvent(BG_AB_EVENT_CAPTURE_STABLE + node, BG_AB_FLAG_CAPTURING_TIME);
message = LANG_BG_AB_NODE_ASSAULTED;
if (teamid == TEAM_ALLIANCE)
{
SendBroadcastText(ABNodes[node].TextAllianceAssaulted, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
}
else
{
SendBroadcastText(ABNodes[node].TextHordeAssaulted, CHAT_MSG_BG_SYSTEM_HORDE, player);
}
} }
else else
{ {
@@ -343,8 +369,17 @@ void BattlegroundAB::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb
_capturePointInfo[node]._ownerTeamId = player->GetTeamId(); _capturePointInfo[node]._ownerTeamId = player->GetTeamId();
_bgEvents.CancelEvent(BG_AB_EVENT_CAPTURE_STABLE + node); _bgEvents.CancelEvent(BG_AB_EVENT_CAPTURE_STABLE + node);
NodeOccupied(node); // after setting team owner NodeOccupied(node); // after setting team owner
message = LANG_BG_AB_NODE_DEFENDED;
if (teamid == TEAM_ALLIANCE)
{
SendBroadcastText(ABNodes[node].TextAllianceDefended, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
}
else
{
SendBroadcastText(ABNodes[node].TextHordeDefended, CHAT_MSG_BG_SYSTEM_HORDE, player);
}
} }
sound = player->GetTeamId() == TEAM_ALLIANCE ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE; sound = player->GetTeamId() == TEAM_ALLIANCE ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
} }
else else
@@ -357,13 +392,20 @@ void BattlegroundAB::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb
ApplyPhaseMask(); ApplyPhaseMask();
_bgEvents.RescheduleEvent(BG_AB_EVENT_CAPTURE_STABLE + node, BG_AB_FLAG_CAPTURING_TIME); _bgEvents.RescheduleEvent(BG_AB_EVENT_CAPTURE_STABLE + node, BG_AB_FLAG_CAPTURING_TIME);
message = LANG_BG_AB_NODE_ASSAULTED;
sound = player->GetTeamId() == TEAM_ALLIANCE ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE; sound = player->GetTeamId() == TEAM_ALLIANCE ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
if (teamid == TEAM_ALLIANCE)
{
SendBroadcastText(ABNodes[node].TextAllianceAssaulted, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
}
else
{
SendBroadcastText(ABNodes[node].TextHordeAssaulted, CHAT_MSG_BG_SYSTEM_HORDE, player);
}
} }
SendNodeUpdate(node); SendNodeUpdate(node);
PlaySoundToAll(sound); PlaySoundToAll(sound);
SendMessage2ToAll(message, player->GetTeamId() == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE, player, LANG_BG_AB_NODE_STABLES + node, message2);
} }
TeamId BattlegroundAB::GetPrematureWinner() TeamId BattlegroundAB::GetPrematureWinner()
@@ -473,26 +515,24 @@ GraveyardStruct const* BattlegroundAB::GetClosestGraveyard(Player* player)
return nearestEntry; return nearestEntry;
} }
void BattlegroundAB::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) bool BattlegroundAB::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
{ {
auto itr = PlayerScores.find(player->GetGUID()); if (!Battleground::UpdatePlayerScore(player, type, value, doAddHonor))
if (itr == PlayerScores.end()) return false;
return;
switch (type) switch (type)
{ {
case SCORE_BASES_ASSAULTED: case SCORE_BASES_ASSAULTED:
((BattlegroundABScore*)itr->second)->BasesAssaulted += value;
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, BG_AB_OBJECTIVE_ASSAULT_BASE); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, BG_AB_OBJECTIVE_ASSAULT_BASE);
break; break;
case SCORE_BASES_DEFENDED: case SCORE_BASES_DEFENDED:
((BattlegroundABScore*)itr->second)->BasesDefended += value;
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, BG_AB_OBJECTIVE_DEFEND_BASE); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, BG_AB_OBJECTIVE_DEFEND_BASE);
break; break;
default: default:
Battleground::UpdatePlayerScore(player, type, value, doAddHonor);
break; break;
} }
return true;
} }
bool BattlegroundAB::AllNodesConrolledByTeam(TeamId teamId) const bool BattlegroundAB::AllNodesConrolledByTeam(TeamId teamId) const
@@ -508,7 +548,8 @@ void BattlegroundAB::ApplyPhaseMask()
phaseMask |= 1 << (i * 2 + 1 + _capturePointInfo[i]._ownerTeamId); phaseMask |= 1 << (i * 2 + 1 + _capturePointInfo[i]._ownerTeamId);
const BattlegroundPlayerMap& bgPlayerMap = GetPlayers(); const BattlegroundPlayerMap& bgPlayerMap = GetPlayers();
for (auto itr : bgPlayerMap)
for (auto const& itr : bgPlayerMap)
{ {
itr.second->SetPhaseMask(phaseMask, false); itr.second->SetPhaseMask(phaseMask, false);
itr.second->UpdateObjectVisibility(true, false); itr.second->UpdateObjectVisibility(true, false);
@@ -19,6 +19,7 @@
#define __BATTLEGROUNDAB_H #define __BATTLEGROUNDAB_H
#include "Battleground.h" #include "Battleground.h"
#include "BattlegroundScore.h"
#include "EventMap.h" #include "EventMap.h"
enum BG_AB_Events enum BG_AB_Events
@@ -147,6 +148,34 @@ enum BG_AB_BattlegroundNodes
BG_AB_ALL_NODES_COUNT = 7, // all nodes (dynamic and static) BG_AB_ALL_NODES_COUNT = 7, // all nodes (dynamic and static)
}; };
enum BG_AB_BroadcastTexts
{
BG_AB_TEXT_ALLIANCE_NEAR_VICTORY = 10598,
BG_AB_TEXT_HORDE_NEAR_VICTORY = 10599,
};
struct ABNodeInfo
{
uint32 NodeId;
uint32 TextAllianceAssaulted;
uint32 TextHordeAssaulted;
uint32 TextAllianceTaken;
uint32 TextHordeTaken;
uint32 TextAllianceDefended;
uint32 TextHordeDefended;
uint32 TextAllianceClaims;
uint32 TextHordeClaims;
};
ABNodeInfo const ABNodes[BG_AB_DYNAMIC_NODES_COUNT] =
{
{ BG_AB_NODE_STABLES, 10199, 10200, 10203, 10204, 10201, 10202, 10286, 10287 },
{ BG_AB_NODE_BLACKSMITH, 10211, 10212, 10213, 10214, 10215, 10216, 10290, 10291 },
{ BG_AB_NODE_FARM, 10217, 10218, 10219, 10220, 10221, 10222, 10288, 10289 },
{ BG_AB_NODE_LUMBER_MILL, 10224, 10225, 10226, 10227, 10228, 10229, 10284, 10285 },
{ BG_AB_NODE_GOLD_MINE, 10230, 10231, 10232, 10233, 10234, 10235, 10282, 10283 }
};
enum BG_AB_NodeStatus enum BG_AB_NodeStatus
{ {
BG_AB_NODE_STATE_NEUTRAL = 0, BG_AB_NODE_STATE_NEUTRAL = 0,
@@ -225,18 +254,40 @@ const float BG_AB_SpiritGuidePos[BG_AB_ALL_NODES_COUNT][4] =
{714.61f, 646.15f, -10.87f, 4.34f} // horde starting base {714.61f, 646.15f, -10.87f, 4.34f} // horde starting base
}; };
struct BattlegroundABScore : public BattlegroundScore struct BattlegroundABScore final : public BattlegroundScore
{ {
explicit BattlegroundABScore(Player* player) : BattlegroundScore(player), BasesAssaulted(0), BasesDefended(0) { } friend class BattlegroundAB;
~BattlegroundABScore() override = default;
uint32 BasesAssaulted;
uint32 BasesDefended;
uint32 GetAttr1() const final { return BasesAssaulted; } protected:
uint32 GetAttr2() const final { return BasesDefended; }
explicit BattlegroundABScore(ObjectGuid playerGuid) : BattlegroundScore(playerGuid) { }
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 override;
uint32 GetAttr1() const final override { return BasesAssaulted; }
uint32 GetAttr2() const final override { return BasesDefended; }
uint32 BasesAssaulted = 0;
uint32 BasesDefended = 0;
}; };
class BattlegroundAB : public Battleground class AC_GAME_API BattlegroundAB : public Battleground
{ {
public: public:
BattlegroundAB(); BattlegroundAB();
@@ -252,7 +303,7 @@ public:
void EndBattleground(TeamId winnerTeamId) override; void EndBattleground(TeamId winnerTeamId) override;
GraveyardStruct const* GetClosestGraveyard(Player* player) override; GraveyardStruct const* GetClosestGraveyard(Player* player) override;
void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override; bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
void FillInitialWorldStates(WorldPacket& data) override; void FillInitialWorldStates(WorldPacket& data) override;
void EventPlayerClickedOnFlag(Player* source, GameObject* gameObject) override; void EventPlayerClickedOnFlag(Player* source, GameObject* gameObject) override;
@@ -288,7 +339,7 @@ private:
EventMap _bgEvents; EventMap _bgEvents;
uint32 _honorTics; uint32 _honorTics;
uint32 _reputationTics; uint32 _reputationTics;
uint8 _controlledPoints[BG_TEAMS_COUNT] {}; uint8 _controlledPoints[PVP_TEAMS_COUNT] {};
bool _teamScores500Disadvantage[BG_TEAMS_COUNT] {}; bool _teamScores500Disadvantage[PVP_TEAMS_COUNT] {};
}; };
#endif #endif
@@ -27,6 +27,16 @@
#include "WorldPacket.h" #include "WorldPacket.h"
#include "WorldSession.h" #include "WorldSession.h"
void BattlegroundAVScore::BuildObjectivesBlock(WorldPacket& data)
{
data << uint32(5); // Objectives Count
data << uint32(GraveyardsAssaulted);
data << uint32(GraveyardsDefended);
data << uint32(TowersAssaulted);
data << uint32(TowersDefended);
data << uint32(MinesCaptured);
}
BattlegroundAV::BattlegroundAV() BattlegroundAV::BattlegroundAV()
{ {
BgObjects.resize(BG_AV_OBJECT_MAX); BgObjects.resize(BG_AV_OBJECT_MAX);
@@ -49,14 +59,9 @@ BattlegroundAV::BattlegroundAV()
for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i) for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i)
InitNode(i, TEAM_NEUTRAL, false); InitNode(i, TEAM_NEUTRAL, false);
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_AV_START_TWO_MINUTES; StartMessageIds[BG_STARTING_EVENT_SECOND] = BG_AV_TEXT_START_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AV_START_ONE_MINUTE; StartMessageIds[BG_STARTING_EVENT_THIRD] = BG_AV_TEXT_START_HALF_MINUTE;
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AV_START_HALF_MINUTE; StartMessageIds[BG_STARTING_EVENT_FOURTH] = BG_AV_TEXT_BATTLE_HAS_BEGUN;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AV_HAS_BEGUN;
}
BattlegroundAV::~BattlegroundAV()
{
} }
void BattlegroundAV::HandleKillPlayer(Player* player, Player* killer) void BattlegroundAV::HandleKillPlayer(Player* player, Player* killer)
@@ -268,7 +273,15 @@ void BattlegroundAV::UpdateScore(TeamId teamId, int16 points)
} }
else if (!m_IsInformedNearVictory[teamId] && m_Team_Scores[teamId] < SEND_MSG_NEAR_LOSE) else if (!m_IsInformedNearVictory[teamId] && m_Team_Scores[teamId] < SEND_MSG_NEAR_LOSE)
{ {
SendMessageToAll(teamId == TEAM_HORDE ? LANG_BG_AV_H_NEAR_LOSE : LANG_BG_AV_A_NEAR_LOSE, teamId == TEAM_HORDE ? CHAT_MSG_BG_SYSTEM_HORDE : CHAT_MSG_BG_SYSTEM_ALLIANCE); if (teamId == TEAM_ALLIANCE)
{
SendBroadcastText(BG_AV_TEXT_ALLIANCE_NEAR_LOSE, CHAT_MSG_BG_SYSTEM_ALLIANCE);
}
else
{
SendBroadcastText(BG_AV_TEXT_HORDE_NEAR_LOSE, CHAT_MSG_BG_SYSTEM_HORDE);
}
PlaySoundToAll(AV_SOUND_NEAR_VICTORY); PlaySoundToAll(AV_SOUND_NEAR_VICTORY);
m_IsInformedNearVictory[teamId] = true; m_IsInformedNearVictory[teamId] = true;
} }
@@ -456,8 +469,7 @@ void BattlegroundAV::StartingEventOpenDoors()
void BattlegroundAV::AddPlayer(Player* player) void BattlegroundAV::AddPlayer(Player* player)
{ {
Battleground::AddPlayer(player); Battleground::AddPlayer(player);
//create score and add it to map, default values are set in constructor PlayerScores.emplace(player->GetGUID().GetCounter(), new BattlegroundAVScore(player->GetGUID()));
PlayerScores[player->GetGUID()] = new BattlegroundAVScore(player);
} }
void BattlegroundAV::EndBattleground(TeamId winnerTeamId) void BattlegroundAV::EndBattleground(TeamId winnerTeamId)
@@ -542,43 +554,33 @@ void BattlegroundAV::HandleAreaTrigger(Player* player, uint32 trigger)
} }
} }
void BattlegroundAV::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) bool BattlegroundAV::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
{ {
auto itr = PlayerScores.find(player->GetGUID()); if (!Battleground::UpdatePlayerScore(player, type, value, doAddHonor))
if (itr == PlayerScores.end()) return false;
return;
switch (type) switch (type)
{ {
case SCORE_GRAVEYARDS_ASSAULTED: case SCORE_GRAVEYARDS_ASSAULTED:
((BattlegroundAVScore*)itr->second)->GraveyardsAssaulted += value;
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_GRAVEYARD); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_GRAVEYARD);
break; break;
case SCORE_GRAVEYARDS_DEFENDED: case SCORE_GRAVEYARDS_DEFENDED:
((BattlegroundAVScore*)itr->second)->GraveyardsDefended += value;
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_GRAVEYARD); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_GRAVEYARD);
break; break;
case SCORE_TOWERS_ASSAULTED: case SCORE_TOWERS_ASSAULTED:
((BattlegroundAVScore*)itr->second)->TowersAssaulted += value;
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_TOWER); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_TOWER);
break; break;
case SCORE_TOWERS_DEFENDED: case SCORE_TOWERS_DEFENDED:
((BattlegroundAVScore*)itr->second)->TowersDefended += value;
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_TOWER); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_TOWER);
break; break;
case SCORE_MINES_CAPTURED: 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;
break; break;
default: default:
Battleground::UpdatePlayerScore(player, type, value, doAddHonor); Battleground::UpdatePlayerScore(player, type, value, doAddHonor);
break; break;
} }
return true;
} }
void BattlegroundAV::EventPlayerDestroyedPoint(BG_AV_Nodes node) void BattlegroundAV::EventPlayerDestroyedPoint(BG_AV_Nodes node)
@@ -19,6 +19,7 @@
#define __BATTLEGROUNDAV_H #define __BATTLEGROUNDAV_H
#include "Battleground.h" #include "Battleground.h"
#include "BattlegroundScore.h"
#define LANG_BG_AV_A_CAPTAIN_BUFF "Begone. Uncouth scum! The Alliance shall prevail in Alterac Valley!" #define LANG_BG_AV_A_CAPTAIN_BUFF "Begone. Uncouth scum! The Alliance shall prevail in Alterac Valley!"
#define LANG_BG_AV_H_CAPTAIN_BUFF "Now is the time to attack! For the Horde!" #define LANG_BG_AV_H_CAPTAIN_BUFF "Now is the time to attack! For the Horde!"
@@ -51,6 +52,16 @@
#define AV_EVENT_START_BATTLE 9166 // Achievement: The Alterac Blitz #define AV_EVENT_START_BATTLE 9166 // Achievement: The Alterac Blitz
enum BG_AV_BroadcastTexts
{
BG_AV_TEXT_START_ONE_MINUTE = 10638,
BG_AV_TEXT_START_HALF_MINUTE = 10639,
BG_AV_TEXT_BATTLE_HAS_BEGUN = 10640,
BG_AV_TEXT_ALLIANCE_NEAR_LOSE = 23210,
BG_AV_TEXT_HORDE_NEAR_LOSE = 23211
};
enum BG_AV_Sounds enum BG_AV_Sounds
{ {
//TODO: get out if there comes a sound when neutral team captures mine //TODO: get out if there comes a sound when neutral team captures mine
@@ -1341,6 +1352,7 @@ enum BG_AV_BUFF
AV_BUFF_A_CAPTAIN = 23693, //the buff which the alliance captain does AV_BUFF_A_CAPTAIN = 23693, //the buff which the alliance captain does
AV_BUFF_H_CAPTAIN = 22751 //the buff which the horde captain does AV_BUFF_H_CAPTAIN = 22751 //the buff which the horde captain does
}; };
enum BG_AV_States enum BG_AV_States
{ {
POINT_NEUTRAL = 0, POINT_NEUTRAL = 0,
@@ -1551,17 +1563,47 @@ struct BG_AV_NodeInfo
inline BG_AV_Nodes& operator++(BG_AV_Nodes& i) { return i = BG_AV_Nodes(i + 1); } 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
{ {
explicit BattlegroundAVScore(Player* player) : BattlegroundScore(player), GraveyardsAssaulted(0), GraveyardsDefended(0), TowersAssaulted(0), TowersDefended(0), MinesCaptured(0), LeadersKilled(0), SecondaryObjectives(0) { } friend class BattlegroundAV;
~BattlegroundAVScore() override { }
uint32 GraveyardsAssaulted; protected:
uint32 GraveyardsDefended; explicit BattlegroundAVScore(ObjectGuid playerGuid) : BattlegroundScore(playerGuid) { }
uint32 TowersAssaulted;
uint32 TowersDefended; void UpdateScore(uint32 type, uint32 value) override
uint32 MinesCaptured; {
uint32 LeadersKilled; switch (type)
uint32 SecondaryObjectives; {
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 override;
uint32 GraveyardsAssaulted = 0;
uint32 GraveyardsDefended = 0;
uint32 TowersAssaulted = 0;
uint32 TowersDefended = 0;
uint32 MinesCaptured = 0;
//uint32 LeadersKilled;
//uint32 SecondaryObjectives;
uint32 GetAttr1() const final { return GraveyardsAssaulted; } uint32 GetAttr1() const final { return GraveyardsAssaulted; }
uint32 GetAttr2() const final { return GraveyardsDefended; } uint32 GetAttr2() const final { return GraveyardsDefended; }
@@ -1570,11 +1612,11 @@ struct BattlegroundAVScore : public BattlegroundScore
uint32 GetAttr5() const final { return MinesCaptured; } uint32 GetAttr5() const final { return MinesCaptured; }
}; };
class BattlegroundAV : public Battleground class AC_GAME_API BattlegroundAV : public Battleground
{ {
public: public:
BattlegroundAV(); BattlegroundAV();
~BattlegroundAV() override; ~BattlegroundAV() override = default;
/* inherited from BattlegroundClass */ /* inherited from BattlegroundClass */
void AddPlayer(Player* player) override; void AddPlayer(Player* player) override;
@@ -1588,7 +1630,7 @@ public:
/*general stuff*/ /*general stuff*/
void UpdateScore(TeamId teamId, int16 points); void UpdateScore(TeamId teamId, int16 points);
void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override; bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
/*handlestuff*/ //these are functions which get called from extern /*handlestuff*/ //these are functions which get called from extern
void EventPlayerClickedOnFlag(Player* source, GameObject* gameObject) override; void EventPlayerClickedOnFlag(Player* source, GameObject* gameObject) override;
@@ -16,7 +16,6 @@
*/ */
#include "BattlegroundBE.h" #include "BattlegroundBE.h"
#include "Language.h"
#include "Log.h" #include "Log.h"
#include "Player.h" #include "Player.h"
#include "WorldPacket.h" #include "WorldPacket.h"
@@ -24,20 +23,6 @@
BattlegroundBE::BattlegroundBE() BattlegroundBE::BattlegroundBE()
{ {
BgObjects.resize(BG_BE_OBJECT_MAX); BgObjects.resize(BG_BE_OBJECT_MAX);
StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
//we must set messageIds
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
}
BattlegroundBE::~BattlegroundBE()
{
} }
void BattlegroundBE::StartingEventCloseDoors() void BattlegroundBE::StartingEventCloseDoors()
@@ -58,39 +43,6 @@ void BattlegroundBE::StartingEventOpenDoors()
SpawnBGObject(i, 60); SpawnBGObject(i, 60);
} }
void BattlegroundBE::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
PlayerScores[player->GetGUID()] = new BattlegroundScore(player);
Battleground::UpdateArenaWorldState();
}
void BattlegroundBE::RemovePlayer(Player* /*player*/)
{
if (GetStatus() == STATUS_WAIT_LEAVE)
return;
Battleground::UpdateArenaWorldState();
CheckArenaWinConditions();
}
void BattlegroundBE::HandleKillPlayer(Player* player, Player* killer)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
if (!killer)
{
LOG_ERROR("bg.battleground", "Killer player not found");
return;
}
Battleground::HandleKillPlayer(player, killer);
Battleground::UpdateArenaWorldState();
CheckArenaWinConditions();
}
bool BattlegroundBE::HandlePlayerUnderMap(Player* player) bool BattlegroundBE::HandlePlayerUnderMap(Player* player)
{ {
player->NearTeleportTo(6238.930176f, 262.963470f, 0.889519f, player->GetOrientation()); player->NearTeleportTo(6238.930176f, 262.963470f, 0.889519f, player->GetOrientation());
@@ -137,14 +89,8 @@ void BattlegroundBE::HandleAreaTrigger(Player* player, uint32 trigger)
void BattlegroundBE::FillInitialWorldStates(WorldPacket& data) void BattlegroundBE::FillInitialWorldStates(WorldPacket& data)
{ {
data << uint32(0x9f3) << uint32(1); // 9 data << uint32(0x9f3) << uint32(1); // 9
Battleground::UpdateArenaWorldState(); Arena::FillInitialWorldStates(data);
}
void BattlegroundBE::Init()
{
//call parent's class reset
Battleground::Init();
} }
bool BattlegroundBE::SetupBattleground() bool BattlegroundBE::SetupBattleground()
@@ -167,8 +113,3 @@ bool BattlegroundBE::SetupBattleground()
return true; return true;
} }
void BattlegroundBE::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
{
Battleground::UpdatePlayerScore(player, type, value, doAddHonor);
}
@@ -18,7 +18,7 @@
#ifndef __BATTLEGROUNDBE_H #ifndef __BATTLEGROUNDBE_H
#define __BATTLEGROUNDBE_H #define __BATTLEGROUNDBE_H
#include "Battleground.h" #include "Arena.h"
enum BattlegroundBEObjectTypes enum BattlegroundBEObjectTypes
{ {
@@ -33,7 +33,7 @@ enum BattlegroundBEObjectTypes
BG_BE_OBJECT_MAX = 8 BG_BE_OBJECT_MAX = 8
}; };
enum BattlegroundBEObjects enum BattlegroundBEGameObjects
{ {
BG_BE_OBJECT_TYPE_DOOR_1 = 183971, BG_BE_OBJECT_TYPE_DOOR_1 = 183971,
BG_BE_OBJECT_TYPE_DOOR_2 = 183973, BG_BE_OBJECT_TYPE_DOOR_2 = 183973,
@@ -43,26 +43,19 @@ enum BattlegroundBEObjects
BG_BE_OBJECT_TYPE_BUFF_2 = 184664 BG_BE_OBJECT_TYPE_BUFF_2 = 184664
}; };
class BattlegroundBE : public Battleground class AC_GAME_API BattlegroundBE : public Arena
{ {
public: public:
BattlegroundBE(); BattlegroundBE();
~BattlegroundBE() override;
/* inherited from BattlegroundClass */ /* inherited from BattlegroundClass */
void AddPlayer(Player* player) override;
void StartingEventCloseDoors() override; void StartingEventCloseDoors() override;
void StartingEventOpenDoors() override; void StartingEventOpenDoors() override;
void RemovePlayer(Player* player) override;
void HandleAreaTrigger(Player* player, uint32 trigger) override; void HandleAreaTrigger(Player* player, uint32 trigger) override;
bool SetupBattleground() override; bool SetupBattleground() override;
void Init() override;
void FillInitialWorldStates(WorldPacket& d) override; void FillInitialWorldStates(WorldPacket& d) override;
void HandleKillPlayer(Player* player, Player* killer) override;
bool HandlePlayerUnderMap(Player* player) override; bool HandlePlayerUnderMap(Player* player) override;
/* Scorekeeping */
void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
}; };
#endif #endif
@@ -16,6 +16,7 @@
*/ */
#include "BattlegroundDS.h" #include "BattlegroundDS.h"
#include "ArenaScore.h"
#include "Creature.h" #include "Creature.h"
#include "GameObject.h" #include "GameObject.h"
#include "Language.h" #include "Language.h"
@@ -30,25 +31,8 @@ BattlegroundDS::BattlegroundDS()
BgObjects.resize(BG_DS_OBJECT_MAX); BgObjects.resize(BG_DS_OBJECT_MAX);
BgCreatures.resize(BG_DS_NPC_MAX); BgCreatures.resize(BG_DS_NPC_MAX);
_waterfallTimer = 0;
_waterfallStatus = 0;
_waterfallKnockbackTimer = 0;
_pipeKnockBackTimer = 0; _pipeKnockBackTimer = 0;
_pipeKnockBackCount = 0; _pipeKnockBackCount = 0;
StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
//we must set messageIds
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
}
BattlegroundDS::~BattlegroundDS()
{
} }
void BattlegroundDS::PostUpdateImpl(uint32 diff) void BattlegroundDS::PostUpdateImpl(uint32 diff)
@@ -56,64 +40,58 @@ void BattlegroundDS::PostUpdateImpl(uint32 diff)
if (GetStatus() != STATUS_IN_PROGRESS) if (GetStatus() != STATUS_IN_PROGRESS)
return; return;
if (getPipeKnockBackCount() < BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT) _events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{ {
if (getPipeKnockBackTimer() < diff) switch (eventId)
{
case BG_DS_EVENT_WATERFALL_WARNING:
// Add the water
DoorClose(BG_DS_OBJECT_WATER_2);
_events.ScheduleEvent(BG_DS_EVENT_WATERFALL_ON, BG_DS_WATERFALL_WARNING_DURATION);
break;
case BG_DS_EVENT_WATERFALL_ON:
// Active collision and start knockback timer
DoorClose(BG_DS_OBJECT_WATER_1);
_events.ScheduleEvent(BG_DS_EVENT_WATERFALL_OFF, BG_DS_WATERFALL_DURATION);
_events.ScheduleEvent(BG_DS_EVENT_WATERFALL_KNOCKBACK, BG_DS_WATERFALL_KNOCKBACK_TIMER);
break;
case BG_DS_EVENT_WATERFALL_OFF:
// Remove collision and water
DoorOpen(BG_DS_OBJECT_WATER_1);
DoorOpen(BG_DS_OBJECT_WATER_2);
_events.CancelEvent(BG_DS_EVENT_WATERFALL_KNOCKBACK);
_events.ScheduleEvent(BG_DS_EVENT_WATERFALL_WARNING, BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX);
break;
case BG_DS_EVENT_WATERFALL_KNOCKBACK:
// Repeat knockback while the waterfall still active
if (Creature* waterSpout = GetBGCreature(BG_DS_NPC_WATERFALL_KNOCKBACK))
waterSpout->CastSpell(waterSpout, BG_DS_SPELL_WATER_SPOUT, true);
_events.ScheduleEvent(eventId, BG_DS_WATERFALL_KNOCKBACK_TIMER);
break;
case BG_DS_EVENT_PIPE_KNOCKBACK:
for (uint32 i = BG_DS_NPC_PIPE_KNOCKBACK_1; i <= BG_DS_NPC_PIPE_KNOCKBACK_2; ++i)
if (Creature* waterSpout = GetBGCreature(i))
waterSpout->CastSpell(waterSpout, BG_DS_SPELL_FLUSH, true);
break;
}
}
if (_pipeKnockBackCount < BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT)
{
if (_pipeKnockBackTimer < diff)
{ {
for (uint32 i = BG_DS_NPC_PIPE_KNOCKBACK_1; i <= BG_DS_NPC_PIPE_KNOCKBACK_2; ++i) for (uint32 i = BG_DS_NPC_PIPE_KNOCKBACK_1; i <= BG_DS_NPC_PIPE_KNOCKBACK_2; ++i)
if (Creature* waterSpout = GetBgMap()->GetCreature(BgCreatures[i])) if (Creature* waterSpout = GetBGCreature(i))
waterSpout->CastSpell(waterSpout, BG_DS_SPELL_FLUSH, true); waterSpout->CastSpell(waterSpout, BG_DS_SPELL_FLUSH, true);
setPipeKnockBackCount(getPipeKnockBackCount() + 1); ++_pipeKnockBackCount;
setPipeKnockBackTimer(BG_DS_PIPE_KNOCKBACK_DELAY); _pipeKnockBackTimer = BG_DS_PIPE_KNOCKBACK_DELAY;
} }
else else
setPipeKnockBackTimer(getPipeKnockBackTimer() - diff); _pipeKnockBackTimer -= diff;
} }
if (getWaterFallStatus() == BG_DS_WATERFALL_STATUS_ON) // Repeat knockback while the waterfall still active
{
if (getWaterFallKnockbackTimer() < diff)
{
if (Creature* waterSpout = GetBgMap()->GetCreature(BgCreatures[BG_DS_NPC_WATERFALL_KNOCKBACK]))
waterSpout->CastSpell(waterSpout, BG_DS_SPELL_WATER_SPOUT, true);
setWaterFallKnockbackTimer(BG_DS_WATERFALL_KNOCKBACK_TIMER);
}
else
setWaterFallKnockbackTimer(getWaterFallKnockbackTimer() - diff);
}
if (getWaterFallTimer() < diff)
{
if (getWaterFallStatus() == BG_DS_WATERFALL_STATUS_OFF) // Add the water
{
DoorClose(BG_DS_OBJECT_WATER_2);
setWaterFallTimer(BG_DS_WATERFALL_WARNING_DURATION);
setWaterFallStatus(BG_DS_WATERFALL_STATUS_WARNING);
}
else if (getWaterFallStatus() == BG_DS_WATERFALL_STATUS_WARNING) // Active collision and perform knockback
{
if (GameObject* gob = GetBgMap()->GetGameObject(BgObjects[BG_DS_OBJECT_WATER_1]))
gob->SetGoState(GO_STATE_READY);
setWaterFallTimer(BG_DS_WATERFALL_DURATION);
setWaterFallStatus(BG_DS_WATERFALL_STATUS_ON);
setWaterFallKnockbackTimer(BG_DS_WATERFALL_KNOCKBACK_TIMER);
}
else //if (getWaterFallStatus() == BG_DS_WATERFALL_STATUS_ON) // Remove collision and water
{
// turn off collision
if (GameObject* gob = GetBgMap()->GetGameObject(BgObjects[BG_DS_OBJECT_WATER_1]))
gob->SetGoState(GO_STATE_ACTIVE);
DoorOpen(BG_DS_OBJECT_WATER_2);
setWaterFallTimer(urand(BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX));
setWaterFallStatus(BG_DS_WATERFALL_STATUS_OFF);
}
}
else
setWaterFallTimer(getWaterFallTimer() - diff);
} }
void BattlegroundDS::StartingEventCloseDoors() void BattlegroundDS::StartingEventCloseDoors()
@@ -130,11 +108,12 @@ void BattlegroundDS::StartingEventOpenDoors()
for (uint32 i = BG_DS_OBJECT_BUFF_1; i <= BG_DS_OBJECT_BUFF_2; ++i) for (uint32 i = BG_DS_OBJECT_BUFF_1; i <= BG_DS_OBJECT_BUFF_2; ++i)
SpawnBGObject(i, 60); SpawnBGObject(i, 60);
setWaterFallTimer(urand(BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX)); _events.ScheduleEvent(BG_DS_EVENT_WATERFALL_WARNING, BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX);
setWaterFallStatus(BG_DS_WATERFALL_STATUS_OFF); //for (uint8 i = 0; i < BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT; ++i)
// _events.ScheduleEvent(BG_DS_EVENT_PIPE_KNOCKBACK, BG_DS_PIPE_KNOCKBACK_FIRST_DELAY + i * BG_DS_PIPE_KNOCKBACK_DELAY);
setPipeKnockBackTimer(BG_DS_PIPE_KNOCKBACK_FIRST_DELAY); _pipeKnockBackCount = 0;
setPipeKnockBackCount(0); _pipeKnockBackTimer = BG_DS_PIPE_KNOCKBACK_FIRST_DELAY;
SpawnBGObject(BG_DS_OBJECT_WATER_2, RESPAWN_IMMEDIATELY); SpawnBGObject(BG_DS_OBJECT_WATER_2, RESPAWN_IMMEDIATELY);
DoorOpen(BG_DS_OBJECT_WATER_2); DoorOpen(BG_DS_OBJECT_WATER_2);
@@ -149,39 +128,6 @@ void BattlegroundDS::StartingEventOpenDoors()
itr->second->RemoveAurasDueToSpell(48018); itr->second->RemoveAurasDueToSpell(48018);
} }
void BattlegroundDS::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
PlayerScores[player->GetGUID()] = new BattlegroundScore(player);
Battleground::UpdateArenaWorldState();
}
void BattlegroundDS::RemovePlayer(Player* /*player*/)
{
if (GetStatus() == STATUS_WAIT_LEAVE)
return;
Battleground::UpdateArenaWorldState();
CheckArenaWinConditions();
}
void BattlegroundDS::HandleKillPlayer(Player* player, Player* killer)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
if (!killer)
{
LOG_ERROR("bg.battleground", "BattlegroundDS: Killer player not found");
return;
}
Battleground::HandleKillPlayer(player, killer);
Battleground::UpdateArenaWorldState();
CheckArenaWinConditions();
}
void BattlegroundDS::HandleAreaTrigger(Player* player, uint32 trigger) void BattlegroundDS::HandleAreaTrigger(Player* player, uint32 trigger)
{ {
if (GetStatus() != STATUS_IN_PROGRESS) if (GetStatus() != STATUS_IN_PROGRESS)
@@ -192,13 +138,13 @@ void BattlegroundDS::HandleAreaTrigger(Player* player, uint32 trigger)
case 5347: case 5347:
case 5348: case 5348:
// Remove effects of Demonic Circle Summon // Remove effects of Demonic Circle Summon
if (player->HasAura(48018)) if (player->HasAura(SPELL_WARL_DEMONIC_CIRCLE))
player->RemoveAurasDueToSpell(48018); player->RemoveAurasDueToSpell(SPELL_WARL_DEMONIC_CIRCLE);
// Someone has get back into the pipes and the knockback has already been performed, // Someone has get back into the pipes and the knockback has already been performed,
// so we reset the knockback count for kicking the player again into the arena. // so we reset the knockback count for kicking the player again into the arena.
if (getPipeKnockBackCount() >= BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT) if (_pipeKnockBackCount >= BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT)
setPipeKnockBackCount(0); _pipeKnockBackCount = 0;
break; break;
// OUTSIDE OF ARENA, TELEPORT! // OUTSIDE OF ARENA, TELEPORT!
case 5328: case 5328:
@@ -218,6 +164,9 @@ void BattlegroundDS::HandleAreaTrigger(Player* player, uint32 trigger)
case 5344: // -60 case 5344: // -60
player->NearTeleportTo(1330.0f, 800.0f, 3.16f, player->GetOrientation()); player->NearTeleportTo(1330.0f, 800.0f, 3.16f, player->GetOrientation());
break; break;
/*default:
Battleground::HandleAreaTrigger(player, trigger);
break;*/
} }
} }
@@ -230,13 +179,7 @@ bool BattlegroundDS::HandlePlayerUnderMap(Player* player)
void BattlegroundDS::FillInitialWorldStates(WorldPacket& data) void BattlegroundDS::FillInitialWorldStates(WorldPacket& data)
{ {
data << uint32(3610) << uint32(1); // 9 show data << uint32(3610) << uint32(1); // 9 show
Battleground::UpdateArenaWorldState(); Arena::FillInitialWorldStates(data);
}
void BattlegroundDS::Init()
{
//call parent's class reset
Battleground::Init();
} }
bool BattlegroundDS::SetupBattleground() bool BattlegroundDS::SetupBattleground()
@@ -18,7 +18,9 @@
#ifndef __BATTLEGROUNDDS_H #ifndef __BATTLEGROUNDDS_H
#define __BATTLEGROUNDDS_H #define __BATTLEGROUNDDS_H
#include "Battleground.h" #include "Arena.h"
#include "Duration.h"
#include "EventMap.h"
enum BattlegroundDSObjectTypes enum BattlegroundDSObjectTypes
{ {
@@ -33,7 +35,7 @@ enum BattlegroundDSObjectTypes
BG_DS_OBJECT_MAX = 8 BG_DS_OBJECT_MAX = 8
}; };
enum BattlegroundDSObjects enum BattlegroundDSGameObjects
{ {
BG_DS_OBJECT_TYPE_DOOR_1 = 192642, BG_DS_OBJECT_TYPE_DOOR_1 = 192642,
BG_DS_OBJECT_TYPE_DOOR_2 = 192643, BG_DS_OBJECT_TYPE_DOOR_2 = 192643,
@@ -61,62 +63,54 @@ enum BattlegroundDSSpells
BG_DS_SPELL_FLUSH = 57405, // Visual and target selector for the starting knockback from the pipe BG_DS_SPELL_FLUSH = 57405, // Visual and target selector for the starting knockback from the pipe
BG_DS_SPELL_FLUSH_KNOCKBACK = 61698, // Knockback effect for previous spell (triggered, not need to be casted) BG_DS_SPELL_FLUSH_KNOCKBACK = 61698, // Knockback effect for previous spell (triggered, not need to be casted)
BG_DS_SPELL_WATER_SPOUT = 58873, // Knockback effect of the central waterfall BG_DS_SPELL_WATER_SPOUT = 58873, // Knockback effect of the central waterfall
SPELL_WARL_DEMONIC_CIRCLE = 48018 // Demonic Circle Summon
}; };
enum BattlegroundDSData enum BattlegroundDSData
{ {
// These values are NOT blizzlike... need the correct data! BG_DS_PIPE_KNOCKBACK_FIRST_DELAY = 5000,
BG_DS_WATERFALL_TIMER_MIN = 30000, BG_DS_PIPE_KNOCKBACK_DELAY = 3000,
BG_DS_WATERFALL_TIMER_MAX = 60000, BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT = 2,
BG_DS_WATERFALL_WARNING_DURATION = 5000,
BG_DS_WATERFALL_DURATION = 30000,
BG_DS_WATERFALL_KNOCKBACK_TIMER = 1500,
BG_DS_PIPE_KNOCKBACK_FIRST_DELAY = 5000,
BG_DS_PIPE_KNOCKBACK_DELAY = 3000,
BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT = 2,
BG_DS_WATERFALL_STATUS_WARNING = 1, // Water starting to fall, but no LoS Blocking nor movement blocking
BG_DS_WATERFALL_STATUS_ON = 2, // LoS and Movement blocking active
BG_DS_WATERFALL_STATUS_OFF = 3,
}; };
class BattlegroundDS : public Battleground // These values are NOT blizzlike... need the correct data!
constexpr Seconds BG_DS_WATERFALL_TIMER_MIN = 30s;
constexpr Seconds BG_DS_WATERFALL_TIMER_MAX = 60s;
constexpr Seconds BG_DS_WATERFALL_WARNING_DURATION = 5s;
constexpr Seconds BG_DS_WATERFALL_DURATION = 30s;
constexpr Milliseconds BG_DS_WATERFALL_KNOCKBACK_TIMER = 1500ms;
enum BattlegroundDSEvents
{
BG_DS_EVENT_WATERFALL_WARNING = 1, // Water starting to fall, but no LoS Blocking nor movement blocking
BG_DS_EVENT_WATERFALL_ON = 2, // LoS and Movement blocking active
BG_DS_EVENT_WATERFALL_OFF = 3,
BG_DS_EVENT_WATERFALL_KNOCKBACK = 4,
BG_DS_EVENT_PIPE_KNOCKBACK = 5
};
class AC_GAME_API BattlegroundDS : public Arena
{ {
public: public:
BattlegroundDS(); BattlegroundDS();
~BattlegroundDS() override;
/* inherited from BattlegroundClass */ /* inherited from BattlegroundClass */
void AddPlayer(Player* player) override;
void StartingEventCloseDoors() override; void StartingEventCloseDoors() override;
void StartingEventOpenDoors() override; void StartingEventOpenDoors() override;
void RemovePlayer(Player* player) override;
void HandleAreaTrigger(Player* player, uint32 trigger) override; void HandleAreaTrigger(Player* player, uint32 trigger) override;
bool SetupBattleground() override; bool SetupBattleground() override;
void Init() override;
void FillInitialWorldStates(WorldPacket& d) override; void FillInitialWorldStates(WorldPacket& d) override;
void HandleKillPlayer(Player* player, Player* killer) override;
bool HandlePlayerUnderMap(Player* player) override; bool HandlePlayerUnderMap(Player* player) override;
private: private:
uint32 _waterfallTimer; void PostUpdateImpl(uint32 diff) override;
uint8 _waterfallStatus;
uint32 _waterfallKnockbackTimer;
uint32 _pipeKnockBackTimer; uint32 _pipeKnockBackTimer;
uint8 _pipeKnockBackCount; uint8 _pipeKnockBackCount;
void PostUpdateImpl(uint32 diff) override; EventMap _events;
protected:
uint32 getWaterFallStatus() { return _waterfallStatus; };
void setWaterFallStatus(uint8 status) { _waterfallStatus = status; };
uint32 getWaterFallTimer() { return _waterfallTimer; };
void setWaterFallTimer(uint32 timer) { _waterfallTimer = timer; };
uint32 getWaterFallKnockbackTimer() { return _waterfallKnockbackTimer; };
void setWaterFallKnockbackTimer(uint32 timer) { _waterfallKnockbackTimer = timer; };
uint8 getPipeKnockBackCount() { return _pipeKnockBackCount; };
void setPipeKnockBackCount(uint8 count) { _pipeKnockBackCount = count; };
uint32 getPipeKnockBackTimer() { return _pipeKnockBackTimer; };
void setPipeKnockBackTimer(uint32 timer) { _pipeKnockBackTimer = timer; };
}; };
#endif #endif
@@ -28,6 +28,12 @@
#include "WorldPacket.h" #include "WorldPacket.h"
#include "WorldSession.h" #include "WorldSession.h"
void BattlegroundEYScore::BuildObjectivesBlock(WorldPacket& data)
{
data << uint32(1); // Objectives Count
data << uint32(FlagCaptures);
}
BattlegroundEY::BattlegroundEY() BattlegroundEY::BattlegroundEY()
{ {
m_BuffChange = true; m_BuffChange = true;
@@ -43,11 +49,6 @@ BattlegroundEY::BattlegroundEY()
_ownedPointsCount[TEAM_HORDE] = 0; _ownedPointsCount[TEAM_HORDE] = 0;
_flagState = BG_EY_FLAG_STATE_ON_BASE; _flagState = BG_EY_FLAG_STATE_ON_BASE;
_flagCapturedObject = 0; _flagCapturedObject = 0;
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_EY_START_TWO_MINUTES;
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_EY_START_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_EY_START_HALF_MINUTE;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_EY_HAS_BEGUN;
} }
BattlegroundEY::~BattlegroundEY() BattlegroundEY::~BattlegroundEY()
@@ -144,6 +145,7 @@ void BattlegroundEY::UpdatePointsState()
itr->second->SendUpdateWorldState(PROGRESS_BAR_PERCENT_GREY, BG_EY_PROGRESS_BAR_PERCENT_GREY); itr->second->SendUpdateWorldState(PROGRESS_BAR_PERCENT_GREY, BG_EY_PROGRESS_BAR_PERCENT_GREY);
itr->second->SendUpdateWorldState(PROGRESS_BAR_STATUS, _capturePointInfo[point]._barStatus); itr->second->SendUpdateWorldState(PROGRESS_BAR_STATUS, _capturePointInfo[point]._barStatus);
++_capturePointInfo[point]._playersCount[itr->second->GetTeamId()]; ++_capturePointInfo[point]._playersCount[itr->second->GetTeamId()];
_capturePointInfo[point].player = itr->second;
// Xinef: ugly hax... area trigger is no longer called by client... // Xinef: ugly hax... area trigger is no longer called by client...
if (pointObject->GetEntry() == BG_OBJECT_FR_TOWER_CAP_EY_ENTRY && itr->second->GetDistance2d(2043.96f, 1729.68f) < 3.0f) if (pointObject->GetEntry() == BG_OBJECT_FR_TOWER_CAP_EY_ENTRY && itr->second->GetDistance2d(2043.96f, 1729.68f) < 3.0f)
@@ -165,10 +167,10 @@ void BattlegroundEY::UpdatePointsState()
if (pointOwnerTeamId != _capturePointInfo[point]._ownerTeamId) if (pointOwnerTeamId != _capturePointInfo[point]._ownerTeamId)
{ {
if (_capturePointInfo[point].IsUncontrolled()) if (_capturePointInfo[point].IsUncontrolled())
EventTeamCapturedPoint(pointOwnerTeamId, point); EventTeamCapturedPoint(_capturePointInfo[point].player, pointOwnerTeamId, point);
if (pointOwnerTeamId == TEAM_NEUTRAL && _capturePointInfo[point].IsUnderControl()) if (pointOwnerTeamId == TEAM_NEUTRAL && _capturePointInfo[point].IsUnderControl())
EventTeamLostPoint(pointOwnerTeamId, point); EventTeamLostPoint(_capturePointInfo[point].player, point);
} }
} }
} }
@@ -206,7 +208,7 @@ void BattlegroundEY::UpdatePointsIcons(uint32 point)
void BattlegroundEY::AddPlayer(Player* player) void BattlegroundEY::AddPlayer(Player* player)
{ {
Battleground::AddPlayer(player); Battleground::AddPlayer(player);
PlayerScores[player->GetGUID()] = new BattlegroundEYScore(player); PlayerScores.emplace(player->GetGUID().GetCounter(), new BattlegroundEYScore(player->GetGUID()));
} }
void BattlegroundEY::RemovePlayer(Player* player) void BattlegroundEY::RemovePlayer(Player* player)
@@ -371,7 +373,7 @@ void BattlegroundEY::RespawnFlag()
_flagCapturedObject = 0; _flagCapturedObject = 0;
SpawnBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM, RESPAWN_IMMEDIATELY); SpawnBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM, RESPAWN_IMMEDIATELY);
SendMessageToAll(LANG_BG_EY_RESETED_FLAG, CHAT_MSG_BG_SYSTEM_NEUTRAL); SendBroadcastText(BG_EY_TEXT_FLAG_RESET, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(BG_EY_SOUND_FLAG_RESET); PlaySoundToAll(BG_EY_SOUND_FLAG_RESET);
UpdateWorldState(NETHERSTORM_FLAG, 1); UpdateWorldState(NETHERSTORM_FLAG, 1);
} }
@@ -413,7 +415,10 @@ void BattlegroundEY::EventPlayerDroppedFlag(Player* player)
player->CastSpell(player, SPELL_RECENTLY_DROPPED_FLAG, true); player->CastSpell(player, SPELL_RECENTLY_DROPPED_FLAG, true);
player->CastSpell(player, BG_EY_PLAYER_DROPPED_FLAG_SPELL, true); player->CastSpell(player, BG_EY_PLAYER_DROPPED_FLAG_SPELL, true);
SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, player->GetTeamId() == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE); if (player->GetTeamId() == TEAM_ALLIANCE)
SendBroadcastText(BG_EY_TEXT_FLAG_DROPPED, CHAT_MSG_BG_SYSTEM_ALLIANCE);
else
SendBroadcastText(BG_EY_TEXT_FLAG_DROPPED, CHAT_MSG_BG_SYSTEM_HORDE);
} }
void BattlegroundEY::EventPlayerClickedOnFlag(Player* player, GameObject* gameObject) void BattlegroundEY::EventPlayerClickedOnFlag(Player* player, GameObject* gameObject)
@@ -429,12 +434,16 @@ void BattlegroundEY::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb
player->CastSpell(player, BG_EY_NETHERSTORM_FLAG_SPELL, true); player->CastSpell(player, BG_EY_NETHERSTORM_FLAG_SPELL, true);
player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
PSendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG, player->GetTeamId() == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE, nullptr, player->GetName().c_str());
PlaySoundToAll(player->GetTeamId() == TEAM_ALLIANCE ? BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE : BG_EY_SOUND_FLAG_PICKED_UP_HORDE); PlaySoundToAll(player->GetTeamId() == TEAM_ALLIANCE ? BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE : BG_EY_SOUND_FLAG_PICKED_UP_HORDE);
UpdateWorldState(NETHERSTORM_FLAG, 0); UpdateWorldState(NETHERSTORM_FLAG, 0);
if (player->GetTeamId() == TEAM_ALLIANCE)
SendBroadcastText(BG_EY_TEXT_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
else
SendBroadcastText(BG_EY_TEXT_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, player);
} }
void BattlegroundEY::EventTeamLostPoint(TeamId /*teamId*/, uint32 point) void BattlegroundEY::EventTeamLostPoint(Player* player, uint32 point)
{ {
TeamId oldTeamId = _capturePointInfo[point]._ownerTeamId; TeamId oldTeamId = _capturePointInfo[point]._ownerTeamId;
if (oldTeamId == TEAM_ALLIANCE) if (oldTeamId == TEAM_ALLIANCE)
@@ -443,7 +452,7 @@ void BattlegroundEY::EventTeamLostPoint(TeamId /*teamId*/, uint32 point)
SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeAlliance, RESPAWN_ONE_DAY); SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeAlliance, RESPAWN_ONE_DAY);
SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeAlliance + 1, RESPAWN_ONE_DAY); SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeAlliance + 1, RESPAWN_ONE_DAY);
SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeAlliance + 2, RESPAWN_ONE_DAY); SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeAlliance + 2, RESPAWN_ONE_DAY);
SendMessageToAll(m_LosingPointTypes[point].MessageIdAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE); SendBroadcastText(m_LosingPointTypes[point].MessageIdAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
} }
else else
{ {
@@ -451,7 +460,7 @@ void BattlegroundEY::EventTeamLostPoint(TeamId /*teamId*/, uint32 point)
SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeHorde, RESPAWN_ONE_DAY); SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeHorde, RESPAWN_ONE_DAY);
SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeHorde + 1, RESPAWN_ONE_DAY); SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeHorde + 1, RESPAWN_ONE_DAY);
SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeHorde + 2, RESPAWN_ONE_DAY); SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeHorde + 2, RESPAWN_ONE_DAY);
SendMessageToAll(m_LosingPointTypes[point].MessageIdHorde, CHAT_MSG_BG_SYSTEM_HORDE); SendBroadcastText(m_LosingPointTypes[point].MessageIdHorde, CHAT_MSG_BG_SYSTEM_HORDE, player);
} }
SpawnBGObject(m_LosingPointTypes[point].SpawnNeutralObjectType, RESPAWN_IMMEDIATELY); SpawnBGObject(m_LosingPointTypes[point].SpawnNeutralObjectType, RESPAWN_IMMEDIATELY);
@@ -465,7 +474,7 @@ void BattlegroundEY::EventTeamLostPoint(TeamId /*teamId*/, uint32 point)
DelCreature(BG_EY_TRIGGER_FEL_REAVER + point); DelCreature(BG_EY_TRIGGER_FEL_REAVER + point);
} }
void BattlegroundEY::EventTeamCapturedPoint(TeamId teamId, uint32 point) void BattlegroundEY::EventTeamCapturedPoint(Player* player, TeamId teamId, uint32 point)
{ {
SpawnBGObject(m_CapturingPointTypes[point].DespawnNeutralObjectType, RESPAWN_ONE_DAY); SpawnBGObject(m_CapturingPointTypes[point].DespawnNeutralObjectType, RESPAWN_ONE_DAY);
SpawnBGObject(m_CapturingPointTypes[point].DespawnNeutralObjectType + 1, RESPAWN_ONE_DAY); SpawnBGObject(m_CapturingPointTypes[point].DespawnNeutralObjectType + 1, RESPAWN_ONE_DAY);
@@ -477,7 +486,7 @@ void BattlegroundEY::EventTeamCapturedPoint(TeamId teamId, uint32 point)
SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeAlliance, RESPAWN_IMMEDIATELY); SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeAlliance, RESPAWN_IMMEDIATELY);
SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeAlliance + 1, RESPAWN_IMMEDIATELY); SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeAlliance + 1, RESPAWN_IMMEDIATELY);
SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeAlliance + 2, RESPAWN_IMMEDIATELY); SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeAlliance + 2, RESPAWN_IMMEDIATELY);
SendMessageToAll(m_CapturingPointTypes[point].MessageIdAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE); SendBroadcastText(m_CapturingPointTypes[point].MessageIdAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
} }
else else
{ {
@@ -485,7 +494,7 @@ void BattlegroundEY::EventTeamCapturedPoint(TeamId teamId, uint32 point)
SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeHorde, RESPAWN_IMMEDIATELY); SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeHorde, RESPAWN_IMMEDIATELY);
SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeHorde + 1, RESPAWN_IMMEDIATELY); SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeHorde + 1, RESPAWN_IMMEDIATELY);
SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeHorde + 2, RESPAWN_IMMEDIATELY); SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeHorde + 2, RESPAWN_IMMEDIATELY);
SendMessageToAll(m_CapturingPointTypes[point].MessageIdHorde, CHAT_MSG_BG_SYSTEM_HORDE); SendBroadcastText(m_CapturingPointTypes[point].MessageIdHorde, CHAT_MSG_BG_SYSTEM_HORDE, player);
} }
_capturePointInfo[point]._ownerTeamId = teamId; _capturePointInfo[point]._ownerTeamId = teamId;
@@ -524,12 +533,12 @@ void BattlegroundEY::EventPlayerCapturedFlag(Player* player, uint32 BgObjectType
if (player->GetTeamId() == TEAM_ALLIANCE) if (player->GetTeamId() == TEAM_ALLIANCE)
{ {
PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE); PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE);
SendMessageToAll(LANG_BG_EY_CAPTURED_FLAG_A, CHAT_MSG_BG_SYSTEM_ALLIANCE, player); SendBroadcastText(BG_EY_TEXT_ALLIANCE_CAPTURED_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
} }
else else
{ {
PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_HORDE); PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_HORDE);
SendMessageToAll(LANG_BG_EY_CAPTURED_FLAG_H, CHAT_MSG_BG_SYSTEM_HORDE, player); SendBroadcastText(BG_EY_TEXT_HORDE_CAPTURED_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, player);
} }
UpdatePlayerScore(player, SCORE_FLAG_CAPTURES, 1); UpdatePlayerScore(player, SCORE_FLAG_CAPTURES, 1);
@@ -537,18 +546,21 @@ void BattlegroundEY::EventPlayerCapturedFlag(Player* player, uint32 BgObjectType
AddPoints(player->GetTeamId(), BG_EY_FlagPoints[_ownedPointsCount[player->GetTeamId()] - 1]); AddPoints(player->GetTeamId(), BG_EY_FlagPoints[_ownedPointsCount[player->GetTeamId()] - 1]);
} }
void BattlegroundEY::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) bool BattlegroundEY::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
{ {
if (type == SCORE_FLAG_CAPTURES) if (!Battleground::UpdatePlayerScore(player, type, value, doAddHonor))
return false;
switch (type)
{ {
BattlegroundScoreMap::iterator itr = PlayerScores.find(player->GetGUID()); case SCORE_FLAG_CAPTURES:
if (itr != PlayerScores.end()) player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, BG_EY_OBJECTIVE_CAPTURE_FLAG);
((BattlegroundEYScore*)itr->second)->FlagCaptures += value; break;
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, BG_EY_OBJECTIVE_CAPTURE_FLAG); default:
return; break;
} }
Battleground::UpdatePlayerScore(player, type, value, doAddHonor); return true;
} }
void BattlegroundEY::FillInitialWorldStates(WorldPacket& data) void BattlegroundEY::FillInitialWorldStates(WorldPacket& data)
@@ -19,8 +19,9 @@
#define __BATTLEGROUNDEY_H #define __BATTLEGROUNDEY_H
#include "Battleground.h" #include "Battleground.h"
#include "EventMap.h" #include "BattlegroundScore.h"
#include "Language.h" #include "Language.h"
#include "EventMap.h"
enum BG_EY_Events enum BG_EY_Events
{ {
@@ -242,6 +243,35 @@ enum BG_EY_FlagState
BG_EY_FLAG_STATE_ON_GROUND = 3 BG_EY_FLAG_STATE_ON_GROUND = 3
}; };
enum BG_EY_BroadcastTexts
{
BG_EY_TEXT_ALLIANCE_TAKEN_FEL_REAVER_RUINS = 17828,
BG_EY_TEXT_HORDE_TAKEN_FEL_REAVER_RUINS = 17829,
BG_EY_TEXT_ALLIANCE_LOST_FEL_REAVER_RUINS = 17835,
BG_EY_TEXT_HORDE_LOST_FEL_REAVER_RUINS = 17836,
BG_EY_TEXT_ALLIANCE_TAKEN_BLOOD_ELF_TOWER = 17819,
BG_EY_TEXT_HORDE_TAKEN_BLOOD_ELF_TOWER = 17823,
BG_EY_TEXT_ALLIANCE_LOST_BLOOD_ELF_TOWER = 17831,
BG_EY_TEXT_HORDE_LOST_BLOOD_ELF_TOWER = 17832,
BG_EY_TEXT_ALLIANCE_TAKEN_DRAENEI_RUINS = 17827,
BG_EY_TEXT_HORDE_TAKEN_DRAENEI_RUINS = 17826,
BG_EY_TEXT_ALLIANCE_LOST_DRAENEI_RUINS = 17833,
BG_EY_TEXT_HORDE_LOST_DRAENEI_RUINS = 17834,
BG_EY_TEXT_ALLIANCE_TAKEN_MAGE_TOWER = 17824,
BG_EY_TEXT_HORDE_TAKEN_MAGE_TOWER = 17825,
BG_EY_TEXT_ALLIANCE_LOST_MAGE_TOWER = 17837,
BG_EY_TEXT_HORDE_LOST_MAGE_TOWER = 17838,
BG_EY_TEXT_TAKEN_FLAG = 18359,
BG_EY_TEXT_FLAG_DROPPED = 18361,
BG_EY_TEXT_FLAG_RESET = 18364,
BG_EY_TEXT_ALLIANCE_CAPTURED_FLAG = 18375,
BG_EY_TEXT_HORDE_CAPTURED_FLAG = 18384,
};
struct BattlegroundEYPointIconsStruct struct BattlegroundEYPointIconsStruct
{ {
BattlegroundEYPointIconsStruct(uint32 _WorldStateControlIndex, uint32 _WorldStateAllianceControlledIndex, uint32 _WorldStateHordeControlledIndex) BattlegroundEYPointIconsStruct(uint32 _WorldStateControlIndex, uint32 _WorldStateAllianceControlledIndex, uint32 _WorldStateHordeControlledIndex)
@@ -305,30 +335,48 @@ const BattlegroundEYPointIconsStruct m_PointsIconStruct[EY_POINTS_MAX] =
const BattlegroundEYLosingPointStruct m_LosingPointTypes[EY_POINTS_MAX] = const BattlegroundEYLosingPointStruct m_LosingPointTypes[EY_POINTS_MAX] =
{ {
BattlegroundEYLosingPointStruct(BG_EY_OBJECT_N_BANNER_FEL_REAVER_CENTER, BG_EY_OBJECT_A_BANNER_FEL_REAVER_CENTER, LANG_BG_EY_HAS_LOST_A_F_RUINS, BG_EY_OBJECT_H_BANNER_FEL_REAVER_CENTER, LANG_BG_EY_HAS_LOST_H_F_RUINS), BattlegroundEYLosingPointStruct(BG_EY_OBJECT_N_BANNER_FEL_REAVER_CENTER, BG_EY_OBJECT_A_BANNER_FEL_REAVER_CENTER, BG_EY_TEXT_ALLIANCE_LOST_FEL_REAVER_RUINS, BG_EY_OBJECT_H_BANNER_FEL_REAVER_CENTER, BG_EY_TEXT_HORDE_LOST_FEL_REAVER_RUINS),
BattlegroundEYLosingPointStruct(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_LOST_A_B_TOWER, BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_LOST_H_B_TOWER), BattlegroundEYLosingPointStruct(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, BG_EY_TEXT_ALLIANCE_LOST_BLOOD_ELF_TOWER, BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, BG_EY_TEXT_HORDE_LOST_BLOOD_ELF_TOWER),
BattlegroundEYLosingPointStruct(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_LOST_A_D_RUINS, BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_LOST_H_D_RUINS), BattlegroundEYLosingPointStruct(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, BG_EY_TEXT_ALLIANCE_LOST_DRAENEI_RUINS, BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, BG_EY_TEXT_HORDE_LOST_DRAENEI_RUINS),
BattlegroundEYLosingPointStruct(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_LOST_A_M_TOWER, BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_LOST_H_M_TOWER) BattlegroundEYLosingPointStruct(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, BG_EY_TEXT_ALLIANCE_LOST_MAGE_TOWER, BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, BG_EY_TEXT_HORDE_LOST_MAGE_TOWER)
}; };
const BattlegroundEYCapturingPointStruct m_CapturingPointTypes[EY_POINTS_MAX] = const BattlegroundEYCapturingPointStruct m_CapturingPointTypes[EY_POINTS_MAX] =
{ {
BattlegroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_FEL_REAVER_CENTER, BG_EY_OBJECT_A_BANNER_FEL_REAVER_CENTER, LANG_BG_EY_HAS_TAKEN_A_F_RUINS, BG_EY_OBJECT_H_BANNER_FEL_REAVER_CENTER, LANG_BG_EY_HAS_TAKEN_H_F_RUINS, BG_EY_GRAVEYARD_FEL_REAVER), BattlegroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_FEL_REAVER_CENTER, BG_EY_OBJECT_A_BANNER_FEL_REAVER_CENTER, BG_EY_TEXT_ALLIANCE_TAKEN_FEL_REAVER_RUINS, BG_EY_OBJECT_H_BANNER_FEL_REAVER_CENTER, BG_EY_TEXT_HORDE_TAKEN_FEL_REAVER_RUINS, BG_EY_GRAVEYARD_FEL_REAVER),
BattlegroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_TAKEN_A_B_TOWER, BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_TAKEN_H_B_TOWER, BG_EY_GRAVEYARD_BLOOD_ELF), BattlegroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, BG_EY_TEXT_ALLIANCE_TAKEN_BLOOD_ELF_TOWER, BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, BG_EY_TEXT_HORDE_TAKEN_BLOOD_ELF_TOWER, BG_EY_GRAVEYARD_BLOOD_ELF),
BattlegroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_TAKEN_A_D_RUINS, BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_TAKEN_H_D_RUINS, BG_EY_GRAVEYARD_DRAENEI_RUINS), BattlegroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, BG_EY_TEXT_ALLIANCE_TAKEN_DRAENEI_RUINS, BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, BG_EY_TEXT_HORDE_TAKEN_DRAENEI_RUINS, BG_EY_GRAVEYARD_DRAENEI_RUINS),
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, BG_EY_GRAVEYARD_MAGE_TOWER) BattlegroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, BG_EY_TEXT_ALLIANCE_TAKEN_MAGE_TOWER, BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, BG_EY_TEXT_HORDE_TAKEN_MAGE_TOWER, BG_EY_GRAVEYARD_MAGE_TOWER)
}; };
struct BattlegroundEYScore : public BattlegroundScore struct BattlegroundEYScore final : public BattlegroundScore
{ {
BattlegroundEYScore(Player* player) : BattlegroundScore(player), FlagCaptures(0) { } friend class BattlegroundEY;
~BattlegroundEYScore() override { }
uint32 FlagCaptures;
uint32 GetAttr1() const final { return FlagCaptures; } protected:
BattlegroundEYScore(ObjectGuid playerGuid) : BattlegroundScore(playerGuid) { }
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 override;
uint32 GetAttr1() const final override { return FlagCaptures; }
uint32 FlagCaptures = 0;
}; };
class BattlegroundEY : public Battleground class AC_GAME_API BattlegroundEY : public Battleground
{ {
public: public:
BattlegroundEY(); BattlegroundEY();
@@ -354,7 +402,7 @@ public:
bool SetupBattleground() override; bool SetupBattleground() override;
void Init() override; void Init() override;
void EndBattleground(TeamId winnerTeamId) override; void EndBattleground(TeamId winnerTeamId) override;
void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override; bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
void FillInitialWorldStates(WorldPacket& data) override; void FillInitialWorldStates(WorldPacket& data) override;
void SetDroppedFlagGUID(ObjectGuid guid, TeamId /*teamId*/ = TEAM_NEUTRAL) override { _droppedFlagGUID = guid; } void SetDroppedFlagGUID(ObjectGuid guid, TeamId /*teamId*/ = TEAM_NEUTRAL) override { _droppedFlagGUID = guid; }
ObjectGuid GetDroppedFlagGUID() const { return _droppedFlagGUID; } ObjectGuid GetDroppedFlagGUID() const { return _droppedFlagGUID; }
@@ -371,8 +419,8 @@ private:
void PostUpdateImpl(uint32 diff) override; void PostUpdateImpl(uint32 diff) override;
void EventPlayerCapturedFlag(Player* Source, uint32 BgObjectType); void EventPlayerCapturedFlag(Player* Source, uint32 BgObjectType);
void EventTeamLostPoint(TeamId teamId, uint32 point); void EventTeamLostPoint(Player* player, uint32 point);
void EventTeamCapturedPoint(TeamId teamId, uint32 point); void EventTeamCapturedPoint(Player* player, TeamId teamId, uint32 point);
void UpdatePointsCount(); void UpdatePointsCount();
void UpdatePointsIcons(uint32 point); void UpdatePointsIcons(uint32 point);
@@ -393,7 +441,8 @@ private:
TeamId _ownerTeamId; TeamId _ownerTeamId;
int8 _barStatus; int8 _barStatus;
uint32 _areaTrigger; uint32 _areaTrigger;
int8 _playersCount[BG_TEAMS_COUNT]; int8 _playersCount[PVP_TEAMS_COUNT];
Player* player = nullptr;
bool IsUnderControl(TeamId teamId) const { return _ownerTeamId == teamId; } bool IsUnderControl(TeamId teamId) const { return _ownerTeamId == teamId; }
bool IsUnderControl() const { return _ownerTeamId != TEAM_NEUTRAL; } bool IsUnderControl() const { return _ownerTeamId != TEAM_NEUTRAL; }
@@ -403,7 +452,7 @@ private:
CapturePointInfo _capturePointInfo[EY_POINTS_MAX]; CapturePointInfo _capturePointInfo[EY_POINTS_MAX];
EventMap _bgEvents; EventMap _bgEvents;
uint32 _honorTics; uint32 _honorTics;
uint8 _ownedPointsCount[BG_TEAMS_COUNT]; uint8 _ownedPointsCount[PVP_TEAMS_COUNT];
ObjectGuid _flagKeeperGUID; ObjectGuid _flagKeeperGUID;
ObjectGuid _droppedFlagGUID; ObjectGuid _droppedFlagGUID;
uint8 _flagState; uint8 _flagState;
@@ -29,16 +29,18 @@
#include "WorldPacket.h" #include "WorldPacket.h"
#include "WorldSession.h" #include "WorldSession.h"
void BattlegroundICScore::BuildObjectivesBlock(WorldPacket& data)
{
data << uint32(2); // Objectives Count
data << uint32(BasesAssaulted);
data << uint32(BasesDefended);
}
BattlegroundIC::BattlegroundIC() BattlegroundIC::BattlegroundIC()
{ {
BgObjects.resize(MAX_NORMAL_GAMEOBJECTS_SPAWNS + MAX_AIRSHIPS_SPAWNS + MAX_HANGAR_TELEPORTERS_SPAWNS + MAX_FORTRESS_TELEPORTERS_SPAWNS + MAX_HANGAR_TELEPORTER_EFFECTS_SPAWNS + MAX_FORTRESS_TELEPORTER_EFFECTS_SPAWNS); BgObjects.resize(MAX_NORMAL_GAMEOBJECTS_SPAWNS + MAX_AIRSHIPS_SPAWNS + MAX_HANGAR_TELEPORTERS_SPAWNS + MAX_FORTRESS_TELEPORTERS_SPAWNS + MAX_HANGAR_TELEPORTER_EFFECTS_SPAWNS + MAX_FORTRESS_TELEPORTER_EFFECTS_SPAWNS);
BgCreatures.resize(MAX_NORMAL_NPCS_SPAWNS + MAX_WORKSHOP_SPAWNS + MAX_DOCKS_SPAWNS + MAX_SPIRIT_GUIDES_SPAWNS + MAX_HANGAR_NPCS_SPAWNS); BgCreatures.resize(MAX_NORMAL_NPCS_SPAWNS + MAX_WORKSHOP_SPAWNS + MAX_DOCKS_SPAWNS + MAX_SPIRIT_GUIDES_SPAWNS + MAX_HANGAR_NPCS_SPAWNS);
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_IC_START_TWO_MINUTES;
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_IC_START_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_IC_START_HALF_MINUTE;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_IC_HAS_BEGUN;
for (uint8 i = 0; i < 2; ++i) for (uint8 i = 0; i < 2; ++i)
factionReinforcements[i] = MAX_REINFORCEMENTS; factionReinforcements[i] = MAX_REINFORCEMENTS;
@@ -60,10 +62,6 @@ BattlegroundIC::BattlegroundIC()
respawnMap.clear(); respawnMap.clear();
} }
BattlegroundIC::~BattlegroundIC()
{
}
void BattlegroundIC::DoAction(uint32 action, ObjectGuid guid) void BattlegroundIC::DoAction(uint32 action, ObjectGuid guid)
{ {
if (action != ACTION_TELEPORT_PLAYER_TO_TRANSPORT) if (action != ACTION_TELEPORT_PLAYER_TO_TRANSPORT)
@@ -246,7 +244,14 @@ void BattlegroundIC::PostUpdateImpl(uint32 diff)
UpdateNodeWorldState(&nodePoint[i]); UpdateNodeWorldState(&nodePoint[i]);
HandleCapturedNodes(&nodePoint[i], false); HandleCapturedNodes(&nodePoint[i], false);
SendMessage2ToAll(LANG_BG_IC_TEAM_HAS_TAKEN_NODE, CHAT_MSG_BG_SYSTEM_NEUTRAL, nullptr, (nodePoint[i].faction == TEAM_ALLIANCE ? LANG_BG_IC_ALLIANCE : LANG_BG_IC_HORDE), nodePoint[i].string); if (nodePoint[i].faction == TEAM_ALLIANCE)
{
SendBroadcastText(ICNodes[i].TextAllianceTaken, CHAT_MSG_BG_SYSTEM_ALLIANCE);
}
else
{
SendBroadcastText(ICNodes[i].TextHordeTaken, CHAT_MSG_BG_SYSTEM_HORDE);
}
nodePoint[i].needChange = false; nodePoint[i].needChange = false;
nodePoint[i].timer = BANNER_STATE_CHANGE_TIME; nodePoint[i].timer = BANNER_STATE_CHANGE_TIME;
@@ -272,10 +277,6 @@ void BattlegroundIC::PostUpdateImpl(uint32 diff)
else resourceTimer -= diff; else resourceTimer -= diff;
} }
void BattlegroundIC::StartingEventCloseDoors()
{
}
void BattlegroundIC::StartingEventOpenDoors() void BattlegroundIC::StartingEventOpenDoors()
{ {
//after 20 seconds they should be despawned //after 20 seconds they should be despawned
@@ -320,7 +321,7 @@ bool BattlegroundIC::IsResourceGlutAllowed(TeamId teamId) const
void BattlegroundIC::AddPlayer(Player* player) void BattlegroundIC::AddPlayer(Player* player)
{ {
Battleground::AddPlayer(player); Battleground::AddPlayer(player);
PlayerScores[player->GetGUID()] = new BattlegroundICScore(player); PlayerScores.emplace(player->GetGUID().GetCounter(), new BattlegroundICScore(player->GetGUID()));
if (nodePoint[NODE_TYPE_QUARRY].nodeState == (player->GetTeamId() == TEAM_ALLIANCE ? NODE_STATE_CONTROLLED_A : NODE_STATE_CONTROLLED_H)) if (nodePoint[NODE_TYPE_QUARRY].nodeState == (player->GetTeamId() == TEAM_ALLIANCE ? NODE_STATE_CONTROLLED_A : NODE_STATE_CONTROLLED_H))
player->CastSpell(player, SPELL_QUARRY, true); player->CastSpell(player, SPELL_QUARRY, true);
@@ -364,26 +365,22 @@ void BattlegroundIC::HandleAreaTrigger(Player* player, uint32 trigger)
} }
} }
void BattlegroundIC::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) bool BattlegroundIC::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
{ {
BattlegroundScoreMap::iterator itr = PlayerScores.find(player->GetGUID()); if (!Battleground::UpdatePlayerScore(player, type, value, doAddHonor))
if (itr == PlayerScores.end()) return false;
return;
switch (type) switch (type)
{ {
case SCORE_BASES_ASSAULTED: case SCORE_BASES_ASSAULTED:
((BattlegroundICScore*)itr->second)->BasesAssaulted += value;
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, IC_OBJECTIVE_ASSAULT_BASE); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, IC_OBJECTIVE_ASSAULT_BASE);
break; break;
case SCORE_BASES_DEFENDED: case SCORE_BASES_DEFENDED:
((BattlegroundICScore*)itr->second)->BasesDefended += value;
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, IC_OBJECTIVE_DEFEND_BASE); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, IC_OBJECTIVE_DEFEND_BASE);
break; break;
default:
Battleground::UpdatePlayerScore(player, type, value, doAddHonor);
break;
} }
return true;
} }
void BattlegroundIC::FillInitialWorldStates(WorldPacket& data) void BattlegroundIC::FillInitialWorldStates(WorldPacket& data)
@@ -553,12 +550,6 @@ void BattlegroundIC::HandleKillPlayer(Player* player, Player* killer)
EndBattleground(killer->GetTeamId()); EndBattleground(killer->GetTeamId());
} }
void BattlegroundIC::EndBattleground(TeamId winnerTeamId)
{
SendMessage2ToAll(LANG_BG_IC_TEAM_WINS, CHAT_MSG_BG_SYSTEM_NEUTRAL, nullptr, (winnerTeamId == TEAM_ALLIANCE ? LANG_BG_IC_ALLIANCE : LANG_BG_IC_HORDE));
Battleground::EndBattleground(winnerTeamId);
}
void BattlegroundIC::EventPlayerClickedOnFlag(Player* player, GameObject* gameObject) void BattlegroundIC::EventPlayerClickedOnFlag(Player* player, GameObject* gameObject)
{ {
if (GetStatus() != STATUS_IN_PROGRESS) if (GetStatus() != STATUS_IN_PROGRESS)
@@ -621,8 +612,15 @@ void BattlegroundIC::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb
UpdatePlayerScore(player, SCORE_BASES_ASSAULTED, 1); UpdatePlayerScore(player, SCORE_BASES_ASSAULTED, 1);
SendMessage2ToAll(LANG_BG_IC_TEAM_ASSAULTED_NODE_1, CHAT_MSG_BG_SYSTEM_NEUTRAL, player, point.string); if (nodePoint[i].faction == TEAM_ALLIANCE)
SendMessage2ToAll(LANG_BG_IC_TEAM_ASSAULTED_NODE_2, CHAT_MSG_BG_SYSTEM_NEUTRAL, player, point.string, (player->GetTeamId() == TEAM_ALLIANCE ? LANG_BG_IC_ALLIANCE : LANG_BG_IC_HORDE)); {
SendBroadcastText(ICNodes[i].TextAssaulted, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
}
else
{
SendBroadcastText(ICNodes[i].TextAssaulted, CHAT_MSG_BG_SYSTEM_HORDE, player);
}
HandleContestedNodes(&point); HandleContestedNodes(&point);
} }
else if (nextBanner == point.banners[BANNER_A_CONTROLLED] || nextBanner == point.banners[BANNER_H_CONTROLLED]) else if (nextBanner == point.banners[BANNER_A_CONTROLLED] || nextBanner == point.banners[BANNER_H_CONTROLLED])
@@ -630,7 +628,16 @@ void BattlegroundIC::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb
{ {
point.timer = BANNER_STATE_CHANGE_TIME; point.timer = BANNER_STATE_CHANGE_TIME;
point.needChange = false; point.needChange = false;
SendMessage2ToAll(LANG_BG_IC_TEAM_DEFENDED_NODE, CHAT_MSG_BG_SYSTEM_NEUTRAL, player, point.string);
if (nodePoint[i].faction == TEAM_ALLIANCE)
{
SendBroadcastText(ICNodes[i].TextDefended, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
}
else
{
SendBroadcastText(ICNodes[i].TextDefended, CHAT_MSG_BG_SYSTEM_HORDE, player);
}
HandleCapturedNodes(&point, true); HandleCapturedNodes(&point, true);
UpdatePlayerScore(player, SCORE_BASES_DEFENDED, 1); UpdatePlayerScore(player, SCORE_BASES_DEFENDED, 1);
} }
@@ -926,33 +933,41 @@ void BattlegroundIC::DestroyGate(Player* /*player*/, GameObject* go)
UpdateWorldState(uws_open, 1); UpdateWorldState(uws_open, 1);
} }
uint32 textId;
ChatMsg msgType;
TeamId teamId = TEAM_ALLIANCE; TeamId teamId = TEAM_ALLIANCE;
uint32 lang_entry = 0;
switch (go->GetEntry()) switch (go->GetEntry())
{ {
case GO_HORDE_GATE_1: case GO_HORDE_GATE_1:
lang_entry = LANG_BG_IC_NORTH_GATE_DESTROYED; textId = BG_IC_TEXT_FRONT_GATE_HORDE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_ALLIANCE;
break; break;
case GO_HORDE_GATE_2: case GO_HORDE_GATE_2:
lang_entry = LANG_BG_IC_EAST_GATE_DESTROYED; textId = BG_IC_TEXT_WEST_GATE_HORDE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_ALLIANCE;
break; break;
case GO_HORDE_GATE_3: case GO_HORDE_GATE_3:
lang_entry = LANG_BG_IC_WEST_GATE_DESTROYED; textId = BG_IC_TEXT_EAST_GATE_HORDE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_ALLIANCE;
break; break;
case GO_ALLIANCE_GATE_1: case GO_ALLIANCE_GATE_1:
textId = BG_IC_TEXT_WEST_GATE_ALLIANCE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_HORDE;
teamId = TEAM_HORDE; teamId = TEAM_HORDE;
lang_entry = LANG_BG_IC_WEST_GATE_DESTROYED;
break; break;
case GO_ALLIANCE_GATE_2: case GO_ALLIANCE_GATE_2:
textId = BG_IC_TEXT_EAST_GATE_ALLIANCE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_HORDE;
teamId = TEAM_HORDE; teamId = TEAM_HORDE;
lang_entry = LANG_BG_IC_EAST_GATE_DESTROYED;
break; break;
case GO_ALLIANCE_GATE_3: case GO_ALLIANCE_GATE_3:
textId = BG_IC_TEXT_FRONT_GATE_ALLIANCE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_HORDE;
teamId = TEAM_HORDE; teamId = TEAM_HORDE;
lang_entry = LANG_BG_IC_SOUTH_GATE_DESTROYED;
break; break;
default: default:
break; return;
} }
if (teamId == TEAM_ALLIANCE) if (teamId == TEAM_ALLIANCE)
@@ -967,11 +982,7 @@ void BattlegroundIC::DestroyGate(Player* /*player*/, GameObject* go)
} }
TurnBosses(true); TurnBosses(true);
SendMessage2ToAll(lang_entry, CHAT_MSG_BG_SYSTEM_NEUTRAL, nullptr, (teamId == TEAM_ALLIANCE ? LANG_BG_IC_HORDE_KEEP : LANG_BG_IC_ALLIANCE_KEEP)); SendBroadcastText(textId, msgType);
}
void BattlegroundIC::EventPlayerDamagedGO(Player* /*player*/, GameObject* /*go*/, uint32 /*eventType*/)
{
} }
GraveyardStruct const* BattlegroundIC::GetClosestGraveyard(Player* player) GraveyardStruct const* BattlegroundIC::GetClosestGraveyard(Player* player)
@@ -19,10 +19,10 @@
#define __BATTLEGROUNDIC_H #define __BATTLEGROUNDIC_H
#include "Battleground.h" #include "Battleground.h"
#include "Language.h" #include "BattlegroundScore.h"
#include "Object.h" #include "Object.h"
const uint32 BG_IC_Factions[BG_TEAMS_COUNT] = const uint32 BG_IC_Factions[PVP_TEAMS_COUNT] =
{ {
1732, // Alliance 1732, // Alliance
1735 // Horde 1735 // Horde
@@ -854,6 +854,36 @@ const float BG_IC_SpiritGuidePos[MAX_NODE_TYPES + 2][4] =
{1148.65f, -1250.98f, 16.60f, 1.74f}, // last resort horde {1148.65f, -1250.98f, 16.60f, 1.74f}, // last resort horde
}; };
enum ICBroadcastTexts
{
BG_IC_TEXT_FRONT_GATE_HORDE_DESTROYED = 35409,
BG_IC_TEXT_FRONT_GATE_ALLIANCE_DESTROYED = 35410,
BG_IC_TEXT_WEST_GATE_HORDE_DESTROYED = 35411,
BG_IC_TEXT_WEST_GATE_ALLIANCE_DESTROYED = 35412,
BG_IC_TEXT_EAST_GATE_HORDE_DESTROYED = 35413,
BG_IC_TEXT_EAST_GATE_ALLIANCE_DESTROYED = 35414
};
struct ICNodeInfo
{
uint32 NodeId;
uint32 TextAssaulted;
uint32 TextDefended;
uint32 TextAllianceTaken;
uint32 TextHordeTaken;
};
ICNodeInfo const ICNodes[MAX_NODE_TYPES] =
{
{ NODE_TYPE_REFINERY, 35377, 35378, 35379, 35380 },
{ NODE_TYPE_QUARRY, 35373, 35374, 35375, 35376 },
{ NODE_TYPE_DOCKS, 35365, 35366, 35367, 35368 },
{ NODE_TYPE_HANGAR, 35369, 35370, 35371, 35372 },
{ NODE_TYPE_WORKSHOP, 35278, 35286, 35279, 35280 },
{ NODE_TYPE_GRAVEYARD_A, 35461, 35459, 35463, 35466 },
{ NODE_TYPE_GRAVEYARD_H, 35462, 35460, 35464, 35465 }
};
// I.E: Hangar, Quarry, Graveyards .. etc // I.E: Hangar, Quarry, Graveyards .. etc
struct ICNodePoint struct ICNodePoint
{ {
@@ -867,18 +897,17 @@ struct ICNodePoint
uint32 last_entry; // the last gameobject_entry uint32 last_entry; // the last gameobject_entry
uint32 worldStates[5]; // the worldstates that represent the node in the map uint32 worldStates[5]; // the worldstates that represent the node in the map
ICNodeState nodeState; ICNodeState nodeState;
uint32 string;
}; };
const ICNodePoint nodePointInitial[7] = const ICNodePoint nodePointInitial[MAX_NODE_TYPES] =
{ {
{BG_IC_GO_REFINERY_BANNER, GO_REFINERY_BANNER, TEAM_NEUTRAL, NODE_TYPE_REFINERY, {GO_ALLIANCE_BANNER_REFINERY, GO_ALLIANCE_BANNER_REFINERY_CONT, GO_HORDE_BANNER_REFINERY, GO_HORDE_BANNER_REFINERY_CONT}, false, 0, 0, {BG_IC_REFINERY_UNCONTROLLED, BG_IC_REFINERY_CONFLICT_A, BG_IC_REFINERY_CONFLICT_H, BG_IC_REFINERY_CONTROLLED_A, BG_IC_REFINERY_CONTROLLED_H}, NODE_STATE_UNCONTROLLED, LANG_BG_IC_REFINERY}, {BG_IC_GO_REFINERY_BANNER, GO_REFINERY_BANNER, TEAM_NEUTRAL, NODE_TYPE_REFINERY, {GO_ALLIANCE_BANNER_REFINERY, GO_ALLIANCE_BANNER_REFINERY_CONT, GO_HORDE_BANNER_REFINERY, GO_HORDE_BANNER_REFINERY_CONT}, false, 0, 0, {BG_IC_REFINERY_UNCONTROLLED, BG_IC_REFINERY_CONFLICT_A, BG_IC_REFINERY_CONFLICT_H, BG_IC_REFINERY_CONTROLLED_A, BG_IC_REFINERY_CONTROLLED_H}, NODE_STATE_UNCONTROLLED},
{BG_IC_GO_QUARRY_BANNER, GO_QUARRY_BANNER, TEAM_NEUTRAL, NODE_TYPE_QUARRY, {GO_ALLIANCE_BANNER_QUARRY, GO_ALLIANCE_BANNER_QUARRY_CONT, GO_HORDE_BANNER_QUARRY, GO_HORDE_BANNER_QUARRY_CONT}, false, 0, 0, {BG_IC_QUARRY_UNCONTROLLED, BG_IC_QUARRY_CONFLICT_A, BG_IC_QUARRY_CONFLICT_H, BG_IC_QUARRY_CONTROLLED_A, BG_IC_QUARRY_CONTROLLED_H}, NODE_STATE_UNCONTROLLED, LANG_BG_IC_QUARRY}, {BG_IC_GO_QUARRY_BANNER, GO_QUARRY_BANNER, TEAM_NEUTRAL, NODE_TYPE_QUARRY, {GO_ALLIANCE_BANNER_QUARRY, GO_ALLIANCE_BANNER_QUARRY_CONT, GO_HORDE_BANNER_QUARRY, GO_HORDE_BANNER_QUARRY_CONT}, false, 0, 0, {BG_IC_QUARRY_UNCONTROLLED, BG_IC_QUARRY_CONFLICT_A, BG_IC_QUARRY_CONFLICT_H, BG_IC_QUARRY_CONTROLLED_A, BG_IC_QUARRY_CONTROLLED_H}, NODE_STATE_UNCONTROLLED},
{BG_IC_GO_DOCKS_BANNER, GO_DOCKS_BANNER, TEAM_NEUTRAL, NODE_TYPE_DOCKS, {GO_ALLIANCE_BANNER_DOCK, GO_ALLIANCE_BANNER_DOCK_CONT, GO_HORDE_BANNER_DOCK, GO_HORDE_BANNER_DOCK_CONT}, false, 0, 0, {BG_IC_DOCKS_UNCONTROLLED, BG_IC_DOCKS_CONFLICT_A, BG_IC_DOCKS_CONFLICT_H, BG_IC_DOCKS_CONTROLLED_A, BG_IC_DOCKS_CONTROLLED_H}, NODE_STATE_UNCONTROLLED, LANG_BG_IC_DOCKS}, {BG_IC_GO_DOCKS_BANNER, GO_DOCKS_BANNER, TEAM_NEUTRAL, NODE_TYPE_DOCKS, {GO_ALLIANCE_BANNER_DOCK, GO_ALLIANCE_BANNER_DOCK_CONT, GO_HORDE_BANNER_DOCK, GO_HORDE_BANNER_DOCK_CONT}, false, 0, 0, {BG_IC_DOCKS_UNCONTROLLED, BG_IC_DOCKS_CONFLICT_A, BG_IC_DOCKS_CONFLICT_H, BG_IC_DOCKS_CONTROLLED_A, BG_IC_DOCKS_CONTROLLED_H}, NODE_STATE_UNCONTROLLED},
{BG_IC_GO_HANGAR_BANNER, GO_HANGAR_BANNER, TEAM_NEUTRAL, NODE_TYPE_HANGAR, {GO_ALLIANCE_BANNER_HANGAR, GO_ALLIANCE_BANNER_HANGAR_CONT, GO_HORDE_BANNER_HANGAR, GO_HORDE_BANNER_HANGAR_CONT}, false, 0, 0, {BG_IC_HANGAR_UNCONTROLLED, BG_IC_HANGAR_CONFLICT_A, BG_IC_HANGAR_CONFLICT_H, BG_IC_HANGAR_CONTROLLED_A, BG_IC_HANGAR_CONTROLLED_H}, NODE_STATE_UNCONTROLLED, LANG_BG_IC_HANGAR}, {BG_IC_GO_HANGAR_BANNER, GO_HANGAR_BANNER, TEAM_NEUTRAL, NODE_TYPE_HANGAR, {GO_ALLIANCE_BANNER_HANGAR, GO_ALLIANCE_BANNER_HANGAR_CONT, GO_HORDE_BANNER_HANGAR, GO_HORDE_BANNER_HANGAR_CONT}, false, 0, 0, {BG_IC_HANGAR_UNCONTROLLED, BG_IC_HANGAR_CONFLICT_A, BG_IC_HANGAR_CONFLICT_H, BG_IC_HANGAR_CONTROLLED_A, BG_IC_HANGAR_CONTROLLED_H}, NODE_STATE_UNCONTROLLED},
{BG_IC_GO_WORKSHOP_BANNER, GO_WORKSHOP_BANNER, TEAM_NEUTRAL, NODE_TYPE_WORKSHOP, {GO_ALLIANCE_BANNER_WORKSHOP, GO_ALLIANCE_BANNER_WORKSHOP_CONT, GO_HORDE_BANNER_WORKSHOP, GO_HORDE_BANNER_WORKSHOP_CONT}, false, 0, 0, {BG_IC_WORKSHOP_UNCONTROLLED, BG_IC_WORKSHOP_CONFLICT_A, BG_IC_WORKSHOP_CONFLICT_H, BG_IC_WORKSHOP_CONTROLLED_A, BG_IC_WORKSHOP_CONTROLLED_H}, NODE_STATE_UNCONTROLLED, LANG_BG_IC_WORKSHOP}, {BG_IC_GO_WORKSHOP_BANNER, GO_WORKSHOP_BANNER, TEAM_NEUTRAL, NODE_TYPE_WORKSHOP, {GO_ALLIANCE_BANNER_WORKSHOP, GO_ALLIANCE_BANNER_WORKSHOP_CONT, GO_HORDE_BANNER_WORKSHOP, GO_HORDE_BANNER_WORKSHOP_CONT}, false, 0, 0, {BG_IC_WORKSHOP_UNCONTROLLED, BG_IC_WORKSHOP_CONFLICT_A, BG_IC_WORKSHOP_CONFLICT_H, BG_IC_WORKSHOP_CONTROLLED_A, BG_IC_WORKSHOP_CONTROLLED_H}, NODE_STATE_UNCONTROLLED},
{BG_IC_GO_ALLIANCE_BANNER, GO_ALLIANCE_BANNER, TEAM_ALLIANCE, NODE_TYPE_GRAVEYARD_A, {GO_ALLIANCE_BANNER_GRAVEYARD_A, GO_ALLIANCE_BANNER_GRAVEYARD_A_CONT, GO_HORDE_BANNER_GRAVEYARD_A, GO_HORDE_BANNER_GRAVEYARD_A_CONT}, false, 0, 0, {BG_IC_ALLIANCE_KEEP_UNCONTROLLED, BG_IC_ALLIANCE_KEEP_CONFLICT_A, BG_IC_ALLIANCE_KEEP_CONFLICT_H, BG_IC_ALLIANCE_KEEP_CONTROLLED_A, BG_IC_ALLIANCE_KEEP_CONTROLLED_H}, NODE_STATE_CONTROLLED_A, LANG_BG_IC_ALLIANCE_KEEP}, {BG_IC_GO_ALLIANCE_BANNER, GO_ALLIANCE_BANNER, TEAM_ALLIANCE, NODE_TYPE_GRAVEYARD_A, {GO_ALLIANCE_BANNER_GRAVEYARD_A, GO_ALLIANCE_BANNER_GRAVEYARD_A_CONT, GO_HORDE_BANNER_GRAVEYARD_A, GO_HORDE_BANNER_GRAVEYARD_A_CONT}, false, 0, 0, {BG_IC_ALLIANCE_KEEP_UNCONTROLLED, BG_IC_ALLIANCE_KEEP_CONFLICT_A, BG_IC_ALLIANCE_KEEP_CONFLICT_H, BG_IC_ALLIANCE_KEEP_CONTROLLED_A, BG_IC_ALLIANCE_KEEP_CONTROLLED_H}, NODE_STATE_CONTROLLED_A},
{BG_IC_GO_HORDE_BANNER, GO_HORDE_BANNER, TEAM_HORDE, NODE_TYPE_GRAVEYARD_H, {GO_ALLIANCE_BANNER_GRAVEYARD_H, GO_ALLIANCE_BANNER_GRAVEYARD_H_CONT, GO_HORDE_BANNER_GRAVEYARD_H, GO_HORDE_BANNER_GRAVEYARD_H_CONT}, false, 0, 0, {BG_IC_HORDE_KEEP_UNCONTROLLED, BG_IC_HORDE_KEEP_CONFLICT_A, BG_IC_HORDE_KEEP_CONFLICT_H, BG_IC_HORDE_KEEP_CONTROLLED_A, BG_IC_HORDE_KEEP_CONTROLLED_H}, NODE_STATE_CONTROLLED_H, LANG_BG_IC_HORDE_KEEP} {BG_IC_GO_HORDE_BANNER, GO_HORDE_BANNER, TEAM_HORDE, NODE_TYPE_GRAVEYARD_H, {GO_ALLIANCE_BANNER_GRAVEYARD_H, GO_ALLIANCE_BANNER_GRAVEYARD_H_CONT, GO_HORDE_BANNER_GRAVEYARD_H, GO_HORDE_BANNER_GRAVEYARD_H_CONT}, false, 0, 0, {BG_IC_HORDE_KEEP_UNCONTROLLED, BG_IC_HORDE_KEEP_CONFLICT_A, BG_IC_HORDE_KEEP_CONFLICT_H, BG_IC_HORDE_KEEP_CONTROLLED_A, BG_IC_HORDE_KEEP_CONTROLLED_H}, NODE_STATE_CONTROLLED_H}
}; };
enum HonorRewards enum HonorRewards
@@ -887,45 +916,63 @@ enum HonorRewards
WINNER_HONOR_AMOUNT = 500 WINNER_HONOR_AMOUNT = 500
}; };
struct BattlegroundICScore : public BattlegroundScore struct BattlegroundICScore final : public BattlegroundScore
{ {
BattlegroundICScore(Player* player) : BattlegroundScore(player), BasesAssaulted(0), BasesDefended(0) { } friend class BattlegroundIC;
~BattlegroundICScore() override { }
uint32 BasesAssaulted;
uint32 BasesDefended;
uint32 GetAttr1() const final { return BasesAssaulted; } protected:
uint32 GetAttr2() const final { return BasesDefended; } BattlegroundICScore(ObjectGuid playerGuid) : BattlegroundScore(playerGuid) { }
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 override;
uint32 GetAttr1() const final override { return BasesAssaulted; }
uint32 GetAttr2() const final override { return BasesDefended; }
uint32 BasesAssaulted = 0;
uint32 BasesDefended = 0;
}; };
class BattlegroundIC : public Battleground class AC_GAME_API BattlegroundIC : public Battleground
{ {
public: public:
BattlegroundIC(); BattlegroundIC();
~BattlegroundIC() override;
/* inherited from BattlegroundClass */ /* inherited from BattlegroundClass */
void AddPlayer(Player* player) override; void AddPlayer(Player* player) override;
void StartingEventCloseDoors() override; void StartingEventCloseDoors() override { }
void StartingEventOpenDoors() override; void StartingEventOpenDoors() override;
void PostUpdateImpl(uint32 diff) override; void PostUpdateImpl(uint32 diff) override;
void RemovePlayer(Player* player) override; void RemovePlayer(Player* player) override;
void HandleAreaTrigger(Player* player, uint32 trigger) override; void HandleAreaTrigger(Player* player, uint32 trigger) override;
bool SetupBattleground() override; bool SetupBattleground() override;
void SpawnLeader(uint32 teamid);
void HandleKillUnit(Creature* unit, Player* killer) override; void HandleKillUnit(Creature* unit, Player* killer) override;
void HandleKillPlayer(Player* player, Player* killer) override; void HandleKillPlayer(Player* player, Player* killer) override;
void EndBattleground(TeamId winnerTeamId) override;
void EventPlayerClickedOnFlag(Player* source, GameObject* /*gameObject*/) override; void EventPlayerClickedOnFlag(Player* source, GameObject* /*gameObject*/) override;
void EventPlayerDamagedGO(Player* /*player*/, GameObject* go, uint32 eventType) override; void EventPlayerDamagedGO(Player* /*player*/, GameObject* /*go*/, uint32 /*eventType*/) override { }
void DestroyGate(Player* player, GameObject* go) override; void DestroyGate(Player* player, GameObject* go) override;
GraveyardStruct const* GetClosestGraveyard(Player* player) override; GraveyardStruct const* GetClosestGraveyard(Player* player) override;
/* Scorekeeping */ /* Scorekeeping */
void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override; bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
void FillInitialWorldStates(WorldPacket& data) override; void FillInitialWorldStates(WorldPacket& data) override;
@@ -16,28 +16,12 @@
*/ */
#include "BattlegroundNA.h" #include "BattlegroundNA.h"
#include "Language.h"
#include "ObjectMgr.h"
#include "Player.h" #include "Player.h"
#include "WorldPacket.h" #include "WorldPacket.h"
BattlegroundNA::BattlegroundNA() BattlegroundNA::BattlegroundNA()
{ {
BgObjects.resize(BG_NA_OBJECT_MAX); BgObjects.resize(BG_NA_OBJECT_MAX);
StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
//we must set messageIds
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
}
BattlegroundNA::~BattlegroundNA()
{
} }
void BattlegroundNA::StartingEventCloseDoors() void BattlegroundNA::StartingEventCloseDoors()
@@ -55,39 +39,6 @@ void BattlegroundNA::StartingEventOpenDoors()
SpawnBGObject(i, 60); SpawnBGObject(i, 60);
} }
void BattlegroundNA::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
PlayerScores[player->GetGUID()] = new BattlegroundScore(player);
Battleground::UpdateArenaWorldState();
}
void BattlegroundNA::RemovePlayer(Player* /*player*/)
{
if (GetStatus() == STATUS_WAIT_LEAVE)
return;
Battleground::UpdateArenaWorldState();
CheckArenaWinConditions();
}
void BattlegroundNA::HandleKillPlayer(Player* player, Player* killer)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
if (!killer)
{
LOG_ERROR("bg.battleground", "BattlegroundNA: Killer player not found");
return;
}
Battleground::HandleKillPlayer(player, killer);
Battleground::UpdateArenaWorldState();
CheckArenaWinConditions();
}
bool BattlegroundNA::HandlePlayerUnderMap(Player* player) bool BattlegroundNA::HandlePlayerUnderMap(Player* player)
{ {
player->NearTeleportTo(4055.504395f, 2919.660645f, 13.611241f, player->GetOrientation()); player->NearTeleportTo(4055.504395f, 2919.660645f, 13.611241f, player->GetOrientation());
@@ -116,13 +67,7 @@ void BattlegroundNA::HandleAreaTrigger(Player* player, uint32 trigger)
void BattlegroundNA::FillInitialWorldStates(WorldPacket& data) void BattlegroundNA::FillInitialWorldStates(WorldPacket& data)
{ {
data << uint32(0xa11) << uint32(1); // 9 data << uint32(0xa11) << uint32(1); // 9
Battleground::UpdateArenaWorldState(); Arena::FillInitialWorldStates(data);
}
void BattlegroundNA::Init()
{
//call parent's class reset
Battleground::Init();
} }
bool BattlegroundNA::SetupBattleground() bool BattlegroundNA::SetupBattleground()
@@ -18,7 +18,7 @@
#ifndef __BATTLEGROUNDNA_H #ifndef __BATTLEGROUNDNA_H
#define __BATTLEGROUNDNA_H #define __BATTLEGROUNDNA_H
#include "Battleground.h" #include "Arena.h"
enum BattlegroundNAObjectTypes enum BattlegroundNAObjectTypes
{ {
@@ -33,7 +33,7 @@ enum BattlegroundNAObjectTypes
BG_NA_OBJECT_MAX = 8 BG_NA_OBJECT_MAX = 8
}; };
enum BattlegroundNAObjects enum BattlegroundNAGameObjects
{ {
BG_NA_OBJECT_TYPE_DOOR_1 = 183978, BG_NA_OBJECT_TYPE_DOOR_1 = 183978,
BG_NA_OBJECT_TYPE_DOOR_2 = 183980, BG_NA_OBJECT_TYPE_DOOR_2 = 183980,
@@ -43,23 +43,19 @@ enum BattlegroundNAObjects
BG_NA_OBJECT_TYPE_BUFF_2 = 184664 BG_NA_OBJECT_TYPE_BUFF_2 = 184664
}; };
class BattlegroundNA : public Battleground class AC_GAME_API BattlegroundNA : public Arena
{ {
public: public:
BattlegroundNA(); BattlegroundNA();
~BattlegroundNA() override;
/* inherited from BattlegroundClass */ /* inherited from BattlegroundClass */
void AddPlayer(Player* player) override;
void StartingEventCloseDoors() override; void StartingEventCloseDoors() override;
void StartingEventOpenDoors() override; void StartingEventOpenDoors() override;
void RemovePlayer(Player* player) override;
void HandleAreaTrigger(Player* player, uint32 trigger) override; void HandleAreaTrigger(Player* player, uint32 trigger) override;
bool SetupBattleground() override; bool SetupBattleground() override;
void Init() override;
void FillInitialWorldStates(WorldPacket& d) override; void FillInitialWorldStates(WorldPacket& d) override;
void HandleKillPlayer(Player* player, Player* killer) override;
bool HandlePlayerUnderMap(Player* player) override; bool HandlePlayerUnderMap(Player* player) override;
}; };
#endif #endif
@@ -16,6 +16,7 @@
*/ */
#include "BattlegroundRL.h" #include "BattlegroundRL.h"
#include "ArenaScore.h"
#include "Language.h" #include "Language.h"
#include "Log.h" #include "Log.h"
#include "Player.h" #include "Player.h"
@@ -24,20 +25,6 @@
BattlegroundRL::BattlegroundRL() BattlegroundRL::BattlegroundRL()
{ {
BgObjects.resize(BG_RL_OBJECT_MAX); BgObjects.resize(BG_RL_OBJECT_MAX);
StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
//we must set messageIds
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
}
BattlegroundRL::~BattlegroundRL()
{
} }
void BattlegroundRL::StartingEventCloseDoors() void BattlegroundRL::StartingEventCloseDoors()
@@ -55,39 +42,6 @@ void BattlegroundRL::StartingEventOpenDoors()
SpawnBGObject(i, 60); SpawnBGObject(i, 60);
} }
void BattlegroundRL::AddPlayer(Player* player)
{
Battleground::AddPlayer(player);
PlayerScores[player->GetGUID()] = new BattlegroundScore(player);
Battleground::UpdateArenaWorldState();
}
void BattlegroundRL::RemovePlayer(Player* /*player*/)
{
if (GetStatus() == STATUS_WAIT_LEAVE)
return;
UpdateArenaWorldState();
CheckArenaWinConditions();
}
void BattlegroundRL::HandleKillPlayer(Player* player, Player* killer)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
if (!killer)
{
LOG_ERROR("bg.battleground", "Killer player not found");
return;
}
Battleground::HandleKillPlayer(player, killer);
Battleground::UpdateArenaWorldState();
CheckArenaWinConditions();
}
bool BattlegroundRL::HandlePlayerUnderMap(Player* player) bool BattlegroundRL::HandlePlayerUnderMap(Player* player)
{ {
player->NearTeleportTo(1285.810547f, 1667.896851f, 39.957642f, player->GetOrientation()); player->NearTeleportTo(1285.810547f, 1667.896851f, 39.957642f, player->GetOrientation());
@@ -142,13 +96,7 @@ void BattlegroundRL::HandleAreaTrigger(Player* player, uint32 trigger)
void BattlegroundRL::FillInitialWorldStates(WorldPacket& data) void BattlegroundRL::FillInitialWorldStates(WorldPacket& data)
{ {
data << uint32(0xbba) << uint32(1); // 9 data << uint32(0xbba) << uint32(1); // 9
Battleground::UpdateArenaWorldState(); Arena::FillInitialWorldStates(data);
}
void BattlegroundRL::Init()
{
//call parent's reset
Battleground::Init();
} }
bool BattlegroundRL::SetupBattleground() bool BattlegroundRL::SetupBattleground()
@@ -18,7 +18,7 @@
#ifndef __BATTLEGROUNDRL_H #ifndef __BATTLEGROUNDRL_H
#define __BATTLEGROUNDRL_H #define __BATTLEGROUNDRL_H
#include "Battleground.h" #include "Arena.h"
enum BattlegroundRLObjectTypes enum BattlegroundRLObjectTypes
{ {
@@ -39,23 +39,19 @@ enum BattlegroundRLObjects
BG_RL_OBJECT_TYPE_BUFF_2 = 184664 BG_RL_OBJECT_TYPE_BUFF_2 = 184664
}; };
class BattlegroundRL : public Battleground class AC_GAME_API BattlegroundRL : public Arena
{ {
public: public:
BattlegroundRL(); BattlegroundRL();
~BattlegroundRL() override;
/* inherited from BattlegroundClass */ /* inherited from BattlegroundClass */
void AddPlayer(Player* player) override;
void Init() override;
void FillInitialWorldStates(WorldPacket& d) override; void FillInitialWorldStates(WorldPacket& d) override;
void StartingEventCloseDoors() override; void StartingEventCloseDoors() override;
void StartingEventOpenDoors() override; void StartingEventOpenDoors() override;
void RemovePlayer(Player* player) override;
void HandleAreaTrigger(Player* player, uint32 trigger) override; void HandleAreaTrigger(Player* player, uint32 trigger) override;
bool SetupBattleground() override; bool SetupBattleground() override;
void HandleKillPlayer(Player* player, Player* killer) override;
bool HandlePlayerUnderMap(Player* player) override; bool HandlePlayerUnderMap(Player* player) override;
}; };
#endif #endif
@@ -16,6 +16,7 @@
*/ */
#include "BattlegroundRV.h" #include "BattlegroundRV.h"
#include "ArenaScore.h"
#include "Battleground.h" #include "Battleground.h"
#include "GameObject.h" #include "GameObject.h"
#include "Language.h" #include "Language.h"
@@ -35,24 +36,16 @@ BattlegroundRV::BattlegroundRV()
{ {
BgObjects.resize(BG_RV_OBJECT_MAX); BgObjects.resize(BG_RV_OBJECT_MAX);
StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; _checkPlayersTimer = 0;
StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; _timer = 0s;
StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; _state = 0;
StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
CheckPlayersTimer = 0;
} }
BattlegroundRV::~BattlegroundRV() { }
void BattlegroundRV::TeleportUnitToNewZ(Unit* unit, float newZ, bool casting) void BattlegroundRV::TeleportUnitToNewZ(Unit* unit, float newZ, bool casting)
{ {
if (!unit->IsAlive()) if (!unit->IsAlive())
return; return;
unit->NearTeleportTo(unit->GetPositionX(), unit->GetPositionY(), newZ, unit->GetOrientation(), casting); unit->NearTeleportTo(unit->GetPositionX(), unit->GetPositionY(), newZ, unit->GetOrientation(), casting);
unit->m_positionZ = newZ; unit->m_positionZ = newZ;
} }
@@ -64,6 +57,7 @@ void BattlegroundRV::CheckPositionForUnit(Unit* unit)
{ {
float groundZ_vmap = unit->GetMap()->GetHeight(unit->GetPositionX(), unit->GetPositionY(), 37.0f, true, 50.0f); float groundZ_vmap = unit->GetMap()->GetHeight(unit->GetPositionX(), unit->GetPositionY(), 37.0f, true, 50.0f);
float groundZ_dyntree = unit->GetMap()->GetDynamicMapTree().getHeight(unit->GetPositionX(), unit->GetPositionY(), 37.0f, 50.0f, unit->GetPhaseMask()); float groundZ_dyntree = unit->GetMap()->GetDynamicMapTree().getHeight(unit->GetPositionX(), unit->GetPositionY(), 37.0f, 50.0f, unit->GetPhaseMask());
if ((groundZ_vmap > 28.0f && groundZ_vmap < 29.0f) || (groundZ_dyntree > 28.0f && groundZ_dyntree < 37.0f)) if ((groundZ_vmap > 28.0f && groundZ_vmap < 29.0f) || (groundZ_dyntree > 28.0f && groundZ_dyntree < 37.0f))
{ {
float groundZ = std::max<float>(groundZ_vmap, groundZ_dyntree); float groundZ = std::max<float>(groundZ_vmap, groundZ_dyntree);
@@ -78,97 +72,99 @@ void BattlegroundRV::PostUpdateImpl(uint32 diff)
if (GetStatus() != STATUS_IN_PROGRESS) if (GetStatus() != STATUS_IN_PROGRESS)
return; return;
if (GetTimer() < Milliseconds(diff)) if (_timer < Milliseconds(diff))
{ {
switch (getState()) switch (_state)
{ {
case BG_RV_STATE_OPEN_FENCES: case BG_RV_STATE_OPEN_FENCES:
{
for (uint8 i = BG_RV_OBJECT_FIRE_1; i <= BG_RV_OBJECT_FIREDOOR_2; ++i) for (uint8 i = BG_RV_OBJECT_FIRE_1; i <= BG_RV_OBJECT_FIREDOOR_2; ++i)
DoorOpen(i); DoorOpen(i);
SetTimer(BG_RV_CLOSE_FIRE_TIMER);
setState(BG_RV_STATE_CLOSE_FIRE);
for (auto itr = m_Players.begin(); itr != m_Players.end(); ++itr) _timer = BG_RV_CLOSE_FIRE_TIMER;
if (Player* player = itr->second) _state = BG_RV_STATE_CLOSE_FIRE;
for (auto const& [playerGuid, player] : m_Players)
{
if (!player)
continue;
// Demonic Circle Summon
if (GameObject* gObj = player->GetGameObject(48018))
{ {
// Demonic Circle Summon gObj->Relocate(gObj->GetPositionX(), gObj->GetPositionY(), 28.28f);
if (GameObject* gObj = player->GetGameObject(48018)) gObj->UpdateObjectVisibility(true);
{
gObj->Relocate(gObj->GetPositionX(), gObj->GetPositionY(), 28.28f);
gObj->UpdateObjectVisibility(true);
}
if (player->GetPositionZ() < 27.0f)
TeleportUnitToNewZ(player, 28.28f, true);
for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
if (player->m_SummonSlot[i])
if (Creature* totem = GetBgMap()->GetCreature(player->m_SummonSlot[i]))
if (totem->GetPositionZ() < 28.0f)
TeleportUnitToNewZ(totem, 28.28f, true);
for (auto itr2 = player->m_Controlled.begin(); itr2 != player->m_Controlled.end(); ++itr2)
{
if ((*itr2)->GetPositionZ() < 28.0f)
TeleportUnitToNewZ((*itr2), 28.28f, true);
// Xinef: override stay position
if (CharmInfo* charmInfo = (*itr2)->GetCharmInfo())
if (charmInfo->IsAtStay())
{
(*itr2)->StopMovingOnCurrentPos();
charmInfo->SaveStayPosition(false);
}
}
} }
if (player->GetPositionZ() < 27.0f)
TeleportUnitToNewZ(player, 28.28f, true);
for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
if (player->m_SummonSlot[i])
if (Creature* totem = GetBgMap()->GetCreature(player->m_SummonSlot[i]))
if (totem->GetPositionZ() < 28.0f)
TeleportUnitToNewZ(totem, 28.28f, true);
for (auto itr2 = player->m_Controlled.begin(); itr2 != player->m_Controlled.end(); ++itr2)
{
if ((*itr2)->GetPositionZ() < 28.0f)
TeleportUnitToNewZ((*itr2), 28.28f, true);
// Xinef: override stay position
if (CharmInfo* charmInfo = (*itr2)->GetCharmInfo())
if (charmInfo->IsAtStay())
{
(*itr2)->StopMovingOnCurrentPos();
charmInfo->SaveStayPosition(false);
}
}
}
// fix ground on elevators (so aoe spells can be casted there) // fix ground on elevators (so aoe spells can be casted there)
{ {
uint32 objects[2] = {BG_RV_OBJECT_ELEVATOR_1, BG_RV_OBJECT_ELEVATOR_2}; uint32 objects[2] = { BG_RV_OBJECT_ELEVATOR_1, BG_RV_OBJECT_ELEVATOR_2 };
for (uint8 i = 0; i < 2; ++i) for (uint8 i = 0; i < 2; ++i)
if (GameObject* go = GetBGObject(objects[i])) if (GameObject* go = GetBGObject(objects[i]))
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_TRANSPORT); go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_TRANSPORT);
} }
break; break;
}
case BG_RV_STATE_CLOSE_FIRE: case BG_RV_STATE_CLOSE_FIRE:
for (uint8 i = BG_RV_OBJECT_FIRE_1; i <= BG_RV_OBJECT_FIREDOOR_2; ++i) for (uint8 i = BG_RV_OBJECT_FIRE_1; i <= BG_RV_OBJECT_FIREDOOR_2; ++i)
DoorClose(i); DoorClose(i);
// Fire got closed after five seconds, leaves twenty seconds before toggling pillars // Fire got closed after five seconds, leaves twenty seconds before toggling pillars
SetTimer(BG_RV_FIRE_TO_PILLAR_TIMER); _timer = BG_RV_FIRE_TO_PILLAR_TIMER;
setState(BG_RV_STATE_SWITCH_PILLARS); _state = BG_RV_STATE_SWITCH_PILLARS;
break; break;
case BG_RV_STATE_SWITCH_PILLARS: case BG_RV_STATE_SWITCH_PILLARS:
UpdatePillars(); UpdatePillars();
SetTimer(BG_RV_PILLAR_SWITCH_TIMER); _timer = BG_RV_PILLAR_SWITCH_TIMER;
break; break;
} }
} }
else else
SetTimer(GetTimer() - Milliseconds(diff)); _timer -= Milliseconds(diff);
if (getState() == BG_RV_STATE_OPEN_FENCES) if (_state == BG_RV_STATE_OPEN_FENCES)
return; return;
if (CheckPlayersTimer <= diff) if (_checkPlayersTimer <= diff)
{ {
CheckPlayersTimer = 0; _checkPlayersTimer = 0;
for (BattlegroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
CheckPositionForUnit(itr->second); for (auto const& itr : m_Players)
CheckPositionForUnit(itr.second);
// maybe for pets and m_Controlled also, but not really necessary // maybe for pets and m_Controlled also, but not really necessary
} }
else else
CheckPlayersTimer -= diff; _checkPlayersTimer -= diff;
}
void BattlegroundRV::StartingEventCloseDoors()
{
} }
void BattlegroundRV::StartingEventOpenDoors() void BattlegroundRV::StartingEventOpenDoors()
{ {
for (BattlegroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) for (auto const& itr : m_Players)
itr->second->SetPhaseMask(1, true); itr.second->SetPhaseMask(1, true);
// Buff respawn // Buff respawn
SpawnBGObject(BG_RV_OBJECT_BUFF_1, 90); SpawnBGObject(BG_RV_OBJECT_BUFF_1, 90);
@@ -178,44 +174,8 @@ void BattlegroundRV::StartingEventOpenDoors()
DoorOpen(BG_RV_OBJECT_ELEVATOR_1); DoorOpen(BG_RV_OBJECT_ELEVATOR_1);
DoorOpen(BG_RV_OBJECT_ELEVATOR_2); DoorOpen(BG_RV_OBJECT_ELEVATOR_2);
setState(BG_RV_STATE_OPEN_FENCES); _state = BG_RV_STATE_OPEN_FENCES;
SetTimer(BG_RV_FIRST_TIMER); _timer = BG_RV_FIRST_TIMER;
}
void BattlegroundRV::AddPlayer(Player* player)
{
if (GetStatus() == STATUS_WAIT_JOIN && player->GetBgTeamId() == TEAM_HORDE)
player->SetPhaseMask(2, true);
Battleground::AddPlayer(player);
PlayerScores[player->GetGUID()] = new BattlegroundScore(player);
BattlegroundRV::UpdateArenaWorldState();
}
void BattlegroundRV::RemovePlayer(Player* player)
{
if (GetStatus() == STATUS_WAIT_LEAVE)
return;
if (GetStatus() == STATUS_WAIT_JOIN)
player->SetPhaseMask(1, true);
BattlegroundRV::UpdateArenaWorldState();
CheckArenaWinConditions();
}
void BattlegroundRV::HandleKillPlayer(Player* player, Player* killer)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
if (!killer)
return;
Battleground::HandleKillPlayer(player, killer);
BattlegroundRV::UpdateArenaWorldState();
CheckArenaWinConditions();
} }
bool BattlegroundRV::HandlePlayerUnderMap(Player* player) bool BattlegroundRV::HandlePlayerUnderMap(Player* player)
@@ -226,7 +186,7 @@ bool BattlegroundRV::HandlePlayerUnderMap(Player* player)
void BattlegroundRV::HandleAreaTrigger(Player* player, uint32 trigger) void BattlegroundRV::HandleAreaTrigger(Player* player, uint32 trigger)
{ {
if (GetStatus() != STATUS_IN_PROGRESS || getState() == BG_RV_STATE_OPEN_FENCES /*during elevator rising it's possible to jump and cause areatrigger*/) if (GetStatus() != STATUS_IN_PROGRESS || _state == BG_RV_STATE_OPEN_FENCES /*during elevator rising it's possible to jump and cause areatrigger*/)
return; return;
switch (trigger) switch (trigger)
@@ -251,13 +211,7 @@ void BattlegroundRV::HandleAreaTrigger(Player* player, uint32 trigger)
void BattlegroundRV::FillInitialWorldStates(WorldPacket& data) void BattlegroundRV::FillInitialWorldStates(WorldPacket& data)
{ {
data << uint32(BG_RV_WORLD_STATE) << uint32(1); data << uint32(BG_RV_WORLD_STATE) << uint32(1);
BattlegroundRV::UpdateArenaWorldState(); Arena::FillInitialWorldStates(data);
}
void BattlegroundRV::UpdateArenaWorldState()
{
UpdateWorldState(BG_RV_WORLD_STATE_A, GetAlivePlayersCountByTeam(TEAM_ALLIANCE));
UpdateWorldState(BG_RV_WORLD_STATE_H, GetAlivePlayersCountByTeam(TEAM_HORDE));
} }
void BattlegroundRV::Init() void BattlegroundRV::Init()
@@ -352,5 +306,6 @@ GameObject* BattlegroundRV::GetPillarAtPosition(Position* p)
uint32 pillar = GetPillarIdForPos(p); uint32 pillar = GetPillarIdForPos(p);
if (!pillar) if (!pillar)
return nullptr; return nullptr;
return GetBgMap()->GetGameObject(BgObjects[pillar]); return GetBgMap()->GetGameObject(BgObjects[pillar]);
} }
@@ -18,7 +18,7 @@
#ifndef __BATTLEGROUNDRV_H #ifndef __BATTLEGROUNDRV_H
#define __BATTLEGROUNDRV_H #define __BATTLEGROUNDRV_H
#include "Battleground.h" #include "Arena.h"
enum BattlegroundRVObjectTypes enum BattlegroundRVObjectTypes
{ {
@@ -48,7 +48,7 @@ enum BattlegroundRVObjectTypes
BG_RV_OBJECT_MAX, BG_RV_OBJECT_MAX,
}; };
enum BattlegroundRVObjects enum BattlegroundRVGameObjects
{ {
BG_RV_OBJECT_TYPE_BUFF_1 = 184663, BG_RV_OBJECT_TYPE_BUFF_1 = 184663,
BG_RV_OBJECT_TYPE_BUFF_2 = 184664, BG_RV_OBJECT_TYPE_BUFF_2 = 184664,
@@ -82,43 +82,33 @@ enum BattlegroundRVData
BG_RV_WORLD_STATE = 0xe1a, BG_RV_WORLD_STATE = 0xe1a,
}; };
class BattlegroundRV : public Battleground class AC_GAME_API BattlegroundRV : public Arena
{ {
public: public:
BattlegroundRV(); BattlegroundRV();
~BattlegroundRV() override;
/* inherited from BattlegroundClass */ /* inherited from BattlegroundClass */
void AddPlayer(Player* player) override;
void RemovePlayer(Player* player) override;
void StartingEventCloseDoors() override;
void StartingEventOpenDoors() override; void StartingEventOpenDoors() override;
void Init() override; void Init() override;
void FillInitialWorldStates(WorldPacket& d) override; void FillInitialWorldStates(WorldPacket& d) override;
void UpdateArenaWorldState() override;
void HandleAreaTrigger(Player* player, uint32 trigger) override; void HandleAreaTrigger(Player* player, uint32 trigger) override;
bool SetupBattleground() override; bool SetupBattleground() override;
void HandleKillPlayer(Player* player, Player* killer) override;
bool HandlePlayerUnderMap(Player* player) override; bool HandlePlayerUnderMap(Player* player) override;
GameObject* GetPillarAtPosition(Position* p); GameObject* GetPillarAtPosition(Position* p);
private: private:
Milliseconds Timer; Milliseconds _timer;
uint32 State; uint32 _state;
uint16 CheckPlayersTimer; uint16 _checkPlayersTimer;
void PostUpdateImpl(uint32 diff) override; void PostUpdateImpl(uint32 diff) override;
protected: protected:
Milliseconds GetTimer() { return Timer; }
void SetTimer(Milliseconds timer) { Timer = timer; }
uint32 getState() { return State; };
void setState(uint32 state) { State = state; }
void TeleportUnitToNewZ(Unit* unit, float newZ, bool casting); void TeleportUnitToNewZ(Unit* unit, float newZ, bool casting);
void CheckPositionForUnit(Unit* unit); void CheckPositionForUnit(Unit* unit);
void UpdatePillars(); void UpdatePillars();
uint32 GetPillarIdForPos(Position* p); uint32 GetPillarIdForPos(Position* p);
}; };
#endif #endif
@@ -29,12 +29,16 @@ constexpr Milliseconds BG_SA_BOAT_START = 1min;
constexpr Milliseconds BG_SA_WARMUPLENGTH = 2min; constexpr Milliseconds BG_SA_WARMUPLENGTH = 2min;
constexpr Milliseconds BG_SA_ROUNDLENGTH = 10min; constexpr Milliseconds BG_SA_ROUNDLENGTH = 10min;
void BattlegroundSAScore::BuildObjectivesBlock(WorldPacket& data)
{
data << uint32(2); // Objectives Count
data << uint32(DemolishersDestroyed);
data << uint32(GatesDestroyed);
}
BattlegroundSA::BattlegroundSA() BattlegroundSA::BattlegroundSA()
{ {
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_SA_START_TWO_MINUTES; StartMessageIds[BG_STARTING_EVENT_FOURTH] = 0;
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_SA_START_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_SA_START_HALF_MINUTE;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_SA_HAS_BEGUN;
BgObjects.resize(BG_SA_MAXOBJ); BgObjects.resize(BG_SA_MAXOBJ);
BgCreatures.resize(static_cast<uint16>(BG_SA_MAXNPC) + BG_SA_MAX_GY); BgCreatures.resize(static_cast<uint16>(BG_SA_MAXNPC) + BG_SA_MAX_GY);
TimerEnabled = false; TimerEnabled = false;
@@ -318,7 +322,7 @@ void BattlegroundSA::PostUpdateImpl(uint32 diff)
{ {
SignaledRoundTwo = true; SignaledRoundTwo = true;
InitSecondRound = false; InitSecondRound = false;
SendMessageToAll(LANG_BG_SA_ROUND_TWO_ONE_MINUTE, CHAT_MSG_BG_SYSTEM_NEUTRAL); SendBroadcastText(BG_SA_TEXT_ROUND_TWO_START_ONE_MINUTE, CHAT_MSG_BG_SYSTEM_NEUTRAL);
} }
} }
else else
@@ -370,7 +374,7 @@ void BattlegroundSA::PostUpdateImpl(uint32 diff)
if (!SignaledRoundTwoHalfMin) if (!SignaledRoundTwoHalfMin)
{ {
SignaledRoundTwoHalfMin = true; SignaledRoundTwoHalfMin = true;
SendMessageToAll(LANG_BG_SA_ROUND_TWO_START_HALF_MINUTE, CHAT_MSG_BG_SYSTEM_NEUTRAL); SendBroadcastText(BG_SA_TEXT_ROUND_TWO_START_HALF_MINUTE, CHAT_MSG_BG_SYSTEM_NEUTRAL);
} }
} }
StartShips(); StartShips();
@@ -496,11 +500,9 @@ void BattlegroundSA::FillInitialWorldStates(WorldPacket& data)
void BattlegroundSA::AddPlayer(Player* player) void BattlegroundSA::AddPlayer(Player* player)
{ {
Battleground::AddPlayer(player); Battleground::AddPlayer(player);
//create score and add it to map, default values are set in constructor PlayerScores.emplace(player->GetGUID().GetCounter(), new BattlegroundSAScore(player->GetGUID()));
BattlegroundSAScore* sc = new BattlegroundSAScore(player);
SendTransportInit(player); SendTransportInit(player);
PlayerScores[player->GetGUID()] = sc;
TeleportToEntrancePosition(player); TeleportToEntrancePosition(player);
} }
@@ -515,20 +517,6 @@ void BattlegroundSA::HandleAreaTrigger(Player* /*Source*/, uint32 /*Trigger*/)
return; return;
} }
void BattlegroundSA::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
{
BattlegroundScoreMap::iterator itr = PlayerScores.find(player->GetGUID());
if (itr == PlayerScores.end())
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(player, type, value, doAddHonor);
}
void BattlegroundSA::TeleportPlayers() void BattlegroundSA::TeleportPlayers()
{ {
for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
@@ -19,17 +19,7 @@
#define __BATTLEGROUNDSA_H #define __BATTLEGROUNDSA_H
#include "Battleground.h" #include "Battleground.h"
#include "BattlegroundScore.h"
struct BattlegroundSAScore : public BattlegroundScore
{
BattlegroundSAScore(Player* player) : BattlegroundScore(player), demolishers_destroyed(0), gates_destroyed(0) { }
~BattlegroundSAScore() override { }
uint8 demolishers_destroyed;
uint8 gates_destroyed;
uint32 GetAttr1() const final { return demolishers_destroyed; }
uint32 GetAttr2() const final { return gates_destroyed; }
};
#define BG_SA_FLAG_AMOUNT 3 #define BG_SA_FLAG_AMOUNT 3
#define BG_SA_DEMOLISHER_AMOUNT 4 #define BG_SA_DEMOLISHER_AMOUNT 4
@@ -405,6 +395,15 @@ float const BG_SA_GYOrientation[BG_SA_MAX_GY] =
6.148f, // defender last GY 6.148f, // defender last GY
}; };
enum BG_SA_BroadcastTexts
{
BG_SA_TEXT_ALLIANCE_CAPTURED_TITAN_PORTAL = 28944,
BG_SA_TEXT_HORDE_CAPTURED_TITAN_PORTAL = 28945,
BG_SA_TEXT_ROUND_TWO_START_ONE_MINUTE = 29448,
BG_SA_TEXT_ROUND_TWO_START_HALF_MINUTE = 29449
};
struct BG_SA_RoundScore struct BG_SA_RoundScore
{ {
TeamId winner; TeamId winner;
@@ -420,8 +419,40 @@ const float SOTADefPortalDest[5][4] =
{ 1193.857f, 69.9f, 58.046f, 5.7245f }, { 1193.857f, 69.9f, 58.046f, 5.7245f },
}; };
struct BattlegroundSAScore final : public BattlegroundScore
{
friend class BattlegroundSA;
protected:
BattlegroundSAScore(ObjectGuid playerGuid) : BattlegroundScore(playerGuid) { }
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 override;
uint32 GetAttr1() const final override { return DemolishersDestroyed; }
uint32 GetAttr2() const final override { return GatesDestroyed; }
uint32 DemolishersDestroyed = 0;
uint32 GatesDestroyed = 0;
};
/// Class for manage Strand of Ancient battleground /// Class for manage Strand of Ancient battleground
class BattlegroundSA : public Battleground class AC_GAME_API BattlegroundSA : public Battleground
{ {
public: public:
BattlegroundSA(); BattlegroundSA();
@@ -491,10 +522,6 @@ public:
void RemovePlayer(Player* player) override; void RemovePlayer(Player* player) override;
void HandleAreaTrigger(Player* player, uint32 trigger) override; void HandleAreaTrigger(Player* player, uint32 trigger) override;
/* Scorekeeping */
/// Update score board
void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
// Teleporters // Teleporters
void DefendersPortalTeleport(GameObject* portal, Player* plr); void DefendersPortalTeleport(GameObject* portal, Player* plr);
@@ -620,6 +647,6 @@ private:
bool _relicClicked; bool _relicClicked;
// Achievement: Not Even a Scratch // Achievement: Not Even a Scratch
bool _notEvenAScratch[BG_TEAMS_COUNT]; bool _notEvenAScratch[PVP_TEAMS_COUNT];
}; };
#endif #endif
@@ -26,15 +26,21 @@
#include "World.h" #include "World.h"
#include "WorldPacket.h" #include "WorldPacket.h"
void BattlegroundWGScore::BuildObjectivesBlock(WorldPacket& data)
{
data << uint32(2); // Objectives Count
data << uint32(FlagCaptures);
data << uint32(FlagReturns);
}
BattlegroundWS::BattlegroundWS() BattlegroundWS::BattlegroundWS()
{ {
BgObjects.resize(BG_WS_OBJECT_MAX); BgObjects.resize(BG_WS_OBJECT_MAX);
BgCreatures.resize(BG_CREATURES_MAX_WS); BgCreatures.resize(BG_CREATURES_MAX_WS);
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES; StartMessageIds[BG_STARTING_EVENT_SECOND] = BG_WS_TEXT_START_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE; StartMessageIds[BG_STARTING_EVENT_THIRD] = BG_WS_TEXT_START_HALF_MINUTE;
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE; StartMessageIds[BG_STARTING_EVENT_FOURTH] = BG_WS_TEXT_BATTLE_HAS_BEGUN;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN;
_flagState[TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_BASE; _flagState[TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_BASE;
_flagState[TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE; _flagState[TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE;
@@ -68,7 +74,7 @@ void BattlegroundWS::PostUpdateImpl(uint32 diff)
case BG_WS_EVENT_RESPAWN_BOTH_FLAGS: case BG_WS_EVENT_RESPAWN_BOTH_FLAGS:
SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY); SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY);
SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY); SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY);
SendMessageToAll(LANG_BG_WS_F_PLACED, CHAT_MSG_BG_SYSTEM_NEUTRAL); SendBroadcastText(BG_WS_TEXT_FLAGS_PLACED, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED); PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED);
break; break;
case BG_WS_EVENT_ALLIANCE_DROP_FLAG: case BG_WS_EVENT_ALLIANCE_DROP_FLAG:
@@ -134,7 +140,7 @@ void BattlegroundWS::StartingEventOpenDoors()
void BattlegroundWS::AddPlayer(Player* player) void BattlegroundWS::AddPlayer(Player* player)
{ {
Battleground::AddPlayer(player); Battleground::AddPlayer(player);
PlayerScores[player->GetGUID()] = new BattlegroundWGScore(player); PlayerScores.emplace(player->GetGUID().GetCounter(), new BattlegroundWGScore(player->GetGUID()));
} }
void BattlegroundWS::RespawnFlagAfterDrop(TeamId teamId) void BattlegroundWS::RespawnFlagAfterDrop(TeamId teamId)
@@ -144,7 +150,7 @@ void BattlegroundWS::RespawnFlagAfterDrop(TeamId teamId)
UpdateFlagState(teamId, BG_WS_FLAG_STATE_ON_BASE); UpdateFlagState(teamId, BG_WS_FLAG_STATE_ON_BASE);
SpawnBGObject(teamId == TEAM_ALLIANCE ? BG_WS_OBJECT_A_FLAG : BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY); SpawnBGObject(teamId == TEAM_ALLIANCE ? BG_WS_OBJECT_A_FLAG : BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY);
SendMessageToAll(teamId == TEAM_ALLIANCE ? LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED : LANG_BG_WS_HORDE_FLAG_RESPAWNED, CHAT_MSG_BG_SYSTEM_NEUTRAL); SendBroadcastText(BG_WS_TEXT_FLAGS_PLACED, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED); PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED);
if (GameObject* flag = GetBgMap()->GetGameObject(GetDroppedFlagGUID(teamId))) if (GameObject* flag = GetBgMap()->GetGameObject(GetDroppedFlagGUID(teamId)))
@@ -187,18 +193,19 @@ void BattlegroundWS::EventPlayerCapturedFlag(Player* player)
AddPoints(player->GetTeamId(), 1); AddPoints(player->GetTeamId(), 1);
SetFlagPicker(ObjectGuid::Empty, GetOtherTeamId(player->GetTeamId())); SetFlagPicker(ObjectGuid::Empty, GetOtherTeamId(player->GetTeamId()));
UpdateFlagState(GetOtherTeamId(player->GetTeamId()), BG_WS_FLAG_STATE_ON_BASE); UpdateFlagState(GetOtherTeamId(player->GetTeamId()), BG_WS_FLAG_STATE_ON_BASE);
if (player->GetTeamId() == TEAM_ALLIANCE) if (player->GetTeamId() == TEAM_ALLIANCE)
{ {
player->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG); player->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG);
PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE); PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE);
SendMessageToAll(LANG_BG_WS_CAPTURED_HF, CHAT_MSG_BG_SYSTEM_ALLIANCE, player); SendBroadcastText(BG_WS_TEXT_CAPTURED_HORDE_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
RewardReputationToTeam(890, _reputationCapture, TEAM_ALLIANCE); RewardReputationToTeam(890, _reputationCapture, TEAM_ALLIANCE);
} }
else else
{ {
player->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG); player->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG);
PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_HORDE); PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_HORDE);
SendMessageToAll(LANG_BG_WS_CAPTURED_AF, CHAT_MSG_BG_SYSTEM_HORDE, player); SendBroadcastText(BG_WS_TEXT_CAPTURED_ALLIANCE_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, player);
RewardReputationToTeam(889, _reputationCapture, TEAM_HORDE); RewardReputationToTeam(889, _reputationCapture, TEAM_HORDE);
} }
@@ -241,14 +248,14 @@ void BattlegroundWS::EventPlayerDroppedFlag(Player* player)
{ {
UpdateFlagState(TEAM_HORDE, BG_WS_FLAG_STATE_ON_GROUND); UpdateFlagState(TEAM_HORDE, BG_WS_FLAG_STATE_ON_GROUND);
player->CastSpell(player, BG_WS_SPELL_WARSONG_FLAG_DROPPED, true); player->CastSpell(player, BG_WS_SPELL_WARSONG_FLAG_DROPPED, true);
SendMessageToAll(LANG_BG_WS_DROPPED_HF, CHAT_MSG_BG_SYSTEM_HORDE, player); SendBroadcastText(BG_WS_TEXT_HORDE_FLAG_DROPPED, CHAT_MSG_BG_SYSTEM_HORDE, player);
_bgEvents.RescheduleEvent(BG_WS_EVENT_HORDE_DROP_FLAG, BG_WS_FLAG_DROP_TIME); _bgEvents.RescheduleEvent(BG_WS_EVENT_HORDE_DROP_FLAG, BG_WS_FLAG_DROP_TIME);
} }
else else
{ {
UpdateFlagState(TEAM_ALLIANCE, BG_WS_FLAG_STATE_ON_GROUND); UpdateFlagState(TEAM_ALLIANCE, BG_WS_FLAG_STATE_ON_GROUND);
player->CastSpell(player, BG_WS_SPELL_SILVERWING_FLAG_DROPPED, true); player->CastSpell(player, BG_WS_SPELL_SILVERWING_FLAG_DROPPED, true);
SendMessageToAll(LANG_BG_WS_DROPPED_AF, CHAT_MSG_BG_SYSTEM_ALLIANCE, player); SendBroadcastText(BG_WS_TEXT_ALLIANCE_FLAG_DROPPED, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
_bgEvents.RescheduleEvent(BG_WS_EVENT_ALLIANCE_DROP_FLAG, BG_WS_FLAG_DROP_TIME); _bgEvents.RescheduleEvent(BG_WS_EVENT_ALLIANCE_DROP_FLAG, BG_WS_FLAG_DROP_TIME);
} }
} }
@@ -270,7 +277,7 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb
player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, BG_WS_SPELL_SILVERWING_FLAG_PICKED); player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, BG_WS_SPELL_SILVERWING_FLAG_PICKED);
PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP); PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP);
SendMessageToAll(LANG_BG_WS_PICKEDUP_AF, CHAT_MSG_BG_SYSTEM_HORDE, player); SendBroadcastText(BG_WS_TEXT_ALLIANCE_FLAG_PICKED_UP, CHAT_MSG_BG_SYSTEM_HORDE, player);
if (GetFlagState(TEAM_HORDE) != BG_WS_FLAG_STATE_ON_BASE) if (GetFlagState(TEAM_HORDE) != BG_WS_FLAG_STATE_ON_BASE)
{ {
@@ -290,7 +297,7 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb
player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, BG_WS_SPELL_WARSONG_FLAG_PICKED); player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, BG_WS_SPELL_WARSONG_FLAG_PICKED);
PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP); PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP);
SendMessageToAll(LANG_BG_WS_PICKEDUP_HF, CHAT_MSG_BG_SYSTEM_ALLIANCE, player); SendBroadcastText(BG_WS_TEXT_HORDE_FLAG_PICKED_UP, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
if (GetFlagState(TEAM_ALLIANCE) != BG_WS_FLAG_STATE_ON_BASE) if (GetFlagState(TEAM_ALLIANCE) != BG_WS_FLAG_STATE_ON_BASE)
{ {
@@ -315,7 +322,7 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb
UpdatePlayerScore(player, SCORE_FLAG_RETURNS, 1); UpdatePlayerScore(player, SCORE_FLAG_RETURNS, 1);
PlaySoundToAll(BG_WS_SOUND_FLAG_RETURNED); PlaySoundToAll(BG_WS_SOUND_FLAG_RETURNED);
SendMessageToAll(LANG_BG_WS_RETURNED_AF, CHAT_MSG_BG_SYSTEM_ALLIANCE, player); SendBroadcastText(BG_WS_TEXT_ALLIANCE_FLAG_RETURNED, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
_bgEvents.CancelEvent(BG_WS_EVENT_BOTH_FLAGS_KEPT10); _bgEvents.CancelEvent(BG_WS_EVENT_BOTH_FLAGS_KEPT10);
_bgEvents.CancelEvent(BG_WS_EVENT_BOTH_FLAGS_KEPT15); _bgEvents.CancelEvent(BG_WS_EVENT_BOTH_FLAGS_KEPT15);
RemoveAssaultAuras(); RemoveAssaultAuras();
@@ -332,7 +339,7 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb
player->CastSpell(player, assaultSpellId, true); player->CastSpell(player, assaultSpellId, true);
PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP); PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP);
SendMessageToAll(LANG_BG_WS_PICKEDUP_AF, CHAT_MSG_BG_SYSTEM_HORDE, player); SendBroadcastText(BG_WS_TEXT_ALLIANCE_FLAG_PICKED_UP, CHAT_MSG_BG_SYSTEM_HORDE, player);
return; return;
} }
} }
@@ -348,7 +355,7 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb
UpdatePlayerScore(player, SCORE_FLAG_RETURNS, 1); UpdatePlayerScore(player, SCORE_FLAG_RETURNS, 1);
PlaySoundToAll(BG_WS_SOUND_FLAG_RETURNED); PlaySoundToAll(BG_WS_SOUND_FLAG_RETURNED);
SendMessageToAll(LANG_BG_WS_RETURNED_HF, CHAT_MSG_BG_SYSTEM_HORDE, player); SendBroadcastText(BG_WS_TEXT_HORDE_FLAG_RETURNED, CHAT_MSG_BG_SYSTEM_HORDE, player);
_bgEvents.CancelEvent(BG_WS_EVENT_BOTH_FLAGS_KEPT10); _bgEvents.CancelEvent(BG_WS_EVENT_BOTH_FLAGS_KEPT10);
_bgEvents.CancelEvent(BG_WS_EVENT_BOTH_FLAGS_KEPT15); _bgEvents.CancelEvent(BG_WS_EVENT_BOTH_FLAGS_KEPT15);
RemoveAssaultAuras(); RemoveAssaultAuras();
@@ -365,7 +372,7 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb
player->CastSpell(player, assaultSpellId, true); player->CastSpell(player, assaultSpellId, true);
PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP); PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP);
SendMessageToAll(LANG_BG_WS_PICKEDUP_HF, CHAT_MSG_BG_SYSTEM_ALLIANCE, player); SendBroadcastText(BG_WS_TEXT_HORDE_FLAG_PICKED_UP, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
return; return;
} }
} }
@@ -509,26 +516,22 @@ void BattlegroundWS::HandleKillPlayer(Player* player, Player* killer)
Battleground::HandleKillPlayer(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 (!Battleground::UpdatePlayerScore(player, type, value, doAddHonor))
if (itr == PlayerScores.end()) return false;
return;
switch (type) switch (type)
{ {
case SCORE_FLAG_CAPTURES: case SCORE_FLAG_CAPTURES:
((BattlegroundWGScore*)itr->second)->FlagCaptures += value;
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, WS_OBJECTIVE_CAPTURE_FLAG); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, WS_OBJECTIVE_CAPTURE_FLAG);
break; break;
case SCORE_FLAG_RETURNS: case SCORE_FLAG_RETURNS:
((BattlegroundWGScore*)itr->second)->FlagReturns += value;
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, WS_OBJECTIVE_RETURN_FLAG); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, WS_OBJECTIVE_RETURN_FLAG);
break; break;
default:
Battleground::UpdatePlayerScore(player, type, value, doAddHonor);
break;
} }
return true;
} }
GraveyardStruct const* BattlegroundWS::GetClosestGraveyard(Player* player) GraveyardStruct const* BattlegroundWS::GetClosestGraveyard(Player* player)
@@ -19,6 +19,7 @@
#define __BATTLEGROUNDWS_H #define __BATTLEGROUNDWS_H
#include "Battleground.h" #include "Battleground.h"
#include "BattlegroundScore.h"
#include "EventMap.h" #include "EventMap.h"
enum BG_WS_Events enum BG_WS_Events
@@ -43,6 +44,23 @@ enum BG_WS_TimerOrScore
BG_WS_SPELL_BRUTAL_TIME = 15 * MINUTE * IN_MILLISECONDS BG_WS_SPELL_BRUTAL_TIME = 15 * MINUTE * IN_MILLISECONDS
}; };
enum BG_WS_BroadcastTexts
{
BG_WS_TEXT_START_ONE_MINUTE = 10015,
BG_WS_TEXT_START_HALF_MINUTE = 10016,
BG_WS_TEXT_BATTLE_HAS_BEGUN = 10014,
BG_WS_TEXT_CAPTURED_HORDE_FLAG = 9801,
BG_WS_TEXT_CAPTURED_ALLIANCE_FLAG = 9802,
BG_WS_TEXT_FLAGS_PLACED = 9803,
BG_WS_TEXT_ALLIANCE_FLAG_PICKED_UP = 9804,
BG_WS_TEXT_ALLIANCE_FLAG_DROPPED = 9805,
BG_WS_TEXT_HORDE_FLAG_PICKED_UP = 9807,
BG_WS_TEXT_HORDE_FLAG_DROPPED = 9806,
BG_WS_TEXT_ALLIANCE_FLAG_RETURNED = 9808,
BG_WS_TEXT_HORDE_FLAG_RETURNED = 9809,
};
enum BG_WS_Sound enum BG_WS_Sound
{ {
BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE = 8173, BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE = 8173,
@@ -164,18 +182,39 @@ enum BG_WS_Trigger
BG_WS_TRIGGER_HORDE_ELIXIR_BERSERK_SPAWN = 3709, BG_WS_TRIGGER_HORDE_ELIXIR_BERSERK_SPAWN = 3709,
}; };
struct BattlegroundWGScore : public BattlegroundScore struct BattlegroundWGScore final : public BattlegroundScore
{ {
BattlegroundWGScore(Player* player): BattlegroundScore(player), FlagCaptures(0), FlagReturns(0) { } friend class BattlegroundWS;
~BattlegroundWGScore() override { }
uint32 FlagCaptures;
uint32 FlagReturns;
uint32 GetAttr1() const final { return FlagCaptures; } protected:
uint32 GetAttr2() const final { return FlagReturns; } BattlegroundWGScore(ObjectGuid playerGuid) : BattlegroundScore(playerGuid) { }
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 override;
uint32 GetAttr1() const final override { return FlagCaptures; }
uint32 GetAttr2() const final override { return FlagReturns; }
uint32 FlagCaptures = 0;
uint32 FlagReturns = 0;
}; };
class BattlegroundWS : public Battleground class AC_GAME_API BattlegroundWS : public Battleground
{ {
public: public:
/* Construction */ /* Construction */
@@ -208,7 +247,7 @@ public:
GraveyardStruct const* GetClosestGraveyard(Player* player) override; GraveyardStruct const* GetClosestGraveyard(Player* player) override;
void UpdateFlagState(TeamId teamId, uint32 value); void UpdateFlagState(TeamId teamId, uint32 value);
void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override; bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override;
void SetDroppedFlagGUID(ObjectGuid guid, TeamId teamId) override { _droppedFlagGUID[teamId] = guid; } void SetDroppedFlagGUID(ObjectGuid guid, TeamId teamId) override { _droppedFlagGUID[teamId] = guid; }
ObjectGuid GetDroppedFlagGUID(TeamId teamId) const { return _droppedFlagGUID[teamId];} ObjectGuid GetDroppedFlagGUID(TeamId teamId) const { return _droppedFlagGUID[teamId];}
void FillInitialWorldStates(WorldPacket& data) override; void FillInitialWorldStates(WorldPacket& data) override;
@@ -234,4 +273,5 @@ private:
void PostUpdateImpl(uint32 diff) override; void PostUpdateImpl(uint32 diff) override;
}; };
#endif #endif
@@ -340,7 +340,7 @@ void WorldSession::HandlePVPLogDataOpcode(WorldPacket& /*recvData*/)
return; return;
WorldPacket data; WorldPacket data;
sBattlegroundMgr->BuildPvpLogDataPacket(&data, bg); bg->BuildPvPLogDataPacket(data);
SendPacket(&data); SendPacket(&data);
LOG_DEBUG("network", "WORLD: Sent MSG_PVP_LOG_DATA Message"); LOG_DEBUG("network", "WORLD: Sent MSG_PVP_LOG_DATA Message");
@@ -94,7 +94,7 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData)
// TODO: find correct opcode // TODO: find correct opcode
if (_player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) if (_player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
{ {
SendNotification(LANG_ARENA_ONE_TOOLOW, sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)); SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", _player->GetName(), ERR_ARENA_TEAM_TARGET_TOO_LOW_S);
return; return;
} }
+6 -110
View File
@@ -645,79 +645,7 @@ enum AcoreStrings
// End Level 3 list, continued at 1100 // End Level 3 list, continued at 1100
// Battleground // 600-704 - free
LANG_BG_A_WINS = 600,
LANG_BG_H_WINS = 601,
LANG_BG_WS_START_TWO_MINUTES = 753,
LANG_BG_WS_START_ONE_MINUTE = 602,
LANG_BG_WS_START_HALF_MINUTE = 603,
LANG_BG_WS_HAS_BEGUN = 604,
LANG_BG_WS_CAPTURED_HF = 605,
LANG_BG_WS_CAPTURED_AF = 606,
LANG_BG_WS_DROPPED_HF = 607,
LANG_BG_WS_DROPPED_AF = 608,
LANG_BG_WS_RETURNED_AF = 609,
LANG_BG_WS_RETURNED_HF = 610,
LANG_BG_WS_PICKEDUP_HF = 611,
LANG_BG_WS_PICKEDUP_AF = 612,
LANG_BG_WS_F_PLACED = 613,
LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED = 614,
LANG_BG_WS_HORDE_FLAG_RESPAWNED = 615,
LANG_BG_EY_START_TWO_MINUTES = 755,
LANG_BG_EY_START_ONE_MINUTE = 636,
LANG_BG_EY_START_HALF_MINUTE = 637,
LANG_BG_EY_HAS_BEGUN = 638,
LANG_BG_AB_ALLY = 650,
LANG_BG_AB_HORDE = 651,
LANG_BG_AB_NODE_STABLES = 652,
LANG_BG_AB_NODE_BLACKSMITH = 653,
LANG_BG_AB_NODE_FARM = 654,
LANG_BG_AB_NODE_LUMBER_MILL = 655,
LANG_BG_AB_NODE_GOLD_MINE = 656,
LANG_BG_AB_NODE_TAKEN = 657,
LANG_BG_AB_NODE_DEFENDED = 658,
LANG_BG_AB_NODE_ASSAULTED = 659,
LANG_BG_AB_NODE_CLAIMED = 660,
LANG_BG_AB_START_TWO_MINUTES = 754,
LANG_BG_AB_START_ONE_MINUTE = 661,
LANG_BG_AB_START_HALF_MINUTE = 662,
LANG_BG_AB_HAS_BEGUN = 663,
LANG_BG_AB_A_NEAR_VICTORY = 664,
LANG_BG_AB_H_NEAR_VICTORY = 665,
LANG_BG_MARK_BY_MAIL = 666,
LANG_BG_EY_HAS_TAKEN_A_M_TOWER = 667,
LANG_BG_EY_HAS_TAKEN_H_M_TOWER = 668,
LANG_BG_EY_HAS_TAKEN_A_D_RUINS = 669,
LANG_BG_EY_HAS_TAKEN_H_D_RUINS = 670,
LANG_BG_EY_HAS_TAKEN_A_B_TOWER = 671,
LANG_BG_EY_HAS_TAKEN_H_B_TOWER = 672,
LANG_BG_EY_HAS_TAKEN_A_F_RUINS = 673,
LANG_BG_EY_HAS_TAKEN_H_F_RUINS = 674,
LANG_BG_EY_HAS_LOST_A_M_TOWER = 675,
LANG_BG_EY_HAS_LOST_H_M_TOWER = 676,
LANG_BG_EY_HAS_LOST_A_D_RUINS = 677,
LANG_BG_EY_HAS_LOST_H_D_RUINS = 678,
LANG_BG_EY_HAS_LOST_A_B_TOWER = 679,
LANG_BG_EY_HAS_LOST_H_B_TOWER = 680,
LANG_BG_EY_HAS_LOST_A_F_RUINS = 681,
LANG_BG_EY_HAS_LOST_H_F_RUINS = 682,
LANG_BG_EY_HAS_TAKEN_FLAG = 683,
LANG_BG_EY_CAPTURED_FLAG_A = 684,
LANG_BG_EY_CAPTURED_FLAG_H = 685,
LANG_BG_EY_DROPPED_FLAG = 686,
LANG_BG_EY_RESETED_FLAG = 687,
LANG_ARENA_ONE_TOOLOW = 700,
LANG_ARENA_ONE_MINUTE = 701,
LANG_ARENA_THIRTY_SECONDS = 702,
LANG_ARENA_FIFTEEN_SECONDS = 703,
LANG_ARENA_HAS_BEGUN = 704,
LANG_WAIT_BEFORE_SPEAKING = 705, LANG_WAIT_BEFORE_SPEAKING = 705,
LANG_NOT_EQUIPPED_ITEM = 706, LANG_NOT_EQUIPPED_ITEM = 706,
@@ -745,9 +673,7 @@ enum AcoreStrings
LANG_ARENA_GROUP_TOO_LARGE = 721, // "Your group is too large for this arena. Please regroup to join." LANG_ARENA_GROUP_TOO_LARGE = 721, // "Your group is too large for this arena. Please regroup to join."
LANG_ARENA_YOUR_TEAM_ONLY = 722, // "Your group has members not in your arena team. Please regroup to join." LANG_ARENA_YOUR_TEAM_ONLY = 722, // "Your group has members not in your arena team. Please regroup to join."
LANG_ARENA_NOT_ENOUGH_PLAYERS = 723, // "Your group does not have enough players to join this match." LANG_ARENA_NOT_ENOUGH_PLAYERS = 723, // "Your group does not have enough players to join this match."
LANG_ARENA_GOLD_WINS = 724, // "The Gold Team wins!" // 724-726 - free
LANG_ARENA_GREEN_WINS = 725, // "The Green Team wins!"
// = 726, see LANG_ARENA_QUEUE_ANNOUNCE_WORLD
LANG_BG_GROUP_OFFLINE_MEMBER = 727, // "Your group has an offline member. Please remove him before joining." LANG_BG_GROUP_OFFLINE_MEMBER = 727, // "Your group has an offline member. Please remove him before joining."
LANG_BG_GROUP_MIXED_FACTION = 728, // "Your group has players from the opposing faction. You can't join the battleground as a group." LANG_BG_GROUP_MIXED_FACTION = 728, // "Your group has players from the opposing faction. You can't join the battleground as a group."
LANG_BG_GROUP_MIXED_LEVELS = 729, // "Your group has players from different battleground brakets. You can't join as group." LANG_BG_GROUP_MIXED_LEVELS = 729, // "Your group has players from different battleground brakets. You can't join as group."
@@ -775,9 +701,6 @@ enum AcoreStrings
LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 750, // "Not enough players. This game will close in %u mins." LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 750, // "Not enough players. This game will close in %u mins."
LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS = 751, // "Not enough players. This game will close in %u seconds." LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS = 751, // "Not enough players. This game will close in %u seconds."
// = 752, see LANG_PINFO_ACC_IP // = 752, see LANG_PINFO_ACC_IP
// LANG_BG_WS_START_TWO_MINUTES = 753, - defined above
// LANG_BG_AB_START_TWO_MINUTES = 754, - defined above
// LANG_BG_EY_START_TWO_MINUTES = 755, - defined above
// Room for BG/ARENA = 773-784, 788-799 not used // Room for BG/ARENA = 773-784, 788-799 not used
LANG_ARENA_TESTING = 785, LANG_ARENA_TESTING = 785,
@@ -1030,32 +953,9 @@ enum AcoreStrings
LANG_DEBUG_AREATRIGGER_OFF = 1203, LANG_DEBUG_AREATRIGGER_OFF = 1203,
LANG_DEBUG_AREATRIGGER_REACHED = 1204, LANG_DEBUG_AREATRIGGER_REACHED = 1204,
// Isle of Conquest // 1205-1299 - free
LANG_BG_IC_START_TWO_MINUTES = 1205,
LANG_BG_IC_START_ONE_MINUTE = 1206,
LANG_BG_IC_START_HALF_MINUTE = 1207,
LANG_BG_IC_HAS_BEGUN = 1208,
LANG_BG_IC_ALLIANCE_KEEP = 1209,
LANG_BG_IC_HORDE_KEEP = 1210,
LANG_BG_IC_TEAM_WINS = 1211,
LANG_BG_IC_WEST_GATE_DESTROYED = 1212,
LANG_BG_IC_EAST_GATE_DESTROYED = 1213,
LANG_BG_IC_SOUTH_GATE_DESTROYED = 1214,
LANG_BG_IC_NORTH_GATE_DESTROYED = 1215,
LANG_BG_IC_TEAM_ASSAULTED_NODE_1 = 1216,
LANG_BG_IC_TEAM_DEFENDED_NODE = 1217,
LANG_BG_IC_TEAM_ASSAULTED_NODE_2 = 1218,
LANG_BG_IC_TEAM_HAS_TAKEN_NODE = 1219,
LANG_BG_IC_WORKSHOP = 1220,
LANG_BG_IC_DOCKS = 1221,
LANG_BG_IC_REFINERY = 1222,
LANG_BG_IC_QUARRY = 1223,
LANG_BG_IC_HANGAR = 1224,
// 1225-1299
LANG_BG_IC_ALLIANCE = 1300,
LANG_BG_IC_HORDE = 1301,
// 1302-1325 // 1300-1333
// AV // AV
LANG_BG_AV_ALLY = 1300, LANG_BG_AV_ALLY = 1300,
LANG_BG_AV_HORDE = 1301, LANG_BG_AV_HORDE = 1301,
@@ -1086,14 +986,10 @@ enum AcoreStrings
LANG_BG_AV_NODE_TOWER_FROST_W = 1324, LANG_BG_AV_NODE_TOWER_FROST_W = 1324,
LANG_BG_AV_NODE_GRAVE_FROST_HUT = 1325, LANG_BG_AV_NODE_GRAVE_FROST_HUT = 1325,
LANG_BG_AV_START_ONE_MINUTE = 1326, // 1326-1330 - free
LANG_BG_AV_START_HALF_MINUTE = 1327,
LANG_BG_AV_HAS_BEGUN = 1328,
LANG_BG_AV_A_NEAR_LOSE = 1329,
LANG_BG_AV_H_NEAR_LOSE = 1330,
LANG_BG_AV_H_CAPTAIN_DEAD = 1331, LANG_BG_AV_H_CAPTAIN_DEAD = 1331,
LANG_BG_AV_A_CAPTAIN_DEAD = 1332, LANG_BG_AV_A_CAPTAIN_DEAD = 1332,
LANG_BG_AV_START_TWO_MINUTES = 1333,
//Player Ticket Strings //Player Ticket Strings
LANG_TICKET_CLOSED = 1334, LANG_TICKET_CLOSED = 1334,
+9 -2
View File
@@ -3407,13 +3407,20 @@ enum PvPTeamId
PVP_TEAM_NEUTRAL = 2 // Battleground: Neutral, Arena: None PVP_TEAM_NEUTRAL = 2 // Battleground: Neutral, Arena: None
}; };
uint8 constexpr PVP_TEAMS_COUNT = 2;
inline PvPTeamId GetPvPTeamId(TeamId teamId) inline PvPTeamId GetPvPTeamId(TeamId teamId)
{ {
return teamId == TEAM_ALLIANCE ? PVP_TEAM_ALLIANCE : PVP_TEAM_HORDE; return teamId == TEAM_ALLIANCE ? PVP_TEAM_ALLIANCE : PVP_TEAM_HORDE;
} }
inline TeamId GetTeamId(PvPTeamId teamId)
{
return teamId == PVP_TEAM_ALLIANCE ? TEAM_ALLIANCE : TEAM_HORDE;
}
// indexes of BattlemasterList.dbc // indexes of BattlemasterList.dbc
enum BattlegroundTypeId enum BattlegroundTypeId : uint8
{ {
BATTLEGROUND_TYPE_NONE = 0, // None BATTLEGROUND_TYPE_NONE = 0, // None
BATTLEGROUND_AV = 1, // Alterac Valley BATTLEGROUND_AV = 1, // Alterac Valley
@@ -3553,7 +3560,7 @@ enum DuelCompleteType
}; };
// handle the queue types and bg types separately to enable joining queue for different sized arenas at the same time // handle the queue types and bg types separately to enable joining queue for different sized arenas at the same time
enum BattlegroundQueueTypeId enum BattlegroundQueueTypeId : uint8
{ {
BATTLEGROUND_QUEUE_NONE = 0, BATTLEGROUND_QUEUE_NONE = 0,
BATTLEGROUND_QUEUE_AV = 1, BATTLEGROUND_QUEUE_AV = 1,