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

Revision 44, 49.6 kB (checked in by yumileroy, 17 years ago)

[svn] * Merge Temp dev SVN with Assembla.
* Changes include:

  • Implementation of w12x's Outdoor PvP and Game Event Systems.
  • Temporary removal of IRC Chat Bot (until infinite loop when disabled is fixed).
  • All mangos -> trinity (to convert your mangos_string table, please run mangos_string_to_trinity_string.sql).
  • Improved Config cleanup.
  • And many more changes.

Original author: Seline
Date: 2008-10-14 11:57:03-05:00

Line 
1/*
2 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
3 *
4 * Thanks to the original authors: MaNGOS <http://www.mangosproject.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}
90
91BattleGround::~BattleGround()
92{
93    // remove objects and creatures
94    // (this is done automatically in mapmanager update, when the instance is reset after the reset time)   
95    int size = m_BgCreatures.size();
96    for(int i = 0; i < size; ++i)
97    {
98        DelCreature(i);
99    }
100    size = m_BgObjects.size();
101    for(int i = 0; i < size; ++i)
102    {
103        DelObject(i);
104    }
105
106    // delete creature and go respawn times
107    WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'",GetInstanceID());
108    WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'",GetInstanceID());
109    // delete instance from db
110    CharacterDatabase.PExecute("DELETE FROM instance WHERE id = '%u'",GetInstanceID());
111    // remove from battlegrounds
112    sBattleGroundMgr.RemoveBattleGround(GetInstanceID());
113    // unload map
114    if(Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID()))
115        if(map->IsBattleGroundOrArena())
116            ((BattleGroundMap*)map)->SetUnload();
117    // remove from bg free slot queue
118    this->RemoveFromBGFreeSlotQueue();
119}
120
121void BattleGround::Update(time_t diff)
122{
123    if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize())
124        //BG is empty
125        return;
126
127    WorldPacket data;
128
129    if(GetRemovedPlayersSize())
130    {
131        for(std::map<uint64, uint8>::iterator itr = m_RemovedPlayers.begin(); itr != m_RemovedPlayers.end(); ++itr)
132        {
133            Player *plr = objmgr.GetPlayer(itr->first);
134            switch(itr->second)
135            {
136                //following code is handled by event:
137                /*case 0:
138                    sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].RemovePlayer(itr->first);
139                    //RemovePlayerFromQueue(itr->first);
140                    if(plr)
141                    {
142                        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0);
143                        plr->GetSession()->SendPacket(&data);
144                    }
145                    break;*/
146                case 1:                                     // currently in bg and was removed from bg
147                    if(plr)
148                        RemovePlayerAtLeave(itr->first, true, true);
149                    else
150                        RemovePlayerAtLeave(itr->first, false, false);
151                    break;
152                case 2:                                     // revive queue
153                    RemovePlayerFromResurrectQueue(itr->first);
154                    break;
155                default:
156                    sLog.outError("BattleGround: Unknown remove player case!");
157            }
158        }
159        m_RemovedPlayers.clear();
160    }
161
162    // this code isn't efficient and its idea isn't implemented yet
163    /* offline players are removed from battleground in worldsession::LogoutPlayer()
164    // remove offline players from bg after ~5 minutes
165    if(GetPlayersSize())
166    {
167        for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
168        {
169            Player *plr = objmgr.GetPlayer(itr->first);
170            itr->second.LastOnlineTime += diff;
171
172            if(plr)
173                itr->second.LastOnlineTime = 0;   // update last online time
174            else
175                if(itr->second.LastOnlineTime >= MAX_OFFLINE_TIME)                   // 5 minutes
176                    m_RemovedPlayers[itr->first] = 1;       // add to remove list (BG)
177        }
178    }*/
179
180    m_LastResurrectTime += diff;
181    if (m_LastResurrectTime >= RESURRECTION_INTERVAL)
182    {
183        if(GetReviveQueueSize())
184        {
185            for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
186            {
187                Creature *sh = NULL;
188                for(std::vector<uint64>::iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
189                {
190                    Player *plr = objmgr.GetPlayer(*itr2);
191                    if(!plr)
192                        continue;
193
194                    if (!sh)
195                    {
196                        sh = ObjectAccessor::GetCreature(*plr, itr->first);
197                        // only for visual effect
198                        if (sh)
199                            sh->CastSpell(sh, SPELL_SPIRIT_HEAL, true);   // Spirit Heal, effect 117
200                    }
201
202                    plr->CastSpell(plr, SPELL_RESURRECTION_VISUAL, true);   // Resurrection visual
203                    m_ResurrectQueue.push_back(*itr2);
204                }
205                (itr->second).clear();
206            }
207
208            m_ReviveQueue.clear();
209            m_LastResurrectTime = 0;
210        }
211        else
212            // queue is clear and time passed, just update last resurrection time
213            m_LastResurrectTime = 0;
214    }
215    else if (m_LastResurrectTime > 500)    // Resurrect players only half a second later, to see spirit heal effect on NPC
216    {
217        for(std::vector<uint64>::iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
218        {
219            Player *plr = objmgr.GetPlayer(*itr);
220            if(!plr)
221                continue;
222            plr->ResurrectPlayer(1.0f);
223            plr->CastSpell(plr, SPELL_SPIRIT_HEAL_MANA, true);
224            ObjectAccessor::Instance().ConvertCorpseForPlayer(*itr);
225        }
226        m_ResurrectQueue.clear();
227    }
228
229    // if less then minimum players are in on one side, then start premature finish timer
230    if(GetStatus() == STATUS_IN_PROGRESS && !isArena() && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam()))
231    {
232        if(!m_PrematureCountDown)
233        {
234            m_PrematureCountDown = true;
235            m_PrematureCountDownTimer = sBattleGroundMgr.GetPrematureFinishTime();
236            SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
237        }
238        else if(m_PrematureCountDownTimer < diff)
239        {
240            // time's up!
241            EndBattleGround(0); // noone wins
242            m_PrematureCountDown = false;
243        } 
244        else 
245        {
246            uint32 newtime = m_PrematureCountDownTimer - diff;
247            // announce every minute
248            if(m_PrematureCountDownTimer != sBattleGroundMgr.GetPrematureFinishTime() && newtime / 60000 != m_PrematureCountDownTimer / 60000)
249                SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
250            m_PrematureCountDownTimer = newtime;
251        }
252    }
253    else if (m_PrematureCountDown)
254        m_PrematureCountDown = false;
255
256    if(GetStatus() == STATUS_WAIT_LEAVE)
257    {
258        // remove all players from battleground after 2 minutes
259        m_EndTime += diff;
260        if(m_EndTime >= TIME_TO_AUTOREMOVE)                 // 2 minutes
261        {
262            for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
263            {
264                m_RemovedPlayers[itr->first] = 1;           // add to remove list (BG)
265            }
266            // do not change any battleground's private variables
267        }
268    }
269}
270
271void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O)
272{
273    uint8 idx = GetTeamIndexByTeamId(TeamID);
274    m_TeamStartLocX[idx] = X;
275    m_TeamStartLocY[idx] = Y;
276    m_TeamStartLocZ[idx] = Z;
277    m_TeamStartLocO[idx] = O;
278}
279
280void BattleGround::SendPacketToAll(WorldPacket *packet)
281{
282    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
283    {
284        Player *plr = objmgr.GetPlayer(itr->first);
285        if(plr)
286            plr->GetSession()->SendPacket(packet);
287        else
288            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
289    }
290}
291
292void BattleGround::SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *sender, bool self)
293{
294    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
295    {
296        Player *plr = objmgr.GetPlayer(itr->first);
297
298        if(!plr)
299        {
300            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
301            continue;
302        }
303
304        if(!self && sender == plr)
305            continue;
306
307        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
308
309        if(team == TeamID)
310            plr->GetSession()->SendPacket(packet);
311    }
312}
313
314void BattleGround::PlaySoundToAll(uint32 SoundID)
315{
316    WorldPacket data;
317    sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
318    SendPacketToAll(&data);
319}
320
321void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID)
322{
323    WorldPacket data;
324
325    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
326    {
327        Player *plr = objmgr.GetPlayer(itr->first);
328
329        if(!plr)
330        {
331            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
332            continue;
333        }
334
335        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
336
337        if(team == TeamID)
338        {
339            sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
340            plr->GetSession()->SendPacket(&data);
341        }
342    }
343}
344
345void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID)
346{
347    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
348    {
349        Player *plr = objmgr.GetPlayer(itr->first);
350
351        if(!plr)
352        {
353            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
354            continue;
355        }
356
357        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
358       
359        if(team == TeamID)
360            plr->CastSpell(plr, SpellID, true);
361    }
362}
363
364void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID)
365{
366    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
367    {
368        Player *plr = objmgr.GetPlayer(itr->first);
369
370        if(!plr)
371        {
372            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
373            continue;
374        }
375
376        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
377
378        if(team == TeamID)
379            UpdatePlayerScore(plr, SCORE_BONUS_HONOR, Honor);
380    }
381}
382
383void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID)
384{
385    FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
386
387    if(!factionEntry)
388        return;
389
390    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
391    {
392        Player *plr = objmgr.GetPlayer(itr->first);
393
394        if(!plr)
395        {
396            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
397            continue;
398        }
399
400        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
401
402        if(team == TeamID)
403            plr->ModifyFactionReputation(factionEntry, Reputation);
404    }
405}
406
407void BattleGround::UpdateWorldState(uint32 Field, uint32 Value)
408{
409    WorldPacket data;
410    sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
411    SendPacketToAll(&data);
412}
413
414void BattleGround::UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player *Source)
415{
416    WorldPacket data;
417    sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
418    Source->GetSession()->SendPacket(&data);
419}
420
421void BattleGround::EndBattleGround(uint32 winner)
422{
423    // battleground finished, remove from the running bg's list
424    this->RemoveFromBGFreeSlotQueue();
425
426    ArenaTeam * winner_arena_team = NULL;
427    ArenaTeam * loser_arena_team = NULL;
428    uint32 loser_rating = 0;
429    uint32 winner_rating = 0;
430    WorldPacket data;
431    Player *Source = NULL;
432    const char *winmsg = "";
433
434    if(winner == ALLIANCE)
435    {
436        if(isBattleGround())
437            winmsg = GetTrinityString(LANG_BG_A_WINS);
438        else
439            winmsg = GetTrinityString(LANG_ARENA_GOLD_WINS);
440
441        PlaySoundToAll(SOUND_ALLIANCE_WINS);                // alliance wins sound
442
443        SetWinner(WINNER_ALLIANCE);
444    }
445    else if(winner == HORDE)
446    {
447        if(isBattleGround())
448            winmsg = GetTrinityString(LANG_BG_H_WINS);
449        else
450            winmsg = GetTrinityString(LANG_ARENA_GREEN_WINS);
451
452        PlaySoundToAll(SOUND_HORDE_WINS);                   // horde wins sound
453
454        SetWinner(WINNER_HORDE);
455    }
456    else
457    {
458        SetWinner(3);
459    }
460
461    SetStatus(STATUS_WAIT_LEAVE);
462    m_EndTime = 0;
463
464    // arena rating calculation
465    if(isArena() && isRated())
466    {
467        if(winner == ALLIANCE)
468        {
469            winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
470            loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
471        }
472        else if(winner == HORDE)
473        {
474            winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
475            loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
476        }
477        if(winner_arena_team && loser_arena_team)
478        {
479            loser_rating = loser_arena_team->GetStats().rating;
480            winner_rating = winner_arena_team->GetStats().rating;
481            float winner_chance = winner_arena_team->GetChanceAgainst(loser_rating);
482            float loser_chance = loser_arena_team->GetChanceAgainst(winner_rating);
483            int32 winner_change = winner_arena_team->WonAgainstChance(winner_chance);
484            int32 loser_change = loser_arena_team->LostAgainstChance(loser_chance);
485            sLog.outDebug("--- %u ; %u ; %d ; %d ; %u ; %u ---",winner_rating,loser_rating,winner_chance,loser_chance,winner_change,loser_change);
486            if(winner == ALLIANCE)
487            {
488                SetArenaTeamRatingChangeForTeam(ALLIANCE, winner_change);
489                SetArenaTeamRatingChangeForTeam(HORDE, loser_change);
490            }
491            else
492            {
493                SetArenaTeamRatingChangeForTeam(HORDE, winner_change);
494                SetArenaTeamRatingChangeForTeam(ALLIANCE, loser_change);
495            }
496        }
497        else
498        {
499            SetArenaTeamRatingChangeForTeam(ALLIANCE, 0);
500            SetArenaTeamRatingChangeForTeam(HORDE, 0);
501        }
502    }
503
504    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
505    {
506        Player *plr = objmgr.GetPlayer(itr->first);
507        if(!plr)
508        {
509            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
510            continue;
511        }
512
513        // should remove spirit of redemption
514        if(plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
515            plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
516
517        if(!plr->isAlive())
518        {
519            plr->ResurrectPlayer(1.0f);
520            plr->SpawnCorpseBones();
521        }
522
523        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
524        if(!team) team = plr->GetTeam();
525
526        // per player calculation
527        if(isArena() && isRated() && winner_arena_team && loser_arena_team)
528        {
529            if(team == winner)
530                winner_arena_team->MemberWon(plr,loser_rating);
531            else
532                loser_arena_team->MemberLost(plr,winner_rating);
533        }
534
535        if(team == winner)
536        {
537            if(!Source)
538                Source = plr;
539            RewardMark(plr,ITEM_WINNER_COUNT);
540            UpdatePlayerScore(plr, SCORE_BONUS_HONOR, 20);
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",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",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}
Note: See TracBrowser for help on using the browser.