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 " I64FMTD
" not found!", itr
->first
);
472 void BattleGround::SendPacketToTeam(uint32 TeamID
, WorldPacket
*packet
, Player
*sender
, bool self
)
474 for(BattleGroundPlayerMap::const_iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
476 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
480 sLog
.outError("BattleGround: Player " I64FMTD
" not found!", 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 " I64FMTD
" not found!", 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 " I64FMTD
" not found!", 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 " I64FMTD
" not found!", 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 " I64FMTD
" not found!", 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 " I64FMTD
" not found!", 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
)
700 winner_arena_team
->MemberWon(plr
,loser_rating
);
702 loser_arena_team
->MemberLost(plr
,winner_rating
);
707 RewardMark(plr
,ITEM_WINNER_COUNT
);
712 RewardMark(plr
,ITEM_LOSER_COUNT
);
715 plr
->CombatStopWithPets(true);
719 sBattleGroundMgr
.BuildPvpLogDataPacket(&data
, this);
720 plr
->GetSession()->SendPacket(&data
);
722 BattleGroundQueueTypeId bgQueueTypeId
= BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
723 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, this, plr
->GetBattleGroundQueueIndex(bgQueueTypeId
), STATUS_IN_PROGRESS
, TIME_TO_AUTOREMOVE
, GetStartTime(), GetArenaType());
724 plr
->GetSession()->SendPacket(&data
);
725 plr
->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND
, 1);
728 if (isArena() && isRated() && winner_arena_team
&& loser_arena_team
)
730 // update arena points only after increasing the player's match count!
731 //obsolete: winner_arena_team->UpdateArenaPointsHelper();
732 //obsolete: loser_arena_team->UpdateArenaPointsHelper();
733 // save the stat changes
734 winner_arena_team
->SaveToDB();
735 loser_arena_team
->SaveToDB();
736 // send updated arena team stats to players
737 // this way all arena team members will get notified, not only the ones who participated in this match
738 winner_arena_team
->NotifyStatsChanged();
739 loser_arena_team
->NotifyStatsChanged();
743 SendMessageToAll(winmsg_id
, CHAT_MSG_BG_SYSTEM_NEUTRAL
);
746 uint32
BattleGround::GetBonusHonorFromKill(uint32 kills
) const
748 //variable kills means how many honorable kills you scored (so we need kills * honor_for_one_kill)
749 return MaNGOS::Honor::hk_honor_at_level(GetMaxLevel(), kills
);
752 uint32
BattleGround::GetBattlemasterEntry() const
756 case BATTLEGROUND_AV
: return 15972;
757 case BATTLEGROUND_WS
: return 14623;
758 case BATTLEGROUND_AB
: return 14879;
759 case BATTLEGROUND_EY
: return 22516;
760 case BATTLEGROUND_NA
: return 20200;
765 void BattleGround::RewardMark(Player
*plr
,uint32 count
)
767 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
768 if (plr
->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE
))
771 BattleGroundMarks mark
;
775 case BATTLEGROUND_AV
:
777 if (count
== ITEM_WINNER_COUNT
)
778 mark
= SPELL_AV_MARK_WINNER
;
780 mark
= SPELL_AV_MARK_LOSER
;
782 case BATTLEGROUND_WS
:
784 if (count
== ITEM_WINNER_COUNT
)
785 mark
= SPELL_WS_MARK_WINNER
;
787 mark
= SPELL_WS_MARK_LOSER
;
789 case BATTLEGROUND_AB
:
791 if (count
== ITEM_WINNER_COUNT
)
792 mark
= SPELL_AB_MARK_WINNER
;
794 mark
= SPELL_AB_MARK_LOSER
;
796 case BATTLEGROUND_EY
:
798 mark
= ITEM_EY_MARK_OF_HONOR
;
805 plr
->CastSpell(plr
, mark
, true);
806 else if (objmgr
.GetItemPrototype( mark
) )
808 ItemPosCountVec dest
;
809 uint32 no_space_count
= 0;
810 uint8 msg
= plr
->CanStoreNewItem( NULL_BAG
, NULL_SLOT
, dest
, mark
, count
, &no_space_count
);
811 if( msg
!= EQUIP_ERR_OK
) // convert to possible store amount
812 count
-= no_space_count
;
814 if( count
!= 0 && !dest
.empty()) // can add some
815 if (Item
* item
= plr
->StoreNewItem( dest
, mark
, true, 0))
816 plr
->SendNewItem(item
,count
,false,true);
818 if (no_space_count
> 0)
819 SendRewardMarkByMail(plr
,mark
,no_space_count
);
823 void BattleGround::SendRewardMarkByMail(Player
*plr
,uint32 mark
, uint32 count
)
825 uint32 bmEntry
= GetBattlemasterEntry();
829 ItemPrototype
const* markProto
= objmgr
.GetItemPrototype(mark
);
833 if (Item
* markItem
= Item::CreateItem(mark
,count
,plr
))
835 // save new item before send
836 markItem
->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
840 mi
.AddItem(markItem
->GetGUIDLow(), markItem
->GetEntry(), markItem
);
842 // subject: item name
843 std::string subject
= markProto
->Name1
;
844 int loc_idx
= plr
->GetSession()->GetSessionDbLocaleIndex();
846 if (ItemLocale
const *il
= objmgr
.GetItemLocale(markProto
->ItemId
))
847 if (il
->Name
.size() > size_t(loc_idx
) && !il
->Name
[loc_idx
].empty())
848 subject
= il
->Name
[loc_idx
];
851 std::string textFormat
= plr
->GetSession()->GetMangosString(LANG_BG_MARK_BY_MAIL
);
853 snprintf(textBuf
,300,textFormat
.c_str(),GetName(),GetName());
854 uint32 itemTextId
= objmgr
.CreateItemText( textBuf
);
856 WorldSession::SendMailTo(plr
, MAIL_CREATURE
, MAIL_STATIONERY_NORMAL
, bmEntry
, plr
->GetGUIDLow(), subject
, itemTextId
, &mi
, 0, 0, MAIL_CHECK_MASK_NONE
);
860 void BattleGround::RewardQuest(Player
*plr
)
862 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
863 if (plr
->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE
))
869 case BATTLEGROUND_AV
:
870 quest
= SPELL_AV_QUEST_REWARD
;
872 case BATTLEGROUND_WS
:
873 quest
= SPELL_WS_QUEST_REWARD
;
875 case BATTLEGROUND_AB
:
876 quest
= SPELL_AB_QUEST_REWARD
;
878 case BATTLEGROUND_EY
:
879 quest
= SPELL_EY_QUEST_REWARD
;
885 plr
->CastSpell(plr
, quest
, true);
888 void BattleGround::BlockMovement(Player
*plr
)
890 plr
->SetClientControl(plr
, 0); // movement disabled NOTE: the effect will be automatically removed by client when the player is teleported from the battleground, so no need to send with uint8(1) in RemovePlayerAtLeave()
893 void BattleGround::RemovePlayerAtLeave(uint64 guid
, bool Transport
, bool SendPacket
)
895 uint32 team
= GetPlayerTeam(guid
);
896 bool participant
= false;
897 // Remove from lists/maps
898 BattleGroundPlayerMap::iterator itr
= m_Players
.find(guid
);
899 if (itr
!= m_Players
.end())
901 UpdatePlayersCountByTeam(team
, true); // -1 player
902 m_Players
.erase(itr
);
903 // check if the player was a participant of the match, or only entered through gm command (goname)
907 std::map
<uint64
, BattleGroundScore
*>::iterator itr2
= m_PlayerScores
.find(guid
);
908 if (itr2
!= m_PlayerScores
.end())
910 delete itr2
->second
; // delete player's score
911 m_PlayerScores
.erase(itr2
);
914 RemovePlayerFromResurrectQueue(guid
);
916 Player
*plr
= objmgr
.GetPlayer(guid
);
918 // should remove spirit of redemption
919 if (plr
&& plr
->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION
))
920 plr
->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT
);
922 if(plr
&& !plr
->isAlive()) // resurrect on exit
924 plr
->ResurrectPlayer(1.0f
);
925 plr
->SpawnCorpseBones();
928 RemovePlayer(plr
, guid
); // BG subclass specific code
930 if(participant
) // if the player was a match participant, remove auras, calc rating, update queue
932 BattleGroundTypeId bgTypeId
= GetTypeID();
933 BattleGroundQueueTypeId bgQueueTypeId
= BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
936 plr
->ClearAfkReports();
938 if(!team
) team
= plr
->GetTeam();
940 // if arena, remove the specific arena auras
943 plr
->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out
944 bgTypeId
=BATTLEGROUND_AA
; // set the bg type to all arenas (it will be used for queue refreshing)
946 // unsummon current and summon old pet if there was one and there isn't a current pet
947 plr
->RemovePet(NULL
, PET_SAVE_NOT_IN_SLOT
);
948 plr
->ResummonPetTemporaryUnSummonedIfAny();
950 if (isRated() && GetStatus() == STATUS_IN_PROGRESS
)
952 //left a rated match while the encounter was in progress, consider as loser
953 ArenaTeam
* winner_arena_team
= objmgr
.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team
)));
954 ArenaTeam
* loser_arena_team
= objmgr
.GetArenaTeamById(GetArenaTeamIdForTeam(team
));
955 if (winner_arena_team
&& loser_arena_team
)
956 loser_arena_team
->MemberLost(plr
,winner_arena_team
->GetRating());
962 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, this, plr
->GetBattleGroundQueueIndex(bgQueueTypeId
), STATUS_NONE
, 0, 0, 0);
963 plr
->GetSession()->SendPacket(&data
);
966 // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
967 plr
->RemoveBattleGroundQueueId(bgQueueTypeId
);
970 // removing offline participant
972 if (isRated() && GetStatus() == STATUS_IN_PROGRESS
)
974 //left a rated match while the encounter was in progress, consider as loser
975 ArenaTeam
* others_arena_team
= objmgr
.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team
)));
976 ArenaTeam
* players_arena_team
= objmgr
.GetArenaTeamById(GetArenaTeamIdForTeam(team
));
977 if (others_arena_team
&& players_arena_team
)
978 players_arena_team
->OfflineMemberLost(guid
, others_arena_team
->GetRating());
982 // remove from raid group if player is member
983 if (Group
*group
= GetBgRaid(team
))
985 if( !group
->RemoveMember(guid
, 0) ) // group was disbanded
987 SetBgRaid(team
, NULL
);
991 DecreaseInvitedCount(team
);
992 //we should update battleground queue, but only if bg isn't ending
993 if (isBattleGround() && GetStatus() < STATUS_WAIT_LEAVE
)
994 sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].Update(bgTypeId
, GetQueueId());
997 sBattleGroundMgr
.BuildPlayerLeftBattleGroundPacket(&data
, guid
);
998 SendPacketToTeam(team
, &data
, plr
, false);
1003 // Do next only if found in battleground
1004 plr
->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE
); // We're not in BG.
1005 // reset destination bg team
1009 plr
->TeleportTo(plr
->GetBattleGroundEntryPoint());
1011 sLog
.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr
->GetName());
1014 if (!GetPlayersSize() && !GetInvitedCount(HORDE
) && !GetInvitedCount(ALLIANCE
))
1016 // if no players left AND no invitees left, set this bg to delete in next update
1017 // direct deletion could cause crashes
1018 m_SetDeleteThis
= true;
1019 // return to prevent addition to freeslotqueue
1023 // a player exited the battleground, so there are free slots. add to queue
1024 this->AddToBGFreeSlotQueue();
1027 // this method is called when no players remains in battleground
1028 void BattleGround::Reset()
1030 SetQueueId(QUEUE_ID_MAX_LEVEL_19
);
1031 SetWinner(WINNER_NONE
);
1032 SetStatus(STATUS_WAIT_QUEUE
);
1035 SetLastResurrectTime(0);
1041 if (m_InvitedAlliance
> 0 || m_InvitedHorde
> 0)
1042 sLog
.outError("BattleGround system: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance
, m_InvitedHorde
);
1044 m_InvitedAlliance
= 0;
1046 m_InBGFreeSlotQueue
= false;
1049 m_PlayerScores
.clear();
1052 void BattleGround::StartBattleGround()
1054 ///this method should spawn spirit guides and so on
1057 SetLastResurrectTime(0);
1060 void BattleGround::AddPlayer(Player
*plr
)
1062 // score struct must be created in inherited class
1064 uint64 guid
= plr
->GetGUID();
1065 uint32 team
= plr
->GetBGTeam();
1067 BattleGroundPlayer bp
;
1068 bp
.OfflineRemoveTime
= 0;
1072 m_Players
[guid
] = bp
;
1074 UpdatePlayersCountByTeam(team
, false); // +1 player
1077 sBattleGroundMgr
.BuildPlayerJoinedBattleGroundPacket(&data
, plr
);
1078 SendPacketToTeam(team
, &data
, plr
, false);
1080 // add arena specific auras
1083 plr
->RemoveArenaSpellCooldowns();
1084 plr
->RemoveArenaAuras();
1085 plr
->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT
);
1086 if(team
== ALLIANCE
) // gold
1088 if (plr
->GetTeam() == HORDE
)
1089 plr
->CastSpell(plr
, SPELL_HORDE_GOLD_FLAG
,true);
1091 plr
->CastSpell(plr
, SPELL_ALLIANCE_GOLD_FLAG
,true);
1095 if (plr
->GetTeam() == HORDE
)
1096 plr
->CastSpell(plr
, SPELL_HORDE_GREEN_FLAG
,true);
1098 plr
->CastSpell(plr
, SPELL_ALLIANCE_GREEN_FLAG
,true);
1101 plr
->DestroyConjuredItems(true);
1102 plr
->UnsummonPetTemporaryIfAny();
1104 if(GetStatus() == STATUS_WAIT_JOIN
) // not started yet
1106 plr
->CastSpell(plr
, SPELL_ARENA_PREPARATION
, true);
1108 plr
->SetHealth(plr
->GetMaxHealth());
1109 plr
->SetPower(POWER_MANA
, plr
->GetMaxPower(POWER_MANA
));
1114 if(GetStatus() == STATUS_WAIT_JOIN
) // not started yet
1115 plr
->CastSpell(plr
, SPELL_PREPARATION
, true); // reduces all mana cost of spells.
1118 plr
->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE
, ACHIEVEMENT_CRITERIA_CONDITION_MAP
, GetMapId());
1119 plr
->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE
, ACHIEVEMENT_CRITERIA_CONDITION_MAP
, GetMapId());
1121 // setup BG group membership
1122 PlayerAddedToBGCheckIfBGIsRunning(plr
);
1123 AddOrSetPlayerToCorrectBgGroup(plr
, guid
, team
);
1126 sLog
.outDetail("BATTLEGROUND: Player %s joined the battle.", plr
->GetName());
1129 /* this method adds player to his team's bg group, or sets his correct group if player is already in bg group */
1130 void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player
*plr
, uint64 plr_guid
, uint32 team
)
1132 Group
* group
= GetBgRaid(team
);
1133 if(!group
) // first player joined
1136 SetBgRaid(team
, group
);
1137 group
->Create(plr_guid
, plr
->GetName());
1139 else // raid already exist
1141 if (group
->IsMember(plr_guid
))
1143 uint8 subgroup
= group
->GetMemberGroup(plr_guid
);
1144 plr
->SetBattleGroundRaid(group
, subgroup
);
1148 group
->AddMember(plr_guid
, plr
->GetName());
1149 if (Group
* originalGroup
= plr
->GetOriginalGroup())
1150 if (originalGroup
->IsLeader(plr_guid
))
1151 group
->ChangeLeader(plr_guid
);
1156 // This method should be called when player logs into running battleground
1157 void BattleGround::EventPlayerLoggedIn(Player
* player
, uint64 plr_guid
)
1159 // player is correct pointer
1160 for(std::deque
<uint64
>::iterator itr
= m_OfflineQueue
.begin(); itr
!= m_OfflineQueue
.end(); ++itr
)
1162 if (*itr
== plr_guid
)
1164 m_OfflineQueue
.erase(itr
);
1168 m_Players
[plr_guid
].OfflineRemoveTime
= 0;
1169 PlayerAddedToBGCheckIfBGIsRunning(player
);
1170 // if battleground is starting, then add preparation aura
1171 // we don't have to do that, because preparation aura isn't removed when player logs out
1174 // This method should be called when player logs out from running battleground
1175 void BattleGround::EventPlayerLoggedOut(Player
* player
)
1177 // player is correct pointer, it is checked in WorldSession::LogoutPlayer()
1178 m_OfflineQueue
.push_back(player
->GetGUID());
1179 m_Players
[player
->GetGUID()].OfflineRemoveTime
= sWorld
.GetGameTime() + MAX_OFFLINE_TIME
;
1180 if (GetStatus() == STATUS_IN_PROGRESS
)
1182 if (isBattleGround())
1183 EventPlayerDroppedFlag(player
);
1186 //1 player is logging out, if it is the last, then end arena!
1187 if (GetAlivePlayersCountByTeam(player
->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player
->GetTeam())))
1188 EndBattleGround(GetOtherTeam(player
->GetTeam()));
1193 /* This method should be called only once ... it adds pointer to queue */
1194 void BattleGround::AddToBGFreeSlotQueue()
1196 // make sure to add only once
1197 if (!m_InBGFreeSlotQueue
&& isBattleGround())
1199 sBattleGroundMgr
.BGFreeSlotQueue
[m_TypeID
].push_front(this);
1200 m_InBGFreeSlotQueue
= true;
1204 /* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
1205 void BattleGround::RemoveFromBGFreeSlotQueue()
1207 // set to be able to re-add if needed
1208 m_InBGFreeSlotQueue
= false;
1209 // uncomment this code when battlegrounds will work like instances
1210 for (BGFreeSlotQueueType::iterator itr
= sBattleGroundMgr
.BGFreeSlotQueue
[m_TypeID
].begin(); itr
!= sBattleGroundMgr
.BGFreeSlotQueue
[m_TypeID
].end(); ++itr
)
1212 if ((*itr
)->GetInstanceID() == m_InstanceID
)
1214 sBattleGroundMgr
.BGFreeSlotQueue
[m_TypeID
].erase(itr
);
1220 // get the number of free slots for team
1221 // returns the number how many players can join battleground to MaxPlayersPerTeam
1222 uint32
BattleGround::GetFreeSlotsForTeam(uint32 Team
) const
1224 //return free slot count to MaxPlayerPerTeam
1225 if (GetStatus() == STATUS_WAIT_JOIN
|| GetStatus() == STATUS_IN_PROGRESS
)
1226 return (GetInvitedCount(Team
) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team
) : 0;
1231 bool BattleGround::HasFreeSlots() const
1233 return GetPlayersSize() < GetMaxPlayers();
1236 void BattleGround::UpdatePlayerScore(Player
*Source
, uint32 type
, uint32 value
)
1238 //this procedure is called from virtual function implemented in bg subclass
1239 std::map
<uint64
, BattleGroundScore
*>::const_iterator itr
= m_PlayerScores
.find(Source
->GetGUID());
1241 if(itr
== m_PlayerScores
.end()) // player not found...
1246 case SCORE_KILLING_BLOWS
: // Killing blows
1247 itr
->second
->KillingBlows
+= value
;
1249 case SCORE_DEATHS
: // Deaths
1250 itr
->second
->Deaths
+= value
;
1252 case SCORE_HONORABLE_KILLS
: // Honorable kills
1253 itr
->second
->HonorableKills
+= value
;
1255 case SCORE_BONUS_HONOR
: // Honor bonus
1256 // do not add honor in arenas
1257 if (isBattleGround())
1259 // reward honor instantly
1260 if (Source
->RewardHonor(NULL
, 1, value
))
1261 itr
->second
->BonusHonor
+= value
;
1264 //used only in EY, but in MSG_PVP_LOG_DATA opcode
1265 case SCORE_DAMAGE_DONE
: // Damage Done
1266 itr
->second
->DamageDone
+= value
;
1268 case SCORE_HEALING_DONE
: // Healing Done
1269 itr
->second
->HealingDone
+= value
;
1272 sLog
.outError("BattleGround: Unknown player score type %u", type
);
1277 void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid
, uint64 player_guid
)
1279 m_ReviveQueue
[npc_guid
].push_back(player_guid
);
1281 Player
*plr
= objmgr
.GetPlayer(player_guid
);
1285 plr
->CastSpell(plr
, SPELL_WAITING_FOR_RESURRECT
, true);
1286 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( SPELL_WAITING_FOR_RESURRECT
);
1289 Aura
*Aur
= CreateAura(spellInfo
, 0, NULL
, plr
);
1294 void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid
)
1296 for(std::map
<uint64
, std::vector
<uint64
> >::iterator itr
= m_ReviveQueue
.begin(); itr
!= m_ReviveQueue
.end(); ++itr
)
1298 for(std::vector
<uint64
>::iterator itr2
=(itr
->second
).begin(); itr2
!= (itr
->second
).end(); ++itr2
)
1300 if (*itr2
== player_guid
)
1302 (itr
->second
).erase(itr2
);
1304 Player
*plr
= objmgr
.GetPlayer(player_guid
);
1308 plr
->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT
);
1316 bool BattleGround::AddObject(uint32 type
, uint32 entry
, float x
, float y
, float z
, float o
, float rotation0
, float rotation1
, float rotation2
, float rotation3
, uint32 respawnTime
)
1318 Map
* map
= MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1322 // must be created this way, adding to godatamap would add it to the base map of the instance
1323 // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
1324 // so we must create it specific for this instance
1325 GameObject
* go
= new GameObject
;
1326 if(!go
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
),entry
, map
,
1327 PHASEMASK_NORMAL
, x
,y
,z
,o
,rotation0
,rotation1
,rotation2
,rotation3
,100,GO_STATE_READY
))
1329 sLog
.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry
);
1330 sLog
.outError("Cannot create gameobject template %u! BattleGround not created!", entry
);
1335 uint32 guid = go->GetGUIDLow();
1337 // without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
1338 // iirc that was changed, so adding to go data map is no longer required if that was the only function using godata from GameObject without checking if it existed
1339 GameObjectData& data = objmgr.NewGOData(guid);
1342 data.mapid = GetMapId();
1346 data.orientation = o;
1347 data.rotation0 = rotation0;
1348 data.rotation1 = rotation1;
1349 data.rotation2 = rotation2;
1350 data.rotation3 = rotation3;
1351 data.spawntimesecs = respawnTime;
1353 data.animprogress = 100;
1356 // add to world, so it can be later looked up from HashMapHolder
1358 m_BgObjects
[type
] = go
->GetGUID();
1362 //some doors aren't despawned so we cannot handle their closing in gameobject::update()
1363 //it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
1364 void BattleGround::DoorClose(uint32 type
)
1366 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1369 //if doors are open, close it
1370 if (obj
->getLootState() == GO_ACTIVATED
&& obj
->GetGoState() != GO_STATE_READY
)
1372 //change state to allow door to be closed
1373 obj
->SetLootState(GO_READY
);
1374 obj
->UseDoorOrButton(RESPAWN_ONE_DAY
);
1379 sLog
.outError("BattleGround: Door object not found (cannot close doors)");
1383 void BattleGround::DoorOpen(uint32 type
)
1385 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1388 //change state to be sure they will be opened
1389 obj
->SetLootState(GO_READY
);
1390 obj
->UseDoorOrButton(RESPAWN_ONE_DAY
);
1394 sLog
.outError("BattleGround: Door object not found! - doors will be closed.");
1398 void BattleGround::SpawnBGObject(uint32 type
, uint32 respawntime
)
1400 Map
* map
= MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1403 if (respawntime
== 0)
1405 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1408 //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
1409 if (obj
->getLootState() == GO_JUST_DEACTIVATED
)
1410 obj
->SetLootState(GO_READY
);
1411 obj
->SetRespawnTime(0);
1417 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1421 obj
->SetRespawnTime(respawntime
);
1422 obj
->SetLootState(GO_JUST_DEACTIVATED
);
1427 Creature
* BattleGround::AddCreature(uint32 entry
, uint32 type
, uint32 teamval
, float x
, float y
, float z
, float o
, uint32 respawntime
)
1429 Map
* map
= MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1433 Creature
* pCreature
= new Creature
;
1434 if (!pCreature
->Create(objmgr
.GenerateLowGuid(HIGHGUID_UNIT
), map
, PHASEMASK_NORMAL
, entry
, teamval
))
1436 sLog
.outError("Can't create creature entry: %u",entry
);
1441 pCreature
->Relocate(x
, y
, z
, o
);
1443 if (!pCreature
->IsPositionValid())
1445 sLog
.outError("Creature (guidlow %d, entry %d) not added to battleground. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature
->GetGUIDLow(),pCreature
->GetEntry(),pCreature
->GetPositionX(),pCreature
->GetPositionY());
1449 pCreature
->AIM_Initialize();
1451 //pCreature->SetDungeonDifficulty(0);
1453 map
->Add(pCreature
);
1454 m_BgCreatures
[type
] = pCreature
->GetGUID();
1459 void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)
1461 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceId());
1465 if (respawntime == 0)
1467 Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1470 //obj->Respawn(); // bugged
1471 obj->SetRespawnTime(0);
1472 objmgr.SaveCreatureRespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);
1478 Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1481 obj->setDeathState(DEAD);
1482 obj->SetRespawnTime(respawntime);
1488 bool BattleGround::DelCreature(uint32 type
)
1490 if (!m_BgCreatures
[type
])
1493 Creature
*cr
= HashMapHolder
<Creature
>::Find(m_BgCreatures
[type
]);
1496 sLog
.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures
[type
]));
1499 cr
->CleanupsBeforeDelete();
1500 cr
->AddObjectToRemoveList();
1501 m_BgCreatures
[type
] = 0;
1505 bool BattleGround::DelObject(uint32 type
)
1507 if (!m_BgObjects
[type
])
1510 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1513 sLog
.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects
[type
]));
1516 obj
->SetRespawnTime(0); // not save respawn time
1518 m_BgObjects
[type
] = 0;
1522 bool BattleGround::AddSpiritGuide(uint32 type
, float x
, float y
, float z
, float o
, uint32 team
)
1526 if (team
== ALLIANCE
)
1531 Creature
* pCreature
= AddCreature(entry
,type
,team
,x
,y
,z
,o
);
1534 sLog
.outError("Can't create Spirit guide. BattleGround not created!");
1539 pCreature
->setDeathState(DEAD
);
1541 pCreature
->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT
, pCreature
->GetGUID());
1543 pCreature
->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL
);
1544 //pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
1545 //pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
1546 //pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
1547 // casting visual effect
1548 pCreature
->SetUInt32Value(UNIT_CHANNEL_SPELL
, SPELL_SPIRIT_HEAL_CHANNEL
);
1549 // correct cast speed
1550 pCreature
->SetFloatValue(UNIT_MOD_CAST_SPEED
, 1.0f
);
1552 //pCreature->CastSpell(pCreature, SPELL_SPIRIT_HEAL_CHANNEL, true);
1557 void BattleGround::SendMessageToAll(int32 entry
, ChatMsg type
, Player
const* source
)
1559 MaNGOS::BattleGroundChatBuilder
bg_builder(type
, entry
, source
);
1560 MaNGOS::LocalizedPacketDo
<MaNGOS::BattleGroundChatBuilder
> bg_do(bg_builder
);
1561 BroadcastWorker(bg_do
);
1564 void BattleGround::PSendMessageToAll(int32 entry
, ChatMsg type
, Player
const* source
, ...)
1567 va_start(ap
, source
);
1569 MaNGOS::BattleGroundChatBuilder
bg_builder(type
, entry
, source
, &ap
);
1570 MaNGOS::LocalizedPacketDo
<MaNGOS::BattleGroundChatBuilder
> bg_do(bg_builder
);
1571 BroadcastWorker(bg_do
);
1576 void BattleGround::SendMessage2ToAll(int32 entry
, ChatMsg type
, Player
const* source
, int32 arg1
, int32 arg2
)
1578 MaNGOS::BattleGround2ChatBuilder
bg_builder(type
, entry
, source
, arg1
, arg2
);
1579 MaNGOS::LocalizedPacketDo
<MaNGOS::BattleGround2ChatBuilder
> bg_do(bg_builder
);
1580 BroadcastWorker(bg_do
);
1583 void BattleGround::EndNow()
1585 RemoveFromBGFreeSlotQueue();
1586 SetStatus(STATUS_WAIT_LEAVE
);
1592 buffs aren't spawned/despawned when players captures anything
1593 buffs are in their positions when battleground starts
1595 void BattleGround::HandleTriggerBuff(uint64
const& go_guid
)
1597 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(go_guid
);
1598 if (!obj
|| obj
->GetGoType() != GAMEOBJECT_TYPE_TRAP
|| !obj
->isSpawned())
1601 //change buff type, when buff is used:
1602 int32 index
= m_BgObjects
.size() - 1;
1603 while (index
>= 0 && m_BgObjects
[index
] != go_guid
)
1607 sLog
.outError("BattleGround (Type: %u) has buff gameobject (Guid: %u Entry: %u Type:%u) but it hasn't that object in its internal data",GetTypeID(),GUID_LOPART(go_guid
),obj
->GetEntry(),obj
->GetGoType());
1611 //randomly select new buff
1612 uint8 buff
= urand(0, 2);
1613 uint32 entry
= obj
->GetEntry();
1614 if (m_BuffChange
&& entry
!= Buff_Entries
[buff
])
1616 //despawn current buff
1617 SpawnBGObject(index
, RESPAWN_ONE_DAY
);
1618 //set index for new one
1619 for (uint8 currBuffTypeIndex
= 0; currBuffTypeIndex
< 3; ++currBuffTypeIndex
)
1620 if (entry
== Buff_Entries
[currBuffTypeIndex
])
1622 index
-= currBuffTypeIndex
;
1627 SpawnBGObject(index
, BUFF_RESPAWN_TIME
);
1630 void BattleGround::HandleKillPlayer( Player
*player
, Player
*killer
)
1632 //keep in mind that for arena this will have to be changed a bit
1635 UpdatePlayerScore(player
, SCORE_DEATHS
, 1);
1637 // add +1 kills to group and +1 killing_blows to killer
1640 UpdatePlayerScore(killer
, SCORE_HONORABLE_KILLS
, 1);
1641 UpdatePlayerScore(killer
, SCORE_KILLING_BLOWS
, 1);
1643 for(BattleGroundPlayerMap::const_iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
1645 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
1647 if (!plr
|| plr
== killer
)
1650 if (plr
->GetTeam() == killer
->GetTeam() && plr
->IsAtGroupRewardDistance(player
))
1651 UpdatePlayerScore(plr
, SCORE_HONORABLE_KILLS
, 1);
1655 // to be able to remove insignia -- ONLY IN BattleGrounds
1657 player
->SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
);
1660 // return the player's team based on battlegroundplayer info
1661 // used in same faction arena matches mainly
1662 uint32
BattleGround::GetPlayerTeam(uint64 guid
)
1664 BattleGroundPlayerMap::const_iterator itr
= m_Players
.find(guid
);
1665 if (itr
!=m_Players
.end())
1666 return itr
->second
.Team
;
1670 uint32
BattleGround::GetOtherTeam(uint32 teamId
)
1672 return (teamId
) ? ((teamId
== ALLIANCE
) ? HORDE
: ALLIANCE
) : 0;
1675 bool BattleGround::IsPlayerInBattleGround(uint64 guid
)
1677 BattleGroundPlayerMap::const_iterator itr
= m_Players
.find(guid
);
1678 if (itr
!= m_Players
.end())
1683 void BattleGround::PlayerAddedToBGCheckIfBGIsRunning(Player
* plr
)
1685 if (GetStatus() != STATUS_WAIT_LEAVE
)
1689 BattleGroundQueueTypeId bgQueueTypeId
= BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
1693 sBattleGroundMgr
.BuildPvpLogDataPacket(&data
, this);
1694 plr
->GetSession()->SendPacket(&data
);
1696 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, this, plr
->GetBattleGroundQueueIndex(bgQueueTypeId
), STATUS_IN_PROGRESS
, GetEndTime(), GetStartTime(), GetArenaType());
1697 plr
->GetSession()->SendPacket(&data
);
1700 uint32
BattleGround::GetAlivePlayersCountByTeam(uint32 Team
) const
1703 for(BattleGroundPlayerMap::const_iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
1705 if (itr
->second
.Team
== Team
)
1707 Player
* pl
= objmgr
.GetPlayer(itr
->first
);
1708 if (pl
&& pl
->isAlive())
1715 void BattleGround::CheckArenaWinConditions()
1717 if (!GetAlivePlayersCountByTeam(ALLIANCE
) && GetPlayersCountByTeam(HORDE
))
1718 EndBattleGround(HORDE
);
1719 else if (GetPlayersCountByTeam(ALLIANCE
) && !GetAlivePlayersCountByTeam(HORDE
))
1720 EndBattleGround(ALLIANCE
);
1723 void BattleGround::SetBgRaid( uint32 TeamID
, Group
*bg_raid
)
1725 Group
* &old_raid
= TeamID
== ALLIANCE
? m_BgRaids
[BG_TEAM_ALLIANCE
] : m_BgRaids
[BG_TEAM_HORDE
];
1726 if(old_raid
) old_raid
->SetBattlegroundGroup(NULL
);
1727 if(bg_raid
) bg_raid
->SetBattlegroundGroup(this);
1731 WorldSafeLocsEntry
const* BattleGround::GetClosestGraveYard( Player
* player
)
1733 return objmgr
.GetClosestGraveYard( player
->GetPositionX(), player
->GetPositionY(), player
->GetPositionZ(), player
->GetMapId(), player
->GetTeam() );