[7297] Fixed profession spells sorting in trainer spell list at client.
[getmangos.git] / src / game / BattleGround.cpp
blob1790df0e55ce280e82f7ee331580b24213da1120
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 "Chat.h"
27 #include "SpellAuras.h"
28 #include "ArenaTeam.h"
29 #include "World.h"
30 #include "Group.h"
31 #include "ObjectMgr.h"
32 #include "WorldPacket.h"
33 #include "Util.h"
35 BattleGround::BattleGround()
37 m_TypeID = BattleGroundTypeId(0);
38 m_InstanceID = 0;
39 m_Status = 0;
40 m_EndTime = 0;
41 m_LastResurrectTime = 0;
42 m_QueueId = MAX_BATTLEGROUND_QUEUES;
43 m_InvitedAlliance = 0;
44 m_InvitedHorde = 0;
45 m_ArenaType = 0;
46 m_IsArena = false;
47 m_Winner = 2;
48 m_StartTime = 0;
49 m_Events = 0;
50 m_IsRated = false;
51 m_BuffChange = false;
52 m_Name = "";
53 m_LevelMin = 0;
54 m_LevelMax = 0;
55 m_InBGFreeSlotQueue = false;
56 m_SetDeleteThis = false;
58 m_MaxPlayersPerTeam = 0;
59 m_MaxPlayers = 0;
60 m_MinPlayersPerTeam = 0;
61 m_MinPlayers = 0;
63 m_MapId = 0;
65 m_TeamStartLocX[BG_TEAM_ALLIANCE] = 0;
66 m_TeamStartLocX[BG_TEAM_HORDE] = 0;
68 m_TeamStartLocY[BG_TEAM_ALLIANCE] = 0;
69 m_TeamStartLocY[BG_TEAM_HORDE] = 0;
71 m_TeamStartLocZ[BG_TEAM_ALLIANCE] = 0;
72 m_TeamStartLocZ[BG_TEAM_HORDE] = 0;
74 m_TeamStartLocO[BG_TEAM_ALLIANCE] = 0;
75 m_TeamStartLocO[BG_TEAM_HORDE] = 0;
77 m_ArenaTeamIds[BG_TEAM_ALLIANCE] = 0;
78 m_ArenaTeamIds[BG_TEAM_HORDE] = 0;
80 m_ArenaTeamRatingChanges[BG_TEAM_ALLIANCE] = 0;
81 m_ArenaTeamRatingChanges[BG_TEAM_HORDE] = 0;
83 m_BgRaids[BG_TEAM_ALLIANCE] = NULL;
84 m_BgRaids[BG_TEAM_HORDE] = NULL;
86 m_PlayersCount[BG_TEAM_ALLIANCE] = 0;
87 m_PlayersCount[BG_TEAM_HORDE] = 0;
89 m_PrematureCountDown = false;
90 m_PrematureCountDown = 0;
93 BattleGround::~BattleGround()
95 // remove objects and creatures
96 // (this is done automatically in mapmanager update, when the instance is reset after the reset time)
97 int size = m_BgCreatures.size();
98 for(int i = 0; i < size; ++i)
100 DelCreature(i);
102 size = m_BgObjects.size();
103 for(int i = 0; i < size; ++i)
105 DelObject(i);
108 if(GetInstanceID()) // not spam by useless queries in case BG templates
110 // delete creature and go respawn times
111 WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'",GetInstanceID());
112 WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'",GetInstanceID());
113 // delete instance from db
114 CharacterDatabase.PExecute("DELETE FROM instance WHERE id = '%u'",GetInstanceID());
115 // remove from battlegrounds
118 sBattleGroundMgr.RemoveBattleGround(GetInstanceID());
119 // unload map
120 if(Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID()))
121 if(map->IsBattleGroundOrArena())
122 ((BattleGroundMap*)map)->SetUnload();
123 // remove from bg free slot queue
124 this->RemoveFromBGFreeSlotQueue();
127 void BattleGround::Update(uint32 diff)
129 if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize())
130 //BG is empty
131 return;
133 WorldPacket data;
135 if(GetRemovedPlayersSize())
137 for(std::map<uint64, uint8>::iterator itr = m_RemovedPlayers.begin(); itr != m_RemovedPlayers.end(); ++itr)
139 Player *plr = objmgr.GetPlayer(itr->first);
140 switch(itr->second)
142 //following code is handled by event:
143 /*case 0:
144 sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].RemovePlayer(itr->first);
145 //RemovePlayerFromQueue(itr->first);
146 if(plr)
148 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0);
149 plr->GetSession()->SendPacket(&data);
151 break;*/
152 case 1: // currently in bg and was removed from bg
153 if(plr)
154 RemovePlayerAtLeave(itr->first, true, true);
155 else
156 RemovePlayerAtLeave(itr->first, false, false);
157 break;
158 case 2: // revive queue
159 RemovePlayerFromResurrectQueue(itr->first);
160 break;
161 default:
162 sLog.outError("BattleGround: Unknown remove player case!");
165 m_RemovedPlayers.clear();
168 // remove offline players from bg after ~5 minutes
169 if(GetPlayersSize())
171 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
173 Player *plr = objmgr.GetPlayer(itr->first);
174 itr->second.LastOnlineTime += diff;
176 if(plr)
177 itr->second.LastOnlineTime = 0; // update last online time
178 else
179 if(itr->second.LastOnlineTime >= MAX_OFFLINE_TIME) // 5 minutes
180 m_RemovedPlayers[itr->first] = 1; // add to remove list (BG)
184 //this should be handled by spell system:
185 m_LastResurrectTime += diff;
186 if (m_LastResurrectTime >= RESURRECTION_INTERVAL)
188 if(GetReviveQueueSize())
190 for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
192 Creature *sh = NULL;
193 for(std::vector<uint64>::iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
195 Player *plr = objmgr.GetPlayer(*itr2);
196 if(!plr)
197 continue;
199 if (!sh)
201 sh = ObjectAccessor::GetCreature(*plr, itr->first);
202 // only for visual effect
203 if (sh)
204 sh->CastSpell(sh, SPELL_SPIRIT_HEAL, true); // Spirit Heal, effect 117
207 plr->CastSpell(plr, SPELL_RESURRECTION_VISUAL, true); // Resurrection visual
208 m_ResurrectQueue.push_back(*itr2);
210 (itr->second).clear();
213 m_ReviveQueue.clear();
214 m_LastResurrectTime = 0;
216 else
217 // queue is clear and time passed, just update last resurrection time
218 m_LastResurrectTime = 0;
220 else if (m_LastResurrectTime > 500) // Resurrect players only half a second later, to see spirit heal effect on NPC
222 for(std::vector<uint64>::iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
224 Player *plr = objmgr.GetPlayer(*itr);
225 if(!plr)
226 continue;
227 plr->ResurrectPlayer(1.0f);
228 plr->CastSpell(plr, SPELL_SPIRIT_HEAL_MANA, true);
229 ObjectAccessor::Instance().ConvertCorpseForPlayer(*itr);
231 m_ResurrectQueue.clear();
234 // if less then minimum players are in on one side, then start premature finish timer
235 if(GetStatus() == STATUS_IN_PROGRESS && !isArena() && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam()))
237 if(!m_PrematureCountDown)
239 m_PrematureCountDown = true;
240 m_PrematureCountDownTimer = sBattleGroundMgr.GetPrematureFinishTime();
241 SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
243 else if(m_PrematureCountDownTimer < diff)
245 // time's up!
246 EndBattleGround(0); // noone wins
247 m_PrematureCountDown = false;
249 else
251 uint32 newtime = m_PrematureCountDownTimer - diff;
252 // announce every minute
253 if(m_PrematureCountDownTimer != sBattleGroundMgr.GetPrematureFinishTime() && newtime / 60000 != m_PrematureCountDownTimer / 60000)
254 SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
255 m_PrematureCountDownTimer = newtime;
258 else if (m_PrematureCountDown)
259 m_PrematureCountDown = false;
261 if(GetStatus() == STATUS_WAIT_LEAVE)
263 // remove all players from battleground after 2 minutes
264 m_EndTime += diff;
265 if(m_EndTime >= TIME_TO_AUTOREMOVE) // 2 minutes
267 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
269 m_RemovedPlayers[itr->first] = 1; // add to remove list (BG)
271 // do not change any battleground's private variables
276 void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O)
278 uint8 idx = GetTeamIndexByTeamId(TeamID);
279 m_TeamStartLocX[idx] = X;
280 m_TeamStartLocY[idx] = Y;
281 m_TeamStartLocZ[idx] = Z;
282 m_TeamStartLocO[idx] = O;
285 void BattleGround::SendPacketToAll(WorldPacket *packet)
287 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
289 Player *plr = objmgr.GetPlayer(itr->first);
290 if(plr)
291 plr->GetSession()->SendPacket(packet);
292 else
293 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
297 void BattleGround::SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *sender, bool self)
299 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
301 Player *plr = objmgr.GetPlayer(itr->first);
303 if(!plr)
305 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
306 continue;
309 if(!self && sender == plr)
310 continue;
312 uint32 team = itr->second.Team;
313 if(!team) team = plr->GetTeam();
315 if(team == TeamID)
316 plr->GetSession()->SendPacket(packet);
320 void BattleGround::PlaySoundToAll(uint32 SoundID)
322 WorldPacket data;
323 sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
324 SendPacketToAll(&data);
327 void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID)
329 WorldPacket data;
331 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
333 Player *plr = objmgr.GetPlayer(itr->first);
335 if(!plr)
337 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
338 continue;
341 uint32 team = itr->second.Team;
342 if(!team) team = plr->GetTeam();
344 if(team == TeamID)
346 sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
347 plr->GetSession()->SendPacket(&data);
352 void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID)
354 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
356 Player *plr = objmgr.GetPlayer(itr->first);
358 if(!plr)
360 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
361 continue;
364 uint32 team = itr->second.Team;
365 if(!team) team = plr->GetTeam();
367 if(team == TeamID)
368 plr->CastSpell(plr, SpellID, true);
372 void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID)
374 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
376 Player *plr = objmgr.GetPlayer(itr->first);
378 if(!plr)
380 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
381 continue;
384 uint32 team = itr->second.Team;
385 if(!team) team = plr->GetTeam();
387 if(team == TeamID)
388 UpdatePlayerScore(plr, SCORE_BONUS_HONOR, Honor);
392 void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID)
394 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
396 if(!factionEntry)
397 return;
399 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
401 Player *plr = objmgr.GetPlayer(itr->first);
403 if(!plr)
405 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
406 continue;
409 uint32 team = itr->second.Team;
410 if(!team) team = plr->GetTeam();
412 if(team == TeamID)
413 plr->ModifyFactionReputation(factionEntry, Reputation);
417 void BattleGround::UpdateWorldState(uint32 Field, uint32 Value)
419 WorldPacket data;
420 sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
421 SendPacketToAll(&data);
424 void BattleGround::UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player *Source)
426 WorldPacket data;
427 sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
428 Source->GetSession()->SendPacket(&data);
431 void BattleGround::EndBattleGround(uint32 winner)
433 this->RemoveFromBGFreeSlotQueue();
435 ArenaTeam * winner_arena_team = NULL;
436 ArenaTeam * loser_arena_team = NULL;
437 uint32 loser_rating = 0;
438 uint32 winner_rating = 0;
439 WorldPacket data;
440 Player *Source = NULL;
441 const char *winmsg = "";
443 if(winner == ALLIANCE)
445 if(isBattleGround())
446 winmsg = GetMangosString(LANG_BG_A_WINS);
447 else
448 winmsg = GetMangosString(LANG_ARENA_GOLD_WINS);
450 PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound
452 SetWinner(WINNER_ALLIANCE);
454 else if(winner == HORDE)
456 if(isBattleGround())
457 winmsg = GetMangosString(LANG_BG_H_WINS);
458 else
459 winmsg = GetMangosString(LANG_ARENA_GREEN_WINS);
461 PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound
463 SetWinner(WINNER_HORDE);
465 else
467 SetWinner(3);
470 SetStatus(STATUS_WAIT_LEAVE);
471 m_EndTime = 0;
473 // arena rating calculation
474 if(isArena() && isRated())
476 if(winner == ALLIANCE)
478 winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
479 loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
481 else if(winner == HORDE)
483 winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
484 loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
486 if(winner_arena_team && loser_arena_team)
488 loser_rating = loser_arena_team->GetStats().rating;
489 winner_rating = winner_arena_team->GetStats().rating;
490 int32 winner_change = winner_arena_team->WonAgainst(loser_rating);
491 int32 loser_change = loser_arena_team->LostAgainst(winner_rating);
492 sLog.outDebug("--- Winner rating: %u, Loser rating: %u, Winner change: %u, Losser change: %u ---", winner_rating, loser_rating, winner_change, loser_change);
493 if(winner == ALLIANCE)
495 SetArenaTeamRatingChangeForTeam(ALLIANCE, winner_change);
496 SetArenaTeamRatingChangeForTeam(HORDE, loser_change);
498 else
500 SetArenaTeamRatingChangeForTeam(HORDE, winner_change);
501 SetArenaTeamRatingChangeForTeam(ALLIANCE, loser_change);
504 else
506 SetArenaTeamRatingChangeForTeam(ALLIANCE, 0);
507 SetArenaTeamRatingChangeForTeam(HORDE, 0);
511 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
513 Player *plr = objmgr.GetPlayer(itr->first);
514 if(!plr)
516 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
517 continue;
520 // should remove spirit of redemption
521 if(plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
522 plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
524 if(!plr->isAlive())
526 plr->ResurrectPlayer(1.0f);
527 plr->SpawnCorpseBones();
530 uint32 team = itr->second.Team;
531 if(!team) team = plr->GetTeam();
533 // per player calculation
534 if(isArena() && isRated() && winner_arena_team && loser_arena_team)
536 if(team == winner)
537 winner_arena_team->MemberWon(plr,loser_rating);
538 else
539 loser_arena_team->MemberLost(plr,winner_rating);
542 if(team == winner)
544 if(!Source)
545 Source = plr;
546 RewardMark(plr,ITEM_WINNER_COUNT);
547 UpdatePlayerScore(plr, SCORE_BONUS_HONOR, 20);
548 RewardQuest(plr);
550 else
552 RewardMark(plr,ITEM_LOSER_COUNT);
555 plr->CombatStopWithPets(true);
557 BlockMovement(plr);
559 sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
560 plr->GetSession()->SendPacket(&data);
562 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
563 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
564 plr->GetSession()->SendPacket(&data);
565 plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1);
568 if(isArena() && isRated() && winner_arena_team && loser_arena_team)
570 // update arena points only after increasing the player's match count!
571 //obsolete: winner_arena_team->UpdateArenaPointsHelper();
572 //obsolete: loser_arena_team->UpdateArenaPointsHelper();
573 // save the stat changes
574 winner_arena_team->SaveToDB();
575 loser_arena_team->SaveToDB();
576 // send updated arena team stats to players
577 // this way all arena team members will get notified, not only the ones who participated in this match
578 winner_arena_team->NotifyStatsChanged();
579 loser_arena_team->NotifyStatsChanged();
582 // inform invited players about the removal
583 sBattleGroundMgr.m_BattleGroundQueues[BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
585 if(Source)
587 ChatHandler(Source).FillMessageData(&data, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, Source->GetGUID(), winmsg);
588 SendPacketToAll(&data);
592 uint32 BattleGround::GetBattlemasterEntry() const
594 switch(GetTypeID())
596 case BATTLEGROUND_AV: return 15972;
597 case BATTLEGROUND_WS: return 14623;
598 case BATTLEGROUND_AB: return 14879;
599 case BATTLEGROUND_EY: return 22516;
600 case BATTLEGROUND_NA: return 20200;
601 default: return 0;
605 void BattleGround::RewardMark(Player *plr,uint32 count)
607 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
608 if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
609 return;
611 BattleGroundMarks mark;
612 bool IsSpell;
613 switch(GetTypeID())
615 case BATTLEGROUND_AV:
616 IsSpell = true;
617 if(count == ITEM_WINNER_COUNT)
618 mark = SPELL_AV_MARK_WINNER;
619 else
620 mark = SPELL_AV_MARK_LOSER;
621 break;
622 case BATTLEGROUND_WS:
623 IsSpell = true;
624 if(count == ITEM_WINNER_COUNT)
625 mark = SPELL_WS_MARK_WINNER;
626 else
627 mark = SPELL_WS_MARK_LOSER;
628 break;
629 case BATTLEGROUND_AB:
630 IsSpell = true;
631 if(count == ITEM_WINNER_COUNT)
632 mark = SPELL_AB_MARK_WINNER;
633 else
634 mark = SPELL_AB_MARK_LOSER;
635 break;
636 case BATTLEGROUND_EY:
637 IsSpell = false;
638 mark = ITEM_EY_MARK_OF_HONOR;
639 break;
640 default:
641 return;
644 if(IsSpell)
645 plr->CastSpell(plr, mark, true);
646 else if ( objmgr.GetItemPrototype( mark ) )
648 ItemPosCountVec dest;
649 uint32 no_space_count = 0;
650 uint8 msg = plr->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, mark, count, &no_space_count );
651 if( msg != EQUIP_ERR_OK ) // convert to possible store amount
652 count -= no_space_count;
654 if( count != 0 && !dest.empty()) // can add some
655 if(Item* item = plr->StoreNewItem( dest, mark, true, 0))
656 plr->SendNewItem(item,count,false,true);
658 if(no_space_count > 0)
659 SendRewardMarkByMail(plr,mark,no_space_count);
663 void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count)
665 uint32 bmEntry = GetBattlemasterEntry();
666 if(!bmEntry)
667 return;
669 ItemPrototype const* markProto = objmgr.GetItemPrototype(mark);
670 if(!markProto)
671 return;
673 if(Item* markItem = Item::CreateItem(mark,count,plr))
675 // save new item before send
676 markItem->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
678 // item
679 MailItemsInfo mi;
680 mi.AddItem(markItem->GetGUIDLow(), markItem->GetEntry(), markItem);
682 // subject: item name
683 std::string subject = markProto->Name1;
684 int loc_idx = plr->GetSession()->GetSessionDbLocaleIndex();
685 if ( loc_idx >= 0 )
686 if(ItemLocale const *il = objmgr.GetItemLocale(markProto->ItemId))
687 if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty())
688 subject = il->Name[loc_idx];
690 // text
691 std::string textFormat = plr->GetSession()->GetMangosString(LANG_BG_MARK_BY_MAIL);
692 char textBuf[300];
693 snprintf(textBuf,300,textFormat.c_str(),GetName(),GetName());
694 uint32 itemTextId = objmgr.CreateItemText( textBuf );
696 WorldSession::SendMailTo(plr, MAIL_CREATURE, MAIL_STATIONERY_NORMAL, bmEntry, plr->GetGUIDLow(), subject, itemTextId , &mi, 0, 0, MAIL_CHECK_MASK_NONE);
700 void BattleGround::RewardQuest(Player *plr)
702 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
703 if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
704 return;
706 uint32 quest;
707 switch(GetTypeID())
709 case BATTLEGROUND_AV:
710 quest = SPELL_AV_QUEST_REWARD;
711 break;
712 case BATTLEGROUND_WS:
713 quest = SPELL_WS_QUEST_REWARD;
714 break;
715 case BATTLEGROUND_AB:
716 quest = SPELL_AB_QUEST_REWARD;
717 break;
718 case BATTLEGROUND_EY:
719 quest = SPELL_EY_QUEST_REWARD;
720 break;
721 default:
722 return;
725 plr->CastSpell(plr, quest, true);
728 void BattleGround::BlockMovement(Player *plr)
730 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()
733 void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket)
735 uint32 team = GetPlayerTeam(guid);
736 bool participant = false;
737 // Remove from lists/maps
738 std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.find(guid);
739 if(itr != m_Players.end())
741 UpdatePlayersCountByTeam(team, true); // -1 player
742 m_Players.erase(itr);
743 // check if the player was a participant of the match, or only entered through gm command (goname)
744 participant = true;
747 std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid);
748 if(itr2 != m_PlayerScores.end())
750 delete itr2->second; // delete player's score
751 m_PlayerScores.erase(itr2);
754 RemovePlayerFromResurrectQueue(guid);
756 Player *plr = objmgr.GetPlayer(guid);
758 // should remove spirit of redemption
759 if(plr && plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
760 plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
762 if(plr && !plr->isAlive()) // resurrect on exit
764 plr->ResurrectPlayer(1.0f);
765 plr->SpawnCorpseBones();
768 RemovePlayer(plr, guid); // BG subclass specific code
770 if(plr)
772 plr->ClearAfkReports();
774 if(participant) // if the player was a match participant, remove auras, calc rating, update queue
776 if(!team) team = plr->GetTeam();
778 BattleGroundTypeId bgTypeId = GetTypeID();
779 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
780 // if arena, remove the specific arena auras
781 if(isArena())
783 plr->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out
784 bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing)
786 // summon old pet if there was one and there isn't a current pet
787 if(!plr->GetPet() && plr->GetTemporaryUnsummonedPetNumber())
789 Pet* NewPet = new Pet;
790 if(!NewPet->LoadPetFromDB(plr, 0, (plr)->GetTemporaryUnsummonedPetNumber(), true))
791 delete NewPet;
793 (plr)->SetTemporaryUnsummonedPetNumber(0);
796 if(isRated() && GetStatus() == STATUS_IN_PROGRESS)
798 //left a rated match while the encounter was in progress, consider as loser
799 ArenaTeam * winner_arena_team = 0;
800 ArenaTeam * loser_arena_team = 0;
801 if(team == HORDE)
803 winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
804 loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
806 else
808 winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
809 loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
811 if(winner_arena_team && loser_arena_team)
813 loser_arena_team->MemberLost(plr,winner_arena_team->GetRating());
818 WorldPacket data;
819 if(SendPacket)
821 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, team, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0);
822 plr->GetSession()->SendPacket(&data);
825 // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
826 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
828 DecreaseInvitedCount(team);
829 //we should update battleground queue, but only if bg isn't ending
830 if (GetQueueId() < MAX_BATTLEGROUND_QUEUES)
831 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueId());
833 Group * group = plr->GetGroup();
834 // remove from raid group if exist
835 if(group && group == GetBgRaid(team))
837 if(!group->RemoveMember(guid, 0)) // group was disbanded
839 SetBgRaid(team, NULL);
840 delete group;
844 // Let others know
845 sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);
846 SendPacketToTeam(team, &data, plr, false);
849 // Do next only if found in battleground
850 plr->SetBattleGroundId(0); // We're not in BG.
851 // reset destination bg team
852 plr->SetBGTeam(0);
854 if(Transport)
855 plr->TeleportTo(plr->GetBattleGroundEntryPoint());
857 // Log
858 sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName());
861 if(!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
863 // if no players left AND no invitees left, set this bg to delete in next update
864 // direct deletion could cause crashes
865 m_SetDeleteThis = true;
866 // return to prevent addition to freeslotqueue
867 return;
870 // a player exited the battleground, so there are free slots. add to queue
871 this->AddToBGFreeSlotQueue();
874 // this method is called when no players remains in battleground
875 void BattleGround::Reset()
877 SetQueueId(MAX_BATTLEGROUND_QUEUES);
878 SetWinner(WINNER_NONE);
879 SetStatus(STATUS_WAIT_QUEUE);
880 SetStartTime(0);
881 SetEndTime(0);
882 SetLastResurrectTime(0);
883 SetArenaType(0);
884 SetRated(false);
886 m_Events = 0;
888 if (m_InvitedAlliance > 0 || m_InvitedHorde > 0)
889 sLog.outError("BattleGround system ERROR: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance, m_InvitedHorde);
891 m_InvitedAlliance = 0;
892 m_InvitedHorde = 0;
893 m_InBGFreeSlotQueue = false;
895 m_Players.clear();
896 m_PlayerScores.clear();
899 void BattleGround::StartBattleGround()
901 ///this method should spawn spirit guides and so on
902 SetStartTime(0);
904 SetLastResurrectTime(0);
907 void BattleGround::AddPlayer(Player *plr)
909 // score struct must be created in inherited class
911 uint64 guid = plr->GetGUID();
912 uint32 team = plr->GetBGTeam();
914 BattleGroundPlayer bp;
915 bp.LastOnlineTime = 0;
916 bp.Team = team;
918 // Add to list/maps
919 m_Players[guid] = bp;
921 UpdatePlayersCountByTeam(team, false); // +1 player
923 WorldPacket data;
924 sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr);
925 SendPacketToTeam(team, &data, plr, false);
927 // add arena specific auras
928 if(isArena())
930 plr->RemoveArenaSpellCooldowns();
931 plr->RemoveArenaAuras();
932 plr->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT);
933 if(team == ALLIANCE) // gold
935 if(plr->GetTeam() == HORDE)
936 plr->CastSpell(plr, SPELL_HORDE_GOLD_FLAG,true);
937 else
938 plr->CastSpell(plr, SPELL_ALLIANCE_GOLD_FLAG,true);
940 else // green
942 if(plr->GetTeam() == HORDE)
943 plr->CastSpell(plr, SPELL_HORDE_GREEN_FLAG,true);
944 else
945 plr->CastSpell(plr, SPELL_ALLIANCE_GREEN_FLAG,true);
948 plr->DestroyConjuredItems(true);
950 Pet* pet = plr->GetPet();
951 if(pet)
953 if(pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET)
955 (plr)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber());
956 (plr)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));
958 (plr)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);
960 else
961 (plr)->SetTemporaryUnsummonedPetNumber(0);
963 if(GetStatus() == STATUS_WAIT_JOIN) // not started yet
965 plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);
967 plr->SetHealth(plr->GetMaxHealth());
968 plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA));
971 else
973 if(GetStatus() == STATUS_WAIT_JOIN) // not started yet
974 plr->CastSpell(plr, SPELL_PREPARATION, true); // reduces all mana cost of spells.
977 // setup BG group membership
978 PlayerRelogin(plr);
979 AddOrSetPlayerToCorrectBgGroup(plr, guid, team);
981 // Log
982 sLog.outDetail("BATTLEGROUND: Player %s joined the battle.", plr->GetName());
985 /* this method adds player to his team's bg group, or sets his correct group if player is already in bg group */
986 void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid, uint32 team)
988 Group* group = GetBgRaid(team);
989 if(!group) // first player joined
991 group = new Group;
992 SetBgRaid(team, group);
993 group->Create(plr_guid, plr->GetName());
995 else // raid already exist
997 if(group->IsMember(plr_guid))
999 uint8 subgroup = group->GetMemberGroup(plr_guid);
1000 plr->SetGroup(group, subgroup);
1002 else
1003 GetBgRaid(team)->AddMember(plr_guid, plr->GetName());
1008 /* This method should be called only once ... it adds pointer to queue */
1009 void BattleGround::AddToBGFreeSlotQueue()
1011 // make sure to add only once
1012 if(!m_InBGFreeSlotQueue)
1014 sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);
1015 m_InBGFreeSlotQueue = true;
1019 /* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
1020 void BattleGround::RemoveFromBGFreeSlotQueue()
1022 // set to be able to re-add if needed
1023 m_InBGFreeSlotQueue = false;
1024 // uncomment this code when battlegrounds will work like instances
1025 for (std::deque<BattleGround*>::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)
1027 if ((*itr)->GetInstanceID() == m_InstanceID)
1029 sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr);
1030 return;
1035 // get the number of free slots for team
1036 // works in similar way that HasFreeSlotsForTeam did, but this is needed for join as group
1037 uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const
1039 //if BG is starting ... invite anyone
1040 if (GetStatus() == STATUS_WAIT_JOIN)
1041 return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
1042 //if BG is already started .. do not allow to join too much players of one faction
1043 uint32 otherTeam;
1044 uint32 otherIn;
1045 if (Team == ALLIANCE)
1047 otherTeam = GetInvitedCount(HORDE);
1048 otherIn = GetPlayersCountByTeam(HORDE);
1050 else
1052 otherTeam = GetInvitedCount(ALLIANCE);
1053 otherIn = GetPlayersCountByTeam(ALLIANCE);
1055 if (GetStatus() == STATUS_IN_PROGRESS)
1057 // difference based on ppl invited (not necessarily entered battle)
1058 // default: allow 0
1059 uint32 diff = 0;
1060 // allow join one person if the sides are equal (to fill up bg to minplayersperteam)
1061 if (otherTeam == GetInvitedCount(Team))
1062 diff = 1;
1063 // allow join more ppl if the other side has more players
1064 else if(otherTeam > GetInvitedCount(Team))
1065 diff = otherTeam - GetInvitedCount(Team);
1067 // difference based on max players per team (don't allow inviting more)
1068 uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
1070 // difference based on players who already entered
1071 // default: allow 0
1072 uint32 diff3 = 0;
1073 // allow join one person if the sides are equal (to fill up bg minplayersperteam)
1074 if (otherIn == GetPlayersCountByTeam(Team))
1075 diff3 = 1;
1076 // allow join more ppl if the other side has more players
1077 else if (otherIn > GetPlayersCountByTeam(Team))
1078 diff3 = otherIn - GetPlayersCountByTeam(Team);
1079 // or other side has less than minPlayersPerTeam
1080 else if (GetInvitedCount(Team) <= GetMinPlayersPerTeam())
1081 diff3 = GetMinPlayersPerTeam() - GetInvitedCount(Team) + 1;
1083 // return the minimum of the 3 differences
1085 // min of diff and diff 2
1086 diff = diff < diff2 ? diff : diff2;
1088 // min of diff, diff2 and diff3
1089 return diff < diff3 ? diff : diff3 ;
1092 return 0;
1095 bool BattleGround::HasFreeSlots() const
1097 return GetPlayersSize() < GetMaxPlayers();
1100 void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
1102 //this procedure is called from virtual function implemented in bg subclass
1103 std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
1105 if(itr == m_PlayerScores.end()) // player not found...
1106 return;
1108 switch(type)
1110 case SCORE_KILLING_BLOWS: // Killing blows
1111 itr->second->KillingBlows += value;
1112 break;
1113 case SCORE_DEATHS: // Deaths
1114 itr->second->Deaths += value;
1115 break;
1116 case SCORE_HONORABLE_KILLS: // Honorable kills
1117 itr->second->HonorableKills += value;
1118 break;
1119 case SCORE_BONUS_HONOR: // Honor bonus
1120 // do not add honor in arenas
1121 if(isBattleGround())
1123 // reward honor instantly
1124 if(Source->RewardHonor(NULL, 1, value))
1125 itr->second->BonusHonor += value;
1127 break;
1128 //used only in EY, but in MSG_PVP_LOG_DATA opcode
1129 case SCORE_DAMAGE_DONE: // Damage Done
1130 itr->second->DamageDone += value;
1131 break;
1132 case SCORE_HEALING_DONE: // Healing Done
1133 itr->second->HealingDone += value;
1134 break;
1135 default:
1136 sLog.outError("BattleGround: Unknown player score type %u", type);
1137 break;
1141 void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid)
1143 m_ReviveQueue[npc_guid].push_back(player_guid);
1145 Player *plr = objmgr.GetPlayer(player_guid);
1146 if(!plr)
1147 return;
1149 plr->CastSpell(plr, SPELL_WAITING_FOR_RESURRECT, true);
1150 SpellEntry const *spellInfo = sSpellStore.LookupEntry( SPELL_WAITING_FOR_RESURRECT );
1151 if(spellInfo)
1153 Aura *Aur = CreateAura(spellInfo, 0, NULL, plr);
1154 plr->AddAura(Aur);
1158 void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid)
1160 for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
1162 for(std::vector<uint64>::iterator itr2 =(itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
1164 if(*itr2 == player_guid)
1166 (itr->second).erase(itr2);
1168 Player *plr = objmgr.GetPlayer(player_guid);
1169 if(!plr)
1170 return;
1172 plr->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
1174 return;
1180 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)
1182 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1183 if(!map)
1184 return false;
1186 // must be created this way, adding to godatamap would add it to the base map of the instance
1187 // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
1188 // so we must create it specific for this instance
1189 GameObject * go = new GameObject;
1190 if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, map,
1191 PHASEMASK_NORMAL, x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,1))
1193 sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);
1194 sLog.outError("Cannot create gameobject template %u! BattleGround not created!", entry);
1195 delete go;
1196 return false;
1199 uint32 guid = go->GetGUIDLow();
1201 // without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
1202 // 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
1203 GameObjectData& data = objmgr.NewGOData(guid);
1205 data.id = entry;
1206 data.mapid = GetMapId();
1207 data.posX = x;
1208 data.posY = y;
1209 data.posZ = z;
1210 data.orientation = o;
1211 data.rotation0 = rotation0;
1212 data.rotation1 = rotation1;
1213 data.rotation2 = rotation2;
1214 data.rotation3 = rotation3;
1215 data.spawntimesecs = respawnTime;
1216 data.spawnMask = 1;
1217 data.animprogress = 100;
1218 data.go_state = 1;
1220 // add to world, so it can be later looked up from HashMapHolder
1221 go->AddToWorld();
1222 m_BgObjects[type] = go->GetGUID();
1223 return true;
1226 //some doors aren't despawned so we cannot handle their closing in gameobject::update()
1227 //it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
1228 void BattleGround::DoorClose(uint32 type)
1230 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1231 if(obj)
1233 //if doors are open, close it
1234 if( obj->getLootState() == GO_ACTIVATED && !obj->GetGoState() )
1236 //change state to allow door to be closed
1237 obj->SetLootState(GO_READY);
1238 obj->UseDoorOrButton(RESPAWN_ONE_DAY);
1241 else
1243 sLog.outError("BattleGround: Door object not found (cannot close doors)");
1247 void BattleGround::DoorOpen(uint32 type)
1249 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1250 if(obj)
1252 //change state to be sure they will be opened
1253 obj->SetLootState(GO_READY);
1254 obj->UseDoorOrButton(RESPAWN_ONE_DAY);
1256 else
1258 sLog.outError("BattleGround: Door object not found! - doors will be closed.");
1262 void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
1264 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1265 if(!map)
1266 return;
1267 if( respawntime == 0 )
1269 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1270 if(obj)
1272 //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
1273 if( obj->getLootState() == GO_JUST_DEACTIVATED )
1274 obj->SetLootState(GO_READY);
1275 obj->SetRespawnTime(0);
1276 map->Add(obj);
1279 else
1281 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1282 if(obj)
1284 map->Add(obj);
1285 obj->SetRespawnTime(respawntime);
1286 obj->SetLootState(GO_JUST_DEACTIVATED);
1291 Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime)
1293 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1294 if(!map)
1295 return NULL;
1297 Creature* pCreature = new Creature;
1298 if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, PHASEMASK_NORMAL, entry, teamval))
1300 sLog.outError("Can't create creature entry: %u",entry);
1301 delete pCreature;
1302 return NULL;
1305 pCreature->Relocate(x, y, z, o);
1307 if(!pCreature->IsPositionValid())
1309 sLog.outError("ERROR: 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());
1310 return NULL;
1313 pCreature->AIM_Initialize();
1315 //pCreature->SetDungeonDifficulty(0);
1317 map->Add(pCreature);
1318 m_BgCreatures[type] = pCreature->GetGUID();
1320 return pCreature;
1323 void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)
1325 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceId());
1326 if(!map)
1327 return false;
1329 if(respawntime == 0)
1331 Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1332 if(obj)
1334 //obj->Respawn(); // bugged
1335 obj->SetRespawnTime(0);
1336 objmgr.SaveCreatureRespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);
1337 map->Add(obj);
1340 else
1342 Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1343 if(obj)
1345 obj->setDeathState(DEAD);
1346 obj->SetRespawnTime(respawntime);
1347 map->Add(obj);
1352 bool BattleGround::DelCreature(uint32 type)
1354 if(!m_BgCreatures[type])
1355 return true;
1357 Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1358 if(!cr)
1360 sLog.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures[type]));
1361 return false;
1363 cr->CleanupsBeforeDelete();
1364 cr->AddObjectToRemoveList();
1365 m_BgCreatures[type] = 0;
1366 return true;
1369 bool BattleGround::DelObject(uint32 type)
1371 if(!m_BgObjects[type])
1372 return true;
1374 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1375 if(!obj)
1377 sLog.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects[type]));
1378 return false;
1380 obj->SetRespawnTime(0); // not save respawn time
1381 obj->Delete();
1382 m_BgObjects[type] = 0;
1383 return true;
1386 bool BattleGround::AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team)
1388 uint32 entry = 0;
1390 if(team == ALLIANCE)
1391 entry = 13116;
1392 else
1393 entry = 13117;
1395 Creature* pCreature = AddCreature(entry,type,team,x,y,z,o);
1396 if(!pCreature)
1398 sLog.outError("Can't create Spirit guide. BattleGround not created!");
1399 EndNow();
1400 return false;
1403 pCreature->setDeathState(DEAD);
1405 pCreature->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, pCreature->GetGUID());
1406 // aura
1407 pCreature->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL);
1408 //pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
1409 //pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
1410 //pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
1411 // casting visual effect
1412 pCreature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_SPIRIT_HEAL_CHANNEL);
1413 // correct cast speed
1414 pCreature->SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
1416 //pCreature->CastSpell(pCreature, SPELL_SPIRIT_HEAL_CHANNEL, true);
1418 return true;
1421 void BattleGround::SendMessageToAll(char const* text)
1423 WorldPacket data;
1424 ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, text, NULL);
1425 SendPacketToAll(&data);
1428 void BattleGround::SendMessageToAll(int32 entry)
1430 char const* text = GetMangosString(entry);
1431 WorldPacket data;
1432 ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, text, NULL);
1433 SendPacketToAll(&data);
1436 void BattleGround::EndNow()
1438 RemoveFromBGFreeSlotQueue();
1439 SetStatus(STATUS_WAIT_LEAVE);
1440 SetEndTime(TIME_TO_AUTOREMOVE);
1441 // inform invited players about the removal
1442 sBattleGroundMgr.m_BattleGroundQueues[BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
1445 // Battleground messages are localized using the dbc lang, they are not client language dependent
1446 const char *BattleGround::GetMangosString(int32 entry)
1448 // FIXME: now we have different DBC locales and need localized message for each target client
1449 return objmgr.GetMangosStringForDBCLocale(entry);
1453 important notice:
1454 buffs aren't spawned/despawned when players captures anything
1455 buffs are in their positions when battleground starts
1457 void BattleGround::HandleTriggerBuff(uint64 const& go_guid)
1459 GameObject *obj = HashMapHolder<GameObject>::Find(go_guid);
1460 if(!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned())
1461 return;
1463 //change buff type, when buff is used:
1464 int32 index = m_BgObjects.size() - 1;
1465 while (index >= 0 && m_BgObjects[index] != go_guid)
1466 index--;
1467 if (index < 0)
1469 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());
1470 return;
1473 //randomly select new buff
1474 uint8 buff = urand(0, 2);
1475 uint32 entry = obj->GetEntry();
1476 if( m_BuffChange && entry != Buff_Entries[buff] )
1478 //despawn current buff
1479 SpawnBGObject(index, RESPAWN_ONE_DAY);
1480 //set index for new one
1481 for (uint8 currBuffTypeIndex = 0; currBuffTypeIndex < 3; ++currBuffTypeIndex)
1482 if( entry == Buff_Entries[currBuffTypeIndex] )
1484 index -= currBuffTypeIndex;
1485 index += buff;
1489 SpawnBGObject(index, BUFF_RESPAWN_TIME);
1492 void BattleGround::HandleKillPlayer( Player *player, Player *killer )
1494 //keep in mind that for arena this will have to be changed a bit
1496 // add +1 deaths
1497 UpdatePlayerScore(player, SCORE_DEATHS, 1);
1499 // add +1 kills to group and +1 killing_blows to killer
1500 if( killer )
1502 UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);
1503 UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1);
1505 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1507 Player *plr = objmgr.GetPlayer(itr->first);
1509 if(!plr || plr == killer)
1510 continue;
1512 if( plr->GetTeam() == killer->GetTeam() && plr->IsAtGroupRewardDistance(player) )
1513 UpdatePlayerScore(plr, SCORE_HONORABLE_KILLS, 1);
1517 // to be able to remove insignia
1518 player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
1521 // return the player's team based on battlegroundplayer info
1522 // used in same faction arena matches mainly
1523 uint32 BattleGround::GetPlayerTeam(uint64 guid)
1525 std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.find(guid);
1526 if(itr!=m_Players.end())
1527 return itr->second.Team;
1528 return 0;
1531 bool BattleGround::IsPlayerInBattleGround(uint64 guid)
1533 std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.find(guid);
1534 if(itr!=m_Players.end())
1535 return true;
1536 return false;
1539 void BattleGround::PlayerRelogin(Player* plr)
1541 if(GetStatus() != STATUS_WAIT_LEAVE)
1542 return;
1544 WorldPacket data;
1545 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
1547 BlockMovement(plr);
1549 sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
1550 plr->GetSession()->SendPacket(&data);
1552 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
1553 plr->GetSession()->SendPacket(&data);
1556 uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const
1558 int count = 0;
1559 for(std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1561 if(itr->second.Team == Team)
1563 Player * pl = objmgr.GetPlayer(itr->first);
1564 if(pl && pl->isAlive())
1565 ++count;
1568 return count;
1571 void BattleGround::SetBgRaid( uint32 TeamID, Group *bg_raid )
1573 Group* &old_raid = TeamID == ALLIANCE ? m_BgRaids[BG_TEAM_ALLIANCE] : m_BgRaids[BG_TEAM_HORDE];
1574 if(old_raid) old_raid->SetBattlegroundGroup(NULL);
1575 if(bg_raid) bg_raid->SetBattlegroundGroup(this);
1576 old_raid = bg_raid;