OregonCore  revision fb2a440-git
Your Favourite TBC server
BattlegroundAB.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore 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 "Object.h"
19 #include "Player.h"
20 #include "Battleground.h"
21 #include "BattlegroundAB.h"
22 #include "Creature.h"
23 #include "MapManager.h"
24 #include "Language.h"
25 #include "Utilities/Util.h"
26 
27 // these variables aren't used outside of this file, so declare them only here
29 {
30  330, // normal honor
31  200 // holiday
32 };
33 
35 {
36  200, // normal honor
37  150 // holiday
38 };
39 
41 {
42  m_BuffChange = true;
45 
50 }
51 
53 {
54 }
55 
57 {
59 
61  {
62  int team_points[BG_TEAMS_COUNT] = { 0, 0 };
63 
64  for (int node = 0; node < BG_AB_NODES_MAX; ++node)
65  {
66  // 3 sec delay to spawn new banner instead previous despawned one
67  if (m_BannerTimers[node].timer)
68  {
69  if (m_BannerTimers[node].timer > diff)
70  m_BannerTimers[node].timer -= diff;
71  else
72  {
73  m_BannerTimers[node].timer = 0;
74  _CreateBanner(node, m_BannerTimers[node].type, m_BannerTimers[node].teamIndex, false);
75  }
76  }
77 
78  // 1-minute to occupy a node from contested state
79  if (m_NodeTimers[node])
80  {
81  if (m_NodeTimers[node] > diff)
82  m_NodeTimers[node] -= diff;
83  else
84  {
85  m_NodeTimers[node] = 0;
86  // Change from contested to occupied !
87  uint8 teamIndex = m_Nodes[node] - 1;
88  m_prevNodes[node] = m_Nodes[node];
89  m_Nodes[node] += 2;
90  // burn current contested banner
91  _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex);
92  // create new occupied banner
93  _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
94  _SendNodeUpdate(node);
95  _NodeOccupied(node, (teamIndex == 0) ? ALLIANCE : HORDE);
96  // Message to chatlog
97 
98  if (teamIndex == 0)
99  {
102  }
103  else
104  {
107  }
108  }
109  }
110 
111  for (int team = 0; team < BG_TEAMS_COUNT; ++team)
112  if (m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED)
113  ++team_points[team];
114  }
115 
116  // Accumulate points
117  for (int team = 0; team < BG_TEAMS_COUNT; ++team)
118  {
119  int points = team_points[team];
120  if (!points)
121  continue;
122  m_lastTick[team] += diff;
123  if (m_lastTick[team] > BG_AB_TickIntervals[points])
124  {
125  m_lastTick[team] -= BG_AB_TickIntervals[points];
126  m_TeamScores[team] += BG_AB_TickPoints[points];
127  m_score[team] = m_TeamScores[team];
128  m_HonorScoreTics[team] += BG_AB_TickPoints[points];
129  m_ReputationScoreTics[team] += BG_AB_TickPoints[points];
131  {
134  }
135  if (m_HonorScoreTics[team] >= BG_AB_HonorScoreTicks[m_HonorMode])
136  {
139  }
141  {
142  if (team == BG_TEAM_ALLIANCE)
144  else
148  }
149 
152  if (team == BG_TEAM_ALLIANCE)
154  if (team == BG_TEAM_HORDE)
156  }
157  }
158 
159  // Test win condition
164  }
165 }
166 
168 {
169  // despawn banners, auras and buffs
170  for (int obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_NODES_MAX * 8; ++obj)
172  for (int i = 0; i < BG_AB_NODES_MAX * 3; ++i)
174 
175  // Starting doors
180 
181  // Starting base spirit guides
184 }
185 
187 {
188  // spawn neutral banners
189  for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i)
191  for (int i = 0; i < BG_AB_NODES_MAX; ++i)
192  {
193  //randomly select buff to spawn
194  uint8 buff = urand(0, 2);
196  }
199 }
200 
202 {
204  //create score and add it to map, default values are set in the constructor
206 
207  m_PlayerScores[plr->GetGUID()] = sc;
208 }
209 
211 {
212 
213 }
214 
216 {
217  if (GetStatus() != STATUS_IN_PROGRESS)
218  return;
219 
220  switch (Trigger)
221  {
222  case 3948: // Arathi Basin Alliance Exit.
223  if (Source->GetTeam() != ALLIANCE)
224  Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal");
225  else
226  Source->LeaveBattleground();
227  break;
228  case 3949: // Arathi Basin Horde Exit.
229  if (Source->GetTeam() != HORDE)
230  Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal");
231  else
232  Source->LeaveBattleground();
233  break;
234  case 3866: // Stables
235  case 3869: // Gold Mine
236  case 3867: // Farm
237  case 3868: // Lumber Mill
238  case 3870: // Black Smith
239  case 4020: // Unk1
240  case 4021: // Unk2
241  //break;
242  default:
243  //sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
244  //Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
245  break;
246  }
247 }
248 
249 /* type: 0-neutral, 1-contested, 3-occupied
250  teamIndex: 0-ally, 1-horde */
251 void BattlegroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay)
252 {
253  // Just put it into the queue
254  if (delay)
255  {
256  m_BannerTimers[node].timer = 2000;
257  m_BannerTimers[node].type = type;
258  m_BannerTimers[node].teamIndex = teamIndex;
259  return;
260  }
261 
262  uint8 obj = node * 8 + type + teamIndex;
263 
265 
266  // handle aura with banner
267  if (!type)
268  return;
269  obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
271 }
272 
273 void BattlegroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex)
274 {
275  uint8 obj = node * 8 + type + teamIndex;
277 
278  // handle aura with banner
279  if (!type)
280  return;
281  obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
283 }
284 
286 {
287  switch (node)
288  {
289  case BG_AB_NODE_STABLES:
293  case BG_AB_NODE_FARM:
294  return LANG_BG_AB_NODE_FARM;
299  default:
300  ASSERT(0);
301  }
302  return 0;
303 }
304 
306 {
307  const uint8 plusArray[] = {0, 2, 3, 0, 1};
308 
309  // Node icons
310  for (uint8 node = 0; node < BG_AB_NODES_MAX; ++node)
311  data << uint32(BG_AB_OP_NODEICONS[node]) << uint32((m_Nodes[node] == 0) ? 1 : 0);
312 
313  // Node occupied states
314  for (uint8 node = 0; node < BG_AB_NODES_MAX; ++node)
315  for (uint8 i = 1; i < BG_AB_NODES_MAX; ++i)
316  data << uint32(BG_AB_OP_NODESTATES[node] + plusArray[i]) << uint32((m_Nodes[node] == i) ? 1 : 0);
317 
318  // How many bases each team owns
319  uint8 ally = 0, horde = 0;
320  for (uint8 node = 0; node < BG_AB_NODES_MAX; ++node)
322  ++ally;
323  else if (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)
324  ++horde;
325 
326  data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY) << uint32(ally);
327  data << uint32(BG_AB_OP_OCCUPIED_BASES_HORDE) << uint32(horde);
328 
329  // Team scores
334 
335  // other unknown
336  data << uint32(0x745) << uint32(0x2); // 37 1861 unk
337 }
338 
340 {
341  // Send node owner state update to refresh map icons on client
342  const uint8 plusArray[] = {0, 2, 3, 0, 1};
343 
344  if (m_prevNodes[node])
345  UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_prevNodes[node]], 0);
346  else
348 
349  UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_Nodes[node]], 1);
350 
351  // How many bases each team owns
352  uint8 ally = 0, horde = 0;
353  for (uint8 i = 0; i < BG_AB_NODES_MAX; ++i)
355  ++ally;
357  ++horde;
358 
361 }
362 
364 {
365  if (!AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team))
366  sLog.outError("Failed to spawn spirit guide! point: %u, team: %u,", node, team);
367 
368  uint8 capturedNodes = 0;
369  for (uint8 i = 0; i < BG_AB_NODES_MAX; ++i)
370  {
372  ++capturedNodes;
373  }
374  if (capturedNodes >= 5)
376  if (capturedNodes >= 4)
378 }
379 
381 {
382  if (node >= BG_AB_NODES_MAX)
383  return;
384 
385  // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard
386  std::vector<uint64> ghost_list = m_ReviveQueue[m_BgCreatures[node]];
387  if (!ghost_list.empty())
388  {
389  WorldSafeLocsEntry const* ClosestGrave = NULL;
390  for (std::vector<uint64>::iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr)
391  {
392  Player* plr = sObjectMgr.GetPlayer(*itr);
393  if (!plr)
394  continue;
395 
396  if (!ClosestGrave) // cache
397  ClosestGrave = GetClosestGraveYard(plr);
398 
399  if (ClosestGrave)
400  plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation());
401  }
402  }
403 
404  if (m_BgCreatures[node])
405  DelCreature(node);
406 
407  // buff object isn't despawned
408 }
409 
410 /* Invoked if a player used a banner as a GameObject*/
412 {
413  if (GetStatus() != STATUS_IN_PROGRESS)
414  return;
415 
416  uint8 node = BG_AB_NODE_STABLES;
417  GameObject* obj = GetBgMap()->GetGameObject(m_BgObjects[node * 8 + 7]);
418  while ((node < BG_AB_NODES_MAX) && ((!obj) || (!source->IsWithinDistInMap(obj, 10))))
419  {
420  ++node;
422  }
423 
424  if (node == BG_AB_NODES_MAX)
425  {
426  // this means our player isn't close to any of banners - maybe cheater ??
427  return;
428  }
429 
430  uint8 teamIndex = GetTeamIndexByTeamId(source->GetTeam());
431 
432  // Check if player really could use this banner, not cheated
433  if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node] % 2))
434  return;
435 
437  uint32 sound = 0;
438  // If node is neutral, change to contested
439  if (m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL)
440  {
442  m_prevNodes[node] = m_Nodes[node];
443  m_Nodes[node] = teamIndex + 1;
444  // burn current neutral banner
446  // create new contested banner
447  _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
448  _SendNodeUpdate(node);
450 
451  if (teamIndex == 0)
453  else
455 
456  sound = BG_AB_SOUND_NODE_CLAIMED;
457  }
458  // If node is contested
460  {
461  // If last state is NOT occupied, change node to enemy-contested
463  {
465  m_prevNodes[node] = m_Nodes[node];
466  m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
467  // burn current contested banner
468  _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
469  // create new contested banner
470  _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
471  _SendNodeUpdate(node);
473 
474  if (teamIndex == BG_TEAM_ALLIANCE)
476  else
478  }
479  // If contested, change back to occupied
480  else
481  {
483  m_prevNodes[node] = m_Nodes[node];
484  m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_OCCUPIED;
485  // burn current contested banner
486  _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
487  // create new occupied banner
488  _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
489  _SendNodeUpdate(node);
490  m_NodeTimers[node] = 0;
491  _NodeOccupied(node, (teamIndex == BG_TEAM_ALLIANCE) ? ALLIANCE : HORDE);
492 
493  if (teamIndex == BG_TEAM_ALLIANCE)
495  else
497  }
499  }
500  // If node is occupied, change to enemy-contested
501  else
502  {
504  m_prevNodes[node] = m_Nodes[node];
505  m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
506  // burn current occupied banner
507  _DelBanner(node, BG_AB_NODE_TYPE_OCCUPIED, !teamIndex);
508  // create new contested banner
509  _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
510  _SendNodeUpdate(node);
511  _NodeDeOccupied(node);
513 
514  if (teamIndex == BG_TEAM_ALLIANCE)
516  else
518 
520  }
521 
522  // If node is occupied again, send "X has taken the Y" msg.
523  if (m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED)
524  {
525  if (teamIndex == BG_TEAM_ALLIANCE)
527  else
529  }
530  PlaySoundToAll(sound);
531 }
532 
534 {
535  for (int i = 0 ; i < BG_AB_NODES_MAX; ++i)
536  {
545  )
546  {
547  sLog.outErrorDb("BatteGroundAB: Failed to spawn some object Battleground not created!");
548  return false;
549  }
550  }
553  )
554  {
555  sLog.outErrorDb("BatteGroundAB: Failed to spawn door object Battleground not created!");
556  return false;
557  }
558  //buffs
559  for (int i = 0; i < BG_AB_NODES_MAX; ++i)
560  {
564  )
565  sLog.outErrorDb("BatteGroundAB: Failed to spawn buff object!");
566  }
567 
568  return true;
569 }
570 
572 {
581  m_IsInformedNearVictory = false;
582 
583  for (uint8 i = 0; i < BG_AB_NODES_MAX; ++i)
584  {
585  m_Nodes[i] = 0;
586  m_prevNodes[i] = 0;
587  m_NodeTimers[i] = 0;
588  m_BannerTimers[i].timer = 0;
589  }
590 
591  for (uint8 i = 0; i < BG_AB_ALL_NODES_COUNT; ++i)
592  if (m_BgCreatures[i])
593  DelCreature(i);
594 }
595 
597 {
598  uint8 teamIndex = GetTeamIndexByTeamId(player->GetTeam());
599 
600  // Is there any occupied node for this team?
601  std::vector<uint8> nodes;
602  for (uint8 i = 0; i < BG_AB_NODES_MAX; ++i)
603  if (m_Nodes[i] == teamIndex + 3)
604  nodes.push_back(i);
605 
606  WorldSafeLocsEntry const* good_entry = NULL;
607  // If so, select the closest node to place ghost on
608  if (!nodes.empty())
609  {
610  float plr_x = player->GetPositionX();
611  float plr_y = player->GetPositionY();
612 
613  float mindist = 999999.0f;
614  for (uint8 i = 0; i < nodes.size(); ++i)
615  {
616  WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(BG_AB_GraveyardIds[nodes[i]]);
617  if (!entry)
618  continue;
619  float dist = (entry->x - plr_x) * (entry->x - plr_x) + (entry->y - plr_y) * (entry->y - plr_y);
620  if (mindist > dist)
621  {
622  mindist = dist;
623  good_entry = entry;
624  }
625  }
626  nodes.clear();
627  }
628  // If not, place ghost on starting location
629  if (!good_entry)
630  good_entry = sWorldSafeLocsStore.LookupEntry(BG_AB_GraveyardIds[teamIndex + 5]);
631 
632  return good_entry;
633 }
634 
636 {
637  BattlegroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID());
638  if (itr == m_PlayerScores.end()) // player not found...
639  return;
640 
641  switch (type)
642  {
644  ((BattlegroundABScore*)itr->second)->BasesAssaulted += value;
645  break;
647  ((BattlegroundABScore*)itr->second)->BasesDefended += value;
648  break;
649  default:
650  Battleground::UpdatePlayerScore(Source, type, value);
651  break;
652  }
653 }
654 
DBCStorage< WorldSafeLocsEntry > sWorldSafeLocsStore(WorldSafeLocsEntryfmt)
bool AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime=0)
uint32 m_StartMessageIds[BG_STARTING_EVENT_COUNT]
Definition: Battleground.h:728
int32 m_TeamScores[BG_TEAMS_COUNT]
Definition: Battleground.h:704
uint8 m_Nodes[BG_AB_NODES_MAX]
void RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID)
void _NodeDeOccupied(uint8 node)
std::map< uint64, std::vector< uint64 > > m_ReviveQueue
Definition: Battleground.h:720
virtual void UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
const uint32 BG_AB_TickIntervals[6]
void RemovePlayer(Player *plr, uint64 guid)
virtual bool SetupBattleground()
void _DelBanner(uint8 node, uint8 type, uint8 teamIndex)
virtual void StartingEventCloseDoors()
void SendMessage2ToAll(int32 entry, ChatMsg type, Player const *source, int32 strId1=0, int32 strId2=0)
uint32 m_NodeTimers[BG_AB_NODES_MAX]
bool m_IsInformedNearVictory
uint32 BG_AB_HonorScoreTicks[BG_HONOR_MODE_NUM]
#define sLog
Log class singleton.
Definition: Log.h:187
const uint32 BG_AB_OP_NODESTATES[5]
ACE_INT32 int32
Definition: Define.h:67
void SpawnBGObject(uint32 type, uint32 respawntime)
virtual void StartingEventOpenDoors()
void UpdateWorldState(uint32 Field, uint32 Value)
uint32 GetStatus() const
Definition: Battleground.h:317
BattlegroundScoreMap m_PlayerScores
Definition: Battleground.h:713
#define sObjectMgr
Definition: ObjectMgr.h:1285
uint8 GetTeamIndexByTeamId(uint32 Team) const
Definition: Battleground.h:609
bool AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team)
const uint32 BG_AB_OP_NODEICONS[5]
virtual void AddPlayer(Player *plr)
virtual WorldSafeLocsEntry const * GetClosestGraveYard(Player *player)
const uint32 BG_AB_GraveyardIds[BG_AB_ALL_NODES_COUNT]
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true) const
Definition: Object.h:774
uint32 m_lastTick[BG_TEAMS_COUNT]
void HandleAreaTrigger(Player *Source, uint32 Trigger)
BGCreatures m_BgCreatures
Definition: Battleground.h:673
BattlegroundMap * GetBgMap()
Definition: Battleground.h:549
Team
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options=0)
Definition: Player.cpp:1488
int32 _GetNodeNameId(uint8 node)
ACE_UINT8 uint8
Definition: Define.h:73
float GetOrientation() const
Definition: Position.h:100
BGObjects m_BgObjects
Definition: Battleground.h:672
void PlaySoundToAll(uint32 SoundID)
void CastSpellOnTeam(uint32 SpellID, uint32 TeamID)
const float BG_AB_NodePositions[BG_AB_NODES_MAX][4]
void LeaveBattleground(bool teleportToEntryPoint=true)
Definition: Player.cpp:18624
void RemoveAurasWithInterruptFlags(uint32 flags, uint32 except=0)
Definition: Unit.cpp:736
#define BG_TEAMS_COUNT
Definition: Battleground.h:214
const float BG_AB_SpiritGuidePos[BG_AB_ALL_NODES_COUNT][4]
float GetPositionY() const
Definition: Position.h:98
const uint32 BG_AB_TickPoints[6]
BG_AB_BannerTimer m_BannerTimers[BG_AB_NODES_MAX]
etc mysql my cnf *Then change max_allowed_packet to a bigger value
void _NodeOccupied(uint8 node, Team team)
uint32 m_ReputationScoreTics[BG_TEAMS_COUNT]
virtual void UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
void Update(uint32 diff)
uint8 m_prevNodes[BG_AB_NODES_MAX]
void RewardHonorToTeam(uint32 Honor, uint32 TeamID)
const float BG_AB_DoorPositions[2][8]
ACE_UINT64 uint64
Definition: Define.h:70
void DoorOpen(uint32 type)
void AddPlayer(Player *plr)
bool DelCreature(uint32 type)
virtual void EventPlayerClickedOnFlag(Player *source, GameObject *target_obj)
uint32 GetTeam() const
Definition: Player.h:2063
void _CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay)
#define ASSERT
Definition: Errors.h:29
virtual void ResetBGSubclass()
void SendAreaTriggerMessage(const char *Text,...) ATTR_PRINTF(2
uint32 GetMapId() const
Definition: Battleground.h:539
WorldSession * GetSession() const
Definition: Player.h:1944
uint32 m_score[2]
Definition: Battleground.h:731
void _SendNodeUpdate(uint8 node)
uint32 m_HonorScoreTics[BG_TEAMS_COUNT]
virtual void FillInitialWorldStates(WorldPacket &data)
void EndBattleground(uint32 winner)
ACE_UINT32 uint32
Definition: Define.h:71
float GetPositionX() const
Definition: Position.h:97
uint32 BG_AB_ReputationScoreTicks[BG_HONOR_MODE_NUM]
const uint32 Buff_Entries[3]
Definition: Battleground.h:110
GameObject * GetGameObject(uint64 guid)
Definition: Map.cpp:2636
Definition: Player.h:922
void DoorClose(uint32 type)
BGHonorMode m_HonorMode
Definition: Battleground.h:733
const float BG_AB_BuffPositions[BG_AB_NODES_MAX][4]
uint32 urand(uint32 min, uint32 max)
Definition: Util.cpp:33
void SendMessageToAll(int32 entry, ChatMsg type, Player const *source=NULL)
const uint64 & GetGUID() const
Definition: Object.h:162
virtual void Update(uint32 diff)