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

Revision 230, 49.7 kB (checked in by yumileroy, 17 years ago)

[svn] *** Source: MaNGOS ***
* Implement localization of creature/gameobject name that say/yell. Author: evilstar (rewrited by: Vladimir)
* Fix auth login queue. Author: Derex
* Allowed switching INVTYPE_HOLDABLE items during combat, used correct spells for triggering global cooldown at weapon switch. Author: mobel/simak
* Fixed some format arg type/value pairs. Other warnings. Author: Vladimir
* [238_world.sql] Allow have team dependent graveyards at entrance map for instances. Author: Vladimir

NOTE:
Entrance map graveyards selected by same way as local (by distance from entrance) Until DB support will work in old way base at current DB data.

Original author: visagalis
Date: 2008-11-14 17:03:03-06:00

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