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