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

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

RevLine 
[2]1/*
[102]2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
[44]4 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
[2]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
[44]13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
[2]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
[44]18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
[2]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"
[9]29#include "ArenaTeam.h"
[2]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;
[9]53    m_InBGFreeSlotQueue = false;
54    m_SetDeleteThis     = false;
[2]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
[9]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
[2]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;
[9]86
87    m_PrematureCountDown = false;
88    m_PrematureCountDown = 0;
[50]89    m_HonorMode = BG_NORMAL;
[2]90}
91
92BattleGround::~BattleGround()
93{
[9]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    }
[2]106
[9]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();
[2]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
[9]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
[2]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
[9]308        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
309
310        if(team == TeamID)
[2]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
[9]336        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
337
338        if(team == TeamID)
[2]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
[9]358        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
359       
360        if(team == TeamID)
[2]361            plr->CastSpell(plr, SpellID, true);
362    }
363}
364
[283]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
[2]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
[9]394        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
395
396        if(team == TeamID)
[2]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
[9]418        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
419
420        if(team == TeamID)
[2]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{
[9]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;
[2]448    WorldPacket data;
449    Player *Source = NULL;
450    const char *winmsg = "";
451
452    if(winner == ALLIANCE)
453    {
[9]454        if(isBattleGround())
[44]455            winmsg = GetTrinityString(LANG_BG_A_WINS);
[9]456        else
[44]457            winmsg = GetTrinityString(LANG_ARENA_GOLD_WINS);
[2]458
459        PlaySoundToAll(SOUND_ALLIANCE_WINS);                // alliance wins sound
460
461        SetWinner(WINNER_ALLIANCE);
462    }
[9]463    else if(winner == HORDE)
[2]464    {
[9]465        if(isBattleGround())
[44]466            winmsg = GetTrinityString(LANG_BG_H_WINS);
[9]467        else
[44]468            winmsg = GetTrinityString(LANG_ARENA_GREEN_WINS);
[2]469
470        PlaySoundToAll(SOUND_HORDE_WINS);                   // horde wins sound
471
472        SetWinner(WINNER_HORDE);
473    }
[9]474    else
475    {
476        SetWinner(3);
477    }
[2]478
479    SetStatus(STATUS_WAIT_LEAVE);
480    m_EndTime = 0;
481
[9]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
[2]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
[9]531        // should remove spirit of redemption
532        if(plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
533            plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
534
[2]535        if(!plr->isAlive())
536        {
537            plr->ResurrectPlayer(1.0f);
538            plr->SpawnCorpseBones();
539        }
540
[9]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)
[2]546        {
[9]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        {
[2]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
[9]572        uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());
573        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
[2]574        plr->GetSession()->SendPacket(&data);
575    }
576
[9]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
[2]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
[44]700        std::string textFormat = plr->GetSession()->GetTrinityString(LANG_BG_MARK_BY_MAIL);
[2]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{
[9]744    uint32 team = GetPlayerTeam(guid);
745    bool participant = false;
[2]746    // Remove from lists/maps
747    std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.find(guid);
748    if(itr != m_Players.end())
749    {
[9]750        UpdatePlayersCountByTeam(team, true);   // -1 player
[2]751        m_Players.erase(itr);
[9]752        // check if the player was a participant of the match, or only entered through gm command (goname)
753        participant = true;
[2]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
[9]767    // should remove spirit of redemption
768    if(plr && plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
769        plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
770
[2]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
[9]783        if(participant) // if the player was a match participant, remove auras, calc rating, update queue
[2]784        {
[9]785            if(!team) team = plr->GetTeam();
[2]786
[9]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)
[2]794
[9]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;
[2]801
[9]802                    (plr)->SetTemporaryUnsummonedPetNumber(0);
803                }
[2]804
[9]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            }
[2]826
[9]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            }
[2]833
[9]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))
[2]845            {
[9]846                if(!group->RemoveMember(guid, 0))               // group was disbanded
847                {
848                    SetBgRaid(team, NULL);
849                    delete group;
850                }
[2]851            }
[9]852
853            // Let others know
854            sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);
855            SendPacketToTeam(team, &data, plr, false);
[2]856        }
857
858        // Do next only if found in battleground
859        plr->SetBattleGroundId(0);                          // We're not in BG.
[9]860        // reset destination bg team
861        plr->SetBGTeam(0);
[2]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
[9]872    if(!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
[2]873    {
[9]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;
[2]879    }
[9]880
881    // a player exited the battleground, so there are free slots. add to queue
882    this->AddToBGFreeSlotQueue();
[2]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);
[9]894    SetArenaType(0);
895    SetRated(false);
[2]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;
[9]904    m_InBGFreeSlotQueue = false;
[2]905
906    m_Players.clear();
907    m_PlayerScores.clear();
908
[9]909    // reset BGSubclass (this cleans up creatures and gos as well)
[2]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
[9]935    UpdatePlayersCountByTeam(team, false);        // +1 player
[2]936
937    WorldPacket data;
938    sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr);
939    SendPacketToTeam(team, &data, plr, false);
940
[9]941    // add arena specific auras
[2]942    if(isArena())
943    {
[9]944        // remove auras first, only then reset spell cooldowns
945        // this is to prevent bugging amp. curse, combustion, etc. like spells
946        plr->RemoveArenaAuras();
[2]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
[9]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
[2]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{
[9]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    }
[2]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{
[9]1002    // set to be able to re-add if needed
1003    m_InBGFreeSlotQueue = false;
1004    // uncomment this code when battlegrounds will work like instances
[2]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        }
[9]1012    }
[2]1013}
1014
[9]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
[2]1018{
1019    //if BG is starting ... invite anyone:
1020    if (GetStatus() == STATUS_WAIT_JOIN)
[9]1021        return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
[2]1022    //if BG is already started .. do not allow to join too much players of one faction
1023    uint32 otherTeam;
[9]1024    uint32 otherIn;
[2]1025    if (Team == ALLIANCE)
[9]1026    {
[2]1027        otherTeam = GetInvitedCount(HORDE);
[9]1028        otherIn = GetPlayersCountByTeam(HORDE);
1029    }
[2]1030    else
[9]1031    {
[2]1032        otherTeam = GetInvitedCount(ALLIANCE);
[9]1033        otherIn = GetPlayersCountByTeam(ALLIANCE);
1034    }
[2]1035    if (GetStatus() == STATUS_IN_PROGRESS)
[9]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);
[2]1046
[9]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;
[2]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
[9]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            }
[2]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{
[9]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))
[2]1168    {
1169        sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);
[9]1170        sLog.outError("Cannot create gameobject template %u! BattleGround not created!", entry);
1171        delete go;
[2]1172        return false;
1173    }
[9]1174/*
1175    uint32 guid = go->GetGUIDLow();
[2]1176
[9]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
[2]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;
[9]1192    data.spawnMask      = 1;
[2]1193    data.animprogress   = 100;
1194    data.go_state       = 1;
[9]1195*/
1196    // add to world, so it can be later looked up from HashMapHolder
1197    go->AddToWorld();
1198    m_BgObjects[type] = go->GetGUID();
[2]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
[283]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
[2]1254void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
1255{
[9]1256    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1257    if(!map)
1258        return;
[2]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);
[9]1267            obj->SetRespawnTime(0);
1268            map->Add(obj);
[2]1269        }
1270    }
1271    else
1272    {
1273        GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1274        if(obj)
1275        {
[9]1276            map->Add(obj);
[2]1277            obj->SetRespawnTime(respawntime);
1278            obj->SetLootState(GO_JUST_DEACTIVATED);
1279        }
1280    }
1281}
1282
[9]1283Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime)
[2]1284{
[9]1285    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1286    if(!map)
1287        return NULL;
[2]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
[283]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
[2]1315    pCreature->AIM_Initialize();
1316
1317    //pCreature->SetDungeonDifficulty(0);
1318
1319    map->Add(pCreature);
1320    m_BgCreatures[type] = pCreature->GetGUID();
[9]1321
[2]1322    return  pCreature;
1323}
1324
1325bool BattleGround::DelCreature(uint32 type)
1326{
1327    Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1328    if(!cr)
1329    {
[230]1330        sLog.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures[type]));
[2]1331        return false;
1332    }
[283]1333    //TODO: only delete creature after not in combat
[2]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    {
[230]1345        sLog.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects[type]));
[2]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{
[44]1398    char const* text = GetTrinityString(entry);
[2]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{
[9]1406    RemoveFromBGFreeSlotQueue();
[2]1407    SetStatus(STATUS_WAIT_LEAVE);
1408    SetEndTime(TIME_TO_AUTOREMOVE);
[9]1409    // inform invited players about the removal
1410    sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
[2]1411}
1412
1413// Battleground messages are localized using the dbc lang, they are not client language dependent
[44]1414const char *BattleGround::GetTrinityString(int32 entry)
[2]1415{
1416    // FIXME: now we have different DBC locales and need localized message for each target client
[44]1417    return objmgr.GetTrinityStringForDBCLocale(entry);
[2]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}
[9]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}
[50]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}
[283]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.