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

Revision 283, 51.5 kB (checked in by yumileroy, 17 years ago)

*Alterac Valley. By Bogie and Balrok. Note: some core contents are modified. Will fix them later. Some sql are disabled because of possible conflict with offical DB. Use them at your own risk.

Original author: megamage
Date: 2008-11-21 19:45:49-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::YellToAll(Creature* creature, const char* text, uint32 language)
366{
367    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
368    {
369        WorldPacket data(SMSG_MESSAGECHAT, 200);
370        Player *plr = objmgr.GetPlayer(itr->first);
371        if(!plr)
372        {
373            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
374            continue;
375        }
376        creature->BuildMonsterChat(&data,CHAT_MSG_MONSTER_YELL,text,language,creature->GetName(),itr->first);
377        plr->GetSession()->SendPacket(&data);
378    }
379}
380
381
382void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID)
383{
384    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
385    {
386        Player *plr = objmgr.GetPlayer(itr->first);
387
388        if(!plr)
389        {
390            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
391            continue;
392        }
393
394        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
395
396        if(team == TeamID)
397            UpdatePlayerScore(plr, SCORE_BONUS_HONOR, Honor);
398    }
399}
400
401void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID)
402{
403    FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
404
405    if(!factionEntry)
406        return;
407
408    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
409    {
410        Player *plr = objmgr.GetPlayer(itr->first);
411
412        if(!plr)
413        {
414            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
415            continue;
416        }
417
418        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
419
420        if(team == TeamID)
421            plr->ModifyFactionReputation(factionEntry, Reputation);
422    }
423}
424
425void BattleGround::UpdateWorldState(uint32 Field, uint32 Value)
426{
427    WorldPacket data;
428    sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
429    SendPacketToAll(&data);
430}
431
432void BattleGround::UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player *Source)
433{
434    WorldPacket data;
435    sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
436    Source->GetSession()->SendPacket(&data);
437}
438
439void BattleGround::EndBattleGround(uint32 winner)
440{
441    // battleground finished, remove from the running bg's list
442    this->RemoveFromBGFreeSlotQueue();
443
444    ArenaTeam * winner_arena_team = NULL;
445    ArenaTeam * loser_arena_team = NULL;
446    uint32 loser_rating = 0;
447    uint32 winner_rating = 0;
448    WorldPacket data;
449    Player *Source = NULL;
450    const char *winmsg = "";
451
452    if(winner == ALLIANCE)
453    {
454        if(isBattleGround())
455            winmsg = GetTrinityString(LANG_BG_A_WINS);
456        else
457            winmsg = GetTrinityString(LANG_ARENA_GOLD_WINS);
458
459        PlaySoundToAll(SOUND_ALLIANCE_WINS);                // alliance wins sound
460
461        SetWinner(WINNER_ALLIANCE);
462    }
463    else if(winner == HORDE)
464    {
465        if(isBattleGround())
466            winmsg = GetTrinityString(LANG_BG_H_WINS);
467        else
468            winmsg = GetTrinityString(LANG_ARENA_GREEN_WINS);
469
470        PlaySoundToAll(SOUND_HORDE_WINS);                   // horde wins sound
471
472        SetWinner(WINNER_HORDE);
473    }
474    else
475    {
476        SetWinner(3);
477    }
478
479    SetStatus(STATUS_WAIT_LEAVE);
480    m_EndTime = 0;
481
482    // arena rating calculation
483    if(isArena() && isRated())
484    {
485        if(winner == ALLIANCE)
486        {
487            winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
488            loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
489        }
490        else if(winner == HORDE)
491        {
492            winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
493            loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
494        }
495        if(winner_arena_team && loser_arena_team)
496        {
497            loser_rating = loser_arena_team->GetStats().rating;
498            winner_rating = winner_arena_team->GetStats().rating;
499            float winner_chance = winner_arena_team->GetChanceAgainst(loser_rating);
500            float loser_chance = loser_arena_team->GetChanceAgainst(winner_rating);
501            int32 winner_change = winner_arena_team->WonAgainstChance(winner_chance);
502            int32 loser_change = loser_arena_team->LostAgainstChance(loser_chance);
503            sLog.outDebug("--- %u ; %u ; %d ; %d ; %u ; %u ---",winner_rating,loser_rating,winner_chance,loser_chance,winner_change,loser_change);
504            if(winner == ALLIANCE)
505            {
506                SetArenaTeamRatingChangeForTeam(ALLIANCE, winner_change);
507                SetArenaTeamRatingChangeForTeam(HORDE, loser_change);
508            }
509            else
510            {
511                SetArenaTeamRatingChangeForTeam(HORDE, winner_change);
512                SetArenaTeamRatingChangeForTeam(ALLIANCE, loser_change);
513            }
514        }
515        else
516        {
517            SetArenaTeamRatingChangeForTeam(ALLIANCE, 0);
518            SetArenaTeamRatingChangeForTeam(HORDE, 0);
519        }
520    }
521
522    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
523    {
524        Player *plr = objmgr.GetPlayer(itr->first);
525        if(!plr)
526        {
527            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
528            continue;
529        }
530
531        // should remove spirit of redemption
532        if(plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
533            plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
534
535        if(!plr->isAlive())
536        {
537            plr->ResurrectPlayer(1.0f);
538            plr->SpawnCorpseBones();
539        }
540
541        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
542        if(!team) team = plr->GetTeam();
543
544        // per player calculation
545        if(isArena() && isRated() && winner_arena_team && loser_arena_team)
546        {
547            if(team == winner)
548                winner_arena_team->MemberWon(plr,loser_rating);
549            else
550                loser_arena_team->MemberLost(plr,winner_rating);
551        }
552
553        if(team == winner)
554        {
555            if(!Source)
556                Source = plr;
557            RewardMark(plr,ITEM_WINNER_COUNT);
558            RewardQuest(plr);
559        }
560        else
561        {
562            RewardMark(plr,ITEM_LOSER_COUNT);
563        }
564
565        plr->CombatStopWithPets(true);
566
567        BlockMovement(plr);
568
569        sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
570        plr->GetSession()->SendPacket(&data);
571
572        uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());
573        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
574        plr->GetSession()->SendPacket(&data);
575    }
576
577    if(isArena() && isRated() && winner_arena_team && loser_arena_team)
578    {
579        // update arena points only after increasing the player's match count!
580        winner_arena_team->UpdateArenaPointsHelper();
581        loser_arena_team->UpdateArenaPointsHelper();
582        // save the stat changes
583        winner_arena_team->SaveToDB();
584        loser_arena_team->SaveToDB();
585        // send updated arena team stats to players
586        // this way all arena team members will get notified, not only the ones who participated in this match
587        winner_arena_team->NotifyStatsChanged();
588        loser_arena_team->NotifyStatsChanged();
589    }
590
591    // inform invited players about the removal
592    sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
593
594    if(Source)
595    {
596        ChatHandler(Source).FillMessageData(&data, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, Source->GetGUID(), winmsg);
597        SendPacketToAll(&data);
598    }
599}
600
601uint32 BattleGround::GetBattlemasterEntry() const
602{
603    switch(GetTypeID())
604    {
605        case BATTLEGROUND_AV: return 15972;
606        case BATTLEGROUND_WS: return 14623;
607        case BATTLEGROUND_AB: return 14879;
608        case BATTLEGROUND_EY: return 22516;
609        case BATTLEGROUND_NA: return 20200;
610        default:              return 0;
611    }
612}
613
614void BattleGround::RewardMark(Player *plr,uint32 count)
615{
616    // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
617    if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
618        return;
619
620    BattleGroundMarks mark;
621    bool IsSpell;
622    switch(GetTypeID())
623    {
624        case BATTLEGROUND_AV:
625            IsSpell = true;
626            if(count == ITEM_WINNER_COUNT)
627                mark = SPELL_AV_MARK_WINNER;
628            else
629                mark = SPELL_AV_MARK_LOSER;
630            break;
631        case BATTLEGROUND_WS:
632            IsSpell = true;
633            if(count == ITEM_WINNER_COUNT)
634                mark = SPELL_WS_MARK_WINNER;
635            else
636                mark = SPELL_WS_MARK_LOSER;
637            break;
638        case BATTLEGROUND_AB:
639            IsSpell = true;
640            if(count == ITEM_WINNER_COUNT)
641                mark = SPELL_AB_MARK_WINNER;
642            else
643                mark = SPELL_AB_MARK_LOSER;
644            break;
645        case BATTLEGROUND_EY:
646            IsSpell = false;
647            mark = ITEM_EY_MARK_OF_HONOR;
648            break;
649        default:
650            return;
651    }
652
653    if(IsSpell)
654        plr->CastSpell(plr, mark, true);
655    else if ( objmgr.GetItemPrototype( mark ) )
656    {
657        ItemPosCountVec dest;
658        uint32 no_space_count = 0;
659        uint8 msg = plr->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, mark, count, &no_space_count );
660        if( msg != EQUIP_ERR_OK )                       // convert to possible store amount
661            count -= no_space_count;
662
663        if( count != 0 && !dest.empty())                // can add some
664            if(Item* item = plr->StoreNewItem( dest, mark, true, 0))
665                plr->SendNewItem(item,count,false,true);
666
667        if(no_space_count > 0)
668            SendRewardMarkByMail(plr,mark,no_space_count);
669    }
670}
671
672void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count)
673{
674    uint32 bmEntry = GetBattlemasterEntry();
675    if(!bmEntry)
676        return;
677
678    ItemPrototype const* markProto = objmgr.GetItemPrototype(mark);
679    if(!markProto)
680        return;
681
682    if(Item* markItem = Item::CreateItem(mark,count,plr))
683    {
684        // save new item before send
685        markItem->SaveToDB();                               // save for prevent lost at next mail load, if send fail then item will deleted
686
687        // item
688        MailItemsInfo mi;
689        mi.AddItem(markItem->GetGUIDLow(), markItem->GetEntry(), markItem);
690
691        // subject: item name
692        std::string subject = markProto->Name1;
693        int loc_idx = plr->GetSession()->GetSessionDbLocaleIndex();
694        if ( loc_idx >= 0 )
695            if(ItemLocale const *il = objmgr.GetItemLocale(markProto->ItemId))
696                if (il->Name.size() > loc_idx && !il->Name[loc_idx].empty())
697                    subject = il->Name[loc_idx];
698
699        // text
700        std::string textFormat = plr->GetSession()->GetTrinityString(LANG_BG_MARK_BY_MAIL);
701        char textBuf[300];
702        snprintf(textBuf,300,textFormat.c_str(),GetName(),GetName());
703        uint32 itemTextId = objmgr.CreateItemText( textBuf );
704
705        WorldSession::SendMailTo(plr, MAIL_CREATURE, MAIL_STATIONERY_NORMAL, bmEntry, plr->GetGUIDLow(), subject, itemTextId , &mi, 0, 0, MAIL_CHECK_MASK_NONE);
706    }
707}
708
709void BattleGround::RewardQuest(Player *plr)
710{
711    // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
712    if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
713        return;
714
715    uint32 quest;
716    switch(GetTypeID())
717    {
718        case BATTLEGROUND_AV:
719            quest = SPELL_AV_QUEST_REWARD;
720            break;
721        case BATTLEGROUND_WS:
722            quest = SPELL_WS_QUEST_REWARD;
723            break;
724        case BATTLEGROUND_AB:
725            quest = SPELL_AB_QUEST_REWARD;
726            break;
727        case BATTLEGROUND_EY:
728            quest = SPELL_EY_QUEST_REWARD;
729            break;
730        default:
731            return;
732    }
733
734    plr->CastSpell(plr, quest, true);
735}
736
737void BattleGround::BlockMovement(Player *plr)
738{
739    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()
740}
741
742void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket)
743{
744    uint32 team = GetPlayerTeam(guid);
745    bool participant = false;
746    // Remove from lists/maps
747    std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.find(guid);
748    if(itr != m_Players.end())
749    {
750        UpdatePlayersCountByTeam(team, true);   // -1 player
751        m_Players.erase(itr);
752        // check if the player was a participant of the match, or only entered through gm command (goname)
753        participant = true;
754    }
755
756    std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid);
757    if(itr2 != m_PlayerScores.end())
758    {
759        delete itr2->second;                                // delete player's score
760        m_PlayerScores.erase(itr2);
761    }
762
763    RemovePlayerFromResurrectQueue(guid);
764
765    Player *plr = objmgr.GetPlayer(guid);
766
767    // should remove spirit of redemption
768    if(plr && plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
769        plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
770
771    if(plr && !plr->isAlive())                              // resurrect on exit
772    {
773        plr->ResurrectPlayer(1.0f);
774        plr->SpawnCorpseBones();
775    }
776
777    RemovePlayer(plr, guid);                                // BG subclass specific code
778
779    if(plr)
780    {
781        plr->ClearAfkReports();
782
783        if(participant) // if the player was a match participant, remove auras, calc rating, update queue
784        {
785            if(!team) team = plr->GetTeam();
786
787            uint32 bgTypeId = GetTypeID();
788            uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());
789            // if arena, remove the specific arena auras
790            if(isArena())
791            {
792                plr->RemoveArenaAuras(true);    // removes debuffs / dots etc., we don't want the player to die after porting out
793                bgTypeId=BATTLEGROUND_AA;       // set the bg type to all arenas (it will be used for queue refreshing)
794
795                // summon old pet if there was one and there isn't a current pet
796                if(!plr->GetPet() && plr->GetTemporaryUnsummonedPetNumber())
797                {
798                    Pet* NewPet = new Pet;
799                    if(!NewPet->LoadPetFromDB(plr, 0, (plr)->GetTemporaryUnsummonedPetNumber(), true))
800                        delete NewPet;
801
802                    (plr)->SetTemporaryUnsummonedPetNumber(0);
803                }
804
805                if(isRated() && GetStatus() == STATUS_IN_PROGRESS)
806                {
807                    //left a rated match while the encounter was in progress, consider as loser
808                    ArenaTeam * winner_arena_team = 0;
809                    ArenaTeam * loser_arena_team = 0;
810                    if(team == HORDE)
811                    {
812                        winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
813                        loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
814                    }
815                    else
816                    {
817                        winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
818                        loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
819                    }
820                    if(winner_arena_team && loser_arena_team)
821                    {
822                        loser_arena_team->MemberLost(plr,winner_arena_team->GetRating());
823                    }
824                }
825            }
826
827            WorldPacket data;
828            if(SendPacket)
829            {
830                sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, team, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0);
831                plr->GetSession()->SendPacket(&data);
832            }
833
834            // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
835            plr->RemoveBattleGroundQueueId(bgQueueTypeId);
836
837            DecreaseInvitedCount(team);
838            //we should update battleground queue, but only if bg isn't ending
839            if (GetQueueType() < MAX_BATTLEGROUND_QUEUES)
840                sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueType());
841
842            Group * group = plr->GetGroup();
843            // remove from raid group if exist
844            if(group && group == GetBgRaid(team))
845            {
846                if(!group->RemoveMember(guid, 0))               // group was disbanded
847                {
848                    SetBgRaid(team, NULL);
849                    delete group;
850                }
851            }
852
853            // Let others know
854            sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);
855            SendPacketToTeam(team, &data, plr, false);
856        }
857
858        // Do next only if found in battleground
859        plr->SetBattleGroundId(0);                          // We're not in BG.
860        // reset destination bg team
861        plr->SetBGTeam(0);
862
863        if(Transport)
864        {
865            plr->TeleportTo(plr->GetBattleGroundEntryPointMap(), plr->GetBattleGroundEntryPointX(), plr->GetBattleGroundEntryPointY(), plr->GetBattleGroundEntryPointZ(), plr->GetBattleGroundEntryPointO());
866        }
867
868        // Log
869        sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName());
870    }
871
872    if(!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
873    {
874        // if no players left AND no invitees left, set this bg to delete in next update
875        // direct deletion could cause crashes
876        m_SetDeleteThis = true;
877        // return to prevent addition to freeslotqueue
878        return;
879    }
880
881    // a player exited the battleground, so there are free slots. add to queue
882    this->AddToBGFreeSlotQueue();
883}
884
885// this method is called when no players remains in battleground
886void BattleGround::Reset()
887{
888    SetQueueType(MAX_BATTLEGROUND_QUEUES);
889    SetWinner(WINNER_NONE);
890    SetStatus(STATUS_WAIT_QUEUE);
891    SetStartTime(0);
892    SetEndTime(0);
893    SetLastResurrectTime(0);
894    SetArenaType(0);
895    SetRated(false);
896
897    m_Events = 0;
898
899    if (m_InvitedAlliance > 0 || m_InvitedHorde > 0)
900        sLog.outError("BattleGround system ERROR: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance, m_InvitedHorde);
901
902    m_InvitedAlliance = 0;
903    m_InvitedHorde = 0;
904    m_InBGFreeSlotQueue = false;
905
906    m_Players.clear();
907    m_PlayerScores.clear();
908
909    // reset BGSubclass (this cleans up creatures and gos as well)
910    this->ResetBGSubclass();
911}
912
913void BattleGround::StartBattleGround()
914{
915    ///this method should spawn spirit guides and so on
916    SetStartTime(0);
917
918    SetLastResurrectTime(0);
919}
920
921void BattleGround::AddPlayer(Player *plr)
922{
923    // score struct must be created in inherited class
924
925    uint64 guid = plr->GetGUID();
926    uint32 team = plr->GetBGTeam();
927
928    BattleGroundPlayer bp;
929    bp.LastOnlineTime = 0;
930    bp.Team = team;
931
932    // Add to list/maps
933    m_Players[guid] = bp;
934
935    UpdatePlayersCountByTeam(team, false);        // +1 player
936
937    WorldPacket data;
938    sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr);
939    SendPacketToTeam(team, &data, plr, false);
940
941    // add arena specific auras
942    if(isArena())
943    {
944        // remove auras first, only then reset spell cooldowns
945        // this is to prevent bugging amp. curse, combustion, etc. like spells
946        plr->RemoveArenaAuras();
947        plr->RemoveArenaSpellCooldowns();
948        plr->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT);
949        if(team == ALLIANCE && plr->GetTeam() == ALLIANCE)
950            plr->CastSpell(plr,SPELL_ALLIANCE_GOLD_FLAG,true);
951        else if(team == HORDE && plr->GetTeam() == ALLIANCE)
952            plr->CastSpell(plr,SPELL_ALLIANCE_GREEN_FLAG,true);
953        else if(team == ALLIANCE && plr->GetTeam() == HORDE)
954            plr->CastSpell(plr,SPELL_HORDE_GOLD_FLAG,true);
955        else
956            plr->CastSpell(plr,SPELL_HORDE_GREEN_FLAG,true);
957        plr->DestroyConjuredItems(true);
958
959        Pet* pet = plr->GetPet();
960        if(pet)
961        {
962            if(pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET)
963            {
964                (plr)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber());
965                (plr)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));
966            }
967            (plr)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);
968        }
969
970        if(GetStatus() == STATUS_WAIT_JOIN)                 // not started yet
971        {
972            plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);
973
974            plr->SetHealth(plr->GetMaxHealth());
975            plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA));
976        }
977    }
978    else
979    {
980        if(GetStatus() == STATUS_WAIT_JOIN)                 // not started yet
981            plr->CastSpell(plr, SPELL_PREPARATION, true);   // reduces all mana cost of spells.
982    }
983
984    // Log
985    sLog.outDetail("BATTLEGROUND: Player %s joined the battle.", plr->GetName());
986}
987
988/* This method should be called only once ... it adds pointer to queue */
989void BattleGround::AddToBGFreeSlotQueue()
990{
991    // make sure to add only once
992    if(!m_InBGFreeSlotQueue)
993    {
994        sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);
995        m_InBGFreeSlotQueue = true;
996    }
997}
998
999/* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
1000void BattleGround::RemoveFromBGFreeSlotQueue()
1001{
1002    // set to be able to re-add if needed
1003    m_InBGFreeSlotQueue = false;
1004    // uncomment this code when battlegrounds will work like instances
1005    for (std::deque<BattleGround*>::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)
1006    {
1007        if ((*itr)->GetInstanceID() == m_InstanceID)
1008        {
1009            sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr);
1010            return;
1011        }
1012    }
1013}
1014
1015// get the number of free slots for team
1016// works in similar way that HasFreeSlotsForTeam did, but this is needed for join as group
1017uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const
1018{
1019    //if BG is starting ... invite anyone:
1020    if (GetStatus() == STATUS_WAIT_JOIN)
1021        return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
1022    //if BG is already started .. do not allow to join too much players of one faction
1023    uint32 otherTeam;
1024    uint32 otherIn;
1025    if (Team == ALLIANCE)
1026    {
1027        otherTeam = GetInvitedCount(HORDE);
1028        otherIn = GetPlayersCountByTeam(HORDE);
1029    }
1030    else
1031    {
1032        otherTeam = GetInvitedCount(ALLIANCE);
1033        otherIn = GetPlayersCountByTeam(ALLIANCE);
1034    }
1035    if (GetStatus() == STATUS_IN_PROGRESS)
1036    {
1037        // difference based on ppl invited (not necessarily entered battle)
1038        // default: allow 0
1039        uint32 diff = 0;
1040        // allow join one person if the sides are equal (to fill up bg to minplayersperteam)
1041        if (otherTeam == GetInvitedCount(Team)) 
1042            diff = 1;
1043        // allow join more ppl if the other side has more players
1044        else if(otherTeam > GetInvitedCount(Team))
1045            diff = otherTeam - GetInvitedCount(Team);
1046
1047        // difference based on max players per team (don't allow inviting more)
1048        uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
1049
1050        // difference based on players who already entered
1051        // default: allow 0
1052        uint32 diff3 = 0;
1053        // allow join one person if the sides are equal (to fill up bg minplayersperteam)
1054        if (otherIn == GetPlayersCountByTeam(Team))
1055            diff3 = 1;
1056        // allow join more ppl if the other side has more players
1057        else if (otherIn > GetPlayersCountByTeam(Team))
1058            diff3 = otherIn - GetPlayersCountByTeam(Team);
1059
1060        // return the minimum of the 3 differences
1061
1062        // min of diff and diff 2
1063        diff = diff < diff2 ? diff : diff2;
1064
1065        // min of diff, diff2 and diff3
1066        return diff < diff3 ? diff : diff3 ;
1067    }
1068
1069    return 0;
1070}
1071
1072bool BattleGround::HasFreeSlots() const
1073{
1074    return GetPlayersSize() < GetMaxPlayers();
1075}
1076
1077void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
1078{
1079    //this procedure is called from virtual function implemented in bg subclass
1080    std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
1081
1082    if(itr == m_PlayerScores.end())                         // player not found...
1083        return;
1084
1085    switch(type)
1086    {
1087        case SCORE_KILLING_BLOWS:                           // Killing blows
1088            itr->second->KillingBlows += value;
1089            break;
1090        case SCORE_DEATHS:                                  // Deaths
1091            itr->second->Deaths += value;
1092            break;
1093        case SCORE_HONORABLE_KILLS:                         // Honorable kills
1094            itr->second->HonorableKills += value;
1095            break;
1096        case SCORE_BONUS_HONOR:                             // Honor bonus
1097            // do not add honor in arenas
1098            if(isBattleGround())
1099            {
1100                // reward honor instantly
1101                if(Source->RewardHonor(NULL, 1, value))
1102                    itr->second->BonusHonor += value;
1103            }
1104            break;
1105            //used only in EY, but in MSG_PVP_LOG_DATA opcode
1106        case SCORE_DAMAGE_DONE:                             // Damage Done
1107            itr->second->DamageDone += value;
1108            break;
1109        case SCORE_HEALING_DONE:                            // Healing Done
1110            itr->second->HealingDone += value;
1111            break;
1112        default:
1113            sLog.outError("BattleGround: Unknown player score type %u", type);
1114            break;
1115    }
1116}
1117
1118void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid)
1119{
1120    m_ReviveQueue[npc_guid].push_back(player_guid);
1121
1122    Player *plr = objmgr.GetPlayer(player_guid);
1123    if(!plr)
1124        return;
1125
1126    plr->CastSpell(plr, SPELL_WAITING_FOR_RESURRECT, true);
1127    SpellEntry const *spellInfo = sSpellStore.LookupEntry( SPELL_WAITING_FOR_RESURRECT );
1128    if(spellInfo)
1129    {
1130        Aura *Aur = CreateAura(spellInfo, 0, NULL, plr);
1131        plr->AddAura(Aur);
1132    }
1133}
1134
1135void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid)
1136{
1137    for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
1138    {
1139        for(std::vector<uint64>::iterator itr2 =(itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
1140        {
1141            if(*itr2 == player_guid)
1142            {
1143                (itr->second).erase(itr2);
1144
1145                Player *plr = objmgr.GetPlayer(player_guid);
1146                if(!plr)
1147                    return;
1148
1149                plr->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
1150
1151                return;
1152            }
1153        }
1154    }
1155}
1156
1157bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime)
1158{
1159    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1160    if(!map)
1161        return false;
1162
1163    // must be created this way, adding to godatamap would add it to the base map of the instance
1164    // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
1165    // so we must create it specific for this instance
1166    GameObject * go = new GameObject;
1167    if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, map,x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,1))
1168    {
1169        sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);
1170        sLog.outError("Cannot create gameobject template %u! BattleGround not created!", entry);
1171        delete go;
1172        return false;
1173    }
1174/*
1175    uint32 guid = go->GetGUIDLow();
1176
1177    // without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
1178    // 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
1179    GameObjectData& data = objmgr.NewGOData(guid);
1180
1181    data.id             = entry;
1182    data.mapid          = GetMapId();
1183    data.posX           = x;
1184    data.posY           = y;
1185    data.posZ           = z;
1186    data.orientation    = o;
1187    data.rotation0      = rotation0;
1188    data.rotation1      = rotation1;
1189    data.rotation2      = rotation2;
1190    data.rotation3      = rotation3;
1191    data.spawntimesecs  = respawnTime;
1192    data.spawnMask      = 1;
1193    data.animprogress   = 100;
1194    data.go_state       = 1;
1195*/
1196    // add to world, so it can be later looked up from HashMapHolder
1197    go->AddToWorld();
1198    m_BgObjects[type] = go->GetGUID();
1199    return true;
1200}
1201
1202//some doors aren't despawned so we cannot handle their closing in gameobject::update()
1203//it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
1204void BattleGround::DoorClose(uint32 type)
1205{
1206    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1207    if(obj)
1208    {
1209        //if doors are open, close it
1210        if( obj->getLootState() == GO_ACTIVATED && !obj->GetGoState() )
1211        {
1212            //change state to allow door to be closed
1213            obj->SetLootState(GO_READY);
1214            obj->UseDoorOrButton(RESPAWN_ONE_DAY);
1215        }
1216    }
1217    else
1218    {
1219        sLog.outError("BattleGround: Door object not found (cannot close doors)");
1220    }
1221}
1222
1223void BattleGround::DoorOpen(uint32 type)
1224{
1225    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1226    if(obj)
1227    {
1228        //change state to be sure they will be opened
1229        obj->SetLootState(GO_READY);
1230        obj->UseDoorOrButton(RESPAWN_ONE_DAY);
1231    }
1232    else
1233    {
1234        sLog.outError("BattleGround: Door object not found! - doors will be closed.");
1235    }
1236}
1237
1238GameObject* BattleGround::GetBGObject(uint32 type)
1239{
1240    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1241    if(!obj)
1242        sLog.outError("couldn't get gameobject %i",type);
1243    return obj;
1244}
1245
1246Creature* BattleGround::GetBGCreature(uint32 type)
1247{
1248    Creature *creature = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1249    if(!creature)
1250        sLog.outError("couldn't get creature %i",type);
1251    return creature;
1252}
1253
1254void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
1255{
1256    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1257    if(!map)
1258        return;
1259    if( respawntime == 0 )
1260    {
1261        GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1262        if(obj)
1263        {
1264            //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
1265            if( obj->getLootState() == GO_JUST_DEACTIVATED )
1266                obj->SetLootState(GO_READY);
1267            obj->SetRespawnTime(0);
1268            map->Add(obj);
1269        }
1270    }
1271    else
1272    {
1273        GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1274        if(obj)
1275        {
1276            map->Add(obj);
1277            obj->SetRespawnTime(respawntime);
1278            obj->SetLootState(GO_JUST_DEACTIVATED);
1279        }
1280    }
1281}
1282
1283Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime)
1284{
1285    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1286    if(!map)
1287        return NULL;
1288
1289    Creature* pCreature = new Creature;
1290    if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, entry, teamval))
1291    {
1292        sLog.outError("Can't create creature entry: %u",entry);
1293        delete pCreature;
1294        return NULL;
1295    }
1296
1297    pCreature->Relocate(x, y, z, o);
1298
1299    if(!pCreature->IsPositionValid())
1300    {
1301        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());
1302        return NULL;
1303    }
1304
1305    CreatureData &data = objmgr.NewOrExistCreatureData(pCreature->GetDBTableGUIDLow());
1306   
1307    data.id             = entry;
1308//    data.mapid          = GetMapId();
1309    data.posX           = x;
1310    data.posY           = y;
1311    data.posZ           = z;
1312    data.orientation    = o;
1313    data.spawndist      = 15;
1314
1315    pCreature->AIM_Initialize();
1316
1317    //pCreature->SetDungeonDifficulty(0);
1318
1319    map->Add(pCreature);
1320    m_BgCreatures[type] = pCreature->GetGUID();
1321
1322    return  pCreature;
1323}
1324
1325bool BattleGround::DelCreature(uint32 type)
1326{
1327    Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1328    if(!cr)
1329    {
1330        sLog.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures[type]));
1331        return false;
1332    }
1333    //TODO: only delete creature after not in combat
1334    cr->CleanupsBeforeDelete();
1335    cr->AddObjectToRemoveList();
1336    m_BgCreatures[type] = 0;
1337    return true;
1338}
1339
1340bool BattleGround::DelObject(uint32 type)
1341{
1342    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1343    if(!obj)
1344    {
1345        sLog.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects[type]));
1346        return false;
1347    }
1348    obj->SetRespawnTime(0);                                 // not save respawn time
1349    obj->Delete();
1350    m_BgObjects[type] = 0;
1351    return true;
1352}
1353
1354bool BattleGround::AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team)
1355{
1356    uint32 entry = 0;
1357
1358    if(team == ALLIANCE)
1359        entry = 13116;
1360    else
1361        entry = 13117;
1362
1363    Creature* pCreature = AddCreature(entry,type,team,x,y,z,o);
1364    if(!pCreature)
1365    {
1366        sLog.outError("Can't create Spirit guide. BattleGround not created!");
1367        this->EndNow();
1368        return false;
1369    }
1370
1371    pCreature->setDeathState(DEAD);
1372
1373    pCreature->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, pCreature->GetGUID());
1374    // aura
1375    pCreature->SetUInt32Value(UNIT_FIELD_AURA, SPELL_SPIRIT_HEAL_CHANNEL);
1376    pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
1377    pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
1378    pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
1379    // casting visual effect
1380    pCreature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_SPIRIT_HEAL_CHANNEL);
1381    // correct cast speed
1382    pCreature->SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
1383
1384    //pCreature->CastSpell(pCreature, SPELL_SPIRIT_HEAL_CHANNEL, true);
1385
1386    return true;
1387}
1388
1389void BattleGround::SendMessageToAll(char const* text)
1390{
1391    WorldPacket data;
1392    ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, text, NULL);
1393    SendPacketToAll(&data);
1394}
1395
1396void BattleGround::SendMessageToAll(int32 entry)
1397{
1398    char const* text = GetTrinityString(entry);
1399    WorldPacket data;
1400    ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, text, NULL);
1401    SendPacketToAll(&data);
1402}
1403
1404void BattleGround::EndNow()
1405{
1406    RemoveFromBGFreeSlotQueue();
1407    SetStatus(STATUS_WAIT_LEAVE);
1408    SetEndTime(TIME_TO_AUTOREMOVE);
1409    // inform invited players about the removal
1410    sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
1411}
1412
1413// Battleground messages are localized using the dbc lang, they are not client language dependent
1414const char *BattleGround::GetTrinityString(int32 entry)
1415{
1416    // FIXME: now we have different DBC locales and need localized message for each target client
1417    return objmgr.GetTrinityStringForDBCLocale(entry);
1418}
1419
1420/*
1421important notice:
1422buffs aren't spawned/despawned when players captures anything
1423buffs are in their positions when battleground starts
1424*/
1425void BattleGround::HandleTriggerBuff(uint64 const& go_guid)
1426{
1427    GameObject *obj = HashMapHolder<GameObject>::Find(go_guid);
1428    if(!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned())
1429        return;
1430
1431    //change buff type, when buff is used:
1432    int32 index = m_BgObjects.size() - 1;
1433    while (index >= 0 && m_BgObjects[index] != go_guid)
1434        index--;
1435    if (index < 0)
1436    {
1437        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());
1438        return;
1439    }
1440
1441    //randomly select new buff
1442    uint8 buff = urand(0, 2);
1443    uint32 entry = obj->GetEntry();
1444    if( m_BuffChange && entry != Buff_Entries[buff] )
1445    {
1446        //despawn current buff
1447        SpawnBGObject(index, RESPAWN_ONE_DAY);
1448        //set index for new one
1449        for (uint8 currBuffTypeIndex = 0; currBuffTypeIndex < 3; ++currBuffTypeIndex)
1450            if( entry == Buff_Entries[currBuffTypeIndex] )
1451            {
1452                index -= currBuffTypeIndex;
1453                index += buff;
1454            }
1455    }
1456
1457    SpawnBGObject(index, BUFF_RESPAWN_TIME);
1458}
1459
1460void BattleGround::HandleKillPlayer( Player *player, Player *killer )
1461{
1462    //keep in mind that for arena this will have to be changed a bit
1463
1464    // add +1 deaths
1465    UpdatePlayerScore(player, SCORE_DEATHS, 1);
1466
1467    // add +1 kills to group and +1 killing_blows to killer
1468    if( killer )
1469    {
1470        UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);
1471        UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1);
1472
1473        for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1474        {
1475            Player *plr = objmgr.GetPlayer(itr->first);
1476
1477            if(!plr || plr == killer)
1478                continue;
1479
1480            if( plr->GetTeam() == killer->GetTeam() && plr->IsAtGroupRewardDistance(player) )
1481                UpdatePlayerScore(plr, SCORE_HONORABLE_KILLS, 1);
1482        }
1483    }
1484
1485    // to be able to remove insignia
1486    player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
1487}
1488
1489// return the player's team based on battlegroundplayer info
1490// used in same faction arena matches mainly
1491uint32 BattleGround::GetPlayerTeam(uint64 guid)
1492{
1493    std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.find(guid);
1494    if(itr!=m_Players.end())
1495        return itr->second.Team;
1496    return 0;
1497}
1498
1499uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const
1500{
1501    int count = 0;
1502    for(std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1503    {
1504        if(itr->second.Team == Team)
1505        {
1506            Player * pl = objmgr.GetPlayer(itr->first);
1507            if(pl && pl->isAlive())
1508                ++count;
1509        }
1510    }
1511    return count;
1512}
1513
1514void BattleGround::SetHoliday(bool is_holiday)
1515{
1516    if(is_holiday)
1517        m_HonorMode = BG_HOLIDAY;
1518    else
1519        m_HonorMode = BG_NORMAL;
1520}
1521
1522int32 BattleGround::GetObjectType(uint64 guid)
1523{
1524    for(uint32 i = 0;i <= m_BgObjects.size(); i++)
1525        if(m_BgObjects[i] == guid)
1526            return i;
1527    sLog.outError("BattleGround: cheating? a player used a gameobject which isnt supposed to be a usable object!");
1528    return -1;
1529}
1530
1531void BattleGround::HandleKillUnit(Creature *creature, Player *killer)
1532{
1533}
Note: See TracBrowser for help on using the browser.