[8449] Deprecate healing/damage item mods and merge internal data in to spell power.
[getmangos.git] / src / game / BattleGroundAB.cpp
blob7e27972ff5717badcbab89345a6c29192aa300ec
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Object.h"
20 #include "Player.h"
21 #include "BattleGround.h"
22 #include "BattleGroundAB.h"
23 #include "Creature.h"
24 #include "ObjectMgr.h"
25 #include "Language.h"
26 #include "Util.h"
27 #include "WorldPacket.h"
29 BattleGroundAB::BattleGroundAB()
31 m_BuffChange = true;
32 m_BgObjects.resize(BG_AB_OBJECT_MAX);
33 m_BgCreatures.resize(BG_AB_ALL_NODES_COUNT);
35 m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_AB_START_TWO_MINUTES;
36 m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AB_START_ONE_MINUTE;
37 m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AB_START_HALF_MINUTE;
38 m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AB_HAS_BEGUN;
41 BattleGroundAB::~BattleGroundAB()
45 void BattleGroundAB::Update(uint32 diff)
47 BattleGround::Update(diff);
49 if (GetStatus() == STATUS_IN_PROGRESS)
51 int team_points[BG_TEAMS_COUNT] = { 0, 0 };
53 for (int node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
55 // 3 sec delay to spawn new banner instead previous despawned one
56 if (m_BannerTimers[node].timer)
58 if (m_BannerTimers[node].timer > diff)
59 m_BannerTimers[node].timer -= diff;
60 else
62 m_BannerTimers[node].timer = 0;
63 _CreateBanner(node, m_BannerTimers[node].type, m_BannerTimers[node].teamIndex, false);
67 // 1-minute to occupy a node from contested state
68 if (m_NodeTimers[node])
70 if (m_NodeTimers[node] > diff)
71 m_NodeTimers[node] -= diff;
72 else
74 m_NodeTimers[node] = 0;
75 // Change from contested to occupied !
76 uint8 teamIndex = m_Nodes[node]-1;
77 m_prevNodes[node] = m_Nodes[node];
78 m_Nodes[node] += 2;
79 // burn current contested banner
80 _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex);
81 // create new occupied banner
82 _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
83 _SendNodeUpdate(node);
84 _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE);
85 // Message to chatlog
87 if (teamIndex == 0)
89 // FIXME: team and node names not localized
90 SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE,NULL,LANG_BG_AB_ALLY,_GetNodeNameId(node));
91 PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
93 else
95 // FIXME: team and node names not localized
96 SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE,NULL,LANG_BG_AB_HORDE,_GetNodeNameId(node));
97 PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
102 for (int team = 0; team < BG_TEAMS_COUNT; ++team)
103 if (m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED)
104 ++team_points[team];
107 // Accumulate points
108 for (int team = 0; team < BG_TEAMS_COUNT; ++team)
110 int points = team_points[team];
111 if (!points)
112 continue;
113 m_lastTick[team] += diff;
114 if (m_lastTick[team] > BG_AB_TickIntervals[points])
116 m_lastTick[team] -= BG_AB_TickIntervals[points];
117 m_TeamScores[team] += BG_AB_TickPoints[points];
118 m_HonorScoreTics[team] += BG_AB_TickPoints[points];
119 m_ReputationScoreTics[team] += BG_AB_TickPoints[points];
120 if (m_ReputationScoreTics[team] >= m_ReputationTics)
122 (team == BG_TEAM_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE);
123 m_ReputationScoreTics[team] -= m_ReputationTics;
125 if (m_HonorScoreTics[team] >= m_HonorTics)
127 RewardHonorToTeam(GetBonusHonorFromKill(1), (team == BG_TEAM_ALLIANCE) ? ALLIANCE : HORDE);
128 m_HonorScoreTics[team] -= m_HonorTics;
130 if (!m_IsInformedNearVictory && m_TeamScores[team] > BG_AB_WARNING_NEAR_VICTORY_SCORE)
132 if (team == BG_TEAM_ALLIANCE)
133 SendMessageToAll(LANG_BG_AB_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
134 else
135 SendMessageToAll(LANG_BG_AB_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
136 PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY);
137 m_IsInformedNearVictory = true;
140 if (m_TeamScores[team] > BG_AB_MAX_TEAM_SCORE)
141 m_TeamScores[team] = BG_AB_MAX_TEAM_SCORE;
142 if (team == BG_TEAM_ALLIANCE)
143 UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]);
144 if (team == BG_TEAM_HORDE)
145 UpdateWorldState(BG_AB_OP_RESOURCES_HORDE, m_TeamScores[team]);
149 // achievements flags
150 if (m_TeamScores[BG_TEAM_ALLIANCE] > m_TeamScores[BG_TEAM_HORDE])
152 if (m_TeamScores[BG_TEAM_ALLIANCE] - m_TeamScores[BG_TEAM_HORDE] >= 500)
153 m_TeamScores500disadvantage[BG_TEAM_HORDE] = true;
155 else
157 if (m_TeamScores[BG_TEAM_HORDE] - m_TeamScores[BG_TEAM_ALLIANCE] >= 500)
158 m_TeamScores500disadvantage[BG_TEAM_ALLIANCE] = true;
161 // Test win condition
162 if (m_TeamScores[BG_TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE)
163 EndBattleGround(ALLIANCE);
164 if (m_TeamScores[BG_TEAM_HORDE] >= BG_AB_MAX_TEAM_SCORE)
165 EndBattleGround(HORDE);
169 void BattleGroundAB::StartingEventCloseDoors()
171 // despawn banners, auras and buffs
172 for (int obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_DYNAMIC_NODES_COUNT * 8; ++obj)
173 SpawnBGObject(obj, RESPAWN_ONE_DAY);
174 for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT * 3; ++i)
175 SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + i, RESPAWN_ONE_DAY);
177 // Starting doors
178 DoorClose(BG_AB_OBJECT_GATE_A);
179 DoorClose(BG_AB_OBJECT_GATE_H);
180 SpawnBGObject(BG_AB_OBJECT_GATE_A, RESPAWN_IMMEDIATELY);
181 SpawnBGObject(BG_AB_OBJECT_GATE_H, RESPAWN_IMMEDIATELY);
183 // Starting base spirit guides
184 _NodeOccupied(BG_AB_SPIRIT_ALIANCE,ALLIANCE);
185 _NodeOccupied(BG_AB_SPIRIT_HORDE,HORDE);
188 void BattleGroundAB::StartingEventOpenDoors()
190 // spawn neutral banners
191 for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i)
192 SpawnBGObject(banner, RESPAWN_IMMEDIATELY);
193 for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
195 //randomly select buff to spawn
196 uint8 buff = urand(0, 2);
197 SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + buff + i * 3, RESPAWN_IMMEDIATELY);
199 DoorOpen(BG_AB_OBJECT_GATE_A);
200 DoorOpen(BG_AB_OBJECT_GATE_H);
203 void BattleGroundAB::AddPlayer(Player *plr)
205 BattleGround::AddPlayer(plr);
206 //create score and add it to map, default values are set in the constructor
207 BattleGroundABScore* sc = new BattleGroundABScore;
209 m_PlayerScores[plr->GetGUID()] = sc;
212 void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/)
217 void BattleGroundAB::HandleAreaTrigger(Player *Source, uint32 Trigger)
219 if (GetStatus() != STATUS_IN_PROGRESS)
220 return;
222 switch(Trigger)
224 case 3948: // Arathi Basin Alliance Exit.
225 if (Source->GetTeam() != ALLIANCE)
226 Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal");
227 else
228 Source->LeaveBattleground();
229 break;
230 case 3949: // Arathi Basin Horde Exit.
231 if (Source->GetTeam() != HORDE)
232 Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal");
233 else
234 Source->LeaveBattleground();
235 break;
236 case 3866: // Stables
237 case 3869: // Gold Mine
238 case 3867: // Farm
239 case 3868: // Lumber Mill
240 case 3870: // Black Smith
241 case 4020: // Unk1
242 case 4021: // Unk2
243 //break;
244 default:
245 //sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
246 //Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
247 break;
251 /* type: 0-neutral, 1-contested, 3-occupied
252 teamIndex: 0-ally, 1-horde */
253 void BattleGroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay)
255 // Just put it into the queue
256 if (delay)
258 m_BannerTimers[node].timer = 2000;
259 m_BannerTimers[node].type = type;
260 m_BannerTimers[node].teamIndex = teamIndex;
261 return;
264 uint8 obj = node*8 + type + teamIndex;
266 SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
268 // handle aura with banner
269 if (!type)
270 return;
271 obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
272 SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
275 void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex)
277 uint8 obj = node*8 + type + teamIndex;
278 SpawnBGObject(obj, RESPAWN_ONE_DAY);
280 // handle aura with banner
281 if (!type)
282 return;
283 obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
284 SpawnBGObject(obj, RESPAWN_ONE_DAY);
287 int32 BattleGroundAB::_GetNodeNameId(uint8 node)
289 switch (node)
291 case BG_AB_NODE_STABLES: return LANG_BG_AB_NODE_STABLES;
292 case BG_AB_NODE_BLACKSMITH: return LANG_BG_AB_NODE_BLACKSMITH;
293 case BG_AB_NODE_FARM: return LANG_BG_AB_NODE_FARM;
294 case BG_AB_NODE_LUMBER_MILL:return LANG_BG_AB_NODE_LUMBER_MILL;
295 case BG_AB_NODE_GOLD_MINE: return LANG_BG_AB_NODE_GOLD_MINE;
296 default:
297 ASSERT(0);
299 return 0;
302 void BattleGroundAB::FillInitialWorldStates(WorldPacket& data)
304 const uint8 plusArray[] = {0, 2, 3, 0, 1};
306 // Node icons
307 for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
308 data << uint32(BG_AB_OP_NODEICONS[node]) << uint32((m_Nodes[node]==0)?1:0);
310 // Node occupied states
311 for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
312 for (uint8 i = 1; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
313 data << uint32(BG_AB_OP_NODESTATES[node] + plusArray[i]) << uint32((m_Nodes[node]==i)?1:0);
315 // How many bases each team owns
316 uint8 ally = 0, horde = 0;
317 for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
318 if (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_OCCUPIED)
319 ++ally;
320 else if (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)
321 ++horde;
323 data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY) << uint32(ally);
324 data << uint32(BG_AB_OP_OCCUPIED_BASES_HORDE) << uint32(horde);
326 // Team scores
327 data << uint32(BG_AB_OP_RESOURCES_MAX) << uint32(BG_AB_MAX_TEAM_SCORE);
328 data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_NEAR_VICTORY_SCORE);
329 data << uint32(BG_AB_OP_RESOURCES_ALLY) << uint32(m_TeamScores[BG_TEAM_ALLIANCE]);
330 data << uint32(BG_AB_OP_RESOURCES_HORDE) << uint32(m_TeamScores[BG_TEAM_HORDE]);
332 // other unknown
333 data << uint32(0x745) << uint32(0x2); // 37 1861 unk
336 void BattleGroundAB::_SendNodeUpdate(uint8 node)
338 // Send node owner state update to refresh map icons on client
339 const uint8 plusArray[] = {0, 2, 3, 0, 1};
341 if (m_prevNodes[node])
342 UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_prevNodes[node]], 0);
343 else
344 UpdateWorldState(BG_AB_OP_NODEICONS[node], 0);
346 UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_Nodes[node]], 1);
348 // How many bases each team owns
349 uint8 ally = 0, horde = 0;
350 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
351 if (m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED)
352 ++ally;
353 else if (m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)
354 ++horde;
356 UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_ALLY, ally);
357 UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_HORDE, horde);
360 void BattleGroundAB::_NodeOccupied(uint8 node,Team team)
362 if (!AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team))
363 sLog.outError("Failed to spawn spirit guide! point: %u, team: %u,", node, team);
364 // SpawnBGCreature(node,RESPAWN_IMMEDIATELY);
366 uint8 capturedNodes = 0;
367 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
369 if (m_Nodes[node] == GetTeamIndexByTeamId(team) + BG_AB_NODE_TYPE_OCCUPIED && !m_NodeTimers[i])
370 ++capturedNodes;
372 if (capturedNodes >= 5)
373 CastSpellOnTeam(SPELL_AB_QUEST_REWARD_5_BASES, team);
374 if (capturedNodes >= 4)
375 CastSpellOnTeam(SPELL_AB_QUEST_REWARD_4_BASES, team);
378 void BattleGroundAB::_NodeDeOccupied(uint8 node)
380 if (node >= BG_AB_DYNAMIC_NODES_COUNT)
381 return;
383 // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard
384 std::vector<uint64> ghost_list = m_ReviveQueue[m_BgCreatures[node]];
385 if (!ghost_list.empty())
387 WorldSafeLocsEntry const *ClosestGrave = NULL;
388 for (std::vector<uint64>::const_iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr)
390 Player* plr = objmgr.GetPlayer(*itr);
391 if (!plr)
392 continue;
394 if (!ClosestGrave) // cache
395 ClosestGrave = GetClosestGraveYard(plr);
397 if (ClosestGrave)
398 plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation());
402 if (m_BgCreatures[node])
403 DelCreature(node);
405 // buff object isn't despawned
408 /* Invoked if a player used a banner as a gameobject */
409 void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*target_obj*/)
411 if (GetStatus() != STATUS_IN_PROGRESS)
412 return;
414 uint8 node = BG_AB_NODE_STABLES;
415 GameObject* obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+7]);
416 while ( (node < BG_AB_DYNAMIC_NODES_COUNT) && ((!obj) || (!source->IsWithinDistInMap(obj,10))))
418 ++node;
419 obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+BG_AB_OBJECT_AURA_CONTESTED]);
422 if (node == BG_AB_DYNAMIC_NODES_COUNT)
424 // this means our player isn't close to any of banners - maybe cheater ??
425 return;
428 BattleGroundTeamId teamIndex = GetTeamIndexByTeamId(source->GetTeam());
430 // Check if player really could use this banner, not cheated
431 if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2))
432 return;
434 source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
435 uint32 sound = 0;
436 // If node is neutral, change to contested
437 if (m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL)
439 UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
440 m_prevNodes[node] = m_Nodes[node];
441 m_Nodes[node] = teamIndex + 1;
442 // burn current neutral banner
443 _DelBanner(node, BG_AB_NODE_TYPE_NEUTRAL, 0);
444 // create new contested banner
445 _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
446 _SendNodeUpdate(node);
447 m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
449 // FIXME: team and node names not localized
450 if (teamIndex == 0)
451 SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node), LANG_BG_AB_ALLY);
452 else
453 SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node), LANG_BG_AB_HORDE);
455 sound = BG_AB_SOUND_NODE_CLAIMED;
457 // If node is contested
458 else if ((m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED))
460 // If last state is NOT occupied, change node to enemy-contested
461 if (m_prevNodes[node] < BG_AB_NODE_TYPE_OCCUPIED)
463 UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
464 m_prevNodes[node] = m_Nodes[node];
465 m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
466 // burn current contested banner
467 _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
468 // create new contested banner
469 _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
470 _SendNodeUpdate(node);
471 m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
473 // FIXME: node names not localized
474 if (teamIndex == BG_TEAM_ALLIANCE)
475 SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
476 else
477 SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
479 // If contested, change back to occupied
480 else
482 UpdatePlayerScore(source, SCORE_BASES_DEFENDED, 1);
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);
493 // FIXME: node names not localized
494 if (teamIndex == BG_TEAM_ALLIANCE)
495 SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
496 else
497 SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
499 sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
501 // If node is occupied, change to enemy-contested
502 else
504 UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
505 m_prevNodes[node] = m_Nodes[node];
506 m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
507 // burn current occupied banner
508 _DelBanner(node, BG_AB_NODE_TYPE_OCCUPIED, !teamIndex);
509 // create new contested banner
510 _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
511 _SendNodeUpdate(node);
512 _NodeDeOccupied(node);
513 m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
515 // FIXME: node names not localized
516 if (teamIndex == BG_TEAM_ALLIANCE)
517 SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
518 else
519 SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
521 sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
524 // If node is occupied again, send "X has taken the Y" msg.
525 if (m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED)
527 // FIXME: team and node names not localized
528 if (teamIndex == BG_TEAM_ALLIANCE)
529 SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, LANG_BG_AB_ALLY, _GetNodeNameId(node));
530 else
531 SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE, NULL, LANG_BG_AB_HORDE, _GetNodeNameId(node));
533 PlaySoundToAll(sound);
536 bool BattleGroundAB::SetupBattleGround()
538 for (int i = 0 ; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
540 if (!AddObject(BG_AB_OBJECT_BANNER_NEUTRAL + 8*i,BG_AB_OBJECTID_NODE_BANNER_0 + i,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
541 || !AddObject(BG_AB_OBJECT_BANNER_CONT_A + 8*i,BG_AB_OBJECTID_BANNER_CONT_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
542 || !AddObject(BG_AB_OBJECT_BANNER_CONT_H + 8*i,BG_AB_OBJECTID_BANNER_CONT_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
543 || !AddObject(BG_AB_OBJECT_BANNER_ALLY + 8*i,BG_AB_OBJECTID_BANNER_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
544 || !AddObject(BG_AB_OBJECT_BANNER_HORDE + 8*i,BG_AB_OBJECTID_BANNER_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
545 || !AddObject(BG_AB_OBJECT_AURA_ALLY + 8*i,BG_AB_OBJECTID_AURA_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
546 || !AddObject(BG_AB_OBJECT_AURA_HORDE + 8*i,BG_AB_OBJECTID_AURA_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
547 || !AddObject(BG_AB_OBJECT_AURA_CONTESTED + 8*i,BG_AB_OBJECTID_AURA_C,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
550 sLog.outErrorDb("BatteGroundAB: Failed to spawn some object BattleGround not created!");
551 return false;
554 if (!AddObject(BG_AB_OBJECT_GATE_A,BG_AB_OBJECTID_GATE_A,BG_AB_DoorPositions[0][0],BG_AB_DoorPositions[0][1],BG_AB_DoorPositions[0][2],BG_AB_DoorPositions[0][3],BG_AB_DoorPositions[0][4],BG_AB_DoorPositions[0][5],BG_AB_DoorPositions[0][6],BG_AB_DoorPositions[0][7],RESPAWN_IMMEDIATELY)
555 || !AddObject(BG_AB_OBJECT_GATE_H,BG_AB_OBJECTID_GATE_H,BG_AB_DoorPositions[1][0],BG_AB_DoorPositions[1][1],BG_AB_DoorPositions[1][2],BG_AB_DoorPositions[1][3],BG_AB_DoorPositions[1][4],BG_AB_DoorPositions[1][5],BG_AB_DoorPositions[1][6],BG_AB_DoorPositions[1][7],RESPAWN_IMMEDIATELY)
558 sLog.outErrorDb("BatteGroundAB: Failed to spawn door object BattleGround not created!");
559 return false;
561 //buffs
562 for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
564 if (!AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i, Buff_Entries[0], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
565 || !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 1, Buff_Entries[1], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
566 || !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 2, Buff_Entries[2], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
568 sLog.outErrorDb("BatteGroundAB: Failed to spawn buff object!");
571 return true;
574 void BattleGroundAB::Reset()
576 //call parent's class reset
577 BattleGround::Reset();
579 m_TeamScores[BG_TEAM_ALLIANCE] = 0;
580 m_TeamScores[BG_TEAM_HORDE] = 0;
581 m_lastTick[BG_TEAM_ALLIANCE] = 0;
582 m_lastTick[BG_TEAM_HORDE] = 0;
583 m_HonorScoreTics[BG_TEAM_ALLIANCE] = 0;
584 m_HonorScoreTics[BG_TEAM_HORDE] = 0;
585 m_ReputationScoreTics[BG_TEAM_ALLIANCE] = 0;
586 m_ReputationScoreTics[BG_TEAM_HORDE] = 0;
587 m_IsInformedNearVictory = false;
588 bool isBGWeekend = false; //TODO FIXME - call sBattleGroundMgr.IsBGWeekend(m_TypeID); - you must also implement that call!
589 m_HonorTics = (isBGWeekend) ? BG_AB_ABBGWeekendHonorTicks : BG_AB_NotABBGWeekendHonorTicks;
590 m_ReputationTics = (isBGWeekend) ? BG_AB_ABBGWeekendReputationTicks : BG_AB_NotABBGWeekendReputationTicks;
591 m_TeamScores500disadvantage[BG_TEAM_ALLIANCE] = false;
592 m_TeamScores500disadvantage[BG_TEAM_HORDE] = false;
594 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
596 m_Nodes[i] = 0;
597 m_prevNodes[i] = 0;
598 m_NodeTimers[i] = 0;
599 m_BannerTimers[i].timer = 0;
602 for (uint8 i = 0; i < BG_AB_ALL_NODES_COUNT; ++i)
603 if (m_BgCreatures[i])
604 DelCreature(i);
607 void BattleGroundAB::EndBattleGround(uint32 winner)
609 //win reward
610 if (winner == ALLIANCE)
611 RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
612 if (winner == HORDE)
613 RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
614 //complete map_end rewards (even if no team wins)
615 RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
616 RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
618 BattleGround::EndBattleGround(winner);
621 WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player)
623 BattleGroundTeamId teamIndex = GetTeamIndexByTeamId(player->GetTeam());
625 // Is there any occupied node for this team?
626 std::vector<uint8> nodes;
627 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
628 if (m_Nodes[i] == teamIndex + 3)
629 nodes.push_back(i);
631 WorldSafeLocsEntry const* good_entry = NULL;
632 // If so, select the closest node to place ghost on
633 if (!nodes.empty())
635 float plr_x = player->GetPositionX();
636 float plr_y = player->GetPositionY();
638 float mindist = 999999.0f;
639 for (uint8 i = 0; i < nodes.size(); ++i)
641 WorldSafeLocsEntry const*entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[nodes[i]] );
642 if (!entry)
643 continue;
644 float dist = (entry->x - plr_x)*(entry->x - plr_x)+(entry->y - plr_y)*(entry->y - plr_y);
645 if (mindist > dist)
647 mindist = dist;
648 good_entry = entry;
651 nodes.clear();
653 // If not, place ghost on starting location
654 if (!good_entry)
655 good_entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[teamIndex+5] );
657 return good_entry;
660 void BattleGroundAB::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
662 BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID());
663 if( itr == m_PlayerScores.end() ) // player not found...
664 return;
666 switch(type)
668 case SCORE_BASES_ASSAULTED:
669 ((BattleGroundABScore*)itr->second)->BasesAssaulted += value;
670 break;
671 case SCORE_BASES_DEFENDED:
672 ((BattleGroundABScore*)itr->second)->BasesDefended += value;
673 break;
674 default:
675 BattleGround::UpdatePlayerScore(Source,type,value);
676 break;
680 bool BattleGroundAB::IsAllNodesConrolledByTeam(uint32 team) const
682 uint32 count = 0;
683 for(int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
684 if (team == ALLIANCE && m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED ||
685 team == HORDE && m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)
686 ++count;
688 return count == BG_AB_DYNAMIC_NODES_COUNT;