[9581] Fixed apply damage reduction to melee/ranged damage.
[getmangos.git] / src / game / BattleGroundAV.cpp
blob3ddc3a9659253742cda8081bcf7e66945300989f
1 /*
2 * Copyright (C) 2005-2010 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 "Player.h"
20 #include "BattleGround.h"
21 #include "BattleGroundAV.h"
22 #include "BattleGroundMgr.h"
23 #include "Creature.h"
24 #include "GameObject.h"
25 #include "Language.h"
26 #include "WorldPacket.h"
28 BattleGroundAV::BattleGroundAV()
30 m_StartMessageIds[BG_STARTING_EVENT_FIRST] = 0;
31 m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AV_START_ONE_MINUTE;
32 m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AV_START_HALF_MINUTE;
33 m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AV_HAS_BEGUN;
36 BattleGroundAV::~BattleGroundAV()
40 void BattleGroundAV::HandleKillPlayer(Player *player, Player *killer)
42 if (GetStatus() != STATUS_IN_PROGRESS)
43 return;
45 BattleGround::HandleKillPlayer(player, killer);
46 UpdateScore(GetTeamIndexByTeamId(player->GetTeam()), -1);
49 void BattleGroundAV::HandleKillUnit(Creature *creature, Player *killer)
51 sLog.outDebug("BattleGroundAV: HandleKillUnit %i", creature->GetEntry());
52 if (GetStatus() != STATUS_IN_PROGRESS)
53 return;
54 uint8 event1 = (sBattleGroundMgr.GetCreatureEventIndex(creature->GetDBTableGUIDLow())).event1;
55 if (event1 == BG_EVENT_NONE)
56 return;
57 switch(event1)
59 case BG_AV_BOSS_A:
60 CastSpellOnTeam(BG_AV_BOSS_KILL_QUEST_SPELL, HORDE); // this is a spell which finishes a quest where a player has to kill the boss
61 RewardReputationToTeam(BG_AV_FACTION_H, m_RepBoss, HORDE);
62 RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_BOSS), HORDE);
63 SendYellToAll(LANG_BG_AV_A_GENERAL_DEAD, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0));
64 EndBattleGround(HORDE);
65 break;
66 case BG_AV_BOSS_H:
67 CastSpellOnTeam(BG_AV_BOSS_KILL_QUEST_SPELL, ALLIANCE); // this is a spell which finishes a quest where a player has to kill the boss
68 RewardReputationToTeam(BG_AV_FACTION_A, m_RepBoss, ALLIANCE);
69 RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_BOSS), ALLIANCE);
70 SendYellToAll(LANG_BG_AV_H_GENERAL_DEAD, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0));
71 EndBattleGround(ALLIANCE);
72 break;
73 case BG_AV_CAPTAIN_A:
74 if (IsActiveEvent(BG_AV_NodeEventCaptainDead_A, 0))
75 return;
76 RewardReputationToTeam(BG_AV_FACTION_H, m_RepCaptain, HORDE);
77 RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_CAPTAIN), HORDE);
78 UpdateScore(BG_TEAM_ALLIANCE, (-1) * BG_AV_RES_CAPTAIN);
79 // spawn destroyed aura
80 SpawnEvent(BG_AV_NodeEventCaptainDead_A, 0, true);
81 break;
82 case BG_AV_CAPTAIN_H:
83 if (IsActiveEvent(BG_AV_NodeEventCaptainDead_H, 0))
84 return;
85 RewardReputationToTeam(BG_AV_FACTION_A, m_RepCaptain, ALLIANCE);
86 RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_CAPTAIN), ALLIANCE);
87 UpdateScore(BG_TEAM_HORDE, (-1) * BG_AV_RES_CAPTAIN);
88 // spawn destroyed aura
89 SpawnEvent(BG_AV_NodeEventCaptainDead_H, 0, true);
90 break;
91 case BG_AV_MINE_BOSSES_NORTH:
92 ChangeMineOwner(BG_AV_NORTH_MINE, GetTeamIndexByTeamId(killer->GetTeam()));
93 break;
94 case BG_AV_MINE_BOSSES_SOUTH:
95 ChangeMineOwner(BG_AV_SOUTH_MINE, GetTeamIndexByTeamId(killer->GetTeam()));
96 break;
100 void BattleGroundAV::HandleQuestComplete(uint32 questid, Player *player)
102 if (GetStatus() != STATUS_IN_PROGRESS)
103 return;
104 uint8 team = GetTeamIndexByTeamId(player->GetTeam());
105 uint32 reputation = 0; // reputation for the whole team (other reputation must be done in db)
106 // TODO add events (including quest not available anymore, next quest availabe, go/npc de/spawning)
107 sLog.outError("BattleGroundAV: Quest %i completed", questid);
108 switch(questid)
110 case BG_AV_QUEST_A_SCRAPS1:
111 case BG_AV_QUEST_A_SCRAPS2:
112 case BG_AV_QUEST_H_SCRAPS1:
113 case BG_AV_QUEST_H_SCRAPS2:
114 m_Team_QuestStatus[team][0] += 20;
115 reputation = 1;
116 if( m_Team_QuestStatus[team][0] == 500 || m_Team_QuestStatus[team][0] == 1000 || m_Team_QuestStatus[team][0] == 1500 ) //25,50,75 turn ins
118 sLog.outDebug("BattleGroundAV: Quest %i completed starting with unit upgrading..", questid);
119 for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i)
120 if (m_Nodes[i].Owner == team && m_Nodes[i].State == POINT_CONTROLLED)
121 PopulateNode(i);
123 break;
124 case BG_AV_QUEST_A_COMMANDER1:
125 case BG_AV_QUEST_H_COMMANDER1:
126 m_Team_QuestStatus[team][1]++;
127 reputation = 1;
128 if (m_Team_QuestStatus[team][1] == 120)
129 sLog.outDebug("BattleGroundAV: Quest %i completed (need to implement some events here", questid);
130 break;
131 case BG_AV_QUEST_A_COMMANDER2:
132 case BG_AV_QUEST_H_COMMANDER2:
133 m_Team_QuestStatus[team][2]++;
134 reputation = 2;
135 if (m_Team_QuestStatus[team][2] == 60)
136 sLog.outDebug("BattleGroundAV: Quest %i completed (need to implement some events here", questid);
137 break;
138 case BG_AV_QUEST_A_COMMANDER3:
139 case BG_AV_QUEST_H_COMMANDER3:
140 m_Team_QuestStatus[team][3]++;
141 reputation = 5;
142 RewardReputationToTeam(team, 1, player->GetTeam());
143 if (m_Team_QuestStatus[team][1] == 30)
144 sLog.outDebug("BattleGroundAV: Quest %i completed (need to implement some events here", questid);
145 break;
146 case BG_AV_QUEST_A_BOSS1:
147 case BG_AV_QUEST_H_BOSS1:
148 m_Team_QuestStatus[team][4] += 4; // there are 2 quests where you can turn in 5 or 1 item.. ( + 4 cause +1 will be done some lines below)
149 reputation = 4;
150 case BG_AV_QUEST_A_BOSS2:
151 case BG_AV_QUEST_H_BOSS2:
152 m_Team_QuestStatus[team][4]++;
153 reputation += 1;
154 if (m_Team_QuestStatus[team][4] >= 200)
155 sLog.outDebug("BattleGroundAV: Quest %i completed (need to implement some events here", questid);
156 break;
157 case BG_AV_QUEST_A_NEAR_MINE:
158 case BG_AV_QUEST_H_NEAR_MINE:
159 m_Team_QuestStatus[team][5]++;
160 reputation = 2;
161 if (m_Team_QuestStatus[team][5] == 28)
163 sLog.outDebug("BattleGroundAV: Quest %i completed (need to implement some events here", questid);
164 if (m_Team_QuestStatus[team][6] == 7)
165 sLog.outDebug("BattleGroundAV: Quest %i completed (need to implement some events here - ground assault ready", questid);
167 break;
168 case BG_AV_QUEST_A_OTHER_MINE:
169 case BG_AV_QUEST_H_OTHER_MINE:
170 m_Team_QuestStatus[team][6]++;
171 reputation = 3;
172 if (m_Team_QuestStatus[team][6] == 7)
174 sLog.outDebug("BattleGroundAV: Quest %i completed (need to implement some events here", questid);
175 if (m_Team_QuestStatus[team][5] == 20)
176 sLog.outDebug("BattleGroundAV: Quest %i completed (need to implement some events here - ground assault ready", questid);
178 break;
179 case BG_AV_QUEST_A_RIDER_HIDE:
180 case BG_AV_QUEST_H_RIDER_HIDE:
181 m_Team_QuestStatus[team][7]++;
182 reputation = 1;
183 if (m_Team_QuestStatus[team][7] == 25)
185 sLog.outDebug("BattleGroundAV: Quest %i completed (need to implement some events here", questid);
186 if (m_Team_QuestStatus[team][8] == 25)
187 sLog.outDebug("BattleGroundAV: Quest %i completed (need to implement some events here - rider assault ready", questid);
189 break;
190 case BG_AV_QUEST_A_RIDER_TAME:
191 case BG_AV_QUEST_H_RIDER_TAME:
192 m_Team_QuestStatus[team][8]++;
193 reputation = 1;
194 if (m_Team_QuestStatus[team][8] == 25)
196 sLog.outDebug("BattleGroundAV: Quest %i completed (need to implement some events here", questid);
197 if (m_Team_QuestStatus[team][7] == 25)
198 sLog.outDebug("BattleGroundAV: Quest %i completed (need to implement some events here - rider assault ready", questid);
200 break;
201 default:
202 sLog.outDebug("BattleGroundAV: Quest %i completed but is not interesting for us", questid);
203 return;
204 break;
206 if (reputation)
207 RewardReputationToTeam((player->GetTeam() == ALLIANCE) ? BG_AV_FACTION_A : BG_AV_FACTION_H, reputation, player->GetTeam());
210 void BattleGroundAV::UpdateScore(BattleGroundTeamId team, int32 points )
212 // note: to remove reinforcements points must be negative, for adding reinforcements points must be positive
213 assert( team == BG_TEAM_ALLIANCE || team == BG_TEAM_HORDE);
214 m_TeamScores[team] += points; // m_TeamScores is int32 - so no problems here
216 if (points < 0)
218 if (m_TeamScores[team] < 1)
220 m_TeamScores[team] = 0;
221 // other team will win:
222 EndBattleGround((team == BG_TEAM_ALLIANCE)? HORDE : ALLIANCE);
224 else if (!m_IsInformedNearLose[team] && m_TeamScores[team] < BG_AV_SCORE_NEAR_LOSE)
226 SendMessageToAll((team == BG_TEAM_HORDE) ? LANG_BG_AV_H_NEAR_LOSE : LANG_BG_AV_A_NEAR_LOSE, CHAT_MSG_BG_SYSTEM_NEUTRAL);
227 PlaySoundToAll(BG_AV_SOUND_NEAR_LOSE);
228 m_IsInformedNearLose[team] = true;
231 // must be called here, else it could display a negative value
232 UpdateWorldState(((team == BG_TEAM_HORDE) ? BG_AV_Horde_Score : BG_AV_Alliance_Score), m_TeamScores[team]);
235 void BattleGroundAV::Update(uint32 diff)
237 BattleGround::Update(diff);
238 if (GetStatus() != STATUS_IN_PROGRESS)
239 return;
241 // add points from mine owning, and look if the neutral team can reclaim the mine
242 for(uint8 mine = 0; mine < BG_AV_MAX_MINES; mine++)
244 if (m_Mine_Owner[mine] == BG_TEAM_ALLIANCE || m_Mine_Owner[mine] == BG_TEAM_HORDE)
246 m_Mine_Timer[mine] -=diff;
247 if (m_Mine_Timer[mine] <= 0)
249 UpdateScore(BattleGroundTeamId(m_Mine_Owner[mine]), 1);
250 m_Mine_Timer[mine] = BG_AV_MINE_TICK_TIMER;
253 if (m_Mine_Reclaim_Timer[mine] > diff)
254 m_Mine_Reclaim_Timer[mine] -= diff;
255 else
256 ChangeMineOwner(mine, BG_AV_NEUTRAL_TEAM);
260 // looks for all timers of the nodes and destroy the building (for graveyards the building wont get destroyed, it goes just to the other team
261 for(BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i)
263 if (m_Nodes[i].State == POINT_ASSAULTED)
265 if (m_Nodes[i].Timer > diff)
266 m_Nodes[i].Timer -= diff;
267 else
268 EventPlayerDestroyedPoint(i);
273 void BattleGroundAV::StartingEventCloseDoors()
275 sLog.outDebug("BattleGroundAV: entering state STATUS_WAIT_JOIN ...");
278 void BattleGroundAV::StartingEventOpenDoors()
280 UpdateWorldState(BG_AV_SHOW_H_SCORE, 1);
281 UpdateWorldState(BG_AV_SHOW_A_SCORE, 1);
283 OpenDoorEvent(BG_EVENT_DOOR);
286 void BattleGroundAV::AddPlayer(Player *plr)
288 BattleGround::AddPlayer(plr);
289 // create score and add it to map, default values are set in constructor
290 BattleGroundAVScore* sc = new BattleGroundAVScore;
291 m_PlayerScores[plr->GetGUID()] = sc;
294 void BattleGroundAV::EndBattleGround(uint32 winner)
296 // calculate bonuskills for both teams:
297 uint32 tower_survived[BG_TEAMS_COUNT] = {0, 0};
298 uint32 graves_owned[BG_TEAMS_COUNT] = {0, 0};
299 uint32 mines_owned[BG_TEAMS_COUNT] = {0, 0};
300 // towers all not destroyed:
301 for(BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_STONEHEART_BUNKER; ++i)
302 if (m_Nodes[i].State == POINT_CONTROLLED)
303 if (m_Nodes[i].TotalOwner == BG_TEAM_ALLIANCE)
304 ++tower_survived[BG_TEAM_ALLIANCE];
305 for(BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_TOWER; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i)
306 if (m_Nodes[i].State == POINT_CONTROLLED)
307 if (m_Nodes[i].TotalOwner == BG_TEAM_HORDE)
308 ++tower_survived[BG_TEAM_HORDE];
310 // graves all controlled
311 for(BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i)
312 if (m_Nodes[i].State == POINT_CONTROLLED)
313 ++graves_owned[m_Nodes[i].Owner];
315 for (uint32 i = 0; i < BG_AV_MAX_MINES; ++i)
316 if (m_Mine_Owner[i] != BG_AV_NEUTRAL_TEAM)
317 ++mines_owned[m_Mine_Owner[i]];
319 // now we have the values give the honor/reputation to the teams:
320 uint32 team[BG_TEAMS_COUNT] = { ALLIANCE, HORDE };
321 uint32 faction[BG_TEAMS_COUNT] = { BG_AV_FACTION_A, BG_AV_FACTION_H };
322 for (uint32 i = 0; i < BG_TEAMS_COUNT; i++)
324 if (tower_survived[i])
326 RewardReputationToTeam(faction[i], tower_survived[i] * m_RepSurviveTower, team[i]);
327 RewardHonorToTeam(GetBonusHonorFromKill(tower_survived[i] * BG_AV_KILL_SURVIVING_TOWER), team[i]);
329 sLog.outDebug("BattleGroundAV: EndbattleGround: bgteam: %u towers:%u honor:%u rep:%u", i, tower_survived[i], GetBonusHonorFromKill(tower_survived[i] * BG_AV_KILL_SURVIVING_TOWER), tower_survived[i] * BG_AV_REP_SURVIVING_TOWER);
330 if (graves_owned[i])
331 RewardReputationToTeam(faction[i], graves_owned[i] * m_RepOwnedGrave, team[i]);
332 if (mines_owned[i])
333 RewardReputationToTeam(faction[i], mines_owned[i] * m_RepOwnedMine, team[i]);
334 // captain survived?:
335 if (!IsActiveEvent(BG_AV_NodeEventCaptainDead_A + GetTeamIndexByTeamId(team[i]), 0))
337 RewardReputationToTeam(faction[i], m_RepSurviveCaptain, team[i]);
338 RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_SURVIVING_CAPTAIN), team[i]);
342 // both teams:
343 if (m_HonorMapComplete)
345 RewardHonorToTeam(m_HonorMapComplete, ALLIANCE);
346 RewardHonorToTeam(m_HonorMapComplete, HORDE);
348 BattleGround::EndBattleGround(winner);
351 void BattleGroundAV::RemovePlayer(Player* /*plr*/,uint64 /*guid*/)
355 void BattleGroundAV::HandleAreaTrigger(Player *Source, uint32 Trigger)
357 // this is wrong way to implement these things. On official it done by gameobject spell cast.
358 switch(Trigger)
360 case 95:
361 case 2608:
362 if (Source->GetTeam() != ALLIANCE)
363 Source->GetSession()->SendNotification(LANG_BATTLEGROUND_ONLY_ALLIANCE_USE);
364 else
365 Source->LeaveBattleground();
366 break;
367 case 2606:
368 if (Source->GetTeam() != HORDE)
369 Source->GetSession()->SendNotification(LANG_BATTLEGROUND_ONLY_HORDE_USE);
370 else
371 Source->LeaveBattleground();
372 break;
373 case 3326:
374 case 3327:
375 case 3328:
376 case 3329:
377 case 3330:
378 case 3331:
379 //Source->Unmount();
380 break;
381 default:
382 sLog.outDebug("BattleGroundAV: WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
383 // Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
384 break;
388 void BattleGroundAV::UpdatePlayerScore(Player* Source, uint32 type, uint32 value)
391 BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID());
392 if(itr == m_PlayerScores.end()) // player not found...
393 return;
395 switch(type)
397 case SCORE_GRAVEYARDS_ASSAULTED:
398 ((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted += value;
399 break;
400 case SCORE_GRAVEYARDS_DEFENDED:
401 ((BattleGroundAVScore*)itr->second)->GraveyardsDefended += value;
402 break;
403 case SCORE_TOWERS_ASSAULTED:
404 ((BattleGroundAVScore*)itr->second)->TowersAssaulted += value;
405 break;
406 case SCORE_TOWERS_DEFENDED:
407 ((BattleGroundAVScore*)itr->second)->TowersDefended += value;
408 break;
409 case SCORE_SECONDARY_OBJECTIVES:
410 ((BattleGroundAVScore*)itr->second)->SecondaryObjectives += value;
411 break;
412 default:
413 BattleGround::UpdatePlayerScore(Source, type, value);
414 break;
418 void BattleGroundAV::EventPlayerDestroyedPoint(BG_AV_Nodes node)
421 sLog.outDebug("BattleGroundAV: player destroyed point node %i", node);
423 // despawn banner
424 DestroyNode(node);
425 PopulateNode(node);
426 UpdateNodeWorldState(node);
428 uint32 owner = m_Nodes[node].Owner;
429 if (IsTower(node))
431 uint8 tmp = node - BG_AV_NODES_DUNBALDAR_SOUTH;
432 // despawn marshal (one of those guys protecting the boss)
433 SpawnEvent(BG_AV_MARSHAL_A_SOUTH + tmp, 0, false);
435 UpdateScore(BattleGroundTeamId(owner^0x1), (-1) * BG_AV_RES_TOWER);
436 RewardReputationToTeam((owner == BG_TEAM_ALLIANCE) ? BG_AV_FACTION_A : BG_AV_FACTION_H, m_RepTowerDestruction, owner);
437 RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_TOWER), owner);
438 SendYell2ToAll(LANG_BG_AV_TOWER_TAKEN, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0), GetNodeName(node), ( owner == BG_TEAM_ALLIANCE ) ? LANG_BG_ALLY : LANG_BG_HORDE);
440 else
442 SendYell2ToAll(LANG_BG_AV_GRAVE_TAKEN, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0), GetNodeName(node), ( owner == BG_TEAM_ALLIANCE ) ? LANG_BG_ALLY : LANG_BG_HORDE);
446 void BattleGroundAV::ChangeMineOwner(uint8 mine, uint32 team)
448 m_Mine_Timer[mine] = BG_AV_MINE_TICK_TIMER;
449 // TODO implement quest 7122
450 // mine=0 northmine, mine=1 southmine
451 // TODO changing the owner should result in setting respawntime to infinite for current creatures (they should fight the new ones), spawning new mine owners creatures and changing the chest - objects so that the current owning team can use them
452 assert(mine == BG_AV_NORTH_MINE || mine == BG_AV_SOUTH_MINE);
453 if (m_Mine_Owner[mine] == int8(team))
454 return;
456 if (team != BG_TEAM_ALLIANCE && team != BG_TEAM_HORDE)
457 team = BG_AV_NEUTRAL_TEAM;
459 m_Mine_PrevOwner[mine] = m_Mine_Owner[mine];
460 m_Mine_Owner[mine] = team;
462 SendMineWorldStates(mine);
464 SpawnEvent(BG_AV_MINE_EVENT + mine, team, true);
465 SpawnEvent(BG_AV_MINE_BOSSES + mine, team, true);
467 if (team == BG_TEAM_ALLIANCE || team == BG_TEAM_HORDE)
469 PlaySoundToAll((team == BG_TEAM_ALLIANCE) ? BG_AV_SOUND_ALLIANCE_GOOD : BG_AV_SOUND_HORDE_GOOD);
470 m_Mine_Reclaim_Timer[mine] = BG_AV_MINE_RECLAIM_TIMER;
471 SendYell2ToAll(LANG_BG_AV_MINE_TAKEN , LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0),
472 (team == BG_TEAM_ALLIANCE ) ? LANG_BG_ALLY : LANG_BG_HORDE,
473 (mine == BG_AV_NORTH_MINE) ? LANG_BG_AV_MINE_NORTH : LANG_BG_AV_MINE_SOUTH);
477 bool BattleGroundAV::PlayerCanDoMineQuest(int32 GOId, uint32 team)
479 if (GOId == BG_AV_OBJECTID_MINE_N)
480 return (m_Mine_Owner[BG_AV_NORTH_MINE] == GetTeamIndexByTeamId(team));
481 if (GOId == BG_AV_OBJECTID_MINE_S)
482 return (m_Mine_Owner[BG_AV_SOUTH_MINE] == GetTeamIndexByTeamId(team));
483 return true; // cause it's no mine'object it is ok if this is true
486 /// will spawn and despawn creatures around a node
487 /// more a wrapper around spawnevent cause graveyards are special
488 void BattleGroundAV::PopulateNode(BG_AV_Nodes node)
490 uint32 team = m_Nodes[node].Owner;
491 if (IsGrave(node) && team != BG_AV_NEUTRAL_TEAM)
493 uint32 graveDefenderType;
494 if (m_Team_QuestStatus[team][0] < 500 )
495 graveDefenderType = 0;
496 else if (m_Team_QuestStatus[team][0] < 1000 )
497 graveDefenderType = 1;
498 else if (m_Team_QuestStatus[team][0] < 1500 )
499 graveDefenderType = 2;
500 else
501 graveDefenderType = 3;
503 if (m_Nodes[node].State == POINT_CONTROLLED) // we can spawn the current owner event
504 SpawnEvent(BG_AV_NODES_MAX + node, team * BG_AV_MAX_GRAVETYPES + graveDefenderType, true);
505 else // we despawn the event from the prevowner
506 SpawnEvent(BG_AV_NODES_MAX + node, m_Nodes[node].PrevOwner * BG_AV_MAX_GRAVETYPES + graveDefenderType, false);
508 SpawnEvent(node, (team * BG_AV_MAX_STATES) + m_Nodes[node].State, true);
511 /// called when using a banner
512 void BattleGroundAV::EventPlayerClickedOnFlag(Player *source, GameObject* target_obj)
514 if (GetStatus() != STATUS_IN_PROGRESS)
515 return;
516 sLog.outDebug("BattleGroundAV: using gameobject %i", target_obj->GetEntry());
517 uint8 event = (sBattleGroundMgr.GetGameObjectEventIndex(target_obj->GetDBTableGUIDLow())).event1;
518 if (event >= BG_AV_NODES_MAX) // not a node
519 return;
520 BG_AV_Nodes node = BG_AV_Nodes(event);
521 switch ((sBattleGroundMgr.GetGameObjectEventIndex(target_obj->GetDBTableGUIDLow())).event2 % BG_AV_MAX_STATES)
523 case POINT_CONTROLLED:
524 EventPlayerAssaultsPoint(source, node);
525 break;
526 case POINT_ASSAULTED:
527 EventPlayerDefendsPoint(source, node);
528 break;
529 default:
530 break;
534 void BattleGroundAV::EventPlayerDefendsPoint(Player* player, BG_AV_Nodes node)
536 assert(GetStatus() == STATUS_IN_PROGRESS);
538 uint32 team = GetTeamIndexByTeamId(player->GetTeam());
540 if (m_Nodes[node].Owner == team || m_Nodes[node].State != POINT_ASSAULTED)
541 return;
542 if( m_Nodes[node].TotalOwner == BG_AV_NEUTRAL_TEAM ) // initial snowfall capture
544 // until snowfall doesn't belong to anyone it is better handled in assault - code (best would be to have a special function
545 // for neutral nodes.. but doing this just for snowfall will be a bit to much i think
546 assert(node == BG_AV_NODES_SNOWFALL_GRAVE); // currently the only neutral grave
547 EventPlayerAssaultsPoint(player, node);
548 return;
550 sLog.outDebug("BattleGroundAV: player defends node: %i", node);
551 if (m_Nodes[node].PrevOwner != team)
553 sLog.outError("BattleGroundAV: player defends point which doesn't belong to his team %i", node);
554 return;
557 DefendNode(node, team); // set the right variables for nodeinfo
558 PopulateNode(node); // spawn node-creatures (defender for example)
559 UpdateNodeWorldState(node); // send new mapicon to the player
561 if (IsTower(node))
563 SendYell2ToAll( LANG_BG_AV_TOWER_DEFENDED, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0),
564 GetNodeName(node),
565 ( team == BG_TEAM_ALLIANCE ) ? LANG_BG_ALLY:LANG_BG_HORDE);
566 UpdatePlayerScore(player, SCORE_TOWERS_DEFENDED, 1);
567 PlaySoundToAll(BG_AV_SOUND_BOTH_TOWER_DEFEND);
569 else
571 SendYell2ToAll(LANG_BG_AV_GRAVE_DEFENDED, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0),
572 GetNodeName(node),
573 ( team == BG_TEAM_ALLIANCE ) ? LANG_BG_ALLY:LANG_BG_HORDE);
574 UpdatePlayerScore(player, SCORE_GRAVEYARDS_DEFENDED, 1);
575 // update the statistic for the defending player
576 PlaySoundToAll((team == BG_TEAM_ALLIANCE)?BG_AV_SOUND_ALLIANCE_GOOD:BG_AV_SOUND_HORDE_GOOD);
580 void BattleGroundAV::EventPlayerAssaultsPoint(Player* player, BG_AV_Nodes node)
582 // TODO implement quest 7101, 7081
583 uint32 team = GetTeamIndexByTeamId(player->GetTeam());
584 sLog.outDebug("BattleGroundAV: player assaults node %i", node);
585 if (m_Nodes[node].Owner == team || team == m_Nodes[node].TotalOwner)
586 return;
588 AssaultNode(node, team); // update nodeinfo variables
589 UpdateNodeWorldState(node); // send mapicon
590 PopulateNode(node);
592 if (IsTower(node))
594 SendYell2ToAll(LANG_BG_AV_TOWER_ASSAULTED, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0),
595 GetNodeName(node),
596 ( team == BG_TEAM_ALLIANCE ) ? LANG_BG_ALLY:LANG_BG_HORDE);
597 UpdatePlayerScore(player, SCORE_TOWERS_ASSAULTED, 1);
599 else
601 SendYell2ToAll(LANG_BG_AV_GRAVE_ASSAULTED, LANG_UNIVERSAL, GetSingleCreatureGuid(BG_AV_HERALD, 0),
602 GetNodeName(node),
603 ( team == BG_TEAM_ALLIANCE ) ? LANG_BG_ALLY:LANG_BG_HORDE);
604 // update the statistic for the assaulting player
605 UpdatePlayerScore(player, SCORE_GRAVEYARDS_ASSAULTED, 1);
608 PlaySoundToAll((team == BG_TEAM_ALLIANCE) ? BG_AV_SOUND_ALLIANCE_ASSAULTS : BG_AV_SOUND_HORDE_ASSAULTS);
611 void BattleGroundAV::FillInitialWorldStates(WorldPacket& data)
613 bool stateok;
614 for (uint32 i = BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i)
616 for (uint8 j = 0; j < BG_AV_MAX_STATES; j++)
618 stateok = (m_Nodes[i].State == j);
619 data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j, BG_TEAM_ALLIANCE)]) << uint32((m_Nodes[i].Owner == BG_TEAM_ALLIANCE && stateok) ? 1 : 0);
620 data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j, BG_TEAM_HORDE)]) << uint32((m_Nodes[i].Owner == BG_TEAM_HORDE && stateok) ? 1 : 0);
624 if( m_Nodes[BG_AV_NODES_SNOWFALL_GRAVE].Owner == BG_AV_NEUTRAL_TEAM ) // cause neutral teams aren't handled generic
625 data << uint32(AV_SNOWFALL_N) << uint32(1);
627 data << uint32(BG_AV_Alliance_Score) << uint32(m_TeamScores[BG_TEAM_ALLIANCE]);
628 data << uint32(BG_AV_Horde_Score) << uint32(m_TeamScores[BG_TEAM_HORDE]);
629 if( GetStatus() == STATUS_IN_PROGRESS ) // only if game is running the teamscores are displayed
631 data << uint32(BG_AV_SHOW_A_SCORE) << uint32(1);
632 data << uint32(BG_AV_SHOW_H_SCORE) << uint32(1);
634 else
636 data << uint32(BG_AV_SHOW_A_SCORE) << uint32(0);
637 data << uint32(BG_AV_SHOW_H_SCORE) << uint32(0);
639 SendMineWorldStates(BG_AV_NORTH_MINE);
640 SendMineWorldStates(BG_AV_SOUTH_MINE);
643 void BattleGroundAV::UpdateNodeWorldState(BG_AV_Nodes node)
645 UpdateWorldState(BG_AV_NodeWorldStates[node][GetWorldStateType(m_Nodes[node].State,m_Nodes[node].Owner)], 1);
646 if( m_Nodes[node].PrevOwner == BG_AV_NEUTRAL_TEAM ) // currently only snowfall is supported as neutral node
647 UpdateWorldState(AV_SNOWFALL_N, 0);
648 else
649 UpdateWorldState(BG_AV_NodeWorldStates[node][GetWorldStateType(m_Nodes[node].PrevState,m_Nodes[node].PrevOwner)], 0);
652 void BattleGroundAV::SendMineWorldStates(uint32 mine)
654 assert(mine == BG_AV_NORTH_MINE || mine == BG_AV_SOUTH_MINE);
655 assert(m_Mine_PrevOwner[mine] == BG_TEAM_ALLIANCE || m_Mine_PrevOwner[mine] == BG_TEAM_HORDE || m_Mine_PrevOwner[mine] == BG_AV_NEUTRAL_TEAM);
656 assert(m_Mine_Owner[mine] == BG_TEAM_ALLIANCE || m_Mine_Owner[mine] == BG_TEAM_HORDE || m_Mine_Owner[mine] == BG_AV_NEUTRAL_TEAM);
658 UpdateWorldState(BG_AV_MineWorldStates[mine][m_Mine_Owner[mine]], 1);
659 if (m_Mine_Owner[mine] != m_Mine_PrevOwner[mine])
660 UpdateWorldState(BG_AV_MineWorldStates[mine][m_Mine_PrevOwner[mine]], 0);
663 WorldSafeLocsEntry const* BattleGroundAV::GetClosestGraveYard(Player *plr)
665 float x = plr->GetPositionX();
666 float y = plr->GetPositionY();
667 uint32 team = GetTeamIndexByTeamId(plr->GetTeam());
668 WorldSafeLocsEntry const* good_entry = NULL;
669 if (GetStatus() == STATUS_IN_PROGRESS)
671 // Is there any occupied node for this team?
672 float mindist = 9999999.0f;
673 for(uint8 i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i)
675 if (m_Nodes[i].Owner != team || m_Nodes[i].State != POINT_CONTROLLED)
676 continue;
677 WorldSafeLocsEntry const * entry = sWorldSafeLocsStore.LookupEntry( BG_AV_GraveyardIds[i] );
678 if (!entry)
679 continue;
680 float dist = (entry->x - x) * (entry->x - x) + (entry->y - y) * (entry->y - y);
681 if (mindist > dist)
683 mindist = dist;
684 good_entry = entry;
688 // If not, place ghost in the starting-cave
689 if (!good_entry)
690 good_entry = sWorldSafeLocsStore.LookupEntry( BG_AV_GraveyardIds[team + 7] );
692 return good_entry;
695 uint32 BattleGroundAV::GetNodeName(BG_AV_Nodes node)
697 switch (node)
699 case BG_AV_NODES_FIRSTAID_STATION: return LANG_BG_AV_NODE_GRAVE_STORM_AID;
700 case BG_AV_NODES_DUNBALDAR_SOUTH: return LANG_BG_AV_NODE_TOWER_DUN_S;
701 case BG_AV_NODES_DUNBALDAR_NORTH: return LANG_BG_AV_NODE_TOWER_DUN_N;
702 case BG_AV_NODES_STORMPIKE_GRAVE: return LANG_BG_AV_NODE_GRAVE_STORMPIKE;
703 case BG_AV_NODES_ICEWING_BUNKER: return LANG_BG_AV_NODE_TOWER_ICEWING;
704 case BG_AV_NODES_STONEHEART_GRAVE: return LANG_BG_AV_NODE_GRAVE_STONE;
705 case BG_AV_NODES_STONEHEART_BUNKER: return LANG_BG_AV_NODE_TOWER_STONE;
706 case BG_AV_NODES_SNOWFALL_GRAVE: return LANG_BG_AV_NODE_GRAVE_SNOW;
707 case BG_AV_NODES_ICEBLOOD_TOWER: return LANG_BG_AV_NODE_TOWER_ICE;
708 case BG_AV_NODES_ICEBLOOD_GRAVE: return LANG_BG_AV_NODE_GRAVE_ICE;
709 case BG_AV_NODES_TOWER_POINT: return LANG_BG_AV_NODE_TOWER_POINT;
710 case BG_AV_NODES_FROSTWOLF_GRAVE: return LANG_BG_AV_NODE_GRAVE_FROST;
711 case BG_AV_NODES_FROSTWOLF_ETOWER: return LANG_BG_AV_NODE_TOWER_FROST_E;
712 case BG_AV_NODES_FROSTWOLF_WTOWER: return LANG_BG_AV_NODE_TOWER_FROST_W;
713 case BG_AV_NODES_FROSTWOLF_HUT: return LANG_BG_AV_NODE_GRAVE_FROST_HUT;
714 default: return 0; break;
718 void BattleGroundAV::AssaultNode(BG_AV_Nodes node, uint32 team)
720 assert(team < 3); // alliance:0, horde:1, neutral:2
721 assert(m_Nodes[node].TotalOwner != team);
722 assert(m_Nodes[node].Owner != team);
723 // only assault an assaulted node if no totalowner exists:
724 assert(m_Nodes[node].State != POINT_ASSAULTED || m_Nodes[node].TotalOwner == BG_AV_NEUTRAL_TEAM);
725 // the timer gets another time, if the previous owner was 0 == Neutral
726 m_Nodes[node].Timer = (m_Nodes[node].PrevOwner != BG_AV_NEUTRAL_TEAM) ? BG_AV_CAPTIME : BG_AV_SNOWFALL_FIRSTCAP;
727 m_Nodes[node].PrevOwner = m_Nodes[node].Owner;
728 m_Nodes[node].Owner = team;
729 m_Nodes[node].PrevState = m_Nodes[node].State;
730 m_Nodes[node].State = POINT_ASSAULTED;
733 void BattleGroundAV::DestroyNode(BG_AV_Nodes node)
735 assert(m_Nodes[node].State == POINT_ASSAULTED);
737 m_Nodes[node].TotalOwner = m_Nodes[node].Owner;
738 m_Nodes[node].PrevOwner = m_Nodes[node].Owner;
739 m_Nodes[node].PrevState = m_Nodes[node].State;
740 m_Nodes[node].State = POINT_CONTROLLED;
741 m_Nodes[node].Timer = 0;
744 void BattleGroundAV::InitNode(BG_AV_Nodes node, uint32 team, bool tower)
746 assert(team < 3); // alliance:0, horde:1, neutral:2
747 m_Nodes[node].TotalOwner = team;
748 m_Nodes[node].Owner = team;
749 m_Nodes[node].PrevOwner = team;
750 m_Nodes[node].State = POINT_CONTROLLED;
751 m_Nodes[node].PrevState = m_Nodes[node].State;
752 m_Nodes[node].State = POINT_CONTROLLED;
753 m_Nodes[node].Timer = 0;
754 m_Nodes[node].Tower = tower;
755 m_ActiveEvents[node] = team * BG_AV_MAX_STATES + m_Nodes[node].State;
756 if (IsGrave(node)) // grave-creatures are special cause of a quest
757 m_ActiveEvents[node + BG_AV_NODES_MAX] = team * BG_AV_MAX_GRAVETYPES;
760 void BattleGroundAV::DefendNode(BG_AV_Nodes node, uint32 team)
762 assert(team < 3); // alliance:0, horde:1, neutral:2
763 assert(m_Nodes[node].TotalOwner == team);
764 assert(m_Nodes[node].Owner != team);
765 assert(m_Nodes[node].State != POINT_CONTROLLED);
766 m_Nodes[node].PrevOwner = m_Nodes[node].Owner;
767 m_Nodes[node].Owner = team;
768 m_Nodes[node].PrevState = m_Nodes[node].State;
769 m_Nodes[node].State = POINT_CONTROLLED;
770 m_Nodes[node].Timer = 0;
773 void BattleGroundAV::Reset()
775 BattleGround::Reset();
776 // set the reputation and honor variables:
777 bool isBGWeekend = sBattleGroundMgr.IsBGWeekend(GetTypeID());
779 m_HonorMapComplete = (isBGWeekend) ? BG_AV_KILL_MAP_COMPLETE_HOLIDAY : BG_AV_KILL_MAP_COMPLETE;
780 m_RepTowerDestruction = (isBGWeekend) ? BG_AV_REP_TOWER_HOLIDAY : BG_AV_REP_TOWER;
781 m_RepCaptain = (isBGWeekend) ? BG_AV_REP_CAPTAIN_HOLIDAY : BG_AV_REP_CAPTAIN;
782 m_RepBoss = (isBGWeekend) ? BG_AV_REP_BOSS_HOLIDAY : BG_AV_REP_BOSS;
783 m_RepOwnedGrave = (isBGWeekend) ? BG_AV_REP_OWNED_GRAVE_HOLIDAY : BG_AV_REP_OWNED_GRAVE;
784 m_RepSurviveCaptain = (isBGWeekend) ? BG_AV_REP_SURVIVING_CAPTAIN_HOLIDAY : BG_AV_REP_SURVIVING_CAPTAIN;
785 m_RepSurviveTower = (isBGWeekend) ? BG_AV_REP_SURVIVING_TOWER_HOLIDAY : BG_AV_REP_SURVIVING_TOWER;
786 m_RepOwnedMine = (isBGWeekend) ? BG_AV_REP_OWNED_MINE_HOLIDAY : BG_AV_REP_OWNED_MINE;
788 for(uint8 i = 0; i < BG_TEAMS_COUNT; i++)
790 for(uint8 j = 0; j < 9; j++) // 9 quests getting tracked
791 m_Team_QuestStatus[i][j] = 0;
792 m_TeamScores[i] = BG_AV_SCORE_INITIAL_POINTS;
793 m_IsInformedNearLose[i] = false;
794 m_ActiveEvents[BG_AV_NodeEventCaptainDead_A + i] = BG_EVENT_NONE;
797 for(uint8 i = 0; i < BG_AV_MAX_MINES; i++)
799 m_Mine_Owner[i] = BG_AV_NEUTRAL_TEAM;
800 m_Mine_PrevOwner[i] = m_Mine_Owner[i];
801 m_ActiveEvents[BG_AV_MINE_BOSSES+ i] = BG_AV_NEUTRAL_TEAM;
802 m_ActiveEvents[BG_AV_MINE_EVENT + i] = BG_AV_NEUTRAL_TEAM;
803 m_Mine_Timer[i] = BG_AV_MINE_TICK_TIMER;
806 m_ActiveEvents[BG_AV_CAPTAIN_A] = 0;
807 m_ActiveEvents[BG_AV_CAPTAIN_H] = 0;
808 m_ActiveEvents[BG_AV_HERALD] = 0;
809 m_ActiveEvents[BG_AV_BOSS_A] = 0;
810 m_ActiveEvents[BG_AV_BOSS_H] = 0;
811 for(BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i) // towers
812 m_ActiveEvents[BG_AV_MARSHAL_A_SOUTH + i - BG_AV_NODES_DUNBALDAR_SOUTH] = 0;
814 for(BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_STONEHEART_GRAVE; ++i) // alliance graves
815 InitNode(i, BG_TEAM_ALLIANCE, false);
816 for(BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_STONEHEART_BUNKER; ++i) // alliance towers
817 InitNode(i, BG_TEAM_ALLIANCE, true);
819 for(BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_GRAVE; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i) // horde graves
820 InitNode(i, BG_TEAM_HORDE, false);
821 for(BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_TOWER; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i) // horde towers
822 InitNode(i, BG_TEAM_HORDE, true);
824 InitNode(BG_AV_NODES_SNOWFALL_GRAVE, BG_AV_NEUTRAL_TEAM, false); // give snowfall neutral owner