Merge branch 'master' into questXPHook

This commit is contained in:
郑佩茹
2022-03-16 15:22:22 -06:00
48 changed files with 2174 additions and 1170 deletions
@@ -75,9 +75,8 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_DEL_IP_NOT_BANNED, "DELETE FROM ip_banned WHERE ip = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_ACCOUNT_BANNED, "INSERT INTO account_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, ?, ?, 1)", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_ACCOUNT_NOT_BANNED, "UPDATE account_banned SET active = 0 WHERE id = ? AND active != 0", CONNECTION_ASYNC);
PrepareStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM, "DELETE FROM realmcharacters WHERE acctid = ? AND realmid = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_REALM_CHARACTERS, "INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(LOGIN_REP_REALM_CHARACTERS, "REPLACE INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_SUM_REALM_CHARACTERS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, salt, verifier, expansion, joindate) VALUES(?, ?, ?, ?, NOW())", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_REALM_CHARACTERS_INIT, "INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL", CONNECTION_ASYNC);
@@ -59,9 +59,8 @@ enum LoginDatabaseStatements : uint32
LOGIN_SEL_ACCOUNT_BY_ID,
LOGIN_INS_ACCOUNT_BANNED,
LOGIN_UPD_ACCOUNT_NOT_BANNED,
LOGIN_DEL_REALM_CHARACTERS_BY_REALM,
LOGIN_DEL_REALM_CHARACTERS,
LOGIN_INS_REALM_CHARACTERS,
LOGIN_REP_REALM_CHARACTERS,
LOGIN_SEL_SUM_REALM_CHARACTERS,
LOGIN_INS_ACCOUNT,
LOGIN_INS_REALM_CHARACTERS_INIT,
@@ -3844,6 +3844,10 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /*
{
l->push_back(owner);
}
else if (me->IsSummon() && me->ToTempSummon()->GetSummonerUnit())
{
l->push_back(me->ToTempSummon()->GetSummonerUnit());
}
}
else if (go)
{
@@ -137,7 +137,7 @@ bool ArenaSpectator::HandleSpectatorSpectateCommand(ChatHandler* handler, std::s
if (uint32 inviteInstanceId = player->GetPendingSpectatorInviteInstanceId())
{
if (Battleground* tbg = sBattlegroundMgr->GetBattleground(inviteInstanceId))
if (Battleground* tbg = sBattlegroundMgr->GetBattleground(inviteInstanceId, BATTLEGROUND_TYPE_NONE))
tbg->RemoveToBeTeleported(player->GetGUID());
player->SetPendingSpectatorInviteInstanceId(0);
}
+4
View File
@@ -312,6 +312,10 @@ void Arena::EndBattleground(TeamId winnerTeamId)
}
}
// update previous opponents for arena queue
winnerArenaTeam->SetPreviousOpponents(loserArenaTeam->GetId());
loserArenaTeam->SetPreviousOpponents(winnerArenaTeam->GetId());
// save the stat changes
if (bValidArena)
{
+1 -1
View File
@@ -61,7 +61,7 @@ protected:
{
RatingChange = ratingChange;
MatchmakerRating = matchMakerRating;
TeamName = teamName;
TeamName = std::string(teamName);
}
void BuildRatingInfoBlock(WorldPacket& data);
+1 -1
View File
@@ -345,7 +345,7 @@ void ArenaTeam::DelMember(ObjectGuid guid, bool cleanDb)
WorldPacket data;
playerMember->RemoveBattlegroundQueueId(bgQueue);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, nullptr, playerMember->GetBattlegroundQueueIndex(bgQueue), STATUS_NONE, 0, 0, 0, TEAM_NEUTRAL);
queue.RemovePlayer(playerMember->GetGUID(), true, 0);
queue.RemovePlayer(playerMember->GetGUID(), true);
playerMember->GetSession()->SendPacket(&data);
}
}
@@ -209,6 +209,9 @@ public:
void FinishWeek();
void FinishGame(int32 mod, const Map* bgMap);
void SetPreviousOpponents(uint32 arenaTeamId) { PreviousOpponents = arenaTeamId; }
uint32 GetPreviousOpponents() { return PreviousOpponents; }
void CreateTempArenaTeam(std::vector<Player*> playerList, uint8 type, std::string const& teamName);
// Containers
@@ -229,5 +232,7 @@ protected:
MemberList Members;
ArenaTeamStats Stats;
uint32 PreviousOpponents = 0;
};
#endif
+70 -2
View File
@@ -232,6 +232,9 @@ Battleground::~Battleground()
m_Map = nullptr;
}
// remove from bg free slot queue
RemoveFromBGFreeSlotQueue();
for (auto const& itr : PlayerScores)
delete itr.second;
}
@@ -251,8 +254,21 @@ void Battleground::Update(uint32 diff)
if (!GetPlayersSize())
{
//BG is empty
// if there are no players invited, delete BG
// this will delete arena or bg object, where any player entered
// [[ but if you use battleground object again (more battles possible to be played on 1 instance)
// then this condition should be removed and code:
// if (!GetInvitedCount(TEAM_HORDE) && !GetInvitedCount(TEAM_ALLIANCE))
// AddToFreeBGObjectsQueue(); // not yet implemented
// should be used instead of current
// ]]
// Battleground Template instance cannot be updated, because it would be deleted
if (!GetInvitedCount(TEAM_HORDE) && !GetInvitedCount(TEAM_ALLIANCE))
{
m_SetDeleteThis = true;
}
return;
}
@@ -768,6 +784,7 @@ void Battleground::EndBattleground(PvPTeamId winnerTeamId)
if (GetStatus() == STATUS_WAIT_LEAVE)
return;
RemoveFromBGFreeSlotQueue();
SetStatus(STATUS_WAIT_LEAVE);
SetWinner(winnerTeamId);
@@ -956,13 +973,17 @@ void Battleground::RemovePlayerAtLeave(Player* player)
// if the player was a match participant
if (participant)
{
WorldPacket data;
player->ClearAfkReports();
WorldPacket data;
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetCurrentBattlegroundQueueSlot(), STATUS_NONE, 0, 0, 0, TEAM_NEUTRAL);
player->GetSession()->SendPacket(&data);
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(GetBgTypeID(), GetArenaType());
// this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
player->RemoveBattlegroundQueueId(bgQueueTypeId);
// remove from raid group if player is member
if (Group* group = GetBgRaid(teamId))
if (group->IsMember(player->GetGUID()))
@@ -977,6 +998,19 @@ void Battleground::RemovePlayerAtLeave(Player* player)
if (isBattleground() && !player->IsGameMaster() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_CAST_DESERTER))
if (status == STATUS_IN_PROGRESS || status == STATUS_WAIT_JOIN)
player->ScheduleDelayedOperation(DELAYED_SPELL_CAST_DESERTER);
DecreaseInvitedCount(teamId);
//we should update battleground queue, but only if bg isn't ending
if (isBattleground() && GetStatus() < STATUS_WAIT_LEAVE)
{
BattlegroundTypeId bgTypeId = GetBgTypeID();
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(GetBgTypeID(), GetArenaType());
// a player has left the battleground, so there are free slots -> add to queue
AddToBGFreeSlotQueue();
sBattlegroundMgr->ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, GetBracketId());
}
}
// Remove shapeshift auras
@@ -1009,6 +1043,7 @@ void Battleground::Init()
m_BgInvitedPlayers[TEAM_ALLIANCE] = 0;
m_BgInvitedPlayers[TEAM_HORDE] = 0;
_InBGFreeSlotQueue = false;
m_Players.clear();
@@ -1028,9 +1063,15 @@ void Battleground::StartBattleground()
SetStartTime(0);
SetLastResurrectTime(0);
// add BG to free slot queue
AddToBGFreeSlotQueue();
// add bg to update list
// this must be done here, because we need to have already invited some players when first Battleground::Update() method is executed
sBattlegroundMgr->AddBattleground(this);
if (m_IsRated)
LOG_DEBUG("bg.arena", "Arena match type: {} for Team1Id: {} - Team2Id: {} started.", m_ArenaType, m_ArenaTeamIds[TEAM_ALLIANCE], m_ArenaTeamIds[TEAM_HORDE]);
}
void Battleground::AddPlayer(Player* player)
@@ -1129,6 +1170,26 @@ void Battleground::AddOrSetPlayerToCorrectBgGroup(Player* player, TeamId teamId)
}
}
// This method should be called only once ... it adds pointer to queue
void Battleground::AddToBGFreeSlotQueue()
{
if (!_InBGFreeSlotQueue && isBattleground())
{
sBattlegroundMgr->AddToBGFreeSlotQueue(m_RealTypeID, this);
_InBGFreeSlotQueue = true;
}
}
// This method removes this battleground from free queue - it must be called when deleting battleground
void Battleground::RemoveFromBGFreeSlotQueue()
{
if (_InBGFreeSlotQueue)
{
sBattlegroundMgr->RemoveFromBGFreeSlotQueue(m_RealTypeID, m_InstanceID);
_InBGFreeSlotQueue = false;
}
}
uint32 Battleground::GetFreeSlotsForTeam(TeamId teamId) const
{
if (!(GetStatus() == STATUS_IN_PROGRESS || GetStatus() == STATUS_WAIT_JOIN))
@@ -1611,6 +1672,7 @@ void Battleground::SendMessage2ToAll(uint32 entry, ChatMsg type, Player const* s
void Battleground::EndNow()
{
RemoveFromBGFreeSlotQueue();
SetStatus(STATUS_WAIT_LEAVE);
SetEndTime(0);
}
@@ -1777,6 +1839,12 @@ GraveyardStruct const* Battleground::GetClosestGraveyard(Player* player)
return sGraveyard->GetClosestGraveyard(player, player->GetBgTeamId());
}
void Battleground::SetBracket(PvPDifficultyEntry const* bracketEntry)
{
m_BracketId = bracketEntry->GetBracketId();
SetLevelRange(bracketEntry->minLevel, bracketEntry->maxLevel);
}
void Battleground::StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry)
{
for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
@@ -316,6 +316,7 @@ public:
// Get methods:
[[nodiscard]] std::string GetName() const { return m_Name; }
[[nodiscard]] BattlegroundTypeId GetBgTypeID(bool GetRandom = false) const { return GetRandom ? m_RandomTypeID : m_RealTypeID; }
[[nodiscard]] BattlegroundBracketId GetBracketId() const { return m_BracketId; }
[[nodiscard]] uint32 GetInstanceID() const { return m_InstanceID; }
[[nodiscard]] BattlegroundStatus GetStatus() const { return m_Status; }
[[nodiscard]] uint32 GetClientInstanceID() const { return m_ClientInstanceID; }
@@ -341,6 +342,7 @@ public:
void SetName(std::string_view name) { m_Name = std::string(name); }
void SetBgTypeID(BattlegroundTypeId TypeID) { m_RealTypeID = TypeID; }
void SetRandomTypeID(BattlegroundTypeId TypeID) { m_RandomTypeID = TypeID; }
void SetBracket(PvPDifficultyEntry const* bracketEntry);
void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; }
void SetStatus(BattlegroundStatus Status) { m_Status = Status; }
void SetClientInstanceID(uint32 InstanceID) { m_ClientInstanceID = InstanceID; }
@@ -361,6 +363,9 @@ public:
void SetMaxPlayersPerTeam(uint32 MaxPlayers) { m_MaxPlayersPerTeam = MaxPlayers; }
void SetMinPlayersPerTeam(uint32 MinPlayers) { m_MinPlayersPerTeam = MinPlayers; }
void AddToBGFreeSlotQueue(); // this queue will be useful when more battlegrounds instances will be available
void RemoveFromBGFreeSlotQueue(); // this method could delete whole BG instance, if another free is available
void DecreaseInvitedCount(TeamId teamId) { if (m_BgInvitedPlayers[teamId]) --m_BgInvitedPlayers[teamId]; }
void IncreaseInvitedCount(TeamId teamId) { ++m_BgInvitedPlayers[teamId]; }
[[nodiscard]] uint32 GetInvitedCount(TeamId teamId) const { return m_BgInvitedPlayers[teamId]; }
@@ -642,7 +647,9 @@ private:
uint32 m_ValidStartPositionTimer;
int32 m_EndTime; // it is set to 120000 when bg is ending and it decreases itself
uint32 m_LastResurrectTime;
BattlegroundBracketId m_BracketId{ BG_BRACKET_ID_FIRST };
uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5
bool _InBGFreeSlotQueue{ false }; // used to make sure that BG is only once inserted into the BattlegroundMgr.BGFreeSlotQueue[bgTypeId] deque
bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave
bool m_IsArena;
PvPTeamId m_WinnerId;
+261 -130
View File
@@ -48,15 +48,22 @@
#include "WorldPacket.h"
#include <unordered_map>
bool BattlegroundTemplate::IsArena() const
{
return BattlemasterEntry->type == MAP_ARENA;
}
/*********************************************************/
/*** BATTLEGROUND MANAGER ***/
/*********************************************************/
BattlegroundMgr::BattlegroundMgr() : m_ArenaTesting(false), m_Testing(false),
m_lastClientVisibleInstanceId(0), m_NextAutoDistributionTime(0), m_AutoDistributionTimeChecker(0), m_NextPeriodicQueueUpdateTime(5 * IN_MILLISECONDS)
BattlegroundMgr::BattlegroundMgr() :
m_ArenaTesting(false),
m_Testing(false),
m_NextAutoDistributionTime(0),
m_AutoDistributionTimeChecker(0),
m_NextPeriodicQueueUpdateTime(5 * IN_MILLISECONDS)
{
for (uint32 qtype = BATTLEGROUND_QUEUE_NONE; qtype < MAX_BATTLEGROUND_QUEUE_TYPES; ++qtype)
m_BattlegroundQueues[qtype].SetBgTypeIdAndArenaType(BGTemplateId(BattlegroundQueueTypeId(qtype)), BGArenaType(BattlegroundQueueTypeId(qtype)));
}
BattlegroundMgr::~BattlegroundMgr()
@@ -72,47 +79,68 @@ BattlegroundMgr* BattlegroundMgr::instance()
void BattlegroundMgr::DeleteAllBattlegrounds()
{
while (!m_Battlegrounds.empty())
delete m_Battlegrounds.begin()->second;
m_Battlegrounds.clear();
for (auto& [_, data] : bgDataStore)
{
while (!data._Battlegrounds.empty())
delete data._Battlegrounds.begin()->second;
while (!m_BattlegroundTemplates.empty())
delete m_BattlegroundTemplates.begin()->second;
m_BattlegroundTemplates.clear();
data._Battlegrounds.clear();
while (!data.BGFreeSlotQueue.empty())
delete data.BGFreeSlotQueue.front();
}
bgDataStore.clear();
}
// used to update running battlegrounds, and delete finished ones
void BattlegroundMgr::Update(uint32 diff)
{
// update all battlegrounds and delete if needed
for (BattlegroundContainer::iterator itr = m_Battlegrounds.begin(), itrDelete; itr != m_Battlegrounds.end(); )
for (auto& [_, bgData] : bgDataStore)
{
itrDelete = itr++;
Battleground* bg = itrDelete->second;
bg->Update(diff);
if (bg->ToBeDeleted())
auto& bgList = bgData._Battlegrounds;
auto itrDelete = bgList.begin();
// first one is template and should not be deleted
for (BattlegroundContainer::iterator itr = ++itrDelete; itr != bgList.end();)
{
itrDelete->second = nullptr;
m_Battlegrounds.erase(itrDelete);
delete bg;
itrDelete = itr++;
Battleground* bg = itrDelete->second;
bg->Update(diff);
if (bg->ToBeDeleted())
{
itrDelete->second = nullptr;
bgList.erase(itrDelete);
BattlegroundClientIdsContainer& clients = bgData._ClientBattlegroundIds[bg->GetBracketId()];
if (!clients.empty())
clients.erase(bg->GetClientInstanceID());
delete bg;
}
}
}
// update events
for (int qtype = BATTLEGROUND_QUEUE_NONE; qtype < MAX_BATTLEGROUND_QUEUE_TYPES; ++qtype)
for (uint8 qtype = BATTLEGROUND_QUEUE_NONE; qtype < MAX_BATTLEGROUND_QUEUE_TYPES; ++qtype)
m_BattlegroundQueues[qtype].UpdateEvents(diff);
// update using scheduled tasks (used only for rated arenas, initial opponent search works differently than periodic queue update)
if (!m_ArenaQueueUpdateScheduler.empty())
if (!m_QueueUpdateScheduler.empty())
{
std::vector<uint64> scheduled;
std::swap(scheduled, m_ArenaQueueUpdateScheduler);
std::swap(scheduled, m_QueueUpdateScheduler);
for (uint8 i = 0; i < scheduled.size(); i++)
{
uint32 arenaRatedTeamId = scheduled[i] >> 32;
uint32 arenaMMRating = scheduled[i] >> 32;
uint8 arenaType = scheduled[i] >> 24 & 255;
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundQueueTypeId(scheduled[i] >> 16 & 255);
BattlegroundTypeId bgTypeId = BattlegroundTypeId((scheduled[i] >> 8) & 255);
BattlegroundBracketId bracket_id = BattlegroundBracketId(scheduled[i] & 255);
m_BattlegroundQueues[bgQueueTypeId].BattlegroundQueueUpdate(diff, bracket_id, true, arenaRatedTeamId); // pussywizard: looking for opponents only for this team
m_BattlegroundQueues[bgQueueTypeId].BattlegroundQueueUpdate(diff, bgTypeId, bracket_id, arenaType, arenaMMRating > 0, arenaMMRating);
}
}
@@ -121,16 +149,16 @@ void BattlegroundMgr::Update(uint32 diff)
{
m_NextPeriodicQueueUpdateTime = 5 * IN_MILLISECONDS;
LOG_TRACE("bg.arena", "BattlegroundMgr: UPDATING ARENA QUEUES");
// for rated arenas
for (uint32 qtype = BATTLEGROUND_QUEUE_2v2; qtype < MAX_BATTLEGROUND_QUEUE_TYPES; ++qtype)
{
for (uint32 bracket = BG_BRACKET_ID_FIRST; bracket < MAX_BATTLEGROUND_BRACKETS; ++bracket)
m_BattlegroundQueues[qtype].BattlegroundQueueUpdate(m_NextPeriodicQueueUpdateTime, BattlegroundBracketId(bracket), true, 0); // pussywizard: 0 for rated means looking for opponents for every team
// for battlegrounds and not rated arenas
// in first loop try to fill already running battlegrounds, then in a second loop try to create new battlegrounds
for (uint32 qtype = BATTLEGROUND_QUEUE_AV; qtype < MAX_BATTLEGROUND_QUEUE_TYPES; ++qtype)
for (uint32 bracket = BG_BRACKET_ID_FIRST; bracket < MAX_BATTLEGROUND_BRACKETS; ++bracket)
m_BattlegroundQueues[qtype].BattlegroundQueueUpdate(m_NextPeriodicQueueUpdateTime, BattlegroundBracketId(bracket), false, 0);
{
m_BattlegroundQueues[qtype].BattlegroundQueueUpdate(diff, BATTLEGROUND_AA, BattlegroundBracketId(bracket), BattlegroundMgr::BGArenaType(BattlegroundQueueTypeId(qtype)), true, 0);
}
}
}
else
m_NextPeriodicQueueUpdateTime -= diff;
@@ -225,36 +253,108 @@ void BattlegroundMgr::BuildPlayerJoinedBattlegroundPacket(WorldPacket* data, Pla
*data << player->GetGUID();
}
Battleground* BattlegroundMgr::GetBattleground(uint32 instanceId)
Battleground* BattlegroundMgr::GetBattlegroundThroughClientInstance(uint32 instanceId, BattlegroundTypeId bgTypeId)
{
//cause at HandleBattlegroundJoinOpcode the clients sends the instanceid he gets from
//SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id
Battleground* bg = GetBattlegroundTemplate(bgTypeId);
if (!bg)
return nullptr;
if (bg->isArena())
return GetBattleground(instanceId, bgTypeId);
auto const& it = bgDataStore.find(bgTypeId);
if (it == bgDataStore.end())
return nullptr;
for (auto const& itr : it->second._Battlegrounds)
{
if (itr.second->GetClientInstanceID() == instanceId)
return itr.second;
}
return nullptr;
}
Battleground* BattlegroundMgr::GetBattleground(uint32 instanceId, BattlegroundTypeId bgTypeId)
{
if (!instanceId)
return nullptr;
BattlegroundContainer::const_iterator itr = m_Battlegrounds.find(instanceId);
if (itr != m_Battlegrounds.end())
return itr->second;
auto GetBgWithInstanceID = [instanceId](BattlegroundData const* bgData) -> Battleground*
{
auto const& itr = bgData->_Battlegrounds.find(instanceId);
if (itr != bgData->_Battlegrounds.end())
return itr->second;
return nullptr;
};
if (bgTypeId == BATTLEGROUND_TYPE_NONE)
{
for (auto const& [bgType, bgData] : bgDataStore)
{
if (auto bg = GetBgWithInstanceID(&bgData))
return bg;
}
}
else
{
auto const& itr = bgDataStore.find(bgTypeId);
if (itr == bgDataStore.end())
return nullptr;
if (auto bg = GetBgWithInstanceID(&itr->second))
return bg;
}
return nullptr;
}
Battleground* BattlegroundMgr::GetBattlegroundTemplate(BattlegroundTypeId bgTypeId)
{
BattlegroundTemplateContainer::const_iterator itr = m_BattlegroundTemplates.find(bgTypeId);
if (itr != m_BattlegroundTemplates.end())
return itr->second;
BattlegroundDataContainer::const_iterator itr = bgDataStore.find(bgTypeId);
if (itr == bgDataStore.end())
return nullptr;
return nullptr;
BattlegroundContainer const& bgs = itr->second._Battlegrounds;
// map is sorted and we can be sure that lowest instance id has only BG template
return bgs.empty() ? nullptr : bgs.begin()->second;
}
uint32 BattlegroundMgr::GetNextClientVisibleInstanceId()
uint32 BattlegroundMgr::CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id)
{
return ++m_lastClientVisibleInstanceId;
if (IsArenaType(bgTypeId))
return 0; // arenas don't have client-instanceids
// we create here an instanceid, which is just for
// displaying this to the client and without any other use..
// the client-instanceIds are unique for each battleground-type
// the instance-id just needs to be as low as possible, beginning with 1
// the following works, because std::set is default ordered with "<"
// the optimalization would be to use as bitmask std::vector<uint32> - but that would only make code unreadable
BattlegroundClientIdsContainer& clientIds = bgDataStore[bgTypeId]._ClientBattlegroundIds[bracket_id];
uint32 lastId = 0;
for (BattlegroundClientIdsContainer::const_iterator itr = clientIds.begin(); itr != clientIds.end();)
{
if ((++lastId) != *itr) // if there is a gap between the ids, we will break..
break;
lastId = *itr;
}
clientIds.emplace(++lastId);
return lastId;
}
// create a new battleground that will really be used to play
Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId originalBgTypeId, uint32 minLevel, uint32 maxLevel, uint8 arenaType, bool isRated)
Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId originalBgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 arenaType, bool isRated)
{
BattlegroundTypeId bgTypeId = GetRandomBG(originalBgTypeId, minLevel);
BattlegroundTypeId bgTypeId = GetRandomBG(originalBgTypeId, bracketEntry->minLevel);
if (originalBgTypeId == BATTLEGROUND_AA)
originalBgTypeId = bgTypeId;
@@ -262,9 +362,13 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId original
// get the template BG
Battleground* bg_template = GetBattlegroundTemplate(bgTypeId);
if (!bg_template)
{
LOG_ERROR("bg.battleground", "Battleground: CreateNewBattleground - bg template not found for {}", bgTypeId);
return nullptr;
}
Battleground* bg = nullptr;
// create a copy of the BG template
if (BattlegroundMgr::bgTypeToTemplate.find(bgTypeId) == BattlegroundMgr::bgTypeToTemplate.end())
{
@@ -275,9 +379,9 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId original
bool isRandom = bgTypeId != originalBgTypeId && !bg->isArena();
bg->SetLevelRange(minLevel, maxLevel);
bg->SetBracket(bracketEntry);
bg->SetInstanceID(sMapMgr->GenerateInstanceId());
bg->SetClientInstanceID(IsArenaType(originalBgTypeId) ? 0 : GetNextClientVisibleInstanceId());
bg->SetClientInstanceID(CreateClientVisibleInstanceId(originalBgTypeId, bracketEntry->GetBracketId()));
bg->Init();
bg->SetStatus(STATUS_WAIT_JOIN); // start the joining of the bg
bg->SetArenaType(arenaType);
@@ -298,37 +402,40 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId original
}
// used to create the BG templates
bool BattlegroundMgr::CreateBattleground(CreateBattlegroundData& data)
bool BattlegroundMgr::CreateBattleground(BattlegroundTemplate const* bgTemplate)
{
// Create the BG
Battleground* bg = nullptr;
bg = BattlegroundMgr::bgtypeToBattleground[data.bgTypeId];
Battleground* bg = GetBattlegroundTemplate(bgTemplate->Id);
if (bg == nullptr)
return false;
if (!bg)
{
bg = BattlegroundMgr::bgtypeToBattleground[bgTemplate->Id];
if (data.bgTypeId == BATTLEGROUND_RB)
bg->SetRandom(true);
ASSERT(bg);
bg->SetMapId(data.MapID);
bg->SetBgTypeID(data.bgTypeId);
bg->SetInstanceID(0);
bg->SetArenaorBGType(data.IsArena);
bg->SetMinPlayersPerTeam(data.MinPlayersPerTeam);
bg->SetMaxPlayersPerTeam(data.MaxPlayersPerTeam);
bg->SetName(data.BattlegroundName);
bg->SetTeamStartPosition(TEAM_ALLIANCE, data.StartLocation[TEAM_ALLIANCE]);
bg->SetTeamStartPosition(TEAM_HORDE, data.StartLocation[TEAM_HORDE]);
bg->SetStartMaxDist(data.StartMaxDist);
bg->SetLevelRange(data.LevelMin, data.LevelMax);
bg->SetScriptId(data.scriptId);
if (bgTemplate->Id == BATTLEGROUND_RB)
bg->SetRandom(true);
AddBattleground(bg);
bg->SetBgTypeID(bgTemplate->Id);
bg->SetInstanceID(0);
AddBattleground(bg);
}
bg->SetMapId(bgTemplate->BattlemasterEntry->mapid[0]);
bg->SetName(bgTemplate->BattlemasterEntry->name[sWorld->GetDefaultDbcLocale()]);
bg->SetArenaorBGType(bgTemplate->IsArena());
bg->SetMinPlayersPerTeam(bgTemplate->MinPlayersPerTeam);
bg->SetMaxPlayersPerTeam(bgTemplate->MaxPlayersPerTeam);
bg->SetTeamStartPosition(TEAM_ALLIANCE, bgTemplate->StartLocation[TEAM_ALLIANCE]);
bg->SetTeamStartPosition(TEAM_HORDE, bgTemplate->StartLocation[TEAM_HORDE]);
bg->SetStartMaxDist(bgTemplate->MaxStartDistSq);
bg->SetLevelRange(bgTemplate->MinLevel, bgTemplate->MaxLevel);
bg->SetScriptId(bgTemplate->ScriptId);
return true;
}
void BattlegroundMgr::CreateInitialBattlegrounds()
void BattlegroundMgr::LoadBattlegroundTemplates()
{
uint32 oldMSTime = getMSTime();
@@ -344,13 +451,11 @@ void BattlegroundMgr::CreateInitialBattlegrounds()
return;
}
uint32 count = 0;
do
{
Field* fields = result->Fetch();
uint32 bgTypeId = fields[0].Get<uint32>();
BattlegroundTypeId bgTypeId = static_cast<BattlegroundTypeId>(fields[0].Get<uint32>());
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId, nullptr))
continue;
@@ -363,72 +468,69 @@ void BattlegroundMgr::CreateInitialBattlegrounds()
continue;
}
CreateBattlegroundData data;
data.bgTypeId = BattlegroundTypeId(bgTypeId);
data.IsArena = (bl->type == TYPE_ARENA);
data.MinPlayersPerTeam = fields[1].Get<uint16>();
data.MaxPlayersPerTeam = fields[2].Get<uint16>();
data.LevelMin = fields[3].Get<uint8>();
data.LevelMax = fields[4].Get<uint8>();
BattlegroundTemplate bgTemplate;
bgTemplate.Id = bgTypeId;
bgTemplate.MinPlayersPerTeam = fields[1].Get<uint16>();
bgTemplate.MaxPlayersPerTeam = fields[2].Get<uint16>();
bgTemplate.MinLevel = fields[3].Get<uint8>();
bgTemplate.MaxLevel = fields[4].Get<uint8>();
float dist = fields[9].Get<float>();
data.StartMaxDist = dist * dist;
data.Weight = fields[10].Get<uint8>();
bgTemplate.MaxStartDistSq = dist * dist;
bgTemplate.Weight = fields[10].Get<uint8>();
bgTemplate.ScriptId = sObjectMgr->GetScriptId(fields[11].Get<std::string>());
bgTemplate.BattlemasterEntry = bl;
data.scriptId = sObjectMgr->GetScriptId(fields[11].Get<std::string>());
data.BattlegroundName = bl->name[sWorld->GetDefaultDbcLocale()];
data.MapID = bl->mapid[0];
if (data.MaxPlayersPerTeam == 0 || data.MinPlayersPerTeam > data.MaxPlayersPerTeam)
if (bgTemplate.MaxPlayersPerTeam == 0 || bgTemplate.MinPlayersPerTeam > bgTemplate.MaxPlayersPerTeam)
{
LOG_ERROR("bg.battleground", "Table `battleground_template` for id {} has bad values for MinPlayersPerTeam ({}) and MaxPlayersPerTeam({})",
data.bgTypeId, data.MinPlayersPerTeam, data.MaxPlayersPerTeam);
LOG_ERROR("sql.sql", "Table `battleground_template` for id {} contains bad values for MinPlayersPerTeam ({}) and MaxPlayersPerTeam({}).",
bgTemplate.Id, bgTemplate.MinPlayersPerTeam, bgTemplate.MaxPlayersPerTeam);
continue;
}
if (data.LevelMin == 0 || data.LevelMax == 0 || data.LevelMin > data.LevelMax)
if (bgTemplate.MinLevel == 0 || bgTemplate.MaxLevel == 0 || bgTemplate.MinLevel > bgTemplate.MaxLevel)
{
LOG_ERROR("bg.battleground", "Table `battleground_template` for id {} has bad values for LevelMin ({}) and LevelMax({})",
data.bgTypeId, data.LevelMin, data.LevelMax);
LOG_ERROR("sql.sql", "Table `battleground_template` for id {} has bad values for LevelMin ({}) and LevelMax({})",
bgTemplate.Id, bgTemplate.MinLevel, bgTemplate.MaxLevel);
continue;
}
if (data.bgTypeId != BATTLEGROUND_AA && data.bgTypeId != BATTLEGROUND_RB)
if (bgTemplate.Id != BATTLEGROUND_AA && bgTemplate.Id != BATTLEGROUND_RB)
{
uint32 startId = fields[5].Get<uint32>();
if (GraveyardStruct const* start = sGraveyard->GetGraveyard(startId))
{
data.StartLocation[TEAM_ALLIANCE].Relocate(start->x, start->y, start->z, fields[6].Get<float>());
bgTemplate.StartLocation[TEAM_ALLIANCE].Relocate(start->x, start->y, start->z, fields[6].Get<float>());
}
else
{
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);
LOG_ERROR("sql.sql", "Table `battleground_template` for id {} contains a non-existing WorldSafeLocs.dbc id {} in field `AllianceStartLoc`. BG not created.", bgTemplate.Id, startId);
continue;
}
startId = fields[7].Get<uint32>();
if (GraveyardStruct const* start = sGraveyard->GetGraveyard(startId))
{
data.StartLocation[TEAM_HORDE].Relocate(start->x, start->y, start->z, fields[8].Get<float>());
bgTemplate.StartLocation[TEAM_HORDE].Relocate(start->x, start->y, start->z, fields[8].Get<float>());
}
else
{
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);
LOG_ERROR("sql.sql", "Table `battleground_template` for id {} contains a non-existing WorldSafeLocs.dbc id {} in field `HordeStartLoc`. BG not created.", bgTemplate.Id, startId);
continue;
}
}
if (!CreateBattleground(data))
if (!CreateBattleground(&bgTemplate))
continue;
_battlegroundTemplates[BattlegroundTypeId(bgTypeId)] = data;
_battlegroundTemplates[bgTypeId] = bgTemplate;
if (bl->mapid[1] == -1) // in this case we have only one mapId
_battlegroundMapTemplates[bl->mapid[0]] = &_battlegroundTemplates[BattlegroundTypeId(bgTypeId)];
if (bgTemplate.BattlemasterEntry->mapid[1] == -1) // in this case we have only one mapId
_battlegroundMapTemplates[bgTemplate.BattlemasterEntry->mapid[0]] = &_battlegroundTemplates[bgTypeId];
++count;
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded {} battlegrounds in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", ">> Loaded {} battlegrounds in {} ms", _battlegroundTemplates.size(), GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
@@ -499,23 +601,31 @@ void BattlegroundMgr::BuildBattlegroundListPacket(WorldPacket* data, ObjectGuid
size_t count_pos = data->wpos();
*data << uint32(0); // number of bg instances
if (Battleground* bgt = GetBattlegroundTemplate(bgTypeId))
if (GetBattlegroundBracketByLevel(bgt->GetMapId(), player->getLevel()))
auto const& it = bgDataStore.find(bgTypeId);
if (it != bgDataStore.end())
{
// expected bracket entry
if (PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(it->second._Battlegrounds.begin()->second->GetMapId(), player->getLevel()))
{
uint32 count = 0;
/*for (BattlegroundClientIdsContainer::const_iterator itr = clientIds.begin(); itr != clientIds.end(); ++itr)
BattlegroundBracketId bracketId = bracketEntry->GetBracketId();
BattlegroundClientIdsContainer& clientIds = it->second._ClientBattlegroundIds[bracketId];
for (auto const& itr : clientIds)
{
*data << uint32(*itr);
*data << uint32(itr);
++count;
}*/
}
data->put<uint32>(count_pos, count);
}
}
}
}
void BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, BattlegroundTypeId bgTypeId)
{
if (Battleground* bg = GetBattleground(instanceId))
if (Battleground* bg = GetBattleground(instanceId, bgTypeId))
{
uint32 mapid = bg->GetMapId();
Position const* pos = bg->GetTeamStartPosition(player->GetBgTeamId());
@@ -636,11 +746,25 @@ void BattlegroundMgr::SetHolidayWeekends(uint32 mask)
}
}
void BattlegroundMgr::ScheduleArenaQueueUpdate(uint32 arenaRatedTeamId, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundBracketId bracket_id)
void BattlegroundMgr::ScheduleQueueUpdate(uint32 arenaMatchmakerRating, uint8 arenaType, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id)
{
uint64 const scheduleId = ((uint64)arenaRatedTeamId << 32) | (bgQueueTypeId << 16) | bracket_id;
if (std::find(m_ArenaQueueUpdateScheduler.begin(), m_ArenaQueueUpdateScheduler.end(), scheduleId) == m_ArenaQueueUpdateScheduler.end())
m_ArenaQueueUpdateScheduler.push_back(scheduleId);
//This method must be atomic, @todo add mutex
//we will use only 1 number created of bgTypeId and bracket_id
uint64 const scheduleId = ((uint64)arenaMatchmakerRating << 32) | ((uint64)arenaType << 24) | ((uint64)bgQueueTypeId << 16) | ((uint64)bgTypeId << 8) | (uint64)bracket_id;
if (std::find(m_QueueUpdateScheduler.begin(), m_QueueUpdateScheduler.end(), scheduleId) == m_QueueUpdateScheduler.end())
m_QueueUpdateScheduler.emplace_back(scheduleId);
}
uint32 BattlegroundMgr::GetMaxRatingDifference() const
{
uint32 diff = sWorld->getIntConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
if (diff == 0)
{
diff = 5000;
}
return diff;
}
uint32 BattlegroundMgr::GetRatingDiscardTimer() const
@@ -766,24 +890,23 @@ bool BattlegroundMgr::IsBGWeekend(BattlegroundTypeId bgTypeId)
BattlegroundTypeId BattlegroundMgr::GetRandomBG(BattlegroundTypeId bgTypeId, uint32 minLevel)
{
if (GetBattlegroundTemplateByTypeId(bgTypeId))
if (BattlegroundTemplate const* bgTemplate = GetBattlegroundTemplateByTypeId(bgTypeId))
{
std::vector<BattlegroundTypeId> ids;
ids.reserve(16);
std::vector<double> weights;
weights.reserve(16);
BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
for (int32 mapId : bl->mapid)
for (int32 mapId : bgTemplate->BattlemasterEntry->mapid)
{
if (mapId == -1)
break;
if (CreateBattlegroundData const* bg = GetBattlegroundTemplateByMapId(mapId))
if (BattlegroundTemplate const* bg = GetBattlegroundTemplateByMapId(mapId))
{
if (bg->LevelMin <= minLevel)
if (bg->MinLevel <= minLevel)
{
ids.push_back(bg->bgTypeId);
ids.push_back(bg->Id);
weights.push_back(bg->Weight);
}
}
@@ -795,30 +918,38 @@ BattlegroundTypeId BattlegroundMgr::GetRandomBG(BattlegroundTypeId bgTypeId, uin
return BATTLEGROUND_TYPE_NONE;
}
BGFreeSlotQueueContainer& BattlegroundMgr::GetBGFreeSlotQueueStore(BattlegroundTypeId bgTypeId)
{
return bgDataStore[bgTypeId].BGFreeSlotQueue;
}
void BattlegroundMgr::AddToBGFreeSlotQueue(BattlegroundTypeId bgTypeId, Battleground* bg)
{
bgDataStore[bgTypeId].BGFreeSlotQueue.push_front(bg);
}
void BattlegroundMgr::RemoveFromBGFreeSlotQueue(BattlegroundTypeId bgTypeId, uint32 instanceId)
{
BGFreeSlotQueueContainer& queues = bgDataStore[bgTypeId].BGFreeSlotQueue;
for (BGFreeSlotQueueContainer::iterator itr = queues.begin(); itr != queues.end(); ++itr)
if ((*itr)->GetInstanceID() == instanceId)
{
queues.erase(itr);
return;
}
}
void BattlegroundMgr::AddBattleground(Battleground* bg)
{
if (bg->GetInstanceID() == 0)
m_BattlegroundTemplates[bg->GetBgTypeID()] = bg;
else
m_Battlegrounds[bg->GetInstanceID()] = bg;
if (bg)
bgDataStore[bg->GetBgTypeID()]._Battlegrounds[bg->GetInstanceID()] = bg;
sScriptMgr->OnBattlegroundCreate(bg);
}
void BattlegroundMgr::RemoveBattleground(BattlegroundTypeId bgTypeId, uint32 instanceId)
{
if (instanceId == 0)
m_BattlegroundTemplates.erase(bgTypeId);
else
m_Battlegrounds.erase(instanceId);
}
void BattlegroundMgr::DoForAllBattlegrounds(std::function<void(Battleground*)> const& worker)
{
for (auto const& [_, bg] : m_Battlegrounds)
{
worker(bg);
}
bgDataStore[bgTypeId]._Battlegrounds.erase(instanceId);
}
// init/update unordered_map
+47 -36
View File
@@ -27,29 +27,38 @@
#include <functional>
typedef std::map<uint32, Battleground*> BattlegroundContainer;
typedef std::set<uint32> BattlegroundClientIdsContainer;
typedef std::unordered_map<uint32, BattlegroundTypeId> BattleMastersMap;
typedef Battleground* (*bgRef)(Battleground*);
typedef void(*bgMapRef)(WorldPacket*, Battleground::BattlegroundScoreMap::const_iterator);
typedef void(*bgTypeRef)(WorldPacket*, Battleground::BattlegroundScoreMap::const_iterator, Battleground*);
struct CreateBattlegroundData
// this container can't be deque, because deque doesn't like removing the last element - if you remove it, it invalidates next iterator and crash appears
using BGFreeSlotQueueContainer = std::list<Battleground*>;
struct BattlegroundData
{
BattlegroundTypeId bgTypeId;
bool IsArena;
uint32 MinPlayersPerTeam;
uint32 MaxPlayersPerTeam;
uint32 LevelMin;
uint32 LevelMax;
char const* BattlegroundName;
uint32 MapID;
float StartMaxDist;
std::array<Position, PVP_TEAMS_COUNT> StartLocation;
uint32 scriptId;
uint8 Weight;
BattlegroundContainer _Battlegrounds;
std::array<BattlegroundClientIdsContainer, MAX_BATTLEGROUND_BRACKETS> _ClientBattlegroundIds;
BGFreeSlotQueueContainer BGFreeSlotQueue;
};
struct GroupQueueInfo;
struct BattlegroundTemplate
{
BattlegroundTypeId Id;
uint16 MinPlayersPerTeam;
uint16 MaxPlayersPerTeam;
uint8 MinLevel;
uint8 MaxLevel;
std::array<Position, PVP_TEAMS_COUNT> StartLocation;
float MaxStartDistSq;
uint8 Weight;
uint32 ScriptId;
BattlemasterListEntry const* BattlemasterEntry;
bool IsArena() const;
};
class BattlegroundMgr
{
@@ -71,21 +80,25 @@ public:
void SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, ObjectGuid guid);
/* Battlegrounds */
Battleground* GetBattleground(uint32 InstanceID);
Battleground* GetBattlegroundThroughClientInstance(uint32 instanceId, BattlegroundTypeId bgTypeId);
Battleground* GetBattleground(uint32 instanceID, BattlegroundTypeId bgTypeId);
Battleground* GetBattlegroundTemplate(BattlegroundTypeId bgTypeId);
Battleground* CreateNewBattleground(BattlegroundTypeId bgTypeId, uint32 minLevel, uint32 maxLevel, uint8 arenaType, bool isRated);
Battleground* CreateNewBattleground(BattlegroundTypeId bgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 arenaType, bool isRated);
void AddBattleground(Battleground* bg);
void RemoveBattleground(BattlegroundTypeId bgTypeId, uint32 instanceId);
void AddToBGFreeSlotQueue(BattlegroundTypeId bgTypeId, Battleground* bg);
void RemoveFromBGFreeSlotQueue(BattlegroundTypeId bgTypeId, uint32 instanceId);
BGFreeSlotQueueContainer& GetBGFreeSlotQueueStore(BattlegroundTypeId bgTypeId);
void CreateInitialBattlegrounds();
void LoadBattlegroundTemplates();
void DeleteAllBattlegrounds();
void SendToBattleground(Player* player, uint32 InstanceID, BattlegroundTypeId bgTypeId);
/* Battleground queues */
BattlegroundQueue& GetBattlegroundQueue(BattlegroundQueueTypeId bgQueueTypeId) { return m_BattlegroundQueues[bgQueueTypeId]; }
void ScheduleArenaQueueUpdate(uint32 arenaRatedTeamId, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundBracketId bracket_id);
void ScheduleQueueUpdate(uint32 arenaMatchmakerRating, uint8 arenaType, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id);
uint32 GetPrematureFinishTime() const;
void ToggleArenaTesting();
@@ -105,10 +118,12 @@ public:
static BattlegroundTypeId WeekendHolidayIdToBGType(HolidayIds holiday);
static bool IsBGWeekend(BattlegroundTypeId bgTypeId);
uint32 GetRatingDiscardTimer() const;
uint32 GetMaxRatingDifference() const;
uint32 GetRatingDiscardTimer() const;
void InitAutomaticArenaPointDistribution();
void LoadBattleMastersEntry();
void CheckBattleMasters();
BattlegroundTypeId GetBattleMasterBG(uint32 entry) const
{
BattleMastersMap::const_iterator itr = mBattleMastersMap.find(entry);
@@ -117,8 +132,6 @@ public:
return BATTLEGROUND_TYPE_NONE;
}
const BattlegroundContainer& GetBattlegroundList() { return m_Battlegrounds; } // pussywizard
static std::unordered_map<int, BattlegroundQueueTypeId> bgToQueue; // BattlegroundTypeId -> BattlegroundQueueTypeId
static std::unordered_map<int, BattlegroundTypeId> queueToBg; // BattlegroundQueueTypeId -> BattlegroundTypeId
static std::unordered_map<int, Battleground*> bgtypeToBattleground; // BattlegroundTypeId -> Battleground*
@@ -128,48 +141,46 @@ public:
static std::unordered_map<uint32, BattlegroundQueueTypeId> ArenaTypeToQueue; // ArenaType -> BattlegroundQueueTypeId
static std::unordered_map<uint32, ArenaType> QueueToArenaType; // BattlegroundQueueTypeId -> ArenaType
void DoForAllBattlegrounds(std::function<void(Battleground*)> const& worker);
private:
bool CreateBattleground(CreateBattlegroundData& data);
uint32 GetNextClientVisibleInstanceId();
bool CreateBattleground(BattlegroundTemplate const* bgTemplate);
uint32 CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id);
BattlegroundTypeId GetRandomBG(BattlegroundTypeId id, uint32 minLevel);
typedef std::map<BattlegroundTypeId, Battleground*> BattlegroundTemplateContainer;
BattlegroundTemplateContainer m_BattlegroundTemplates;
BattlegroundContainer m_Battlegrounds;
typedef std::map<BattlegroundTypeId, BattlegroundData> BattlegroundDataContainer;
BattlegroundDataContainer bgDataStore;
BattlegroundQueue m_BattlegroundQueues[MAX_BATTLEGROUND_QUEUE_TYPES];
std::vector<uint64> m_ArenaQueueUpdateScheduler;
std::vector<uint64> m_QueueUpdateScheduler;
bool m_ArenaTesting;
bool m_Testing;
uint32 m_lastClientVisibleInstanceId;
Seconds m_NextAutoDistributionTime;
uint32 m_AutoDistributionTimeChecker;
uint32 m_NextPeriodicQueueUpdateTime;
BattleMastersMap mBattleMastersMap;
CreateBattlegroundData const* GetBattlegroundTemplateByTypeId(BattlegroundTypeId id)
BattlegroundTemplate const* GetBattlegroundTemplateByTypeId(BattlegroundTypeId id)
{
BattlegroundTemplateMap::const_iterator itr = _battlegroundTemplates.find(id);
auto const& itr = _battlegroundTemplates.find(id);
if (itr != _battlegroundTemplates.end())
return &itr->second;
return nullptr;
}
CreateBattlegroundData const* GetBattlegroundTemplateByMapId(uint32 mapId)
BattlegroundTemplate const* GetBattlegroundTemplateByMapId(uint32 mapId)
{
BattlegroundMapTemplateContainer::const_iterator itr = _battlegroundMapTemplates.find(mapId);
auto const& itr = _battlegroundMapTemplates.find(mapId);
if (itr != _battlegroundMapTemplates.end())
return itr->second;
return nullptr;
}
typedef std::map<BattlegroundTypeId, uint8 /*weight*/> BattlegroundSelectionWeightMap;
typedef std::map<BattlegroundTypeId, CreateBattlegroundData> BattlegroundTemplateMap;
typedef std::map<uint32 /*mapId*/, CreateBattlegroundData*> BattlegroundMapTemplateContainer;
typedef std::map<BattlegroundTypeId, BattlegroundTemplate> BattlegroundTemplateMap;
typedef std::map<uint32 /*mapId*/, BattlegroundTemplate*> BattlegroundMapTemplateContainer;
BattlegroundTemplateMap _battlegroundTemplates;
BattlegroundMapTemplateContainer _battlegroundMapTemplates;
};
File diff suppressed because it is too large Load Diff
@@ -25,7 +25,7 @@
#include <array>
#include <deque>
#define COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME 10
constexpr auto COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME = 10;
struct GroupQueueInfo // stores information about the group in queue (also used when joined as solo!)
{
@@ -43,10 +43,9 @@ struct GroupQueueInfo // stores informatio
uint32 ArenaMatchmakerRating; // if rated match, inited to the rating of the team
uint32 OpponentsTeamRating; // for rated arena matches
uint32 OpponentsMatchmakerRating; // for rated arena matches
// pussywizard: for internal use
uint8 _bracketId;
uint8 _groupType;
uint32 PreviousOpponentsTeamId; // excluded from the current queue until the timer is met
uint8 BracketId; // BattlegroundBracketId
uint8 GroupType; // BattlegroundQueueGroupTypes
};
enum BattlegroundQueueGroupTypes
@@ -61,22 +60,21 @@ enum BattlegroundQueueGroupTypes
BG_QUEUE_MAX = 10
};
class Battleground;
class BattlegroundQueue
{
public:
BattlegroundQueue();
~BattlegroundQueue();
void BattlegroundQueueUpdate(uint32 diff, BattlegroundBracketId bracket_id, bool isRated, uint32 arenaRatedTeamId);
void BattlegroundQueueUpdate(uint32 diff, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id, uint8 arenaType, bool isRated, uint32 arenaRating);
void UpdateEvents(uint32 diff);
void FillPlayersToBG(Battleground* bg, int32 aliFree, int32 hordeFree, BattlegroundBracketId bracket_id);
void FillPlayersToBG(Battleground* bg, BattlegroundBracketId bracket_id);
bool CheckPremadeMatch(BattlegroundBracketId bracket_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam);
bool CheckNormalMatch(Battleground* bgTemplate, BattlegroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers);
bool CheckSkirmishForSameFaction(BattlegroundBracketId bracket_id, uint32 minPlayersPerTeam);
GroupQueueInfo* AddGroup(Player* leader, Group* group, PvPDifficultyEntry const* bracketEntry, bool isRated, bool isPremade, uint32 ArenaRating, uint32 MatchmakerRating, uint32 ArenaTeamId);
void RemovePlayer(ObjectGuid guid, bool sentToBg, uint32 playerQueueSlot);
GroupQueueInfo* AddGroup(Player* leader, Group* group, BattlegroundTypeId bgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 arenaType, bool isRated, bool isPremade, uint32 arenaRating, uint32 matchmakerRating, uint32 arenaTeamId = 0, uint32 opponentsArenaTeamId = 0);
void RemovePlayer(ObjectGuid guid, bool decreaseInvitedCount);
bool IsPlayerInvitedToRatedArena(ObjectGuid pl_guid);
bool IsPlayerInvited(ObjectGuid pl_guid, uint32 bgInstanceGuid, uint32 removeTime);
bool GetPlayerGroupInfoData(ObjectGuid guid, GroupQueueInfo* ginfo);
@@ -89,7 +87,6 @@ public:
void SendJoinMessageArenaQueue(Player* leader, GroupQueueInfo* ginfo, PvPDifficultyEntry const* bracketEntry, bool isRated);
void SendExitMessageArenaQueue(GroupQueueInfo* ginfo);
void SetBgTypeIdAndArenaType(BattlegroundTypeId b, uint8 a) { m_bgTypeId = b; m_arenaType = ArenaType(a); } // pussywizard
void AddEvent(BasicEvent* Event, uint64 e_time);
typedef std::map<ObjectGuid, GroupQueueInfo*> QueuedPlayersMap;
@@ -127,15 +124,10 @@ public:
//one selection pool for horde, other one for alliance
SelectionPool m_SelectionPools[PVP_TEAMS_COUNT];
ArenaType GetArenaType() { return m_arenaType; }
BattlegroundTypeId GetBGTypeID() { return m_bgTypeId; }
void SetQueueAnnouncementTimer(uint32 bracketId, int32 timer, bool isCrossFactionBG = true);
[[nodiscard]] int32 GetQueueAnnouncementTimer(uint32 bracketId) const;
private:
BattlegroundTypeId m_bgTypeId;
ArenaType m_arenaType;
uint32 m_WaitTimes[PVP_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME];
uint32 m_WaitTimeLastIndex[PVP_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS];
@@ -176,9 +168,8 @@ private:
class BGQueueRemoveEvent : public BasicEvent
{
public:
BGQueueRemoveEvent(ObjectGuid pl_guid, uint32 bgInstanceGUID, BattlegroundQueueTypeId bgQueueTypeId, uint32 removeTime)
: m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_RemoveTime(removeTime), m_BgQueueTypeId(bgQueueTypeId)
{}
BGQueueRemoveEvent(ObjectGuid pl_guid, uint32 bgInstanceGUID, BattlegroundTypeId BgTypeId, BattlegroundQueueTypeId bgQueueTypeId, uint32 removeTime) :
m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_RemoveTime(removeTime), m_BgTypeId(BgTypeId), m_BgQueueTypeId(bgQueueTypeId) { }
~BGQueueRemoveEvent() override = default;
@@ -188,6 +179,7 @@ private:
ObjectGuid m_PlayerGuid;
uint32 m_BgInstanceGUID;
uint32 m_RemoveTime;
BattlegroundTypeId m_BgTypeId;
BattlegroundQueueTypeId m_BgQueueTypeId;
};
+190 -98
View File
@@ -61,19 +61,27 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
}
case CONDITION_ITEM:
{
if (Player* player = object->ToPlayer())
if (Unit* unit = object->ToUnit())
{
// don't allow 0 items (it's checked during table load)
ASSERT(ConditionValue2);
bool checkBank = !!ConditionValue3;
condMeets = player->HasItemCount(ConditionValue1, ConditionValue2, checkBank);
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
// don't allow 0 items (it's checked during table load)
ASSERT(ConditionValue2);
bool checkBank = !!ConditionValue3;
condMeets = player->HasItemCount(ConditionValue1, ConditionValue2, checkBank);
}
}
break;
}
case CONDITION_ITEM_EQUIPPED:
{
if (Player* player = object->ToPlayer())
condMeets = player->HasItemOrGemWithIdEquipped(ConditionValue1, 1);
if (Unit* unit = object->ToUnit())
{
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
condMeets = player->HasItemOrGemWithIdEquipped(ConditionValue1, 1);
}
}
break;
}
case CONDITION_ZONEID:
@@ -81,26 +89,39 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
break;
case CONDITION_REPUTATION_RANK:
{
if (Player* player = object->ToPlayer())
if (Unit* unit = object->ToUnit())
{
if (FactionEntry const* faction = sFactionStore.LookupEntry(ConditionValue1))
condMeets = (ConditionValue2 & (1 << player->GetReputationMgr().GetRank(faction)));
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
if (FactionEntry const* faction = sFactionStore.LookupEntry(ConditionValue1))
{
condMeets = (ConditionValue2 & (1 << player->GetReputationMgr().GetRank(faction)));
}
}
}
break;
}
case CONDITION_ACHIEVEMENT:
{
if (Player* player = object->ToPlayer())
condMeets = player->HasAchieved(ConditionValue1);
if (Unit* unit = object->ToUnit())
{
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
condMeets = player->HasAchieved(ConditionValue1);
}
}
break;
}
case CONDITION_TEAM:
{
if (Player* player = object->ToPlayer())
if (Unit* unit = object->ToUnit())
{
// Xinef: DB Data compatibility...
uint32 teamOld = player->GetTeamId() == TEAM_ALLIANCE ? ALLIANCE : HORDE;
condMeets = teamOld == ConditionValue1;
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
// Xinef: DB Data compatibility...
uint32 teamOld = player->GetTeamId() == TEAM_ALLIANCE ? ALLIANCE : HORDE;
condMeets = teamOld == ConditionValue1;
}
}
break;
}
@@ -118,56 +139,83 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
}
case CONDITION_GENDER:
{
if (Player* player = object->ToPlayer())
condMeets = player->getGender() == ConditionValue1;
if (Unit* unit = object->ToUnit())
{
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
condMeets = player->getGender() == ConditionValue1;
}
}
break;
}
case CONDITION_SKILL:
{
if (Player* player = object->ToPlayer())
condMeets = player->HasSkill(ConditionValue1) && player->GetBaseSkillValue(ConditionValue1) >= ConditionValue2;
if (Unit* unit = object->ToUnit())
{
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
condMeets = player->HasSkill(ConditionValue1) && player->GetBaseSkillValue(ConditionValue1) >= ConditionValue2;
}
}
break;
}
case CONDITION_QUESTREWARDED:
{
if (Player* player = object->ToPlayer())
condMeets = player->GetQuestRewardStatus(ConditionValue1);
if (Unit* unit = object->ToUnit())
{
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
condMeets = player->GetQuestRewardStatus(ConditionValue1);
}
}
break;
}
case CONDITION_QUESTTAKEN:
{
if (Player* player = object->ToPlayer())
if (Unit* unit = object->ToUnit())
{
QuestStatus status = player->GetQuestStatus(ConditionValue1);
condMeets = (status == QUEST_STATUS_INCOMPLETE);
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
QuestStatus status = player->GetQuestStatus(ConditionValue1);
condMeets = (status == QUEST_STATUS_INCOMPLETE);
}
}
break;
}
case CONDITION_QUEST_COMPLETE:
{
if (Player* player = object->ToPlayer())
if (Unit* unit = object->ToUnit())
{
QuestStatus status = player->GetQuestStatus(ConditionValue1);
condMeets = (status == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(ConditionValue1));
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
QuestStatus status = player->GetQuestStatus(ConditionValue1);
condMeets = (status == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(ConditionValue1));
}
}
break;
}
case CONDITION_QUEST_NONE:
{
if (Player* player = object->ToPlayer())
if (Unit* unit = object->ToUnit())
{
QuestStatus status = player->GetQuestStatus(ConditionValue1);
condMeets = (status == QUEST_STATUS_NONE);
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
QuestStatus status = player->GetQuestStatus(ConditionValue1);
condMeets = (status == QUEST_STATUS_NONE);
}
}
break;
}
case CONDITION_QUEST_SATISFY_EXCLUSIVE:
{
if (Player* player = object->ToPlayer())
if (Unit* unit = object->ToUnit())
{
// Xinef: cannot be null, checked at loading
const Quest* quest = sObjectMgr->GetQuestTemplate(ConditionValue1);
condMeets = !player->IsQuestRewarded(ConditionValue1) && player->SatisfyQuestExclusiveGroup(quest, false);
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
// Xinef: cannot be null, checked at loading
const Quest* quest = sObjectMgr->GetQuestTemplate(ConditionValue1);
condMeets = !player->IsQuestRewarded(ConditionValue1) && player->SatisfyQuestExclusiveGroup(quest, false);
}
}
break;
}
@@ -183,18 +231,18 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
{
switch (ConditionValue3)
{
case INSTANCE_INFO_DATA:
condMeets = instance->GetData(ConditionValue1) == ConditionValue2;
break;
case INSTANCE_INFO_GUID_DATA:
condMeets = instance->GetGuidData(ConditionValue1) == ObjectGuid(uint64(ConditionValue2));
break;
case INSTANCE_INFO_BOSS_STATE:
condMeets = instance->GetBossState(ConditionValue1) == EncounterState(ConditionValue2);
break;
case INSTANCE_INFO_DATA64:
condMeets = instance->GetData64(ConditionValue1) == ConditionValue2;
break;
case INSTANCE_INFO_DATA:
condMeets = instance->GetData(ConditionValue1) == ConditionValue2;
break;
case INSTANCE_INFO_GUID_DATA:
condMeets = instance->GetGuidData(ConditionValue1) == ObjectGuid(uint64(ConditionValue2));
break;
case INSTANCE_INFO_BOSS_STATE:
condMeets = instance->GetBossState(ConditionValue1) == EncounterState(ConditionValue2);
break;
case INSTANCE_INFO_DATA64:
condMeets = instance->GetData64(ConditionValue1) == ConditionValue2;
break;
}
}
}
@@ -208,8 +256,13 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
break;
case CONDITION_SPELL:
{
if (Player* player = object->ToPlayer())
condMeets = player->HasSpell(ConditionValue1);
if (Unit* unit = object->ToUnit())
{
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
condMeets = player->HasSpell(ConditionValue1);
}
}
break;
}
case CONDITION_LEVEL:
@@ -220,8 +273,13 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
}
case CONDITION_DRUNKENSTATE:
{
if (Player* player = object->ToPlayer())
condMeets = (uint32) Player::GetDrunkenstateByValue(player->GetDrunkValue()) >= ConditionValue1;
if (Unit* unit = object->ToUnit())
{
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
condMeets = (uint32)Player::GetDrunkenstateByValue(player->GetDrunkValue()) >= ConditionValue1;
}
}
break;
}
case CONDITION_NEAR_CREATURE:
@@ -248,14 +306,14 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
{
switch (object->GetTypeId())
{
case TYPEID_UNIT:
condMeets &= object->ToCreature()->GetSpawnId() == ConditionValue3;
break;
case TYPEID_GAMEOBJECT:
condMeets &= object->ToGameObject()->GetSpawnId() == ConditionValue3;
break;
default:
break;
case TYPEID_UNIT:
condMeets &= object->ToCreature()->GetSpawnId() == ConditionValue3;
break;
case TYPEID_GAMEOBJECT:
condMeets &= object->ToGameObject()->GetSpawnId() == ConditionValue3;
break;
default:
break;
}
}
}
@@ -276,24 +334,24 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
{
switch (ConditionValue2)
{
case RELATION_SELF:
condMeets = unit == toUnit;
break;
case RELATION_IN_PARTY:
condMeets = unit->IsInPartyWith(toUnit);
break;
case RELATION_IN_RAID_OR_PARTY:
condMeets = unit->IsInRaidWith(toUnit);
break;
case RELATION_OWNED_BY:
condMeets = unit->GetOwnerGUID() == toUnit->GetGUID();
break;
case RELATION_PASSENGER_OF:
condMeets = unit->IsOnVehicle(toUnit);
break;
case RELATION_CREATED_BY:
condMeets = unit->GetCreatorGUID() == toUnit->GetGUID();
break;
case RELATION_SELF:
condMeets = unit == toUnit;
break;
case RELATION_IN_PARTY:
condMeets = unit->IsInPartyWith(toUnit);
break;
case RELATION_IN_RAID_OR_PARTY:
condMeets = unit->IsInRaidWith(toUnit);
break;
case RELATION_OWNED_BY:
condMeets = unit->GetOwnerGUID() == toUnit->GetGUID();
break;
case RELATION_PASSENGER_OF:
condMeets = unit->IsOnVehicle(toUnit);
break;
case RELATION_CREATED_BY:
condMeets = unit->GetCreatorGUID() == toUnit->GetGUID();
break;
}
}
}
@@ -346,8 +404,13 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
}
case CONDITION_TITLE:
{
if (Player* player = object->ToPlayer())
condMeets = player->HasTitle(ConditionValue1);
if (Unit* unit = object->ToUnit())
{
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
condMeets = player->HasTitle(ConditionValue1);
}
}
break;
}
case CONDITION_SPAWNMASK:
@@ -382,35 +445,52 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
}
case CONDITION_QUESTSTATE:
{
if (Player* player = object->ToPlayer())
if (Unit* unit = object->ToUnit())
{
uint32 queststateConditionValue1 = player->GetQuestStatus(ConditionValue1);
if (((ConditionValue2 & (1 << QUEST_STATUS_NONE)) && (queststateConditionValue1 == QUEST_STATUS_NONE)) || ((ConditionValue2 & (1 << QUEST_STATUS_COMPLETE)) && (queststateConditionValue1 == QUEST_STATUS_COMPLETE)) || ((ConditionValue2 & (1 << QUEST_STATUS_INCOMPLETE)) && (queststateConditionValue1 == QUEST_STATUS_INCOMPLETE)) || ((ConditionValue2 & (1 << QUEST_STATUS_FAILED)) && (queststateConditionValue1 == QUEST_STATUS_FAILED)) ||
((ConditionValue2 & (1 << QUEST_STATUS_REWARDED)) && player->GetQuestRewardStatus(ConditionValue1)))
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
condMeets = true;
uint32 queststateConditionValue1 = player->GetQuestStatus(ConditionValue1);
if (((ConditionValue2 & (1 << QUEST_STATUS_NONE)) && (queststateConditionValue1 == QUEST_STATUS_NONE)) ||
((ConditionValue2 & (1 << QUEST_STATUS_COMPLETE)) && (queststateConditionValue1 == QUEST_STATUS_COMPLETE)) ||
((ConditionValue2 & (1 << QUEST_STATUS_INCOMPLETE)) && (queststateConditionValue1 == QUEST_STATUS_INCOMPLETE)) ||
((ConditionValue2 & (1 << QUEST_STATUS_FAILED)) && (queststateConditionValue1 == QUEST_STATUS_FAILED)) ||
((ConditionValue2 & (1 << QUEST_STATUS_REWARDED)) && player->GetQuestRewardStatus(ConditionValue1)))
{
condMeets = true;
}
}
}
break;
}
case CONDITION_DAILY_QUEST_DONE:
{
if (Player* player = object->ToPlayer())
if (Unit* unit = object->ToUnit())
{
condMeets = player->IsDailyQuestDone(ConditionValue1);
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
condMeets = player->IsDailyQuestDone(ConditionValue1);
}
}
break;
}
case CONDITION_QUEST_OBJECTIVE_PROGRESS:
{
if (Player* player = object->ToPlayer())
if (Unit* unit = object->ToUnit())
{
const Quest* quest = ASSERT_NOTNULL(sObjectMgr->GetQuestTemplate(ConditionValue1));
uint16 log_slot = player->FindQuestSlot(quest->GetQuestId());
if (log_slot >= MAX_QUEST_LOG_SIZE)
break;
if (player->GetQuestSlotCounter(log_slot, ConditionValue2) == ConditionValue3)
condMeets = true;
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
Quest const* quest = ASSERT_NOTNULL(sObjectMgr->GetQuestTemplate(ConditionValue1));
uint16 log_slot = player->FindQuestSlot(quest->GetQuestId());
if (log_slot >= MAX_QUEST_LOG_SIZE)
{
break;
}
if (player->GetQuestSlotCounter(log_slot, ConditionValue2) == ConditionValue3)
{
condMeets = true;
}
}
}
break;
}
@@ -427,15 +507,27 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
}
case CONDITION_PET_TYPE:
{
if (Player* player = object->ToPlayer())
if (Pet* pet = player->GetPet())
condMeets = (((1 << pet->getPetType()) & ConditionValue1) != 0);
if (Unit* unit = object->ToUnit())
{
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
if (Pet* pet = player->GetPet())
{
condMeets = (((1 << pet->getPetType()) & ConditionValue1) != 0);
}
}
}
break;
}
case CONDITION_TAXI:
{
if (Player* player = object->ToPlayer())
condMeets = player->IsInFlight();
if (Unit* unit = object->ToUnit())
{
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
condMeets = player->IsInFlight();
}
}
break;
}
case CONDITION_CHARMED:
+1 -1
View File
@@ -250,7 +250,7 @@ void LoadM2Cameras(std::string const& dataPath)
LOG_ERROR("server.loading", "Camera file %s is damaged. Camera references position beyond file end", filename.string().c_str());
}
LOG_INFO("server.loading", ">> Loaded %u cinematic waypoint sets in %u ms", (uint32)sFlyByCameraStore.size(), GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", ">> Loaded {} cinematic waypoint sets in {} ms", (uint32)sFlyByCameraStore.size(), GetMSTimeDiffToNow(oldMSTime));
}
std::vector<FlyByCamera> const* GetFlyByCameras(uint32 cinematicCameraId)
+1 -1
View File
@@ -1708,7 +1708,7 @@ namespace lfg
if (bgQueueTypeId != BATTLEGROUND_QUEUE_NONE)
{
plr->RemoveBattlegroundQueueId(bgQueueTypeId);
sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId).RemovePlayer(plr->GetGUID(), false, i);
sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId).RemovePlayer(plr->GetGUID(), true);
}
}
}
+99 -12
View File
@@ -248,7 +248,10 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
m_swingErrorMsg = 0;
for (uint8 j = 0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; ++j)
m_bgBattlegroundQueueID[j] = BATTLEGROUND_QUEUE_NONE;
{
_BgBattlegroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE;
_BgBattlegroundQueueID[j].invitedToInstance = 0;
}
m_logintime = GameTime::GetGameTime().count();
m_Last_tick = m_logintime;
@@ -11025,6 +11028,8 @@ void Player::LeaveBattleground(Battleground* bg)
sScriptMgr->OnBattlegroundDesertion(this, BG_DESERTION_TYPE_LEAVE_BG);
}
bg->RemovePlayerAtLeave(this);
// xinef: reset corpse reclaim time
m_deathExpireTime = GameTime::GetGameTime().count();
@@ -11853,10 +11858,102 @@ Battleground* Player::GetBattleground(bool create) const
if (GetBattlegroundId() == 0)
return nullptr;
Battleground* bg = sBattlegroundMgr->GetBattleground(GetBattlegroundId());
Battleground* bg = sBattlegroundMgr->GetBattleground(GetBattlegroundId(), GetBattlegroundTypeId());
return (create || (bg && bg->FindBgMap()) ? bg : nullptr);
}
bool Player::InBattlegroundQueue(bool ignoreArena) const
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (_BgBattlegroundQueueID[i].bgQueueTypeId != BATTLEGROUND_QUEUE_NONE &&
(!ignoreArena || (_BgBattlegroundQueueID[i].bgQueueTypeId != BATTLEGROUND_QUEUE_2v2 &&
_BgBattlegroundQueueID[i].bgQueueTypeId != BATTLEGROUND_QUEUE_3v3 &&
_BgBattlegroundQueueID[i].bgQueueTypeId != BATTLEGROUND_QUEUE_5v5)))
return true;
return false;
}
BattlegroundQueueTypeId Player::GetBattlegroundQueueTypeId(uint32 index) const
{
return _BgBattlegroundQueueID[index].bgQueueTypeId;
}
uint32 Player::GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (_BgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
return i;
return PLAYER_MAX_BATTLEGROUND_QUEUES;
}
bool Player::IsInvitedForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (_BgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
return _BgBattlegroundQueueID[i].invitedToInstance != 0;
return false;
}
bool Player::InBattlegroundQueueForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const
{
return GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES;
}
uint32 Player::AddBattlegroundQueueId(BattlegroundQueueTypeId val)
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
{
if (_BgBattlegroundQueueID[i].bgQueueTypeId == BATTLEGROUND_QUEUE_NONE || _BgBattlegroundQueueID[i].bgQueueTypeId == val)
{
_BgBattlegroundQueueID[i].bgQueueTypeId = val;
_BgBattlegroundQueueID[i].invitedToInstance = 0;
return i;
}
}
return PLAYER_MAX_BATTLEGROUND_QUEUES;
}
bool Player::HasFreeBattlegroundQueueId() const
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (_BgBattlegroundQueueID[i].bgQueueTypeId == BATTLEGROUND_QUEUE_NONE)
return true;
return false;
}
void Player::RemoveBattlegroundQueueId(BattlegroundQueueTypeId val)
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
{
if (_BgBattlegroundQueueID[i].bgQueueTypeId == val)
{
_BgBattlegroundQueueID[i].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE;
_BgBattlegroundQueueID[i].invitedToInstance = 0;
return;
}
}
}
void Player::SetInviteForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId, uint32 instanceId)
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (_BgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
_BgBattlegroundQueueID[i].invitedToInstance = instanceId;
}
bool Player::IsInvitedForBattlegroundInstance(uint32 instanceId) const
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (_BgBattlegroundQueueID[i].invitedToInstance == instanceId)
return true;
return false;
}
bool Player::InArena() const
{
Battleground* bg = GetBattleground();
@@ -11868,16 +11965,6 @@ bool Player::InArena() const
void Player::SetBattlegroundId(uint32 id, BattlegroundTypeId bgTypeId, uint32 queueSlot, bool invited, bool isRandom, TeamId teamId)
{
// if leaving current bg (and was invited) - decrease invited count for current one
if (m_bgData.bgInstanceID && m_bgData.isInvited)
if (Battleground* bg = sBattlegroundMgr->GetBattleground(m_bgData.bgInstanceID))
bg->DecreaseInvitedCount(m_bgData.bgTeamId);
// if entering new bg (and is invited) - increase invited count for new one
if (id && invited)
if (Battleground* bg = sBattlegroundMgr->GetBattleground(id))
bg->IncreaseInvitedCount(teamId);
m_bgData.bgInstanceID = id;
m_bgData.bgTypeID = bgTypeId;
m_bgData.bgQueueSlot = queueSlot;
+19 -52
View File
@@ -177,7 +177,7 @@ enum TalentTree // talent tabs
// Spell modifier (used for modify other spells)
struct SpellModifier
{
SpellModifier(Aura* _ownerAura = nullptr) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), charges(0), mask(), ownerAura(_ownerAura) {}
SpellModifier(Aura* _ownerAura = nullptr) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), charges(0), mask(), ownerAura(_ownerAura) {}
SpellModOp op : 8;
SpellModType type : 8;
int16 charges : 16;
@@ -2188,59 +2188,20 @@ public:
void SetBGData(BGData& bgdata) { m_bgData = bgdata; }
[[nodiscard]] Battleground* GetBattleground(bool create = false) const;
[[nodiscard]] bool InBattlegroundQueue() const
{
for (auto i : m_bgBattlegroundQueueID)
if (i != BATTLEGROUND_QUEUE_NONE)
return true;
return false;
}
[[nodiscard]] bool InBattlegroundQueue(bool ignoreArena = false) const;
[[nodiscard]] bool IsDeserter() const { return HasAura(26013); }
[[nodiscard]] BattlegroundQueueTypeId GetBattlegroundQueueTypeId(uint32 index) const { return m_bgBattlegroundQueueID[index]; }
[[nodiscard]] uint32 GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (m_bgBattlegroundQueueID[i] == bgQueueTypeId)
return i;
return PLAYER_MAX_BATTLEGROUND_QUEUES;
}
[[nodiscard]] bool InBattlegroundQueueForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const
{
return GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES;
}
[[nodiscard]] BattlegroundQueueTypeId GetBattlegroundQueueTypeId(uint32 index) const;
[[nodiscard]] uint32 GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const;
[[nodiscard]] bool IsInvitedForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const;
[[nodiscard]] bool InBattlegroundQueueForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const;
void SetBattlegroundId(uint32 id, BattlegroundTypeId bgTypeId, uint32 queueSlot, bool invited, bool isRandom, TeamId teamId);
uint32 AddBattlegroundQueueId(BattlegroundQueueTypeId val)
{
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (m_bgBattlegroundQueueID[i] == BATTLEGROUND_QUEUE_NONE || m_bgBattlegroundQueueID[i] == val)
{
m_bgBattlegroundQueueID[i] = val;
return i;
}
return PLAYER_MAX_BATTLEGROUND_QUEUES;
}
bool HasFreeBattlegroundQueueId()
{
for (auto & i : m_bgBattlegroundQueueID)
if (i == BATTLEGROUND_QUEUE_NONE)
return true;
return false;
}
void RemoveBattlegroundQueueId(BattlegroundQueueTypeId val)
{
for (auto & i : m_bgBattlegroundQueueID)
if (i == val)
{
i = BATTLEGROUND_QUEUE_NONE;
return;
}
}
uint32 AddBattlegroundQueueId(BattlegroundQueueTypeId val);
bool HasFreeBattlegroundQueueId() const;
void RemoveBattlegroundQueueId(BattlegroundQueueTypeId val);
void SetInviteForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId, uint32 instanceId);
bool IsInvitedForBattlegroundInstance(uint32 instanceId) const;
[[nodiscard]] TeamId GetBgTeamId() const { return m_bgData.bgTeamId != TEAM_NEUTRAL ? m_bgData.bgTeamId : GetTeamId(); }
@@ -2601,7 +2562,13 @@ public:
/*** BATTLEGROUND SYSTEM ***/
/*********************************************************/
BattlegroundQueueTypeId m_bgBattlegroundQueueID[PLAYER_MAX_BATTLEGROUND_QUEUES];
struct BgBattlegroundQueueID_Rec
{
BattlegroundQueueTypeId bgQueueTypeId;
uint32 invitedToInstance;
};
std::array<BgBattlegroundQueueID_Rec, PLAYER_MAX_BATTLEGROUND_QUEUES> _BgBattlegroundQueueID;
BGData m_bgData;
bool m_IsBGRandomWinner;
+6
View File
@@ -7233,6 +7233,12 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
if (!victim)
return false;
// Do not proc from Glyph of Holy Light and Judgement of Light
if (procSpell->Id == 20267 || procSpell->Id == 54968)
{
return false;
}
Unit* beaconTarget = triggeredByAura->GetBase()->GetCaster();
if (!beaconTarget || beaconTarget == this || !beaconTarget->GetAura(53563, victim->GetGUID()))
return false;
+17
View File
@@ -2189,6 +2189,11 @@ ObjectGuid Group::GetLeaderGUID() const
return m_leaderGuid;
}
Player* Group::GetLeader()
{
return ObjectAccessor::FindConnectedPlayer(m_leaderGuid);
}
ObjectGuid Group::GetGUID() const
{
return m_guid;
@@ -2425,3 +2430,15 @@ void Group::SetDifficultyChangePrevention(DifficultyPreventionChangeType type)
_difficultyChangePreventionTime = GameTime::GetGameTime().count() + MINUTE;
_difficultyChangePreventionType = type;
}
void Group::DoForAllMembers(std::function<void(Player*)> const& worker)
{
for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
{
Player* member = itr->GetSource();
if (!member)
continue;
worker(member);
}
}
+4
View File
@@ -23,6 +23,7 @@
#include "LootMgr.h"
#include "QueryResult.h"
#include "SharedDefines.h"
#include <functional>
class Battlefield;
class Battleground;
@@ -214,6 +215,7 @@ public:
bool isBGGroup() const;
bool IsCreated() const;
ObjectGuid GetLeaderGUID() const;
Player* GetLeader();
ObjectGuid GetGUID() const;
const char* GetLeaderName() const;
LootMethod GetLootMethod() const;
@@ -313,6 +315,8 @@ public:
DifficultyPreventionChangeType GetDifficultyChangePreventionReason() const { return _difficultyChangePreventionType; }
void SetDifficultyChangePrevention(DifficultyPreventionChangeType type);
void DoForAllMembers(std::function<void(Player*)> const& worker);
protected:
void _homebindIfInstance(Player* player);
void _cancelHomebindIfInstance(Player* player);
+218 -194
View File
@@ -72,8 +72,9 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
{
ObjectGuid guid;
uint32 bgTypeId_;
uint32 instanceId; // sent to queue for particular bg from battlemaster's list, currently not used
uint32 instanceId;
uint8 joinAsGroup;
bool isPremade = false;
recvData >> guid; // battlemaster guid
recvData >> bgTypeId_; // battleground type id (DBC id)
@@ -82,7 +83,10 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
// entry not found
if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
{
LOG_ERROR("network", "Battleground: invalid bgtype ({}) received. possible cheater? player {}", bgTypeId_, _player->GetGUID().ToString());
return;
}
// chosen battleground type is disabled
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId_, nullptr))
@@ -91,6 +95,8 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
return;
}
LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from {}", guid.ToString());
// get queue typeid and random typeid to check if already queued for them
BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_);
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, 0);
@@ -100,35 +106,26 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
if (bgQueueTypeId == BATTLEGROUND_QUEUE_NONE)
return;
// get bg template
Battleground* bgt = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
if (!bgt)
// ignore if player is already in BG
if (_player->InBattleground())
return;
// get bg instance or bg template if instance not found
Battleground* bg = nullptr;
if (instanceId)
bg = sBattlegroundMgr->GetBattlegroundThroughClientInstance(instanceId, bgTypeId);
if (!bg)
bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
if (!bg)
return;
// expected bracket entry
PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bgt->GetMapId(), _player->getLevel());
PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel());
if (!bracketEntry)
return;
// pussywizard: if trying to queue for already queued
// just remove from queue and it will requeue!
uint32 qSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId);
if (qSlot < PLAYER_MAX_BATTLEGROUND_QUEUES)
{
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
if (bgQueue.IsPlayerInvitedToRatedArena(_player->GetGUID()))
{
WorldPacket data;
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_JOIN_FAILED);
SendPacket(&data);
return;
}
bgQueue.RemovePlayer(_player->GetGUID(), false, qSlot);
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
}
// must have free queue slot
if (!_player->HasFreeBattlegroundQueueId())
{
@@ -139,7 +136,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
}
// queue result (default ok)
GroupJoinBattlegroundResult err = GroupJoinBattlegroundResult(bgt->GetBgTypeID());
GroupJoinBattlegroundResult err = GroupJoinBattlegroundResult(bg->GetBgTypeID());
if (!sScriptMgr->CanJoinInBattlegroundQueue(_player, guid, bgTypeId, joinAsGroup, err) && err <= 0)
{
@@ -149,6 +146,8 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
return;
}
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
// check if player can queue:
if (!joinAsGroup)
{
@@ -169,6 +168,10 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
{
err = ERR_IN_RANDOM_BG;
}
else if (_player->InBattlegroundQueueForBattlegroundQueueType(bgQueueTypeId)) // queued for this bg
{
err = ERR_BATTLEGROUND_NONE;
}
else if (_player->InBattlegroundQueue() && bgTypeId == BATTLEGROUND_RB) // already in queue, so can't queue for random
{
err = ERR_IN_NON_RANDOM_BG;
@@ -193,15 +196,13 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
return;
}
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, nullptr, bracketEntry, false, false, 0, 0, 0);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, nullptr, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
uint32 avgWaitTime = bgQueue.GetAverageQueueWaitTime(ginfo);
uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId);
// send status packet
WorldPacket data;
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bgt, queueSlot, STATUS_WAIT_QUEUE, avgWaitTime, 0, 0, TEAM_NEUTRAL);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgWaitTime, 0, 0, TEAM_NEUTRAL);
SendPacket(&data);
sScriptMgr->OnPlayerJoinBG(_player);
@@ -214,30 +215,6 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
if (!grp || grp->GetLeaderGUID() != _player->GetGUID())
return;
// pussywizard: for party members - remove queues for which leader is not queued to!
std::set<uint32> leaderQueueTypeIds;
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
leaderQueueTypeIds.insert((uint32)_player->GetBattlegroundQueueTypeId(i));
for (GroupReference* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next())
if (Player* member = itr->GetSource())
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (BattlegroundQueueTypeId mqtid = member->GetBattlegroundQueueTypeId(i))
if (leaderQueueTypeIds.count((uint32)mqtid) == 0)
{
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(mqtid);
if (bgQueue.IsPlayerInvitedToRatedArena(member->GetGUID()))
{
WorldPacket data;
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_JOIN_FAILED);
SendPacket(&data);
return;
}
bgQueue.RemovePlayer(member->GetGUID(), false, i);
member->RemoveBattlegroundQueueId(mqtid);
}
if (_player->InBattlegroundQueueForBattlegroundQueueType(bgQueueTypeIdRandom)) // queued for random bg, so can't queue for anything else
err = ERR_IN_RANDOM_BG;
else if (_player->InBattlegroundQueue() && bgTypeId == BATTLEGROUND_RB) // already in queue, so can't queue for random
@@ -248,44 +225,42 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
err = ERR_BATTLEGROUND_QUEUED_FOR_RATED;
if (err > 0)
err = grp->CanJoinBattlegroundQueue(bgt, bgQueueTypeId, 0, bgt->GetMaxPlayersPerTeam(), false, 0);
err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
bool isPremade = (grp->GetMembersCount() >= bgt->GetMinPlayersPerTeam() && bgTypeId != BATTLEGROUND_RB);
isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam() && bgTypeId != BATTLEGROUND_RB);
uint32 avgWaitTime = 0;
if (err > 0)
{
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bracketEntry, false, isPremade, 0, 0, 0);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
avgWaitTime = bgQueue.GetAverageQueueWaitTime(ginfo);
}
WorldPacket data;
for (GroupReference* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next())
grp->DoForAllMembers([bg, err, bgQueueTypeId, avgWaitTime](Player* member)
{
Player* member = itr->GetSource();
if (!member)
continue;
WorldPacket data;
if (err <= 0)
{
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err);
member->GetSession()->SendPacket(&data);
continue;
return;
}
uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId);
// send status packet
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bgt, queueSlot, STATUS_WAIT_QUEUE, avgWaitTime, 0, 0, TEAM_NEUTRAL);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgWaitTime, 0, 0, TEAM_NEUTRAL);
member->GetSession()->SendPacket(&data);
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err);
member->GetSession()->SendPacket(&data);
sScriptMgr->OnPlayerJoinBG(member);
}
});
}
sBattlegroundMgr->ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId());
}
void WorldSession::HandleBattlegroundPlayerPositionsOpcode(WorldPacket& /*recvData*/)
@@ -373,7 +348,10 @@ void WorldSession::HandleBattlefieldListOpcode(WorldPacket& recvData)
BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
if (!bl)
{
LOG_DEBUG("bg.battleground", "BattlegroundHandler: invalid bgtype ({}) with player (Name: {}, {}) received.", bgTypeId, _player->GetName(), _player->GetGUID().ToString());
return;
}
WorldPacket data;
sBattlegroundMgr->BuildBattlegroundListPacket(&data, ObjectGuid::Empty, _player, BattlegroundTypeId(bgTypeId), fromWhere);
@@ -382,21 +360,27 @@ void WorldSession::HandleBattlefieldListOpcode(WorldPacket& recvData)
void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData)
{
uint8 arenaType; // arenatype if arena
uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
uint32 bgTypeId_; // type id from dbc
uint16 unk; // 0x1F90 constant?
uint8 action; // enter battle 0x1, leave queue 0x0
uint8 arenaType; // arenatype if arena
uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
uint32 bgTypeId_; // type id from dbc
uint16 unk; // 0x1F90 constant?
uint8 action; // enter battle 0x1, leave queue 0x0
recvData >> arenaType >> unk2 >> bgTypeId_ >> unk >> action;
// bgTypeId not valid
if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
{
LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Invalid BgType!", GetPlayerInfo(), arenaType, unk2, bgTypeId_, action);
return;
}
// player not in any queue, so can't really answer
if (!_player->InBattlegroundQueue())
{
LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Player not in queue!", GetPlayerInfo(), arenaType, unk2, bgTypeId_, action);
return;
}
// get BattlegroundQueue for received
BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_);
@@ -409,20 +393,40 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData)
// get group info from queue
GroupQueueInfo ginfo;
if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo))
{
LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Player not in queue (No player Group Info)!",
GetPlayerInfo(), arenaType, unk2, bgTypeId_, action);
return;
}
// to accept, player must be invited to particular battleground id
if (!ginfo.IsInvitedToBGInstanceGUID && action == 1)
{
LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Player is not invited to any bg!",
GetPlayerInfo(), arenaType, unk2, bgTypeId_, action);
return;
}
Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID);
// use template if leaving queue (instance might not be created yet)
if (!bg && action == 0)
bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
if (!bg)
return;
{
if (action)
{
LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}. Cant find BG with id {}!",
GetPlayerInfo(), arenaType, unk2, bgTypeId_, action, ginfo.IsInvitedToBGInstanceGUID);
return;
}
bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
if (!bg)
{
LOG_ERROR("network", "BattlegroundHandler: bg_template not found for type id {}.", bgTypeId);
return;
}
}
LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT {} ArenaType: {}, Unk: {}, BgType: {}, Action: {}.",
GetPlayerInfo(), arenaType, unk2, bgTypeId_, action);
// expected bracket entry
PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel());
@@ -439,74 +443,90 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData)
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS);
SendPacket(&data);
action = 0;
LOG_DEBUG("bg.battleground", "Player {} {} has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUID().ToString());
}
if (_player->getLevel() > bg->GetMaxLevel())
{
LOG_ERROR("network", "Player {} {} has level ({}) higher than maxlevel ({}) of battleground ({})! Do not port him to battleground!",
_player->GetName(), _player->GetGUID().ToString(), _player->getLevel(), bg->GetMaxLevel(), bg->GetBgTypeID());
action = 0;
}
}
// get player queue slot index for this bg (can be in up to 2 queues at the same time)
uint32 queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId);
WorldPacket data;
switch (action)
if (action) // accept
{
case 1: // accept
// check Freeze debuff
if (_player->HasAura(9454))
return;
if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId))
return; // cheating?
// set entry point if not in battleground
if (!_player->InBattleground())
_player->SetEntryPoint();
// resurrect the player
if (!_player->IsAlive())
{
_player->ResurrectPlayer(1.0f);
_player->SpawnCorpseBones();
}
TeamId teamId = ginfo.teamId;
// send status packet
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType(), teamId);
SendPacket(&data);
// remove battleground queue status from BGmgr
bgQueue.RemovePlayer(_player->GetGUID(), false);
// this is still needed here if battleground "jumping" shouldn't add deserter debuff
// also this is required to prevent stuck at old battleground after SetBattlegroundId set to new
if (Battleground* currentBg = _player->GetBattleground())
currentBg->RemovePlayerAtLeave(_player);
// Remove from LFG queues
sLFGMgr->LeaveAllLfgQueues(_player->GetGUID(), false);
_player->SetBattlegroundId(bg->GetInstanceID(), bg->GetBgTypeID(), queueSlot, true, bgTypeId == BATTLEGROUND_RB, teamId);
sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
LOG_DEBUG("bg.battleground", "Battleground: player {} {} joined battle for bg {}, bgtype {}, queue type {}.", _player->GetName(), _player->GetGUID().ToString(), bg->GetInstanceID(), bg->GetBgTypeID(), bgQueueTypeId);
}
else // leave queue
{
bgQueue.RemovePlayer(_player->GetGUID(), true);
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, TEAM_NEUTRAL);
SendPacket(&data);
LOG_DEBUG("bg.battleground", "Battleground: player {} {} left queue for bgtype {}, queue type {}.", _player->GetName(), _player->GetGUID().ToString(), bg->GetBgTypeID(), bgQueueTypeId);
// player left queue, we should update it - do not update Arena Queue
if (!ginfo.ArenaType)
sBattlegroundMgr->ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId());
// track if player refuses to join the BG after being invited
if (bg->isBattleground() && (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN))
{
if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_TRACK_DESERTERS))
{
// set entry point if not in battleground
if (!_player->InBattleground())
_player->SetEntryPoint();
// resurrect the player
if (!_player->IsAlive())
{
_player->ResurrectPlayer(1.0f);
_player->SpawnCorpseBones();
}
TeamId teamId = ginfo.teamId;
// remove player from all bg queues
for (uint32 qslot = 0; qslot < PLAYER_MAX_BATTLEGROUND_QUEUES; ++qslot)
if (BattlegroundQueueTypeId q = _player->GetBattlegroundQueueTypeId(qslot))
{
BattlegroundQueue& queue = sBattlegroundMgr->GetBattlegroundQueue(q);
queue.RemovePlayer(_player->GetGUID(), (bgQueueTypeId == q), qslot);
_player->RemoveBattlegroundQueueId(q);
}
// send status packet
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType(), teamId);
SendPacket(&data);
// Remove from LFG queues
sLFGMgr->LeaveAllLfgQueues(_player->GetGUID(), false);
_player->SetBattlegroundId(bg->GetInstanceID(), bg->GetBgTypeID(), queueSlot, true, bgTypeId == BATTLEGROUND_RB, teamId);
sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_DESERTER_TRACK);
stmt->SetData(0, _player->GetGUID().GetCounter());
stmt->SetData(1, BG_DESERTION_TYPE_LEAVE_QUEUE);
CharacterDatabase.Execute(stmt);
}
break;
case 0: // leave queue
{
bgQueue.RemovePlayer(_player->GetGUID(), false, queueSlot);
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
// track if player refuses to join the BG after being invited
if (bg->isBattleground() && (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN))
{
if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_TRACK_DESERTERS))
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_DESERTER_TRACK);
stmt->SetData(0, _player->GetGUID().GetCounter());
stmt->SetData(1, BG_DESERTION_TYPE_LEAVE_QUEUE);
CharacterDatabase.Execute(stmt);
}
sScriptMgr->OnBattlegroundDesertion(_player, BG_DESERTION_TYPE_LEAVE_QUEUE);
}
}
break;
default:
break;
sScriptMgr->OnBattlegroundDesertion(_player, BG_DESERTION_TYPE_LEAVE_QUEUE);
}
}
}
@@ -562,7 +582,7 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket& /*recvData*/)
// if invited - send STATUS_WAIT_JOIN
if (ginfo.IsInvitedToBGInstanceGUID)
{
Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID);
Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
if (!bg)
continue;
@@ -591,10 +611,12 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket& /*recvData*/)
void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
{
ObjectGuid guid; // arena Battlemaster guid
uint8 arenaslot; // 2v2, 3v3 or 5v5
uint8 asGroup; // asGroup
uint8 isRated; // isRated
LOG_DEBUG("network", "WORLD: CMSG_BATTLEMASTER_JOIN_ARENA");
ObjectGuid guid; // arena Battlemaster guid
uint8 arenaslot; // 2v2, 3v3 or 5v5
uint8 asGroup; // asGroup
uint8 isRated; // isRated
recvData >> guid >> arenaslot >> asGroup >> isRated;
@@ -602,6 +624,10 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
if (isRated && !asGroup)
return;
// ignore if we already in BG or BG queue
if (_player->InBattleground())
return;
// find creature by guid
Creature* unit = GetPlayer()->GetMap()->GetCreature(guid);
if (!unit || !unit->IsBattleMaster())
@@ -609,6 +635,11 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
// get arena type
uint8 arenatype = 0;
uint32 ateamId = 0;
uint32 arenaRating = 0;
uint32 matchmakerRating = 0;
uint32 previousOpponents = 0;
switch (arenaslot)
{
case 0:
@@ -621,13 +652,17 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
arenatype = ARENA_TYPE_5v5;
break;
default:
LOG_ERROR("network", "Unknown arena slot {} at HandleBattlemasterJoinArena()", arenaslot);
return;
}
// get template for all arenas
Battleground* bgt = sBattlegroundMgr->GetBattlegroundTemplate(BATTLEGROUND_AA);
if (!bgt)
{
LOG_ERROR("network", "Battleground: template bg (all arenas) not found");
return;
}
// arenas disabled
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, BATTLEGROUND_AA, nullptr))
@@ -637,32 +672,12 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
}
BattlegroundTypeId bgTypeId = bgt->GetBgTypeID();
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, arenatype);
// expected bracket entry
PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bgt->GetMapId(), _player->getLevel());
if (!bracketEntry)
return;
// pussywizard: if trying to queue for already queued
// just remove from queue and it will requeue!
uint32 qSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId);
if (qSlot < PLAYER_MAX_BATTLEGROUND_QUEUES)
{
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
if (bgQueue.IsPlayerInvitedToRatedArena(_player->GetGUID()))
{
WorldPacket data;
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_JOIN_FAILED);
SendPacket(&data);
return;
}
bgQueue.RemovePlayer(_player->GetGUID(), false, qSlot);
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
}
// must have free queue slot
// pussywizard: allow being queued only in one arena queue, and it even cannot be together with bg queues
if (_player->InBattlegroundQueue())
@@ -684,6 +699,9 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
return;
}
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, arenatype);
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
// check if player can queue:
if (!asGroup)
{
@@ -705,16 +723,25 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
return;
}
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, nullptr, bracketEntry, false, false, 0, 0, 0);
uint32 avgWaitTime = bgQueue.GetAverageQueueWaitTime(ginfo);
// check if already in queue
if (_player->GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
//player is already in this queue
return;
// check if has free queue slots
if (!_player->HasFreeBattlegroundQueueId())
return;
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, nullptr, bgTypeId, bracketEntry, arenatype, isRated != 0, false, arenaRating, matchmakerRating, ateamId, previousOpponents);
uint32 avgWaitTime = bgQueue.GetAverageQueueWaitTime(ginfo);
uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId);
WorldPacket data;
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bgt, queueSlot, STATUS_WAIT_QUEUE, avgWaitTime, 0, arenatype, TEAM_NEUTRAL);
SendPacket(&data);
LOG_DEBUG("bg.battleground", "Battleground: player joined queue for arena, skirmish, bg queue type {} bg type {}: {}, NAME {}", bgQueueTypeId, bgTypeId, _player->GetGUID().ToString(), _player->GetName());
sScriptMgr->OnPlayerJoinArena(_player);
}
// check if group can queue:
@@ -725,34 +752,6 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
if (!grp || grp->GetLeaderGUID() != _player->GetGUID())
return;
// pussywizard: for party members - remove queues for which leader is not queued to!
std::set<uint32> leaderQueueTypeIds;
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
leaderQueueTypeIds.insert((uint32)_player->GetBattlegroundQueueTypeId(i));
for (GroupReference* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next())
if (Player* member = itr->GetSource())
for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (BattlegroundQueueTypeId mqtid = member->GetBattlegroundQueueTypeId(i))
if (leaderQueueTypeIds.count((uint32)mqtid) == 0)
{
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(mqtid);
if (bgQueue.IsPlayerInvitedToRatedArena(member->GetGUID()))
{
WorldPacket data;
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_JOIN_FAILED);
SendPacket(&data);
return;
}
bgQueue.RemovePlayer(member->GetGUID(), false, i);
member->RemoveBattlegroundQueueId(mqtid);
}
uint32 ateamId = 0;
uint32 arenaRating = 0;
uint32 matchmakerRating = 0;
// additional checks for rated arenas
if (isRated)
{
@@ -775,15 +774,40 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
matchmakerRating = at->GetAverageMMR(grp);
if (arenaRating <= 0)
arenaRating = 1;
previousOpponents = at->GetPreviousOpponents();
}
err = grp->CanJoinBattlegroundQueue(bgt, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot);
// Check queue group members
if (err)
{
grp->DoForAllMembers([&bgQueue, &err](Player* member)
{
if (bgQueue.IsPlayerInvitedToRatedArena(member->GetGUID()))
{
err = ERR_BATTLEGROUND_JOIN_FAILED;
}
});
}
uint32 avgWaitTime = 0;
if (err > 0)
{
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bracketEntry, isRated, false, arenaRating, matchmakerRating, ateamId);
LOG_DEBUG("bg.battleground", "Battleground: arena join as group start");
if (isRated)
{
LOG_DEBUG("bg.battleground", "Battleground: arena team id {}, leader {} queued with matchmaker rating {} for type {}", _player->GetArenaTeamId(arenaslot), _player->GetName(), matchmakerRating, arenatype);
bgt->SetRated(true);
}
else
{
bgt->SetRated(false);
}
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, arenatype, isRated != 0, false, arenaRating, matchmakerRating, ateamId, previousOpponents);
avgWaitTime = bgQueue.GetAverageQueueWaitTime(ginfo);
}
@@ -810,13 +834,13 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err);
member->GetSession()->SendPacket(&data);
LOG_DEBUG("bg.battleground", "Battleground: player joined queue for arena as group bg queue type {} bg type {}: {}, NAME {}", bgQueueTypeId, bgTypeId, member->GetGUID().ToString(), member->GetName());
sScriptMgr->OnPlayerJoinArena(member);
}
// pussywizard: schedule update for rated arena
if (ateamId)
sBattlegroundMgr->ScheduleArenaQueueUpdate(ateamId, bgQueueTypeId, bracketEntry->GetBracketId());
}
sBattlegroundMgr->ScheduleQueueUpdate(matchmakerRating, arenatype, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId());
}
void WorldSession::HandleReportPvPAFK(WorldPacket& recvData)
@@ -561,12 +561,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
newChar->SaveToDB(characterTransaction, true, false);
createInfo->CharCount++;
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM);
stmt->SetData(0, GetAccountId());
stmt->SetData(1, realm.Id.Realm);
trans->Append(stmt);
stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS);
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_REP_REALM_CHARACTERS);
stmt->SetData(0, createInfo->CharCount);
stmt->SetData(1, GetAccountId());
stmt->SetData(2, realm.Id.Realm);
+3 -3
View File
@@ -170,7 +170,7 @@ void WorldSession::HandleMoveWorldportAck()
if (uint32 inviteInstanceId = _player->GetPendingSpectatorInviteInstanceId())
{
if (Battleground* tbg = sBattlegroundMgr->GetBattleground(inviteInstanceId))
if (Battleground* tbg = sBattlegroundMgr->GetBattleground(inviteInstanceId, BATTLEGROUND_TYPE_NONE))
tbg->RemoveToBeTeleported(_player->GetGUID());
_player->SetPendingSpectatorInviteInstanceId(0);
}
@@ -904,14 +904,14 @@ void WorldSession::ComputeNewClockDelta()
std::vector<uint32> latencies;
std::vector<int64> clockDeltasAfterFiltering;
for (auto pair : _timeSyncClockDeltaQueue.content())
for (auto& pair : _timeSyncClockDeltaQueue.content())
latencies.push_back(pair.second);
uint32 latencyMedian = median(latencies);
uint32 latencyStandardDeviation = standard_deviation(latencies);
uint32 sampleSizeAfterFiltering = 0;
for (auto pair : _timeSyncClockDeltaQueue.content())
for (auto& pair : _timeSyncClockDeltaQueue.content())
{
if (pair.second <= latencyMedian + latencyStandardDeviation) {
clockDeltasAfterFiltering.push_back(pair.first);
@@ -66,58 +66,41 @@ void ScriptMgr::OnBattlegroundRemovePlayerAtLeave(Battleground* bg, Player* play
});
}
void ScriptMgr::OnAddGroup(BattlegroundQueue* queue, GroupQueueInfo* ginfo, uint32& index, Player* leader, Group* grp, PvPDifficultyEntry const* bracketEntry, bool isPremade)
void ScriptMgr::OnAddGroup(BattlegroundQueue* queue, GroupQueueInfo* ginfo, uint32& index, Player* leader, Group* group, BattlegroundTypeId bgTypeId, PvPDifficultyEntry const* bracketEntry,
uint8 arenaType, bool isRated, bool isPremade, uint32 arenaRating, uint32 matchmakerRating, uint32 arenaTeamId, uint32 opponentsArenaTeamId)
{
ExecuteScript<BGScript>([&](BGScript* script)
{
script->OnAddGroup(queue, ginfo, index, leader, grp, bracketEntry, isPremade);
script->OnAddGroup(queue, ginfo, index, leader, group, bgTypeId, bracketEntry,
arenaType, isRated, isPremade, arenaRating, matchmakerRating, arenaTeamId, opponentsArenaTeamId);
});
}
bool ScriptMgr::CanFillPlayersToBG(BattlegroundQueue* queue, Battleground* bg, const int32 aliFree, const int32 hordeFree, BattlegroundBracketId bracket_id)
bool ScriptMgr::CanFillPlayersToBG(BattlegroundQueue* queue, Battleground* bg, BattlegroundBracketId bracket_id)
{
auto ret = IsValidBoolScript<BGScript>([&](BGScript* script)
{
return !script->CanFillPlayersToBG(queue, bg, aliFree, hordeFree, bracket_id);
return !script->CanFillPlayersToBG(queue, bg, bracket_id);
});
if (ret && *ret)
{
return false;
}
return true;
return ReturnValidBool(ret);
}
bool ScriptMgr::CanFillPlayersToBGWithSpecific(BattlegroundQueue* queue, Battleground* bg, const int32 aliFree, const int32 hordeFree,
BattlegroundBracketId thisBracketId, BattlegroundQueue* specificQueue, BattlegroundBracketId specificBracketId)
bool ScriptMgr::IsCheckNormalMatch(BattlegroundQueue* queue, Battleground* bgTemplate, BattlegroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers)
{
auto ret = IsValidBoolScript<BGScript>([&](BGScript* script)
{
return !script->CanFillPlayersToBGWithSpecific(queue, bg, aliFree, hordeFree, thisBracketId, specificQueue, specificBracketId);
return script->IsCheckNormalMatch(queue, bgTemplate, bracket_id, minPlayers, maxPlayers);
});
if (ret && *ret)
{
return false;
}
return true;
return ReturnValidBool(ret, true);
}
void ScriptMgr::OnCheckNormalMatch(BattlegroundQueue* queue, uint32& Coef, Battleground* bgTemplate, BattlegroundBracketId bracket_id, uint32& minPlayers, uint32& maxPlayers)
void ScriptMgr::OnQueueUpdate(BattlegroundQueue* queue, uint32 diff, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id, uint8 arenaType, bool isRated, uint32 arenaRating)
{
ExecuteScript<BGScript>([&](BGScript* script)
{
script->OnCheckNormalMatch(queue, Coef, bgTemplate, bracket_id, minPlayers, maxPlayers);
});
}
void ScriptMgr::OnQueueUpdate(BattlegroundQueue* queue, BattlegroundBracketId bracket_id, bool isRated, uint32 arenaRatedTeamId)
{
ExecuteScript<BGScript>([&](BGScript* script)
{
script->OnQueueUpdate(queue, bracket_id, isRated, arenaRatedTeamId);
script->OnQueueUpdate(queue, diff, bgTypeId, bracket_id, arenaType, isRated, arenaRating);
});
}
@@ -128,12 +111,7 @@ bool ScriptMgr::CanSendMessageBGQueue(BattlegroundQueue* queue, Player* leader,
return !script->CanSendMessageBGQueue(queue, leader, bg, bracketEntry);
});
if (ret && *ret)
{
return false;
}
return true;
return ReturnValidBool(ret);
}
bool ScriptMgr::OnBeforeSendJoinMessageArenaQueue(BattlegroundQueue* queue, Player* leader, GroupQueueInfo* ginfo, PvPDifficultyEntry const* bracketEntry, bool isRated)
@@ -143,12 +121,7 @@ bool ScriptMgr::OnBeforeSendJoinMessageArenaQueue(BattlegroundQueue* queue, Play
return !script->OnBeforeSendJoinMessageArenaQueue(queue, leader, ginfo, bracketEntry, isRated);
});
if (ret && *ret)
{
return false;
}
return true;
return ReturnValidBool(ret);
}
bool ScriptMgr::OnBeforeSendExitMessageArenaQueue(BattlegroundQueue* queue, GroupQueueInfo* ginfo)
@@ -158,12 +131,7 @@ bool ScriptMgr::OnBeforeSendExitMessageArenaQueue(BattlegroundQueue* queue, Grou
return !script->OnBeforeSendExitMessageArenaQueue(queue, ginfo);
});
if (ret && *ret)
{
return false;
}
return true;
return ReturnValidBool(ret);
}
void ScriptMgr::OnBattlegroundEnd(Battleground* bg, TeamId winnerTeam)
+10 -13
View File
@@ -1569,16 +1569,14 @@ public:
// Remove player at leave BG
virtual void OnBattlegroundRemovePlayerAtLeave(Battleground* /*bg*/, Player* /*player*/) { }
virtual void OnQueueUpdate(BattlegroundQueue* /*queue*/, BattlegroundBracketId /*bracket_id*/, bool /*isRated*/, uint32 /*arenaRatedTeamId*/) { }
virtual void OnQueueUpdate(BattlegroundQueue* /*queue*/, uint32 /* diff */, BattlegroundTypeId /* bgTypeId */, BattlegroundBracketId /* bracket_id */, uint8 /* arenaType */, bool /* isRated */, uint32 /* arenaRating */) { }
virtual void OnAddGroup(BattlegroundQueue* /*queue*/, GroupQueueInfo* /*ginfo*/, uint32& /*index*/, Player* /*leader*/, Group* /*grp*/, PvPDifficultyEntry const* /*bracketEntry*/, bool /*isPremade*/) { }
virtual void OnAddGroup(BattlegroundQueue* /*queue*/, GroupQueueInfo* /*ginfo*/, uint32& /*index*/, Player* /*leader*/, Group* /*group*/, BattlegroundTypeId /* bgTypeId */, PvPDifficultyEntry const* /* bracketEntry */,
uint8 /* arenaType */, bool /* isRated */, bool /* isPremade */, uint32 /* arenaRating */, uint32 /* matchmakerRating */, uint32 /* arenaTeamId */, uint32 /* opponentsArenaTeamId */) { }
[[nodiscard]] virtual bool CanFillPlayersToBG(BattlegroundQueue* /*queue*/, Battleground* /*bg*/, const int32 /*aliFree*/, const int32 /*hordeFree*/, BattlegroundBracketId /*bracket_id*/) { return true; }
[[nodiscard]] virtual bool CanFillPlayersToBG(BattlegroundQueue* /*queue*/, Battleground* /*bg*/, BattlegroundBracketId /*bracket_id*/) { return true; }
[[nodiscard]] virtual bool CanFillPlayersToBGWithSpecific(BattlegroundQueue* /*queue*/, Battleground* /*bg*/, const int32 /*aliFree*/, const int32 /*hordeFree*/,
BattlegroundBracketId /*thisBracketId*/, BattlegroundQueue* /*specificQueue*/, BattlegroundBracketId /*specificBracketId*/) { return true; }
virtual void OnCheckNormalMatch(BattlegroundQueue* /*queue*/, uint32& /*Coef*/, Battleground* /*bgTemplate*/, BattlegroundBracketId /*bracket_id*/, uint32& /*minPlayers*/, uint32& /*maxPlayers*/) { }
[[nodiscard]] virtual bool IsCheckNormalMatch(BattlegroundQueue* /*queue*/, Battleground* /*bgTemplate*/, BattlegroundBracketId /*bracket_id*/, uint32 /*minPlayers*/, uint32 /*maxPlayers*/) { return false; };
[[nodiscard]] virtual bool CanSendMessageBGQueue(BattlegroundQueue* /*queue*/, Player* /*leader*/, Battleground* /*bg*/, PvPDifficultyEntry const* /*bracketEntry*/) { return true; }
@@ -2406,12 +2404,11 @@ public: /* BGScript */
void OnBattlegroundAddPlayer(Battleground* bg, Player* player);
void OnBattlegroundBeforeAddPlayer(Battleground* bg, Player* player);
void OnBattlegroundRemovePlayerAtLeave(Battleground* bg, Player* player);
void OnQueueUpdate(BattlegroundQueue* queue, BattlegroundBracketId bracket_id, bool isRated, uint32 arenaRatedTeamId);
void OnAddGroup(BattlegroundQueue* queue, GroupQueueInfo* ginfo, uint32& index, Player* leader, Group* grp, PvPDifficultyEntry const* bracketEntry, bool isPremade);
bool CanFillPlayersToBG(BattlegroundQueue* queue, Battleground* bg, const int32 aliFree, const int32 hordeFree, BattlegroundBracketId bracket_id);
bool CanFillPlayersToBGWithSpecific(BattlegroundQueue* queue, Battleground* bg, const int32 aliFree, const int32 hordeFree,
BattlegroundBracketId thisBracketId, BattlegroundQueue* specificQueue, BattlegroundBracketId specificBracketId);
void OnCheckNormalMatch(BattlegroundQueue* queue, uint32& Coef, Battleground* bgTemplate, BattlegroundBracketId bracket_id, uint32& minPlayers, uint32& maxPlayers);
void OnQueueUpdate(BattlegroundQueue* queue, uint32 diff, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id, uint8 arenaType, bool isRated, uint32 arenaRating);
void OnAddGroup(BattlegroundQueue* queue, GroupQueueInfo* ginfo, uint32& index, Player* leader, Group* group, BattlegroundTypeId bgTypeId, PvPDifficultyEntry const* bracketEntry,
uint8 arenaType, bool isRated, bool isPremade, uint32 arenaRating, uint32 matchmakerRating, uint32 arenaTeamId, uint32 opponentsArenaTeamId);
bool CanFillPlayersToBG(BattlegroundQueue* queue, Battleground* bg, BattlegroundBracketId bracket_id);
bool IsCheckNormalMatch(BattlegroundQueue* queue, Battleground* bgTemplate, BattlegroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers);
bool CanSendMessageBGQueue(BattlegroundQueue* queue, Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry);
bool OnBeforeSendJoinMessageArenaQueue(BattlegroundQueue* queue, Player* leader, GroupQueueInfo* ginfo, PvPDifficultyEntry const* bracketEntry, bool isRated);
bool OnBeforeSendExitMessageArenaQueue(BattlegroundQueue* queue, GroupQueueInfo* ginfo);
@@ -64,4 +64,9 @@ inline void ExecuteScript(std::function<void(ScriptName*)> executeHook)
}
}
inline bool ReturnValidBool(Optional<bool> ret, bool need = false)
{
return ret && *ret ? need : !need;
}
#endif // _SCRIPT_MGR_MACRO_H_
+4 -2
View File
@@ -587,8 +587,6 @@ void WorldSession::LogoutPlayer(bool save)
for (int i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(i))
{
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId).RemovePlayer(_player->GetGUID(), false, i);
// track if player logs out after invited to join BG
if (_player->IsInvitedForBattlegroundInstance())
{
@@ -599,8 +597,12 @@ void WorldSession::LogoutPlayer(bool save)
stmt->SetData(1, BG_DESERTION_TYPE_INVITE_LOGOUT);
CharacterDatabase.Execute(stmt);
}
sScriptMgr->OnBattlegroundDesertion(_player, BG_DESERTION_TYPE_INVITE_LOGOUT);
}
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId).RemovePlayer(_player->GetGUID(), true);
}
///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members
@@ -892,9 +892,16 @@ void AuraEffect::Update(uint32 diff, Unit* caster)
{
if (m_isPeriodic && (GetBase()->GetDuration() >= 0 || GetBase()->IsPassive() || GetBase()->IsPermanent()))
{
uint32 totalTicks = GetTotalTicks();
m_periodicTimer -= int32(diff);
while (m_periodicTimer <= 0)
{
if (!GetBase()->IsPermanent() && (m_tickNumber + 1) > totalTicks)
{
break;
}
++m_tickNumber;
// update before tick (aura can be removed in TriggerSpell or PeriodicTick calls)
@@ -6993,3 +7000,19 @@ void AuraEffect::HandleRaidProcFromChargeWithValueAuraProc(AuraApplication* aurA
LOG_DEBUG("spells.aura", "AuraEffect::HandleRaidProcFromChargeWithValueAuraProc: Triggering spell {} from aura {} proc", triggerSpellId, GetId());
target->CastCustomSpell(target, triggerSpellId, &value, nullptr, nullptr, true, nullptr, this, GetCasterGUID());
}
int32 AuraEffect::GetTotalTicks() const
{
uint32 totalTicks = 1;
if (m_amplitude)
{
totalTicks = GetBase()->GetMaxDuration() / m_amplitude;
if (m_spellInfo->HasAttribute(SPELL_ATTR5_EXTRA_INITIAL_PERIOD))
{
++totalTicks;
}
}
return totalTicks;
}
@@ -84,7 +84,7 @@ public:
void UpdatePeriodic(Unit* caster);
uint32 GetTickNumber() const { return m_tickNumber; }
int32 GetTotalTicks() const { return m_amplitude ? (GetBase()->GetMaxDuration() / m_amplitude) : 1;}
int32 GetTotalTicks() const;
void ResetPeriodic(bool resetPeriodicTimer = false) { if (resetPeriodicTimer) m_periodicTimer = m_amplitude; m_tickNumber = 0;}
void ResetTicks() { m_tickNumber = 0; }
+2 -2
View File
@@ -5877,7 +5877,7 @@ void Spell::EffectKillCreditPersonal(SpellEffIndex effIndex)
if (!unitTarget)
return;
Player* player = unitTarget->ToPlayer();
Player* player = unitTarget->GetCharmerOrOwnerPlayerOrPlayerItself();
if (!player)
{
return;
@@ -5894,7 +5894,7 @@ void Spell::EffectKillCredit(SpellEffIndex effIndex)
if (!unitTarget)
return;
Player* player = unitTarget->ToPlayer();
Player* player = unitTarget->GetCharmerOrOwnerPlayerOrPlayerItself();
if (!player)
{
return;
+1
View File
@@ -307,6 +307,7 @@ enum WorldIntConfigs
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_LIMIT_MIN_PLAYERS,
CONFIG_ARENA_MAX_RATING_DIFFERENCE,
CONFIG_ARENA_RATING_DISCARD_TIMER,
CONFIG_ARENA_PREV_OPPONENTS_DISCARD_TIMER,
CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS,
CONFIG_ARENA_GAMES_REQUIRED,
CONFIG_ARENA_SEASON_ID,
+14 -18
View File
@@ -1163,25 +1163,26 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_BATTLEGROUND_SPEED_BUFF_RESPAWN] = 150;
}
m_int_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfigMgr->GetOption<int32> ("Arena.MaxRatingDifference", 150);
m_int_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfigMgr->GetOption<int32> ("Arena.RatingDiscardTimer", 10 * MINUTE * IN_MILLISECONDS);
m_int_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfigMgr->GetOption<uint32>("Arena.MaxRatingDifference", 150);
m_int_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfigMgr->GetOption<uint32>("Arena.RatingDiscardTimer", 10 * MINUTE * IN_MILLISECONDS);
m_int_configs[CONFIG_ARENA_PREV_OPPONENTS_DISCARD_TIMER] = sConfigMgr->GetOption<uint32>("Arena.PreviousOpponentsDiscardTimer", 2 * MINUTE * IN_MILLISECONDS);
m_bool_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfigMgr->GetOption<bool>("Arena.AutoDistributePoints", false);
m_int_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfigMgr->GetOption<int32> ("Arena.AutoDistributeInterval", 7); // pussywizard: spoiled by implementing constant day and hour, always 7 now
m_int_configs[CONFIG_ARENA_GAMES_REQUIRED] = sConfigMgr->GetOption<int32> ("Arena.GamesRequired", 10);
m_int_configs[CONFIG_ARENA_SEASON_ID] = sConfigMgr->GetOption<int32> ("Arena.ArenaSeason.ID", 1);
m_int_configs[CONFIG_ARENA_START_RATING] = sConfigMgr->GetOption<int32> ("Arena.ArenaStartRating", 0);
m_int_configs[CONFIG_ARENA_START_PERSONAL_RATING] = sConfigMgr->GetOption<int32> ("Arena.ArenaStartPersonalRating", 1000);
m_int_configs[CONFIG_ARENA_START_MATCHMAKER_RATING] = sConfigMgr->GetOption<int32> ("Arena.ArenaStartMatchmakerRating", 1500);
m_int_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfigMgr->GetOption<uint32>("Arena.AutoDistributeInterval", 7); // pussywizard: spoiled by implementing constant day and hour, always 7 now
m_int_configs[CONFIG_ARENA_GAMES_REQUIRED] = sConfigMgr->GetOption<uint32>("Arena.GamesRequired", 10);
m_int_configs[CONFIG_ARENA_SEASON_ID] = sConfigMgr->GetOption<uint32>("Arena.ArenaSeason.ID", 1);
m_int_configs[CONFIG_ARENA_START_RATING] = sConfigMgr->GetOption<uint32>("Arena.ArenaStartRating", 0);
m_int_configs[CONFIG_ARENA_START_PERSONAL_RATING] = sConfigMgr->GetOption<uint32>("Arena.ArenaStartPersonalRating", 1000);
m_int_configs[CONFIG_ARENA_START_MATCHMAKER_RATING] = sConfigMgr->GetOption<uint32>("Arena.ArenaStartMatchmakerRating", 1500);
m_bool_configs[CONFIG_ARENA_SEASON_IN_PROGRESS] = sConfigMgr->GetOption<bool>("Arena.ArenaSeason.InProgress", true);
m_float_configs[CONFIG_ARENA_WIN_RATING_MODIFIER_1] = sConfigMgr->GetOption<float>("Arena.ArenaWinRatingModifier1", 48.0f);
m_float_configs[CONFIG_ARENA_WIN_RATING_MODIFIER_2] = sConfigMgr->GetOption<float>("Arena.ArenaWinRatingModifier2", 24.0f);
m_float_configs[CONFIG_ARENA_LOSE_RATING_MODIFIER] = sConfigMgr->GetOption<float>("Arena.ArenaLoseRatingModifier", 24.0f);
m_float_configs[CONFIG_ARENA_MATCHMAKER_RATING_MODIFIER] = sConfigMgr->GetOption<float>("Arena.ArenaMatchmakerRatingModifier", 24.0f);
m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE] = sConfigMgr->GetOption<bool> ("Arena.QueueAnnouncer.Enable", false);
m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_PLAYERONLY] = sConfigMgr->GetOption<bool> ("Arena.QueueAnnouncer.PlayerOnly", false);
m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE] = sConfigMgr->GetOption<bool>("Arena.QueueAnnouncer.Enable", false);
m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_PLAYERONLY] = sConfigMgr->GetOption<bool>("Arena.QueueAnnouncer.PlayerOnly", false);
m_bool_configs[CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN] = sConfigMgr->GetOption<bool>("OffhandCheckAtSpellUnlearn", true);
m_int_configs[CONFIG_CREATURE_STOP_FOR_PLAYER] = sConfigMgr->GetOption<int32>("Creature.MovingStopTimeForPlayer", 3 * MINUTE * IN_MILLISECONDS);
m_int_configs[CONFIG_CREATURE_STOP_FOR_PLAYER] = sConfigMgr->GetOption<uint32>("Creature.MovingStopTimeForPlayer", 3 * MINUTE * IN_MILLISECONDS);
if (int32 clientCacheId = sConfigMgr->GetOption<int32>("ClientCacheVersion", 0))
{
@@ -2046,7 +2047,7 @@ void World::SetInitialWorldSettings()
///- Initialize Battlegrounds
LOG_INFO("server.loading", "Starting Battleground System");
sBattlegroundMgr->CreateInitialBattlegrounds();
sBattlegroundMgr->LoadBattlegroundTemplates();
sBattlegroundMgr->InitAutomaticArenaPointDistribution();
///- Initialize outdoor pvp
@@ -3039,12 +3040,7 @@ void World::_UpdateRealmCharCount(PreparedQueryResult resultCharCount)
LoginDatabaseTransaction trans = LoginDatabase.BeginTransaction();
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM);
stmt->SetData(0, accountId);
stmt->SetData(1, realm.Id.Realm);
trans->Append(stmt);
stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS);
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_REP_REALM_CHARACTERS);
stmt->SetData(0, charCount);
stmt->SetData(1, accountId);
stmt->SetData(2, realm.Id.Realm);
+1 -1
View File
@@ -412,7 +412,7 @@ public:
return false;
}
Battleground* bg = sBattlegroundMgr->CreateNewBattleground(randomizedArenaBgTypeId, 80, 80, ArenaType(hcnt >= 2 ? hcnt : 2), false);
Battleground* bg = sBattlegroundMgr->CreateNewBattleground(randomizedArenaBgTypeId, GetBattlegroundBracketById(bgt->GetMapId(), bgt->GetBracketId()), ArenaType(hcnt >= 2 ? hcnt : 2), false);
if (!bg)
{
handler->PSendSysMessage("Couldn't create arena map!");
+1 -1
View File
@@ -215,7 +215,7 @@ public:
static bool HandleReloadBattlegroundTemplate(ChatHandler* handler)
{
LOG_INFO("server.loading", "Re-Loading Battleground Templates...");
sBattlegroundMgr->CreateInitialBattlegrounds();
sBattlegroundMgr->LoadBattlegroundTemplates();
handler->SendGlobalGMSysMessage("DB table `battleground_template` reloaded.");
return true;
}
@@ -78,7 +78,6 @@ enum Events
EVENT_HAND_OF_RAGNAROS,
EVENT_MIGHT_OF_RAGNAROS,
EVENT_LAVA_BURST,
EVENT_MAGMA_BLAST_MELEE_CHECK,
EVENT_MAGMA_BLAST,
EVENT_SUBMERGE,
EVENT_LAVA_BURST_TRIGGER,
@@ -122,6 +121,7 @@ public:
boss_ragnarosAI(Creature* creature) : BossAI(creature, DATA_RAGNAROS),
_isIntroDone(false),
_hasYelledMagmaBurst(false),
_processingMagmaBurst(false),
_hasSubmergedOnce(false),
_isKnockbackEmoteAllowed(true)
{
@@ -143,6 +143,7 @@ public:
}
_hasYelledMagmaBurst = false;
_processingMagmaBurst = false;
_hasSubmergedOnce = false;
_isKnockbackEmoteAllowed = true;
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
@@ -231,6 +232,28 @@ public:
}
}
void EnterEvadeMode() override
{
if (!me->getThreatMgr().getThreatList().empty())
{
if (!_processingMagmaBurst)
{
// Boss try to evade, but still got some targets on threat list - it means that none of these targets are in melee range - cast magma blast
_processingMagmaBurst = true;
events.ScheduleEvent(EVENT_MAGMA_BLAST, 4000, PHASE_EMERGED, PHASE_EMERGED);
}
}
else
{
BossAI::EnterEvadeMode();
}
}
bool CanAIAttack(Unit const* victim) const override
{
return me->IsWithinMeleeRange(victim);
}
void UpdateAI(uint32 diff) override
{
if (!extraEvents.Empty())
@@ -297,7 +320,10 @@ public:
if (!UpdateVictim())
{
return;
if (!_processingMagmaBurst)
{
return;
}
}
events.Update(diff);
@@ -340,38 +366,10 @@ public:
DoCastAOE(SPELL_LAVA_BURST);
break;
}
case EVENT_MAGMA_BLAST_MELEE_CHECK:
{
if (Unit* target = ObjectAccessor::GetUnit(*me, me->GetTarget()))
{
if (!target->IsAlive())
{
me->SetTarget(ObjectGuid::Empty);
}
}
if (!IsVictimWithinMeleeRange())
{
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 0, [&](Unit* u) { return u && u->IsPlayer() && me->IsWithinMeleeRange(u); }))
{
me->AttackerStateUpdate(target);
me->SetTarget(target->GetGUID());
events.RepeatEvent(500);
}
else
{
events.ScheduleEvent(EVENT_MAGMA_BLAST, 4000, PHASE_EMERGED, PHASE_EMERGED);
}
}
else
{
_hasYelledMagmaBurst = false;
events.RepeatEvent(500);
}
break;
}
case EVENT_MAGMA_BLAST:
{
_processingMagmaBurst = false;
if (!IsVictimWithinMeleeRange())
{
DoCastRandomTarget(SPELL_MAGMA_BLAST);
@@ -383,7 +381,6 @@ public:
}
}
events.RescheduleEvent(EVENT_MAGMA_BLAST_MELEE_CHECK, 500, PHASE_EMERGED, PHASE_EMERGED);
break;
}
case EVENT_MIGHT_OF_RAGNAROS:
@@ -444,6 +441,7 @@ public:
EventMap extraEvents;
bool _isIntroDone;
bool _hasYelledMagmaBurst;
bool _processingMagmaBurst;
bool _hasSubmergedOnce;
bool _isKnockbackEmoteAllowed; // Prevents possible text overlap
@@ -480,7 +478,6 @@ public:
events.RescheduleEvent(EVENT_WRATH_OF_RAGNAROS, 30000, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_HAND_OF_RAGNAROS, 25000, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_LAVA_BURST, 10000, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_MAGMA_BLAST_MELEE_CHECK, 10000, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_SUBMERGE, 180000, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_MIGHT_OF_RAGNAROS, 11000, PHASE_EMERGED, PHASE_EMERGED);
}
@@ -426,7 +426,7 @@ public:
bool OnGossipHello(Player* /*player*/, GameObject* go) override
{
if (go->GetInstanceScript())
if (go->GetInstanceScript() && !go->FindNearestCreature(NPC_ARLOKK, 25.0f))
{
go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
go->SendCustomAnim(0);
@@ -45,12 +45,6 @@ public:
LoadDoorData(doorData);
}
bool IsEncounterInProgress() const override
{
// not active in Zul'Gurub
return false;
}
void OnCreatureCreate(Creature* creature) override
{
switch (creature->GetEntry())
+2 -1
View File
@@ -1289,7 +1289,8 @@ class spell_gen_adaptive_warding : public AuraScript
45826 - East Frostwolf Warmaster
45828 - Dun Baldar North Marshal
45829 - Dun Baldar South Marshal
45830 - Stonehearth Marshal */
45830 - Stonehearth Marshal
45831 - Icewing Marshal */
class spell_gen_av_drekthar_presence : public AuraScript
{
PrepareAuraScript(spell_gen_av_drekthar_presence);
+104 -47
View File
@@ -18,7 +18,7 @@
/* ScriptData
SDName: Npc_Professions
SD%Complete: 80
SDComment: Provides learn/unlearn/relearn-options for professions. Not supported: Unlearn engineering, re-learn engineering, re-learn leatherworking.
SDComment: Provides learn/unlearn/relearn-options for professions. Not supported: Unlearn engineering, re-learn engineering.
SDCategory: NPCs
EndScriptData */
@@ -86,10 +86,6 @@ there is no difference here (except that default text is chosen with `gameobject
#define BOX_UNLEARN_WEAPON_SPEC "Do you really want to unlearn your weaponsmith specialty and lose all associated recipes? \n Cost: "
#define GOSSIP_LEARN_DRAGON "I wish to learn Dragonscale Leatherworking"
#define GOSSIP_LEARN_ELEMENTAL "I wish to learn Elemental Leatherworking"
#define GOSSIP_LEARN_TRIBAL "I wish to learn Tribal Leatherworking"
#define GOSSIP_LEARN_SPELLFIRE "Please teach me how to become a Spellcloth tailor"
#define GOSSIP_UNLEARN_SPELLFIRE "I wish to unlearn Spellfire Tailoring"
#define GOSSIP_LEARN_MOONCLOTH "Please teach me how to become a Mooncloth tailor"
@@ -230,6 +226,37 @@ enum SpecializationQuests
Q_MASTER_POTION = 10897,
};
// All referred to gossips (menu, menu_opt, actions)
enum Gossips
{
// Leatherworking
GOSSIP_MENU_PETER_GALEN = 3067,
GOSSIP_MENU_THORKAF_DRAGONEYE = 3068,
GOSSIP_MENU_BRUMN_WINTERHOOF = 3069,
GOSSIP_MENU_SARAH_TANNER = 3070,
GOSSIP_MENU_CARYSSIA_MOONHUNTER = 3072,
GOSSIP_MENU_SEJIB = 3073,
GOSSIP_MENU_UNLEARN_CONFIRM_DRAGONSCALE = 3075,
GOSSIP_MENU_UNLEARN_CONFIRM_ELEMENTAL = 3076,
GOSSIP_MENU_UNLEARN_CONFIRM_TRIBAL = 3077,
GOSSIP_MENU_OPTION_TRAIN = 0,
GOSSIP_MENU_OPTION_CONFIRM_UNLEARN_DRAGONSCALE = 1,
GOSSIP_MENU_OPTION_CONFIRM_UNLEARN_ELEMENTAL = 1,
GOSSIP_MENU_OPTION_CONFIRM_UNLEARN_TRIBAL = 1,
GOSSIP_TEXT_UNLEARN_CONFIRM_DRAGONSCALE = 10304,
GOSSIP_TEXT_UNLEARN_CONFIRM_ELEMENTAL = 10302,
GOSSIP_TEXT_UNLEARN_CONFIRM_TRIBAL = 10303,
GOSSIP_MENU_GO_SOOTHSAYING_FOR_DUMMIES = 7058,
GOSSIP_MENU_OPTION_GO_LEARN_DRAGONSCALE = 4,
GOSSIP_MENU_OPTION_GO_LEARN_ELEMENTAL = 5,
GOSSIP_MENU_OPTION_GO_LEARN_TRIBAL = 6,
};
/*###
# formulas to calculate unlearning cost
###*/
@@ -347,7 +374,11 @@ void ProfessionUnlearnSpells(Player* player, uint32 type)
player->removeSpell(36259, SPEC_MASK_ALL, false); // Lionheart Executioner
break;
case S_UNLEARN_DRAGON: // S_UNLEARN_DRAGON
player->removeSpell(10619, SPEC_MASK_ALL, false); // Dragonscale Guantlets
player->removeSpell(10650, SPEC_MASK_ALL, false); // Dragonscale Breastplate
player->removeSpell(36076, SPEC_MASK_ALL, false); // Dragonstrike Leggings
player->removeSpell(24655, SPEC_MASK_ALL, false); // Green Dragonscale Gauntlets
player->removeSpell(24654, SPEC_MASK_ALL, false); // Blue Dragonscale Leggings
player->removeSpell(36079, SPEC_MASK_ALL, false); // Golden Dragonstrike Breastplate
player->removeSpell(35576, SPEC_MASK_ALL, false); // Ebon Netherscale Belt
player->removeSpell(35577, SPEC_MASK_ALL, false); // Ebon Netherscale Bracers
@@ -362,6 +393,8 @@ void ProfessionUnlearnSpells(Player* player, uint32 type)
player->removeSpell(35590, SPEC_MASK_ALL, false); // Primalstrike Belt
player->removeSpell(35591, SPEC_MASK_ALL, false); // Primalstrike Bracers
player->removeSpell(35589, SPEC_MASK_ALL, false); // Primalstrike Vest
player->removeSpell(10630, SPEC_MASK_ALL, false); // Gauntlets of the Sea
player->removeSpell(10632, SPEC_MASK_ALL, false); // Helm of Fire
break;
case S_UNLEARN_TRIBAL: // S_UNLEARN_TRIBAL
player->removeSpell(35585, SPEC_MASK_ALL, false); // Windhawk Hauberk
@@ -369,6 +402,8 @@ void ProfessionUnlearnSpells(Player* player, uint32 type)
player->removeSpell(35588, SPEC_MASK_ALL, false); // Windhawk Bracers
player->removeSpell(36075, SPEC_MASK_ALL, false); // Wildfeather Leggings
player->removeSpell(36078, SPEC_MASK_ALL, false); // Living Crystal Breastplate
player->removeSpell(10621, SPEC_MASK_ALL, false); // Wolfshead Helm
player->removeSpell(10647, SPEC_MASK_ALL, false); // Feathered Breastplate
break;
case S_UNLEARN_SPELLFIRE: // S_UNLEARN_SPELLFIRE
player->removeSpell(26752, SPEC_MASK_ALL, false); // Spellfire Belt
@@ -950,44 +985,39 @@ public:
bool OnGossipHello(Player* player, Creature* creature) override
{
ClearGossipMenuFor(player);
if (creature->IsQuestGiver())
{
player->PrepareQuestMenu(creature->GetGUID());
}
if (creature->IsVendor())
AddGossipItemFor(player, GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE);
// pussywizard: NO UNLEARNING! LEATHERWORKING SPECIALTY IS A PERMANENT DECISION AND CANNOT BE CHANGED IN ANY WAY!
// pussywizard: CAN RE-LEARN ONLY THE ONE FOR WHICH QUEST IS COMPLETED!
if (player->HasSkill(SKILL_LEATHERWORKING) && player->GetBaseSkillValue(SKILL_LEATHERWORKING) >= 250 && player->getLevel() > 49)
if (player->HasSkill(SKILL_LEATHERWORKING) && player->GetBaseSkillValue(SKILL_LEATHERWORKING) >= 225 && player->getLevel() > 40)
{
switch (creature->GetEntry())
{
case N_TRAINER_DRAGON1: //Peter Galen
case N_TRAINER_DRAGON2: //Thorkaf Dragoneye
if (!HasLeatherSpecialty(player) && (player->GetQuestRewardStatus(5141) || player->GetQuestRewardStatus(5145)))
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_LEARN_DRAGON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
case N_TRAINER_DRAGON1: //Peter Galen
case N_TRAINER_DRAGON2: //Thorkaf Dragoneye
if (player->HasSpell(S_DRAGON))
{
AddGossipItemFor(player, GOSSIP_ICON_TRAINER, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN);
AddGossipItemFor(player, creature->GetEntry() == N_TRAINER_DRAGON1 ? GOSSIP_MENU_PETER_GALEN : GOSSIP_MENU_THORKAF_DRAGONEYE, GOSSIP_MENU_OPTION_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN);
AddGossipItemFor(player, creature->GetEntry() == N_TRAINER_DRAGON1 ? GOSSIP_MENU_PETER_GALEN : GOSSIP_MENU_THORKAF_DRAGONEYE, GOSSIP_MENU_OPTION_CONFIRM_UNLEARN_DRAGONSCALE, GOSSIP_SENDER_MAIN, GOSSIP_MENU_UNLEARN_CONFIRM_DRAGONSCALE);
}
break;
case N_TRAINER_ELEMENTAL1: //Sarah Tanner
case N_TRAINER_ELEMENTAL2: //Brumn Winterhoof
if (!HasLeatherSpecialty(player) && (player->GetQuestRewardStatus(5144) || player->GetQuestRewardStatus(5146)))
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_LEARN_ELEMENTAL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
case N_TRAINER_ELEMENTAL1: //Sarah Tanner
case N_TRAINER_ELEMENTAL2: //Brumn Winterhoof
if (player->HasSpell(S_ELEMENTAL))
{
AddGossipItemFor(player, GOSSIP_ICON_TRAINER, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN);
AddGossipItemFor(player, creature->GetEntry() == N_TRAINER_ELEMENTAL1 ? GOSSIP_MENU_SARAH_TANNER : GOSSIP_MENU_BRUMN_WINTERHOOF, GOSSIP_MENU_OPTION_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN);
AddGossipItemFor(player, creature->GetEntry() == N_TRAINER_ELEMENTAL1 ? GOSSIP_MENU_SARAH_TANNER : GOSSIP_MENU_BRUMN_WINTERHOOF, GOSSIP_MENU_OPTION_CONFIRM_UNLEARN_ELEMENTAL, GOSSIP_SENDER_MAIN, GOSSIP_MENU_UNLEARN_CONFIRM_ELEMENTAL);
}
break;
case N_TRAINER_TRIBAL1: //Caryssia Moonhunter
case N_TRAINER_TRIBAL2: //Se'Jib
if (!HasLeatherSpecialty(player) && (player->GetQuestRewardStatus(5143) || player->GetQuestRewardStatus(5148)))
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_LEARN_TRIBAL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
case N_TRAINER_TRIBAL1: //Caryssia Moonhunter
case N_TRAINER_TRIBAL2: //Se'Jib
if (player->HasSpell(S_TRIBAL))
{
AddGossipItemFor(player, GOSSIP_ICON_TRAINER, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN);
AddGossipItemFor(player, creature->GetEntry() == N_TRAINER_TRIBAL1 ? GOSSIP_MENU_CARYSSIA_MOONHUNTER : GOSSIP_MENU_SEJIB, GOSSIP_MENU_OPTION_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN);
AddGossipItemFor(player, creature->GetEntry() == N_TRAINER_TRIBAL1 ? GOSSIP_MENU_CARYSSIA_MOONHUNTER : GOSSIP_MENU_SEJIB, GOSSIP_MENU_OPTION_CONFIRM_UNLEARN_TRIBAL, GOSSIP_SENDER_MAIN, GOSSIP_MENU_UNLEARN_CONFIRM_TRIBAL);
}
break;
}
@@ -997,36 +1027,35 @@ public:
return true;
}
void SendActionMenu(Player* player, Creature* creature, uint32 action)
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
switch (action)
{
case GOSSIP_ACTION_TRADE:
player->GetSession()->SendListInventory(creature->GetGUID());
break;
case GOSSIP_ACTION_TRAIN:
player->GetSession()->SendTrainerList(creature->GetGUID());
break;
// Learn Leather
case GOSSIP_MENU_UNLEARN_CONFIRM_DRAGONSCALE:
AddGossipItemFor(player, GOSSIP_MENU_UNLEARN_CONFIRM_DRAGONSCALE, GOSSIP_MENU_OPTION_CONFIRM_UNLEARN_DRAGONSCALE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1, DoMedUnlearnCost(player));
SendGossipMenuFor(player, GOSSIP_TEXT_UNLEARN_CONFIRM_DRAGONSCALE, creature);
break;
case GOSSIP_MENU_UNLEARN_CONFIRM_ELEMENTAL:
AddGossipItemFor(player, GOSSIP_MENU_UNLEARN_CONFIRM_ELEMENTAL, GOSSIP_MENU_OPTION_CONFIRM_UNLEARN_ELEMENTAL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2, DoMedUnlearnCost(player));
SendGossipMenuFor(player, GOSSIP_TEXT_UNLEARN_CONFIRM_ELEMENTAL, creature);
break;
case GOSSIP_MENU_UNLEARN_CONFIRM_TRIBAL:
AddGossipItemFor(player, GOSSIP_MENU_UNLEARN_CONFIRM_TRIBAL, GOSSIP_MENU_OPTION_CONFIRM_UNLEARN_TRIBAL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3, DoMedUnlearnCost(player));
SendGossipMenuFor(player, GOSSIP_TEXT_UNLEARN_CONFIRM_TRIBAL, creature);
break;
case GOSSIP_ACTION_INFO_DEF + 1:
ProcessCastaction(player, creature, S_DRAGON, S_LEARN_DRAGON, 0);
ProcessUnlearnAction(player, creature, S_UNLEARN_DRAGON, 0, DoMedUnlearnCost(player));
break;
case GOSSIP_ACTION_INFO_DEF + 2:
ProcessCastaction(player, creature, S_ELEMENTAL, S_LEARN_ELEMENTAL, 0);
ProcessUnlearnAction(player, creature, S_UNLEARN_ELEMENTAL, 0, DoMedUnlearnCost(player));
break;
case GOSSIP_ACTION_INFO_DEF + 3:
ProcessCastaction(player, creature, S_TRIBAL, S_LEARN_TRIBAL, 0);
break;
}
}
bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) override
{
ClearGossipMenuFor(player);
switch (sender)
{
case GOSSIP_SENDER_MAIN:
SendActionMenu(player, creature, action);
ProcessUnlearnAction(player, creature, S_UNLEARN_TRIBAL, 0, DoMedUnlearnCost(player));
break;
}
return true;
@@ -1210,9 +1239,14 @@ class go_evil_book_for_dummies : public GameObjectScript
public:
go_evil_book_for_dummies() : GameObjectScript("go_evil_book_for_dummies") { }
inline bool HasLeatherSpecialty(Player* player)
{
return (player->HasSpell(S_DRAGON) || player->HasSpell(S_ELEMENTAL) || player->HasSpell(S_TRIBAL));
}
bool OnGossipHello(Player* player, GameObject* gameobject) override
{
//TAILORING SPEC
//ENGINEERING SPEC
if (player->HasSkill(SKILL_ENGINEERING) && player->GetBaseSkillValue(SKILL_ENGINEERING) >= 225 && player->getLevel() >= 35)
{
if (player->GetQuestRewardStatus(3643) || player->GetQuestRewardStatus(3641) || player->GetQuestRewardStatus(3639))
@@ -1233,6 +1267,17 @@ public:
}
}
//LEATHERWORKING SPEC
if (player->HasSkill(SKILL_LEATHERWORKING) && player->GetBaseSkillValue(SKILL_LEATHERWORKING) >= 225 && player->getLevel() >= 40)
{
if (!HasLeatherSpecialty(player) && (player->GetQuestRewardStatus(5141) || player->GetQuestRewardStatus(5143) || player->GetQuestRewardStatus(5144) || player->GetQuestRewardStatus(5145) || player->GetQuestRewardStatus(5146) || player->GetQuestRewardStatus(5148)))
{
AddGossipItemFor(player, GOSSIP_MENU_GO_SOOTHSAYING_FOR_DUMMIES, GOSSIP_MENU_OPTION_GO_LEARN_DRAGONSCALE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5);
AddGossipItemFor(player, GOSSIP_MENU_GO_SOOTHSAYING_FOR_DUMMIES, GOSSIP_MENU_OPTION_GO_LEARN_ELEMENTAL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6);
AddGossipItemFor(player, GOSSIP_MENU_GO_SOOTHSAYING_FOR_DUMMIES, GOSSIP_MENU_OPTION_GO_LEARN_TRIBAL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7);
}
}
SendGossipMenuFor(player, player->GetGossipTextId(gameobject), gameobject->GetGUID());
return true;
}
@@ -1257,6 +1302,18 @@ public:
case GOSSIP_ACTION_INFO_DEF + 4:
ProcessUnlearnAction(player, nullptr, S_UNLEARN_GNOMISH, 0, DoHighUnlearnCost(player));
break;
//Learn Dragon
case GOSSIP_ACTION_INFO_DEF + 5:
ProcessCastaction(player, nullptr, S_DRAGON, S_LEARN_DRAGON, 0);
break;
//Learn Elemental
case GOSSIP_ACTION_INFO_DEF + 6:
ProcessCastaction(player, nullptr, S_ELEMENTAL, S_LEARN_ELEMENTAL, 0);
break;
//Learn Tribal
case GOSSIP_ACTION_INFO_DEF + 7:
ProcessCastaction(player, nullptr, S_TRIBAL, S_LEARN_TRIBAL, 0);
break;
}
}
@@ -2923,6 +2923,14 @@ Arena.MaxRatingDifference = 150
Arena.RatingDiscardTimer = 600000
#
# Arena.PreviousOpponentsDiscardTimer
# Description: Time (in milliseconds) after which the previous opponents will be ignored.
# Default: 120000 - (Enabled, 2 minutes - Blizzlike)
# 0 - (Disabled)
Arena.PreviousOpponentsDiscardTimer = 120000
#
# Arena.AutoDistributePoints
# Description: Automatically distribute arena points.