[7732] Fixed compile warnings.
[getmangos.git] / src / game / BattleGround.cpp
blobb19d53474d37833432a7b2722d87fc56ffe06694
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 "BattleGroundMgr.h"
23 #include "Creature.h"
24 #include "MapManager.h"
25 #include "Language.h"
26 #include "SpellAuras.h"
27 #include "ArenaTeam.h"
28 #include "World.h"
29 #include "Group.h"
30 #include "ObjectMgr.h"
31 #include "WorldPacket.h"
32 #include "Util.h"
33 #include "Formulas.h"
34 #include "GridNotifiersImpl.h"
36 namespace MaNGOS
38 class BattleGroundChatBuilder
40 public:
41 BattleGroundChatBuilder(ChatMsg msgtype, int32 textId, Player const* source, va_list* args = NULL)
42 : i_msgtype(msgtype), i_textId(textId), i_source(source), i_args(args) {}
43 void operator()(WorldPacket& data, int32 loc_idx)
45 char const* text = objmgr.GetMangosString(i_textId,loc_idx);
47 if (i_args)
49 // we need copy va_list before use or original va_list will corrupted
50 va_list ap;
51 va_copy(ap,*i_args);
53 char str [2048];
54 vsnprintf(str,2048,text, ap );
55 va_end(ap);
57 do_helper(data,&str[0]);
59 else
60 do_helper(data,text);
62 private:
63 void do_helper(WorldPacket& data, char const* text)
65 uint64 target_guid = i_source ? i_source ->GetGUID() : 0;
67 data << uint8(i_msgtype);
68 data << uint32(LANG_UNIVERSAL);
69 data << uint64(target_guid); // there 0 for BG messages
70 data << uint32(0); // can be chat msg group or something
71 data << uint64(target_guid);
72 data << uint32(strlen(text)+1);
73 data << text;
74 data << uint8(i_source ? i_source->chatTag() : uint8(0));
77 ChatMsg i_msgtype;
78 int32 i_textId;
79 Player const* i_source;
80 va_list* i_args;
83 class BattleGround2ChatBuilder
85 public:
86 BattleGround2ChatBuilder(ChatMsg msgtype, int32 textId, Player const* source, int32 arg1, int32 arg2)
87 : i_msgtype(msgtype), i_textId(textId), i_source(source), i_arg1(arg1), i_arg2(arg2) {}
88 void operator()(WorldPacket& data, int32 loc_idx)
90 char const* text = objmgr.GetMangosString(i_textId,loc_idx);
91 char const* arg1str = i_arg1 ? objmgr.GetMangosString(i_arg1,loc_idx) : "";
92 char const* arg2str = i_arg2 ? objmgr.GetMangosString(i_arg2,loc_idx) : "";
94 char str [2048];
95 snprintf(str,2048,text, arg1str, arg2str );
97 uint64 target_guid = i_source ? i_source ->GetGUID() : 0;
99 data << uint8(i_msgtype);
100 data << uint32(LANG_UNIVERSAL);
101 data << uint64(target_guid); // there 0 for BG messages
102 data << uint32(0); // can be chat msg group or something
103 data << uint64(target_guid);
104 data << uint32(strlen(str)+1);
105 data << str;
106 data << uint8(i_source ? i_source->chatTag() : uint8(0));
108 private:
110 ChatMsg i_msgtype;
111 int32 i_textId;
112 Player const* i_source;
113 int32 i_arg1;
114 int32 i_arg2;
116 } // namespace MaNGOS
118 template<class Do>
119 void BattleGround::BroadcastWorker(Do& _do)
121 for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
122 if (Player *plr = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)))
123 _do(plr);
126 BattleGround::BattleGround()
128 m_TypeID = BattleGroundTypeId(0);
129 m_InstanceID = 0;
130 m_Status = STATUS_NONE;
131 m_ClientInstanceID = 0;
132 m_EndTime = 0;
133 m_LastResurrectTime = 0;
134 m_QueueId = QUEUE_ID_MAX_LEVEL_19;
135 m_InvitedAlliance = 0;
136 m_InvitedHorde = 0;
137 m_ArenaType = 0;
138 m_IsArena = false;
139 m_Winner = 2;
140 m_StartTime = 0;
141 m_Events = 0;
142 m_IsRated = false;
143 m_BuffChange = false;
144 m_Name = "";
145 m_LevelMin = 0;
146 m_LevelMax = 0;
147 m_InBGFreeSlotQueue = false;
148 m_SetDeleteThis = false;
150 m_MaxPlayersPerTeam = 0;
151 m_MaxPlayers = 0;
152 m_MinPlayersPerTeam = 0;
153 m_MinPlayers = 0;
155 m_MapId = 0;
157 m_TeamStartLocX[BG_TEAM_ALLIANCE] = 0;
158 m_TeamStartLocX[BG_TEAM_HORDE] = 0;
160 m_TeamStartLocY[BG_TEAM_ALLIANCE] = 0;
161 m_TeamStartLocY[BG_TEAM_HORDE] = 0;
163 m_TeamStartLocZ[BG_TEAM_ALLIANCE] = 0;
164 m_TeamStartLocZ[BG_TEAM_HORDE] = 0;
166 m_TeamStartLocO[BG_TEAM_ALLIANCE] = 0;
167 m_TeamStartLocO[BG_TEAM_HORDE] = 0;
169 m_ArenaTeamIds[BG_TEAM_ALLIANCE] = 0;
170 m_ArenaTeamIds[BG_TEAM_HORDE] = 0;
172 m_ArenaTeamRatingChanges[BG_TEAM_ALLIANCE] = 0;
173 m_ArenaTeamRatingChanges[BG_TEAM_HORDE] = 0;
175 m_BgRaids[BG_TEAM_ALLIANCE] = NULL;
176 m_BgRaids[BG_TEAM_HORDE] = NULL;
178 m_PlayersCount[BG_TEAM_ALLIANCE] = 0;
179 m_PlayersCount[BG_TEAM_HORDE] = 0;
181 m_PrematureCountDown = false;
182 m_PrematureCountDown = 0;
184 m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_2M;
185 m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_1M;
186 m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_30S;
187 m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
188 //we must set to some default existing values
189 m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES;
190 m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE;
191 m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE;
192 m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN;
195 BattleGround::~BattleGround()
197 // remove objects and creatures
198 // (this is done automatically in mapmanager update, when the instance is reset after the reset time)
199 int size = m_BgCreatures.size();
200 for(int i = 0; i < size; ++i)
202 DelCreature(i);
204 size = m_BgObjects.size();
205 for(int i = 0; i < size; ++i)
207 DelObject(i);
210 if(GetInstanceID()) // not spam by useless queries in case BG templates
212 // delete creature and go respawn times
213 WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'",GetInstanceID());
214 WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'",GetInstanceID());
215 // delete instance from db
216 CharacterDatabase.PExecute("DELETE FROM instance WHERE id = '%u'",GetInstanceID());
217 // remove from battlegrounds
220 sBattleGroundMgr.RemoveBattleGround(GetInstanceID(), GetTypeID());
221 // unload map
222 if (Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID()))
223 if (map->IsBattleGroundOrArena())
224 ((BattleGroundMap*)map)->SetUnload();
225 // remove from bg free slot queue
226 this->RemoveFromBGFreeSlotQueue();
229 void BattleGround::Update(uint32 diff)
231 if (!GetPlayersSize() && !GetReviveQueueSize())
232 //BG is empty
233 return;
235 // remove offline players from bg after 5 minutes
236 if (!m_OfflineQueue.empty())
238 BattleGroundPlayerMap::iterator itr = m_Players.find(*(m_OfflineQueue.begin()));
239 if (itr != m_Players.end())
241 if (itr->second.OfflineRemoveTime <= sWorld.GetGameTime())
243 RemovePlayerAtLeave(itr->first, true, true);// remove player from BG
244 m_OfflineQueue.pop_front(); // remove from offline queue
245 //do not use itr for anything, because it is erased in RemovePlayerAtLeave()
250 /*********************************************************/
251 /*** BATTLEGROUND RESSURECTION SYSTEM ***/
252 /*********************************************************/
254 //this should be handled by spell system
255 m_LastResurrectTime += diff;
256 if (m_LastResurrectTime >= RESURRECTION_INTERVAL)
258 if (GetReviveQueueSize())
260 for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
262 Creature *sh = NULL;
263 for(std::vector<uint64>::const_iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
265 Player *plr = objmgr.GetPlayer(*itr2);
266 if (!plr)
267 continue;
269 if (!sh && plr->IsInWorld())
271 sh = plr->GetMap()->GetCreature(itr->first);
272 // only for visual effect
273 if (sh)
274 sh->CastSpell(sh, SPELL_SPIRIT_HEAL, true); // Spirit Heal, effect 117
277 plr->CastSpell(plr, SPELL_RESURRECTION_VISUAL, true); // Resurrection visual
278 m_ResurrectQueue.push_back(*itr2);
280 (itr->second).clear();
283 m_ReviveQueue.clear();
284 m_LastResurrectTime = 0;
286 else
287 // queue is clear and time passed, just update last resurrection time
288 m_LastResurrectTime = 0;
290 else if (m_LastResurrectTime > 500) // Resurrect players only half a second later, to see spirit heal effect on NPC
292 for(std::vector<uint64>::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
294 Player *plr = objmgr.GetPlayer(*itr);
295 if (!plr)
296 continue;
297 plr->ResurrectPlayer(1.0f);
298 plr->CastSpell(plr, SPELL_SPIRIT_HEAL_MANA, true);
299 ObjectAccessor::Instance().ConvertCorpseForPlayer(*itr);
301 m_ResurrectQueue.clear();
304 /*********************************************************/
305 /*** BATTLEGROUND BALLANCE SYSTEM ***/
306 /*********************************************************/
308 // if less then minimum players are in on one side, then start premature finish timer
309 if (GetStatus() == STATUS_IN_PROGRESS && !isArena() && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam()))
311 if (!m_PrematureCountDown)
313 m_PrematureCountDown = true;
314 m_PrematureCountDownTimer = sBattleGroundMgr.GetPrematureFinishTime();
316 else if (m_PrematureCountDownTimer < diff)
318 // time's up!
319 uint32 winner = 0;
320 if (GetPlayersCountByTeam(ALLIANCE) >= GetMinPlayersPerTeam())
321 winner = ALLIANCE;
322 else if (GetPlayersCountByTeam(HORDE) >= GetMinPlayersPerTeam())
323 winner = HORDE;
325 EndBattleGround(winner);
326 m_PrematureCountDown = false;
328 else
330 uint32 newtime = m_PrematureCountDownTimer - diff;
331 // announce every minute
332 if (newtime > (MINUTE * IN_MILISECONDS))
334 if (newtime / (MINUTE * IN_MILISECONDS) != m_PrematureCountDownTimer / (MINUTE * IN_MILISECONDS))
335 PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING, CHAT_MSG_SYSTEM, NULL, (uint32)(m_PrematureCountDownTimer / (MINUTE * IN_MILISECONDS)));
337 else
339 //announce every 15 seconds
340 if (newtime / (15 * IN_MILISECONDS) != m_PrematureCountDownTimer / (15 * IN_MILISECONDS))
341 PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS, CHAT_MSG_SYSTEM, NULL, (uint32)(m_PrematureCountDownTimer / IN_MILISECONDS));
343 m_PrematureCountDownTimer = newtime;
346 else if (m_PrematureCountDown)
347 m_PrematureCountDown = false;
349 /*********************************************************/
350 /*** BATTLEGROUND STARTING SYSTEM ***/
351 /*********************************************************/
353 if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
355 ModifyStartDelayTime(diff);
357 if (!(m_Events & BG_STARTING_EVENT_1))
359 m_Events |= BG_STARTING_EVENT_1;
361 // setup here, only when at least one player has ported to the map
362 if (!SetupBattleGround())
364 EndNow();
365 return;
368 StartingEventCloseDoors();
369 SetStartDelayTime(m_StartDelayTimes[BG_STARTING_EVENT_FIRST]);
370 //first start warning - 2 or 1 minute
371 SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_FIRST], CHAT_MSG_BG_SYSTEM_NEUTRAL);
373 // After 1 minute or 30 seconds, warning is signalled
374 else if (GetStartDelayTime() <= m_StartDelayTimes[BG_STARTING_EVENT_SECOND] && !(m_Events & BG_STARTING_EVENT_2))
376 m_Events |= BG_STARTING_EVENT_2;
377 SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_SECOND], CHAT_MSG_BG_SYSTEM_NEUTRAL);
379 // After 30 or 15 seconds, warning is signalled
380 else if (GetStartDelayTime() <= m_StartDelayTimes[BG_STARTING_EVENT_THIRD] && !(m_Events & BG_STARTING_EVENT_3))
382 m_Events |= BG_STARTING_EVENT_3;
383 SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_THIRD], CHAT_MSG_BG_SYSTEM_NEUTRAL);
385 // delay expired (atfer 2 or 1 minute)
386 else if (GetStartDelayTime() <= 0 && !(m_Events & BG_STARTING_EVENT_4))
388 m_Events |= BG_STARTING_EVENT_4;
390 StartingEventOpenDoors();
392 SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_FOURTH], CHAT_MSG_BG_SYSTEM_NEUTRAL);
393 SetStatus(STATUS_IN_PROGRESS);
394 SetStartDelayTime(m_StartDelayTimes[BG_STARTING_EVENT_FOURTH]);
396 //remove preparation
397 if (isArena())
399 //TODO : add arena sound PlaySoundToAll(SOUND_ARENA_START);
401 for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
402 if (Player *plr = objmgr.GetPlayer(itr->first))
403 plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
405 CheckArenaWinConditions();
407 else
410 PlaySoundToAll(SOUND_BG_START);
412 for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
413 if (Player* plr = objmgr.GetPlayer(itr->first))
414 plr->RemoveAurasDueToSpell(SPELL_PREPARATION);
415 //Announce BG starting
416 if (sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE))
418 sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, GetName(), GetMinLevel(), GetMaxLevel());
424 /*********************************************************/
425 /*** BATTLEGROUND ENDING SYSTEM ***/
426 /*********************************************************/
428 if (GetStatus() == STATUS_WAIT_LEAVE)
430 // remove all players from battleground after 2 minutes
431 m_EndTime -= diff;
432 if (m_EndTime <= 0)
434 m_EndTime = 0;
435 BattleGroundPlayerMap::iterator itr, next;
436 for(itr = m_Players.begin(); itr != m_Players.end(); itr = next)
438 next = itr;
439 ++next;
440 //itr is erased here!
441 RemovePlayerAtLeave(itr->first, true, true);// remove player from BG
442 // do not change any battleground's private variables
447 //update start time
448 m_StartTime += diff;
451 void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O)
453 uint8 idx = GetTeamIndexByTeamId(TeamID);
454 m_TeamStartLocX[idx] = X;
455 m_TeamStartLocY[idx] = Y;
456 m_TeamStartLocZ[idx] = Z;
457 m_TeamStartLocO[idx] = O;
460 void BattleGround::SendPacketToAll(WorldPacket *packet)
462 for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
464 Player *plr = objmgr.GetPlayer(itr->first);
465 if (plr)
466 plr->GetSession()->SendPacket(packet);
467 else
468 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
472 void BattleGround::SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *sender, bool self)
474 for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
476 Player *plr = objmgr.GetPlayer(itr->first);
478 if (!plr)
480 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
481 continue;
484 if (!self && sender == plr)
485 continue;
487 uint32 team = itr->second.Team;
488 if(!team) team = plr->GetTeam();
490 if (team == TeamID)
491 plr->GetSession()->SendPacket(packet);
495 void BattleGround::PlaySoundToAll(uint32 SoundID)
497 WorldPacket data;
498 sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
499 SendPacketToAll(&data);
502 void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID)
504 WorldPacket data;
506 for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
508 Player *plr = objmgr.GetPlayer(itr->first);
510 if (!plr)
512 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
513 continue;
516 uint32 team = itr->second.Team;
517 if(!team) team = plr->GetTeam();
519 if (team == TeamID)
521 sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
522 plr->GetSession()->SendPacket(&data);
527 void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID)
529 for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
531 Player *plr = objmgr.GetPlayer(itr->first);
533 if (!plr)
535 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
536 continue;
539 uint32 team = itr->second.Team;
540 if(!team) team = plr->GetTeam();
542 if (team == TeamID)
543 plr->CastSpell(plr, SpellID, true);
547 void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID)
549 for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
551 Player *plr = objmgr.GetPlayer(itr->first);
553 if (!plr)
555 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
556 continue;
559 uint32 team = itr->second.Team;
560 if(!team) team = plr->GetTeam();
562 if (team == TeamID)
563 UpdatePlayerScore(plr, SCORE_BONUS_HONOR, Honor);
567 void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID)
569 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
571 if (!factionEntry)
572 return;
574 for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
576 Player *plr = objmgr.GetPlayer(itr->first);
578 if (!plr)
580 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
581 continue;
584 uint32 team = itr->second.Team;
585 if(!team) team = plr->GetTeam();
587 if (team == TeamID)
588 plr->GetReputationMgr().ModifyReputation(factionEntry, Reputation);
592 void BattleGround::UpdateWorldState(uint32 Field, uint32 Value)
594 WorldPacket data;
595 sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
596 SendPacketToAll(&data);
599 void BattleGround::UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player *Source)
601 WorldPacket data;
602 sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
603 Source->GetSession()->SendPacket(&data);
606 void BattleGround::EndBattleGround(uint32 winner)
608 this->RemoveFromBGFreeSlotQueue();
610 ArenaTeam * winner_arena_team = NULL;
611 ArenaTeam * loser_arena_team = NULL;
612 uint32 loser_rating = 0;
613 uint32 winner_rating = 0;
614 WorldPacket data;
615 int32 winmsg_id = 0;
617 if (winner == ALLIANCE)
619 winmsg_id = isBattleGround() ? LANG_BG_A_WINS : LANG_ARENA_GOLD_WINS;
621 PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound
623 SetWinner(WINNER_ALLIANCE);
625 else if (winner == HORDE)
627 winmsg_id = isBattleGround() ? LANG_BG_H_WINS : LANG_ARENA_GREEN_WINS;
629 PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound
631 SetWinner(WINNER_HORDE);
633 else
635 SetWinner(3);
638 SetStatus(STATUS_WAIT_LEAVE);
639 //we must set it this way, because end time is sent in packet!
640 m_EndTime = TIME_TO_AUTOREMOVE;
642 // arena rating calculation
643 if (isArena() && isRated())
645 winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(winner));
646 loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(winner)));
647 if (winner_arena_team && loser_arena_team)
649 loser_rating = loser_arena_team->GetStats().rating;
650 winner_rating = winner_arena_team->GetStats().rating;
651 int32 winner_change = winner_arena_team->WonAgainst(loser_rating);
652 int32 loser_change = loser_arena_team->LostAgainst(winner_rating);
653 sLog.outDebug("--- Winner rating: %u, Loser rating: %u, Winner change: %u, Losser change: %u ---", winner_rating, loser_rating, winner_change, loser_change);
654 SetArenaTeamRatingChangeForTeam(winner, winner_change);
655 SetArenaTeamRatingChangeForTeam(GetOtherTeam(winner), loser_change);
657 else
659 SetArenaTeamRatingChangeForTeam(ALLIANCE, 0);
660 SetArenaTeamRatingChangeForTeam(HORDE, 0);
664 for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
666 Player *plr = objmgr.GetPlayer(itr->first);
667 uint32 team = itr->second.Team;
669 if (!plr)
671 //if rated arena match - make member lost!
672 if (isArena() && isRated() && winner_arena_team && loser_arena_team)
674 if (team == winner)
675 winner_arena_team->OfflineMemberLost(itr->first, loser_rating);
676 else
677 loser_arena_team->OfflineMemberLost(itr->first, winner_rating);
679 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
680 continue;
683 // should remove spirit of redemption
684 if (plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
685 plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
687 if (!plr->isAlive())
689 plr->ResurrectPlayer(1.0f);
690 plr->SpawnCorpseBones();
693 //this line is obsolete - team is set ALWAYS
694 //if(!team) team = plr->GetTeam();
696 // per player calculation
697 if (isArena() && isRated() && winner_arena_team && loser_arena_team)
699 if (team == winner)
700 winner_arena_team->MemberWon(plr,loser_rating);
701 else
702 loser_arena_team->MemberLost(plr,winner_rating);
705 if (team == winner)
707 RewardMark(plr,ITEM_WINNER_COUNT);
708 RewardQuest(plr);
710 else
712 RewardMark(plr,ITEM_LOSER_COUNT);
715 plr->CombatStopWithPets(true);
717 BlockMovement(plr);
719 sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
720 plr->GetSession()->SendPacket(&data);
722 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
723 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType());
724 plr->GetSession()->SendPacket(&data);
725 plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1);
728 if (isArena() && isRated() && winner_arena_team && loser_arena_team)
730 // update arena points only after increasing the player's match count!
731 //obsolete: winner_arena_team->UpdateArenaPointsHelper();
732 //obsolete: loser_arena_team->UpdateArenaPointsHelper();
733 // save the stat changes
734 winner_arena_team->SaveToDB();
735 loser_arena_team->SaveToDB();
736 // send updated arena team stats to players
737 // this way all arena team members will get notified, not only the ones who participated in this match
738 winner_arena_team->NotifyStatsChanged();
739 loser_arena_team->NotifyStatsChanged();
742 if (winmsg_id)
743 SendMessageToAll(winmsg_id, CHAT_MSG_BG_SYSTEM_NEUTRAL);
746 uint32 BattleGround::GetBonusHonorFromKill(uint32 kills) const
748 //variable kills means how many honorable kills you scored (so we need kills * honor_for_one_kill)
749 return MaNGOS::Honor::hk_honor_at_level(GetMaxLevel(), kills);
752 uint32 BattleGround::GetBattlemasterEntry() const
754 switch(GetTypeID())
756 case BATTLEGROUND_AV: return 15972;
757 case BATTLEGROUND_WS: return 14623;
758 case BATTLEGROUND_AB: return 14879;
759 case BATTLEGROUND_EY: return 22516;
760 case BATTLEGROUND_NA: return 20200;
761 default: return 0;
765 void BattleGround::RewardMark(Player *plr,uint32 count)
767 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
768 if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
769 return;
771 BattleGroundMarks mark;
772 bool IsSpell;
773 switch(GetTypeID())
775 case BATTLEGROUND_AV:
776 IsSpell = true;
777 if (count == ITEM_WINNER_COUNT)
778 mark = SPELL_AV_MARK_WINNER;
779 else
780 mark = SPELL_AV_MARK_LOSER;
781 break;
782 case BATTLEGROUND_WS:
783 IsSpell = true;
784 if (count == ITEM_WINNER_COUNT)
785 mark = SPELL_WS_MARK_WINNER;
786 else
787 mark = SPELL_WS_MARK_LOSER;
788 break;
789 case BATTLEGROUND_AB:
790 IsSpell = true;
791 if (count == ITEM_WINNER_COUNT)
792 mark = SPELL_AB_MARK_WINNER;
793 else
794 mark = SPELL_AB_MARK_LOSER;
795 break;
796 case BATTLEGROUND_EY:
797 IsSpell = false;
798 mark = ITEM_EY_MARK_OF_HONOR;
799 break;
800 default:
801 return;
804 if (IsSpell)
805 plr->CastSpell(plr, mark, true);
806 else if (objmgr.GetItemPrototype( mark ) )
808 ItemPosCountVec dest;
809 uint32 no_space_count = 0;
810 uint8 msg = plr->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, mark, count, &no_space_count );
811 if( msg != EQUIP_ERR_OK ) // convert to possible store amount
812 count -= no_space_count;
814 if( count != 0 && !dest.empty()) // can add some
815 if (Item* item = plr->StoreNewItem( dest, mark, true, 0))
816 plr->SendNewItem(item,count,false,true);
818 if (no_space_count > 0)
819 SendRewardMarkByMail(plr,mark,no_space_count);
823 void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count)
825 uint32 bmEntry = GetBattlemasterEntry();
826 if (!bmEntry)
827 return;
829 ItemPrototype const* markProto = objmgr.GetItemPrototype(mark);
830 if (!markProto)
831 return;
833 if (Item* markItem = Item::CreateItem(mark,count,plr))
835 // save new item before send
836 markItem->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
838 // item
839 MailItemsInfo mi;
840 mi.AddItem(markItem->GetGUIDLow(), markItem->GetEntry(), markItem);
842 // subject: item name
843 std::string subject = markProto->Name1;
844 int loc_idx = plr->GetSession()->GetSessionDbLocaleIndex();
845 if (loc_idx >= 0 )
846 if (ItemLocale const *il = objmgr.GetItemLocale(markProto->ItemId))
847 if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty())
848 subject = il->Name[loc_idx];
850 // text
851 std::string textFormat = plr->GetSession()->GetMangosString(LANG_BG_MARK_BY_MAIL);
852 char textBuf[300];
853 snprintf(textBuf,300,textFormat.c_str(),GetName(),GetName());
854 uint32 itemTextId = objmgr.CreateItemText( textBuf );
856 WorldSession::SendMailTo(plr, MAIL_CREATURE, MAIL_STATIONERY_NORMAL, bmEntry, plr->GetGUIDLow(), subject, itemTextId , &mi, 0, 0, MAIL_CHECK_MASK_NONE);
860 void BattleGround::RewardQuest(Player *plr)
862 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
863 if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
864 return;
866 uint32 quest;
867 switch(GetTypeID())
869 case BATTLEGROUND_AV:
870 quest = SPELL_AV_QUEST_REWARD;
871 break;
872 case BATTLEGROUND_WS:
873 quest = SPELL_WS_QUEST_REWARD;
874 break;
875 case BATTLEGROUND_AB:
876 quest = SPELL_AB_QUEST_REWARD;
877 break;
878 case BATTLEGROUND_EY:
879 quest = SPELL_EY_QUEST_REWARD;
880 break;
881 default:
882 return;
885 plr->CastSpell(plr, quest, true);
888 void BattleGround::BlockMovement(Player *plr)
890 plr->SetClientControl(plr, 0); // movement disabled NOTE: the effect will be automatically removed by client when the player is teleported from the battleground, so no need to send with uint8(1) in RemovePlayerAtLeave()
893 void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket)
895 uint32 team = GetPlayerTeam(guid);
896 bool participant = false;
897 // Remove from lists/maps
898 BattleGroundPlayerMap::iterator itr = m_Players.find(guid);
899 if (itr != m_Players.end())
901 UpdatePlayersCountByTeam(team, true); // -1 player
902 m_Players.erase(itr);
903 // check if the player was a participant of the match, or only entered through gm command (goname)
904 participant = true;
907 std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid);
908 if (itr2 != m_PlayerScores.end())
910 delete itr2->second; // delete player's score
911 m_PlayerScores.erase(itr2);
914 RemovePlayerFromResurrectQueue(guid);
916 Player *plr = objmgr.GetPlayer(guid);
918 // should remove spirit of redemption
919 if (plr && plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
920 plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
922 if(plr && !plr->isAlive()) // resurrect on exit
924 plr->ResurrectPlayer(1.0f);
925 plr->SpawnCorpseBones();
928 RemovePlayer(plr, guid); // BG subclass specific code
930 if(participant) // if the player was a match participant, remove auras, calc rating, update queue
932 BattleGroundTypeId bgTypeId = GetTypeID();
933 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
934 if (plr)
936 plr->ClearAfkReports();
938 if(!team) team = plr->GetTeam();
940 // if arena, remove the specific arena auras
941 if (isArena())
943 plr->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out
944 bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing)
946 // unsummon current and summon old pet if there was one and there isn't a current pet
947 plr->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT);
948 plr->ResummonPetTemporaryUnSummonedIfAny();
950 if (isRated() && GetStatus() == STATUS_IN_PROGRESS)
952 //left a rated match while the encounter was in progress, consider as loser
953 ArenaTeam * winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team)));
954 ArenaTeam * loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(team));
955 if (winner_arena_team && loser_arena_team)
956 loser_arena_team->MemberLost(plr,winner_arena_team->GetRating());
959 if (SendPacket)
961 WorldPacket data;
962 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0, 0);
963 plr->GetSession()->SendPacket(&data);
966 // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
967 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
969 else
970 // removing offline participant
972 if (isRated() && GetStatus() == STATUS_IN_PROGRESS)
974 //left a rated match while the encounter was in progress, consider as loser
975 ArenaTeam * others_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team)));
976 ArenaTeam * players_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(team));
977 if (others_arena_team && players_arena_team)
978 players_arena_team->OfflineMemberLost(guid, others_arena_team->GetRating());
982 // remove from raid group if player is member
983 if (Group *group = GetBgRaid(team))
985 if( !group->RemoveMember(guid, 0) ) // group was disbanded
987 SetBgRaid(team, NULL);
988 delete group;
991 DecreaseInvitedCount(team);
992 //we should update battleground queue, but only if bg isn't ending
993 if (isBattleGround() && GetStatus() < STATUS_WAIT_LEAVE)
994 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueId());
995 // Let others know
996 WorldPacket data;
997 sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, guid);
998 SendPacketToTeam(team, &data, plr, false);
1001 if (plr)
1003 // Do next only if found in battleground
1004 plr->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG.
1005 // reset destination bg team
1006 plr->SetBGTeam(0);
1008 if (Transport)
1009 plr->TeleportTo(plr->GetBattleGroundEntryPoint());
1011 sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName());
1014 if (!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
1016 // if no players left AND no invitees left, set this bg to delete in next update
1017 // direct deletion could cause crashes
1018 m_SetDeleteThis = true;
1019 // return to prevent addition to freeslotqueue
1020 return;
1023 // a player exited the battleground, so there are free slots. add to queue
1024 this->AddToBGFreeSlotQueue();
1027 // this method is called when no players remains in battleground
1028 void BattleGround::Reset()
1030 SetQueueId(QUEUE_ID_MAX_LEVEL_19);
1031 SetWinner(WINNER_NONE);
1032 SetStatus(STATUS_WAIT_QUEUE);
1033 SetStartTime(0);
1034 SetEndTime(0);
1035 SetLastResurrectTime(0);
1036 SetArenaType(0);
1037 SetRated(false);
1039 m_Events = 0;
1041 if (m_InvitedAlliance > 0 || m_InvitedHorde > 0)
1042 sLog.outError("BattleGround system: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance, m_InvitedHorde);
1044 m_InvitedAlliance = 0;
1045 m_InvitedHorde = 0;
1046 m_InBGFreeSlotQueue = false;
1048 m_Players.clear();
1049 m_PlayerScores.clear();
1052 void BattleGround::StartBattleGround()
1054 ///this method should spawn spirit guides and so on
1055 SetStartTime(0);
1057 SetLastResurrectTime(0);
1060 void BattleGround::AddPlayer(Player *plr)
1062 // score struct must be created in inherited class
1064 uint64 guid = plr->GetGUID();
1065 uint32 team = plr->GetBGTeam();
1067 BattleGroundPlayer bp;
1068 bp.OfflineRemoveTime = 0;
1069 bp.Team = team;
1071 // Add to list/maps
1072 m_Players[guid] = bp;
1074 UpdatePlayersCountByTeam(team, false); // +1 player
1076 WorldPacket data;
1077 sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr);
1078 SendPacketToTeam(team, &data, plr, false);
1080 // add arena specific auras
1081 if (isArena())
1083 plr->RemoveArenaSpellCooldowns();
1084 plr->RemoveArenaAuras();
1085 plr->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT);
1086 if(team == ALLIANCE) // gold
1088 if (plr->GetTeam() == HORDE)
1089 plr->CastSpell(plr, SPELL_HORDE_GOLD_FLAG,true);
1090 else
1091 plr->CastSpell(plr, SPELL_ALLIANCE_GOLD_FLAG,true);
1093 else // green
1095 if (plr->GetTeam() == HORDE)
1096 plr->CastSpell(plr, SPELL_HORDE_GREEN_FLAG,true);
1097 else
1098 plr->CastSpell(plr, SPELL_ALLIANCE_GREEN_FLAG,true);
1101 plr->DestroyConjuredItems(true);
1102 plr->UnsummonPetTemporaryIfAny();
1104 if(GetStatus() == STATUS_WAIT_JOIN) // not started yet
1106 plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);
1108 plr->SetHealth(plr->GetMaxHealth());
1109 plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA));
1112 else
1114 if(GetStatus() == STATUS_WAIT_JOIN) // not started yet
1115 plr->CastSpell(plr, SPELL_PREPARATION, true); // reduces all mana cost of spells.
1118 plr->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, ACHIEVEMENT_CRITERIA_CONDITION_MAP, GetMapId());
1119 plr->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, ACHIEVEMENT_CRITERIA_CONDITION_MAP, GetMapId());
1121 // setup BG group membership
1122 PlayerAddedToBGCheckIfBGIsRunning(plr);
1123 AddOrSetPlayerToCorrectBgGroup(plr, guid, team);
1125 // Log
1126 sLog.outDetail("BATTLEGROUND: Player %s joined the battle.", plr->GetName());
1129 /* this method adds player to his team's bg group, or sets his correct group if player is already in bg group */
1130 void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid, uint32 team)
1132 Group* group = GetBgRaid(team);
1133 if(!group) // first player joined
1135 group = new Group;
1136 SetBgRaid(team, group);
1137 group->Create(plr_guid, plr->GetName());
1139 else // raid already exist
1141 if (group->IsMember(plr_guid))
1143 uint8 subgroup = group->GetMemberGroup(plr_guid);
1144 plr->SetBattleGroundRaid(group, subgroup);
1146 else
1148 group->AddMember(plr_guid, plr->GetName());
1149 if (Group* originalGroup = plr->GetOriginalGroup())
1150 if (originalGroup->IsLeader(plr_guid))
1151 group->ChangeLeader(plr_guid);
1156 // This method should be called when player logs into running battleground
1157 void BattleGround::EventPlayerLoggedIn(Player* player, uint64 plr_guid)
1159 // player is correct pointer
1160 for(std::deque<uint64>::iterator itr = m_OfflineQueue.begin(); itr != m_OfflineQueue.end(); ++itr)
1162 if (*itr == plr_guid)
1164 m_OfflineQueue.erase(itr);
1165 break;
1168 m_Players[plr_guid].OfflineRemoveTime = 0;
1169 PlayerAddedToBGCheckIfBGIsRunning(player);
1170 // if battleground is starting, then add preparation aura
1171 // we don't have to do that, because preparation aura isn't removed when player logs out
1174 // This method should be called when player logs out from running battleground
1175 void BattleGround::EventPlayerLoggedOut(Player* player)
1177 // player is correct pointer, it is checked in WorldSession::LogoutPlayer()
1178 m_OfflineQueue.push_back(player->GetGUID());
1179 m_Players[player->GetGUID()].OfflineRemoveTime = sWorld.GetGameTime() + MAX_OFFLINE_TIME;
1180 if (GetStatus() == STATUS_IN_PROGRESS)
1182 if (isBattleGround())
1183 EventPlayerDroppedFlag(player);
1184 else
1186 //1 player is logging out, if it is the last, then end arena!
1187 if (GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam())))
1188 EndBattleGround(GetOtherTeam(player->GetTeam()));
1193 /* This method should be called only once ... it adds pointer to queue */
1194 void BattleGround::AddToBGFreeSlotQueue()
1196 // make sure to add only once
1197 if (!m_InBGFreeSlotQueue && isBattleGround())
1199 sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);
1200 m_InBGFreeSlotQueue = true;
1204 /* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
1205 void BattleGround::RemoveFromBGFreeSlotQueue()
1207 // set to be able to re-add if needed
1208 m_InBGFreeSlotQueue = false;
1209 // uncomment this code when battlegrounds will work like instances
1210 for (BGFreeSlotQueueType::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)
1212 if ((*itr)->GetInstanceID() == m_InstanceID)
1214 sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr);
1215 return;
1220 // get the number of free slots for team
1221 // returns the number how many players can join battleground to MaxPlayersPerTeam
1222 uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const
1224 //return free slot count to MaxPlayerPerTeam
1225 if (GetStatus() == STATUS_WAIT_JOIN || GetStatus() == STATUS_IN_PROGRESS)
1226 return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
1228 return 0;
1231 bool BattleGround::HasFreeSlots() const
1233 return GetPlayersSize() < GetMaxPlayers();
1236 void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
1238 //this procedure is called from virtual function implemented in bg subclass
1239 std::map<uint64, BattleGroundScore*>::const_iterator itr = m_PlayerScores.find(Source->GetGUID());
1241 if(itr == m_PlayerScores.end()) // player not found...
1242 return;
1244 switch(type)
1246 case SCORE_KILLING_BLOWS: // Killing blows
1247 itr->second->KillingBlows += value;
1248 break;
1249 case SCORE_DEATHS: // Deaths
1250 itr->second->Deaths += value;
1251 break;
1252 case SCORE_HONORABLE_KILLS: // Honorable kills
1253 itr->second->HonorableKills += value;
1254 break;
1255 case SCORE_BONUS_HONOR: // Honor bonus
1256 // do not add honor in arenas
1257 if (isBattleGround())
1259 // reward honor instantly
1260 if (Source->RewardHonor(NULL, 1, value))
1261 itr->second->BonusHonor += value;
1263 break;
1264 //used only in EY, but in MSG_PVP_LOG_DATA opcode
1265 case SCORE_DAMAGE_DONE: // Damage Done
1266 itr->second->DamageDone += value;
1267 break;
1268 case SCORE_HEALING_DONE: // Healing Done
1269 itr->second->HealingDone += value;
1270 break;
1271 default:
1272 sLog.outError("BattleGround: Unknown player score type %u", type);
1273 break;
1277 void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid)
1279 m_ReviveQueue[npc_guid].push_back(player_guid);
1281 Player *plr = objmgr.GetPlayer(player_guid);
1282 if (!plr)
1283 return;
1285 plr->CastSpell(plr, SPELL_WAITING_FOR_RESURRECT, true);
1286 SpellEntry const *spellInfo = sSpellStore.LookupEntry( SPELL_WAITING_FOR_RESURRECT );
1287 if (spellInfo)
1289 Aura *Aur = CreateAura(spellInfo, 0, NULL, plr);
1290 plr->AddAura(Aur);
1294 void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid)
1296 for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
1298 for(std::vector<uint64>::iterator itr2 =(itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
1300 if (*itr2 == player_guid)
1302 (itr->second).erase(itr2);
1304 Player *plr = objmgr.GetPlayer(player_guid);
1305 if (!plr)
1306 return;
1308 plr->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
1310 return;
1316 bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime)
1318 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1319 if (!map)
1320 return false;
1322 // must be created this way, adding to godatamap would add it to the base map of the instance
1323 // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
1324 // so we must create it specific for this instance
1325 GameObject * go = new GameObject;
1326 if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, map,
1327 PHASEMASK_NORMAL, x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,GO_STATE_READY))
1329 sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);
1330 sLog.outError("Cannot create gameobject template %u! BattleGround not created!", entry);
1331 delete go;
1332 return false;
1335 uint32 guid = go->GetGUIDLow();
1337 // without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
1338 // iirc that was changed, so adding to go data map is no longer required if that was the only function using godata from GameObject without checking if it existed
1339 GameObjectData& data = objmgr.NewGOData(guid);
1341 data.id = entry;
1342 data.mapid = GetMapId();
1343 data.posX = x;
1344 data.posY = y;
1345 data.posZ = z;
1346 data.orientation = o;
1347 data.rotation0 = rotation0;
1348 data.rotation1 = rotation1;
1349 data.rotation2 = rotation2;
1350 data.rotation3 = rotation3;
1351 data.spawntimesecs = respawnTime;
1352 data.spawnMask = 1;
1353 data.animprogress = 100;
1354 data.go_state = 1;
1356 // add to world, so it can be later looked up from HashMapHolder
1357 go->AddToWorld();
1358 m_BgObjects[type] = go->GetGUID();
1359 return true;
1362 //some doors aren't despawned so we cannot handle their closing in gameobject::update()
1363 //it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
1364 void BattleGround::DoorClose(uint32 type)
1366 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1367 if (obj)
1369 //if doors are open, close it
1370 if (obj->getLootState() == GO_ACTIVATED && obj->GetGoState() != GO_STATE_READY)
1372 //change state to allow door to be closed
1373 obj->SetLootState(GO_READY);
1374 obj->UseDoorOrButton(RESPAWN_ONE_DAY);
1377 else
1379 sLog.outError("BattleGround: Door object not found (cannot close doors)");
1383 void BattleGround::DoorOpen(uint32 type)
1385 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1386 if (obj)
1388 //change state to be sure they will be opened
1389 obj->SetLootState(GO_READY);
1390 obj->UseDoorOrButton(RESPAWN_ONE_DAY);
1392 else
1394 sLog.outError("BattleGround: Door object not found! - doors will be closed.");
1398 void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
1400 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1401 if (!map)
1402 return;
1403 if (respawntime == 0)
1405 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1406 if (obj)
1408 //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
1409 if (obj->getLootState() == GO_JUST_DEACTIVATED)
1410 obj->SetLootState(GO_READY);
1411 obj->SetRespawnTime(0);
1412 map->Add(obj);
1415 else
1417 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1418 if (obj)
1420 map->Add(obj);
1421 obj->SetRespawnTime(respawntime);
1422 obj->SetLootState(GO_JUST_DEACTIVATED);
1427 Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime)
1429 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1430 if (!map)
1431 return NULL;
1433 Creature* pCreature = new Creature;
1434 if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, PHASEMASK_NORMAL, entry, teamval))
1436 sLog.outError("Can't create creature entry: %u",entry);
1437 delete pCreature;
1438 return NULL;
1441 pCreature->Relocate(x, y, z, o);
1443 if (!pCreature->IsPositionValid())
1445 sLog.outError("Creature (guidlow %d, entry %d) not added to battleground. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
1446 return NULL;
1449 pCreature->AIM_Initialize();
1451 //pCreature->SetDungeonDifficulty(0);
1453 map->Add(pCreature);
1454 m_BgCreatures[type] = pCreature->GetGUID();
1456 return pCreature;
1459 void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)
1461 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceId());
1462 if (!map)
1463 return false;
1465 if (respawntime == 0)
1467 Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1468 if (obj)
1470 //obj->Respawn(); // bugged
1471 obj->SetRespawnTime(0);
1472 objmgr.SaveCreatureRespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);
1473 map->Add(obj);
1476 else
1478 Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1479 if (obj)
1481 obj->setDeathState(DEAD);
1482 obj->SetRespawnTime(respawntime);
1483 map->Add(obj);
1488 bool BattleGround::DelCreature(uint32 type)
1490 if (!m_BgCreatures[type])
1491 return true;
1493 Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1494 if (!cr)
1496 sLog.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures[type]));
1497 return false;
1499 cr->CleanupsBeforeDelete();
1500 cr->AddObjectToRemoveList();
1501 m_BgCreatures[type] = 0;
1502 return true;
1505 bool BattleGround::DelObject(uint32 type)
1507 if (!m_BgObjects[type])
1508 return true;
1510 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1511 if (!obj)
1513 sLog.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects[type]));
1514 return false;
1516 obj->SetRespawnTime(0); // not save respawn time
1517 obj->Delete();
1518 m_BgObjects[type] = 0;
1519 return true;
1522 bool BattleGround::AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team)
1524 uint32 entry = 0;
1526 if (team == ALLIANCE)
1527 entry = 13116;
1528 else
1529 entry = 13117;
1531 Creature* pCreature = AddCreature(entry,type,team,x,y,z,o);
1532 if (!pCreature)
1534 sLog.outError("Can't create Spirit guide. BattleGround not created!");
1535 EndNow();
1536 return false;
1539 pCreature->setDeathState(DEAD);
1541 pCreature->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, pCreature->GetGUID());
1542 // aura
1543 pCreature->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL);
1544 //pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
1545 //pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
1546 //pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
1547 // casting visual effect
1548 pCreature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_SPIRIT_HEAL_CHANNEL);
1549 // correct cast speed
1550 pCreature->SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
1552 //pCreature->CastSpell(pCreature, SPELL_SPIRIT_HEAL_CHANNEL, true);
1554 return true;
1557 void BattleGround::SendMessageToAll(int32 entry, ChatMsg type, Player const* source)
1559 MaNGOS::BattleGroundChatBuilder bg_builder(type, entry, source);
1560 MaNGOS::LocalizedPacketDo<MaNGOS::BattleGroundChatBuilder> bg_do(bg_builder);
1561 BroadcastWorker(bg_do);
1564 void BattleGround::PSendMessageToAll(int32 entry, ChatMsg type, Player const* source, ...)
1566 va_list ap;
1567 va_start(ap, source);
1569 MaNGOS::BattleGroundChatBuilder bg_builder(type, entry, source, &ap);
1570 MaNGOS::LocalizedPacketDo<MaNGOS::BattleGroundChatBuilder> bg_do(bg_builder);
1571 BroadcastWorker(bg_do);
1573 va_end(ap);
1576 void BattleGround::SendMessage2ToAll(int32 entry, ChatMsg type, Player const* source, int32 arg1, int32 arg2)
1578 MaNGOS::BattleGround2ChatBuilder bg_builder(type, entry, source, arg1, arg2);
1579 MaNGOS::LocalizedPacketDo<MaNGOS::BattleGround2ChatBuilder> bg_do(bg_builder);
1580 BroadcastWorker(bg_do);
1583 void BattleGround::EndNow()
1585 RemoveFromBGFreeSlotQueue();
1586 SetStatus(STATUS_WAIT_LEAVE);
1587 SetEndTime(0);
1591 important notice:
1592 buffs aren't spawned/despawned when players captures anything
1593 buffs are in their positions when battleground starts
1595 void BattleGround::HandleTriggerBuff(uint64 const& go_guid)
1597 GameObject *obj = HashMapHolder<GameObject>::Find(go_guid);
1598 if (!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned())
1599 return;
1601 //change buff type, when buff is used:
1602 int32 index = m_BgObjects.size() - 1;
1603 while (index >= 0 && m_BgObjects[index] != go_guid)
1604 index--;
1605 if (index < 0)
1607 sLog.outError("BattleGround (Type: %u) has buff gameobject (Guid: %u Entry: %u Type:%u) but it hasn't that object in its internal data",GetTypeID(),GUID_LOPART(go_guid),obj->GetEntry(),obj->GetGoType());
1608 return;
1611 //randomly select new buff
1612 uint8 buff = urand(0, 2);
1613 uint32 entry = obj->GetEntry();
1614 if (m_BuffChange && entry != Buff_Entries[buff])
1616 //despawn current buff
1617 SpawnBGObject(index, RESPAWN_ONE_DAY);
1618 //set index for new one
1619 for (uint8 currBuffTypeIndex = 0; currBuffTypeIndex < 3; ++currBuffTypeIndex)
1620 if (entry == Buff_Entries[currBuffTypeIndex])
1622 index -= currBuffTypeIndex;
1623 index += buff;
1627 SpawnBGObject(index, BUFF_RESPAWN_TIME);
1630 void BattleGround::HandleKillPlayer( Player *player, Player *killer )
1632 //keep in mind that for arena this will have to be changed a bit
1634 // add +1 deaths
1635 UpdatePlayerScore(player, SCORE_DEATHS, 1);
1637 // add +1 kills to group and +1 killing_blows to killer
1638 if (killer)
1640 UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);
1641 UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1);
1643 for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1645 Player *plr = objmgr.GetPlayer(itr->first);
1647 if (!plr || plr == killer)
1648 continue;
1650 if (plr->GetTeam() == killer->GetTeam() && plr->IsAtGroupRewardDistance(player))
1651 UpdatePlayerScore(plr, SCORE_HONORABLE_KILLS, 1);
1655 // to be able to remove insignia -- ONLY IN BattleGrounds
1656 if (!isArena())
1657 player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
1660 // return the player's team based on battlegroundplayer info
1661 // used in same faction arena matches mainly
1662 uint32 BattleGround::GetPlayerTeam(uint64 guid)
1664 BattleGroundPlayerMap::const_iterator itr = m_Players.find(guid);
1665 if (itr!=m_Players.end())
1666 return itr->second.Team;
1667 return 0;
1670 uint32 BattleGround::GetOtherTeam(uint32 teamId)
1672 return (teamId) ? ((teamId == ALLIANCE) ? HORDE : ALLIANCE) : 0;
1675 bool BattleGround::IsPlayerInBattleGround(uint64 guid)
1677 BattleGroundPlayerMap::const_iterator itr = m_Players.find(guid);
1678 if (itr != m_Players.end())
1679 return true;
1680 return false;
1683 void BattleGround::PlayerAddedToBGCheckIfBGIsRunning(Player* plr)
1685 if (GetStatus() != STATUS_WAIT_LEAVE)
1686 return;
1688 WorldPacket data;
1689 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
1691 BlockMovement(plr);
1693 sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
1694 plr->GetSession()->SendPacket(&data);
1696 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType());
1697 plr->GetSession()->SendPacket(&data);
1700 uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const
1702 int count = 0;
1703 for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1705 if (itr->second.Team == Team)
1707 Player * pl = objmgr.GetPlayer(itr->first);
1708 if (pl && pl->isAlive())
1709 ++count;
1712 return count;
1715 void BattleGround::CheckArenaWinConditions()
1717 if (!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
1718 EndBattleGround(HORDE);
1719 else if (GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))
1720 EndBattleGround(ALLIANCE);
1723 void BattleGround::SetBgRaid( uint32 TeamID, Group *bg_raid )
1725 Group* &old_raid = TeamID == ALLIANCE ? m_BgRaids[BG_TEAM_ALLIANCE] : m_BgRaids[BG_TEAM_HORDE];
1726 if(old_raid) old_raid->SetBattlegroundGroup(NULL);
1727 if(bg_raid) bg_raid->SetBattlegroundGroup(this);
1728 old_raid = bg_raid;
1731 WorldSafeLocsEntry const* BattleGround::GetClosestGraveYard( Player* player )
1733 return objmgr.GetClosestGraveYard( player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetMapId(), player->GetTeam() );