Skip to content

feat(Core): make BGs and Arena prep time configurable #22136

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/server/apps/worldserver/worldserver.conf.dist
Original file line number Diff line number Diff line change
Expand Up @@ -3490,6 +3490,14 @@ Wintergrasp.CrashRestartTimer = 10

###################################################################################################
# BATTLEGROUND
#
# Battleground.PrepTime
# Description: Time (in seconds) for battleground preparation phase. Strand of the Ancients will be
# the exception and will always use the default 120 seconds timer, due to its boat timing mechanic.
# Default: 120

Battleground.PrepTime = 120

#
# Battleground.CastDeserter
# Description: Cast Deserter spell at players who leave battlegrounds in progress.
Expand Down Expand Up @@ -3755,6 +3763,13 @@ Battleground.EyeOfTheStorm.CapturePoints = 1600

###################################################################################################
# ARENA
#
# Arena.PrepTime
# Description: Time (in seconds) for arena preparation phase.
# Default: 60

Arena.PrepTime = 60

#
# Arena.MaxRatingDifference
# Description: Maximum rating difference between two teams in rated matches.
Expand Down
123 changes: 106 additions & 17 deletions src/server/game/Battlegrounds/Battleground.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ Battleground::Battleground()
m_TeamScores[TEAM_ALLIANCE] = 0;
m_TeamScores[TEAM_HORDE] = 0;

for (int i = 0; i < 5; i++)
m_AnnouncementsMade[i] = false;

m_PrematureCountDown = false;
m_PrematureCountDownTimer = 0;

Expand Down Expand Up @@ -494,29 +497,105 @@ inline void Battleground::_ProcessJoin(uint32 diff)
}

StartingEventCloseDoors();
SetStartDelayTime(StartDelayTimes[BG_STARTING_EVENT_FIRST]);

// First start warning - 2 or 1 minute
if (StartMessageIds[BG_STARTING_EVENT_FIRST])
SendBroadcastText(StartMessageIds[BG_STARTING_EVENT_FIRST], CHAT_MSG_BG_SYSTEM_NEUTRAL);
// Set the initial delay based on configuration
uint32 initialDelay;

// Special case for Strand of the Ancients - always use 120 seconds due to boat timing mechanics
if (GetBgTypeID() == BATTLEGROUND_SA)
{
initialDelay = 120 * IN_MILLISECONDS;
}
else
{
initialDelay = isArena() ? GetArenaPrepTime() * IN_MILLISECONDS : GetBattlegroundPrepTime() * IN_MILLISECONDS;
}

SetStartDelayTime(initialDelay);

// Initialize which announcements should be skipped based on the initial delay
if (!isArena())
{
// For battlegrounds
// If initial delay is less than 2 minutes, mark the 2-minute announcement as already made
if (initialDelay < BG_ANNOUNCEMENT_TWO_MINUTE)
m_AnnouncementsMade[0] = true;

// If initial delay is less than 1 minute, mark the 1-minute announcement as already made
if (initialDelay < BG_ANNOUNCEMENT_ONE_MINUTE)
m_AnnouncementsMade[1] = true;

// If initial delay is less than 30 seconds, mark the 30-second announcement as already made
if (initialDelay < BG_ANNOUNCEMENT_HALF_MINUTE)
m_AnnouncementsMade[2] = true;
}
else
{
// For arenas
// If initial delay is less than 1 minute, mark the 1-minute announcement as already made
if (initialDelay < BG_ANNOUNCEMENT_ONE_MINUTE)
m_AnnouncementsMade[1] = true;

// If initial delay is less than 30 seconds, mark the 30-second announcement as already made
if (initialDelay < BG_ANNOUNCEMENT_HALF_MINUTE)
m_AnnouncementsMade[2] = true;

// If initial delay is less than 15 seconds, mark the 15-second announcement as already made
if (initialDelay < BG_ANNOUNCEMENT_QUARTER_MINUTE)
m_AnnouncementsMade[3] = true;
}
}
// After 1 minute or 30 seconds, warning is signaled
else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_SECOND] && !(m_Events & BG_STARTING_EVENT_2))

// Get the current delay time
uint32 currentTime = GetStartDelayTime();

// Check for battleground announcements based on absolute time thresholds
if (!isArena())
{
m_Events |= BG_STARTING_EVENT_2;
// Battleground announcements at 120s, 60s, 30s, 0s

if (StartMessageIds[BG_STARTING_EVENT_SECOND])
SendBroadcastText(StartMessageIds[BG_STARTING_EVENT_SECOND], CHAT_MSG_BG_SYSTEM_NEUTRAL);
// Two minute announcement (120s)
if (!m_AnnouncementsMade[0] && currentTime <= BG_ANNOUNCEMENT_TWO_MINUTE && currentTime > BG_ANNOUNCEMENT_ONE_MINUTE)
{
m_AnnouncementsMade[0] = true;
SendBroadcastText(BG_TEXT_START_TWO_MINUTES, CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
// One minute announcement (60s)
else if (!m_AnnouncementsMade[1] && currentTime <= BG_ANNOUNCEMENT_ONE_MINUTE && currentTime > BG_ANNOUNCEMENT_HALF_MINUTE)
{
m_AnnouncementsMade[1] = true;
SendBroadcastText(BG_TEXT_START_ONE_MINUTE, CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
// Thirty seconds announcement (30s)
else if (!m_AnnouncementsMade[2] && currentTime <= BG_ANNOUNCEMENT_HALF_MINUTE && currentTime > 0)
{
m_AnnouncementsMade[2] = true;
SendBroadcastText(BG_TEXT_START_HALF_MINUTE, CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
}
// After 30 or 15 seconds, warning is signaled
else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_THIRD] && !(m_Events & BG_STARTING_EVENT_3))
else
{
m_Events |= BG_STARTING_EVENT_3;
// Arena announcements at 60s, 30s, 15s, 0s

if (StartMessageIds[BG_STARTING_EVENT_THIRD])
SendBroadcastText(StartMessageIds[BG_STARTING_EVENT_THIRD], CHAT_MSG_BG_SYSTEM_NEUTRAL);
// One minute announcement (60s)
if (!m_AnnouncementsMade[1] && currentTime <= BG_ANNOUNCEMENT_ONE_MINUTE && currentTime > BG_ANNOUNCEMENT_HALF_MINUTE)
{
m_AnnouncementsMade[1] = true;
SendBroadcastText(ARENA_TEXT_START_ONE_MINUTE, CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
// Thirty seconds announcement (30s)
else if (!m_AnnouncementsMade[2] && currentTime <= BG_ANNOUNCEMENT_HALF_MINUTE && currentTime > BG_ANNOUNCEMENT_QUARTER_MINUTE)
{
m_AnnouncementsMade[2] = true;
SendBroadcastText(ARENA_TEXT_START_THIRTY_SECONDS, CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
// Fifteen seconds announcement (15s)
else if (!m_AnnouncementsMade[3] && currentTime <= BG_ANNOUNCEMENT_QUARTER_MINUTE && currentTime > 0)
{
m_AnnouncementsMade[3] = true;
SendBroadcastText(ARENA_TEXT_START_FIFTEEN_SECONDS, CHAT_MSG_BG_SYSTEM_NEUTRAL);

if (isArena())
// Remove the ready markers for arenas
switch (GetBgTypeID())
{
case BATTLEGROUND_NA:
Expand All @@ -542,12 +621,16 @@ inline void Battleground::_ProcessJoin(uint32 diff)
default:
break;
}
}
}
// Delay expired (after 2 or 1 minute)
else if (GetStartDelayTime() <= 0 && !(m_Events & BG_STARTING_EVENT_4))

// Delay expired (timer reached 0)
if (GetStartDelayTime() <= 0 && !(m_Events & BG_STARTING_EVENT_4))
{
m_Events |= BG_STARTING_EVENT_4;
m_AnnouncementsMade[4] = true;

// Start the battle
StartingEventOpenDoors();

if (StartMessageIds[BG_STARTING_EVENT_FOURTH])
Expand Down Expand Up @@ -1087,6 +1170,12 @@ void Battleground::Init()
m_BgInvitedPlayers[TEAM_HORDE] = 0;
_InBGFreeSlotQueue = false;

// Set the start delay based on configuration
if (isArena())
SetStartDelayTime(GetArenaPrepTime() * IN_MILLISECONDS);
else
SetStartDelayTime(GetBattlegroundPrepTime() * IN_MILLISECONDS);

m_Players.clear();

for (auto const& itr : PlayerScores)
Expand Down
11 changes: 11 additions & 0 deletions src/server/game/Battlegrounds/Battleground.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,9 @@ class Battleground
[[nodiscard]] uint32 GetMinLevel() const { return m_LevelMin; }
[[nodiscard]] uint32 GetMaxLevel() const { return m_LevelMax; }

static uint32 GetBattlegroundPrepTime() { return sWorld->getIntConfig(CONFIG_BATTLEGROUND_PREP_TIME); }
static uint32 GetArenaPrepTime() { return sWorld->getIntConfig(CONFIG_ARENA_PREP_TIME); }

[[nodiscard]] bool isTemplate() const { return m_IsTemplate; }
[[nodiscard]] bool isMaxLevel() const
{
Expand Down Expand Up @@ -614,6 +617,14 @@ class Battleground
void _ProcessJoin(uint32 diff);
void _CheckSafePositions(uint32 diff);

bool m_AnnouncementsMade[5]; // Array to track which announcements have been made

// Absolute announcement times (in milliseconds)
static constexpr uint32 BG_ANNOUNCEMENT_TWO_MINUTE = 120000; // 2 minutes
static constexpr uint32 BG_ANNOUNCEMENT_ONE_MINUTE = 60000; // 1 minute
static constexpr uint32 BG_ANNOUNCEMENT_HALF_MINUTE = 30000; // 30 seconds
static constexpr uint32 BG_ANNOUNCEMENT_QUARTER_MINUTE = 15000; // 15 seconds

// Scorekeeping
BattlegroundScoreMap PlayerScores; // Player scores
// must be implemented in BG subclass
Expand Down
2 changes: 2 additions & 0 deletions src/server/game/World/IWorld.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ enum WorldIntConfigs
CONFIG_DEATH_SICKNESS_LEVEL,
CONFIG_INSTANT_LOGOUT,
CONFIG_DISABLE_BREATHING,
CONFIG_BATTLEGROUND_PREP_TIME,
CONFIG_BATTLEGROUND_OVERRIDE_LOWLEVELS_MINPLAYERS,
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_SPAM_DELAY,
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_TIMER,
Expand All @@ -325,6 +326,7 @@ enum WorldIntConfigs
CONFIG_BATTLEGROUND_ALTERAC_REP_ONBOSSDEATH,
CONFIG_BATTLEGROUND_EYEOFTHESTORM_CAPTUREPOINTS,
CONFIG_WINTERGRASP_ENABLE,
CONFIG_ARENA_PREP_TIME,
CONFIG_ARENA_MAX_RATING_DIFFERENCE,
CONFIG_ARENA_RATING_DISCARD_TIMER,
CONFIG_ARENA_PREV_OPPONENTS_DISCARD_TIMER,
Expand Down
2 changes: 2 additions & 0 deletions src/server/game/World/World.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,7 @@ void World::LoadConfigSettings(bool reload)
_float_configs[CONFIG_LISTEN_RANGE_TEXTEMOTE] = sConfigMgr->GetOption<float>("ListenRange.TextEmote", 25.0f);
_float_configs[CONFIG_LISTEN_RANGE_YELL] = sConfigMgr->GetOption<float>("ListenRange.Yell", 300.0f);

_int_configs[CONFIG_BATTLEGROUND_PREP_TIME] = sConfigMgr->GetOption<int32>("Battleground.PrepTime", 120);
_int_configs[CONFIG_BATTLEGROUND_OVERRIDE_LOWLEVELS_MINPLAYERS] = sConfigMgr->GetOption<uint32>("Battleground.Override.LowLevels.MinPlayers", 0);
_bool_configs[CONFIG_BATTLEGROUND_DISABLE_QUEST_SHARE_IN_BG] = sConfigMgr->GetOption<bool>("Battleground.DisableQuestShareInBG", false);
_bool_configs[CONFIG_BATTLEGROUND_DISABLE_READY_CHECK_IN_BG] = sConfigMgr->GetOption<bool>("Battleground.DisableReadyCheckInBG", false);
Expand Down Expand Up @@ -936,6 +937,7 @@ void World::LoadConfigSettings(bool reload)
_int_configs[CONFIG_BATTLEGROUND_ALTERAC_REP_ONBOSSDEATH] = sConfigMgr->GetOption<uint32>("Battleground.Alterac.ReputationOnBossDeath", 350);
_int_configs[CONFIG_BATTLEGROUND_EYEOFTHESTORM_CAPTUREPOINTS] = sConfigMgr->GetOption<uint32>("Battleground.EyeOfTheStorm.CapturePoints", 1600);

_int_configs[CONFIG_ARENA_PREP_TIME] = sConfigMgr->GetOption<int32>("Arena.PrepTime", 60);
_int_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfigMgr->GetOption<uint32>("Arena.MaxRatingDifference", 150);
_int_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfigMgr->GetOption<uint32>("Arena.RatingDiscardTimer", 10 * MINUTE * IN_MILLISECONDS);
_int_configs[CONFIG_ARENA_PREV_OPPONENTS_DISCARD_TIMER] = sConfigMgr->GetOption<uint32>("Arena.PreviousOpponentsDiscardTimer", 2 * MINUTE * IN_MILLISECONDS);
Expand Down