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::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
>::iterator itr2
= (itr
->second
).begin(); itr2
!= (itr
->second
).end(); ++itr2
)
265 Player
*plr
= objmgr
.GetPlayer(*itr2
);
271 sh
= ObjectAccessor::GetCreature(*plr
, 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
>::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::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::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::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::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::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::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();
742 // inform invited players about the removal
743 sBattleGroundMgr
.m_BattleGroundQueues
[BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
746 SendMessageToAll(winmsg_id
, CHAT_MSG_BG_SYSTEM_NEUTRAL
);
749 uint32
BattleGround::GetBonusHonorFromKill(uint32 kills
) const
751 //variable kills means how many honorable kills you scored (so we need kills * honor_for_one_kill)
752 return MaNGOS::Honor::hk_honor_at_level(GetMaxLevel(), kills
);
755 uint32
BattleGround::GetBattlemasterEntry() const
759 case BATTLEGROUND_AV
: return 15972;
760 case BATTLEGROUND_WS
: return 14623;
761 case BATTLEGROUND_AB
: return 14879;
762 case BATTLEGROUND_EY
: return 22516;
763 case BATTLEGROUND_NA
: return 20200;
768 void BattleGround::RewardMark(Player
*plr
,uint32 count
)
770 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
771 if(plr
->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE
))
774 BattleGroundMarks mark
;
778 case BATTLEGROUND_AV
:
780 if(count
== ITEM_WINNER_COUNT
)
781 mark
= SPELL_AV_MARK_WINNER
;
783 mark
= SPELL_AV_MARK_LOSER
;
785 case BATTLEGROUND_WS
:
787 if(count
== ITEM_WINNER_COUNT
)
788 mark
= SPELL_WS_MARK_WINNER
;
790 mark
= SPELL_WS_MARK_LOSER
;
792 case BATTLEGROUND_AB
:
794 if(count
== ITEM_WINNER_COUNT
)
795 mark
= SPELL_AB_MARK_WINNER
;
797 mark
= SPELL_AB_MARK_LOSER
;
799 case BATTLEGROUND_EY
:
801 mark
= ITEM_EY_MARK_OF_HONOR
;
808 plr
->CastSpell(plr
, mark
, true);
809 else if ( objmgr
.GetItemPrototype( mark
) )
811 ItemPosCountVec dest
;
812 uint32 no_space_count
= 0;
813 uint8 msg
= plr
->CanStoreNewItem( NULL_BAG
, NULL_SLOT
, dest
, mark
, count
, &no_space_count
);
814 if( msg
!= EQUIP_ERR_OK
) // convert to possible store amount
815 count
-= no_space_count
;
817 if( count
!= 0 && !dest
.empty()) // can add some
818 if(Item
* item
= plr
->StoreNewItem( dest
, mark
, true, 0))
819 plr
->SendNewItem(item
,count
,false,true);
821 if(no_space_count
> 0)
822 SendRewardMarkByMail(plr
,mark
,no_space_count
);
826 void BattleGround::SendRewardMarkByMail(Player
*plr
,uint32 mark
, uint32 count
)
828 uint32 bmEntry
= GetBattlemasterEntry();
832 ItemPrototype
const* markProto
= objmgr
.GetItemPrototype(mark
);
836 if(Item
* markItem
= Item::CreateItem(mark
,count
,plr
))
838 // save new item before send
839 markItem
->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
843 mi
.AddItem(markItem
->GetGUIDLow(), markItem
->GetEntry(), markItem
);
845 // subject: item name
846 std::string subject
= markProto
->Name1
;
847 int loc_idx
= plr
->GetSession()->GetSessionDbLocaleIndex();
849 if(ItemLocale
const *il
= objmgr
.GetItemLocale(markProto
->ItemId
))
850 if (il
->Name
.size() > size_t(loc_idx
) && !il
->Name
[loc_idx
].empty())
851 subject
= il
->Name
[loc_idx
];
854 std::string textFormat
= plr
->GetSession()->GetMangosString(LANG_BG_MARK_BY_MAIL
);
856 snprintf(textBuf
,300,textFormat
.c_str(),GetName(),GetName());
857 uint32 itemTextId
= objmgr
.CreateItemText( textBuf
);
859 WorldSession::SendMailTo(plr
, MAIL_CREATURE
, MAIL_STATIONERY_NORMAL
, bmEntry
, plr
->GetGUIDLow(), subject
, itemTextId
, &mi
, 0, 0, MAIL_CHECK_MASK_NONE
);
863 void BattleGround::RewardQuest(Player
*plr
)
865 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
866 if(plr
->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE
))
872 case BATTLEGROUND_AV
:
873 quest
= SPELL_AV_QUEST_REWARD
;
875 case BATTLEGROUND_WS
:
876 quest
= SPELL_WS_QUEST_REWARD
;
878 case BATTLEGROUND_AB
:
879 quest
= SPELL_AB_QUEST_REWARD
;
881 case BATTLEGROUND_EY
:
882 quest
= SPELL_EY_QUEST_REWARD
;
888 plr
->CastSpell(plr
, quest
, true);
891 void BattleGround::BlockMovement(Player
*plr
)
893 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()
896 void BattleGround::RemovePlayerAtLeave(uint64 guid
, bool Transport
, bool SendPacket
)
898 uint32 team
= GetPlayerTeam(guid
);
899 bool participant
= false;
900 // Remove from lists/maps
901 BattleGroundPlayerMap::iterator itr
= m_Players
.find(guid
);
902 if(itr
!= m_Players
.end())
904 UpdatePlayersCountByTeam(team
, true); // -1 player
905 m_Players
.erase(itr
);
906 // check if the player was a participant of the match, or only entered through gm command (goname)
910 std::map
<uint64
, BattleGroundScore
*>::iterator itr2
= m_PlayerScores
.find(guid
);
911 if(itr2
!= m_PlayerScores
.end())
913 delete itr2
->second
; // delete player's score
914 m_PlayerScores
.erase(itr2
);
917 RemovePlayerFromResurrectQueue(guid
);
919 Player
*plr
= objmgr
.GetPlayer(guid
);
921 // should remove spirit of redemption
922 if(plr
&& plr
->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION
))
923 plr
->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT
);
925 if(plr
&& !plr
->isAlive()) // resurrect on exit
927 plr
->ResurrectPlayer(1.0f
);
928 plr
->SpawnCorpseBones();
931 RemovePlayer(plr
, guid
); // BG subclass specific code
933 if(participant
) // if the player was a match participant, remove auras, calc rating, update queue
935 BattleGroundTypeId bgTypeId
= GetTypeID();
936 BattleGroundQueueTypeId bgQueueTypeId
= BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
939 plr
->ClearAfkReports();
941 if(!team
) team
= plr
->GetTeam();
943 // if arena, remove the specific arena auras
946 plr
->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out
947 bgTypeId
=BATTLEGROUND_AA
; // set the bg type to all arenas (it will be used for queue refreshing)
949 // summon old pet if there was one and there isn't a current pet
950 if(!plr
->GetPet() && plr
->GetTemporaryUnsummonedPetNumber())
952 Pet
* NewPet
= new Pet
;
953 if(!NewPet
->LoadPetFromDB(plr
, 0, (plr
)->GetTemporaryUnsummonedPetNumber(), true))
956 (plr
)->SetTemporaryUnsummonedPetNumber(0);
959 if(isRated() && GetStatus() == STATUS_IN_PROGRESS
)
961 //left a rated match while the encounter was in progress, consider as loser
962 ArenaTeam
* winner_arena_team
= objmgr
.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team
)));
963 ArenaTeam
* loser_arena_team
= objmgr
.GetArenaTeamById(GetArenaTeamIdForTeam(team
));
964 if(winner_arena_team
&& loser_arena_team
)
965 loser_arena_team
->MemberLost(plr
,winner_arena_team
->GetRating());
971 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, this, plr
->GetBattleGroundQueueIndex(bgQueueTypeId
), STATUS_NONE
, 0, 0, 0);
972 plr
->GetSession()->SendPacket(&data
);
975 // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
976 plr
->RemoveBattleGroundQueueId(bgQueueTypeId
);
979 // removing offline participant
981 if(isRated() && GetStatus() == STATUS_IN_PROGRESS
)
983 //left a rated match while the encounter was in progress, consider as loser
984 ArenaTeam
* others_arena_team
= objmgr
.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team
)));
985 ArenaTeam
* players_arena_team
= objmgr
.GetArenaTeamById(GetArenaTeamIdForTeam(team
));
986 if( others_arena_team
&& players_arena_team
)
987 players_arena_team
->OfflineMemberLost(guid
, others_arena_team
->GetRating());
991 // remove from raid group if player is member
992 if(Group
*group
= GetBgRaid(team
))
994 if( !group
->RemoveMember(guid
, 0) ) // group was disbanded
996 SetBgRaid(team
, NULL
);
1000 DecreaseInvitedCount(team
);
1001 //we should update battleground queue, but only if bg isn't ending
1002 if( isBattleGround() && GetStatus() < STATUS_WAIT_LEAVE
)
1003 sBattleGroundMgr
.m_BattleGroundQueues
[bgQueueTypeId
].Update(bgTypeId
, GetQueueId());
1006 sBattleGroundMgr
.BuildPlayerLeftBattleGroundPacket(&data
, guid
);
1007 SendPacketToTeam(team
, &data
, plr
, false);
1012 // Do next only if found in battleground
1013 plr
->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE
); // We're not in BG.
1014 // reset destination bg team
1018 plr
->TeleportTo(plr
->GetBattleGroundEntryPoint());
1020 sLog
.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr
->GetName());
1023 if(!GetPlayersSize() && !GetInvitedCount(HORDE
) && !GetInvitedCount(ALLIANCE
))
1025 // if no players left AND no invitees left, set this bg to delete in next update
1026 // direct deletion could cause crashes
1027 m_SetDeleteThis
= true;
1028 // return to prevent addition to freeslotqueue
1032 // a player exited the battleground, so there are free slots. add to queue
1033 this->AddToBGFreeSlotQueue();
1036 // this method is called when no players remains in battleground
1037 void BattleGround::Reset()
1039 SetQueueId(QUEUE_ID_MAX_LEVEL_19
);
1040 SetWinner(WINNER_NONE
);
1041 SetStatus(STATUS_WAIT_QUEUE
);
1044 SetLastResurrectTime(0);
1050 if (m_InvitedAlliance
> 0 || m_InvitedHorde
> 0)
1051 sLog
.outError("BattleGround system: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance
, m_InvitedHorde
);
1053 m_InvitedAlliance
= 0;
1055 m_InBGFreeSlotQueue
= false;
1058 m_PlayerScores
.clear();
1061 void BattleGround::StartBattleGround()
1063 ///this method should spawn spirit guides and so on
1066 SetLastResurrectTime(0);
1069 void BattleGround::AddPlayer(Player
*plr
)
1071 // score struct must be created in inherited class
1073 uint64 guid
= plr
->GetGUID();
1074 uint32 team
= plr
->GetBGTeam();
1076 BattleGroundPlayer bp
;
1077 bp
.OfflineRemoveTime
= 0;
1081 m_Players
[guid
] = bp
;
1083 UpdatePlayersCountByTeam(team
, false); // +1 player
1086 sBattleGroundMgr
.BuildPlayerJoinedBattleGroundPacket(&data
, plr
);
1087 SendPacketToTeam(team
, &data
, plr
, false);
1089 // add arena specific auras
1092 plr
->RemoveArenaSpellCooldowns();
1093 plr
->RemoveArenaAuras();
1094 plr
->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT
);
1095 if(team
== ALLIANCE
) // gold
1097 if(plr
->GetTeam() == HORDE
)
1098 plr
->CastSpell(plr
, SPELL_HORDE_GOLD_FLAG
,true);
1100 plr
->CastSpell(plr
, SPELL_ALLIANCE_GOLD_FLAG
,true);
1104 if(plr
->GetTeam() == HORDE
)
1105 plr
->CastSpell(plr
, SPELL_HORDE_GREEN_FLAG
,true);
1107 plr
->CastSpell(plr
, SPELL_ALLIANCE_GREEN_FLAG
,true);
1110 plr
->DestroyConjuredItems(true);
1112 Pet
* pet
= plr
->GetPet();
1115 if(pet
->getPetType() == SUMMON_PET
|| pet
->getPetType() == HUNTER_PET
)
1117 (plr
)->SetTemporaryUnsummonedPetNumber(pet
->GetCharmInfo()->GetPetNumber());
1118 (plr
)->SetOldPetSpell(pet
->GetUInt32Value(UNIT_CREATED_BY_SPELL
));
1120 (plr
)->RemovePet(NULL
,PET_SAVE_NOT_IN_SLOT
);
1123 (plr
)->SetTemporaryUnsummonedPetNumber(0);
1125 if(GetStatus() == STATUS_WAIT_JOIN
) // not started yet
1127 plr
->CastSpell(plr
, SPELL_ARENA_PREPARATION
, true);
1129 plr
->SetHealth(plr
->GetMaxHealth());
1130 plr
->SetPower(POWER_MANA
, plr
->GetMaxPower(POWER_MANA
));
1135 if(GetStatus() == STATUS_WAIT_JOIN
) // not started yet
1136 plr
->CastSpell(plr
, SPELL_PREPARATION
, true); // reduces all mana cost of spells.
1139 // setup BG group membership
1140 PlayerAddedToBGCheckIfBGIsRunning(plr
);
1141 AddOrSetPlayerToCorrectBgGroup(plr
, guid
, team
);
1144 sLog
.outDetail("BATTLEGROUND: Player %s joined the battle.", plr
->GetName());
1147 /* this method adds player to his team's bg group, or sets his correct group if player is already in bg group */
1148 void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player
*plr
, uint64 plr_guid
, uint32 team
)
1150 Group
* group
= GetBgRaid(team
);
1151 if(!group
) // first player joined
1154 SetBgRaid(team
, group
);
1155 group
->Create(plr_guid
, plr
->GetName());
1157 else // raid already exist
1159 if(group
->IsMember(plr_guid
))
1161 uint8 subgroup
= group
->GetMemberGroup(plr_guid
);
1162 plr
->SetBattleGroundRaid(group
, subgroup
);
1166 group
->AddMember(plr_guid
, plr
->GetName());
1167 if( Group
* originalGroup
= plr
->GetOriginalGroup() )
1168 if( originalGroup
->IsLeader(plr_guid
) )
1169 group
->ChangeLeader(plr_guid
);
1174 // This method should be called when player logs into running battleground
1175 void BattleGround::EventPlayerLoggedIn(Player
* player
, uint64 plr_guid
)
1177 // player is correct pointer
1178 for(std::deque
<uint64
>::iterator itr
= m_OfflineQueue
.begin(); itr
!= m_OfflineQueue
.end(); ++itr
)
1180 if( *itr
== plr_guid
)
1182 m_OfflineQueue
.erase(itr
);
1186 m_Players
[plr_guid
].OfflineRemoveTime
= 0;
1187 PlayerAddedToBGCheckIfBGIsRunning(player
);
1188 // if battleground is starting, then add preparation aura
1189 // we don't have to do that, because preparation aura isn't removed when player logs out
1192 // This method should be called when player logs out from running battleground
1193 void BattleGround::EventPlayerLoggedOut(Player
* player
)
1195 // player is correct pointer, it is checked in WorldSession::LogoutPlayer()
1196 m_OfflineQueue
.push_back(player
->GetGUID());
1197 m_Players
[player
->GetGUID()].OfflineRemoveTime
= sWorld
.GetGameTime() + MAX_OFFLINE_TIME
;
1198 if( GetStatus() == STATUS_IN_PROGRESS
)
1200 if( isBattleGround() )
1201 EventPlayerDroppedFlag(player
);
1204 //1 player is logging out, if it is the last, then end arena!
1205 if( GetAlivePlayersCountByTeam(player
->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player
->GetTeam())) )
1206 EndBattleGround(GetOtherTeam(player
->GetTeam()));
1211 /* This method should be called only once ... it adds pointer to queue */
1212 void BattleGround::AddToBGFreeSlotQueue()
1214 // make sure to add only once
1215 if(!m_InBGFreeSlotQueue
&& isBattleGround())
1217 sBattleGroundMgr
.BGFreeSlotQueue
[m_TypeID
].push_front(this);
1218 m_InBGFreeSlotQueue
= true;
1222 /* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
1223 void BattleGround::RemoveFromBGFreeSlotQueue()
1225 // set to be able to re-add if needed
1226 m_InBGFreeSlotQueue
= false;
1227 // uncomment this code when battlegrounds will work like instances
1228 for (BGFreeSlotQueueType::iterator itr
= sBattleGroundMgr
.BGFreeSlotQueue
[m_TypeID
].begin(); itr
!= sBattleGroundMgr
.BGFreeSlotQueue
[m_TypeID
].end(); ++itr
)
1230 if ((*itr
)->GetInstanceID() == m_InstanceID
)
1232 sBattleGroundMgr
.BGFreeSlotQueue
[m_TypeID
].erase(itr
);
1238 // get the number of free slots for team
1239 // returns the number how many players can join battleground to MaxPlayersPerTeam
1240 uint32
BattleGround::GetFreeSlotsForTeam(uint32 Team
) const
1242 //return free slot count to MaxPlayerPerTeam
1243 if (GetStatus() == STATUS_WAIT_JOIN
|| GetStatus() == STATUS_IN_PROGRESS
)
1244 return (GetInvitedCount(Team
) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team
) : 0;
1249 bool BattleGround::HasFreeSlots() const
1251 return GetPlayersSize() < GetMaxPlayers();
1254 void BattleGround::UpdatePlayerScore(Player
*Source
, uint32 type
, uint32 value
)
1256 //this procedure is called from virtual function implemented in bg subclass
1257 std::map
<uint64
, BattleGroundScore
*>::iterator itr
= m_PlayerScores
.find(Source
->GetGUID());
1259 if(itr
== m_PlayerScores
.end()) // player not found...
1264 case SCORE_KILLING_BLOWS
: // Killing blows
1265 itr
->second
->KillingBlows
+= value
;
1267 case SCORE_DEATHS
: // Deaths
1268 itr
->second
->Deaths
+= value
;
1270 case SCORE_HONORABLE_KILLS
: // Honorable kills
1271 itr
->second
->HonorableKills
+= value
;
1273 case SCORE_BONUS_HONOR
: // Honor bonus
1274 // do not add honor in arenas
1275 if(isBattleGround())
1277 // reward honor instantly
1278 if(Source
->RewardHonor(NULL
, 1, value
))
1279 itr
->second
->BonusHonor
+= value
;
1282 //used only in EY, but in MSG_PVP_LOG_DATA opcode
1283 case SCORE_DAMAGE_DONE
: // Damage Done
1284 itr
->second
->DamageDone
+= value
;
1286 case SCORE_HEALING_DONE
: // Healing Done
1287 itr
->second
->HealingDone
+= value
;
1290 sLog
.outError("BattleGround: Unknown player score type %u", type
);
1295 void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid
, uint64 player_guid
)
1297 m_ReviveQueue
[npc_guid
].push_back(player_guid
);
1299 Player
*plr
= objmgr
.GetPlayer(player_guid
);
1303 plr
->CastSpell(plr
, SPELL_WAITING_FOR_RESURRECT
, true);
1304 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( SPELL_WAITING_FOR_RESURRECT
);
1307 Aura
*Aur
= CreateAura(spellInfo
, 0, NULL
, plr
);
1312 void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid
)
1314 for(std::map
<uint64
, std::vector
<uint64
> >::iterator itr
= m_ReviveQueue
.begin(); itr
!= m_ReviveQueue
.end(); ++itr
)
1316 for(std::vector
<uint64
>::iterator itr2
=(itr
->second
).begin(); itr2
!= (itr
->second
).end(); ++itr2
)
1318 if(*itr2
== player_guid
)
1320 (itr
->second
).erase(itr2
);
1322 Player
*plr
= objmgr
.GetPlayer(player_guid
);
1326 plr
->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT
);
1334 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
)
1336 Map
* map
= MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1340 // must be created this way, adding to godatamap would add it to the base map of the instance
1341 // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
1342 // so we must create it specific for this instance
1343 GameObject
* go
= new GameObject
;
1344 if(!go
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
),entry
, map
,
1345 PHASEMASK_NORMAL
, x
,y
,z
,o
,rotation0
,rotation1
,rotation2
,rotation3
,100,1))
1347 sLog
.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry
);
1348 sLog
.outError("Cannot create gameobject template %u! BattleGround not created!", entry
);
1353 uint32 guid = go->GetGUIDLow();
1355 // without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
1356 // 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
1357 GameObjectData& data = objmgr.NewGOData(guid);
1360 data.mapid = GetMapId();
1364 data.orientation = o;
1365 data.rotation0 = rotation0;
1366 data.rotation1 = rotation1;
1367 data.rotation2 = rotation2;
1368 data.rotation3 = rotation3;
1369 data.spawntimesecs = respawnTime;
1371 data.animprogress = 100;
1374 // add to world, so it can be later looked up from HashMapHolder
1376 m_BgObjects
[type
] = go
->GetGUID();
1380 //some doors aren't despawned so we cannot handle their closing in gameobject::update()
1381 //it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
1382 void BattleGround::DoorClose(uint32 type
)
1384 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1387 //if doors are open, close it
1388 if( obj
->getLootState() == GO_ACTIVATED
&& !obj
->GetGoState() )
1390 //change state to allow door to be closed
1391 obj
->SetLootState(GO_READY
);
1392 obj
->UseDoorOrButton(RESPAWN_ONE_DAY
);
1397 sLog
.outError("BattleGround: Door object not found (cannot close doors)");
1401 void BattleGround::DoorOpen(uint32 type
)
1403 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1406 //change state to be sure they will be opened
1407 obj
->SetLootState(GO_READY
);
1408 obj
->UseDoorOrButton(RESPAWN_ONE_DAY
);
1412 sLog
.outError("BattleGround: Door object not found! - doors will be closed.");
1416 void BattleGround::SpawnBGObject(uint32 type
, uint32 respawntime
)
1418 Map
* map
= MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1421 if( respawntime
== 0 )
1423 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1426 //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
1427 if( obj
->getLootState() == GO_JUST_DEACTIVATED
)
1428 obj
->SetLootState(GO_READY
);
1429 obj
->SetRespawnTime(0);
1435 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1439 obj
->SetRespawnTime(respawntime
);
1440 obj
->SetLootState(GO_JUST_DEACTIVATED
);
1445 Creature
* BattleGround::AddCreature(uint32 entry
, uint32 type
, uint32 teamval
, float x
, float y
, float z
, float o
, uint32 respawntime
)
1447 Map
* map
= MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1451 Creature
* pCreature
= new Creature
;
1452 if (!pCreature
->Create(objmgr
.GenerateLowGuid(HIGHGUID_UNIT
), map
, PHASEMASK_NORMAL
, entry
, teamval
))
1454 sLog
.outError("Can't create creature entry: %u",entry
);
1459 pCreature
->Relocate(x
, y
, z
, o
);
1461 if(!pCreature
->IsPositionValid())
1463 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());
1467 pCreature
->AIM_Initialize();
1469 //pCreature->SetDungeonDifficulty(0);
1471 map
->Add(pCreature
);
1472 m_BgCreatures
[type
] = pCreature
->GetGUID();
1477 void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)
1479 Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceId());
1483 if(respawntime == 0)
1485 Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1488 //obj->Respawn(); // bugged
1489 obj->SetRespawnTime(0);
1490 objmgr.SaveCreatureRespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);
1496 Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1499 obj->setDeathState(DEAD);
1500 obj->SetRespawnTime(respawntime);
1506 bool BattleGround::DelCreature(uint32 type
)
1508 if(!m_BgCreatures
[type
])
1511 Creature
*cr
= HashMapHolder
<Creature
>::Find(m_BgCreatures
[type
]);
1514 sLog
.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures
[type
]));
1517 cr
->CleanupsBeforeDelete();
1518 cr
->AddObjectToRemoveList();
1519 m_BgCreatures
[type
] = 0;
1523 bool BattleGround::DelObject(uint32 type
)
1525 if(!m_BgObjects
[type
])
1528 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1531 sLog
.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects
[type
]));
1534 obj
->SetRespawnTime(0); // not save respawn time
1536 m_BgObjects
[type
] = 0;
1540 bool BattleGround::AddSpiritGuide(uint32 type
, float x
, float y
, float z
, float o
, uint32 team
)
1544 if(team
== ALLIANCE
)
1549 Creature
* pCreature
= AddCreature(entry
,type
,team
,x
,y
,z
,o
);
1552 sLog
.outError("Can't create Spirit guide. BattleGround not created!");
1557 pCreature
->setDeathState(DEAD
);
1559 pCreature
->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT
, pCreature
->GetGUID());
1561 pCreature
->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL
);
1562 //pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
1563 //pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
1564 //pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
1565 // casting visual effect
1566 pCreature
->SetUInt32Value(UNIT_CHANNEL_SPELL
, SPELL_SPIRIT_HEAL_CHANNEL
);
1567 // correct cast speed
1568 pCreature
->SetFloatValue(UNIT_MOD_CAST_SPEED
, 1.0f
);
1570 //pCreature->CastSpell(pCreature, SPELL_SPIRIT_HEAL_CHANNEL, true);
1575 void BattleGround::SendMessageToAll(int32 entry
, ChatMsg type
, Player
const* source
)
1577 MaNGOS::BattleGroundChatBuilder
bg_builder(type
, entry
, source
);
1578 MaNGOS::LocalizedPacketDo
<MaNGOS::BattleGroundChatBuilder
> bg_do(bg_builder
);
1579 BroadcastWorker(bg_do
);
1582 void BattleGround::PSendMessageToAll(int32 entry
, ChatMsg type
, Player
const* source
, ...)
1585 va_start(ap
, source
);
1587 MaNGOS::BattleGroundChatBuilder
bg_builder(type
, entry
, source
, &ap
);
1588 MaNGOS::LocalizedPacketDo
<MaNGOS::BattleGroundChatBuilder
> bg_do(bg_builder
);
1589 BroadcastWorker(bg_do
);
1594 void BattleGround::SendMessage2ToAll(int32 entry
, ChatMsg type
, Player
const* source
, int32 arg1
, int32 arg2
)
1596 MaNGOS::BattleGround2ChatBuilder
bg_builder(type
, entry
, source
, arg1
, arg2
);
1597 MaNGOS::LocalizedPacketDo
<MaNGOS::BattleGround2ChatBuilder
> bg_do(bg_builder
);
1598 BroadcastWorker(bg_do
);
1601 void BattleGround::EndNow()
1603 RemoveFromBGFreeSlotQueue();
1604 SetStatus(STATUS_WAIT_LEAVE
);
1606 // inform invited players about the removal
1607 sBattleGroundMgr
.m_BattleGroundQueues
[BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
1612 buffs aren't spawned/despawned when players captures anything
1613 buffs are in their positions when battleground starts
1615 void BattleGround::HandleTriggerBuff(uint64
const& go_guid
)
1617 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(go_guid
);
1618 if(!obj
|| obj
->GetGoType() != GAMEOBJECT_TYPE_TRAP
|| !obj
->isSpawned())
1621 //change buff type, when buff is used:
1622 int32 index
= m_BgObjects
.size() - 1;
1623 while (index
>= 0 && m_BgObjects
[index
] != go_guid
)
1627 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());
1631 //randomly select new buff
1632 uint8 buff
= urand(0, 2);
1633 uint32 entry
= obj
->GetEntry();
1634 if( m_BuffChange
&& entry
!= Buff_Entries
[buff
] )
1636 //despawn current buff
1637 SpawnBGObject(index
, RESPAWN_ONE_DAY
);
1638 //set index for new one
1639 for (uint8 currBuffTypeIndex
= 0; currBuffTypeIndex
< 3; ++currBuffTypeIndex
)
1640 if( entry
== Buff_Entries
[currBuffTypeIndex
] )
1642 index
-= currBuffTypeIndex
;
1647 SpawnBGObject(index
, BUFF_RESPAWN_TIME
);
1650 void BattleGround::HandleKillPlayer( Player
*player
, Player
*killer
)
1652 //keep in mind that for arena this will have to be changed a bit
1655 UpdatePlayerScore(player
, SCORE_DEATHS
, 1);
1657 // add +1 kills to group and +1 killing_blows to killer
1660 UpdatePlayerScore(killer
, SCORE_HONORABLE_KILLS
, 1);
1661 UpdatePlayerScore(killer
, SCORE_KILLING_BLOWS
, 1);
1663 for(BattleGroundPlayerMap::iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
1665 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
1667 if(!plr
|| plr
== killer
)
1670 if( plr
->GetTeam() == killer
->GetTeam() && plr
->IsAtGroupRewardDistance(player
) )
1671 UpdatePlayerScore(plr
, SCORE_HONORABLE_KILLS
, 1);
1675 // to be able to remove insignia -- ONLY IN BattleGrounds
1677 player
->SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
);
1680 // return the player's team based on battlegroundplayer info
1681 // used in same faction arena matches mainly
1682 uint32
BattleGround::GetPlayerTeam(uint64 guid
)
1684 BattleGroundPlayerMap::const_iterator itr
= m_Players
.find(guid
);
1685 if(itr
!=m_Players
.end())
1686 return itr
->second
.Team
;
1690 uint32
BattleGround::GetOtherTeam(uint32 teamId
)
1692 return (teamId
) ? ((teamId
== ALLIANCE
) ? HORDE
: ALLIANCE
) : 0;
1695 bool BattleGround::IsPlayerInBattleGround(uint64 guid
)
1697 BattleGroundPlayerMap::const_iterator itr
= m_Players
.find(guid
);
1698 if(itr
!= m_Players
.end())
1703 void BattleGround::PlayerAddedToBGCheckIfBGIsRunning(Player
* plr
)
1705 if(GetStatus() != STATUS_WAIT_LEAVE
)
1709 BattleGroundQueueTypeId bgQueueTypeId
= BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
1713 sBattleGroundMgr
.BuildPvpLogDataPacket(&data
, this);
1714 plr
->GetSession()->SendPacket(&data
);
1716 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, this, plr
->GetBattleGroundQueueIndex(bgQueueTypeId
), STATUS_IN_PROGRESS
, GetEndTime(), GetStartTime(), GetArenaType());
1717 plr
->GetSession()->SendPacket(&data
);
1720 uint32
BattleGround::GetAlivePlayersCountByTeam(uint32 Team
) const
1723 for(BattleGroundPlayerMap::const_iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
1725 if(itr
->second
.Team
== Team
)
1727 Player
* pl
= objmgr
.GetPlayer(itr
->first
);
1728 if(pl
&& pl
->isAlive())
1735 void BattleGround::CheckArenaWinConditions()
1737 if( !GetAlivePlayersCountByTeam(ALLIANCE
) && GetPlayersCountByTeam(HORDE
) )
1738 EndBattleGround(HORDE
);
1739 else if( GetPlayersCountByTeam(ALLIANCE
) && !GetAlivePlayersCountByTeam(HORDE
) )
1740 EndBattleGround(ALLIANCE
);
1743 void BattleGround::SetBgRaid( uint32 TeamID
, Group
*bg_raid
)
1745 Group
* &old_raid
= TeamID
== ALLIANCE
? m_BgRaids
[BG_TEAM_ALLIANCE
] : m_BgRaids
[BG_TEAM_HORDE
];
1746 if(old_raid
) old_raid
->SetBattlegroundGroup(NULL
);
1747 if(bg_raid
) bg_raid
->SetBattlegroundGroup(this);
1751 WorldSafeLocsEntry
const* BattleGround::GetClosestGraveYard( Player
* player
)
1753 return objmgr
.GetClosestGraveYard( player
->GetPositionX(), player
->GetPositionY(), player
->GetPositionZ(), player
->GetMapId(), player
->GetTeam() );