From e74adf550e778bbbf182e1f4ef95ba2acb67fa19 Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Sun, 1 Mar 2026 21:54:15 -0300 Subject: [PATCH] feat(Core/Scripting): Add Battlefield scripting hooks and API (#24957) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/server/game/Battlefield/Battlefield.cpp | 11 +++ src/server/game/Battlefield/Battlefield.h | 7 ++ .../ScriptDefines/AllScriptsObjects.h | 1 + .../ScriptDefines/BattlefieldScript.cpp | 53 +++++++++++++ .../ScriptDefines/BattlefieldScript.h | 79 +++++++++++++++++++ src/server/game/Scripting/ScriptMgr.h | 7 ++ 6 files changed, 158 insertions(+) create mode 100644 src/server/game/Scripting/ScriptDefines/BattlefieldScript.cpp create mode 100644 src/server/game/Scripting/ScriptDefines/BattlefieldScript.h diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index 7a52fb9c1..a7235e2c9 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -17,6 +17,7 @@ #include "Battlefield.h" #include "BattlefieldMgr.h" +#include "ScriptMgr.h" #include "CellImpl.h" #include "CreatureTextMgr.h" #include "GameGraveyard.h" @@ -81,6 +82,10 @@ Battlefield::~Battlefield() // Called when a player enters the zone void Battlefield::HandlePlayerEnterZone(Player* player, uint32 /*zone*/) { + // Allow scripts to adjust the player's effective team or appearance before + // any team-based battlefield containers (such as player lists or queues) are updated. + sScriptMgr->OnBattlefieldPlayerEnterZone(this, player); + // Xinef: do not invite players on taxi if (!player->IsInFlight()) { @@ -126,6 +131,7 @@ void Battlefield::HandlePlayerLeaveZone(Player* player, uint32 /*zone*/) group->RemoveMember(player->GetGUID()); OnPlayerLeaveWar(player); + sScriptMgr->OnBattlefieldPlayerLeaveWar(this, player); } } @@ -138,6 +144,10 @@ void Battlefield::HandlePlayerLeaveZone(Player* player, uint32 /*zone*/) SendRemoveWorldStates(player); RemovePlayerFromResurrectQueue(player->GetGUID()); OnPlayerLeaveZone(player); + // Scripts must restore player->GetTeamId() here (e.g. ClearFakePlayer). + // All Battlefield data-structure cleanup above has already completed using + // the assigned team, so it is safe to restore the real team now. + sScriptMgr->OnBattlefieldPlayerLeaveZone(this, player); } bool Battlefield::Update(uint32 diff) @@ -434,6 +444,7 @@ void Battlefield::PlayerAcceptInviteToWar(Player* player) player->ToggleAFK(); OnPlayerJoinWar(player); //for scripting + sScriptMgr->OnBattlefieldPlayerJoinWar(this, player); } } diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h index f67e16862..0e767a441 100644 --- a/src/server/game/Battlefield/Battlefield.h +++ b/src/server/game/Battlefield/Battlefield.h @@ -354,6 +354,13 @@ public: uint32 GetTimer() { return m_Timer; } void SetTimer(uint32 timer) { m_Timer = timer; } + // Returns combined count of players in war + invited (per team) for balance checking + uint32 GetPlayersInWarCount(TeamId teamId) const { return static_cast(m_PlayersInWar[teamId].size() + m_InvitedPlayers[teamId].size()); } + // Returns total count of players in the battlefield zone per team + uint32 GetPlayersInZoneCount(TeamId teamId) const { return static_cast(m_players[teamId].size()); } + // Returns the maximum players allowed per team + uint32 GetMaxPlayersPerTeam() const { return m_MaxPlayer; } + void DoPlaySoundToAll(uint32 SoundID); void InvitePlayerToQueue(Player* player); diff --git a/src/server/game/Scripting/ScriptDefines/AllScriptsObjects.h b/src/server/game/Scripting/ScriptDefines/AllScriptsObjects.h index 92dc41756..ce22bbad4 100644 --- a/src/server/game/Scripting/ScriptDefines/AllScriptsObjects.h +++ b/src/server/game/Scripting/ScriptDefines/AllScriptsObjects.h @@ -32,6 +32,7 @@ #include "ArenaScript.h" #include "ArenaTeamScript.h" #include "AuctionHouseScript.h" +#include "BattlefieldScript.h" #include "BattlegroundMapScript.h" #include "BattlegroundScript.h" #include "CommandScript.h" diff --git a/src/server/game/Scripting/ScriptDefines/BattlefieldScript.cpp b/src/server/game/Scripting/ScriptDefines/BattlefieldScript.cpp new file mode 100644 index 000000000..106f02d23 --- /dev/null +++ b/src/server/game/Scripting/ScriptDefines/BattlefieldScript.cpp @@ -0,0 +1,53 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "BattlefieldScript.h" +#include "ScriptMgr.h" +#include "ScriptMgrMacros.h" + +void ScriptMgr::OnBattlefieldPlayerEnterZone(Battlefield* bf, Player* player) +{ + CALL_ENABLED_HOOKS(BattlefieldScript, BATTLEFIELDHOOK_ON_PLAYER_ENTER_ZONE, script->OnBattlefieldPlayerEnterZone(bf, player)); +} + +void ScriptMgr::OnBattlefieldPlayerLeaveZone(Battlefield* bf, Player* player) +{ + CALL_ENABLED_HOOKS(BattlefieldScript, BATTLEFIELDHOOK_ON_PLAYER_LEAVE_ZONE, script->OnBattlefieldPlayerLeaveZone(bf, player)); +} + +void ScriptMgr::OnBattlefieldPlayerJoinWar(Battlefield* bf, Player* player) +{ + CALL_ENABLED_HOOKS(BattlefieldScript, BATTLEFIELDHOOK_ON_PLAYER_JOIN_WAR, script->OnBattlefieldPlayerJoinWar(bf, player)); +} + +void ScriptMgr::OnBattlefieldPlayerLeaveWar(Battlefield* bf, Player* player) +{ + CALL_ENABLED_HOOKS(BattlefieldScript, BATTLEFIELDHOOK_ON_PLAYER_LEAVE_WAR, script->OnBattlefieldPlayerLeaveWar(bf, player)); +} + +BattlefieldScript::BattlefieldScript(char const* name, std::vector enabledHooks) : + ScriptObject(name, BATTLEFIELDHOOK_END) +{ + // If empty - enable all available hooks. + if (enabledHooks.empty()) + for (uint16 i = 0; i < BATTLEFIELDHOOK_END; ++i) + enabledHooks.emplace_back(i); + + ScriptRegistry::AddScript(this, std::move(enabledHooks)); +} + +template class AC_GAME_API ScriptRegistry; diff --git a/src/server/game/Scripting/ScriptDefines/BattlefieldScript.h b/src/server/game/Scripting/ScriptDefines/BattlefieldScript.h new file mode 100644 index 000000000..5f96741f7 --- /dev/null +++ b/src/server/game/Scripting/ScriptDefines/BattlefieldScript.h @@ -0,0 +1,79 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef SCRIPT_OBJECT_BATTLEFIELD_SCRIPT_H_ +#define SCRIPT_OBJECT_BATTLEFIELD_SCRIPT_H_ + +#include "ScriptObject.h" +#include + +enum BattlefieldHook +{ + BATTLEFIELDHOOK_ON_PLAYER_ENTER_ZONE, // 0 - fires at start of HandlePlayerEnterZone, before team assignment + BATTLEFIELDHOOK_ON_PLAYER_LEAVE_ZONE, // 1 - fires at end of HandlePlayerLeaveZone, after all cleanup + BATTLEFIELDHOOK_ON_PLAYER_JOIN_WAR, // 2 - fires after player is added to the active war + BATTLEFIELDHOOK_ON_PLAYER_LEAVE_WAR, // 3 - fires after player is removed from the active war + BATTLEFIELDHOOK_END +}; + +class Battlefield; +class Player; + +class BattlefieldScript : public ScriptObject +{ +protected: + BattlefieldScript(const char* name, std::vector enabledHooks = std::vector()); + +public: + [[nodiscard]] bool IsDatabaseBound() const override { return false; } + + /** + * @brief Called when a player enters the battlefield zone, before team-based data assignment. + * This is the ideal place to reassign a player's team for cross-faction purposes. + * + * @param bf The Battlefield instance + * @param player The player entering the zone + */ + virtual void OnBattlefieldPlayerEnterZone(Battlefield* /*bf*/, Player* /*player*/) { } + + /** + * @brief Called when a player leaves the battlefield zone, after all cleanup. + * This is the ideal place to restore a player's original team/faction. + * + * @param bf The Battlefield instance + * @param player The player leaving the zone + */ + virtual void OnBattlefieldPlayerLeaveZone(Battlefield* /*bf*/, Player* /*player*/) { } + + /** + * @brief Called after a player has been added to the active war (accepted the invitation). + * + * @param bf The Battlefield instance + * @param player The player joining the war + */ + virtual void OnBattlefieldPlayerJoinWar(Battlefield* /*bf*/, Player* /*player*/) { } + + /** + * @brief Called after a player has been removed from the active war. + * + * @param bf The Battlefield instance + * @param player The player leaving the war + */ + virtual void OnBattlefieldPlayerLeaveWar(Battlefield* /*bf*/, Player* /*player*/) { } +}; + +#endif // SCRIPT_OBJECT_BATTLEFIELD_SCRIPT_H_ diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 3687e455a..d0540acb1 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -43,6 +43,7 @@ class AuctionHouseObject; class AuraScript; +class Battlefield; class Battleground; class BattlegroundMap; class BattlegroundQueue; @@ -577,6 +578,12 @@ public: /* AllMapScript */ void OnBeforeCreateInstanceScript(InstanceMap* instanceMap, InstanceScript** instanceData, bool load, std::string data, uint32 completedEncounterMask); void OnDestroyInstance(MapInstanced* mapInstanced, Map* map); +public: /* BattlefieldScript */ + void OnBattlefieldPlayerEnterZone(Battlefield* bf, Player* player); + void OnBattlefieldPlayerLeaveZone(Battlefield* bf, Player* player); + void OnBattlefieldPlayerJoinWar(Battlefield* bf, Player* player); + void OnBattlefieldPlayerLeaveWar(Battlefield* bf, Player* player); + public: /* BGScript */ void OnBattlegroundStart(Battleground* bg); void OnBattlegroundEndReward(Battleground* bg, Player* player, TeamId winnerTeamId);