2 * Copyright (C) 2005-2008 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"
23 #include "MapManager.h"
26 #include "SpellAuras.h"
30 BattleGround::BattleGround()
36 m_LastResurrectTime
= 0;
37 m_Queue_type
= MAX_BATTLEGROUND_QUEUES
;
38 m_InvitedAlliance
= 0;
51 m_MaxPlayersPerTeam
= 0;
53 m_MinPlayersPerTeam
= 0;
58 m_TeamStartLocX
[BG_TEAM_ALLIANCE
] = 0;
59 m_TeamStartLocX
[BG_TEAM_HORDE
] = 0;
61 m_TeamStartLocY
[BG_TEAM_ALLIANCE
] = 0;
62 m_TeamStartLocY
[BG_TEAM_HORDE
] = 0;
64 m_TeamStartLocZ
[BG_TEAM_ALLIANCE
] = 0;
65 m_TeamStartLocZ
[BG_TEAM_HORDE
] = 0;
67 m_TeamStartLocO
[BG_TEAM_ALLIANCE
] = 0;
68 m_TeamStartLocO
[BG_TEAM_HORDE
] = 0;
70 m_BgRaids
[BG_TEAM_ALLIANCE
] = NULL
;
71 m_BgRaids
[BG_TEAM_HORDE
] = NULL
;
73 m_PlayersCount
[BG_TEAM_ALLIANCE
] = 0;
74 m_PlayersCount
[BG_TEAM_HORDE
] = 0;
77 BattleGround::~BattleGround()
82 void BattleGround::Update(time_t diff
)
85 if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize())
91 if(GetRemovedPlayersSize())
93 for(std::map
<uint64
, uint8
>::iterator itr
= m_RemovedPlayers
.begin(); itr
!= m_RemovedPlayers
.end(); ++itr
)
95 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
98 //following code is handled by event:
100 sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].RemovePlayer(itr->first);
101 //RemovePlayerFromQueue(itr->first);
104 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0);
105 plr->GetSession()->SendPacket(&data);
108 case 1: // currently in bg and was removed from bg
110 RemovePlayerAtLeave(itr
->first
, true, true);
112 RemovePlayerAtLeave(itr
->first
, false, false);
114 case 2: // revive queue
115 RemovePlayerFromResurrectQueue(itr
->first
);
118 sLog
.outError("BattleGround: Unknown remove player case!");
121 m_RemovedPlayers
.clear();
124 // this code isn't efficient and its idea isn't implemented yet
125 /* offline players are removed from battleground in worldsession::LogoutPlayer()
126 // remove offline players from bg after ~5 minutes
129 for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
131 Player *plr = objmgr.GetPlayer(itr->first);
132 itr->second.LastOnlineTime += diff;
135 itr->second.LastOnlineTime = 0; // update last online time
137 if(itr->second.LastOnlineTime >= MAX_OFFLINE_TIME) // 5 minutes
138 m_RemovedPlayers[itr->first] = 1; // add to remove list (BG)
142 m_LastResurrectTime
+= diff
;
143 if (m_LastResurrectTime
>= RESURRECTION_INTERVAL
)
145 if(GetReviveQueueSize())
147 for(std::map
<uint64
, std::vector
<uint64
> >::iterator itr
= m_ReviveQueue
.begin(); itr
!= m_ReviveQueue
.end(); ++itr
)
150 for(std::vector
<uint64
>::iterator itr2
= (itr
->second
).begin(); itr2
!= (itr
->second
).end(); ++itr2
)
152 Player
*plr
= objmgr
.GetPlayer(*itr2
);
158 sh
= ObjectAccessor::GetCreature(*plr
, itr
->first
);
159 // only for visual effect
161 sh
->CastSpell(sh
, SPELL_SPIRIT_HEAL
, true); // Spirit Heal, effect 117
164 plr
->CastSpell(plr
, SPELL_RESURRECTION_VISUAL
, true); // Resurrection visual
165 m_ResurrectQueue
.push_back(*itr2
);
167 (itr
->second
).clear();
170 m_ReviveQueue
.clear();
171 m_LastResurrectTime
= 0;
174 // queue is clear and time passed, just update last resurrection time
175 m_LastResurrectTime
= 0;
177 else if (m_LastResurrectTime
> 500) // Resurrect players only half a second later, to see spirit heal effect on NPC
179 for(std::vector
<uint64
>::iterator itr
= m_ResurrectQueue
.begin(); itr
!= m_ResurrectQueue
.end(); ++itr
)
181 Player
*plr
= objmgr
.GetPlayer(*itr
);
184 plr
->ResurrectPlayer(1.0f
);
185 plr
->CastSpell(plr
, SPELL_SPIRIT_HEAL_MANA
, true);
186 ObjectAccessor::Instance().ConvertCorpseForPlayer(*itr
);
188 m_ResurrectQueue
.clear();
191 if(GetStatus() == STATUS_WAIT_LEAVE
)
193 // remove all players from battleground after 2 minutes
195 if(m_EndTime
>= TIME_TO_AUTOREMOVE
) // 2 minutes
197 for(std::map
<uint64
, BattleGroundPlayer
>::iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
199 m_RemovedPlayers
[itr
->first
] = 1; // add to remove list (BG)
201 // do not change any battleground's private variables
206 void BattleGround::SetTeamStartLoc(uint32 TeamID
, float X
, float Y
, float Z
, float O
)
208 uint8 idx
= GetTeamIndexByTeamId(TeamID
);
209 m_TeamStartLocX
[idx
] = X
;
210 m_TeamStartLocY
[idx
] = Y
;
211 m_TeamStartLocZ
[idx
] = Z
;
212 m_TeamStartLocO
[idx
] = O
;
215 void BattleGround::SendPacketToAll(WorldPacket
*packet
)
217 for(std::map
<uint64
, BattleGroundPlayer
>::iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
219 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
221 plr
->GetSession()->SendPacket(packet
);
223 sLog
.outError("BattleGround: Player " I64FMTD
" not found!", itr
->first
);
227 void BattleGround::SendPacketToTeam(uint32 TeamID
, WorldPacket
*packet
, Player
*sender
, bool self
)
229 for(std::map
<uint64
, BattleGroundPlayer
>::iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
231 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
235 sLog
.outError("BattleGround: Player " I64FMTD
" not found!", itr
->first
);
239 if(!self
&& sender
== plr
)
242 if(plr
->GetTeam() == TeamID
)
243 plr
->GetSession()->SendPacket(packet
);
247 void BattleGround::PlaySoundToAll(uint32 SoundID
)
250 sBattleGroundMgr
.BuildPlaySoundPacket(&data
, SoundID
);
251 SendPacketToAll(&data
);
254 void BattleGround::PlaySoundToTeam(uint32 SoundID
, uint32 TeamID
)
258 for(std::map
<uint64
, BattleGroundPlayer
>::iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
260 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
264 sLog
.outError("BattleGround: Player " I64FMTD
" not found!", itr
->first
);
268 if(plr
->GetTeam() == TeamID
)
270 sBattleGroundMgr
.BuildPlaySoundPacket(&data
, SoundID
);
271 plr
->GetSession()->SendPacket(&data
);
276 void BattleGround::CastSpellOnTeam(uint32 SpellID
, uint32 TeamID
)
278 for(std::map
<uint64
, BattleGroundPlayer
>::iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
280 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
284 sLog
.outError("BattleGround: Player " I64FMTD
" not found!", itr
->first
);
288 if(plr
->GetTeam() == TeamID
)
289 plr
->CastSpell(plr
, SpellID
, true);
293 void BattleGround::RewardHonorToTeam(uint32 Honor
, uint32 TeamID
)
295 for(std::map
<uint64
, BattleGroundPlayer
>::iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
297 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
301 sLog
.outError("BattleGround: Player " I64FMTD
" not found!", itr
->first
);
305 if(plr
->GetTeam() == TeamID
)
306 UpdatePlayerScore(plr
, SCORE_BONUS_HONOR
, Honor
);
310 void BattleGround::RewardReputationToTeam(uint32 faction_id
, uint32 Reputation
, uint32 TeamID
)
312 FactionEntry
const* factionEntry
= sFactionStore
.LookupEntry(faction_id
);
317 for(std::map
<uint64
, BattleGroundPlayer
>::iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
319 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
323 sLog
.outError("BattleGround: Player " I64FMTD
" not found!", itr
->first
);
327 if(plr
->GetTeam() == TeamID
)
328 plr
->ModifyFactionReputation(factionEntry
, Reputation
);
332 void BattleGround::UpdateWorldState(uint32 Field
, uint32 Value
)
335 sBattleGroundMgr
.BuildUpdateWorldStatePacket(&data
, Field
, Value
);
336 SendPacketToAll(&data
);
339 void BattleGround::UpdateWorldStateForPlayer(uint32 Field
, uint32 Value
, Player
*Source
)
342 sBattleGroundMgr
.BuildUpdateWorldStatePacket(&data
, Field
, Value
);
343 Source
->GetSession()->SendPacket(&data
);
346 void BattleGround::EndBattleGround(uint32 winner
)
349 Player
*Source
= NULL
;
350 const char *winmsg
= "";
352 if(winner
== ALLIANCE
)
354 winmsg
= GetMangosString(LANG_BG_A_WINS
);
356 PlaySoundToAll(SOUND_ALLIANCE_WINS
); // alliance wins sound
358 SetWinner(WINNER_ALLIANCE
);
362 winmsg
= GetMangosString(LANG_BG_H_WINS
);
364 PlaySoundToAll(SOUND_HORDE_WINS
); // horde wins sound
366 SetWinner(WINNER_HORDE
);
369 SetStatus(STATUS_WAIT_LEAVE
);
372 for(std::map
<uint64
, BattleGroundPlayer
>::iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
374 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
377 sLog
.outError("BattleGround: Player " I64FMTD
" not found!", itr
->first
);
383 plr
->ResurrectPlayer(1.0f
);
384 plr
->SpawnCorpseBones();
387 if(plr
->GetTeam() == winner
)
391 RewardMark(plr
,ITEM_WINNER_COUNT
);
392 UpdatePlayerScore(plr
, SCORE_BONUS_HONOR
, 20);
397 RewardMark(plr
,ITEM_LOSER_COUNT
);
400 plr
->CombatStopWithPets(true);
404 sBattleGroundMgr
.BuildPvpLogDataPacket(&data
, this);
405 plr
->GetSession()->SendPacket(&data
);
407 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, this, plr
->GetTeam(), plr
->GetBattleGroundQueueIndex(m_TypeID
), STATUS_IN_PROGRESS
, TIME_TO_AUTOREMOVE
, GetStartTime());
408 plr
->GetSession()->SendPacket(&data
);
409 plr
->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND
, 1);
414 ChatHandler(Source
).FillMessageData(&data
, CHAT_MSG_BG_SYSTEM_NEUTRAL
, LANG_UNIVERSAL
, Source
->GetGUID(), winmsg
);
415 SendPacketToAll(&data
);
419 uint32
BattleGround::GetBattlemasterEntry() const
423 case BATTLEGROUND_AV
: return 15972;
424 case BATTLEGROUND_WS
: return 14623;
425 case BATTLEGROUND_AB
: return 14879;
426 case BATTLEGROUND_EY
: return 22516;
427 case BATTLEGROUND_NA
: return 20200;
432 void BattleGround::RewardMark(Player
*plr
,uint32 count
)
434 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
435 if(plr
->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE
))
438 BattleGroundMarks mark
;
442 case BATTLEGROUND_AV
:
444 if(count
== ITEM_WINNER_COUNT
)
445 mark
= SPELL_AV_MARK_WINNER
;
447 mark
= SPELL_AV_MARK_LOSER
;
449 case BATTLEGROUND_WS
:
451 if(count
== ITEM_WINNER_COUNT
)
452 mark
= SPELL_WS_MARK_WINNER
;
454 mark
= SPELL_WS_MARK_LOSER
;
456 case BATTLEGROUND_AB
:
458 if(count
== ITEM_WINNER_COUNT
)
459 mark
= SPELL_AB_MARK_WINNER
;
461 mark
= SPELL_AB_MARK_LOSER
;
463 case BATTLEGROUND_EY
:
465 mark
= ITEM_EY_MARK_OF_HONOR
;
472 plr
->CastSpell(plr
, mark
, true);
473 else if ( objmgr
.GetItemPrototype( mark
) )
475 ItemPosCountVec dest
;
476 uint32 no_space_count
= 0;
477 uint8 msg
= plr
->CanStoreNewItem( NULL_BAG
, NULL_SLOT
, dest
, mark
, count
, &no_space_count
);
478 if( msg
!= EQUIP_ERR_OK
) // convert to possible store amount
479 count
-= no_space_count
;
481 if( count
!= 0 && !dest
.empty()) // can add some
482 if(Item
* item
= plr
->StoreNewItem( dest
, mark
, true, 0))
483 plr
->SendNewItem(item
,count
,false,true);
485 if(no_space_count
> 0)
486 SendRewardMarkByMail(plr
,mark
,no_space_count
);
490 void BattleGround::SendRewardMarkByMail(Player
*plr
,uint32 mark
, uint32 count
)
492 uint32 bmEntry
= GetBattlemasterEntry();
496 ItemPrototype
const* markProto
= objmgr
.GetItemPrototype(mark
);
500 if(Item
* markItem
= Item::CreateItem(mark
,count
,plr
))
502 // save new item before send
503 markItem
->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
507 mi
.AddItem(markItem
->GetGUIDLow(), markItem
->GetEntry(), markItem
);
509 // subject: item name
510 std::string subject
= markProto
->Name1
;
511 int loc_idx
= plr
->GetSession()->GetSessionDbLocaleIndex();
513 if(ItemLocale
const *il
= objmgr
.GetItemLocale(markProto
->ItemId
))
514 if (il
->Name
.size() > loc_idx
&& !il
->Name
[loc_idx
].empty())
515 subject
= il
->Name
[loc_idx
];
518 std::string textFormat
= plr
->GetSession()->GetMangosString(LANG_BG_MARK_BY_MAIL
);
520 snprintf(textBuf
,300,textFormat
.c_str(),GetName(),GetName());
521 uint32 itemTextId
= objmgr
.CreateItemText( textBuf
);
523 WorldSession::SendMailTo(plr
, MAIL_CREATURE
, MAIL_STATIONERY_NORMAL
, bmEntry
, plr
->GetGUIDLow(), subject
, itemTextId
, &mi
, 0, 0, MAIL_CHECK_MASK_NONE
);
527 void BattleGround::RewardQuest(Player
*plr
)
529 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
530 if(plr
->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE
))
536 case BATTLEGROUND_AV
:
537 quest
= SPELL_AV_QUEST_REWARD
;
539 case BATTLEGROUND_WS
:
540 quest
= SPELL_WS_QUEST_REWARD
;
542 case BATTLEGROUND_AB
:
543 quest
= SPELL_AB_QUEST_REWARD
;
545 case BATTLEGROUND_EY
:
546 quest
= SPELL_EY_QUEST_REWARD
;
552 plr
->CastSpell(plr
, quest
, true);
555 void BattleGround::BlockMovement(Player
*plr
)
557 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()
560 void BattleGround::RemovePlayerAtLeave(uint64 guid
, bool Transport
, bool SendPacket
)
562 // Remove from lists/maps
563 std::map
<uint64
, BattleGroundPlayer
>::iterator itr
= m_Players
.find(guid
);
564 if(itr
!= m_Players
.end())
566 UpdatePlayersCountByTeam(itr
->second
.Team
, true); // -1 player
567 m_Players
.erase(itr
);
570 std::map
<uint64
, BattleGroundScore
*>::iterator itr2
= m_PlayerScores
.find(guid
);
571 if(itr2
!= m_PlayerScores
.end())
573 delete itr2
->second
; // delete player's score
574 m_PlayerScores
.erase(itr2
);
577 RemovePlayerFromResurrectQueue(guid
);
579 Player
*plr
= objmgr
.GetPlayer(guid
);
581 if(plr
&& !plr
->isAlive()) // resurrect on exit
583 plr
->ResurrectPlayer(1.0f
);
584 plr
->SpawnCorpseBones();
587 RemovePlayer(plr
, guid
); // BG subclass specific code
591 plr
->ClearAfkReports();
595 if(!sWorld
.IsFFAPvPRealm())
596 plr
->RemoveFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
);
602 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, this, plr
->GetTeam(), plr
->GetBattleGroundQueueIndex(m_TypeID
), STATUS_NONE
, 0, 0);
603 plr
->GetSession()->SendPacket(&data
);
606 // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
607 plr
->RemoveBattleGroundQueueId(m_TypeID
);
609 DecreaseInvitedCount(plr
->GetTeam());
610 //we should update battleground queue, but only if bg isn't ending
611 if (GetQueueType() < MAX_BATTLEGROUND_QUEUES
)
612 sBattleGroundMgr
.m_BattleGroundQueues
[GetTypeID()].Update(GetTypeID(), GetQueueType());
614 if(!plr
->GetBattleGroundId())
617 Group
* group
= plr
->GetGroup();
619 // remove from raid group if exist
620 if(group
&& group
== GetBgRaid(plr
->GetTeam()))
622 if(!group
->RemoveMember(guid
, 0)) // group was disbanded
624 SetBgRaid(plr
->GetTeam(), NULL
);
629 // Do next only if found in battleground
630 plr
->SetBattleGroundId(0); // We're not in BG.
633 sBattleGroundMgr
.BuildPlayerLeftBattleGroundPacket(&data
, plr
);
634 SendPacketToTeam(plr
->GetTeam(), &data
, plr
, false);
638 plr
->TeleportTo(plr
->GetBattleGroundEntryPointMap(), plr
->GetBattleGroundEntryPointX(), plr
->GetBattleGroundEntryPointY(), plr
->GetBattleGroundEntryPointZ(), plr
->GetBattleGroundEntryPointO());
639 //sLog.outDetail("BATTLEGROUND: Sending %s to %f,%f,%f,%f", pl->GetName(), x,y,z,O);
643 sLog
.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr
->GetName());
646 /// there will be code which will add battleground to BGFreeSlotQueue , when battleground instance will exist
647 // we always should check if BG is in that queue before adding..
649 if(!GetPlayersSize())
655 // this method is called when no players remains in battleground
656 void BattleGround::Reset()
658 SetQueueType(MAX_BATTLEGROUND_QUEUES
);
659 SetWinner(WINNER_NONE
);
660 SetStatus(STATUS_WAIT_QUEUE
);
663 SetLastResurrectTime(0);
667 if (m_InvitedAlliance
> 0 || m_InvitedHorde
> 0)
668 sLog
.outError("BattleGround system ERROR: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance
, m_InvitedHorde
);
670 m_InvitedAlliance
= 0;
674 m_PlayerScores
.clear();
677 this->ResetBGSubclass();
680 void BattleGround::StartBattleGround()
682 ///this method should spawn spirit guides and so on
685 SetLastResurrectTime(0);
688 void BattleGround::AddPlayer(Player
*plr
)
690 // score struct must be created in inherited class
692 uint64 guid
= plr
->GetGUID();
693 uint32 team
= plr
->GetBGTeam();
695 BattleGroundPlayer bp
;
696 bp
.LastOnlineTime
= 0;
700 m_Players
[guid
] = bp
;
702 UpdatePlayersCountByTeam(team
, false); // +1 player
705 sBattleGroundMgr
.BuildPlayerJoinedBattleGroundPacket(&data
, plr
);
706 SendPacketToTeam(team
, &data
, plr
, false);
710 plr
->RemoveArenaSpellCooldowns();
711 //plr->RemoveArenaAuras();
712 plr
->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT
);
713 if(team
== ALLIANCE
&& plr
->GetTeam() == ALLIANCE
)
714 plr
->CastSpell(plr
,SPELL_ALLIANCE_GOLD_FLAG
,true);
715 else if(team
== HORDE
&& plr
->GetTeam() == ALLIANCE
)
716 plr
->CastSpell(plr
,SPELL_ALLIANCE_GREEN_FLAG
,true);
717 else if(team
== ALLIANCE
&& plr
->GetTeam() == HORDE
)
718 plr
->CastSpell(plr
,SPELL_HORDE_GOLD_FLAG
,true);
720 plr
->CastSpell(plr
,SPELL_HORDE_GREEN_FLAG
,true);
721 plr
->DestroyConjuredItems(true);
723 if(GetStatus() == STATUS_WAIT_JOIN
) // not started yet
725 plr
->CastSpell(plr
, SPELL_ARENA_PREPARATION
, true);
727 plr
->SetHealth(plr
->GetMaxHealth());
728 plr
->SetPower(POWER_MANA
, plr
->GetMaxPower(POWER_MANA
));
733 if(GetStatus() == STATUS_WAIT_JOIN
) // not started yet
734 plr
->CastSpell(plr
, SPELL_PREPARATION
, true); // reduces all mana cost of spells.
738 plr
->SetFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
);
741 sLog
.outDetail("BATTLEGROUND: Player %s joined the battle.", plr
->GetName());
744 /* This method should be called only once ... it adds pointer to queue */
745 void BattleGround::AddToBGFreeSlotQueue()
747 sBattleGroundMgr
.BGFreeSlotQueue
[m_TypeID
].push_front(this);
750 /* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
751 void BattleGround::RemoveFromBGFreeSlotQueue()
753 /* uncomment this code when battlegrounds will work like instances
754 for (std::deque<BattleGround*>::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)
756 if ((*itr)->GetInstanceID() == m_InstanceID)
758 sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr);
765 this method should decide, if we can invite new player of certain team to BG, it is based on BATTLEGROUND_STATUS
767 bool BattleGround::HasFreeSlotsForTeam(uint32 Team
) const
769 //if BG is starting ... invite anyone:
770 if (GetStatus() == STATUS_WAIT_JOIN
)
771 return GetInvitedCount(Team
) < GetMaxPlayersPerTeam();
772 //if BG is already started .. do not allow to join too much players of one faction
774 if (Team
== ALLIANCE
)
775 otherTeam
= GetInvitedCount(HORDE
);
777 otherTeam
= GetInvitedCount(ALLIANCE
);
778 if (GetStatus() == STATUS_IN_PROGRESS
)
779 return (GetInvitedCount(Team
) <= otherTeam
&& GetInvitedCount(Team
) < GetMaxPlayersPerTeam());
784 /* this method isn't called already, it will be useful when more battlegrounds of one type will be available */
785 bool BattleGround::HasFreeSlots() const
787 return GetPlayersSize() < GetMaxPlayers();
790 void BattleGround::UpdatePlayerScore(Player
*Source
, uint32 type
, uint32 value
)
792 //this procedure is called from virtual function implemented in bg subclass
793 std::map
<uint64
, BattleGroundScore
*>::iterator itr
= m_PlayerScores
.find(Source
->GetGUID());
795 if(itr
== m_PlayerScores
.end()) // player not found...
800 case SCORE_KILLING_BLOWS
: // Killing blows
801 itr
->second
->KillingBlows
+= value
;
803 case SCORE_DEATHS
: // Deaths
804 itr
->second
->Deaths
+= value
;
806 case SCORE_HONORABLE_KILLS
: // Honorable kills
807 itr
->second
->HonorableKills
+= value
;
809 case SCORE_BONUS_HONOR
: // Honor bonus
810 // reward honor instantly
811 if(Source
->RewardHonor(NULL
, 1, value
))
812 itr
->second
->BonusHonor
+= value
;
814 //used only in EY, but in MSG_PVP_LOG_DATA opcode
815 case SCORE_DAMAGE_DONE
: // Damage Done
816 itr
->second
->DamageDone
+= value
;
818 case SCORE_HEALING_DONE
: // Healing Done
819 itr
->second
->HealingDone
+= value
;
822 sLog
.outError("BattleGround: Unknown player score type %u", type
);
827 void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid
, uint64 player_guid
)
829 m_ReviveQueue
[npc_guid
].push_back(player_guid
);
831 Player
*plr
= objmgr
.GetPlayer(player_guid
);
835 plr
->CastSpell(plr
, SPELL_WAITING_FOR_RESURRECT
, true);
836 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( SPELL_WAITING_FOR_RESURRECT
);
839 Aura
*Aur
= CreateAura(spellInfo
, 0, NULL
, plr
);
844 void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid
)
846 for(std::map
<uint64
, std::vector
<uint64
> >::iterator itr
= m_ReviveQueue
.begin(); itr
!= m_ReviveQueue
.end(); ++itr
)
848 for(std::vector
<uint64
>::iterator itr2
=(itr
->second
).begin(); itr2
!= (itr
->second
).end(); ++itr2
)
850 if(*itr2
== player_guid
)
852 (itr
->second
).erase(itr2
);
854 Player
*plr
= objmgr
.GetPlayer(player_guid
);
858 plr
->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT
);
866 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
)
868 GameObjectInfo
const* goinfo
= objmgr
.GetGameObjectInfo(entry
);
871 sLog
.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry
);
875 uint32 guid
= objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
);
877 GameObjectData
& data
= objmgr
.NewGOData(guid
);
880 data
.mapid
= GetMapId();
884 data
.orientation
= o
;
885 data
.rotation0
= rotation0
;
886 data
.rotation1
= rotation1
;
887 data
.rotation2
= rotation2
;
888 data
.rotation3
= rotation3
;
889 data
.spawntimesecs
= respawnTime
;
890 data
.animprogress
= 100;
893 objmgr
.AddGameobjectToGrid(guid
, &data
);
895 m_BgObjects
[type
] = MAKE_NEW_GUID(guid
, entry
, HIGHGUID_GAMEOBJECT
);
900 //some doors aren't despawned so we cannot handle their closing in gameobject::update()
901 //it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
902 void BattleGround::DoorClose(uint32 type
)
904 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
907 //if doors are open, close it
908 if( obj
->getLootState() == GO_ACTIVATED
&& !obj
->GetGoState() )
910 //change state to allow door to be closed
911 obj
->SetLootState(GO_READY
);
912 obj
->UseDoorOrButton(RESPAWN_ONE_DAY
);
917 sLog
.outError("BattleGround: Door object not found (cannot close doors)");
921 void BattleGround::DoorOpen(uint32 type
)
923 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
926 //change state to be sure they will be opened
927 obj
->SetLootState(GO_READY
);
928 obj
->UseDoorOrButton(RESPAWN_ONE_DAY
);
932 sLog
.outError("BattleGround: Door object not found! - doors will be closed.");
936 void BattleGround::SpawnBGObject(uint32 type
, uint32 respawntime
)
938 if( respawntime
== 0 )
940 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
943 //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
944 if( obj
->getLootState() == GO_JUST_DEACTIVATED
)
945 obj
->SetLootState(GO_READY
);
949 objmgr
.SaveGORespawnTime(GUID_LOPART(m_BgObjects
[type
]), 0, 0);
953 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
956 obj
->SetRespawnTime(respawntime
);
957 obj
->SetLootState(GO_JUST_DEACTIVATED
);
960 objmgr
.SaveGORespawnTime(GUID_LOPART(m_BgObjects
[type
]), 0, time(NULL
) + respawntime
);
964 Creature
* BattleGround::AddCreature(uint32 entry
, uint32 type
, uint32 teamval
, float x
, float y
, float z
, float o
)
966 // note: this should normally be FindMap
967 // but it's a hack to allow the battlegrounds to initialize at server startup
968 Map
* map
= MapManager::Instance().GetMap(GetMapId(), 0);
969 if(!map
) return NULL
;
971 Creature
* pCreature
= new Creature
;
972 if (!pCreature
->Create(objmgr
.GenerateLowGuid(HIGHGUID_UNIT
), map
, entry
, teamval
))
974 sLog
.outError("Can't create creature entry: %u",entry
);
979 pCreature
->Relocate(x
, y
, z
, o
);
981 if(!pCreature
->IsPositionValid())
983 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());
987 pCreature
->AIM_Initialize();
989 //pCreature->SetDungeonDifficulty(0);
992 m_BgCreatures
[type
] = pCreature
->GetGUID();
996 bool BattleGround::DelCreature(uint32 type
)
998 Creature
*cr
= HashMapHolder
<Creature
>::Find(m_BgCreatures
[type
]);
1001 sLog
.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures
[type
]));
1004 cr
->CleanupsBeforeDelete();
1005 cr
->AddObjectToRemoveList();
1006 m_BgCreatures
[type
] = 0;
1010 bool BattleGround::DelObject(uint32 type
)
1012 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1015 sLog
.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects
[type
]));
1018 obj
->SetRespawnTime(0); // not save respawn time
1020 m_BgObjects
[type
] = 0;
1024 bool BattleGround::AddSpiritGuide(uint32 type
, float x
, float y
, float z
, float o
, uint32 team
)
1028 if(team
== ALLIANCE
)
1033 Creature
* pCreature
= AddCreature(entry
,type
,team
,x
,y
,z
,o
);
1036 sLog
.outError("Can't create Spirit guide. BattleGround not created!");
1041 pCreature
->setDeathState(DEAD
);
1043 pCreature
->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT
, pCreature
->GetGUID());
1045 pCreature
->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL
);
1046 //pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
1047 //pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
1048 //pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
1049 // casting visual effect
1050 pCreature
->SetUInt32Value(UNIT_CHANNEL_SPELL
, SPELL_SPIRIT_HEAL_CHANNEL
);
1051 // correct cast speed
1052 pCreature
->SetFloatValue(UNIT_MOD_CAST_SPEED
, 1.0f
);
1054 //pCreature->CastSpell(pCreature, SPELL_SPIRIT_HEAL_CHANNEL, true);
1059 void BattleGround::SendMessageToAll(char const* text
)
1062 ChatHandler::FillMessageData(&data
, NULL
, CHAT_MSG_BG_SYSTEM_NEUTRAL
, LANG_UNIVERSAL
, NULL
, 0, text
, NULL
);
1063 SendPacketToAll(&data
);
1066 void BattleGround::SendMessageToAll(int32 entry
)
1068 char const* text
= GetMangosString(entry
);
1070 ChatHandler::FillMessageData(&data
, NULL
, CHAT_MSG_BG_SYSTEM_NEUTRAL
, LANG_UNIVERSAL
, NULL
, 0, text
, NULL
);
1071 SendPacketToAll(&data
);
1074 void BattleGround::EndNow()
1076 SetStatus(STATUS_WAIT_LEAVE
);
1077 SetEndTime(TIME_TO_AUTOREMOVE
);
1080 // Battleground messages are localized using the dbc lang, they are not client language dependent
1081 const char *BattleGround::GetMangosString(int32 entry
)
1083 // FIXME: now we have different DBC locales and need localized message for each target client
1084 return objmgr
.GetMangosStringForDBCLocale(entry
);
1089 buffs aren't spawned/despawned when players captures anything
1090 buffs are in their positions when battleground starts
1092 void BattleGround::HandleTriggerBuff(uint64
const& go_guid
)
1094 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(go_guid
);
1095 if(!obj
|| obj
->GetGoType() != GAMEOBJECT_TYPE_TRAP
|| !obj
->isSpawned())
1098 //change buff type, when buff is used:
1099 int32 index
= m_BgObjects
.size() - 1;
1100 while (index
>= 0 && m_BgObjects
[index
] != go_guid
)
1104 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());
1108 //randomly select new buff
1109 uint8 buff
= urand(0, 2);
1110 uint32 entry
= obj
->GetEntry();
1111 if( m_BuffChange
&& entry
!= Buff_Entries
[buff
] )
1113 //despawn current buff
1114 SpawnBGObject(index
, RESPAWN_ONE_DAY
);
1115 //set index for new one
1116 for (uint8 currBuffTypeIndex
= 0; currBuffTypeIndex
< 3; ++currBuffTypeIndex
)
1117 if( entry
== Buff_Entries
[currBuffTypeIndex
] )
1119 index
-= currBuffTypeIndex
;
1124 SpawnBGObject(index
, BUFF_RESPAWN_TIME
);
1127 void BattleGround::HandleKillPlayer( Player
*player
, Player
*killer
)
1129 //keep in mind that for arena this will have to be changed a bit
1132 UpdatePlayerScore(player
, SCORE_DEATHS
, 1);
1134 // add +1 kills to group and +1 killing_blows to killer
1137 UpdatePlayerScore(killer
, SCORE_HONORABLE_KILLS
, 1);
1138 UpdatePlayerScore(killer
, SCORE_KILLING_BLOWS
, 1);
1140 for(std::map
<uint64
, BattleGroundPlayer
>::iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
1142 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
1144 if(!plr
|| plr
== killer
)
1147 if( plr
->GetTeam() == killer
->GetTeam() && plr
->IsAtGroupRewardDistance(player
) )
1148 UpdatePlayerScore(plr
, SCORE_HONORABLE_KILLS
, 1);
1152 // to be able to remove insignia
1153 player
->SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
);