[7409] Support localization for messsages in specialized battagorund code BattleGroun...
[AHbot.git] / src / game / BattleGround.cpp
bloba838ad10dc27ad546f98e7752921deb15a76c3c4
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 "GridNotifiersImpl.h"
35 namespace MaNGOS
37 class BattleGroundChatBuilder
39 public:
40 BattleGroundChatBuilder(ChatMsg msgtype, int32 textId, Player const* source, va_list* args = NULL)
41 : i_msgtype(msgtype), i_textId(textId), i_source(source), i_args(args) {}
42 void operator()(WorldPacket& data, int32 loc_idx)
44 char const* text = objmgr.GetMangosString(i_textId,loc_idx);
46 if(i_args)
48 // we need copy va_list before use or original va_list will corrupted
49 va_list ap;
50 va_copy(ap,*i_args);
52 char str [2048];
53 vsnprintf(str,2048,text, ap );
54 va_end(ap);
56 do_helper(data,&str[0]);
58 else
59 do_helper(data,text);
61 private:
62 void do_helper(WorldPacket& data, char const* text)
64 uint64 target_guid = i_source ? i_source ->GetGUID() : 0;
66 data << uint8(i_msgtype);
67 data << uint32(LANG_UNIVERSAL);
68 data << uint64(target_guid); // there 0 for BG messages
69 data << uint32(0); // can be chat msg group or something
70 data << uint64(target_guid);
71 data << uint32(strlen(text)+1);
72 data << text;
73 data << uint8(i_source ? i_source->chatTag() : uint8(0));
76 ChatMsg i_msgtype;
77 int32 i_textId;
78 Player const* i_source;
79 va_list* i_args;
81 } // namespace MaNGOS
83 BattleGround::BattleGround()
85 m_TypeID = BattleGroundTypeId(0);
86 m_InstanceID = 0;
87 m_Status = STATUS_NONE;
88 m_EndTime = 0;
89 m_LastResurrectTime = 0;
90 m_QueueId = QUEUE_ID_MAX_LEVEL_19;
91 m_InvitedAlliance = 0;
92 m_InvitedHorde = 0;
93 m_ArenaType = 0;
94 m_IsArena = false;
95 m_Winner = 2;
96 m_StartTime = 0;
97 m_Events = 0;
98 m_IsRated = false;
99 m_BuffChange = false;
100 m_Name = "";
101 m_LevelMin = 0;
102 m_LevelMax = 0;
103 m_InBGFreeSlotQueue = false;
104 m_SetDeleteThis = false;
106 m_MaxPlayersPerTeam = 0;
107 m_MaxPlayers = 0;
108 m_MinPlayersPerTeam = 0;
109 m_MinPlayers = 0;
111 m_MapId = 0;
113 m_TeamStartLocX[BG_TEAM_ALLIANCE] = 0;
114 m_TeamStartLocX[BG_TEAM_HORDE] = 0;
116 m_TeamStartLocY[BG_TEAM_ALLIANCE] = 0;
117 m_TeamStartLocY[BG_TEAM_HORDE] = 0;
119 m_TeamStartLocZ[BG_TEAM_ALLIANCE] = 0;
120 m_TeamStartLocZ[BG_TEAM_HORDE] = 0;
122 m_TeamStartLocO[BG_TEAM_ALLIANCE] = 0;
123 m_TeamStartLocO[BG_TEAM_HORDE] = 0;
125 m_ArenaTeamIds[BG_TEAM_ALLIANCE] = 0;
126 m_ArenaTeamIds[BG_TEAM_HORDE] = 0;
128 m_ArenaTeamRatingChanges[BG_TEAM_ALLIANCE] = 0;
129 m_ArenaTeamRatingChanges[BG_TEAM_HORDE] = 0;
131 m_BgRaids[BG_TEAM_ALLIANCE] = NULL;
132 m_BgRaids[BG_TEAM_HORDE] = NULL;
134 m_PlayersCount[BG_TEAM_ALLIANCE] = 0;
135 m_PlayersCount[BG_TEAM_HORDE] = 0;
137 m_PrematureCountDown = false;
138 m_PrematureCountDown = 0;
140 m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_2M;
141 m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_1M;
142 m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_30S;
143 m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
144 //we must set to some default existing values
145 m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES;
146 m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE;
147 m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE;
148 m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN;
151 BattleGround::~BattleGround()
153 // remove objects and creatures
154 // (this is done automatically in mapmanager update, when the instance is reset after the reset time)
155 int size = m_BgCreatures.size();
156 for(int i = 0; i < size; ++i)
158 DelCreature(i);
160 size = m_BgObjects.size();
161 for(int i = 0; i < size; ++i)
163 DelObject(i);
166 if(GetInstanceID()) // not spam by useless queries in case BG templates
168 // delete creature and go respawn times
169 WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'",GetInstanceID());
170 WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'",GetInstanceID());
171 // delete instance from db
172 CharacterDatabase.PExecute("DELETE FROM instance WHERE id = '%u'",GetInstanceID());
173 // remove from battlegrounds
176 sBattleGroundMgr.RemoveBattleGround(GetInstanceID(), GetTypeID());
177 // unload map
178 if(Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID()))
179 if(map->IsBattleGroundOrArena())
180 ((BattleGroundMap*)map)->SetUnload();
181 // remove from bg free slot queue
182 this->RemoveFromBGFreeSlotQueue();
185 void BattleGround::Update(uint32 diff)
187 if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize())
188 //BG is empty
189 return;
191 if(GetRemovedPlayersSize())
193 for(std::map<uint64, uint8>::iterator itr = m_RemovedPlayers.begin(); itr != m_RemovedPlayers.end(); ++itr)
195 Player *plr = objmgr.GetPlayer(itr->first);
196 switch(itr->second)
198 case 1: // currently in bg and was removed from bg
199 if(plr)
200 RemovePlayerAtLeave(itr->first, true, true);
201 else
202 RemovePlayerAtLeave(itr->first, false, false);
203 break;
204 case 2: // revive queue
205 RemovePlayerFromResurrectQueue(itr->first);
206 break;
207 default:
208 sLog.outError("BattleGround: Unknown remove player case!");
211 m_RemovedPlayers.clear();
214 // remove offline players from bg after 5 minutes
215 if(GetPlayersSize())
217 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
219 Player *plr = objmgr.GetPlayer(itr->first);
220 itr->second.LastOnlineTime += diff;
222 if(plr)
223 itr->second.LastOnlineTime = 0; // update last online time
224 else
225 if(itr->second.LastOnlineTime >= MAX_OFFLINE_TIME)
226 m_RemovedPlayers[itr->first] = 1; // add to remove list (BG)
230 /*********************************************************/
231 /*** BATTLEGROUND RESSURECTION SYSTEM ***/
232 /*********************************************************/
234 //this should be handled by spell system
235 m_LastResurrectTime += diff;
236 if (m_LastResurrectTime >= RESURRECTION_INTERVAL)
238 if(GetReviveQueueSize())
240 for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
242 Creature *sh = NULL;
243 for(std::vector<uint64>::iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
245 Player *plr = objmgr.GetPlayer(*itr2);
246 if(!plr)
247 continue;
249 if (!sh)
251 sh = ObjectAccessor::GetCreature(*plr, itr->first);
252 // only for visual effect
253 if (sh)
254 sh->CastSpell(sh, SPELL_SPIRIT_HEAL, true); // Spirit Heal, effect 117
257 plr->CastSpell(plr, SPELL_RESURRECTION_VISUAL, true); // Resurrection visual
258 m_ResurrectQueue.push_back(*itr2);
260 (itr->second).clear();
263 m_ReviveQueue.clear();
264 m_LastResurrectTime = 0;
266 else
267 // queue is clear and time passed, just update last resurrection time
268 m_LastResurrectTime = 0;
270 else if (m_LastResurrectTime > 500) // Resurrect players only half a second later, to see spirit heal effect on NPC
272 for(std::vector<uint64>::iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
274 Player *plr = objmgr.GetPlayer(*itr);
275 if(!plr)
276 continue;
277 plr->ResurrectPlayer(1.0f);
278 plr->CastSpell(plr, SPELL_SPIRIT_HEAL_MANA, true);
279 ObjectAccessor::Instance().ConvertCorpseForPlayer(*itr);
281 m_ResurrectQueue.clear();
284 /*********************************************************/
285 /*** BATTLEGROUND BALLANCE SYSTEM ***/
286 /*********************************************************/
288 // if less then minimum players are in on one side, then start premature finish timer
289 if(GetStatus() == STATUS_IN_PROGRESS && !isArena() && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam()))
291 if(!m_PrematureCountDown)
293 m_PrematureCountDown = true;
294 m_PrematureCountDownTimer = sBattleGroundMgr.GetPrematureFinishTime();
296 else if(m_PrematureCountDownTimer < diff)
298 // time's up!
299 EndBattleGround(0); // noone wins
300 m_PrematureCountDown = false;
302 else
304 uint32 newtime = m_PrematureCountDownTimer - diff;
305 // announce every minute
306 if( newtime > (MINUTE * IN_MILISECONDS) )
308 if( newtime / (MINUTE * IN_MILISECONDS) != m_PrematureCountDownTimer / (MINUTE * IN_MILISECONDS) )
309 PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING, CHAT_MSG_SYSTEM, NULL, (uint32)(m_PrematureCountDownTimer / (MINUTE * IN_MILISECONDS)));
311 else
313 //announce every 15 seconds
314 if( newtime / (15 * IN_MILISECONDS) != m_PrematureCountDownTimer / (15 * IN_MILISECONDS) )
315 PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS, CHAT_MSG_SYSTEM, NULL, (uint32)(m_PrematureCountDownTimer / IN_MILISECONDS));
317 m_PrematureCountDownTimer = newtime;
320 else if (m_PrematureCountDown)
321 m_PrematureCountDown = false;
323 /*********************************************************/
324 /*** BATTLEGROUND STARTING SYSTEM ***/
325 /*********************************************************/
327 if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
329 ModifyStartDelayTime(diff);
331 if (!(m_Events & BG_STARTING_EVENT_1))
333 m_Events |= BG_STARTING_EVENT_1;
335 // setup here, only when at least one player has ported to the map
336 if(!SetupBattleGround())
338 EndNow();
339 return;
342 StartingEventCloseDoors();
343 SetStartDelayTime(m_StartDelayTimes[BG_STARTING_EVENT_FIRST]);
344 //first start warning - 2 or 1 minute
345 SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_FIRST], CHAT_MSG_BG_SYSTEM_NEUTRAL);
347 // After 1 minute or 30 seconds, warning is signalled
348 else if (GetStartDelayTime() <= m_StartDelayTimes[BG_STARTING_EVENT_SECOND] && !(m_Events & BG_STARTING_EVENT_2))
350 m_Events |= BG_STARTING_EVENT_2;
351 SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_SECOND], CHAT_MSG_BG_SYSTEM_NEUTRAL);
353 // After 30 or 15 seconds, warning is signalled
354 else if (GetStartDelayTime() <= m_StartDelayTimes[BG_STARTING_EVENT_THIRD] && !(m_Events & BG_STARTING_EVENT_3))
356 m_Events |= BG_STARTING_EVENT_3;
357 SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_THIRD], CHAT_MSG_BG_SYSTEM_NEUTRAL);
359 // delay expired (atfer 2 or 1 minute)
360 else if (GetStartDelayTime() <= 0 && !(m_Events & BG_STARTING_EVENT_4))
362 m_Events |= BG_STARTING_EVENT_4;
364 StartingEventOpenDoors();
366 SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_FOURTH], CHAT_MSG_BG_SYSTEM_NEUTRAL);
367 SetStatus(STATUS_IN_PROGRESS);
368 SetStartDelayTime(m_StartDelayTimes[BG_STARTING_EVENT_FOURTH]);
370 //remove preparation
371 if( isArena() )
373 //TODO : add arena sound PlaySoundToAll(SOUND_ARENA_START);
375 for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
376 if(Player *plr = objmgr.GetPlayer(itr->first))
377 plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
379 CheckArenaWinConditions();
381 else
384 PlaySoundToAll(SOUND_BG_START);
386 for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
387 if(Player* plr = objmgr.GetPlayer(itr->first))
388 plr->RemoveAurasDueToSpell(SPELL_PREPARATION);
389 //Announce BG starting
390 if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) )
392 sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, GetName(), GetMinLevel(), GetMaxLevel());
398 /*********************************************************/
399 /*** BATTLEGROUND ENDING SYSTEM ***/
400 /*********************************************************/
402 if(GetStatus() == STATUS_WAIT_LEAVE)
404 // remove all players from battleground after 2 minutes
405 m_EndTime += diff;
406 if(m_EndTime >= TIME_TO_AUTOREMOVE) // 2 minutes
408 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
410 m_RemovedPlayers[itr->first] = 1; // add to remove list (BG)
412 // do not change any battleground's private variables
418 void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O)
420 uint8 idx = GetTeamIndexByTeamId(TeamID);
421 m_TeamStartLocX[idx] = X;
422 m_TeamStartLocY[idx] = Y;
423 m_TeamStartLocZ[idx] = Z;
424 m_TeamStartLocO[idx] = O;
427 void BattleGround::SendPacketToAll(WorldPacket *packet)
429 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
431 Player *plr = objmgr.GetPlayer(itr->first);
432 if(plr)
433 plr->GetSession()->SendPacket(packet);
434 else
435 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
439 void BattleGround::SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *sender, bool self)
441 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
443 Player *plr = objmgr.GetPlayer(itr->first);
445 if(!plr)
447 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
448 continue;
451 if(!self && sender == plr)
452 continue;
454 uint32 team = itr->second.Team;
455 if(!team) team = plr->GetTeam();
457 if(team == TeamID)
458 plr->GetSession()->SendPacket(packet);
462 void BattleGround::PlaySoundToAll(uint32 SoundID)
464 WorldPacket data;
465 sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
466 SendPacketToAll(&data);
469 void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID)
471 WorldPacket data;
473 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
475 Player *plr = objmgr.GetPlayer(itr->first);
477 if(!plr)
479 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
480 continue;
483 uint32 team = itr->second.Team;
484 if(!team) team = plr->GetTeam();
486 if(team == TeamID)
488 sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
489 plr->GetSession()->SendPacket(&data);
494 void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID)
496 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
498 Player *plr = objmgr.GetPlayer(itr->first);
500 if(!plr)
502 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
503 continue;
506 uint32 team = itr->second.Team;
507 if(!team) team = plr->GetTeam();
509 if(team == TeamID)
510 plr->CastSpell(plr, SpellID, true);
514 void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID)
516 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
518 Player *plr = objmgr.GetPlayer(itr->first);
520 if(!plr)
522 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
523 continue;
526 uint32 team = itr->second.Team;
527 if(!team) team = plr->GetTeam();
529 if(team == TeamID)
530 UpdatePlayerScore(plr, SCORE_BONUS_HONOR, Honor);
534 void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID)
536 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
538 if(!factionEntry)
539 return;
541 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
543 Player *plr = objmgr.GetPlayer(itr->first);
545 if(!plr)
547 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
548 continue;
551 uint32 team = itr->second.Team;
552 if(!team) team = plr->GetTeam();
554 if(team == TeamID)
555 plr->ModifyFactionReputation(factionEntry, Reputation);
559 void BattleGround::UpdateWorldState(uint32 Field, uint32 Value)
561 WorldPacket data;
562 sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
563 SendPacketToAll(&data);
566 void BattleGround::UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player *Source)
568 WorldPacket data;
569 sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
570 Source->GetSession()->SendPacket(&data);
573 void BattleGround::EndBattleGround(uint32 winner)
575 this->RemoveFromBGFreeSlotQueue();
577 ArenaTeam * winner_arena_team = NULL;
578 ArenaTeam * loser_arena_team = NULL;
579 uint32 loser_rating = 0;
580 uint32 winner_rating = 0;
581 WorldPacket data;
582 int32 winmsg_id = 0;
584 if(winner == ALLIANCE)
586 winmsg_id = isBattleGround() ? LANG_BG_A_WINS : LANG_ARENA_GOLD_WINS;
588 PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound
590 SetWinner(WINNER_ALLIANCE);
592 else if(winner == HORDE)
594 winmsg_id = isBattleGround() ? LANG_BG_H_WINS : LANG_ARENA_GREEN_WINS;
596 PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound
598 SetWinner(WINNER_HORDE);
600 else
602 SetWinner(3);
605 SetStatus(STATUS_WAIT_LEAVE);
606 m_EndTime = 0;
608 // arena rating calculation
609 if(isArena() && isRated())
611 if(winner == ALLIANCE)
613 winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
614 loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
616 else if(winner == HORDE)
618 winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
619 loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
621 if(winner_arena_team && loser_arena_team)
623 loser_rating = loser_arena_team->GetStats().rating;
624 winner_rating = winner_arena_team->GetStats().rating;
625 int32 winner_change = winner_arena_team->WonAgainst(loser_rating);
626 int32 loser_change = loser_arena_team->LostAgainst(winner_rating);
627 sLog.outDebug("--- Winner rating: %u, Loser rating: %u, Winner change: %u, Losser change: %u ---", winner_rating, loser_rating, winner_change, loser_change);
628 if(winner == ALLIANCE)
630 SetArenaTeamRatingChangeForTeam(ALLIANCE, winner_change);
631 SetArenaTeamRatingChangeForTeam(HORDE, loser_change);
633 else
635 SetArenaTeamRatingChangeForTeam(HORDE, winner_change);
636 SetArenaTeamRatingChangeForTeam(ALLIANCE, loser_change);
639 else
641 SetArenaTeamRatingChangeForTeam(ALLIANCE, 0);
642 SetArenaTeamRatingChangeForTeam(HORDE, 0);
646 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
648 Player *plr = objmgr.GetPlayer(itr->first);
649 if(!plr)
651 sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
652 continue;
655 // should remove spirit of redemption
656 if(plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
657 plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
659 if(!plr->isAlive())
661 plr->ResurrectPlayer(1.0f);
662 plr->SpawnCorpseBones();
665 uint32 team = itr->second.Team;
666 if(!team) team = plr->GetTeam();
668 // per player calculation
669 if(isArena() && isRated() && winner_arena_team && loser_arena_team)
671 if(team == winner)
672 winner_arena_team->MemberWon(plr,loser_rating);
673 else
674 loser_arena_team->MemberLost(plr,winner_rating);
677 if(team == winner)
679 RewardMark(plr,ITEM_WINNER_COUNT);
680 UpdatePlayerScore(plr, SCORE_BONUS_HONOR, 20);
681 RewardQuest(plr);
683 else
685 RewardMark(plr,ITEM_LOSER_COUNT);
688 plr->CombatStopWithPets(true);
690 BlockMovement(plr);
692 sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
693 plr->GetSession()->SendPacket(&data);
695 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
696 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
697 plr->GetSession()->SendPacket(&data);
698 plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1);
701 if(isArena() && isRated() && winner_arena_team && loser_arena_team)
703 // update arena points only after increasing the player's match count!
704 //obsolete: winner_arena_team->UpdateArenaPointsHelper();
705 //obsolete: loser_arena_team->UpdateArenaPointsHelper();
706 // save the stat changes
707 winner_arena_team->SaveToDB();
708 loser_arena_team->SaveToDB();
709 // send updated arena team stats to players
710 // this way all arena team members will get notified, not only the ones who participated in this match
711 winner_arena_team->NotifyStatsChanged();
712 loser_arena_team->NotifyStatsChanged();
715 // inform invited players about the removal
716 sBattleGroundMgr.m_BattleGroundQueues[BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
718 if(winmsg_id)
719 SendMessageToAll(winmsg_id,CHAT_MSG_BG_SYSTEM_NEUTRAL);
722 uint32 BattleGround::GetBattlemasterEntry() const
724 switch(GetTypeID())
726 case BATTLEGROUND_AV: return 15972;
727 case BATTLEGROUND_WS: return 14623;
728 case BATTLEGROUND_AB: return 14879;
729 case BATTLEGROUND_EY: return 22516;
730 case BATTLEGROUND_NA: return 20200;
731 default: return 0;
735 void BattleGround::RewardMark(Player *plr,uint32 count)
737 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
738 if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
739 return;
741 BattleGroundMarks mark;
742 bool IsSpell;
743 switch(GetTypeID())
745 case BATTLEGROUND_AV:
746 IsSpell = true;
747 if(count == ITEM_WINNER_COUNT)
748 mark = SPELL_AV_MARK_WINNER;
749 else
750 mark = SPELL_AV_MARK_LOSER;
751 break;
752 case BATTLEGROUND_WS:
753 IsSpell = true;
754 if(count == ITEM_WINNER_COUNT)
755 mark = SPELL_WS_MARK_WINNER;
756 else
757 mark = SPELL_WS_MARK_LOSER;
758 break;
759 case BATTLEGROUND_AB:
760 IsSpell = true;
761 if(count == ITEM_WINNER_COUNT)
762 mark = SPELL_AB_MARK_WINNER;
763 else
764 mark = SPELL_AB_MARK_LOSER;
765 break;
766 case BATTLEGROUND_EY:
767 IsSpell = false;
768 mark = ITEM_EY_MARK_OF_HONOR;
769 break;
770 default:
771 return;
774 if(IsSpell)
775 plr->CastSpell(plr, mark, true);
776 else if ( objmgr.GetItemPrototype( mark ) )
778 ItemPosCountVec dest;
779 uint32 no_space_count = 0;
780 uint8 msg = plr->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, mark, count, &no_space_count );
781 if( msg != EQUIP_ERR_OK ) // convert to possible store amount
782 count -= no_space_count;
784 if( count != 0 && !dest.empty()) // can add some
785 if(Item* item = plr->StoreNewItem( dest, mark, true, 0))
786 plr->SendNewItem(item,count,false,true);
788 if(no_space_count > 0)
789 SendRewardMarkByMail(plr,mark,no_space_count);
793 void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count)
795 uint32 bmEntry = GetBattlemasterEntry();
796 if(!bmEntry)
797 return;
799 ItemPrototype const* markProto = objmgr.GetItemPrototype(mark);
800 if(!markProto)
801 return;
803 if(Item* markItem = Item::CreateItem(mark,count,plr))
805 // save new item before send
806 markItem->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
808 // item
809 MailItemsInfo mi;
810 mi.AddItem(markItem->GetGUIDLow(), markItem->GetEntry(), markItem);
812 // subject: item name
813 std::string subject = markProto->Name1;
814 int loc_idx = plr->GetSession()->GetSessionDbLocaleIndex();
815 if ( loc_idx >= 0 )
816 if(ItemLocale const *il = objmgr.GetItemLocale(markProto->ItemId))
817 if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty())
818 subject = il->Name[loc_idx];
820 // text
821 std::string textFormat = plr->GetSession()->GetMangosString(LANG_BG_MARK_BY_MAIL);
822 char textBuf[300];
823 snprintf(textBuf,300,textFormat.c_str(),GetName(),GetName());
824 uint32 itemTextId = objmgr.CreateItemText( textBuf );
826 WorldSession::SendMailTo(plr, MAIL_CREATURE, MAIL_STATIONERY_NORMAL, bmEntry, plr->GetGUIDLow(), subject, itemTextId , &mi, 0, 0, MAIL_CHECK_MASK_NONE);
830 void BattleGround::RewardQuest(Player *plr)
832 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
833 if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
834 return;
836 uint32 quest;
837 switch(GetTypeID())
839 case BATTLEGROUND_AV:
840 quest = SPELL_AV_QUEST_REWARD;
841 break;
842 case BATTLEGROUND_WS:
843 quest = SPELL_WS_QUEST_REWARD;
844 break;
845 case BATTLEGROUND_AB:
846 quest = SPELL_AB_QUEST_REWARD;
847 break;
848 case BATTLEGROUND_EY:
849 quest = SPELL_EY_QUEST_REWARD;
850 break;
851 default:
852 return;
855 plr->CastSpell(plr, quest, true);
858 void BattleGround::BlockMovement(Player *plr)
860 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()
863 void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket)
865 uint32 team = GetPlayerTeam(guid);
866 bool participant = false;
867 // Remove from lists/maps
868 std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.find(guid);
869 if(itr != m_Players.end())
871 UpdatePlayersCountByTeam(team, true); // -1 player
872 m_Players.erase(itr);
873 // check if the player was a participant of the match, or only entered through gm command (goname)
874 participant = true;
877 std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid);
878 if(itr2 != m_PlayerScores.end())
880 delete itr2->second; // delete player's score
881 m_PlayerScores.erase(itr2);
884 RemovePlayerFromResurrectQueue(guid);
886 Player *plr = objmgr.GetPlayer(guid);
888 // should remove spirit of redemption
889 if(plr && plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
890 plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
892 if(plr && !plr->isAlive()) // resurrect on exit
894 plr->ResurrectPlayer(1.0f);
895 plr->SpawnCorpseBones();
898 RemovePlayer(plr, guid); // BG subclass specific code
900 if(plr)
902 plr->ClearAfkReports();
904 if(participant) // if the player was a match participant, remove auras, calc rating, update queue
906 if(!team) team = plr->GetTeam();
908 BattleGroundTypeId bgTypeId = GetTypeID();
909 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
910 // if arena, remove the specific arena auras
911 if(isArena())
913 plr->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out
914 bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing)
916 // summon old pet if there was one and there isn't a current pet
917 if(!plr->GetPet() && plr->GetTemporaryUnsummonedPetNumber())
919 Pet* NewPet = new Pet;
920 if(!NewPet->LoadPetFromDB(plr, 0, (plr)->GetTemporaryUnsummonedPetNumber(), true))
921 delete NewPet;
923 (plr)->SetTemporaryUnsummonedPetNumber(0);
926 if(isRated() && GetStatus() == STATUS_IN_PROGRESS)
928 //left a rated match while the encounter was in progress, consider as loser
929 ArenaTeam * winner_arena_team = 0;
930 ArenaTeam * loser_arena_team = 0;
931 if(team == HORDE)
933 winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
934 loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
936 else
938 winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
939 loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
941 if(winner_arena_team && loser_arena_team)
943 loser_arena_team->MemberLost(plr,winner_arena_team->GetRating());
948 WorldPacket data;
949 if(SendPacket)
951 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, team, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0);
952 plr->GetSession()->SendPacket(&data);
955 // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
956 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
958 DecreaseInvitedCount(team);
959 //we should update battleground queue, but only if bg isn't ending
960 if (GetStatus() < STATUS_WAIT_LEAVE)
961 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueId());
963 Group * group = plr->GetGroup();
964 // remove from raid group if exist
965 if(group && group == GetBgRaid(team))
967 if(!group->RemoveMember(guid, 0)) // group was disbanded
969 SetBgRaid(team, NULL);
970 delete group;
974 // Let others know
975 sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);
976 SendPacketToTeam(team, &data, plr, false);
979 // Do next only if found in battleground
980 plr->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG.
981 // reset destination bg team
982 plr->SetBGTeam(0);
984 if(Transport)
985 plr->TeleportTo(plr->GetBattleGroundEntryPoint());
987 // Log
988 sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName());
991 if(!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
993 // if no players left AND no invitees left, set this bg to delete in next update
994 // direct deletion could cause crashes
995 m_SetDeleteThis = true;
996 // return to prevent addition to freeslotqueue
997 return;
1000 // a player exited the battleground, so there are free slots. add to queue
1001 this->AddToBGFreeSlotQueue();
1004 // this method is called when no players remains in battleground
1005 void BattleGround::Reset()
1007 SetQueueId(QUEUE_ID_MAX_LEVEL_19);
1008 SetWinner(WINNER_NONE);
1009 SetStatus(STATUS_WAIT_QUEUE);
1010 SetStartTime(0);
1011 SetEndTime(0);
1012 SetLastResurrectTime(0);
1013 SetArenaType(0);
1014 SetRated(false);
1016 m_Events = 0;
1018 if (m_InvitedAlliance > 0 || m_InvitedHorde > 0)
1019 sLog.outError("BattleGround system ERROR: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance, m_InvitedHorde);
1021 m_InvitedAlliance = 0;
1022 m_InvitedHorde = 0;
1023 m_InBGFreeSlotQueue = false;
1025 m_Players.clear();
1026 m_PlayerScores.clear();
1029 void BattleGround::StartBattleGround()
1031 ///this method should spawn spirit guides and so on
1032 SetStartTime(0);
1034 SetLastResurrectTime(0);
1037 void BattleGround::AddPlayer(Player *plr)
1039 // score struct must be created in inherited class
1041 uint64 guid = plr->GetGUID();
1042 uint32 team = plr->GetBGTeam();
1044 BattleGroundPlayer bp;
1045 bp.LastOnlineTime = 0;
1046 bp.Team = team;
1048 // Add to list/maps
1049 m_Players[guid] = bp;
1051 UpdatePlayersCountByTeam(team, false); // +1 player
1053 WorldPacket data;
1054 sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr);
1055 SendPacketToTeam(team, &data, plr, false);
1057 // add arena specific auras
1058 if(isArena())
1060 plr->RemoveArenaSpellCooldowns();
1061 plr->RemoveArenaAuras();
1062 plr->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT);
1063 if(team == ALLIANCE) // gold
1065 if(plr->GetTeam() == HORDE)
1066 plr->CastSpell(plr, SPELL_HORDE_GOLD_FLAG,true);
1067 else
1068 plr->CastSpell(plr, SPELL_ALLIANCE_GOLD_FLAG,true);
1070 else // green
1072 if(plr->GetTeam() == HORDE)
1073 plr->CastSpell(plr, SPELL_HORDE_GREEN_FLAG,true);
1074 else
1075 plr->CastSpell(plr, SPELL_ALLIANCE_GREEN_FLAG,true);
1078 plr->DestroyConjuredItems(true);
1080 Pet* pet = plr->GetPet();
1081 if(pet)
1083 if(pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET)
1085 (plr)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber());
1086 (plr)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));
1088 (plr)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);
1090 else
1091 (plr)->SetTemporaryUnsummonedPetNumber(0);
1093 if(GetStatus() == STATUS_WAIT_JOIN) // not started yet
1095 plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);
1097 plr->SetHealth(plr->GetMaxHealth());
1098 plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA));
1101 else
1103 if(GetStatus() == STATUS_WAIT_JOIN) // not started yet
1104 plr->CastSpell(plr, SPELL_PREPARATION, true); // reduces all mana cost of spells.
1107 // setup BG group membership
1108 PlayerRelogin(plr);
1109 AddOrSetPlayerToCorrectBgGroup(plr, guid, team);
1111 // Log
1112 sLog.outDetail("BATTLEGROUND: Player %s joined the battle.", plr->GetName());
1115 /* this method adds player to his team's bg group, or sets his correct group if player is already in bg group */
1116 void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid, uint32 team)
1118 Group* group = GetBgRaid(team);
1119 if(!group) // first player joined
1121 group = new Group;
1122 SetBgRaid(team, group);
1123 group->Create(plr_guid, plr->GetName());
1125 else // raid already exist
1127 if(group->IsMember(plr_guid))
1129 uint8 subgroup = group->GetMemberGroup(plr_guid);
1130 plr->SetGroup(group, subgroup);
1132 else
1133 GetBgRaid(team)->AddMember(plr_guid, plr->GetName());
1137 // This method should be called when player logs out from running battleground
1138 void BattleGround::EventPlayerLoggedOut(Player* player)
1140 if( GetStatus() == STATUS_IN_PROGRESS )
1142 if( isBattleGround() )
1143 EventPlayerDroppedFlag(player);
1144 else
1145 CheckArenaWinConditions();
1149 /* This method should be called only once ... it adds pointer to queue */
1150 void BattleGround::AddToBGFreeSlotQueue()
1152 // make sure to add only once
1153 if(!m_InBGFreeSlotQueue && isBattleGround())
1155 sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);
1156 m_InBGFreeSlotQueue = true;
1160 /* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
1161 void BattleGround::RemoveFromBGFreeSlotQueue()
1163 // set to be able to re-add if needed
1164 m_InBGFreeSlotQueue = false;
1165 // uncomment this code when battlegrounds will work like instances
1166 for (BGFreeSlotQueueType::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)
1168 if ((*itr)->GetInstanceID() == m_InstanceID)
1170 sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr);
1171 return;
1176 // get the number of free slots for team
1177 // returns the number how many players can join battleground to MaxPlayersPerTeam
1178 uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const
1180 //return free slot count to MaxPlayerPerTeam
1181 if (GetStatus() == STATUS_WAIT_JOIN || GetStatus() == STATUS_IN_PROGRESS)
1182 return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
1184 return 0;
1187 bool BattleGround::HasFreeSlots() const
1189 return GetPlayersSize() < GetMaxPlayers();
1192 void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
1194 //this procedure is called from virtual function implemented in bg subclass
1195 std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
1197 if(itr == m_PlayerScores.end()) // player not found...
1198 return;
1200 switch(type)
1202 case SCORE_KILLING_BLOWS: // Killing blows
1203 itr->second->KillingBlows += value;
1204 break;
1205 case SCORE_DEATHS: // Deaths
1206 itr->second->Deaths += value;
1207 break;
1208 case SCORE_HONORABLE_KILLS: // Honorable kills
1209 itr->second->HonorableKills += value;
1210 break;
1211 case SCORE_BONUS_HONOR: // Honor bonus
1212 // do not add honor in arenas
1213 if(isBattleGround())
1215 // reward honor instantly
1216 if(Source->RewardHonor(NULL, 1, value))
1217 itr->second->BonusHonor += value;
1219 break;
1220 //used only in EY, but in MSG_PVP_LOG_DATA opcode
1221 case SCORE_DAMAGE_DONE: // Damage Done
1222 itr->second->DamageDone += value;
1223 break;
1224 case SCORE_HEALING_DONE: // Healing Done
1225 itr->second->HealingDone += value;
1226 break;
1227 default:
1228 sLog.outError("BattleGround: Unknown player score type %u", type);
1229 break;
1233 void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid)
1235 m_ReviveQueue[npc_guid].push_back(player_guid);
1237 Player *plr = objmgr.GetPlayer(player_guid);
1238 if(!plr)
1239 return;
1241 plr->CastSpell(plr, SPELL_WAITING_FOR_RESURRECT, true);
1242 SpellEntry const *spellInfo = sSpellStore.LookupEntry( SPELL_WAITING_FOR_RESURRECT );
1243 if(spellInfo)
1245 Aura *Aur = CreateAura(spellInfo, 0, NULL, plr);
1246 plr->AddAura(Aur);
1250 void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid)
1252 for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
1254 for(std::vector<uint64>::iterator itr2 =(itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
1256 if(*itr2 == player_guid)
1258 (itr->second).erase(itr2);
1260 Player *plr = objmgr.GetPlayer(player_guid);
1261 if(!plr)
1262 return;
1264 plr->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
1266 return;
1272 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)
1274 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1275 if(!map)
1276 return false;
1278 // must be created this way, adding to godatamap would add it to the base map of the instance
1279 // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
1280 // so we must create it specific for this instance
1281 GameObject * go = new GameObject;
1282 if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, map,
1283 PHASEMASK_NORMAL, x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,1))
1285 sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);
1286 sLog.outError("Cannot create gameobject template %u! BattleGround not created!", entry);
1287 delete go;
1288 return false;
1291 uint32 guid = go->GetGUIDLow();
1293 // without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
1294 // 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
1295 GameObjectData& data = objmgr.NewGOData(guid);
1297 data.id = entry;
1298 data.mapid = GetMapId();
1299 data.posX = x;
1300 data.posY = y;
1301 data.posZ = z;
1302 data.orientation = o;
1303 data.rotation0 = rotation0;
1304 data.rotation1 = rotation1;
1305 data.rotation2 = rotation2;
1306 data.rotation3 = rotation3;
1307 data.spawntimesecs = respawnTime;
1308 data.spawnMask = 1;
1309 data.animprogress = 100;
1310 data.go_state = 1;
1312 // add to world, so it can be later looked up from HashMapHolder
1313 go->AddToWorld();
1314 m_BgObjects[type] = go->GetGUID();
1315 return true;
1318 //some doors aren't despawned so we cannot handle their closing in gameobject::update()
1319 //it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
1320 void BattleGround::DoorClose(uint32 type)
1322 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1323 if(obj)
1325 //if doors are open, close it
1326 if( obj->getLootState() == GO_ACTIVATED && !obj->GetGoState() )
1328 //change state to allow door to be closed
1329 obj->SetLootState(GO_READY);
1330 obj->UseDoorOrButton(RESPAWN_ONE_DAY);
1333 else
1335 sLog.outError("BattleGround: Door object not found (cannot close doors)");
1339 void BattleGround::DoorOpen(uint32 type)
1341 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1342 if(obj)
1344 //change state to be sure they will be opened
1345 obj->SetLootState(GO_READY);
1346 obj->UseDoorOrButton(RESPAWN_ONE_DAY);
1348 else
1350 sLog.outError("BattleGround: Door object not found! - doors will be closed.");
1354 void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
1356 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1357 if(!map)
1358 return;
1359 if( respawntime == 0 )
1361 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1362 if(obj)
1364 //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
1365 if( obj->getLootState() == GO_JUST_DEACTIVATED )
1366 obj->SetLootState(GO_READY);
1367 obj->SetRespawnTime(0);
1368 map->Add(obj);
1371 else
1373 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1374 if(obj)
1376 map->Add(obj);
1377 obj->SetRespawnTime(respawntime);
1378 obj->SetLootState(GO_JUST_DEACTIVATED);
1383 Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime)
1385 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1386 if(!map)
1387 return NULL;
1389 Creature* pCreature = new Creature;
1390 if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, PHASEMASK_NORMAL, entry, teamval))
1392 sLog.outError("Can't create creature entry: %u",entry);
1393 delete pCreature;
1394 return NULL;
1397 pCreature->Relocate(x, y, z, o);
1399 if(!pCreature->IsPositionValid())
1401 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());
1402 return NULL;
1405 pCreature->AIM_Initialize();
1407 //pCreature->SetDungeonDifficulty(0);
1409 map->Add(pCreature);
1410 m_BgCreatures[type] = pCreature->GetGUID();
1412 return pCreature;
1415 void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)
1417 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceId());
1418 if(!map)
1419 return false;
1421 if(respawntime == 0)
1423 Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1424 if(obj)
1426 //obj->Respawn(); // bugged
1427 obj->SetRespawnTime(0);
1428 objmgr.SaveCreatureRespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);
1429 map->Add(obj);
1432 else
1434 Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1435 if(obj)
1437 obj->setDeathState(DEAD);
1438 obj->SetRespawnTime(respawntime);
1439 map->Add(obj);
1444 bool BattleGround::DelCreature(uint32 type)
1446 if(!m_BgCreatures[type])
1447 return true;
1449 Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1450 if(!cr)
1452 sLog.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures[type]));
1453 return false;
1455 cr->CleanupsBeforeDelete();
1456 cr->AddObjectToRemoveList();
1457 m_BgCreatures[type] = 0;
1458 return true;
1461 bool BattleGround::DelObject(uint32 type)
1463 if(!m_BgObjects[type])
1464 return true;
1466 GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1467 if(!obj)
1469 sLog.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects[type]));
1470 return false;
1472 obj->SetRespawnTime(0); // not save respawn time
1473 obj->Delete();
1474 m_BgObjects[type] = 0;
1475 return true;
1478 bool BattleGround::AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team)
1480 uint32 entry = 0;
1482 if(team == ALLIANCE)
1483 entry = 13116;
1484 else
1485 entry = 13117;
1487 Creature* pCreature = AddCreature(entry,type,team,x,y,z,o);
1488 if(!pCreature)
1490 sLog.outError("Can't create Spirit guide. BattleGround not created!");
1491 EndNow();
1492 return false;
1495 pCreature->setDeathState(DEAD);
1497 pCreature->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, pCreature->GetGUID());
1498 // aura
1499 pCreature->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL);
1500 //pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
1501 //pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
1502 //pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
1503 // casting visual effect
1504 pCreature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_SPIRIT_HEAL_CHANNEL);
1505 // correct cast speed
1506 pCreature->SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
1508 //pCreature->CastSpell(pCreature, SPELL_SPIRIT_HEAL_CHANNEL, true);
1510 return true;
1513 void BattleGround::SendMessageToAll(int32 entry, ChatMsg type, Player const* source)
1515 MaNGOS::BattleGroundChatBuilder bg_builder(type, entry, source);
1516 MaNGOS::LocalizedPacketDo<MaNGOS::BattleGroundChatBuilder> bg_do(bg_builder);
1517 BroadcastWorker(bg_do);
1520 void BattleGround::PSendMessageToAll(int32 entry, ChatMsg type, Player const* source, ...)
1522 va_list ap;
1523 va_start(ap, type);
1525 MaNGOS::BattleGroundChatBuilder bg_builder(type, entry, source, &ap);
1526 MaNGOS::LocalizedPacketDo<MaNGOS::BattleGroundChatBuilder> bg_do(bg_builder);
1527 BroadcastWorker(bg_do);
1529 va_end(ap);
1532 void BattleGround::EndNow()
1534 RemoveFromBGFreeSlotQueue();
1535 SetStatus(STATUS_WAIT_LEAVE);
1536 SetEndTime(TIME_TO_AUTOREMOVE);
1537 // inform invited players about the removal
1538 sBattleGroundMgr.m_BattleGroundQueues[BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
1541 // Battleground messages are localized using the dbc lang, they are not client language dependent
1542 const char *BattleGround::GetMangosString(int32 entry)
1544 // FIXME: now we have different DBC locales and need localized message for each target client
1545 return objmgr.GetMangosStringForDBCLocale(entry);
1549 important notice:
1550 buffs aren't spawned/despawned when players captures anything
1551 buffs are in their positions when battleground starts
1553 void BattleGround::HandleTriggerBuff(uint64 const& go_guid)
1555 GameObject *obj = HashMapHolder<GameObject>::Find(go_guid);
1556 if(!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned())
1557 return;
1559 //change buff type, when buff is used:
1560 int32 index = m_BgObjects.size() - 1;
1561 while (index >= 0 && m_BgObjects[index] != go_guid)
1562 index--;
1563 if (index < 0)
1565 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());
1566 return;
1569 //randomly select new buff
1570 uint8 buff = urand(0, 2);
1571 uint32 entry = obj->GetEntry();
1572 if( m_BuffChange && entry != Buff_Entries[buff] )
1574 //despawn current buff
1575 SpawnBGObject(index, RESPAWN_ONE_DAY);
1576 //set index for new one
1577 for (uint8 currBuffTypeIndex = 0; currBuffTypeIndex < 3; ++currBuffTypeIndex)
1578 if( entry == Buff_Entries[currBuffTypeIndex] )
1580 index -= currBuffTypeIndex;
1581 index += buff;
1585 SpawnBGObject(index, BUFF_RESPAWN_TIME);
1588 void BattleGround::HandleKillPlayer( Player *player, Player *killer )
1590 //keep in mind that for arena this will have to be changed a bit
1592 // add +1 deaths
1593 UpdatePlayerScore(player, SCORE_DEATHS, 1);
1595 // add +1 kills to group and +1 killing_blows to killer
1596 if( killer )
1598 UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);
1599 UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1);
1601 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1603 Player *plr = objmgr.GetPlayer(itr->first);
1605 if(!plr || plr == killer)
1606 continue;
1608 if( plr->GetTeam() == killer->GetTeam() && plr->IsAtGroupRewardDistance(player) )
1609 UpdatePlayerScore(plr, SCORE_HONORABLE_KILLS, 1);
1613 // to be able to remove insignia
1614 player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
1617 // return the player's team based on battlegroundplayer info
1618 // used in same faction arena matches mainly
1619 uint32 BattleGround::GetPlayerTeam(uint64 guid)
1621 std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.find(guid);
1622 if(itr!=m_Players.end())
1623 return itr->second.Team;
1624 return 0;
1627 bool BattleGround::IsPlayerInBattleGround(uint64 guid)
1629 std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.find(guid);
1630 if(itr!=m_Players.end())
1631 return true;
1632 return false;
1635 void BattleGround::PlayerRelogin(Player* plr)
1637 if(GetStatus() != STATUS_WAIT_LEAVE)
1638 return;
1640 WorldPacket data;
1641 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
1643 BlockMovement(plr);
1645 sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
1646 plr->GetSession()->SendPacket(&data);
1648 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
1649 plr->GetSession()->SendPacket(&data);
1652 uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const
1654 int count = 0;
1655 for(std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1657 if(itr->second.Team == Team)
1659 Player * pl = objmgr.GetPlayer(itr->first);
1660 if(pl && pl->isAlive())
1661 ++count;
1664 return count;
1667 void BattleGround::CheckArenaWinConditions()
1669 if( !GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE) )
1670 EndBattleGround(HORDE);
1671 else if( GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE) )
1672 EndBattleGround(ALLIANCE);
1675 void BattleGround::SetBgRaid( uint32 TeamID, Group *bg_raid )
1677 Group* &old_raid = TeamID == ALLIANCE ? m_BgRaids[BG_TEAM_ALLIANCE] : m_BgRaids[BG_TEAM_HORDE];
1678 if(old_raid) old_raid->SetBattlegroundGroup(NULL);
1679 if(bg_raid) bg_raid->SetBattlegroundGroup(this);
1680 old_raid = bg_raid;
1683 WorldSafeLocsEntry const* BattleGround::GetClosestGraveYard( Player* player )
1685 return objmgr.GetClosestGraveYard( player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetMapId(), player->GetTeam() );