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
21 #include "BattleGround.h"
22 #include "BattleGroundMgr.h"
24 #include "MapManager.h"
26 #include "SpellAuras.h"
27 #include "ArenaTeam.h"
30 #include "ObjectMgr.h"
31 #include "WorldPacket.h"
34 #include "GridNotifiersImpl.h"
38 class BattleGroundChatBuilder
41 BattleGroundChatBuilder(ChatMsg msgtype
, int32 textId
, Player
const* source
, va_list* args
= NULL
)
42 : i_msgtype(msgtype
), i_textId(textId
), i_source(source
), i_args(args
) {}
43 void operator()(WorldPacket
& data
, int32 loc_idx
)
45 char const* text
= objmgr
.GetMangosString(i_textId
,loc_idx
);
49 // we need copy va_list before use or original va_list will corrupted
54 vsnprintf(str
,2048,text
, ap
);
57 do_helper(data
,&str
[0]);
63 void do_helper(WorldPacket
& data
, char const* text
)
65 uint64 target_guid
= i_source
? i_source
->GetGUID() : 0;
67 data
<< uint8(i_msgtype
);
68 data
<< uint32(LANG_UNIVERSAL
);
69 data
<< uint64(target_guid
); // there 0 for BG messages
70 data
<< uint32(0); // can be chat msg group or something
71 data
<< uint64(target_guid
);
72 data
<< uint32(strlen(text
)+1);
74 data
<< uint8(i_source
? i_source
->chatTag() : uint8(0));
79 Player
const* i_source
;
83 class BattleGround2ChatBuilder
86 BattleGround2ChatBuilder(ChatMsg msgtype
, int32 textId
, Player
const* source
, int32 arg1
, int32 arg2
)
87 : i_msgtype(msgtype
), i_textId(textId
), i_source(source
), i_arg1(arg1
), i_arg2(arg2
) {}
88 void operator()(WorldPacket
& data
, int32 loc_idx
)
90 char const* text
= objmgr
.GetMangosString(i_textId
,loc_idx
);
91 char const* arg1str
= i_arg1
? objmgr
.GetMangosString(i_arg1
,loc_idx
) : "";
92 char const* arg2str
= i_arg2
? objmgr
.GetMangosString(i_arg2
,loc_idx
) : "";
95 snprintf(str
,2048,text
, arg1str
, arg2str
);
97 uint64 target_guid
= i_source
? i_source
->GetGUID() : 0;
99 data
<< uint8(i_msgtype
);
100 data
<< uint32(LANG_UNIVERSAL
);
101 data
<< uint64(target_guid
); // there 0 for BG messages
102 data
<< uint32(0); // can be chat msg group or something
103 data
<< uint64(target_guid
);
104 data
<< uint32(strlen(str
)+1);
106 data
<< uint8(i_source
? i_source
->chatTag() : uint8(0));
112 Player
const* i_source
;
116 } // namespace MaNGOS
119 void BattleGround::BroadcastWorker(Do
& _do
)
121 for(BattleGroundPlayerMap::const_iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
122 if (Player
*plr
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
)))
126 BattleGround::BattleGround()
128 m_TypeID
= BattleGroundTypeId(0);
130 m_Status
= STATUS_NONE
;
131 m_ClientInstanceID
= 0;
133 m_LastResurrectTime
= 0;
134 m_QueueId
= QUEUE_ID_MAX_LEVEL_19
;
135 m_InvitedAlliance
= 0;
143 m_BuffChange
= false;
147 m_InBGFreeSlotQueue
= false;
148 m_SetDeleteThis
= false;
150 m_MaxPlayersPerTeam
= 0;
152 m_MinPlayersPerTeam
= 0;
157 m_TeamStartLocX
[BG_TEAM_ALLIANCE
] = 0;
158 m_TeamStartLocX
[BG_TEAM_HORDE
] = 0;
160 m_TeamStartLocY
[BG_TEAM_ALLIANCE
] = 0;
161 m_TeamStartLocY
[BG_TEAM_HORDE
] = 0;
163 m_TeamStartLocZ
[BG_TEAM_ALLIANCE
] = 0;
164 m_TeamStartLocZ
[BG_TEAM_HORDE
] = 0;
166 m_TeamStartLocO
[BG_TEAM_ALLIANCE
] = 0;
167 m_TeamStartLocO
[BG_TEAM_HORDE
] = 0;
169 m_ArenaTeamIds
[BG_TEAM_ALLIANCE
] = 0;
170 m_ArenaTeamIds
[BG_TEAM_HORDE
] = 0;
172 m_ArenaTeamRatingChanges
[BG_TEAM_ALLIANCE
] = 0;
173 m_ArenaTeamRatingChanges
[BG_TEAM_HORDE
] = 0;
175 m_BgRaids
[BG_TEAM_ALLIANCE
] = NULL
;
176 m_BgRaids
[BG_TEAM_HORDE
] = NULL
;
178 m_PlayersCount
[BG_TEAM_ALLIANCE
] = 0;
179 m_PlayersCount
[BG_TEAM_HORDE
] = 0;
181 m_PrematureCountDown
= false;
182 m_PrematureCountDown
= 0;
184 m_StartDelayTimes
[BG_STARTING_EVENT_FIRST
] = BG_START_DELAY_2M
;
185 m_StartDelayTimes
[BG_STARTING_EVENT_SECOND
] = BG_START_DELAY_1M
;
186 m_StartDelayTimes
[BG_STARTING_EVENT_THIRD
] = BG_START_DELAY_30S
;
187 m_StartDelayTimes
[BG_STARTING_EVENT_FOURTH
] = BG_START_DELAY_NONE
;
188 //we must set to some default existing values
189 m_StartMessageIds
[BG_STARTING_EVENT_FIRST
] = LANG_BG_WS_START_TWO_MINUTES
;
190 m_StartMessageIds
[BG_STARTING_EVENT_SECOND
] = LANG_BG_WS_START_ONE_MINUTE
;
191 m_StartMessageIds
[BG_STARTING_EVENT_THIRD
] = LANG_BG_WS_START_HALF_MINUTE
;
192 m_StartMessageIds
[BG_STARTING_EVENT_FOURTH
] = LANG_BG_WS_HAS_BEGUN
;
195 BattleGround::~BattleGround()
197 // remove objects and creatures
198 // (this is done automatically in mapmanager update, when the instance is reset after the reset time)
199 int size
= m_BgCreatures
.size();
200 for(int i
= 0; i
< size
; ++i
)
204 size
= m_BgObjects
.size();
205 for(int i
= 0; i
< size
; ++i
)
210 if(GetInstanceID()) // not spam by useless queries in case BG templates
212 // delete creature and go respawn times
213 WorldDatabase
.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'",GetInstanceID());
214 WorldDatabase
.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'",GetInstanceID());
215 // delete instance from db
216 CharacterDatabase
.PExecute("DELETE FROM instance WHERE id = '%u'",GetInstanceID());
217 // remove from battlegrounds
220 sBattleGroundMgr
.RemoveBattleGround(GetInstanceID(), GetTypeID());
222 if (Map
* map
= MapManager::Instance().FindMap(GetMapId(), GetInstanceID()))
223 if (map
->IsBattleGroundOrArena())
224 ((BattleGroundMap
*)map
)->SetUnload();
225 // remove from bg free slot queue
226 this->RemoveFromBGFreeSlotQueue();
229 void BattleGround::Update(uint32 diff
)
231 if (!GetPlayersSize() && !GetReviveQueueSize())
235 // remove offline players from bg after 5 minutes
236 if (!m_OfflineQueue
.empty())
238 BattleGroundPlayerMap::iterator itr
= m_Players
.find(*(m_OfflineQueue
.begin()));
239 if (itr
!= m_Players
.end())
241 if (itr
->second
.OfflineRemoveTime
<= sWorld
.GetGameTime())
243 RemovePlayerAtLeave(itr
->first
, true, true);// remove player from BG
244 m_OfflineQueue
.pop_front(); // remove from offline queue
245 //do not use itr for anything, because it is erased in RemovePlayerAtLeave()
250 /*********************************************************/
251 /*** BATTLEGROUND RESSURECTION SYSTEM ***/
252 /*********************************************************/
254 //this should be handled by spell system
255 m_LastResurrectTime
+= diff
;
256 if (m_LastResurrectTime
>= RESURRECTION_INTERVAL
)
258 if (GetReviveQueueSize())
260 for(std::map
<uint64
, std::vector
<uint64
> >::iterator itr
= m_ReviveQueue
.begin(); itr
!= m_ReviveQueue
.end(); ++itr
)
263 for(std::vector
<uint64
>::const_iterator itr2
= (itr
->second
).begin(); itr2
!= (itr
->second
).end(); ++itr2
)
265 Player
*plr
= objmgr
.GetPlayer(*itr2
);
269 if (!sh
&& plr
->IsInWorld())
271 sh
= plr
->GetMap()->GetCreature(itr
->first
);
272 // only for visual effect
274 sh
->CastSpell(sh
, SPELL_SPIRIT_HEAL
, true); // Spirit Heal, effect 117
277 plr
->CastSpell(plr
, SPELL_RESURRECTION_VISUAL
, true); // Resurrection visual
278 m_ResurrectQueue
.push_back(*itr2
);
280 (itr
->second
).clear();
283 m_ReviveQueue
.clear();
284 m_LastResurrectTime
= 0;
287 // queue is clear and time passed, just update last resurrection time
288 m_LastResurrectTime
= 0;
290 else if (m_LastResurrectTime
> 500) // Resurrect players only half a second later, to see spirit heal effect on NPC
292 for(std::vector
<uint64
>::const_iterator itr
= m_ResurrectQueue
.begin(); itr
!= m_ResurrectQueue
.end(); ++itr
)
294 Player
*plr
= objmgr
.GetPlayer(*itr
);
297 plr
->ResurrectPlayer(1.0f
);
298 plr
->CastSpell(plr
, SPELL_SPIRIT_HEAL_MANA
, true);
299 ObjectAccessor::Instance().ConvertCorpseForPlayer(*itr
);
301 m_ResurrectQueue
.clear();
304 /*********************************************************/
305 /*** BATTLEGROUND BALLANCE SYSTEM ***/
306 /*********************************************************/
308 // if less then minimum players are in on one side, then start premature finish timer
309 if (GetStatus() == STATUS_IN_PROGRESS
&& !isArena() && sBattleGroundMgr
.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE
) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE
) < GetMinPlayersPerTeam()))
311 if (!m_PrematureCountDown
)
313 m_PrematureCountDown
= true;
314 m_PrematureCountDownTimer
= sBattleGroundMgr
.GetPrematureFinishTime();
316 else if (m_PrematureCountDownTimer
< diff
)
320 if (GetPlayersCountByTeam(ALLIANCE
) >= GetMinPlayersPerTeam())
322 else if (GetPlayersCountByTeam(HORDE
) >= GetMinPlayersPerTeam())
325 EndBattleGround(winner
);
326 m_PrematureCountDown
= false;
330 uint32 newtime
= m_PrematureCountDownTimer
- diff
;
331 // announce every minute
332 if (newtime
> (MINUTE
* IN_MILISECONDS
))
334 if (newtime
/ (MINUTE
* IN_MILISECONDS
) != m_PrematureCountDownTimer
/ (MINUTE
* IN_MILISECONDS
))
335 PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING
, CHAT_MSG_SYSTEM
, NULL
, (uint32
)(m_PrematureCountDownTimer
/ (MINUTE
* IN_MILISECONDS
)));
339 //announce every 15 seconds
340 if (newtime
/ (15 * IN_MILISECONDS
) != m_PrematureCountDownTimer
/ (15 * IN_MILISECONDS
))
341 PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS
, CHAT_MSG_SYSTEM
, NULL
, (uint32
)(m_PrematureCountDownTimer
/ IN_MILISECONDS
));
343 m_PrematureCountDownTimer
= newtime
;
346 else if (m_PrematureCountDown
)
347 m_PrematureCountDown
= false;
349 /*********************************************************/
350 /*** BATTLEGROUND STARTING SYSTEM ***/
351 /*********************************************************/
353 if (GetStatus() == STATUS_WAIT_JOIN
&& GetPlayersSize())
355 ModifyStartDelayTime(diff
);
357 if (!(m_Events
& BG_STARTING_EVENT_1
))
359 m_Events
|= BG_STARTING_EVENT_1
;
361 // setup here, only when at least one player has ported to the map
362 if (!SetupBattleGround())
368 StartingEventCloseDoors();
369 SetStartDelayTime(m_StartDelayTimes
[BG_STARTING_EVENT_FIRST
]);
370 //first start warning - 2 or 1 minute
371 SendMessageToAll(m_StartMessageIds
[BG_STARTING_EVENT_FIRST
], CHAT_MSG_BG_SYSTEM_NEUTRAL
);
373 // After 1 minute or 30 seconds, warning is signalled
374 else if (GetStartDelayTime() <= m_StartDelayTimes
[BG_STARTING_EVENT_SECOND
] && !(m_Events
& BG_STARTING_EVENT_2
))
376 m_Events
|= BG_STARTING_EVENT_2
;
377 SendMessageToAll(m_StartMessageIds
[BG_STARTING_EVENT_SECOND
], CHAT_MSG_BG_SYSTEM_NEUTRAL
);
379 // After 30 or 15 seconds, warning is signalled
380 else if (GetStartDelayTime() <= m_StartDelayTimes
[BG_STARTING_EVENT_THIRD
] && !(m_Events
& BG_STARTING_EVENT_3
))
382 m_Events
|= BG_STARTING_EVENT_3
;
383 SendMessageToAll(m_StartMessageIds
[BG_STARTING_EVENT_THIRD
], CHAT_MSG_BG_SYSTEM_NEUTRAL
);
385 // delay expired (atfer 2 or 1 minute)
386 else if (GetStartDelayTime() <= 0 && !(m_Events
& BG_STARTING_EVENT_4
))
388 m_Events
|= BG_STARTING_EVENT_4
;
390 StartingEventOpenDoors();
392 SendMessageToAll(m_StartMessageIds
[BG_STARTING_EVENT_FOURTH
], CHAT_MSG_BG_SYSTEM_NEUTRAL
);
393 SetStatus(STATUS_IN_PROGRESS
);
394 SetStartDelayTime(m_StartDelayTimes
[BG_STARTING_EVENT_FOURTH
]);
399 //TODO : add arena sound PlaySoundToAll(SOUND_ARENA_START);
401 for(BattleGroundPlayerMap::const_iterator itr
= GetPlayers().begin(); itr
!= GetPlayers().end(); ++itr
)
402 if (Player
*plr
= objmgr
.GetPlayer(itr
->first
))
403 plr
->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION
);
405 CheckArenaWinConditions();
410 PlaySoundToAll(SOUND_BG_START
);
412 for(BattleGroundPlayerMap::const_iterator itr
= GetPlayers().begin(); itr
!= GetPlayers().end(); ++itr
)
413 if (Player
* plr
= objmgr
.GetPlayer(itr
->first
))
414 plr
->RemoveAurasDueToSpell(SPELL_PREPARATION
);
415 //Announce BG starting
416 if (sWorld
.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE
))
418 sWorld
.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD
, GetName(), GetMinLevel(), GetMaxLevel());
424 /*********************************************************/
425 /*** BATTLEGROUND ENDING SYSTEM ***/
426 /*********************************************************/
428 if (GetStatus() == STATUS_WAIT_LEAVE
)
430 // remove all players from battleground after 2 minutes
435 BattleGroundPlayerMap::iterator itr
, next
;
436 for(itr
= m_Players
.begin(); itr
!= m_Players
.end(); itr
= next
)
440 //itr is erased here!
441 RemovePlayerAtLeave(itr
->first
, true, true);// remove player from BG
442 // do not change any battleground's private variables
451 void BattleGround::SetTeamStartLoc(uint32 TeamID
, float X
, float Y
, float Z
, float O
)
453 uint8 idx
= GetTeamIndexByTeamId(TeamID
);
454 m_TeamStartLocX
[idx
] = X
;
455 m_TeamStartLocY
[idx
] = Y
;
456 m_TeamStartLocZ
[idx
] = Z
;
457 m_TeamStartLocO
[idx
] = O
;
460 void BattleGround::SendPacketToAll(WorldPacket
*packet
)
462 for(BattleGroundPlayerMap::const_iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
464 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
466 plr
->GetSession()->SendPacket(packet
);
468 sLog
.outError("BattleGround: Player (GUID: %u) not found!", GUID_LOPART(itr
->first
));
472 void BattleGround::SendPacketToTeam(uint32 TeamID
, WorldPacket
*packet
, Player
*sender
, bool self
)
474 for(BattleGroundPlayerMap::const_iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
476 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
480 sLog
.outError("BattleGround: Player (GUID: %u) not found!", GUID_LOPART(itr
->first
));
484 if (!self
&& sender
== plr
)
487 uint32 team
= itr
->second
.Team
;
488 if(!team
) team
= plr
->GetTeam();
491 plr
->GetSession()->SendPacket(packet
);
495 void BattleGround::PlaySoundToAll(uint32 SoundID
)
498 sBattleGroundMgr
.BuildPlaySoundPacket(&data
, SoundID
);
499 SendPacketToAll(&data
);
502 void BattleGround::PlaySoundToTeam(uint32 SoundID
, uint32 TeamID
)
506 for(BattleGroundPlayerMap::const_iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
508 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
512 sLog
.outError("BattleGround: Player (GUID: %u) not found!", GUID_LOPART(itr
->first
));
516 uint32 team
= itr
->second
.Team
;
517 if(!team
) team
= plr
->GetTeam();
521 sBattleGroundMgr
.BuildPlaySoundPacket(&data
, SoundID
);
522 plr
->GetSession()->SendPacket(&data
);
527 void BattleGround::CastSpellOnTeam(uint32 SpellID
, uint32 TeamID
)
529 for(BattleGroundPlayerMap::const_iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
531 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
535 sLog
.outError("BattleGround: Player (GUID: %u) not found!", GUID_LOPART(itr
->first
));
539 uint32 team
= itr
->second
.Team
;
540 if(!team
) team
= plr
->GetTeam();
543 plr
->CastSpell(plr
, SpellID
, true);
547 void BattleGround::RewardHonorToTeam(uint32 Honor
, uint32 TeamID
)
549 for(BattleGroundPlayerMap::const_iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
551 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
555 sLog
.outError("BattleGround: Player (GUID: %u) not found!", GUID_LOPART(itr
->first
));
559 uint32 team
= itr
->second
.Team
;
560 if(!team
) team
= plr
->GetTeam();
563 UpdatePlayerScore(plr
, SCORE_BONUS_HONOR
, Honor
);
567 void BattleGround::RewardReputationToTeam(uint32 faction_id
, uint32 Reputation
, uint32 TeamID
)
569 FactionEntry
const* factionEntry
= sFactionStore
.LookupEntry(faction_id
);
574 for(BattleGroundPlayerMap::const_iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
576 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
580 sLog
.outError("BattleGround: Player (GUID: %u) not found!", GUID_LOPART(itr
->first
));
584 uint32 team
= itr
->second
.Team
;
585 if(!team
) team
= plr
->GetTeam();
588 plr
->GetReputationMgr().ModifyReputation(factionEntry
, Reputation
);
592 void BattleGround::UpdateWorldState(uint32 Field
, uint32 Value
)
595 sBattleGroundMgr
.BuildUpdateWorldStatePacket(&data
, Field
, Value
);
596 SendPacketToAll(&data
);
599 void BattleGround::UpdateWorldStateForPlayer(uint32 Field
, uint32 Value
, Player
*Source
)
602 sBattleGroundMgr
.BuildUpdateWorldStatePacket(&data
, Field
, Value
);
603 Source
->GetSession()->SendPacket(&data
);
606 void BattleGround::EndBattleGround(uint32 winner
)
608 this->RemoveFromBGFreeSlotQueue();
610 ArenaTeam
* winner_arena_team
= NULL
;
611 ArenaTeam
* loser_arena_team
= NULL
;
612 uint32 loser_rating
= 0;
613 uint32 winner_rating
= 0;
617 if (winner
== ALLIANCE
)
619 winmsg_id
= isBattleGround() ? LANG_BG_A_WINS
: LANG_ARENA_GOLD_WINS
;
621 PlaySoundToAll(SOUND_ALLIANCE_WINS
); // alliance wins sound
623 SetWinner(WINNER_ALLIANCE
);
625 else if (winner
== HORDE
)
627 winmsg_id
= isBattleGround() ? LANG_BG_H_WINS
: LANG_ARENA_GREEN_WINS
;
629 PlaySoundToAll(SOUND_HORDE_WINS
); // horde wins sound
631 SetWinner(WINNER_HORDE
);
638 SetStatus(STATUS_WAIT_LEAVE
);
639 //we must set it this way, because end time is sent in packet!
640 m_EndTime
= TIME_TO_AUTOREMOVE
;
642 // arena rating calculation
643 if (isArena() && isRated())
645 winner_arena_team
= objmgr
.GetArenaTeamById(GetArenaTeamIdForTeam(winner
));
646 loser_arena_team
= objmgr
.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(winner
)));
647 if (winner_arena_team
&& loser_arena_team
)
649 loser_rating
= loser_arena_team
->GetStats().rating
;
650 winner_rating
= winner_arena_team
->GetStats().rating
;
651 int32 winner_change
= winner_arena_team
->WonAgainst(loser_rating
);
652 int32 loser_change
= loser_arena_team
->LostAgainst(winner_rating
);
653 sLog
.outDebug("--- Winner rating: %u, Loser rating: %u, Winner change: %u, Losser change: %u ---", winner_rating
, loser_rating
, winner_change
, loser_change
);
654 SetArenaTeamRatingChangeForTeam(winner
, winner_change
);
655 SetArenaTeamRatingChangeForTeam(GetOtherTeam(winner
), loser_change
);
659 SetArenaTeamRatingChangeForTeam(ALLIANCE
, 0);
660 SetArenaTeamRatingChangeForTeam(HORDE
, 0);
664 for(BattleGroundPlayerMap::iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
666 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
667 uint32 team
= itr
->second
.Team
;
671 //if rated arena match - make member lost!
672 if (isArena() && isRated() && winner_arena_team
&& loser_arena_team
)
675 winner_arena_team
->OfflineMemberLost(itr
->first
, loser_rating
);
677 loser_arena_team
->OfflineMemberLost(itr
->first
, winner_rating
);
679 sLog
.outError("BattleGround: Player (GUID: %u) not found!", GUID_LOPART(itr
->first
));
683 // should remove spirit of redemption
684 if (plr
->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION
))
685 plr
->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT
);
689 plr
->ResurrectPlayer(1.0f
);
690 plr
->SpawnCorpseBones();
693 //this line is obsolete - team is set ALWAYS
694 //if(!team) team = plr->GetTeam();
696 // per player calculation
697 if (isArena() && isRated() && winner_arena_team
&& loser_arena_team
)
701 // update achievement BEFORE personal rating update
702 plr
->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA
, winner_arena_team
->GetMember(plr
->GetGUID())->personal_rating
);
704 winner_arena_team
->MemberWon(plr
,loser_rating
);
708 loser_arena_team
->MemberLost(plr
,winner_rating
);
710 // Arena lost => reset the win_rated_arena having the "no_loose" condition
711 plr
->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA
, ACHIEVEMENT_CRITERIA_CONDITION_NO_LOOSE
);
717 RewardMark(plr
,ITEM_WINNER_COUNT
);
718 RewardQuestComplete(plr
);
721 RewardMark(plr
,ITEM_LOSER_COUNT
);
723 plr
->CombatStopWithPets(true);
727 sBattleGroundMgr
.BuildPvpLogDataPacket(&data
, this);
728 plr
->GetSession()->SendPacket(&data
);
730 BattleGroundQueueTypeId bgQueueTypeId
= BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
731 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, this, plr
->GetBattleGroundQueueIndex(bgQueueTypeId
), STATUS_IN_PROGRESS
, TIME_TO_AUTOREMOVE
, GetStartTime(), GetArenaType());
732 plr
->GetSession()->SendPacket(&data
);
733 plr
->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND
, 1);
736 if (isArena() && isRated() && winner_arena_team
&& loser_arena_team
)
738 // update arena points only after increasing the player's match count!
739 //obsolete: winner_arena_team->UpdateArenaPointsHelper();
740 //obsolete: loser_arena_team->UpdateArenaPointsHelper();
741 // save the stat changes
742 winner_arena_team
->SaveToDB();
743 loser_arena_team
->SaveToDB();
744 // send updated arena team stats to players
745 // this way all arena team members will get notified, not only the ones who participated in this match
746 winner_arena_team
->NotifyStatsChanged();
747 loser_arena_team
->NotifyStatsChanged();
751 SendMessageToAll(winmsg_id
, CHAT_MSG_BG_SYSTEM_NEUTRAL
);
754 uint32
BattleGround::GetBonusHonorFromKill(uint32 kills
) const
756 //variable kills means how many honorable kills you scored (so we need kills * honor_for_one_kill)
757 return MaNGOS::Honor::hk_honor_at_level(GetMaxLevel(), kills
);
760 uint32
BattleGround::GetBattlemasterEntry() const
764 case BATTLEGROUND_AV
: return 15972;
765 case BATTLEGROUND_WS
: return 14623;
766 case BATTLEGROUND_AB
: return 14879;
767 case BATTLEGROUND_EY
: return 22516;
768 case BATTLEGROUND_NA
: return 20200;
773 void BattleGround::RewardMark(Player
*plr
,uint32 count
)
775 BattleGroundMarks mark
;
779 case BATTLEGROUND_AV
:
781 if (count
== ITEM_WINNER_COUNT
)
782 mark
= SPELL_AV_MARK_WINNER
;
784 mark
= SPELL_AV_MARK_LOSER
;
786 case BATTLEGROUND_WS
:
788 if (count
== ITEM_WINNER_COUNT
)
789 mark
= SPELL_WS_MARK_WINNER
;
791 mark
= SPELL_WS_MARK_LOSER
;
793 case BATTLEGROUND_AB
:
795 if (count
== ITEM_WINNER_COUNT
)
796 mark
= SPELL_AB_MARK_WINNER
;
798 mark
= SPELL_AB_MARK_LOSER
;
800 case BATTLEGROUND_EY
:
802 mark
= ITEM_EY_MARK_OF_HONOR
;
809 RewardSpellCast(plr
,mark
);
811 RewardItem(plr
,mark
,count
);
814 void BattleGround::RewardSpellCast(Player
*plr
, uint32 spell_id
)
816 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
817 if (plr
->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE
))
820 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spell_id
);
823 sLog
.outError("Battleground reward casting spell %u not exist.",spell_id
);
827 plr
->CastSpell(plr
, spellInfo
, true);
830 void BattleGround::RewardItem(Player
*plr
, uint32 item_id
, uint32 count
)
832 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
833 if (plr
->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE
))
836 ItemPosCountVec dest
;
837 uint32 no_space_count
= 0;
838 uint8 msg
= plr
->CanStoreNewItem( NULL_BAG
, NULL_SLOT
, dest
, item_id
, count
, &no_space_count
);
840 if( msg
== EQUIP_ERR_ITEM_NOT_FOUND
)
842 sLog
.outErrorDb("Battleground reward item (Entry %u) not exist in `item_template`.",item_id
);
846 if( msg
!= EQUIP_ERR_OK
) // convert to possible store amount
847 count
-= no_space_count
;
849 if( count
!= 0 && !dest
.empty()) // can add some
850 if (Item
* item
= plr
->StoreNewItem( dest
, item_id
, true, 0))
851 plr
->SendNewItem(item
,count
,false,true);
853 if (no_space_count
> 0)
854 SendRewardMarkByMail(plr
,item_id
,no_space_count
);
857 void BattleGround::SendRewardMarkByMail(Player
*plr
,uint32 mark
, uint32 count
)
859 uint32 bmEntry
= GetBattlemasterEntry();
863 ItemPrototype
const* markProto
= objmgr
.GetItemPrototype(mark
);
867 if (Item
* markItem
= Item::CreateItem(mark
,count
,plr
))
869 // save new item before send
870 markItem
->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
874 mi
.AddItem(markItem
->GetGUIDLow(), markItem
->GetEntry(), markItem
);
876 // subject: item name
877 std::string subject
= markProto
->Name1
;
878 int loc_idx
= plr
->GetSession()->GetSessionDbLocaleIndex();
880 if (ItemLocale
const *il
= objmgr
.GetItemLocale(markProto
->ItemId
))
881 if (il
->Name
.size() > size_t(loc_idx
) && !il
->Name
[loc_idx
].empty())
882 subject
= il
->Name
[loc_idx
];
885 std::string textFormat
= plr
->GetSession()->GetMangosString(LANG_BG_MARK_BY_MAIL
);
887 snprintf(textBuf
,300,textFormat
.c_str(),GetName(),GetName());
888 uint32 itemTextId
= objmgr
.CreateItemText( textBuf
);
890 WorldSession::SendMailTo(plr
, MAIL_CREATURE
, MAIL_STATIONERY_NORMAL
, bmEntry
, plr
->GetGUIDLow(), subject
, itemTextId
, &mi
, 0, 0, MAIL_CHECK_MASK_NONE
);
894 void BattleGround::RewardQuestComplete(Player
*plr
)
899 case BATTLEGROUND_AV
:
900 quest
= SPELL_AV_QUEST_REWARD
;
902 case BATTLEGROUND_WS
:
903 quest
= SPELL_WS_QUEST_REWARD
;
905 case BATTLEGROUND_AB
:
906 quest
= SPELL_AB_QUEST_REWARD
;
908 case BATTLEGROUND_EY
:
909 quest
= SPELL_EY_QUEST_REWARD
;
915 RewardSpellCast(plr
, quest
);
918 void BattleGround::BlockMovement(Player
*plr
)
920 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()
923 void BattleGround::RemovePlayerAtLeave(uint64 guid
, bool Transport
, bool SendPacket
)
925 uint32 team
= GetPlayerTeam(guid
);
926 bool participant
= false;
927 // Remove from lists/maps
928 BattleGroundPlayerMap::iterator itr
= m_Players
.find(guid
);
929 if (itr
!= m_Players
.end())
931 UpdatePlayersCountByTeam(team
, true); // -1 player
932 m_Players
.erase(itr
);
933 // check if the player was a participant of the match, or only entered through gm command (goname)
937 std::map
<uint64
, BattleGroundScore
*>::iterator itr2
= m_PlayerScores
.find(guid
);
938 if (itr2
!= m_PlayerScores
.end())
940 delete itr2
->second
; // delete player's score
941 m_PlayerScores
.erase(itr2
);
944 RemovePlayerFromResurrectQueue(guid
);
946 Player
*plr
= objmgr
.GetPlayer(guid
);
948 // should remove spirit of redemption
949 if (plr
&& plr
->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION
))
950 plr
->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT
);
952 if(plr
&& !plr
->isAlive()) // resurrect on exit
954 plr
->ResurrectPlayer(1.0f
);
955 plr
->SpawnCorpseBones();
958 RemovePlayer(plr
, guid
); // BG subclass specific code
960 if(participant
) // if the player was a match participant, remove auras, calc rating, update queue
962 BattleGroundTypeId bgTypeId
= GetTypeID();
963 BattleGroundQueueTypeId bgQueueTypeId
= BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
966 plr
->ClearAfkReports();
968 if(!team
) team
= plr
->GetTeam();
970 // if arena, remove the specific arena auras
973 plr
->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out
974 bgTypeId
=BATTLEGROUND_AA
; // set the bg type to all arenas (it will be used for queue refreshing)
976 // unsummon current and summon old pet if there was one and there isn't a current pet
977 plr
->RemovePet(NULL
, PET_SAVE_NOT_IN_SLOT
);
978 plr
->ResummonPetTemporaryUnSummonedIfAny();
980 if (isRated() && GetStatus() == STATUS_IN_PROGRESS
)
982 //left a rated match while the encounter was in progress, consider as loser
983 ArenaTeam
* winner_arena_team
= objmgr
.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team
)));
984 ArenaTeam
* loser_arena_team
= objmgr
.GetArenaTeamById(GetArenaTeamIdForTeam(team
));
985 if (winner_arena_team
&& loser_arena_team
)
986 loser_arena_team
->MemberLost(plr
,winner_arena_team
->GetRating());
992 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, this, plr
->GetBattleGroundQueueIndex(bgQueueTypeId
), STATUS_NONE
, 0, 0, 0);
993 plr
->GetSession()->SendPacket(&data
);
996 // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
997 plr
->RemoveBattleGroundQueueId(bgQueueTypeId
);
1000 // removing offline participant
1002 if (isRated() && GetStatus() == STATUS_IN_PROGRESS
)
1004 //left a rated match while the encounter was in progress, consider as loser
1005 ArenaTeam
* others_arena_team
= objmgr
.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team
)));
1006 ArenaTeam
* players_arena_team
= objmgr
.GetArenaTeamById(GetArenaTeamIdForTeam(team
));
1007 if (others_arena_team
&& players_arena_team
)
1008 players_arena_team
->OfflineMemberLost(guid
, others_arena_team
->GetRating());
1012 // remove from raid group if player is member
1013 if (Group
*group
= GetBgRaid(team
))
1015 if( !group
->RemoveMember(guid
, 0) ) // group was disbanded
1017 SetBgRaid(team
, NULL
);
1021 DecreaseInvitedCount(team
);
1022 //we should update battleground queue, but only if bg isn't ending
1023 if (isBattleGround() && GetStatus() < STATUS_WAIT_LEAVE
)
1024 sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].Update(bgTypeId
, GetQueueId());
1027 sBattleGroundMgr
.BuildPlayerLeftBattleGroundPacket(&data
, guid
);
1028 SendPacketToTeam(team
, &data
, plr
, false);
1033 // Do next only if found in battleground
1034 plr
->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE
); // We're not in BG.
1035 // reset destination bg team
1039 plr
->TeleportTo(plr
->GetBattleGroundEntryPoint());
1041 sLog
.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr
->GetName());
1044 if (!GetPlayersSize() && !GetInvitedCount(HORDE
) && !GetInvitedCount(ALLIANCE
))
1046 // if no players left AND no invitees left, set this bg to delete in next update
1047 // direct deletion could cause crashes
1048 m_SetDeleteThis
= true;
1049 // return to prevent addition to freeslotqueue
1053 // a player exited the battleground, so there are free slots. add to queue
1054 this->AddToBGFreeSlotQueue();
1057 // this method is called when no players remains in battleground
1058 void BattleGround::Reset()
1060 SetQueueId(QUEUE_ID_MAX_LEVEL_19
);
1061 SetWinner(WINNER_NONE
);
1062 SetStatus(STATUS_WAIT_QUEUE
);
1065 SetLastResurrectTime(0);
1071 if (m_InvitedAlliance
> 0 || m_InvitedHorde
> 0)
1072 sLog
.outError("BattleGround system: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance
, m_InvitedHorde
);
1074 m_InvitedAlliance
= 0;
1076 m_InBGFreeSlotQueue
= false;
1079 m_PlayerScores
.clear();
1082 void BattleGround::StartBattleGround()
1084 ///this method should spawn spirit guides and so on
1087 SetLastResurrectTime(0);
1090 void BattleGround::AddPlayer(Player
*plr
)
1092 // score struct must be created in inherited class
1094 uint64 guid
= plr
->GetGUID();
1095 uint32 team
= plr
->GetBGTeam();
1097 BattleGroundPlayer bp
;
1098 bp
.OfflineRemoveTime
= 0;
1102 m_Players
[guid
] = bp
;
1104 UpdatePlayersCountByTeam(team
, false); // +1 player
1107 sBattleGroundMgr
.BuildPlayerJoinedBattleGroundPacket(&data
, plr
);
1108 SendPacketToTeam(team
, &data
, plr
, false);
1110 // add arena specific auras
1113 plr
->RemoveArenaSpellCooldowns();
1114 plr
->RemoveArenaAuras();
1115 plr
->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT
);
1116 if(team
== ALLIANCE
) // gold
1118 if (plr
->GetTeam() == HORDE
)
1119 plr
->CastSpell(plr
, SPELL_HORDE_GOLD_FLAG
,true);
1121 plr
->CastSpell(plr
, SPELL_ALLIANCE_GOLD_FLAG
,true);
1125 if (plr
->GetTeam() == HORDE
)
1126 plr
->CastSpell(plr
, SPELL_HORDE_GREEN_FLAG
,true);
1128 plr
->CastSpell(plr
, SPELL_ALLIANCE_GREEN_FLAG
,true);
1131 plr
->DestroyConjuredItems(true);
1132 plr
->UnsummonPetTemporaryIfAny();
1134 if(GetStatus() == STATUS_WAIT_JOIN
) // not started yet
1136 plr
->CastSpell(plr
, SPELL_ARENA_PREPARATION
, true);
1138 plr
->SetHealth(plr
->GetMaxHealth());
1139 plr
->SetPower(POWER_MANA
, plr
->GetMaxPower(POWER_MANA
));
1144 if(GetStatus() == STATUS_WAIT_JOIN
) // not started yet
1145 plr
->CastSpell(plr
, SPELL_PREPARATION
, true); // reduces all mana cost of spells.
1148 plr
->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE
, ACHIEVEMENT_CRITERIA_CONDITION_MAP
, GetMapId());
1149 plr
->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE
, ACHIEVEMENT_CRITERIA_CONDITION_MAP
, GetMapId());
1151 // setup BG group membership
1152 PlayerAddedToBGCheckIfBGIsRunning(plr
);
1153 AddOrSetPlayerToCorrectBgGroup(plr
, guid
, team
);
1156 sLog
.outDetail("BATTLEGROUND: Player %s joined the battle.", plr
->GetName());
1159 /* this method adds player to his team's bg group, or sets his correct group if player is already in bg group */
1160 void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player
*plr
, uint64 plr_guid
, uint32 team
)
1162 Group
* group
= GetBgRaid(team
);
1163 if(!group
) // first player joined
1166 SetBgRaid(team
, group
);
1167 group
->Create(plr_guid
, plr
->GetName());
1169 else // raid already exist
1171 if (group
->IsMember(plr_guid
))
1173 uint8 subgroup
= group
->GetMemberGroup(plr_guid
);
1174 plr
->SetBattleGroundRaid(group
, subgroup
);
1178 group
->AddMember(plr_guid
, plr
->GetName());
1179 if (Group
* originalGroup
= plr
->GetOriginalGroup())
1180 if (originalGroup
->IsLeader(plr_guid
))
1181 group
->ChangeLeader(plr_guid
);
1186 // This method should be called when player logs into running battleground
1187 void BattleGround::EventPlayerLoggedIn(Player
* player
, uint64 plr_guid
)
1189 // player is correct pointer
1190 for(std::deque
<uint64
>::iterator itr
= m_OfflineQueue
.begin(); itr
!= m_OfflineQueue
.end(); ++itr
)
1192 if (*itr
== plr_guid
)
1194 m_OfflineQueue
.erase(itr
);
1198 m_Players
[plr_guid
].OfflineRemoveTime
= 0;
1199 PlayerAddedToBGCheckIfBGIsRunning(player
);
1200 // if battleground is starting, then add preparation aura
1201 // we don't have to do that, because preparation aura isn't removed when player logs out
1204 // This method should be called when player logs out from running battleground
1205 void BattleGround::EventPlayerLoggedOut(Player
* player
)
1207 // player is correct pointer, it is checked in WorldSession::LogoutPlayer()
1208 m_OfflineQueue
.push_back(player
->GetGUID());
1209 m_Players
[player
->GetGUID()].OfflineRemoveTime
= sWorld
.GetGameTime() + MAX_OFFLINE_TIME
;
1210 if (GetStatus() == STATUS_IN_PROGRESS
)
1212 if (isBattleGround())
1213 EventPlayerDroppedFlag(player
);
1216 //1 player is logging out, if it is the last, then end arena!
1217 if (GetAlivePlayersCountByTeam(player
->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player
->GetTeam())))
1218 EndBattleGround(GetOtherTeam(player
->GetTeam()));
1223 /* This method should be called only once ... it adds pointer to queue */
1224 void BattleGround::AddToBGFreeSlotQueue()
1226 // make sure to add only once
1227 if (!m_InBGFreeSlotQueue
&& isBattleGround())
1229 sBattleGroundMgr
.BGFreeSlotQueue
[m_TypeID
].push_front(this);
1230 m_InBGFreeSlotQueue
= true;
1234 /* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
1235 void BattleGround::RemoveFromBGFreeSlotQueue()
1237 // set to be able to re-add if needed
1238 m_InBGFreeSlotQueue
= false;
1239 // uncomment this code when battlegrounds will work like instances
1240 for (BGFreeSlotQueueType::iterator itr
= sBattleGroundMgr
.BGFreeSlotQueue
[m_TypeID
].begin(); itr
!= sBattleGroundMgr
.BGFreeSlotQueue
[m_TypeID
].end(); ++itr
)
1242 if ((*itr
)->GetInstanceID() == m_InstanceID
)
1244 sBattleGroundMgr
.BGFreeSlotQueue
[m_TypeID
].erase(itr
);
1250 // get the number of free slots for team
1251 // returns the number how many players can join battleground to MaxPlayersPerTeam
1252 uint32
BattleGround::GetFreeSlotsForTeam(uint32 Team
) const
1254 //return free slot count to MaxPlayerPerTeam
1255 if (GetStatus() == STATUS_WAIT_JOIN
|| GetStatus() == STATUS_IN_PROGRESS
)
1256 return (GetInvitedCount(Team
) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team
) : 0;
1261 bool BattleGround::HasFreeSlots() const
1263 return GetPlayersSize() < GetMaxPlayers();
1266 void BattleGround::UpdatePlayerScore(Player
*Source
, uint32 type
, uint32 value
)
1268 //this procedure is called from virtual function implemented in bg subclass
1269 std::map
<uint64
, BattleGroundScore
*>::const_iterator itr
= m_PlayerScores
.find(Source
->GetGUID());
1271 if(itr
== m_PlayerScores
.end()) // player not found...
1276 case SCORE_KILLING_BLOWS
: // Killing blows
1277 itr
->second
->KillingBlows
+= value
;
1279 case SCORE_DEATHS
: // Deaths
1280 itr
->second
->Deaths
+= value
;
1282 case SCORE_HONORABLE_KILLS
: // Honorable kills
1283 itr
->second
->HonorableKills
+= value
;
1285 case SCORE_BONUS_HONOR
: // Honor bonus
1286 // do not add honor in arenas
1287 if (isBattleGround())
1289 // reward honor instantly
1290 if (Source
->RewardHonor(NULL
, 1, value
))
1291 itr
->second
->BonusHonor
+= value
;
1294 //used only in EY, but in MSG_PVP_LOG_DATA opcode
1295 case SCORE_DAMAGE_DONE
: // Damage Done
1296 itr
->second
->DamageDone
+= value
;
1298 case SCORE_HEALING_DONE
: // Healing Done
1299 itr
->second
->HealingDone
+= value
;
1302 sLog
.outError("BattleGround: Unknown player score type %u", type
);
1307 void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid
, uint64 player_guid
)
1309 m_ReviveQueue
[npc_guid
].push_back(player_guid
);
1311 Player
*plr
= objmgr
.GetPlayer(player_guid
);
1315 plr
->CastSpell(plr
, SPELL_WAITING_FOR_RESURRECT
, true);
1316 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( SPELL_WAITING_FOR_RESURRECT
);
1319 Aura
*Aur
= CreateAura(spellInfo
, 0, NULL
, plr
);
1324 void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid
)
1326 for(std::map
<uint64
, std::vector
<uint64
> >::iterator itr
= m_ReviveQueue
.begin(); itr
!= m_ReviveQueue
.end(); ++itr
)
1328 for(std::vector
<uint64
>::iterator itr2
=(itr
->second
).begin(); itr2
!= (itr
->second
).end(); ++itr2
)
1330 if (*itr2
== player_guid
)
1332 (itr
->second
).erase(itr2
);
1334 Player
*plr
= objmgr
.GetPlayer(player_guid
);
1338 plr
->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT
);
1346 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
)
1348 Map
* map
= MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1352 // must be created this way, adding to godatamap would add it to the base map of the instance
1353 // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
1354 // so we must create it specific for this instance
1355 GameObject
* go
= new GameObject
;
1356 if(!go
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
),entry
, map
,
1357 PHASEMASK_NORMAL
, x
,y
,z
,o
,rotation0
,rotation1
,rotation2
,rotation3
,100,GO_STATE_READY
))
1359 sLog
.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry
);
1360 sLog
.outError("Cannot create gameobject template %u! BattleGround not created!", entry
);
1365 uint32 guid = go->GetGUIDLow();
1367 // without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
1368 // 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
1369 GameObjectData& data = objmgr.NewGOData(guid);
1372 data.mapid = GetMapId();
1376 data.orientation = o;
1377 data.rotation0 = rotation0;
1378 data.rotation1 = rotation1;
1379 data.rotation2 = rotation2;
1380 data.rotation3 = rotation3;
1381 data.spawntimesecs = respawnTime;
1383 data.animprogress = 100;
1386 // add to world, so it can be later looked up from HashMapHolder
1388 m_BgObjects
[type
] = go
->GetGUID();
1392 //some doors aren't despawned so we cannot handle their closing in gameobject::update()
1393 //it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
1394 void BattleGround::DoorClose(uint32 type
)
1396 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1399 //if doors are open, close it
1400 if (obj
->getLootState() == GO_ACTIVATED
&& obj
->GetGoState() != GO_STATE_READY
)
1402 //change state to allow door to be closed
1403 obj
->SetLootState(GO_READY
);
1404 obj
->UseDoorOrButton(RESPAWN_ONE_DAY
);
1409 sLog
.outError("BattleGround: Door object not found (cannot close doors)");
1413 void BattleGround::DoorOpen(uint32 type
)
1415 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1418 //change state to be sure they will be opened
1419 obj
->SetLootState(GO_READY
);
1420 obj
->UseDoorOrButton(RESPAWN_ONE_DAY
);
1424 sLog
.outError("BattleGround: Door object not found! - doors will be closed.");
1428 void BattleGround::SpawnBGObject(uint32 type
, uint32 respawntime
)
1430 Map
* map
= MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1433 if (respawntime
== 0)
1435 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1438 //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
1439 if (obj
->getLootState() == GO_JUST_DEACTIVATED
)
1440 obj
->SetLootState(GO_READY
);
1441 obj
->SetRespawnTime(0);
1447 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1451 obj
->SetRespawnTime(respawntime
);
1452 obj
->SetLootState(GO_JUST_DEACTIVATED
);
1457 Creature
* BattleGround::AddCreature(uint32 entry
, uint32 type
, uint32 teamval
, float x
, float y
, float z
, float o
, uint32 respawntime
)
1459 Map
* map
= MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1463 Creature
* pCreature
= new Creature
;
1464 if (!pCreature
->Create(objmgr
.GenerateLowGuid(HIGHGUID_UNIT
), map
, PHASEMASK_NORMAL
, entry
, teamval
))
1466 sLog
.outError("Can't create creature entry: %u",entry
);
1471 pCreature
->Relocate(x
, y
, z
, o
);
1473 if (!pCreature
->IsPositionValid())
1475 sLog
.outError("Creature (guidlow %d, entry %d) not added to battleground. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature
->GetGUIDLow(),pCreature
->GetEntry(),pCreature
->GetPositionX(),pCreature
->GetPositionY());
1480 pCreature
->AIM_Initialize();
1482 //pCreature->SetDungeonDifficulty(0);
1484 map
->Add(pCreature
);
1485 m_BgCreatures
[type
] = pCreature
->GetGUID();
1490 void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)
1492 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceId());
1496 if (respawntime == 0)
1498 Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1501 //obj->Respawn(); // bugged
1502 obj->SetRespawnTime(0);
1503 objmgr.SaveCreatureRespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);
1509 Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1512 obj->setDeathState(DEAD);
1513 obj->SetRespawnTime(respawntime);
1519 bool BattleGround::DelCreature(uint32 type
)
1521 if (!m_BgCreatures
[type
])
1524 Creature
*cr
= HashMapHolder
<Creature
>::Find(m_BgCreatures
[type
]);
1527 sLog
.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures
[type
]));
1530 cr
->CleanupsBeforeDelete();
1531 cr
->AddObjectToRemoveList();
1532 m_BgCreatures
[type
] = 0;
1536 bool BattleGround::DelObject(uint32 type
)
1538 if (!m_BgObjects
[type
])
1541 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1544 sLog
.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects
[type
]));
1547 obj
->SetRespawnTime(0); // not save respawn time
1549 m_BgObjects
[type
] = 0;
1553 bool BattleGround::AddSpiritGuide(uint32 type
, float x
, float y
, float z
, float o
, uint32 team
)
1557 if (team
== ALLIANCE
)
1562 Creature
* pCreature
= AddCreature(entry
,type
,team
,x
,y
,z
,o
);
1565 sLog
.outError("Can't create Spirit guide. BattleGround not created!");
1570 pCreature
->setDeathState(DEAD
);
1572 pCreature
->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT
, pCreature
->GetGUID());
1574 pCreature
->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL
);
1575 //pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
1576 //pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
1577 //pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
1578 // casting visual effect
1579 pCreature
->SetUInt32Value(UNIT_CHANNEL_SPELL
, SPELL_SPIRIT_HEAL_CHANNEL
);
1580 // correct cast speed
1581 pCreature
->SetFloatValue(UNIT_MOD_CAST_SPEED
, 1.0f
);
1583 //pCreature->CastSpell(pCreature, SPELL_SPIRIT_HEAL_CHANNEL, true);
1588 void BattleGround::SendMessageToAll(int32 entry
, ChatMsg type
, Player
const* source
)
1590 MaNGOS::BattleGroundChatBuilder
bg_builder(type
, entry
, source
);
1591 MaNGOS::LocalizedPacketDo
<MaNGOS::BattleGroundChatBuilder
> bg_do(bg_builder
);
1592 BroadcastWorker(bg_do
);
1595 void BattleGround::PSendMessageToAll(int32 entry
, ChatMsg type
, Player
const* source
, ...)
1598 va_start(ap
, source
);
1600 MaNGOS::BattleGroundChatBuilder
bg_builder(type
, entry
, source
, &ap
);
1601 MaNGOS::LocalizedPacketDo
<MaNGOS::BattleGroundChatBuilder
> bg_do(bg_builder
);
1602 BroadcastWorker(bg_do
);
1607 void BattleGround::SendMessage2ToAll(int32 entry
, ChatMsg type
, Player
const* source
, int32 arg1
, int32 arg2
)
1609 MaNGOS::BattleGround2ChatBuilder
bg_builder(type
, entry
, source
, arg1
, arg2
);
1610 MaNGOS::LocalizedPacketDo
<MaNGOS::BattleGround2ChatBuilder
> bg_do(bg_builder
);
1611 BroadcastWorker(bg_do
);
1614 void BattleGround::EndNow()
1616 RemoveFromBGFreeSlotQueue();
1617 SetStatus(STATUS_WAIT_LEAVE
);
1623 buffs aren't spawned/despawned when players captures anything
1624 buffs are in their positions when battleground starts
1626 void BattleGround::HandleTriggerBuff(uint64
const& go_guid
)
1628 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(go_guid
);
1629 if (!obj
|| obj
->GetGoType() != GAMEOBJECT_TYPE_TRAP
|| !obj
->isSpawned())
1632 //change buff type, when buff is used:
1633 int32 index
= m_BgObjects
.size() - 1;
1634 while (index
>= 0 && m_BgObjects
[index
] != go_guid
)
1638 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());
1642 //randomly select new buff
1643 uint8 buff
= urand(0, 2);
1644 uint32 entry
= obj
->GetEntry();
1645 if (m_BuffChange
&& entry
!= Buff_Entries
[buff
])
1647 //despawn current buff
1648 SpawnBGObject(index
, RESPAWN_ONE_DAY
);
1649 //set index for new one
1650 for (uint8 currBuffTypeIndex
= 0; currBuffTypeIndex
< 3; ++currBuffTypeIndex
)
1651 if (entry
== Buff_Entries
[currBuffTypeIndex
])
1653 index
-= currBuffTypeIndex
;
1658 SpawnBGObject(index
, BUFF_RESPAWN_TIME
);
1661 void BattleGround::HandleKillPlayer( Player
*player
, Player
*killer
)
1663 //keep in mind that for arena this will have to be changed a bit
1666 UpdatePlayerScore(player
, SCORE_DEATHS
, 1);
1668 // add +1 kills to group and +1 killing_blows to killer
1671 UpdatePlayerScore(killer
, SCORE_HONORABLE_KILLS
, 1);
1672 UpdatePlayerScore(killer
, SCORE_KILLING_BLOWS
, 1);
1674 for(BattleGroundPlayerMap::const_iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
1676 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
1678 if (!plr
|| plr
== killer
)
1681 if (plr
->GetTeam() == killer
->GetTeam() && plr
->IsAtGroupRewardDistance(player
))
1682 UpdatePlayerScore(plr
, SCORE_HONORABLE_KILLS
, 1);
1686 // to be able to remove insignia -- ONLY IN BattleGrounds
1688 player
->SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
);
1691 // return the player's team based on battlegroundplayer info
1692 // used in same faction arena matches mainly
1693 uint32
BattleGround::GetPlayerTeam(uint64 guid
)
1695 BattleGroundPlayerMap::const_iterator itr
= m_Players
.find(guid
);
1696 if (itr
!=m_Players
.end())
1697 return itr
->second
.Team
;
1701 uint32
BattleGround::GetOtherTeam(uint32 teamId
)
1703 return (teamId
) ? ((teamId
== ALLIANCE
) ? HORDE
: ALLIANCE
) : 0;
1706 bool BattleGround::IsPlayerInBattleGround(uint64 guid
)
1708 BattleGroundPlayerMap::const_iterator itr
= m_Players
.find(guid
);
1709 if (itr
!= m_Players
.end())
1714 void BattleGround::PlayerAddedToBGCheckIfBGIsRunning(Player
* plr
)
1716 if (GetStatus() != STATUS_WAIT_LEAVE
)
1720 BattleGroundQueueTypeId bgQueueTypeId
= BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
1724 sBattleGroundMgr
.BuildPvpLogDataPacket(&data
, this);
1725 plr
->GetSession()->SendPacket(&data
);
1727 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, this, plr
->GetBattleGroundQueueIndex(bgQueueTypeId
), STATUS_IN_PROGRESS
, GetEndTime(), GetStartTime(), GetArenaType());
1728 plr
->GetSession()->SendPacket(&data
);
1731 uint32
BattleGround::GetAlivePlayersCountByTeam(uint32 Team
) const
1734 for(BattleGroundPlayerMap::const_iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
1736 if (itr
->second
.Team
== Team
)
1738 Player
* pl
= objmgr
.GetPlayer(itr
->first
);
1739 if (pl
&& pl
->isAlive())
1746 void BattleGround::CheckArenaWinConditions()
1748 if (!GetAlivePlayersCountByTeam(ALLIANCE
) && GetPlayersCountByTeam(HORDE
))
1749 EndBattleGround(HORDE
);
1750 else if (GetPlayersCountByTeam(ALLIANCE
) && !GetAlivePlayersCountByTeam(HORDE
))
1751 EndBattleGround(ALLIANCE
);
1754 void BattleGround::SetBgRaid( uint32 TeamID
, Group
*bg_raid
)
1756 Group
* &old_raid
= TeamID
== ALLIANCE
? m_BgRaids
[BG_TEAM_ALLIANCE
] : m_BgRaids
[BG_TEAM_HORDE
];
1757 if(old_raid
) old_raid
->SetBattlegroundGroup(NULL
);
1758 if(bg_raid
) bg_raid
->SetBattlegroundGroup(this);
1762 WorldSafeLocsEntry
const* BattleGround::GetClosestGraveYard( Player
* player
)
1764 return objmgr
.GetClosestGraveYard( player
->GetPositionX(), player
->GetPositionY(), player
->GetPositionZ(), player
->GetMapId(), player
->GetTeam() );