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

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

Line 
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"
27#include "ArenaTeam.h"
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;
51    m_InBGFreeSlotQueue = false;
52    m_SetDeleteThis     = false;
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
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
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;
84
85    m_PrematureCountDown = false;
86    m_PrematureCountDown = 0;
87}
88
89BattleGround::~BattleGround()
90{
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    }
103
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();
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
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
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
305        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
306
307        if(team == TeamID)
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
333        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
334
335        if(team == TeamID)
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
355        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
356       
357        if(team == TeamID)
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
374        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
375
376        if(team == TeamID)
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
398        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
399
400        if(team == TeamID)
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{
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;
428    WorldPacket data;
429    Player *Source = NULL;
430    const char *winmsg = "";
431
432    if(winner == ALLIANCE)
433    {
434        if(isBattleGround())
435            winmsg = GetMangosString(LANG_BG_A_WINS);
436        else
437            winmsg = GetMangosString(LANG_ARENA_GOLD_WINS);
438
439        PlaySoundToAll(SOUND_ALLIANCE_WINS);                // alliance wins sound
440
441        SetWinner(WINNER_ALLIANCE);
442    }
443    else if(winner == HORDE)
444    {
445        if(isBattleGround())
446            winmsg = GetMangosString(LANG_BG_H_WINS);
447        else
448            winmsg = GetMangosString(LANG_ARENA_GREEN_WINS);
449
450        PlaySoundToAll(SOUND_HORDE_WINS);                   // horde wins sound
451
452        SetWinner(WINNER_HORDE);
453    }
454    else
455    {
456        SetWinner(3);
457    }
458
459    SetStatus(STATUS_WAIT_LEAVE);
460    m_EndTime = 0;
461
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
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
511        // should remove spirit of redemption
512        if(plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
513            plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
514
515        if(!plr->isAlive())
516        {
517            plr->ResurrectPlayer(1.0f);
518            plr->SpawnCorpseBones();
519        }
520
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)
526        {
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        {
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
553        uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());
554        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
555        plr->GetSession()->SendPacket(&data);
556    }
557
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
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{
725    uint32 team = GetPlayerTeam(guid);
726    bool participant = false;
727    // Remove from lists/maps
728    std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.find(guid);
729    if(itr != m_Players.end())
730    {
731        UpdatePlayersCountByTeam(team, true);   // -1 player
732        m_Players.erase(itr);
733        // check if the player was a participant of the match, or only entered through gm command (goname)
734        participant = true;
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
748    // should remove spirit of redemption
749    if(plr && plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
750        plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
751
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
764        if(participant) // if the player was a match participant, remove auras, calc rating, update queue
765        {
766            if(!team) team = plr->GetTeam();
767
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)
775
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;
782
783                    (plr)->SetTemporaryUnsummonedPetNumber(0);
784                }
785
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            }
807
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            }
814
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))
826            {
827                if(!group->RemoveMember(guid, 0))               // group was disbanded
828                {
829                    SetBgRaid(team, NULL);
830                    delete group;
831                }
832            }
833
834            // Let others know
835            sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);
836            SendPacketToTeam(team, &data, plr, false);
837        }
838
839        // Do next only if found in battleground
840        plr->SetBattleGroundId(0);                          // We're not in BG.
841        // reset destination bg team
842        plr->SetBGTeam(0);
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
853    if(!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
854    {
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;
860    }
861
862    // a player exited the battleground, so there are free slots. add to queue
863    this->AddToBGFreeSlotQueue();
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);
875    SetArenaType(0);
876    SetRated(false);
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;
885    m_InBGFreeSlotQueue = false;
886
887    m_Players.clear();
888    m_PlayerScores.clear();
889
890    // reset BGSubclass (this cleans up creatures and gos as well)
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
916    UpdatePlayersCountByTeam(team, false);        // +1 player
917
918    WorldPacket data;
919    sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr);
920    SendPacketToTeam(team, &data, plr, false);
921
922    // add arena specific auras
923    if(isArena())
924    {
925        // remove auras first, only then reset spell cooldowns
926        // this is to prevent bugging amp. curse, combustion, etc. like spells
927        plr->RemoveArenaAuras();
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
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
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{
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    }
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{
983    // set to be able to re-add if needed
984    m_InBGFreeSlotQueue = false;
985    // uncomment this code when battlegrounds will work like instances
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        }
993    }
994}
995
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
999{
1000    //if BG is starting ... invite anyone:
1001    if (GetStatus() == STATUS_WAIT_JOIN)
1002        return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
1003    //if BG is already started .. do not allow to join too much players of one faction
1004    uint32 otherTeam;
1005    uint32 otherIn;
1006    if (Team == ALLIANCE)
1007    {
1008        otherTeam = GetInvitedCount(HORDE);
1009        otherIn = GetPlayersCountByTeam(HORDE);
1010    }
1011    else
1012    {
1013        otherTeam = GetInvitedCount(ALLIANCE);
1014        otherIn = GetPlayersCountByTeam(ALLIANCE);
1015    }
1016    if (GetStatus() == STATUS_IN_PROGRESS)
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);
1027
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;
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
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            }
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{
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))
1149    {
1150        sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);
1151        sLog.outError("Cannot create gameobject template %u! BattleGround not created!", entry);
1152        delete go;
1153        return false;
1154    }
1155/*
1156    uint32 guid = go->GetGUIDLow();
1157
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
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;
1173    data.spawnMask      = 1;
1174    data.animprogress   = 100;
1175    data.go_state       = 1;
1176*/
1177    // add to world, so it can be later looked up from HashMapHolder
1178    go->AddToWorld();
1179    m_BgObjects[type] = go->GetGUID();
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{
1221    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1222    if(!map)
1223        return;
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);
1232            obj->SetRespawnTime(0);
1233            map->Add(obj);
1234        }
1235    }
1236    else
1237    {
1238        GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1239        if(obj)
1240        {
1241            map->Add(obj);
1242            obj->SetRespawnTime(respawntime);
1243            obj->SetLootState(GO_JUST_DEACTIVATED);
1244        }
1245    }
1246}
1247
1248Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime)
1249{
1250    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1251    if(!map)
1252        return NULL;
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();
1276
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{
1360    RemoveFromBGFreeSlotQueue();
1361    SetStatus(STATUS_WAIT_LEAVE);
1362    SetEndTime(TIME_TO_AUTOREMOVE);
1363    // inform invited players about the removal
1364    sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
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}
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.