[7915] Implement more stricted checks and limitations at loading creature addon data.
[getmangos.git] / src / game / BattleGround.cpp
blobe2c5137000f48e4303fae47f52b4546f4cc1ef53
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 RewardQuestComplete(plr);
710 else
711 RewardMark(plr,ITEM_LOSER_COUNT);
713 plr->CombatStopWithPets(true);
715 BlockMovement(plr);
717 sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
718 plr->GetSession()->SendPacket(&data);
720 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
721 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType());
722 plr->GetSession()->SendPacket(&data);
723 plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1);
726 if (isArena() && isRated() && winner_arena_team && loser_arena_team)
728 // update arena points only after increasing the player's match count!
729 //obsolete: winner_arena_team->UpdateArenaPointsHelper();
730 //obsolete: loser_arena_team->UpdateArenaPointsHelper();
731 // save the stat changes
732 winner_arena_team->SaveToDB();
733 loser_arena_team->SaveToDB();
734 // send updated arena team stats to players
735 // this way all arena team members will get notified, not only the ones who participated in this match
736 winner_arena_team->NotifyStatsChanged();
737 loser_arena_team->NotifyStatsChanged();
740 if (winmsg_id)
741 SendMessageToAll(winmsg_id, CHAT_MSG_BG_SYSTEM_NEUTRAL);
744 uint32 BattleGround::GetBonusHonorFromKill(uint32 kills) const
746 //variable kills means how many honorable kills you scored (so we need kills * honor_for_one_kill)
747 return MaNGOS::Honor::hk_honor_at_level(GetMaxLevel(), kills);
750 uint32 BattleGround::GetBattlemasterEntry() const
752 switch(GetTypeID())
754 case BATTLEGROUND_AV: return 15972;
755 case BATTLEGROUND_WS: return 14623;
756 case BATTLEGROUND_AB: return 14879;
757 case BATTLEGROUND_EY: return 22516;
758 case BATTLEGROUND_NA: return 20200;
759 default: return 0;
763 void BattleGround::RewardMark(Player *plr,uint32 count)
765 BattleGroundMarks mark;
766 bool IsSpell;
767 switch(GetTypeID())
769 case BATTLEGROUND_AV:
770 IsSpell = true;
771 if (count == ITEM_WINNER_COUNT)
772 mark = SPELL_AV_MARK_WINNER;
773 else
774 mark = SPELL_AV_MARK_LOSER;
775 break;
776 case BATTLEGROUND_WS:
777 IsSpell = true;
778 if (count == ITEM_WINNER_COUNT)
779 mark = SPELL_WS_MARK_WINNER;
780 else
781 mark = SPELL_WS_MARK_LOSER;
782 break;
783 case BATTLEGROUND_AB:
784 IsSpell = true;
785 if (count == ITEM_WINNER_COUNT)
786 mark = SPELL_AB_MARK_WINNER;
787 else
788 mark = SPELL_AB_MARK_LOSER;
789 break;
790 case BATTLEGROUND_EY:
791 IsSpell = false;
792 mark = ITEM_EY_MARK_OF_HONOR;
793 break;
794 default:
795 return;
798 if (IsSpell)
799 RewardSpellCast(plr,mark);
800 else
801 RewardItem(plr,mark,count);
804 void BattleGround::RewardSpellCast(Player *plr, uint32 spell_id)
806 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
807 if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
808 return;
810 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
811 if(!spellInfo)
813 sLog.outError("Battleground reward casting spell %u not exist.",spell_id);
814 return;
817 plr->CastSpell(plr, spellInfo, true);
820 void BattleGround::RewardItem(Player *plr, uint32 item_id, uint32 count)
822 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
823 if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
824 return;
826 ItemPosCountVec dest;
827 uint32 no_space_count = 0;
828 uint8 msg = plr->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item_id, count, &no_space_count );
830 if( msg == EQUIP_ERR_ITEM_NOT_FOUND)
832 sLog.outErrorDb("Battleground reward item (Entry %u) not exist in `item_template`.",item_id);
833 return;
836 if( msg != EQUIP_ERR_OK ) // convert to possible store amount
837 count -= no_space_count;
839 if( count != 0 && !dest.empty()) // can add some
840 if (Item* item = plr->StoreNewItem( dest, item_id, true, 0))
841 plr->SendNewItem(item,count,false,true);
843 if (no_space_count > 0)
844 SendRewardMarkByMail(plr,item_id,no_space_count);
847 void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count)
849 uint32 bmEntry = GetBattlemasterEntry();
850 if (!bmEntry)
851 return;
853 ItemPrototype const* markProto = objmgr.GetItemPrototype(mark);
854 if (!markProto)
855 return;
857 if (Item* markItem = Item::CreateItem(mark,count,plr))
859 // save new item before send
860 markItem->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
862 // item
863 MailItemsInfo mi;
864 mi.AddItem(markItem->GetGUIDLow(), markItem->GetEntry(), markItem);
866 // subject: item name
867 std::string subject = markProto->Name1;
868 int loc_idx = plr->GetSession()->GetSessionDbLocaleIndex();
869 if (loc_idx >= 0 )
870 if (ItemLocale const *il = objmgr.GetItemLocale(markProto->ItemId))
871 if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty())
872 subject = il->Name[loc_idx];
874 // text
875 std::string textFormat = plr->GetSession()->GetMangosString(LANG_BG_MARK_BY_MAIL);
876 char textBuf[300];
877 snprintf(textBuf,300,textFormat.c_str(),GetName(),GetName());
878 uint32 itemTextId = objmgr.CreateItemText( textBuf );
880 WorldSession::SendMailTo(plr, MAIL_CREATURE, MAIL_STATIONERY_NORMAL, bmEntry, plr->GetGUIDLow(), subject, itemTextId , &mi, 0, 0, MAIL_CHECK_MASK_NONE);
884 void BattleGround::RewardQuestComplete(Player *plr)
886 uint32 quest;
887 switch(GetTypeID())
889 case BATTLEGROUND_AV:
890 quest = SPELL_AV_QUEST_REWARD;
891 break;
892 case BATTLEGROUND_WS:
893 quest = SPELL_WS_QUEST_REWARD;
894 break;
895 case BATTLEGROUND_AB:
896 quest = SPELL_AB_QUEST_REWARD;
897 break;
898 case BATTLEGROUND_EY:
899 quest = SPELL_EY_QUEST_REWARD;
900 break;
901 default:
902 return;
905 RewardSpellCast(plr, quest);
908 void BattleGround::BlockMovement(Player *plr)
910 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()
913 void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket)
915 uint32 team = GetPlayerTeam(guid);
916 bool participant = false;
917 // Remove from lists/maps
918 BattleGroundPlayerMap::iterator itr = m_Players.find(guid);
919 if (itr != m_Players.end())
921 UpdatePlayersCountByTeam(team, true); // -1 player
922 m_Players.erase(itr);
923 // check if the player was a participant of the match, or only entered through gm command (goname)
924 participant = true;
927 std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid);
928 if (itr2 != m_PlayerScores.end())
930 delete itr2->second; // delete player's score
931 m_PlayerScores.erase(itr2);
934 RemovePlayerFromResurrectQueue(guid);
936 Player *plr = objmgr.GetPlayer(guid);
938 // should remove spirit of redemption
939 if (plr && plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
940 plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
942 if(plr && !plr->isAlive()) // resurrect on exit
944 plr->ResurrectPlayer(1.0f);
945 plr->SpawnCorpseBones();
948 RemovePlayer(plr, guid); // BG subclass specific code
950 if(participant) // if the player was a match participant, remove auras, calc rating, update queue
952 BattleGroundTypeId bgTypeId = GetTypeID();
953 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
954 if (plr)
956 plr->ClearAfkReports();
958 if(!team) team = plr->GetTeam();
960 // if arena, remove the specific arena auras
961 if (isArena())
963 plr->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out
964 bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing)
966 // unsummon current and summon old pet if there was one and there isn't a current pet
967 plr->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT);
968 plr->ResummonPetTemporaryUnSummonedIfAny();
970 if (isRated() && GetStatus() == STATUS_IN_PROGRESS)
972 //left a rated match while the encounter was in progress, consider as loser
973 ArenaTeam * winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team)));
974 ArenaTeam * loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(team));
975 if (winner_arena_team && loser_arena_team)
976 loser_arena_team->MemberLost(plr,winner_arena_team->GetRating());
979 if (SendPacket)
981 WorldPacket data;
982 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0, 0);
983 plr->GetSession()->SendPacket(&data);
986 // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
987 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
989 else
990 // removing offline participant
992 if (isRated() && GetStatus() == STATUS_IN_PROGRESS)
994 //left a rated match while the encounter was in progress, consider as loser
995 ArenaTeam * others_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team)));
996 ArenaTeam * players_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(team));
997 if (others_arena_team && players_arena_team)
998 players_arena_team->OfflineMemberLost(guid, others_arena_team->GetRating());
1002 // remove from raid group if player is member
1003 if (Group *group = GetBgRaid(team))
1005 if( !group->RemoveMember(guid, 0) ) // group was disbanded
1007 SetBgRaid(team, NULL);
1008 delete group;
1011 DecreaseInvitedCount(team);
1012 //we should update battleground queue, but only if bg isn't ending
1013 if (isBattleGround() && GetStatus() < STATUS_WAIT_LEAVE)
1014 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueId());
1015 // Let others know
1016 WorldPacket data;
1017 sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, guid);
1018 SendPacketToTeam(team, &data, plr, false);
1021 if (plr)
1023 // Do next only if found in battleground
1024 plr->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG.
1025 // reset destination bg team
1026 plr->SetBGTeam(0);
1028 if (Transport)
1029 plr->TeleportTo(plr->GetBattleGroundEntryPoint());
1031 sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName());
1034 if (!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
1036 // if no players left AND no invitees left, set this bg to delete in next update
1037 // direct deletion could cause crashes
1038 m_SetDeleteThis = true;
1039 // return to prevent addition to freeslotqueue
1040 return;
1043 // a player exited the battleground, so there are free slots. add to queue
1044 this->AddToBGFreeSlotQueue();
1047 // this method is called when no players remains in battleground
1048 void BattleGround::Reset()
1050 SetQueueId(QUEUE_ID_MAX_LEVEL_19);
1051 SetWinner(WINNER_NONE);
1052 SetStatus(STATUS_WAIT_QUEUE);
1053 SetStartTime(0);
1054 SetEndTime(0);
1055 SetLastResurrectTime(0);
1056 SetArenaType(0);
1057 SetRated(false);
1059 m_Events = 0;
1061 if (m_InvitedAlliance > 0 || m_InvitedHorde > 0)
1062 sLog.outError("BattleGround system: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance, m_InvitedHorde);
1064 m_InvitedAlliance = 0;
1065 m_InvitedHorde = 0;
1066 m_InBGFreeSlotQueue = false;
1068 m_Players.clear();
1069 m_PlayerScores.clear();
1072 void BattleGround::StartBattleGround()
1074 ///this method should spawn spirit guides and so on
1075 SetStartTime(0);
1077 SetLastResurrectTime(0);
1080 void BattleGround::AddPlayer(Player *plr)
1082 // score struct must be created in inherited class
1084 uint64 guid = plr->GetGUID();
1085 uint32 team = plr->GetBGTeam();
1087 BattleGroundPlayer bp;
1088 bp.OfflineRemoveTime = 0;
1089 bp.Team = team;
1091 // Add to list/maps
1092 m_Players[guid] = bp;
1094 UpdatePlayersCountByTeam(team, false); // +1 player
1096 WorldPacket data;
1097 sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr);
1098 SendPacketToTeam(team, &data, plr, false);
1100 // add arena specific auras
1101 if (isArena())
1103 plr->RemoveArenaSpellCooldowns();
1104 plr->RemoveArenaAuras();
1105 plr->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT);
1106 if(team == ALLIANCE) // gold
1108 if (plr->GetTeam() == HORDE)
1109 plr->CastSpell(plr, SPELL_HORDE_GOLD_FLAG,true);
1110 else
1111 plr->CastSpell(plr, SPELL_ALLIANCE_GOLD_FLAG,true);
1113 else // green
1115 if (plr->GetTeam() == HORDE)
1116 plr->CastSpell(plr, SPELL_HORDE_GREEN_FLAG,true);
1117 else
1118 plr->CastSpell(plr, SPELL_ALLIANCE_GREEN_FLAG,true);
1121 plr->DestroyConjuredItems(true);
1122 plr->UnsummonPetTemporaryIfAny();
1124 if(GetStatus() == STATUS_WAIT_JOIN) // not started yet
1126 plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);
1128 plr->SetHealth(plr->GetMaxHealth());
1129 plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA));
1132 else
1134 if(GetStatus() == STATUS_WAIT_JOIN) // not started yet
1135 plr->CastSpell(plr, SPELL_PREPARATION, true); // reduces all mana cost of spells.
1138 plr->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, ACHIEVEMENT_CRITERIA_CONDITION_MAP, GetMapId());
1139 plr->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, ACHIEVEMENT_CRITERIA_CONDITION_MAP, GetMapId());
1141 // setup BG group membership
1142 PlayerAddedToBGCheckIfBGIsRunning(plr);
1143 AddOrSetPlayerToCorrectBgGroup(plr, guid, team);
1145 // Log
1146 sLog.outDetail("BATTLEGROUND: Player %s joined the battle.", plr->GetName());
1149 /* this method adds player to his team's bg group, or sets his correct group if player is already in bg group */
1150 void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid, uint32 team)
1152 Group* group = GetBgRaid(team);
1153 if(!group) // first player joined
1155 group = new Group;
1156 SetBgRaid(team, group);
1157 group->Create(plr_guid, plr->GetName());
1159 else // raid already exist
1161 if (group->IsMember(plr_guid))
1163 uint8 subgroup = group->GetMemberGroup(plr_guid);
1164 plr->SetBattleGroundRaid(group, subgroup);
1166 else
1168 group->AddMember(plr_guid, plr->GetName());
1169 if (Group* originalGroup = plr->GetOriginalGroup())
1170 if (originalGroup->IsLeader(plr_guid))
1171 group->ChangeLeader(plr_guid);
1176 // This method should be called when player logs into running battleground
1177 void BattleGround::EventPlayerLoggedIn(Player* player, uint64 plr_guid)
1179 // player is correct pointer
1180 for(std::deque<uint64>::iterator itr = m_OfflineQueue.begin(); itr != m_OfflineQueue.end(); ++itr)
1182 if (*itr == plr_guid)
1184 m_OfflineQueue.erase(itr);
1185 break;
1188 m_Players[plr_guid].OfflineRemoveTime = 0;
1189 PlayerAddedToBGCheckIfBGIsRunning(player);
1190 // if battleground is starting, then add preparation aura
1191 // we don't have to do that, because preparation aura isn't removed when player logs out
1194 // This method should be called when player logs out from running battleground
1195 void BattleGround::EventPlayerLoggedOut(Player* player)
1197 // player is correct pointer, it is checked in WorldSession::LogoutPlayer()
1198 m_OfflineQueue.push_back(player->GetGUID());
1199 m_Players[player->GetGUID()].OfflineRemoveTime = sWorld.GetGameTime() + MAX_OFFLINE_TIME;
1200 if (GetStatus() == STATUS_IN_PROGRESS)
1202 if (isBattleGround())
1203 EventPlayerDroppedFlag(player);
1204 else
1206 //1 player is logging out, if it is the last, then end arena!
1207 if (GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam())))
1208 EndBattleGround(GetOtherTeam(player->GetTeam()));
1213 /* This method should be called only once ... it adds pointer to queue */
1214 void BattleGround::AddToBGFreeSlotQueue()
1216 // make sure to add only once
1217 if (!m_InBGFreeSlotQueue && isBattleGround())
1219 sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);
1220 m_InBGFreeSlotQueue = true;
1224 /* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
1225 void BattleGround::RemoveFromBGFreeSlotQueue()
1227 // set to be able to re-add if needed
1228 m_InBGFreeSlotQueue = false;
1229 // uncomment this code when battlegrounds will work like instances
1230 for (BGFreeSlotQueueType::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)
1232 if ((*itr)->GetInstanceID() == m_InstanceID)
1234 sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr);
1235 return;
1240 // get the number of free slots for team
1241 // returns the number how many players can join battleground to MaxPlayersPerTeam
1242 uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const
1244 //return free slot count to MaxPlayerPerTeam
1245 if (GetStatus() == STATUS_WAIT_JOIN || GetStatus() == STATUS_IN_PROGRESS)
1246 return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
1248 return 0;
1251 bool BattleGround::HasFreeSlots() const
1253 return GetPlayersSize() < GetMaxPlayers();
1256 void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
1258 //this procedure is called from virtual function implemented in bg subclass
1259 std::map<uint64, BattleGroundScore*>::const_iterator itr = m_PlayerScores.find(Source->GetGUID());
1261 if(itr == m_PlayerScores.end()) // player not found...
1262 return;
1264 switch(type)
1266 case SCORE_KILLING_BLOWS: // Killing blows
1267 itr->second->KillingBlows += value;
1268 break;
1269 case SCORE_DEATHS: // Deaths
1270 itr->second->Deaths += value;
1271 break;
1272 case SCORE_HONORABLE_KILLS: // Honorable kills
1273 itr->second->HonorableKills += value;
1274 break;
1275 case SCORE_BONUS_HONOR: // Honor bonus
1276 // do not add honor in arenas
1277 if (isBattleGround())
1279 // reward honor instantly
1280 if (Source->RewardHonor(NULL, 1, value))
1281 itr->second->BonusHonor += value;
1283 break;
1284 //used only in EY, but in MSG_PVP_LOG_DATA opcode
1285 case SCORE_DAMAGE_DONE: // Damage Done
1286 itr->second->DamageDone += value;
1287 break;
1288 case SCORE_HEALING_DONE: // Healing Done
1289 itr->second->HealingDone += value;
1290 break;
1291 default:
1292 sLog.outError("BattleGround: Unknown player score type %u", type);
1293 break;
1297 void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid)
1299 m_ReviveQueue[npc_guid].push_back(player_guid);
1301 Player *plr = objmgr.GetPlayer(player_guid);
1302 if (!plr)
1303 return;
1305 plr->CastSpell(plr, SPELL_WAITING_FOR_RESURRECT, true);
1306 SpellEntry const *spellInfo = sSpellStore.LookupEntry( SPELL_WAITING_FOR_RESURRECT );
1307 if (spellInfo)
1309 Aura *Aur = CreateAura(spellInfo, 0, NULL, plr);
1310 plr->AddAura(Aur);
1314 void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid)
1316 for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
1318 for(std::vector<uint64>::iterator itr2 =(itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
1320 if (*itr2 == player_guid)
1322 (itr->second).erase(itr2);
1324 Player *plr = objmgr.GetPlayer(player_guid);
1325 if (!plr)
1326 return;
1328 plr->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
1330 return;
1336 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)
1338 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1339 if (!map)
1340 return false;
1342 // must be created this way, adding to godatamap would add it to the base map of the instance
1343 // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
1344 // so we must create it specific for this instance
1345 GameObject * go = new GameObject;
1346 if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, map,
1347 PHASEMASK_NORMAL, x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,GO_STATE_READY))
1349 sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);
1350 sLog.outError("Cannot create gameobject template %u! BattleGround not created!", entry);
1351 delete go;
1352 return false;
1355 uint32 guid = go->GetGUIDLow();
1357 // without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
1358 // 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
1359 GameObjectData& data = objmgr.NewGOData(guid);
1361 data.id = entry;
1362 data.mapid = GetMapId();
1363 data.posX = x;
1364 data.posY = y;
1365 data.posZ = z;
1366 data.orientation = o;
1367 data.rotation0 = rotation0;
1368 data.rotation1 = rotation1;
1369 data.rotation2 = rotation2;
1370 data.rotation3 = rotation3;
1371 data.spawntimesecs = respawnTime;
1372 data.spawnMask = 1;
1373 data.animprogress = 100;
1374 data.go_state = 1;
1376 // add to world, so it can be later looked up from HashMapHolder
1377 go->AddToWorld();
1378 m_BgObjects[type] = go->GetGUID();
1379 return true;
1382 //some doors aren't despawned so we cannot handle their closing in gameobject::update()
1383 //it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
1384 void BattleGround::DoorClose(uint32 type)
1386 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1387 if (obj)
1389 //if doors are open, close it
1390 if (obj->getLootState() == GO_ACTIVATED && obj->GetGoState() != GO_STATE_READY)
1392 //change state to allow door to be closed
1393 obj->SetLootState(GO_READY);
1394 obj->UseDoorOrButton(RESPAWN_ONE_DAY);
1397 else
1399 sLog.outError("BattleGround: Door object not found (cannot close doors)");
1403 void BattleGround::DoorOpen(uint32 type)
1405 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1406 if (obj)
1408 //change state to be sure they will be opened
1409 obj->SetLootState(GO_READY);
1410 obj->UseDoorOrButton(RESPAWN_ONE_DAY);
1412 else
1414 sLog.outError("BattleGround: Door object not found! - doors will be closed.");
1418 void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
1420 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1421 if (!map)
1422 return;
1423 if (respawntime == 0)
1425 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1426 if (obj)
1428 //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
1429 if (obj->getLootState() == GO_JUST_DEACTIVATED)
1430 obj->SetLootState(GO_READY);
1431 obj->SetRespawnTime(0);
1432 map->Add(obj);
1435 else
1437 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1438 if (obj)
1440 map->Add(obj);
1441 obj->SetRespawnTime(respawntime);
1442 obj->SetLootState(GO_JUST_DEACTIVATED);
1447 Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime)
1449 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1450 if (!map)
1451 return NULL;
1453 Creature* pCreature = new Creature;
1454 if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, PHASEMASK_NORMAL, entry, teamval))
1456 sLog.outError("Can't create creature entry: %u",entry);
1457 delete pCreature;
1458 return NULL;
1461 pCreature->Relocate(x, y, z, o);
1463 if (!pCreature->IsPositionValid())
1465 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());
1466 delete pCreature;
1467 return NULL;
1470 pCreature->AIM_Initialize();
1472 //pCreature->SetDungeonDifficulty(0);
1474 map->Add(pCreature);
1475 m_BgCreatures[type] = pCreature->GetGUID();
1477 return pCreature;
1480 void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)
1482 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceId());
1483 if (!map)
1484 return false;
1486 if (respawntime == 0)
1488 Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1489 if (obj)
1491 //obj->Respawn(); // bugged
1492 obj->SetRespawnTime(0);
1493 objmgr.SaveCreatureRespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);
1494 map->Add(obj);
1497 else
1499 Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1500 if (obj)
1502 obj->setDeathState(DEAD);
1503 obj->SetRespawnTime(respawntime);
1504 map->Add(obj);
1509 bool BattleGround::DelCreature(uint32 type)
1511 if (!m_BgCreatures[type])
1512 return true;
1514 Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1515 if (!cr)
1517 sLog.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures[type]));
1518 return false;
1520 cr->CleanupsBeforeDelete();
1521 cr->AddObjectToRemoveList();
1522 m_BgCreatures[type] = 0;
1523 return true;
1526 bool BattleGround::DelObject(uint32 type)
1528 if (!m_BgObjects[type])
1529 return true;
1531 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1532 if (!obj)
1534 sLog.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects[type]));
1535 return false;
1537 obj->SetRespawnTime(0); // not save respawn time
1538 obj->Delete();
1539 m_BgObjects[type] = 0;
1540 return true;
1543 bool BattleGround::AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team)
1545 uint32 entry = 0;
1547 if (team == ALLIANCE)
1548 entry = 13116;
1549 else
1550 entry = 13117;
1552 Creature* pCreature = AddCreature(entry,type,team,x,y,z,o);
1553 if (!pCreature)
1555 sLog.outError("Can't create Spirit guide. BattleGround not created!");
1556 EndNow();
1557 return false;
1560 pCreature->setDeathState(DEAD);
1562 pCreature->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, pCreature->GetGUID());
1563 // aura
1564 pCreature->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL);
1565 //pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
1566 //pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
1567 //pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
1568 // casting visual effect
1569 pCreature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_SPIRIT_HEAL_CHANNEL);
1570 // correct cast speed
1571 pCreature->SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
1573 //pCreature->CastSpell(pCreature, SPELL_SPIRIT_HEAL_CHANNEL, true);
1575 return true;
1578 void BattleGround::SendMessageToAll(int32 entry, ChatMsg type, Player const* source)
1580 MaNGOS::BattleGroundChatBuilder bg_builder(type, entry, source);
1581 MaNGOS::LocalizedPacketDo<MaNGOS::BattleGroundChatBuilder> bg_do(bg_builder);
1582 BroadcastWorker(bg_do);
1585 void BattleGround::PSendMessageToAll(int32 entry, ChatMsg type, Player const* source, ...)
1587 va_list ap;
1588 va_start(ap, source);
1590 MaNGOS::BattleGroundChatBuilder bg_builder(type, entry, source, &ap);
1591 MaNGOS::LocalizedPacketDo<MaNGOS::BattleGroundChatBuilder> bg_do(bg_builder);
1592 BroadcastWorker(bg_do);
1594 va_end(ap);
1597 void BattleGround::SendMessage2ToAll(int32 entry, ChatMsg type, Player const* source, int32 arg1, int32 arg2)
1599 MaNGOS::BattleGround2ChatBuilder bg_builder(type, entry, source, arg1, arg2);
1600 MaNGOS::LocalizedPacketDo<MaNGOS::BattleGround2ChatBuilder> bg_do(bg_builder);
1601 BroadcastWorker(bg_do);
1604 void BattleGround::EndNow()
1606 RemoveFromBGFreeSlotQueue();
1607 SetStatus(STATUS_WAIT_LEAVE);
1608 SetEndTime(0);
1612 important notice:
1613 buffs aren't spawned/despawned when players captures anything
1614 buffs are in their positions when battleground starts
1616 void BattleGround::HandleTriggerBuff(uint64 const& go_guid)
1618 GameObject *obj = HashMapHolder<GameObject>::Find(go_guid);
1619 if (!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned())
1620 return;
1622 //change buff type, when buff is used:
1623 int32 index = m_BgObjects.size() - 1;
1624 while (index >= 0 && m_BgObjects[index] != go_guid)
1625 index--;
1626 if (index < 0)
1628 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());
1629 return;
1632 //randomly select new buff
1633 uint8 buff = urand(0, 2);
1634 uint32 entry = obj->GetEntry();
1635 if (m_BuffChange && entry != Buff_Entries[buff])
1637 //despawn current buff
1638 SpawnBGObject(index, RESPAWN_ONE_DAY);
1639 //set index for new one
1640 for (uint8 currBuffTypeIndex = 0; currBuffTypeIndex < 3; ++currBuffTypeIndex)
1641 if (entry == Buff_Entries[currBuffTypeIndex])
1643 index -= currBuffTypeIndex;
1644 index += buff;
1648 SpawnBGObject(index, BUFF_RESPAWN_TIME);
1651 void BattleGround::HandleKillPlayer( Player *player, Player *killer )
1653 //keep in mind that for arena this will have to be changed a bit
1655 // add +1 deaths
1656 UpdatePlayerScore(player, SCORE_DEATHS, 1);
1658 // add +1 kills to group and +1 killing_blows to killer
1659 if (killer)
1661 UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);
1662 UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1);
1664 for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1666 Player *plr = objmgr.GetPlayer(itr->first);
1668 if (!plr || plr == killer)
1669 continue;
1671 if (plr->GetTeam() == killer->GetTeam() && plr->IsAtGroupRewardDistance(player))
1672 UpdatePlayerScore(plr, SCORE_HONORABLE_KILLS, 1);
1676 // to be able to remove insignia -- ONLY IN BattleGrounds
1677 if (!isArena())
1678 player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
1681 // return the player's team based on battlegroundplayer info
1682 // used in same faction arena matches mainly
1683 uint32 BattleGround::GetPlayerTeam(uint64 guid)
1685 BattleGroundPlayerMap::const_iterator itr = m_Players.find(guid);
1686 if (itr!=m_Players.end())
1687 return itr->second.Team;
1688 return 0;
1691 uint32 BattleGround::GetOtherTeam(uint32 teamId)
1693 return (teamId) ? ((teamId == ALLIANCE) ? HORDE : ALLIANCE) : 0;
1696 bool BattleGround::IsPlayerInBattleGround(uint64 guid)
1698 BattleGroundPlayerMap::const_iterator itr = m_Players.find(guid);
1699 if (itr != m_Players.end())
1700 return true;
1701 return false;
1704 void BattleGround::PlayerAddedToBGCheckIfBGIsRunning(Player* plr)
1706 if (GetStatus() != STATUS_WAIT_LEAVE)
1707 return;
1709 WorldPacket data;
1710 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
1712 BlockMovement(plr);
1714 sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
1715 plr->GetSession()->SendPacket(&data);
1717 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType());
1718 plr->GetSession()->SendPacket(&data);
1721 uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const
1723 int count = 0;
1724 for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1726 if (itr->second.Team == Team)
1728 Player * pl = objmgr.GetPlayer(itr->first);
1729 if (pl && pl->isAlive())
1730 ++count;
1733 return count;
1736 void BattleGround::CheckArenaWinConditions()
1738 if (!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
1739 EndBattleGround(HORDE);
1740 else if (GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))
1741 EndBattleGround(ALLIANCE);
1744 void BattleGround::SetBgRaid( uint32 TeamID, Group *bg_raid )
1746 Group* &old_raid = TeamID == ALLIANCE ? m_BgRaids[BG_TEAM_ALLIANCE] : m_BgRaids[BG_TEAM_HORDE];
1747 if(old_raid) old_raid->SetBattlegroundGroup(NULL);
1748 if(bg_raid) bg_raid->SetBattlegroundGroup(this);
1749 old_raid = bg_raid;
1752 WorldSafeLocsEntry const* BattleGround::GetClosestGraveYard( Player* player )
1754 return objmgr.GetClosestGraveYard( player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetMapId(), player->GetTeam() );