TrinityCore
BattlegroundWS.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "BattlegroundWS.h"
19#include "AreaTrigger.h"
20#include "BattlegroundMgr.h"
21#include "DB2Stores.h"
22#include "GameObject.h"
23#include "GameTime.h"
24#include "Log.h"
25#include "Map.h"
26#include "Object.h"
27#include "ObjectAccessor.h"
28#include "ObjectMgr.h"
29#include "Player.h"
30#include "SpellAuras.h"
31#include "SpellInfo.h"
32
33// these variables aren't used outside of this file, so declare them only here
35{
40};
41
43{
44 {20, 40, 40}, // normal honor
45 {60, 40, 80} // holiday
46};
47
49{
52};
53
54BattlegroundWS::BattlegroundWS(BattlegroundTemplate const* battlegroundTemplate) : Battleground(battlegroundTemplate)
55{
56 BgObjects.resize(0);
57 BgCreatures.resize(0);
58
62
63 _bothFlagsKept = false;
64
69
70 _flags = { };
72
75}
76
78
80{
82 {
84 {
86 {
87 if (GetTeamScore(TEAM_HORDE) == 0) // No one scored - result is tie
89 else // Horde has more points and thus wins
91 }
92 else if (GetTeamScore(TEAM_HORDE) == 0) // Alliance has > 0, Horde has 0, alliance wins
94 else if (GetTeamScore(TEAM_HORDE) == GetTeamScore(TEAM_ALLIANCE)) // Team score equal, winner is team that scored the last flag
96 else if (GetTeamScore(TEAM_HORDE) > GetTeamScore(TEAM_ALLIANCE)) // Last but not least, check who has the higher score
98 else
100 }
101
102 if (_bothFlagsKept)
103 {
106 {
109
110 // update assault debuff stacks
111 DoForFlagKeepers([&](Player* player) -> void
112 {
114 });
115 }
116 }
117 }
118}
119
120void BattlegroundWS::DoForFlagKeepers(std::function<void(Player*)> action) const
121{
122 for (ObjectGuid flagGUID : _flags)
123 {
124 if (GameObject* flag = GetBgMap()->GetGameObject(flagGUID))
125 {
126 if (Player* carrier = ObjectAccessor::FindPlayer(flag->GetFlagCarrierGUID()))
127 action(carrier);
128 }
129 }
130}
131
133{
134 _bothFlagsKept = false;
137 DoForFlagKeepers([&](Player* player) -> void
138 {
140 });
141}
142
144{
145 if (_assaultStackCount == 0)
146 return;
147
150 {
152 spellId = WS_SPELL_BRUTAL_ASSAULT;
153 }
154
155 Aura* aura = player->GetAura(spellId);
156 if (!aura)
157 {
158 player->CastSpell(player, spellId, true);
159 aura = player->GetAura(spellId);
160 }
161
162 if (aura)
164}
165
167{
170}
171
173{
174 for (ObjectGuid door : _doors)
175 {
176 if (GameObject* gameObject = GetBgMap()->GetGameObject(door))
177 {
178 gameObject->UseDoorOrButton();
179 gameObject->DespawnOrUnsummon(3s);
180 }
181 }
182
185
186 // players joining later are not eligibles
188}
189
191{
192 if (GameObject* gameObject = FindBgMap()->GetGameObject(_flags[team]))
193 return gameObject->GetFlagState();
194
195 return FlagState(0);
196}
197
199{
200 if (GameObject* gameObject = FindBgMap()->GetGameObject(_flags[team]))
201 return gameObject->GetFlagCarrierGUID();
202
203 return ObjectGuid::Empty;
204}
205
207{
208 DoForFlagKeepers([&](Player* player) -> void
209 {
212 if (trigger->GetInsideUnits().contains(player->GetGUID()))
213 if (CanCaptureFlag(trigger, player))
214 OnCaptureFlag(trigger, player);
215 });
216}
217
219{
220 auto transformValueToOtherTeamControlWorldState = [](FlagState value)
221 {
222 switch (value)
223 {
227 return 1;
228 case FlagState::Taken:
229 return 2;
230 default:
231 return 0;
232 }
233 };
234
235 if (team == ALLIANCE)
236 {
238 UpdateWorldState(BG_WS_FLAG_CONTROL_HORDE, transformValueToOtherTeamControlWorldState(value));
239 }
240 else
241 {
243 UpdateWorldState(BG_WS_FLAG_CONTROL_ALLIANCE, transformValueToOtherTeamControlWorldState(value));
244 }
245}
246
248{
249 if (team == TEAM_ALLIANCE)
251 else
253}
254
256{
257 return true;
258}
259
261{
262 //call parent's class reset
264
267
268 if (sBattlegroundMgr->IsBGWeekend(GetTypeID()))
269 {
271 m_HonorWinKills = 3;
272 m_HonorEndKills = 4;
273 }
274 else
275 {
277 m_HonorWinKills = 1;
278 m_HonorEndKills = 2;
279 }
281 _bothFlagsKept = false;
282
283 _doors.clear();
284 _flags = { };
288}
289
291{
292 // Win reward
293 if (winner == ALLIANCE)
295 if (winner == HORDE)
297
298 // Complete map_end rewards (even if no team wins)
301
303}
304
306{
308 return;
309
311
312 Battleground::HandleKillPlayer(player, killer);
313}
314
316{
317 return sObjectMgr->GetClosestGraveyard(*player, player->GetBGTeam(), player);
318}
319
321{
323}
324
326{
328 return ALLIANCE;
330 return HORDE;
331
333}
334
336{
337 switch (gameObject->GetEntry())
338 {
345 _doors.insert(gameObject->GetGUID());
346 break;
348 _flags[TEAM_ALLIANCE] = gameObject->GetGUID();
349 break;
351 _flags[TEAM_HORDE] = gameObject->GetGUID();
352 break;
353 default:
354 break;
355 }
356}
357
359{
360 if (!areaTrigger->IsStaticSpawn())
361 return;
362
363 switch (areaTrigger->GetEntry())
364 {
367 break;
370 break;
371 default:
372 break;
373 }
374}
375
376void BattlegroundWS::OnFlagStateChange(GameObject* flagInBase, FlagState /*oldValue*/, FlagState newValue, Player* player)
377{
378 Team team = flagInBase->GetEntry() == BG_WS_OBJECT_HORDE_FLAG_IN_BASE ? HORDE : ALLIANCE;
379 TeamId otherTeamId = GetTeamIndexByTeamId(GetOtherTeam(team));
380
381 UpdateFlagState(team, newValue);
382
383 switch (newValue)
384 {
386 {
388 {
390 if (player)
391 {
392 // flag got returned to base by player interaction
393 UpdatePvpStat(player, PVP_STAT_FLAG_RETURNS, 1); // +1 flag returns
394
395 if (team == ALLIANCE)
396 {
399 }
400 else
401 {
404 }
405 }
406 // Flag respawned due to timeout/capture
407 else if (GetFlagState(otherTeamId) != FlagState::Respawning)
408 {
409 // if other flag is respawning, we will let that one handle the message and sound to prevent double message/sound.
412 }
413
415 }
416 break;
417 }
419 {
422
423 uint32 recentlyDroppedSpellId = SPELL_RECENTLY_DROPPED_HORDE_FLAG;
424 if (team == ALLIANCE)
425 {
426 recentlyDroppedSpellId = SPELL_RECENTLY_DROPPED_ALLIANCE_FLAG;
428 }
429 else
431
432 player->CastSpell(player, recentlyDroppedSpellId, true);
433 break;
434 }
435 case FlagState::Taken:
436 {
437 if (team == HORDE)
438 {
441 }
442 else
443 {
446 }
447
448 if (GetFlagState(otherTeamId) == FlagState::Taken)
449 _bothFlagsKept = true;
450
452
453 flagInBase->CastSpell(player, BG_WS_SPELL_QUICK_CAP_TIMER, true);
455 break;
456 }
459 break;
460 default:
461 break;
462 }
463}
464
466{
468 return false;
469
470 Team team = GetPlayerTeam(player->GetGUID());
471 TeamId teamId = GetTeamIndexByTeamId(team);
472 TeamId otherTeamId = GetTeamIndexByTeamId(GetOtherTeam(team));
473
474 if (areaTrigger->GetGUID() != _capturePointAreaTriggers[teamId])
475 return false;
476
477 // check if enemy flag's carrier is this player
478 if (GetFlagCarrierGUID(otherTeamId) != player->GetGUID())
479 return false;
480
481 // check that team's flag is in base
482 return GetFlagState(teamId) == FlagState::InBase;
483}
484
485void BattlegroundWS::OnCaptureFlag(AreaTrigger* /*areaTrigger*/, Player* player)
486{
487 Team winner = TEAM_OTHER;
488
489 Team team = GetPlayerTeam(player->GetGUID());
490 TeamId teamId = GetTeamIndexByTeamId(team);
491 TeamId otherTeamId = GetTeamIndexByTeamId(GetOtherTeam(team));
492
493 /*
494 1. Update flag states & score world states
495 2. udpate points
496 3. chat message & sound
497 4. update criterias & achievements
498 5. remove all related auras
499 ?. Reward honor & reputation
500 */
501
502 // 1. update the flag states
503 for (uint8 i = 0; i < _flags.size(); i++)
504 if (GameObject* gameObject = GetBgMap()->GetGameObject(_flags[i]))
505 gameObject->HandleCustomTypeCommand(GameObjectType::SetNewFlagState(FlagState::Respawning, player));
506
507 // 2. update points
509 AddPoint(team, 1);
510
511 UpdateTeamScore(teamId);
512
513 // 3. chat message & sound
514 if (team == ALLIANCE)
515 {
520 }
521 else
522 {
527 }
528
529 // 4. update criteria's for achievement, player score etc.
530 UpdatePvpStat(player, PVP_STAT_FLAG_CAPTURES, 1); // +1 flag captures
531
532 // 5. Remove all related auras
534
535 if (GameObject* gameObject = GetBgMap()->GetGameObject(_flags[otherTeamId]))
536 player->RemoveAurasDueToSpell(gameObject->GetGOInfo()->newflag.pickupSpell, gameObject->GetGUID());
537
539
541
543
544 // update last flag capture to be used if teamscore is equal
545 SetLastFlagCapture(team);
546
547 if (GetTeamScore(teamId) == BG_WS_MAX_TEAM_SCORE)
548 winner = team;
549
550 if (winner)
551 {
555
557 EndBattleground(winner);
558 }
559}
#define sBattlegroundMgr
WarsongGulchPvpStats
@ PVP_STAT_FLAG_CAPTURES
@ PVP_STAT_FLAG_RETURNS
uint32 BG_WSG_Honor[2][BG_WSG_REWARD_NUM]
BG_WSG_Rewards
@ BG_WSG_FLAG_CAP
@ BG_WSG_WIN
@ BG_WSG_REWARD_NUM
@ BG_WSG_MAP_COMPLETE
@ WS_EXPLOIT_TELEPORT_LOCATION_HORDE
@ WS_EXPLOIT_TELEPORT_LOCATION_ALLIANCE
static constexpr uint32 WS_EVENT_START_BATTLE
@ BG_WS_SPELL_QUICK_CAP_TIMER
@ BG_WS_SOUND_FLAG_CAPTURED_HORDE
@ BG_WS_SOUND_FLAGS_RESPAWNED
@ BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE
@ BG_WS_SOUND_HORDE_FLAG_PICKED_UP
@ BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP
@ BG_WS_SOUND_FLAG_RETURNED
static constexpr uint16 FLAG_BRUTAL_ASSAULT_STACK_COUNT
@ WS_SPELL_BRUTAL_ASSAULT
@ SPELL_CAPTURED_HORDE_COSMETIC_FX
@ SPELL_CAPTURED_ALLIANCE_COSMETIC_FX
@ WS_SPELL_FOCUSED_ASSAULT
@ BG_WS_TEXT_START_HALF_MINUTE
@ BG_WS_TEXT_HORDE_FLAG_PICKED_UP
@ BG_WS_TEXT_ALLIANCE_FLAG_DROPPED
@ BG_WS_TEXT_ALLIANCE_FLAG_RETURNED
@ BG_WS_TEXT_ALLIANCE_FLAG_PICKED_UP
@ BG_WS_TEXT_CAPTURED_HORDE_FLAG
@ BG_WS_TEXT_BATTLE_HAS_BEGUN
@ BG_WS_TEXT_CAPTURED_ALLIANCE_FLAG
@ BG_WS_TEXT_HORDE_FLAG_DROPPED
@ BG_WS_TEXT_START_ONE_MINUTE
@ BG_WS_TEXT_HORDE_FLAG_RETURNED
@ BG_WS_TEXT_FLAGS_PLACED
static constexpr Seconds FLAG_ASSAULT_TIMER
@ BG_WS_OBJECT_HORDE_FLAG_IN_BASE
@ BG_WS_OBJECT_PORTCULLIS_002
@ BG_WS_OBJECT_HORDE_GATE_1
@ BG_WS_OBJECT_HORDE_GATE_2
@ BG_WS_OBJECT_COLLISION_PC_SIZE
@ BG_WS_OBJECT_ALLIANCE_FLAG_IN_BASE
@ BG_WS_OBJECT_PORTCULLIS_009
@ BG_WS_OBJECT_ALLIANCE_DOOR
@ BG_WS_MAX_TEAM_SCORE
@ AT_CAPTURE_POINT_HORDE
@ AT_CAPTURE_POINT_ALLIANCE
@ BG_WS_STATE_TIMER
@ BG_WS_FLAG_STATE_HORDE
@ BG_WS_FLAG_STATE_ALLIANCE
@ BG_WS_FLAG_CAPTURES_HORDE
@ BG_WS_STATE_TIMER_ACTIVE
@ BG_WS_FLAG_CONTROL_HORDE
@ BG_WS_FLAG_CONTROL_ALLIANCE
@ BG_WS_FLAG_CAPTURES_ALLIANCE
@ SPELL_RECENTLY_DROPPED_ALLIANCE_FLAG
Definition: Battleground.h:111
@ SPELL_RECENTLY_DROPPED_HORDE_FLAG
Definition: Battleground.h:112
@ STATUS_IN_PROGRESS
Definition: Battleground.h:167
@ BG_STARTING_EVENT_THIRD
Definition: Battleground.h:208
@ BG_STARTING_EVENT_SECOND
Definition: Battleground.h:207
@ BG_STARTING_EVENT_FOURTH
Definition: Battleground.h:209
@ IN_MILLISECONDS
Definition: Common.h:35
@ MINUTE
Definition: Common.h:29
uint8_t uint8
Definition: Define.h:144
uint32_t uint32
Definition: Define.h:142
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition: Duration.h:32
FlagState
Definition: GameObject.h:46
#define sObjectMgr
Definition: ObjectMgr.h:1946
TeamId
@ TEAM_ALLIANCE
@ TEAM_HORDE
Team
@ TEAM_OTHER
@ ALLIANCE
@ HORDE
@ CHAT_MSG_BG_SYSTEM_ALLIANCE
@ CHAT_MSG_BG_SYSTEM_HORDE
@ CHAT_MSG_BG_SYSTEM_NEUTRAL
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:491
bool IsStaticSpawn() const
Definition: AreaTrigger.h:78
void SetStackAmount(uint8 num)
static bool IsBGWeekend(BattlegroundTypeId bgTypeId)
TimeTracker _flagAssaultTimer
uint32 m_HonorWinKills
WorldSafeLocsEntry const * GetClosestGraveyard(Player *player) override
void EndBattleground(Team winner) override
uint32 m_ReputationCapture
void HandleKillPlayer(Player *player, Player *killer) override
uint32 m_HonorEndKills
std::array< ObjectGuid, 2 > _flags
void OnFlagStateChange(GameObject *flagInBase, FlagState oldValue, FlagState newValue, Player *player) override
BattlegroundWS(BattlegroundTemplate const *battlegroundTemplate)
FlagState GetFlagState(TeamId team) const
void Reset() override
void UpdateFlagState(uint32 team, FlagState value)
void HandleFlagRoomCapturePoint()
void SetLastFlagCapture(Team team)
void RemoveAssaultDebuffFromPlayer(Player *player)
std::array< ObjectGuid, 2 > _capturePointAreaTriggers
Team GetPrematureWinner() override
void UpdateTeamScore(TeamId team)
bool SetupBattleground() override
void OnGameObjectCreate(GameObject *gameObject) override
void OnAreaTriggerCreate(AreaTrigger *areaTrigger) override
void ApplyAssaultDebuffToPlayer(Player *player)
WorldSafeLocsEntry const * GetExploitTeleportLocation(Team team) override
ObjectGuid const & GetFlagCarrierGUID(TeamId team) const
void OnCaptureFlag(AreaTrigger *areatrigger, Player *player) override
void PostUpdateImpl(uint32 diff) override
Post-update hook.
void AddPoint(Team team, uint32 Points=1)
void DoForFlagKeepers(std::function< void(Player *)> action) const
uint16 _assaultStackCount
void StartingEventOpenDoors() override
bool CanCaptureFlag(AreaTrigger *areatrigger, Player *player) override
virtual Team GetPrematureWinner()
virtual void HandleKillPlayer(Player *player, Player *killer)
virtual void Reset()
void PlaySoundToAll(uint32 SoundID)
uint32 GetTeamScore(TeamId teamId) const
GuidVector BgObjects
Definition: Battleground.h:443
void RewardHonorToTeam(uint32 Honor, Team team)
BattlegroundMap * GetBgMap() const
BattlegroundMap * FindBgMap() const
Definition: Battleground.h:351
BattlegroundTypeId GetTypeID() const
void TriggerGameEvent(uint32 gameEventId, WorldObject *source=nullptr, WorldObject *target=nullptr) override
int32 m_TeamScores[PVP_TEAMS_COUNT]
Definition: Battleground.h:565
GuidVector BgCreatures
Definition: Battleground.h:444
Team GetOtherTeam(Team team) const
static TeamId GetTeamIndexByTeamId(Team team)
Definition: Battleground.h:392
void UpdateWorldState(int32 worldStateId, int32 value, bool hidden=false)
virtual void EndBattleground(Team winner)
void SendBroadcastText(uint32 id, ChatMsg msgType, WorldObject const *target=nullptr)
void RewardReputationToTeam(uint32 faction_id, uint32 Reputation, Team team)
BattlegroundStatus GetStatus() const
Definition: Battleground.h:284
Team GetPlayerTeam(ObjectGuid guid) const
virtual void EventPlayerDroppedFlag(Player *)
Definition: Battleground.h:420
uint32 GetBonusHonorFromKill(uint32 kills) const
void UpdatePvpStat(Player *player, uint32 pvpStatId, uint32 value)
uint32 GetElapsedTime() const
Definition: Battleground.h:286
uint32 StartMessageIds[BG_STARTING_EVENT_COUNT]
Definition: Battleground.h:563
time_t GetFlagTakenFromBaseTime() const
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
uint32 GetEntry() const
Definition: Object.h:161
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
void StartCriteria(CriteriaStartEvent startEvent, uint32 entry, Milliseconds timeLost=Milliseconds::zero())
Definition: Player.cpp:26756
Team GetBGTeam() const
Definition: Player.cpp:23609
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4560
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition: Unit.cpp:4101
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3831
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
time_t GetGameTime()
Definition: GameTime.cpp:44
TC_GAME_API GameObject * GetGameObject(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API AreaTrigger * GetAreaTrigger(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
void Update(int32 diff)
Definition: Timer.h:121
bool Passed() const
Definition: Timer.h:131
void Reset(int32 expiry)
Definition: Timer.h:136