root/trunk/src/game/BattleGround.cpp @ 9

Revision 9, 49.5 kB (checked in by yumileroy, 17 years ago)

[svn] -enabled instantiated battlegrounds
-enabled arena matches
-rewritten battleground queuing to support joining as group
-removed queue announcements

Original author: w12x
Date: 2008-10-05 08:48:32-05:00

RevLine 
[2]1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
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.
8 *
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.
13 *
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
17 */
18
19#include "Object.h"
20#include "Player.h"
21#include "BattleGround.h"
22#include "Creature.h"
23#include "MapManager.h"
24#include "Language.h"
25#include "Chat.h"
26#include "SpellAuras.h"
[9]27#include "ArenaTeam.h"
[2]28#include "World.h"
29#include "Util.h"
30
31BattleGround::BattleGround()
32{
33    m_TypeID            = 0;
34    m_InstanceID        = 0;
35    m_Status            = 0;
36    m_EndTime           = 0;
37    m_LastResurrectTime = 0;
38    m_Queue_type        = MAX_BATTLEGROUND_QUEUES;
39    m_InvitedAlliance   = 0;
40    m_InvitedHorde      = 0;
41    m_ArenaType         = 0;
42    m_IsArena           = false;
43    m_Winner            = 2;
44    m_StartTime         = 0;
45    m_Events            = 0;
46    m_IsRated           = false;
47    m_BuffChange        = false;
48    m_Name              = "";
49    m_LevelMin          = 0;
50    m_LevelMax          = 0;
[9]51    m_InBGFreeSlotQueue = false;
52    m_SetDeleteThis     = false;
[2]53
54    m_MaxPlayersPerTeam = 0;
55    m_MaxPlayers        = 0;
56    m_MinPlayersPerTeam = 0;
57    m_MinPlayers        = 0;
58
59    m_MapId             = 0;
60
61    m_TeamStartLocX[BG_TEAM_ALLIANCE]   = 0;
62    m_TeamStartLocX[BG_TEAM_HORDE]      = 0;
63
64    m_TeamStartLocY[BG_TEAM_ALLIANCE]   = 0;
65    m_TeamStartLocY[BG_TEAM_HORDE]      = 0;
66
67    m_TeamStartLocZ[BG_TEAM_ALLIANCE]   = 0;
68    m_TeamStartLocZ[BG_TEAM_HORDE]      = 0;
69
70    m_TeamStartLocO[BG_TEAM_ALLIANCE]   = 0;
71    m_TeamStartLocO[BG_TEAM_HORDE]      = 0;
72
[9]73    m_ArenaTeamIds[BG_TEAM_ALLIANCE]   = 0;
74    m_ArenaTeamIds[BG_TEAM_HORDE]      = 0;
75
76    m_ArenaTeamRatingChanges[BG_TEAM_ALLIANCE]   = 0;
77    m_ArenaTeamRatingChanges[BG_TEAM_HORDE]      = 0;
78
[2]79    m_BgRaids[BG_TEAM_ALLIANCE]         = NULL;
80    m_BgRaids[BG_TEAM_HORDE]            = NULL;
81
82    m_PlayersCount[BG_TEAM_ALLIANCE]    = 0;
83    m_PlayersCount[BG_TEAM_HORDE]       = 0;
[9]84
85    m_PrematureCountDown = false;
86    m_PrematureCountDown = 0;
[2]87}
88
89BattleGround::~BattleGround()
90{
[9]91    // remove objects and creatures
92    // (this is done automatically in mapmanager update, when the instance is reset after the reset time)   
93    int size = m_BgCreatures.size();
94    for(int i = 0; i < size; ++i)
95    {
96        DelCreature(i);
97    }
98    size = m_BgObjects.size();
99    for(int i = 0; i < size; ++i)
100    {
101        DelObject(i);
102    }
[2]103
[9]104    // delete creature and go respawn times
105    WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'",GetInstanceID());
106    WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'",GetInstanceID());
107    // delete instance from db
108    CharacterDatabase.PExecute("DELETE FROM instance WHERE id = '%u'",GetInstanceID());
109    // remove from battlegrounds
110    sBattleGroundMgr.RemoveBattleGround(GetInstanceID());
111    // unload map
112    if(Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID()))
113        if(map->IsBattleGroundOrArena())
114            ((BattleGroundMap*)map)->SetUnload();
115    // remove from bg free slot queue
116    this->RemoveFromBGFreeSlotQueue();
[2]117}
118
119void BattleGround::Update(time_t diff)
120{
121    if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize())
122        //BG is empty
123        return;
124
125    WorldPacket data;
126
127    if(GetRemovedPlayersSize())
128    {
129        for(std::map<uint64, uint8>::iterator itr = m_RemovedPlayers.begin(); itr != m_RemovedPlayers.end(); ++itr)
130        {
131            Player *plr = objmgr.GetPlayer(itr->first);
132            switch(itr->second)
133            {
134                //following code is handled by event:
135                /*case 0:
136                    sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].RemovePlayer(itr->first);
137                    //RemovePlayerFromQueue(itr->first);
138                    if(plr)
139                    {
140                        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0);
141                        plr->GetSession()->SendPacket(&data);
142                    }
143                    break;*/
144                case 1:                                     // currently in bg and was removed from bg
145                    if(plr)
146                        RemovePlayerAtLeave(itr->first, true, true);
147                    else
148                        RemovePlayerAtLeave(itr->first, false, false);
149                    break;
150                case 2:                                     // revive queue
151                    RemovePlayerFromResurrectQueue(itr->first);
152                    break;
153                default:
154                    sLog.outError("BattleGround: Unknown remove player case!");
155            }
156        }
157        m_RemovedPlayers.clear();
158    }
159
160    // this code isn't efficient and its idea isn't implemented yet
161    /* offline players are removed from battleground in worldsession::LogoutPlayer()
162    // remove offline players from bg after ~5 minutes
163    if(GetPlayersSize())
164    {
165        for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
166        {
167            Player *plr = objmgr.GetPlayer(itr->first);
168            itr->second.LastOnlineTime += diff;
169
170            if(plr)
171                itr->second.LastOnlineTime = 0;   // update last online time
172            else
173                if(itr->second.LastOnlineTime >= MAX_OFFLINE_TIME)                   // 5 minutes
174                    m_RemovedPlayers[itr->first] = 1;       // add to remove list (BG)
175        }
176    }*/
177
178    m_LastResurrectTime += diff;
179    if (m_LastResurrectTime >= RESURRECTION_INTERVAL)
180    {
181        if(GetReviveQueueSize())
182        {
183            for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
184            {
185                Creature *sh = NULL;
186                for(std::vector<uint64>::iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
187                {
188                    Player *plr = objmgr.GetPlayer(*itr2);
189                    if(!plr)
190                        continue;
191
192                    if (!sh)
193                    {
194                        sh = ObjectAccessor::GetCreature(*plr, itr->first);
195                        // only for visual effect
196                        if (sh)
197                            sh->CastSpell(sh, SPELL_SPIRIT_HEAL, true);   // Spirit Heal, effect 117
198                    }
199
200                    plr->CastSpell(plr, SPELL_RESURRECTION_VISUAL, true);   // Resurrection visual
201                    m_ResurrectQueue.push_back(*itr2);
202                }
203                (itr->second).clear();
204            }
205
206            m_ReviveQueue.clear();
207            m_LastResurrectTime = 0;
208        }
209        else
210            // queue is clear and time passed, just update last resurrection time
211            m_LastResurrectTime = 0;
212    }
213    else if (m_LastResurrectTime > 500)    // Resurrect players only half a second later, to see spirit heal effect on NPC
214    {
215        for(std::vector<uint64>::iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
216        {
217            Player *plr = objmgr.GetPlayer(*itr);
218            if(!plr)
219                continue;
220            plr->ResurrectPlayer(1.0f);
221            plr->CastSpell(plr, SPELL_SPIRIT_HEAL_MANA, true);
222            ObjectAccessor::Instance().ConvertCorpseForPlayer(*itr);
223        }
224        m_ResurrectQueue.clear();
225    }
226
[9]227    // if less then minimum players are in on one side, then start premature finish timer
228    if(GetStatus() == STATUS_IN_PROGRESS && !isArena() && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam()))
229    {
230        if(!m_PrematureCountDown)
231        {
232            m_PrematureCountDown = true;
233            m_PrematureCountDownTimer = sBattleGroundMgr.GetPrematureFinishTime();
234            SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
235        }
236        else if(m_PrematureCountDownTimer < diff)
237        {
238            // time's up!
239            EndBattleGround(0); // noone wins
240            m_PrematureCountDown = false;
241        } 
242        else 
243        {
244            uint32 newtime = m_PrematureCountDownTimer - diff;
245            // announce every minute
246            if(m_PrematureCountDownTimer != sBattleGroundMgr.GetPrematureFinishTime() && newtime / 60000 != m_PrematureCountDownTimer / 60000)
247                SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
248            m_PrematureCountDownTimer = newtime;
249        }
250    }
251    else if (m_PrematureCountDown)
252        m_PrematureCountDown = false;
253
[2]254    if(GetStatus() == STATUS_WAIT_LEAVE)
255    {
256        // remove all players from battleground after 2 minutes
257        m_EndTime += diff;
258        if(m_EndTime >= TIME_TO_AUTOREMOVE)                 // 2 minutes
259        {
260            for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
261            {
262                m_RemovedPlayers[itr->first] = 1;           // add to remove list (BG)
263            }
264            // do not change any battleground's private variables
265        }
266    }
267}
268
269void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O)
270{
271    uint8 idx = GetTeamIndexByTeamId(TeamID);
272    m_TeamStartLocX[idx] = X;
273    m_TeamStartLocY[idx] = Y;
274    m_TeamStartLocZ[idx] = Z;
275    m_TeamStartLocO[idx] = O;
276}
277
278void BattleGround::SendPacketToAll(WorldPacket *packet)
279{
280    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
281    {
282        Player *plr = objmgr.GetPlayer(itr->first);
283        if(plr)
284            plr->GetSession()->SendPacket(packet);
285        else
286            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
287    }
288}
289
290void BattleGround::SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *sender, bool self)
291{
292    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
293    {
294        Player *plr = objmgr.GetPlayer(itr->first);
295
296        if(!plr)
297        {
298            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
299            continue;
300        }
301
302        if(!self && sender == plr)
303            continue;
304
[9]305        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
306
307        if(team == TeamID)
[2]308            plr->GetSession()->SendPacket(packet);
309    }
310}
311
312void BattleGround::PlaySoundToAll(uint32 SoundID)
313{
314    WorldPacket data;
315    sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
316    SendPacketToAll(&data);
317}
318
319void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID)
320{
321    WorldPacket data;
322
323    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
324    {
325        Player *plr = objmgr.GetPlayer(itr->first);
326
327        if(!plr)
328        {
329            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
330            continue;
331        }
332
[9]333        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
334
335        if(team == TeamID)
[2]336        {
337            sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
338            plr->GetSession()->SendPacket(&data);
339        }
340    }
341}
342
343void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID)
344{
345    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
346    {
347        Player *plr = objmgr.GetPlayer(itr->first);
348
349        if(!plr)
350        {
351            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
352            continue;
353        }
354
[9]355        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
356       
357        if(team == TeamID)
[2]358            plr->CastSpell(plr, SpellID, true);
359    }
360}
361
362void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID)
363{
364    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
365    {
366        Player *plr = objmgr.GetPlayer(itr->first);
367
368        if(!plr)
369        {
370            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
371            continue;
372        }
373
[9]374        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
375
376        if(team == TeamID)
[2]377            UpdatePlayerScore(plr, SCORE_BONUS_HONOR, Honor);
378    }
379}
380
381void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID)
382{
383    FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
384
385    if(!factionEntry)
386        return;
387
388    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
389    {
390        Player *plr = objmgr.GetPlayer(itr->first);
391
392        if(!plr)
393        {
394            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
395            continue;
396        }
397
[9]398        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
399
400        if(team == TeamID)
[2]401            plr->ModifyFactionReputation(factionEntry, Reputation);
402    }
403}
404
405void BattleGround::UpdateWorldState(uint32 Field, uint32 Value)
406{
407    WorldPacket data;
408    sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
409    SendPacketToAll(&data);
410}
411
412void BattleGround::UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player *Source)
413{
414    WorldPacket data;
415    sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
416    Source->GetSession()->SendPacket(&data);
417}
418
419void BattleGround::EndBattleGround(uint32 winner)
420{
[9]421    // battleground finished, remove from the running bg's list
422    this->RemoveFromBGFreeSlotQueue();
423
424    ArenaTeam * winner_arena_team = NULL;
425    ArenaTeam * loser_arena_team = NULL;
426    uint32 loser_rating = 0;
427    uint32 winner_rating = 0;
[2]428    WorldPacket data;
429    Player *Source = NULL;
430    const char *winmsg = "";
431
432    if(winner == ALLIANCE)
433    {
[9]434        if(isBattleGround())
435            winmsg = GetMangosString(LANG_BG_A_WINS);
436        else
437            winmsg = GetMangosString(LANG_ARENA_GOLD_WINS);
[2]438
439        PlaySoundToAll(SOUND_ALLIANCE_WINS);                // alliance wins sound
440
441        SetWinner(WINNER_ALLIANCE);
442    }
[9]443    else if(winner == HORDE)
[2]444    {
[9]445        if(isBattleGround())
446            winmsg = GetMangosString(LANG_BG_H_WINS);
447        else
448            winmsg = GetMangosString(LANG_ARENA_GREEN_WINS);
[2]449
450        PlaySoundToAll(SOUND_HORDE_WINS);                   // horde wins sound
451
452        SetWinner(WINNER_HORDE);
453    }
[9]454    else
455    {
456        SetWinner(3);
457    }
[2]458
459    SetStatus(STATUS_WAIT_LEAVE);
460    m_EndTime = 0;
461
[9]462    // arena rating calculation
463    if(isArena() && isRated())
464    {
465        if(winner == ALLIANCE)
466        {
467            winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
468            loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
469        }
470        else if(winner == HORDE)
471        {
472            winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
473            loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
474        }
475        if(winner_arena_team && loser_arena_team)
476        {
477            loser_rating = loser_arena_team->GetStats().rating;
478            winner_rating = winner_arena_team->GetStats().rating;
479            float winner_chance = winner_arena_team->GetChanceAgainst(loser_rating);
480            float loser_chance = loser_arena_team->GetChanceAgainst(winner_rating);
481            int32 winner_change = winner_arena_team->WonAgainstChance(winner_chance);
482            int32 loser_change = loser_arena_team->LostAgainstChance(loser_chance);
483            sLog.outDebug("--- %u ; %u ; %d ; %d ; %u ; %u ---",winner_rating,loser_rating,winner_chance,loser_chance,winner_change,loser_change);
484            if(winner == ALLIANCE)
485            {
486                SetArenaTeamRatingChangeForTeam(ALLIANCE, winner_change);
487                SetArenaTeamRatingChangeForTeam(HORDE, loser_change);
488            }
489            else
490            {
491                SetArenaTeamRatingChangeForTeam(HORDE, winner_change);
492                SetArenaTeamRatingChangeForTeam(ALLIANCE, loser_change);
493            }
494        }
495        else
496        {
497            SetArenaTeamRatingChangeForTeam(ALLIANCE, 0);
498            SetArenaTeamRatingChangeForTeam(HORDE, 0);
499        }
500    }
501
[2]502    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
503    {
504        Player *plr = objmgr.GetPlayer(itr->first);
505        if(!plr)
506        {
507            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
508            continue;
509        }
510
[9]511        // should remove spirit of redemption
512        if(plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
513            plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
514
[2]515        if(!plr->isAlive())
516        {
517            plr->ResurrectPlayer(1.0f);
518            plr->SpawnCorpseBones();
519        }
520
[9]521        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
522        if(!team) team = plr->GetTeam();
523
524        // per player calculation
525        if(isArena() && isRated() && winner_arena_team && loser_arena_team)
[2]526        {
[9]527            if(team == winner)
528                winner_arena_team->MemberWon(plr,loser_rating);
529            else
530                loser_arena_team->MemberLost(plr,winner_rating);
531        }
532
533        if(team == winner)
534        {
[2]535            if(!Source)
536                Source = plr;
537            RewardMark(plr,ITEM_WINNER_COUNT);
538            UpdatePlayerScore(plr, SCORE_BONUS_HONOR, 20);
539            RewardQuest(plr);
540        }
541        else
542        {
543            RewardMark(plr,ITEM_LOSER_COUNT);
544        }
545
546        plr->CombatStopWithPets(true);
547
548        BlockMovement(plr);
549
550        sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
551        plr->GetSession()->SendPacket(&data);
552
[9]553        uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());
554        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
[2]555        plr->GetSession()->SendPacket(&data);
556    }
557
[9]558    if(isArena() && isRated() && winner_arena_team && loser_arena_team)
559    {
560        // update arena points only after increasing the player's match count!
561        winner_arena_team->UpdateArenaPointsHelper();
562        loser_arena_team->UpdateArenaPointsHelper();
563        // save the stat changes
564        winner_arena_team->SaveToDB();
565        loser_arena_team->SaveToDB();
566        // send updated arena team stats to players
567        // this way all arena team members will get notified, not only the ones who participated in this match
568        winner_arena_team->NotifyStatsChanged();
569        loser_arena_team->NotifyStatsChanged();
570    }
571
572    // inform invited players about the removal
573    sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
574
[2]575    if(Source)
576    {
577        ChatHandler(Source).FillMessageData(&data, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, Source->GetGUID(), winmsg);
578        SendPacketToAll(&data);
579    }
580}
581
582uint32 BattleGround::GetBattlemasterEntry() const
583{
584    switch(GetTypeID())
585    {
586        case BATTLEGROUND_AV: return 15972;
587        case BATTLEGROUND_WS: return 14623;
588        case BATTLEGROUND_AB: return 14879;
589        case BATTLEGROUND_EY: return 22516;
590        case BATTLEGROUND_NA: return 20200;
591        default:              return 0;
592    }
593}
594
595void BattleGround::RewardMark(Player *plr,uint32 count)
596{
597    // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
598    if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
599        return;
600
601    BattleGroundMarks mark;
602    bool IsSpell;
603    switch(GetTypeID())
604    {
605        case BATTLEGROUND_AV:
606            IsSpell = true;
607            if(count == ITEM_WINNER_COUNT)
608                mark = SPELL_AV_MARK_WINNER;
609            else
610                mark = SPELL_AV_MARK_LOSER;
611            break;
612        case BATTLEGROUND_WS:
613            IsSpell = true;
614            if(count == ITEM_WINNER_COUNT)
615                mark = SPELL_WS_MARK_WINNER;
616            else
617                mark = SPELL_WS_MARK_LOSER;
618            break;
619        case BATTLEGROUND_AB:
620            IsSpell = true;
621            if(count == ITEM_WINNER_COUNT)
622                mark = SPELL_AB_MARK_WINNER;
623            else
624                mark = SPELL_AB_MARK_LOSER;
625            break;
626        case BATTLEGROUND_EY:
627            IsSpell = false;
628            mark = ITEM_EY_MARK_OF_HONOR;
629            break;
630        default:
631            return;
632    }
633
634    if(IsSpell)
635        plr->CastSpell(plr, mark, true);
636    else if ( objmgr.GetItemPrototype( mark ) )
637    {
638        ItemPosCountVec dest;
639        uint32 no_space_count = 0;
640        uint8 msg = plr->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, mark, count, &no_space_count );
641        if( msg != EQUIP_ERR_OK )                       // convert to possible store amount
642            count -= no_space_count;
643
644        if( count != 0 && !dest.empty())                // can add some
645            if(Item* item = plr->StoreNewItem( dest, mark, true, 0))
646                plr->SendNewItem(item,count,false,true);
647
648        if(no_space_count > 0)
649            SendRewardMarkByMail(plr,mark,no_space_count);
650    }
651}
652
653void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count)
654{
655    uint32 bmEntry = GetBattlemasterEntry();
656    if(!bmEntry)
657        return;
658
659    ItemPrototype const* markProto = objmgr.GetItemPrototype(mark);
660    if(!markProto)
661        return;
662
663    if(Item* markItem = Item::CreateItem(mark,count,plr))
664    {
665        // save new item before send
666        markItem->SaveToDB();                               // save for prevent lost at next mail load, if send fail then item will deleted
667
668        // item
669        MailItemsInfo mi;
670        mi.AddItem(markItem->GetGUIDLow(), markItem->GetEntry(), markItem);
671
672        // subject: item name
673        std::string subject = markProto->Name1;
674        int loc_idx = plr->GetSession()->GetSessionDbLocaleIndex();
675        if ( loc_idx >= 0 )
676            if(ItemLocale const *il = objmgr.GetItemLocale(markProto->ItemId))
677                if (il->Name.size() > loc_idx && !il->Name[loc_idx].empty())
678                    subject = il->Name[loc_idx];
679
680        // text
681        std::string textFormat = plr->GetSession()->GetMangosString(LANG_BG_MARK_BY_MAIL);
682        char textBuf[300];
683        snprintf(textBuf,300,textFormat.c_str(),GetName(),GetName());
684        uint32 itemTextId = objmgr.CreateItemText( textBuf );
685
686        WorldSession::SendMailTo(plr, MAIL_CREATURE, MAIL_STATIONERY_NORMAL, bmEntry, plr->GetGUIDLow(), subject, itemTextId , &mi, 0, 0, MAIL_CHECK_MASK_NONE);
687    }
688}
689
690void BattleGround::RewardQuest(Player *plr)
691{
692    // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
693    if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
694        return;
695
696    uint32 quest;
697    switch(GetTypeID())
698    {
699        case BATTLEGROUND_AV:
700            quest = SPELL_AV_QUEST_REWARD;
701            break;
702        case BATTLEGROUND_WS:
703            quest = SPELL_WS_QUEST_REWARD;
704            break;
705        case BATTLEGROUND_AB:
706            quest = SPELL_AB_QUEST_REWARD;
707            break;
708        case BATTLEGROUND_EY:
709            quest = SPELL_EY_QUEST_REWARD;
710            break;
711        default:
712            return;
713    }
714
715    plr->CastSpell(plr, quest, true);
716}
717
718void BattleGround::BlockMovement(Player *plr)
719{
720    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()
721}
722
723void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket)
724{
[9]725    uint32 team = GetPlayerTeam(guid);
726    bool participant = false;
[2]727    // Remove from lists/maps
728    std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.find(guid);
729    if(itr != m_Players.end())
730    {
[9]731        UpdatePlayersCountByTeam(team, true);   // -1 player
[2]732        m_Players.erase(itr);
[9]733        // check if the player was a participant of the match, or only entered through gm command (goname)
734        participant = true;
[2]735    }
736
737    std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid);
738    if(itr2 != m_PlayerScores.end())
739    {
740        delete itr2->second;                                // delete player's score
741        m_PlayerScores.erase(itr2);
742    }
743
744    RemovePlayerFromResurrectQueue(guid);
745
746    Player *plr = objmgr.GetPlayer(guid);
747
[9]748    // should remove spirit of redemption
749    if(plr && plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
750        plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
751
[2]752    if(plr && !plr->isAlive())                              // resurrect on exit
753    {
754        plr->ResurrectPlayer(1.0f);
755        plr->SpawnCorpseBones();
756    }
757
758    RemovePlayer(plr, guid);                                // BG subclass specific code
759
760    if(plr)
761    {
762        plr->ClearAfkReports();
763
[9]764        if(participant) // if the player was a match participant, remove auras, calc rating, update queue
[2]765        {
[9]766            if(!team) team = plr->GetTeam();
[2]767
[9]768            uint32 bgTypeId = GetTypeID();
769            uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());
770            // if arena, remove the specific arena auras
771            if(isArena())
772            {
773                plr->RemoveArenaAuras(true);    // removes debuffs / dots etc., we don't want the player to die after porting out
774                bgTypeId=BATTLEGROUND_AA;       // set the bg type to all arenas (it will be used for queue refreshing)
[2]775
[9]776                // summon old pet if there was one and there isn't a current pet
777                if(!plr->GetPet() && plr->GetTemporaryUnsummonedPetNumber())
778                {
779                    Pet* NewPet = new Pet;
780                    if(!NewPet->LoadPetFromDB(plr, 0, (plr)->GetTemporaryUnsummonedPetNumber(), true))
781                        delete NewPet;
[2]782
[9]783                    (plr)->SetTemporaryUnsummonedPetNumber(0);
784                }
[2]785
[9]786                if(isRated() && GetStatus() == STATUS_IN_PROGRESS)
787                {
788                    //left a rated match while the encounter was in progress, consider as loser
789                    ArenaTeam * winner_arena_team = 0;
790                    ArenaTeam * loser_arena_team = 0;
791                    if(team == HORDE)
792                    {
793                        winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
794                        loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
795                    }
796                    else
797                    {
798                        winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
799                        loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
800                    }
801                    if(winner_arena_team && loser_arena_team)
802                    {
803                        loser_arena_team->MemberLost(plr,winner_arena_team->GetRating());
804                    }
805                }
806            }
[2]807
[9]808            WorldPacket data;
809            if(SendPacket)
810            {
811                sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, team, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0);
812                plr->GetSession()->SendPacket(&data);
813            }
[2]814
[9]815            // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
816            plr->RemoveBattleGroundQueueId(bgQueueTypeId);
817
818            DecreaseInvitedCount(team);
819            //we should update battleground queue, but only if bg isn't ending
820            if (GetQueueType() < MAX_BATTLEGROUND_QUEUES)
821                sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueType());
822
823            Group * group = plr->GetGroup();
824            // remove from raid group if exist
825            if(group && group == GetBgRaid(team))
[2]826            {
[9]827                if(!group->RemoveMember(guid, 0))               // group was disbanded
828                {
829                    SetBgRaid(team, NULL);
830                    delete group;
831                }
[2]832            }
[9]833
834            // Let others know
835            sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);
836            SendPacketToTeam(team, &data, plr, false);
[2]837        }
838
839        // Do next only if found in battleground
840        plr->SetBattleGroundId(0);                          // We're not in BG.
[9]841        // reset destination bg team
842        plr->SetBGTeam(0);
[2]843
844        if(Transport)
845        {
846            plr->TeleportTo(plr->GetBattleGroundEntryPointMap(), plr->GetBattleGroundEntryPointX(), plr->GetBattleGroundEntryPointY(), plr->GetBattleGroundEntryPointZ(), plr->GetBattleGroundEntryPointO());
847        }
848
849        // Log
850        sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName());
851    }
852
[9]853    if(!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
[2]854    {
[9]855        // if no players left AND no invitees left, set this bg to delete in next update
856        // direct deletion could cause crashes
857        m_SetDeleteThis = true;
858        // return to prevent addition to freeslotqueue
859        return;
[2]860    }
[9]861
862    // a player exited the battleground, so there are free slots. add to queue
863    this->AddToBGFreeSlotQueue();
[2]864}
865
866// this method is called when no players remains in battleground
867void BattleGround::Reset()
868{
869    SetQueueType(MAX_BATTLEGROUND_QUEUES);
870    SetWinner(WINNER_NONE);
871    SetStatus(STATUS_WAIT_QUEUE);
872    SetStartTime(0);
873    SetEndTime(0);
874    SetLastResurrectTime(0);
[9]875    SetArenaType(0);
876    SetRated(false);
[2]877
878    m_Events = 0;
879
880    if (m_InvitedAlliance > 0 || m_InvitedHorde > 0)
881        sLog.outError("BattleGround system ERROR: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance, m_InvitedHorde);
882
883    m_InvitedAlliance = 0;
884    m_InvitedHorde = 0;
[9]885    m_InBGFreeSlotQueue = false;
[2]886
887    m_Players.clear();
888    m_PlayerScores.clear();
889
[9]890    // reset BGSubclass (this cleans up creatures and gos as well)
[2]891    this->ResetBGSubclass();
892}
893
894void BattleGround::StartBattleGround()
895{
896    ///this method should spawn spirit guides and so on
897    SetStartTime(0);
898
899    SetLastResurrectTime(0);
900}
901
902void BattleGround::AddPlayer(Player *plr)
903{
904    // score struct must be created in inherited class
905
906    uint64 guid = plr->GetGUID();
907    uint32 team = plr->GetBGTeam();
908
909    BattleGroundPlayer bp;
910    bp.LastOnlineTime = 0;
911    bp.Team = team;
912
913    // Add to list/maps
914    m_Players[guid] = bp;
915
[9]916    UpdatePlayersCountByTeam(team, false);        // +1 player
[2]917
918    WorldPacket data;
919    sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr);
920    SendPacketToTeam(team, &data, plr, false);
921
[9]922    // add arena specific auras
[2]923    if(isArena())
924    {
[9]925        // remove auras first, only then reset spell cooldowns
926        // this is to prevent bugging amp. curse, combustion, etc. like spells
927        plr->RemoveArenaAuras();
[2]928        plr->RemoveArenaSpellCooldowns();
929        plr->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT);
930        if(team == ALLIANCE && plr->GetTeam() == ALLIANCE)
931            plr->CastSpell(plr,SPELL_ALLIANCE_GOLD_FLAG,true);
932        else if(team == HORDE && plr->GetTeam() == ALLIANCE)
933            plr->CastSpell(plr,SPELL_ALLIANCE_GREEN_FLAG,true);
934        else if(team == ALLIANCE && plr->GetTeam() == HORDE)
935            plr->CastSpell(plr,SPELL_HORDE_GOLD_FLAG,true);
936        else
937            plr->CastSpell(plr,SPELL_HORDE_GREEN_FLAG,true);
938        plr->DestroyConjuredItems(true);
939
[9]940        Pet* pet = plr->GetPet();
941        if(pet)
942        {
943            if(pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET)
944            {
945                (plr)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber());
946                (plr)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));
947            }
948            (plr)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);
949        }
950
[2]951        if(GetStatus() == STATUS_WAIT_JOIN)                 // not started yet
952        {
953            plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);
954
955            plr->SetHealth(plr->GetMaxHealth());
956            plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA));
957        }
958    }
959    else
960    {
961        if(GetStatus() == STATUS_WAIT_JOIN)                 // not started yet
962            plr->CastSpell(plr, SPELL_PREPARATION, true);   // reduces all mana cost of spells.
963    }
964
965    // Log
966    sLog.outDetail("BATTLEGROUND: Player %s joined the battle.", plr->GetName());
967}
968
969/* This method should be called only once ... it adds pointer to queue */
970void BattleGround::AddToBGFreeSlotQueue()
971{
[9]972    // make sure to add only once
973    if(!m_InBGFreeSlotQueue)
974    {
975        sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);
976        m_InBGFreeSlotQueue = true;
977    }
[2]978}
979
980/* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
981void BattleGround::RemoveFromBGFreeSlotQueue()
982{
[9]983    // set to be able to re-add if needed
984    m_InBGFreeSlotQueue = false;
985    // uncomment this code when battlegrounds will work like instances
[2]986    for (std::deque<BattleGround*>::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)
987    {
988        if ((*itr)->GetInstanceID() == m_InstanceID)
989        {
990            sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr);
991            return;
992        }
[9]993    }
[2]994}
995
[9]996// get the number of free slots for team
997// works in similar way that HasFreeSlotsForTeam did, but this is needed for join as group
998uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const
[2]999{
1000    //if BG is starting ... invite anyone:
1001    if (GetStatus() == STATUS_WAIT_JOIN)
[9]1002        return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
[2]1003    //if BG is already started .. do not allow to join too much players of one faction
1004    uint32 otherTeam;
[9]1005    uint32 otherIn;
[2]1006    if (Team == ALLIANCE)
[9]1007    {
[2]1008        otherTeam = GetInvitedCount(HORDE);
[9]1009        otherIn = GetPlayersCountByTeam(HORDE);
1010    }
[2]1011    else
[9]1012    {
[2]1013        otherTeam = GetInvitedCount(ALLIANCE);
[9]1014        otherIn = GetPlayersCountByTeam(ALLIANCE);
1015    }
[2]1016    if (GetStatus() == STATUS_IN_PROGRESS)
[9]1017    {
1018        // difference based on ppl invited (not necessarily entered battle)
1019        // default: allow 0
1020        uint32 diff = 0;
1021        // allow join one person if the sides are equal (to fill up bg to minplayersperteam)
1022        if (otherTeam == GetInvitedCount(Team)) 
1023            diff = 1;
1024        // allow join more ppl if the other side has more players
1025        else if(otherTeam > GetInvitedCount(Team))
1026            diff = otherTeam - GetInvitedCount(Team);
[2]1027
[9]1028        // difference based on max players per team (don't allow inviting more)
1029        uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
1030
1031        // difference based on players who already entered
1032        // default: allow 0
1033        uint32 diff3 = 0;
1034        // allow join one person if the sides are equal (to fill up bg minplayersperteam)
1035        if (otherIn == GetPlayersCountByTeam(Team))
1036            diff3 = 1;
1037        // allow join more ppl if the other side has more players
1038        else if (otherIn > GetPlayersCountByTeam(Team))
1039            diff3 = otherIn - GetPlayersCountByTeam(Team);
1040
1041        // return the minimum of the 3 differences
1042
1043        // min of diff and diff 2
1044        diff = diff < diff2 ? diff : diff2;
1045
1046        // min of diff, diff2 and diff3
1047        return diff < diff3 ? diff : diff3 ;
1048    }
1049
1050    return 0;
[2]1051}
1052
1053bool BattleGround::HasFreeSlots() const
1054{
1055    return GetPlayersSize() < GetMaxPlayers();
1056}
1057
1058void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
1059{
1060    //this procedure is called from virtual function implemented in bg subclass
1061    std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
1062
1063    if(itr == m_PlayerScores.end())                         // player not found...
1064        return;
1065
1066    switch(type)
1067    {
1068        case SCORE_KILLING_BLOWS:                           // Killing blows
1069            itr->second->KillingBlows += value;
1070            break;
1071        case SCORE_DEATHS:                                  // Deaths
1072            itr->second->Deaths += value;
1073            break;
1074        case SCORE_HONORABLE_KILLS:                         // Honorable kills
1075            itr->second->HonorableKills += value;
1076            break;
1077        case SCORE_BONUS_HONOR:                             // Honor bonus
[9]1078            // do not add honor in arenas
1079            if(isBattleGround())
1080            {
1081                // reward honor instantly
1082                if(Source->RewardHonor(NULL, 1, value))
1083                    itr->second->BonusHonor += value;
1084            }
[2]1085            break;
1086            //used only in EY, but in MSG_PVP_LOG_DATA opcode
1087        case SCORE_DAMAGE_DONE:                             // Damage Done
1088            itr->second->DamageDone += value;
1089            break;
1090        case SCORE_HEALING_DONE:                            // Healing Done
1091            itr->second->HealingDone += value;
1092            break;
1093        default:
1094            sLog.outError("BattleGround: Unknown player score type %u", type);
1095            break;
1096    }
1097}
1098
1099void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid)
1100{
1101    m_ReviveQueue[npc_guid].push_back(player_guid);
1102
1103    Player *plr = objmgr.GetPlayer(player_guid);
1104    if(!plr)
1105        return;
1106
1107    plr->CastSpell(plr, SPELL_WAITING_FOR_RESURRECT, true);
1108    SpellEntry const *spellInfo = sSpellStore.LookupEntry( SPELL_WAITING_FOR_RESURRECT );
1109    if(spellInfo)
1110    {
1111        Aura *Aur = CreateAura(spellInfo, 0, NULL, plr);
1112        plr->AddAura(Aur);
1113    }
1114}
1115
1116void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid)
1117{
1118    for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
1119    {
1120        for(std::vector<uint64>::iterator itr2 =(itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
1121        {
1122            if(*itr2 == player_guid)
1123            {
1124                (itr->second).erase(itr2);
1125
1126                Player *plr = objmgr.GetPlayer(player_guid);
1127                if(!plr)
1128                    return;
1129
1130                plr->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
1131
1132                return;
1133            }
1134        }
1135    }
1136}
1137
1138bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime)
1139{
[9]1140    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1141    if(!map)
1142        return false;
1143
1144    // must be created this way, adding to godatamap would add it to the base map of the instance
1145    // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
1146    // so we must create it specific for this instance
1147    GameObject * go = new GameObject;
1148    if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, map,x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,1))
[2]1149    {
1150        sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);
[9]1151        sLog.outError("Cannot create gameobject template %u! BattleGround not created!", entry);
1152        delete go;
[2]1153        return false;
1154    }
[9]1155/*
1156    uint32 guid = go->GetGUIDLow();
[2]1157
[9]1158    // without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
1159    // 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
[2]1160    GameObjectData& data = objmgr.NewGOData(guid);
1161
1162    data.id             = entry;
1163    data.mapid          = GetMapId();
1164    data.posX           = x;
1165    data.posY           = y;
1166    data.posZ           = z;
1167    data.orientation    = o;
1168    data.rotation0      = rotation0;
1169    data.rotation1      = rotation1;
1170    data.rotation2      = rotation2;
1171    data.rotation3      = rotation3;
1172    data.spawntimesecs  = respawnTime;
[9]1173    data.spawnMask      = 1;
[2]1174    data.animprogress   = 100;
1175    data.go_state       = 1;
[9]1176*/
1177    // add to world, so it can be later looked up from HashMapHolder
1178    go->AddToWorld();
1179    m_BgObjects[type] = go->GetGUID();
[2]1180    return true;
1181}
1182
1183//some doors aren't despawned so we cannot handle their closing in gameobject::update()
1184//it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
1185void BattleGround::DoorClose(uint32 type)
1186{
1187    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1188    if(obj)
1189    {
1190        //if doors are open, close it
1191        if( obj->getLootState() == GO_ACTIVATED && !obj->GetGoState() )
1192        {
1193            //change state to allow door to be closed
1194            obj->SetLootState(GO_READY);
1195            obj->UseDoorOrButton(RESPAWN_ONE_DAY);
1196        }
1197    }
1198    else
1199    {
1200        sLog.outError("BattleGround: Door object not found (cannot close doors)");
1201    }
1202}
1203
1204void BattleGround::DoorOpen(uint32 type)
1205{
1206    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1207    if(obj)
1208    {
1209        //change state to be sure they will be opened
1210        obj->SetLootState(GO_READY);
1211        obj->UseDoorOrButton(RESPAWN_ONE_DAY);
1212    }
1213    else
1214    {
1215        sLog.outError("BattleGround: Door object not found! - doors will be closed.");
1216    }
1217}
1218
1219void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
1220{
[9]1221    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1222    if(!map)
1223        return;
[2]1224    if( respawntime == 0 )
1225    {
1226        GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1227        if(obj)
1228        {
1229            //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
1230            if( obj->getLootState() == GO_JUST_DEACTIVATED )
1231                obj->SetLootState(GO_READY);
[9]1232            obj->SetRespawnTime(0);
1233            map->Add(obj);
[2]1234        }
1235    }
1236    else
1237    {
1238        GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1239        if(obj)
1240        {
[9]1241            map->Add(obj);
[2]1242            obj->SetRespawnTime(respawntime);
1243            obj->SetLootState(GO_JUST_DEACTIVATED);
1244        }
1245    }
1246}
1247
[9]1248Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime)
[2]1249{
[9]1250    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1251    if(!map)
1252        return NULL;
[2]1253
1254    Creature* pCreature = new Creature;
1255    if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, entry, teamval))
1256    {
1257        sLog.outError("Can't create creature entry: %u",entry);
1258        delete pCreature;
1259        return NULL;
1260    }
1261
1262    pCreature->Relocate(x, y, z, o);
1263
1264    if(!pCreature->IsPositionValid())
1265    {
1266        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());
1267        return NULL;
1268    }
1269
1270    pCreature->AIM_Initialize();
1271
1272    //pCreature->SetDungeonDifficulty(0);
1273
1274    map->Add(pCreature);
1275    m_BgCreatures[type] = pCreature->GetGUID();
[9]1276
[2]1277    return  pCreature;
1278}
1279
1280bool BattleGround::DelCreature(uint32 type)
1281{
1282    Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1283    if(!cr)
1284    {
1285        sLog.outError("Can't find creature guid: %u",m_BgCreatures[type]);
1286        return false;
1287    }
1288    cr->CleanupsBeforeDelete();
1289    cr->AddObjectToRemoveList();
1290    m_BgCreatures[type] = 0;
1291    return true;
1292}
1293
1294bool BattleGround::DelObject(uint32 type)
1295{
1296    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1297    if(!obj)
1298    {
1299        sLog.outError("Can't find gobject guid: %u",m_BgObjects[type]);
1300        return false;
1301    }
1302    obj->SetRespawnTime(0);                                 // not save respawn time
1303    obj->Delete();
1304    m_BgObjects[type] = 0;
1305    return true;
1306}
1307
1308bool BattleGround::AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team)
1309{
1310    uint32 entry = 0;
1311
1312    if(team == ALLIANCE)
1313        entry = 13116;
1314    else
1315        entry = 13117;
1316
1317    Creature* pCreature = AddCreature(entry,type,team,x,y,z,o);
1318    if(!pCreature)
1319    {
1320        sLog.outError("Can't create Spirit guide. BattleGround not created!");
1321        this->EndNow();
1322        return false;
1323    }
1324
1325    pCreature->setDeathState(DEAD);
1326
1327    pCreature->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, pCreature->GetGUID());
1328    // aura
1329    pCreature->SetUInt32Value(UNIT_FIELD_AURA, SPELL_SPIRIT_HEAL_CHANNEL);
1330    pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
1331    pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
1332    pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
1333    // casting visual effect
1334    pCreature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_SPIRIT_HEAL_CHANNEL);
1335    // correct cast speed
1336    pCreature->SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
1337
1338    //pCreature->CastSpell(pCreature, SPELL_SPIRIT_HEAL_CHANNEL, true);
1339
1340    return true;
1341}
1342
1343void BattleGround::SendMessageToAll(char const* text)
1344{
1345    WorldPacket data;
1346    ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, text, NULL);
1347    SendPacketToAll(&data);
1348}
1349
1350void BattleGround::SendMessageToAll(int32 entry)
1351{
1352    char const* text = GetMangosString(entry);
1353    WorldPacket data;
1354    ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, text, NULL);
1355    SendPacketToAll(&data);
1356}
1357
1358void BattleGround::EndNow()
1359{
[9]1360    RemoveFromBGFreeSlotQueue();
[2]1361    SetStatus(STATUS_WAIT_LEAVE);
1362    SetEndTime(TIME_TO_AUTOREMOVE);
[9]1363    // inform invited players about the removal
1364    sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
[2]1365}
1366
1367// Battleground messages are localized using the dbc lang, they are not client language dependent
1368const char *BattleGround::GetMangosString(int32 entry)
1369{
1370    // FIXME: now we have different DBC locales and need localized message for each target client
1371    return objmgr.GetMangosStringForDBCLocale(entry);
1372}
1373
1374/*
1375important notice:
1376buffs aren't spawned/despawned when players captures anything
1377buffs are in their positions when battleground starts
1378*/
1379void BattleGround::HandleTriggerBuff(uint64 const& go_guid)
1380{
1381    GameObject *obj = HashMapHolder<GameObject>::Find(go_guid);
1382    if(!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned())
1383        return;
1384
1385    //change buff type, when buff is used:
1386    int32 index = m_BgObjects.size() - 1;
1387    while (index >= 0 && m_BgObjects[index] != go_guid)
1388        index--;
1389    if (index < 0)
1390    {
1391        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());
1392        return;
1393    }
1394
1395    //randomly select new buff
1396    uint8 buff = urand(0, 2);
1397    uint32 entry = obj->GetEntry();
1398    if( m_BuffChange && entry != Buff_Entries[buff] )
1399    {
1400        //despawn current buff
1401        SpawnBGObject(index, RESPAWN_ONE_DAY);
1402        //set index for new one
1403        for (uint8 currBuffTypeIndex = 0; currBuffTypeIndex < 3; ++currBuffTypeIndex)
1404            if( entry == Buff_Entries[currBuffTypeIndex] )
1405            {
1406                index -= currBuffTypeIndex;
1407                index += buff;
1408            }
1409    }
1410
1411    SpawnBGObject(index, BUFF_RESPAWN_TIME);
1412}
1413
1414void BattleGround::HandleKillPlayer( Player *player, Player *killer )
1415{
1416    //keep in mind that for arena this will have to be changed a bit
1417
1418    // add +1 deaths
1419    UpdatePlayerScore(player, SCORE_DEATHS, 1);
1420
1421    // add +1 kills to group and +1 killing_blows to killer
1422    if( killer )
1423    {
1424        UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);
1425        UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1);
1426
1427        for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1428        {
1429            Player *plr = objmgr.GetPlayer(itr->first);
1430
1431            if(!plr || plr == killer)
1432                continue;
1433
1434            if( plr->GetTeam() == killer->GetTeam() && plr->IsAtGroupRewardDistance(player) )
1435                UpdatePlayerScore(plr, SCORE_HONORABLE_KILLS, 1);
1436        }
1437    }
1438
1439    // to be able to remove insignia
1440    player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
1441}
[9]1442
1443// return the player's team based on battlegroundplayer info
1444// used in same faction arena matches mainly
1445uint32 BattleGround::GetPlayerTeam(uint64 guid)
1446{
1447    std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.find(guid);
1448    if(itr!=m_Players.end())
1449        return itr->second.Team;
1450    return 0;
1451}
1452
1453uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const
1454{
1455    int count = 0;
1456    for(std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1457    {
1458        if(itr->second.Team == Team)
1459        {
1460            Player * pl = objmgr.GetPlayer(itr->first);
1461            if(pl && pl->isAlive())
1462                ++count;
1463        }
1464    }
1465    return count;
1466}
Note: See TracBrowser for help on using the browser.