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
);
413 ChatHandler(Source
).FillMessageData(&data
, CHAT_MSG_BG_SYSTEM_NEUTRAL
, LANG_UNIVERSAL
, Source
->GetGUID(), winmsg
);
414 SendPacketToAll(&data
);
418 uint32
BattleGround::GetBattlemasterEntry() const
422 case BATTLEGROUND_AV
: return 15972;
423 case BATTLEGROUND_WS
: return 14623;
424 case BATTLEGROUND_AB
: return 14879;
425 case BATTLEGROUND_EY
: return 22516;
426 case BATTLEGROUND_NA
: return 20200;
431 void BattleGround::RewardMark(Player
*plr
,uint32 count
)
433 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
434 if(plr
->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE
))
437 BattleGroundMarks mark
;
441 case BATTLEGROUND_AV
:
443 if(count
== ITEM_WINNER_COUNT
)
444 mark
= SPELL_AV_MARK_WINNER
;
446 mark
= SPELL_AV_MARK_LOSER
;
448 case BATTLEGROUND_WS
:
450 if(count
== ITEM_WINNER_COUNT
)
451 mark
= SPELL_WS_MARK_WINNER
;
453 mark
= SPELL_WS_MARK_LOSER
;
455 case BATTLEGROUND_AB
:
457 if(count
== ITEM_WINNER_COUNT
)
458 mark
= SPELL_AB_MARK_WINNER
;
460 mark
= SPELL_AB_MARK_LOSER
;
462 case BATTLEGROUND_EY
:
464 mark
= ITEM_EY_MARK_OF_HONOR
;
471 plr
->CastSpell(plr
, mark
, true);
472 else if ( objmgr
.GetItemPrototype( mark
) )
474 ItemPosCountVec dest
;
475 uint32 no_space_count
= 0;
476 uint8 msg
= plr
->CanStoreNewItem( NULL_BAG
, NULL_SLOT
, dest
, mark
, count
, &no_space_count
);
477 if( msg
!= EQUIP_ERR_OK
) // convert to possible store amount
478 count
-= no_space_count
;
480 if( count
!= 0 && !dest
.empty()) // can add some
481 if(Item
* item
= plr
->StoreNewItem( dest
, mark
, true, 0))
482 plr
->SendNewItem(item
,count
,false,true);
484 if(no_space_count
> 0)
485 SendRewardMarkByMail(plr
,mark
,no_space_count
);
489 void BattleGround::SendRewardMarkByMail(Player
*plr
,uint32 mark
, uint32 count
)
491 uint32 bmEntry
= GetBattlemasterEntry();
495 ItemPrototype
const* markProto
= objmgr
.GetItemPrototype(mark
);
499 if(Item
* markItem
= Item::CreateItem(mark
,count
,plr
))
501 // save new item before send
502 markItem
->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
506 mi
.AddItem(markItem
->GetGUIDLow(), markItem
->GetEntry(), markItem
);
508 // subject: item name
509 std::string subject
= markProto
->Name1
;
510 int loc_idx
= plr
->GetSession()->GetSessionDbLocaleIndex();
512 if(ItemLocale
const *il
= objmgr
.GetItemLocale(markProto
->ItemId
))
513 if (il
->Name
.size() > size_t(loc_idx
) && !il
->Name
[loc_idx
].empty())
514 subject
= il
->Name
[loc_idx
];
517 std::string textFormat
= plr
->GetSession()->GetMangosString(LANG_BG_MARK_BY_MAIL
);
519 snprintf(textBuf
,300,textFormat
.c_str(),GetName(),GetName());
520 uint32 itemTextId
= objmgr
.CreateItemText( textBuf
);
522 WorldSession::SendMailTo(plr
, MAIL_CREATURE
, MAIL_STATIONERY_NORMAL
, bmEntry
, plr
->GetGUIDLow(), subject
, itemTextId
, &mi
, 0, 0, MAIL_CHECK_MASK_NONE
);
526 void BattleGround::RewardQuest(Player
*plr
)
528 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
529 if(plr
->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE
))
535 case BATTLEGROUND_AV
:
536 quest
= SPELL_AV_QUEST_REWARD
;
538 case BATTLEGROUND_WS
:
539 quest
= SPELL_WS_QUEST_REWARD
;
541 case BATTLEGROUND_AB
:
542 quest
= SPELL_AB_QUEST_REWARD
;
544 case BATTLEGROUND_EY
:
545 quest
= SPELL_EY_QUEST_REWARD
;
551 plr
->CastSpell(plr
, quest
, true);
554 void BattleGround::BlockMovement(Player
*plr
)
556 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()
559 void BattleGround::RemovePlayerAtLeave(uint64 guid
, bool Transport
, bool SendPacket
)
561 // Remove from lists/maps
562 std::map
<uint64
, BattleGroundPlayer
>::iterator itr
= m_Players
.find(guid
);
563 if(itr
!= m_Players
.end())
565 UpdatePlayersCountByTeam(itr
->second
.Team
, true); // -1 player
566 m_Players
.erase(itr
);
569 std::map
<uint64
, BattleGroundScore
*>::iterator itr2
= m_PlayerScores
.find(guid
);
570 if(itr2
!= m_PlayerScores
.end())
572 delete itr2
->second
; // delete player's score
573 m_PlayerScores
.erase(itr2
);
576 RemovePlayerFromResurrectQueue(guid
);
578 Player
*plr
= objmgr
.GetPlayer(guid
);
580 if(plr
&& !plr
->isAlive()) // resurrect on exit
582 plr
->ResurrectPlayer(1.0f
);
583 plr
->SpawnCorpseBones();
586 RemovePlayer(plr
, guid
); // BG subclass specific code
590 plr
->ClearAfkReports();
594 if(!sWorld
.IsFFAPvPRealm())
595 plr
->RemoveFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
);
601 sBattleGroundMgr
.BuildBattleGroundStatusPacket(&data
, this, plr
->GetTeam(), plr
->GetBattleGroundQueueIndex(m_TypeID
), STATUS_NONE
, 0, 0);
602 plr
->GetSession()->SendPacket(&data
);
605 // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
606 plr
->RemoveBattleGroundQueueId(m_TypeID
);
608 DecreaseInvitedCount(plr
->GetTeam());
609 //we should update battleground queue, but only if bg isn't ending
610 if (GetQueueType() < MAX_BATTLEGROUND_QUEUES
)
611 sBattleGroundMgr
.m_BattleGroundQueues
[GetTypeID()].Update(GetTypeID(), GetQueueType());
613 if(!plr
->GetBattleGroundId())
616 Group
* group
= plr
->GetGroup();
618 // remove from raid group if exist
619 if(group
&& group
== GetBgRaid(plr
->GetTeam()))
621 if(!group
->RemoveMember(guid
, 0)) // group was disbanded
623 SetBgRaid(plr
->GetTeam(), NULL
);
628 // Do next only if found in battleground
629 plr
->SetBattleGroundId(0); // We're not in BG.
632 sBattleGroundMgr
.BuildPlayerLeftBattleGroundPacket(&data
, plr
);
633 SendPacketToTeam(plr
->GetTeam(), &data
, plr
, false);
637 plr
->TeleportTo(plr
->GetBattleGroundEntryPointMap(), plr
->GetBattleGroundEntryPointX(), plr
->GetBattleGroundEntryPointY(), plr
->GetBattleGroundEntryPointZ(), plr
->GetBattleGroundEntryPointO());
638 //sLog.outDetail("BATTLEGROUND: Sending %s to %f,%f,%f,%f", pl->GetName(), x,y,z,O);
642 sLog
.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr
->GetName());
645 /// there will be code which will add battleground to BGFreeSlotQueue , when battleground instance will exist
646 // we always should check if BG is in that queue before adding..
648 if(!GetPlayersSize())
654 // this method is called when no players remains in battleground
655 void BattleGround::Reset()
657 SetQueueType(MAX_BATTLEGROUND_QUEUES
);
658 SetWinner(WINNER_NONE
);
659 SetStatus(STATUS_WAIT_QUEUE
);
662 SetLastResurrectTime(0);
666 if (m_InvitedAlliance
> 0 || m_InvitedHorde
> 0)
667 sLog
.outError("BattleGround system ERROR: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance
, m_InvitedHorde
);
669 m_InvitedAlliance
= 0;
673 m_PlayerScores
.clear();
679 void BattleGround::StartBattleGround()
681 ///this method should spawn spirit guides and so on
684 SetLastResurrectTime(0);
687 void BattleGround::AddPlayer(Player
*plr
)
689 // score struct must be created in inherited class
691 uint64 guid
= plr
->GetGUID();
692 uint32 team
= plr
->GetBGTeam();
694 BattleGroundPlayer bp
;
695 bp
.LastOnlineTime
= 0;
699 m_Players
[guid
] = bp
;
701 UpdatePlayersCountByTeam(team
, false); // +1 player
704 sBattleGroundMgr
.BuildPlayerJoinedBattleGroundPacket(&data
, plr
);
705 SendPacketToTeam(team
, &data
, plr
, false);
709 plr
->RemoveArenaSpellCooldowns();
710 //plr->RemoveArenaAuras();
711 plr
->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT
);
712 if(team
== ALLIANCE
) // gold
714 if(plr
->GetTeam() == HORDE
)
715 plr
->CastSpell(plr
, SPELL_HORDE_GOLD_FLAG
,true);
717 plr
->CastSpell(plr
, SPELL_ALLIANCE_GOLD_FLAG
,true);
721 if(plr
->GetTeam() == HORDE
)
722 plr
->CastSpell(plr
, SPELL_HORDE_GREEN_FLAG
,true);
724 plr
->CastSpell(plr
, SPELL_ALLIANCE_GREEN_FLAG
,true);
727 plr
->DestroyConjuredItems(true);
729 if(GetStatus() == STATUS_WAIT_JOIN
) // not started yet
731 plr
->CastSpell(plr
, SPELL_ARENA_PREPARATION
, true);
733 plr
->SetHealth(plr
->GetMaxHealth());
734 plr
->SetPower(POWER_MANA
, plr
->GetMaxPower(POWER_MANA
));
739 if(GetStatus() == STATUS_WAIT_JOIN
) // not started yet
740 plr
->CastSpell(plr
, SPELL_PREPARATION
, true); // reduces all mana cost of spells.
744 plr
->SetFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
);
747 sLog
.outDetail("BATTLEGROUND: Player %s joined the battle.", plr
->GetName());
750 /* This method should be called only once ... it adds pointer to queue */
751 void BattleGround::AddToBGFreeSlotQueue()
753 sBattleGroundMgr
.BGFreeSlotQueue
[m_TypeID
].push_front(this);
756 /* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
757 void BattleGround::RemoveFromBGFreeSlotQueue()
759 /* uncomment this code when battlegrounds will work like instances
760 for (std::deque<BattleGround*>::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)
762 if ((*itr)->GetInstanceID() == m_InstanceID)
764 sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr);
771 this method should decide, if we can invite new player of certain team to BG, it is based on BATTLEGROUND_STATUS
773 bool BattleGround::HasFreeSlotsForTeam(uint32 Team
) const
775 //if BG is starting ... invite anyone:
776 if (GetStatus() == STATUS_WAIT_JOIN
)
777 return GetInvitedCount(Team
) < GetMaxPlayersPerTeam();
778 //if BG is already started .. do not allow to join too much players of one faction
780 if (Team
== ALLIANCE
)
781 otherTeam
= GetInvitedCount(HORDE
);
783 otherTeam
= GetInvitedCount(ALLIANCE
);
784 if (GetStatus() == STATUS_IN_PROGRESS
)
785 return (GetInvitedCount(Team
) <= otherTeam
&& GetInvitedCount(Team
) < GetMaxPlayersPerTeam());
790 /* this method isn't called already, it will be useful when more battlegrounds of one type will be available */
791 bool BattleGround::HasFreeSlots() const
793 return GetPlayersSize() < GetMaxPlayers();
796 void BattleGround::UpdatePlayerScore(Player
*Source
, uint32 type
, uint32 value
)
798 //this procedure is called from virtual function implemented in bg subclass
799 std::map
<uint64
, BattleGroundScore
*>::iterator itr
= m_PlayerScores
.find(Source
->GetGUID());
801 if(itr
== m_PlayerScores
.end()) // player not found...
806 case SCORE_KILLING_BLOWS
: // Killing blows
807 itr
->second
->KillingBlows
+= value
;
809 case SCORE_DEATHS
: // Deaths
810 itr
->second
->Deaths
+= value
;
812 case SCORE_HONORABLE_KILLS
: // Honorable kills
813 itr
->second
->HonorableKills
+= value
;
815 case SCORE_BONUS_HONOR
: // Honor bonus
816 // reward honor instantly
817 if(Source
->RewardHonor(NULL
, 1, value
))
818 itr
->second
->BonusHonor
+= value
;
820 //used only in EY, but in MSG_PVP_LOG_DATA opcode
821 case SCORE_DAMAGE_DONE
: // Damage Done
822 itr
->second
->DamageDone
+= value
;
824 case SCORE_HEALING_DONE
: // Healing Done
825 itr
->second
->HealingDone
+= value
;
828 sLog
.outError("BattleGround: Unknown player score type %u", type
);
833 void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid
, uint64 player_guid
)
835 m_ReviveQueue
[npc_guid
].push_back(player_guid
);
837 Player
*plr
= objmgr
.GetPlayer(player_guid
);
841 plr
->CastSpell(plr
, SPELL_WAITING_FOR_RESURRECT
, true);
842 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( SPELL_WAITING_FOR_RESURRECT
);
845 Aura
*Aur
= CreateAura(spellInfo
, 0, NULL
, plr
);
850 void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid
)
852 for(std::map
<uint64
, std::vector
<uint64
> >::iterator itr
= m_ReviveQueue
.begin(); itr
!= m_ReviveQueue
.end(); ++itr
)
854 for(std::vector
<uint64
>::iterator itr2
=(itr
->second
).begin(); itr2
!= (itr
->second
).end(); ++itr2
)
856 if(*itr2
== player_guid
)
858 (itr
->second
).erase(itr2
);
860 Player
*plr
= objmgr
.GetPlayer(player_guid
);
864 plr
->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT
);
872 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
)
874 GameObjectInfo
const* goinfo
= objmgr
.GetGameObjectInfo(entry
);
877 sLog
.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry
);
881 uint32 guid
= objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
);
883 GameObjectData
& data
= objmgr
.NewGOData(guid
);
886 data
.mapid
= GetMapId();
890 data
.orientation
= o
;
891 data
.rotation0
= rotation0
;
892 data
.rotation1
= rotation1
;
893 data
.rotation2
= rotation2
;
894 data
.rotation3
= rotation3
;
895 data
.spawntimesecs
= respawnTime
;
896 data
.animprogress
= 100;
899 objmgr
.AddGameobjectToGrid(guid
, &data
);
901 m_BgObjects
[type
] = MAKE_NEW_GUID(guid
, entry
, HIGHGUID_GAMEOBJECT
);
906 //some doors aren't despawned so we cannot handle their closing in gameobject::update()
907 //it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
908 void BattleGround::DoorClose(uint32 type
)
910 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
913 //if doors are open, close it
914 if( obj
->getLootState() == GO_ACTIVATED
&& !obj
->GetGoState() )
916 //change state to allow door to be closed
917 obj
->SetLootState(GO_READY
);
918 obj
->UseDoorOrButton(RESPAWN_ONE_DAY
);
923 sLog
.outError("BattleGround: Door object not found (cannot close doors)");
927 void BattleGround::DoorOpen(uint32 type
)
929 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
932 //change state to be sure they will be opened
933 obj
->SetLootState(GO_READY
);
934 obj
->UseDoorOrButton(RESPAWN_ONE_DAY
);
938 sLog
.outError("BattleGround: Door object not found! - doors will be closed.");
942 void BattleGround::SpawnBGObject(uint32 type
, uint32 respawntime
)
944 if( respawntime
== 0 )
946 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
949 //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
950 if( obj
->getLootState() == GO_JUST_DEACTIVATED
)
951 obj
->SetLootState(GO_READY
);
955 objmgr
.SaveGORespawnTime(GUID_LOPART(m_BgObjects
[type
]), 0, 0);
959 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
962 obj
->SetRespawnTime(respawntime
);
963 obj
->SetLootState(GO_JUST_DEACTIVATED
);
966 objmgr
.SaveGORespawnTime(GUID_LOPART(m_BgObjects
[type
]), 0, time(NULL
) + respawntime
);
970 Creature
* BattleGround::AddCreature(uint32 entry
, uint32 type
, uint32 teamval
, float x
, float y
, float z
, float o
)
972 // note: this should normally be FindMap
973 // but it's a hack to allow the battlegrounds to initialize at server startup
974 Map
* map
= MapManager::Instance().GetMap(GetMapId(), 0);
975 if(!map
) return NULL
;
977 Creature
* pCreature
= new Creature
;
978 if (!pCreature
->Create(objmgr
.GenerateLowGuid(HIGHGUID_UNIT
), map
, entry
, teamval
))
980 sLog
.outError("Can't create creature entry: %u",entry
);
985 pCreature
->Relocate(x
, y
, z
, o
);
987 if(!pCreature
->IsPositionValid())
989 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());
993 pCreature
->AIM_Initialize();
995 //pCreature->SetDungeonDifficulty(0);
998 m_BgCreatures
[type
] = pCreature
->GetGUID();
1002 bool BattleGround::DelCreature(uint32 type
)
1004 Creature
*cr
= HashMapHolder
<Creature
>::Find(m_BgCreatures
[type
]);
1007 sLog
.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures
[type
]));
1010 cr
->CleanupsBeforeDelete();
1011 cr
->AddObjectToRemoveList();
1012 m_BgCreatures
[type
] = 0;
1016 bool BattleGround::DelObject(uint32 type
)
1018 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(m_BgObjects
[type
]);
1021 sLog
.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects
[type
]));
1024 obj
->SetRespawnTime(0); // not save respawn time
1026 m_BgObjects
[type
] = 0;
1030 bool BattleGround::AddSpiritGuide(uint32 type
, float x
, float y
, float z
, float o
, uint32 team
)
1034 if(team
== ALLIANCE
)
1039 Creature
* pCreature
= AddCreature(entry
,type
,team
,x
,y
,z
,o
);
1042 sLog
.outError("Can't create Spirit guide. BattleGround not created!");
1047 pCreature
->setDeathState(DEAD
);
1049 pCreature
->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT
, pCreature
->GetGUID());
1051 pCreature
->SetUInt32Value(UNIT_FIELD_AURA
, SPELL_SPIRIT_HEAL_CHANNEL
);
1052 pCreature
->SetUInt32Value(UNIT_FIELD_AURAFLAGS
, 0x00000009);
1053 pCreature
->SetUInt32Value(UNIT_FIELD_AURALEVELS
, 0x0000003C);
1054 pCreature
->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS
, 0x000000FF);
1055 // casting visual effect
1056 pCreature
->SetUInt32Value(UNIT_CHANNEL_SPELL
, SPELL_SPIRIT_HEAL_CHANNEL
);
1057 // correct cast speed
1058 pCreature
->SetFloatValue(UNIT_MOD_CAST_SPEED
, 1.0f
);
1060 //pCreature->CastSpell(pCreature, SPELL_SPIRIT_HEAL_CHANNEL, true);
1065 void BattleGround::SendMessageToAll(char const* text
)
1068 ChatHandler::FillMessageData(&data
, NULL
, CHAT_MSG_BG_SYSTEM_NEUTRAL
, LANG_UNIVERSAL
, NULL
, 0, text
, NULL
);
1069 SendPacketToAll(&data
);
1072 void BattleGround::SendMessageToAll(int32 entry
)
1074 char const* text
= GetMangosString(entry
);
1076 ChatHandler::FillMessageData(&data
, NULL
, CHAT_MSG_BG_SYSTEM_NEUTRAL
, LANG_UNIVERSAL
, NULL
, 0, text
, NULL
);
1077 SendPacketToAll(&data
);
1080 void BattleGround::EndNow()
1082 SetStatus(STATUS_WAIT_LEAVE
);
1083 SetEndTime(TIME_TO_AUTOREMOVE
);
1086 // Battleground messages are localized using the dbc lang, they are not client language dependent
1087 const char *BattleGround::GetMangosString(int32 entry
)
1089 // FIXME: now we have different DBC locales and need localized message for each target client
1090 return objmgr
.GetMangosStringForDBCLocale(entry
);
1095 buffs aren't spawned/despawned when players captures anything
1096 buffs are in their positions when battleground starts
1098 void BattleGround::HandleTriggerBuff(uint64
const& go_guid
)
1100 GameObject
*obj
= HashMapHolder
<GameObject
>::Find(go_guid
);
1101 if(!obj
|| obj
->GetGoType() != GAMEOBJECT_TYPE_TRAP
|| !obj
->isSpawned())
1104 //change buff type, when buff is used:
1105 int32 index
= m_BgObjects
.size() - 1;
1106 while (index
>= 0 && m_BgObjects
[index
] != go_guid
)
1110 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());
1114 //randomly select new buff
1115 uint8 buff
= urand(0, 2);
1116 uint32 entry
= obj
->GetEntry();
1117 if( m_BuffChange
&& entry
!= Buff_Entries
[buff
] )
1119 //despawn current buff
1120 SpawnBGObject(index
, RESPAWN_ONE_DAY
);
1121 //set index for new one
1122 for (uint8 currBuffTypeIndex
= 0; currBuffTypeIndex
< 3; ++currBuffTypeIndex
)
1123 if( entry
== Buff_Entries
[currBuffTypeIndex
] )
1125 index
-= currBuffTypeIndex
;
1130 SpawnBGObject(index
, BUFF_RESPAWN_TIME
);
1133 void BattleGround::HandleKillPlayer( Player
*player
, Player
*killer
)
1135 //keep in mind that for arena this will have to be changed a bit
1138 UpdatePlayerScore(player
, SCORE_DEATHS
, 1);
1140 // add +1 kills to group and +1 killing_blows to killer
1143 UpdatePlayerScore(killer
, SCORE_HONORABLE_KILLS
, 1);
1144 UpdatePlayerScore(killer
, SCORE_KILLING_BLOWS
, 1);
1146 for(std::map
<uint64
, BattleGroundPlayer
>::iterator itr
= m_Players
.begin(); itr
!= m_Players
.end(); ++itr
)
1148 Player
*plr
= objmgr
.GetPlayer(itr
->first
);
1150 if(!plr
|| plr
== killer
)
1153 if( plr
->GetTeam() == killer
->GetTeam() && plr
->IsAtGroupRewardDistance(player
) )
1154 UpdatePlayerScore(plr
, SCORE_HONORABLE_KILLS
, 1);
1158 // to be able to remove insignia
1159 player
->SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
);