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

Revision 2, 36.5 kB (checked in by yumileroy, 17 years ago)

[svn] * Proper SVN structure

Original author: Neo2003
Date: 2008-10-02 16:23:55-05:00

RevLine 
[2]1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18
19#include "Object.h"
20#include "Player.h"
21#include "BattleGround.h"
22#include "Creature.h"
23#include "MapManager.h"
24#include "Language.h"
25#include "Chat.h"
26#include "SpellAuras.h"
27#include "World.h"
28#include "Util.h"
29
30BattleGround::BattleGround()
31{
32    m_TypeID            = 0;
33    m_InstanceID        = 0;
34    m_Status            = 0;
35    m_EndTime           = 0;
36    m_LastResurrectTime = 0;
37    m_Queue_type        = MAX_BATTLEGROUND_QUEUES;
38    m_InvitedAlliance   = 0;
39    m_InvitedHorde      = 0;
40    m_ArenaType         = 0;
41    m_IsArena           = false;
42    m_Winner            = 2;
43    m_StartTime         = 0;
44    m_Events            = 0;
45    m_IsRated           = false;
46    m_BuffChange        = false;
47    m_Name              = "";
48    m_LevelMin          = 0;
49    m_LevelMax          = 0;
50
51    m_MaxPlayersPerTeam = 0;
52    m_MaxPlayers        = 0;
53    m_MinPlayersPerTeam = 0;
54    m_MinPlayers        = 0;
55
56    m_MapId             = 0;
57
58    m_TeamStartLocX[BG_TEAM_ALLIANCE]   = 0;
59    m_TeamStartLocX[BG_TEAM_HORDE]      = 0;
60
61    m_TeamStartLocY[BG_TEAM_ALLIANCE]   = 0;
62    m_TeamStartLocY[BG_TEAM_HORDE]      = 0;
63
64    m_TeamStartLocZ[BG_TEAM_ALLIANCE]   = 0;
65    m_TeamStartLocZ[BG_TEAM_HORDE]      = 0;
66
67    m_TeamStartLocO[BG_TEAM_ALLIANCE]   = 0;
68    m_TeamStartLocO[BG_TEAM_HORDE]      = 0;
69
70    m_BgRaids[BG_TEAM_ALLIANCE]         = NULL;
71    m_BgRaids[BG_TEAM_HORDE]            = NULL;
72
73    m_PlayersCount[BG_TEAM_ALLIANCE]    = 0;
74    m_PlayersCount[BG_TEAM_HORDE]       = 0;
75}
76
77BattleGround::~BattleGround()
78{
79
80}
81
82void BattleGround::Update(time_t diff)
83{
84
85    if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize())
86        //BG is empty
87        return;
88
89    WorldPacket data;
90
91    if(GetRemovedPlayersSize())
92    {
93        for(std::map<uint64, uint8>::iterator itr = m_RemovedPlayers.begin(); itr != m_RemovedPlayers.end(); ++itr)
94        {
95            Player *plr = objmgr.GetPlayer(itr->first);
96            switch(itr->second)
97            {
98                //following code is handled by event:
99                /*case 0:
100                    sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].RemovePlayer(itr->first);
101                    //RemovePlayerFromQueue(itr->first);
102                    if(plr)
103                    {
104                        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0);
105                        plr->GetSession()->SendPacket(&data);
106                    }
107                    break;*/
108                case 1:                                     // currently in bg and was removed from bg
109                    if(plr)
110                        RemovePlayerAtLeave(itr->first, true, true);
111                    else
112                        RemovePlayerAtLeave(itr->first, false, false);
113                    break;
114                case 2:                                     // revive queue
115                    RemovePlayerFromResurrectQueue(itr->first);
116                    break;
117                default:
118                    sLog.outError("BattleGround: Unknown remove player case!");
119            }
120        }
121        m_RemovedPlayers.clear();
122    }
123
124    // this code isn't efficient and its idea isn't implemented yet
125    /* offline players are removed from battleground in worldsession::LogoutPlayer()
126    // remove offline players from bg after ~5 minutes
127    if(GetPlayersSize())
128    {
129        for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
130        {
131            Player *plr = objmgr.GetPlayer(itr->first);
132            itr->second.LastOnlineTime += diff;
133
134            if(plr)
135                itr->second.LastOnlineTime = 0;   // update last online time
136            else
137                if(itr->second.LastOnlineTime >= MAX_OFFLINE_TIME)                   // 5 minutes
138                    m_RemovedPlayers[itr->first] = 1;       // add to remove list (BG)
139        }
140    }*/
141
142    m_LastResurrectTime += diff;
143    if (m_LastResurrectTime >= RESURRECTION_INTERVAL)
144    {
145        if(GetReviveQueueSize())
146        {
147            for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
148            {
149                Creature *sh = NULL;
150                for(std::vector<uint64>::iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
151                {
152                    Player *plr = objmgr.GetPlayer(*itr2);
153                    if(!plr)
154                        continue;
155
156                    if (!sh)
157                    {
158                        sh = ObjectAccessor::GetCreature(*plr, itr->first);
159                        // only for visual effect
160                        if (sh)
161                            sh->CastSpell(sh, SPELL_SPIRIT_HEAL, true);   // Spirit Heal, effect 117
162                    }
163
164                    plr->CastSpell(plr, SPELL_RESURRECTION_VISUAL, true);   // Resurrection visual
165                    m_ResurrectQueue.push_back(*itr2);
166                }
167                (itr->second).clear();
168            }
169
170            m_ReviveQueue.clear();
171            m_LastResurrectTime = 0;
172        }
173        else
174            // queue is clear and time passed, just update last resurrection time
175            m_LastResurrectTime = 0;
176    }
177    else if (m_LastResurrectTime > 500)    // Resurrect players only half a second later, to see spirit heal effect on NPC
178    {
179        for(std::vector<uint64>::iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
180        {
181            Player *plr = objmgr.GetPlayer(*itr);
182            if(!plr)
183                continue;
184            plr->ResurrectPlayer(1.0f);
185            plr->CastSpell(plr, SPELL_SPIRIT_HEAL_MANA, true);
186            ObjectAccessor::Instance().ConvertCorpseForPlayer(*itr);
187        }
188        m_ResurrectQueue.clear();
189    }
190
191    if(GetStatus() == STATUS_WAIT_LEAVE)
192    {
193        // remove all players from battleground after 2 minutes
194        m_EndTime += diff;
195        if(m_EndTime >= TIME_TO_AUTOREMOVE)                 // 2 minutes
196        {
197            for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
198            {
199                m_RemovedPlayers[itr->first] = 1;           // add to remove list (BG)
200            }
201            // do not change any battleground's private variables
202        }
203    }
204}
205
206void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O)
207{
208    uint8 idx = GetTeamIndexByTeamId(TeamID);
209    m_TeamStartLocX[idx] = X;
210    m_TeamStartLocY[idx] = Y;
211    m_TeamStartLocZ[idx] = Z;
212    m_TeamStartLocO[idx] = O;
213}
214
215void BattleGround::SendPacketToAll(WorldPacket *packet)
216{
217    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
218    {
219        Player *plr = objmgr.GetPlayer(itr->first);
220        if(plr)
221            plr->GetSession()->SendPacket(packet);
222        else
223            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
224    }
225}
226
227void BattleGround::SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *sender, bool self)
228{
229    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
230    {
231        Player *plr = objmgr.GetPlayer(itr->first);
232
233        if(!plr)
234        {
235            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
236            continue;
237        }
238
239        if(!self && sender == plr)
240            continue;
241
242        if(plr->GetTeam() == TeamID)
243            plr->GetSession()->SendPacket(packet);
244    }
245}
246
247void BattleGround::PlaySoundToAll(uint32 SoundID)
248{
249    WorldPacket data;
250    sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
251    SendPacketToAll(&data);
252}
253
254void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID)
255{
256    WorldPacket data;
257
258    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
259    {
260        Player *plr = objmgr.GetPlayer(itr->first);
261
262        if(!plr)
263        {
264            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
265            continue;
266        }
267
268        if(plr->GetTeam() == TeamID)
269        {
270            sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
271            plr->GetSession()->SendPacket(&data);
272        }
273    }
274}
275
276void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID)
277{
278    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
279    {
280        Player *plr = objmgr.GetPlayer(itr->first);
281
282        if(!plr)
283        {
284            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
285            continue;
286        }
287
288        if(plr->GetTeam() == TeamID)
289            plr->CastSpell(plr, SpellID, true);
290    }
291}
292
293void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID)
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(plr->GetTeam() == TeamID)
306            UpdatePlayerScore(plr, SCORE_BONUS_HONOR, Honor);
307    }
308}
309
310void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID)
311{
312    FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
313
314    if(!factionEntry)
315        return;
316
317    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
318    {
319        Player *plr = objmgr.GetPlayer(itr->first);
320
321        if(!plr)
322        {
323            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
324            continue;
325        }
326
327        if(plr->GetTeam() == TeamID)
328            plr->ModifyFactionReputation(factionEntry, Reputation);
329    }
330}
331
332void BattleGround::UpdateWorldState(uint32 Field, uint32 Value)
333{
334    WorldPacket data;
335    sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
336    SendPacketToAll(&data);
337}
338
339void BattleGround::UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player *Source)
340{
341    WorldPacket data;
342    sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
343    Source->GetSession()->SendPacket(&data);
344}
345
346void BattleGround::EndBattleGround(uint32 winner)
347{
348    WorldPacket data;
349    Player *Source = NULL;
350    const char *winmsg = "";
351
352    if(winner == ALLIANCE)
353    {
354        winmsg = GetMangosString(LANG_BG_A_WINS);
355
356        PlaySoundToAll(SOUND_ALLIANCE_WINS);                // alliance wins sound
357
358        SetWinner(WINNER_ALLIANCE);
359    }
360    else
361    {
362        winmsg = GetMangosString(LANG_BG_H_WINS);
363
364        PlaySoundToAll(SOUND_HORDE_WINS);                   // horde wins sound
365
366        SetWinner(WINNER_HORDE);
367    }
368
369    SetStatus(STATUS_WAIT_LEAVE);
370    m_EndTime = 0;
371
372    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
373    {
374        Player *plr = objmgr.GetPlayer(itr->first);
375        if(!plr)
376        {
377            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
378            continue;
379        }
380
381        if(!plr->isAlive())
382        {
383            plr->ResurrectPlayer(1.0f);
384            plr->SpawnCorpseBones();
385        }
386
387        if(plr->GetTeam() == winner)
388        {
389            if(!Source)
390                Source = plr;
391            RewardMark(plr,ITEM_WINNER_COUNT);
392            UpdatePlayerScore(plr, SCORE_BONUS_HONOR, 20);
393            RewardQuest(plr);
394        }
395        else
396        {
397            RewardMark(plr,ITEM_LOSER_COUNT);
398        }
399
400        plr->CombatStopWithPets(true);
401
402        BlockMovement(plr);
403
404        sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
405        plr->GetSession()->SendPacket(&data);
406
407        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
408        plr->GetSession()->SendPacket(&data);
409    }
410
411    if(Source)
412    {
413        ChatHandler(Source).FillMessageData(&data, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, Source->GetGUID(), winmsg);
414        SendPacketToAll(&data);
415    }
416}
417
418uint32 BattleGround::GetBattlemasterEntry() const
419{
420    switch(GetTypeID())
421    {
422        case BATTLEGROUND_AV: return 15972;
423        case BATTLEGROUND_WS: return 14623;
424        case BATTLEGROUND_AB: return 14879;
425        case BATTLEGROUND_EY: return 22516;
426        case BATTLEGROUND_NA: return 20200;
427        default:              return 0;
428    }
429}
430
431void BattleGround::RewardMark(Player *plr,uint32 count)
432{
433    // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
434    if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
435        return;
436
437    BattleGroundMarks mark;
438    bool IsSpell;
439    switch(GetTypeID())
440    {
441        case BATTLEGROUND_AV:
442            IsSpell = true;
443            if(count == ITEM_WINNER_COUNT)
444                mark = SPELL_AV_MARK_WINNER;
445            else
446                mark = SPELL_AV_MARK_LOSER;
447            break;
448        case BATTLEGROUND_WS:
449            IsSpell = true;
450            if(count == ITEM_WINNER_COUNT)
451                mark = SPELL_WS_MARK_WINNER;
452            else
453                mark = SPELL_WS_MARK_LOSER;
454            break;
455        case BATTLEGROUND_AB:
456            IsSpell = true;
457            if(count == ITEM_WINNER_COUNT)
458                mark = SPELL_AB_MARK_WINNER;
459            else
460                mark = SPELL_AB_MARK_LOSER;
461            break;
462        case BATTLEGROUND_EY:
463            IsSpell = false;
464            mark = ITEM_EY_MARK_OF_HONOR;
465            break;
466        default:
467            return;
468    }
469
470    if(IsSpell)
471        plr->CastSpell(plr, mark, true);
472    else if ( objmgr.GetItemPrototype( mark ) )
473    {
474        ItemPosCountVec dest;
475        uint32 no_space_count = 0;
476        uint8 msg = plr->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, mark, count, &no_space_count );
477        if( msg != EQUIP_ERR_OK )                       // convert to possible store amount
478            count -= no_space_count;
479
480        if( count != 0 && !dest.empty())                // can add some
481            if(Item* item = plr->StoreNewItem( dest, mark, true, 0))
482                plr->SendNewItem(item,count,false,true);
483
484        if(no_space_count > 0)
485            SendRewardMarkByMail(plr,mark,no_space_count);
486    }
487}
488
489void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count)
490{
491    uint32 bmEntry = GetBattlemasterEntry();
492    if(!bmEntry)
493        return;
494
495    ItemPrototype const* markProto = objmgr.GetItemPrototype(mark);
496    if(!markProto)
497        return;
498
499    if(Item* markItem = Item::CreateItem(mark,count,plr))
500    {
501        // save new item before send
502        markItem->SaveToDB();                               // save for prevent lost at next mail load, if send fail then item will deleted
503
504        // item
505        MailItemsInfo mi;
506        mi.AddItem(markItem->GetGUIDLow(), markItem->GetEntry(), markItem);
507
508        // subject: item name
509        std::string subject = markProto->Name1;
510        int loc_idx = plr->GetSession()->GetSessionDbLocaleIndex();
511        if ( loc_idx >= 0 )
512            if(ItemLocale const *il = objmgr.GetItemLocale(markProto->ItemId))
513                if (il->Name.size() > loc_idx && !il->Name[loc_idx].empty())
514                    subject = il->Name[loc_idx];
515
516        // text
517        std::string textFormat = plr->GetSession()->GetMangosString(LANG_BG_MARK_BY_MAIL);
518        char textBuf[300];
519        snprintf(textBuf,300,textFormat.c_str(),GetName(),GetName());
520        uint32 itemTextId = objmgr.CreateItemText( textBuf );
521
522        WorldSession::SendMailTo(plr, MAIL_CREATURE, MAIL_STATIONERY_NORMAL, bmEntry, plr->GetGUIDLow(), subject, itemTextId , &mi, 0, 0, MAIL_CHECK_MASK_NONE);
523    }
524}
525
526void BattleGround::RewardQuest(Player *plr)
527{
528    // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
529    if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
530        return;
531
532    uint32 quest;
533    switch(GetTypeID())
534    {
535        case BATTLEGROUND_AV:
536            quest = SPELL_AV_QUEST_REWARD;
537            break;
538        case BATTLEGROUND_WS:
539            quest = SPELL_WS_QUEST_REWARD;
540            break;
541        case BATTLEGROUND_AB:
542            quest = SPELL_AB_QUEST_REWARD;
543            break;
544        case BATTLEGROUND_EY:
545            quest = SPELL_EY_QUEST_REWARD;
546            break;
547        default:
548            return;
549    }
550
551    plr->CastSpell(plr, quest, true);
552}
553
554void BattleGround::BlockMovement(Player *plr)
555{
556    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()
557}
558
559void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket)
560{
561    // Remove from lists/maps
562    std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.find(guid);
563    if(itr != m_Players.end())
564    {
565        UpdatePlayersCountByTeam(itr->second.Team, true);   // -1 player
566        m_Players.erase(itr);
567    }
568
569    std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid);
570    if(itr2 != m_PlayerScores.end())
571    {
572        delete itr2->second;                                // delete player's score
573        m_PlayerScores.erase(itr2);
574    }
575
576    RemovePlayerFromResurrectQueue(guid);
577
578    Player *plr = objmgr.GetPlayer(guid);
579
580    if(plr && !plr->isAlive())                              // resurrect on exit
581    {
582        plr->ResurrectPlayer(1.0f);
583        plr->SpawnCorpseBones();
584    }
585
586    RemovePlayer(plr, guid);                                // BG subclass specific code
587
588    if(plr)
589    {
590        plr->ClearAfkReports();
591
592        if(isArena())
593        {
594            if(!sWorld.IsFFAPvPRealm())
595                plr->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);
596        }
597
598        WorldPacket data;
599        if(SendPacket)
600        {
601            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0);
602            plr->GetSession()->SendPacket(&data);
603        }
604
605        // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
606        plr->RemoveBattleGroundQueueId(m_TypeID);
607
608        DecreaseInvitedCount(plr->GetTeam());
609        //we should update battleground queue, but only if bg isn't ending
610        if (GetQueueType() < MAX_BATTLEGROUND_QUEUES)
611            sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].Update(GetTypeID(), GetQueueType());
612
613        if(!plr->GetBattleGroundId())
614            return;
615
616        Group * group = plr->GetGroup();
617
618        // remove from raid group if exist
619        if(group && group == GetBgRaid(plr->GetTeam()))
620        {
621            if(!group->RemoveMember(guid, 0))               // group was disbanded
622            {
623                SetBgRaid(plr->GetTeam(), NULL);
624                delete group;
625            }
626        }
627
628        // Do next only if found in battleground
629        plr->SetBattleGroundId(0);                          // We're not in BG.
630
631        // Let others know
632        sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);
633        SendPacketToTeam(plr->GetTeam(), &data, plr, false);
634
635        if(Transport)
636        {
637            plr->TeleportTo(plr->GetBattleGroundEntryPointMap(), plr->GetBattleGroundEntryPointX(), plr->GetBattleGroundEntryPointY(), plr->GetBattleGroundEntryPointZ(), plr->GetBattleGroundEntryPointO());
638            //sLog.outDetail("BATTLEGROUND: Sending %s to %f,%f,%f,%f", pl->GetName(), x,y,z,O);
639        }
640
641        // Log
642        sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName());
643    }
644
645    /// there will be code which will add battleground to BGFreeSlotQueue , when battleground instance will exist
646    // we always should check if BG is in that queue before adding..
647
648    if(!GetPlayersSize())
649    {
650        Reset();
651    }
652}
653
654// this method is called when no players remains in battleground
655void BattleGround::Reset()
656{
657    SetQueueType(MAX_BATTLEGROUND_QUEUES);
658    SetWinner(WINNER_NONE);
659    SetStatus(STATUS_WAIT_QUEUE);
660    SetStartTime(0);
661    SetEndTime(0);
662    SetLastResurrectTime(0);
663
664    m_Events = 0;
665
666    if (m_InvitedAlliance > 0 || m_InvitedHorde > 0)
667        sLog.outError("BattleGround system ERROR: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance, m_InvitedHorde);
668
669    m_InvitedAlliance = 0;
670    m_InvitedHorde = 0;
671
672    m_Players.clear();
673    m_PlayerScores.clear();
674
675    // reset BGSubclass
676    this->ResetBGSubclass();
677}
678
679void BattleGround::StartBattleGround()
680{
681    ///this method should spawn spirit guides and so on
682    SetStartTime(0);
683
684    SetLastResurrectTime(0);
685}
686
687void BattleGround::AddPlayer(Player *plr)
688{
689    // score struct must be created in inherited class
690
691    uint64 guid = plr->GetGUID();
692    uint32 team = plr->GetBGTeam();
693
694    BattleGroundPlayer bp;
695    bp.LastOnlineTime = 0;
696    bp.Team = team;
697
698    // Add to list/maps
699    m_Players[guid] = bp;
700
701    UpdatePlayersCountByTeam(team, false);                  // +1 player
702
703    WorldPacket data;
704    sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr);
705    SendPacketToTeam(team, &data, plr, false);
706
707    if(isArena())
708    {
709        plr->RemoveArenaSpellCooldowns();
710        //plr->RemoveArenaAuras();
711        plr->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT);
712        if(team == ALLIANCE && plr->GetTeam() == ALLIANCE)
713            plr->CastSpell(plr,SPELL_ALLIANCE_GOLD_FLAG,true);
714        else if(team == HORDE && plr->GetTeam() == ALLIANCE)
715            plr->CastSpell(plr,SPELL_ALLIANCE_GREEN_FLAG,true);
716        else if(team == ALLIANCE && plr->GetTeam() == HORDE)
717            plr->CastSpell(plr,SPELL_HORDE_GOLD_FLAG,true);
718        else
719            plr->CastSpell(plr,SPELL_HORDE_GREEN_FLAG,true);
720        plr->DestroyConjuredItems(true);
721
722        if(GetStatus() == STATUS_WAIT_JOIN)                 // not started yet
723        {
724            plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);
725
726            plr->SetHealth(plr->GetMaxHealth());
727            plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA));
728        }
729    }
730    else
731    {
732        if(GetStatus() == STATUS_WAIT_JOIN)                 // not started yet
733            plr->CastSpell(plr, SPELL_PREPARATION, true);   // reduces all mana cost of spells.
734    }
735
736    if(isArena())
737        plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);
738
739    // Log
740    sLog.outDetail("BATTLEGROUND: Player %s joined the battle.", plr->GetName());
741}
742
743/* This method should be called only once ... it adds pointer to queue */
744void BattleGround::AddToBGFreeSlotQueue()
745{
746    sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);
747}
748
749/* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
750void BattleGround::RemoveFromBGFreeSlotQueue()
751{
752    /* uncomment this code when battlegrounds will work like instances
753    for (std::deque<BattleGround*>::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)
754    {
755        if ((*itr)->GetInstanceID() == m_InstanceID)
756        {
757            sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr);
758            return;
759        }
760    }*/
761}
762
763/*
764this method should decide, if we can invite new player of certain team to BG, it is based on BATTLEGROUND_STATUS
765*/
766bool BattleGround::HasFreeSlotsForTeam(uint32 Team) const
767{
768    //if BG is starting ... invite anyone:
769    if (GetStatus() == STATUS_WAIT_JOIN)
770        return GetInvitedCount(Team) < GetMaxPlayersPerTeam();
771    //if BG is already started .. do not allow to join too much players of one faction
772    uint32 otherTeam;
773    if (Team == ALLIANCE)
774        otherTeam = GetInvitedCount(HORDE);
775    else
776        otherTeam = GetInvitedCount(ALLIANCE);
777    if (GetStatus() == STATUS_IN_PROGRESS)
778        return (GetInvitedCount(Team) <= otherTeam && GetInvitedCount(Team) < GetMaxPlayersPerTeam());
779
780    return false;
781}
782
783/* this method isn't called already, it will be useful when more battlegrounds of one type will be available */
784bool BattleGround::HasFreeSlots() const
785{
786    return GetPlayersSize() < GetMaxPlayers();
787}
788
789void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
790{
791    //this procedure is called from virtual function implemented in bg subclass
792    std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
793
794    if(itr == m_PlayerScores.end())                         // player not found...
795        return;
796
797    switch(type)
798    {
799        case SCORE_KILLING_BLOWS:                           // Killing blows
800            itr->second->KillingBlows += value;
801            break;
802        case SCORE_DEATHS:                                  // Deaths
803            itr->second->Deaths += value;
804            break;
805        case SCORE_HONORABLE_KILLS:                         // Honorable kills
806            itr->second->HonorableKills += value;
807            break;
808        case SCORE_BONUS_HONOR:                             // Honor bonus
809            // reward honor instantly
810            if(Source->RewardHonor(NULL, 1, value))
811                itr->second->BonusHonor += value;
812            break;
813            //used only in EY, but in MSG_PVP_LOG_DATA opcode
814        case SCORE_DAMAGE_DONE:                             // Damage Done
815            itr->second->DamageDone += value;
816            break;
817        case SCORE_HEALING_DONE:                            // Healing Done
818            itr->second->HealingDone += value;
819            break;
820        default:
821            sLog.outError("BattleGround: Unknown player score type %u", type);
822            break;
823    }
824}
825
826void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid)
827{
828    m_ReviveQueue[npc_guid].push_back(player_guid);
829
830    Player *plr = objmgr.GetPlayer(player_guid);
831    if(!plr)
832        return;
833
834    plr->CastSpell(plr, SPELL_WAITING_FOR_RESURRECT, true);
835    SpellEntry const *spellInfo = sSpellStore.LookupEntry( SPELL_WAITING_FOR_RESURRECT );
836    if(spellInfo)
837    {
838        Aura *Aur = CreateAura(spellInfo, 0, NULL, plr);
839        plr->AddAura(Aur);
840    }
841}
842
843void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid)
844{
845    for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
846    {
847        for(std::vector<uint64>::iterator itr2 =(itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
848        {
849            if(*itr2 == player_guid)
850            {
851                (itr->second).erase(itr2);
852
853                Player *plr = objmgr.GetPlayer(player_guid);
854                if(!plr)
855                    return;
856
857                plr->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
858
859                return;
860            }
861        }
862    }
863}
864
865bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime)
866{
867    GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(entry);
868    if(!goinfo)
869    {
870        sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);
871        return false;
872    }
873
874    uint32 guid = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);
875
876    GameObjectData& data = objmgr.NewGOData(guid);
877
878    data.id             = entry;
879    data.mapid          = GetMapId();
880    data.posX           = x;
881    data.posY           = y;
882    data.posZ           = z;
883    data.orientation    = o;
884    data.rotation0      = rotation0;
885    data.rotation1      = rotation1;
886    data.rotation2      = rotation2;
887    data.rotation3      = rotation3;
888    data.spawntimesecs  = respawnTime;
889    data.animprogress   = 100;
890    data.go_state       = 1;
891    data.spawnMask      = 1;
892    objmgr.AddGameobjectToGrid(guid, &data);
893
894    m_BgObjects[type] = MAKE_NEW_GUID(guid, entry, HIGHGUID_GAMEOBJECT);
895
896    return true;
897}
898
899//some doors aren't despawned so we cannot handle their closing in gameobject::update()
900//it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
901void BattleGround::DoorClose(uint32 type)
902{
903    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
904    if(obj)
905    {
906        //if doors are open, close it
907        if( obj->getLootState() == GO_ACTIVATED && !obj->GetGoState() )
908        {
909            //change state to allow door to be closed
910            obj->SetLootState(GO_READY);
911            obj->UseDoorOrButton(RESPAWN_ONE_DAY);
912        }
913    }
914    else
915    {
916        sLog.outError("BattleGround: Door object not found (cannot close doors)");
917    }
918}
919
920void BattleGround::DoorOpen(uint32 type)
921{
922    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
923    if(obj)
924    {
925        //change state to be sure they will be opened
926        obj->SetLootState(GO_READY);
927        obj->UseDoorOrButton(RESPAWN_ONE_DAY);
928    }
929    else
930    {
931        sLog.outError("BattleGround: Door object not found! - doors will be closed.");
932    }
933}
934
935void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
936{
937    if( respawntime == 0 )
938    {
939        GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
940        if(obj)
941        {
942            //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
943            if( obj->getLootState() == GO_JUST_DEACTIVATED )
944                obj->SetLootState(GO_READY);
945            obj->Respawn();
946        }
947        else
948            objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), 0, 0);
949    }
950    else
951    {
952        GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
953        if(obj)
954        {
955            obj->SetRespawnTime(respawntime);
956            obj->SetLootState(GO_JUST_DEACTIVATED);
957        }
958        else
959            objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), 0, time(NULL) + respawntime);
960    }
961}
962
963Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o)
964{
965    // note: this should normally be FindMap
966    // but it's a hack to allow the battlegrounds to initialize at server startup
967    Map * map = MapManager::Instance().GetMap(GetMapId(), 0);
968    if(!map) return NULL;
969
970    Creature* pCreature = new Creature;
971    if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, entry, teamval))
972    {
973        sLog.outError("Can't create creature entry: %u",entry);
974        delete pCreature;
975        return NULL;
976    }
977
978    pCreature->Relocate(x, y, z, o);
979
980    if(!pCreature->IsPositionValid())
981    {
982        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());
983        return NULL;
984    }
985
986    pCreature->AIM_Initialize();
987
988    //pCreature->SetDungeonDifficulty(0);
989
990    map->Add(pCreature);
991    m_BgCreatures[type] = pCreature->GetGUID();
992    return  pCreature;
993}
994
995bool BattleGround::DelCreature(uint32 type)
996{
997    Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
998    if(!cr)
999    {
1000        sLog.outError("Can't find creature guid: %u",m_BgCreatures[type]);
1001        return false;
1002    }
1003    cr->CleanupsBeforeDelete();
1004    cr->AddObjectToRemoveList();
1005    m_BgCreatures[type] = 0;
1006    return true;
1007}
1008
1009bool BattleGround::DelObject(uint32 type)
1010{
1011    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1012    if(!obj)
1013    {
1014        sLog.outError("Can't find gobject guid: %u",m_BgObjects[type]);
1015        return false;
1016    }
1017    obj->SetRespawnTime(0);                                 // not save respawn time
1018    obj->Delete();
1019    m_BgObjects[type] = 0;
1020    return true;
1021}
1022
1023bool BattleGround::AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team)
1024{
1025    uint32 entry = 0;
1026
1027    if(team == ALLIANCE)
1028        entry = 13116;
1029    else
1030        entry = 13117;
1031
1032    Creature* pCreature = AddCreature(entry,type,team,x,y,z,o);
1033    if(!pCreature)
1034    {
1035        sLog.outError("Can't create Spirit guide. BattleGround not created!");
1036        this->EndNow();
1037        return false;
1038    }
1039
1040    pCreature->setDeathState(DEAD);
1041
1042    pCreature->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, pCreature->GetGUID());
1043    // aura
1044    pCreature->SetUInt32Value(UNIT_FIELD_AURA, SPELL_SPIRIT_HEAL_CHANNEL);
1045    pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
1046    pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
1047    pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
1048    // casting visual effect
1049    pCreature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_SPIRIT_HEAL_CHANNEL);
1050    // correct cast speed
1051    pCreature->SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
1052
1053    //pCreature->CastSpell(pCreature, SPELL_SPIRIT_HEAL_CHANNEL, true);
1054
1055    return true;
1056}
1057
1058void BattleGround::SendMessageToAll(char const* text)
1059{
1060    WorldPacket data;
1061    ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, text, NULL);
1062    SendPacketToAll(&data);
1063}
1064
1065void BattleGround::SendMessageToAll(int32 entry)
1066{
1067    char const* text = GetMangosString(entry);
1068    WorldPacket data;
1069    ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, text, NULL);
1070    SendPacketToAll(&data);
1071}
1072
1073void BattleGround::EndNow()
1074{
1075    SetStatus(STATUS_WAIT_LEAVE);
1076    SetEndTime(TIME_TO_AUTOREMOVE);
1077}
1078
1079// Battleground messages are localized using the dbc lang, they are not client language dependent
1080const char *BattleGround::GetMangosString(int32 entry)
1081{
1082    // FIXME: now we have different DBC locales and need localized message for each target client
1083    return objmgr.GetMangosStringForDBCLocale(entry);
1084}
1085
1086/*
1087important notice:
1088buffs aren't spawned/despawned when players captures anything
1089buffs are in their positions when battleground starts
1090*/
1091void BattleGround::HandleTriggerBuff(uint64 const& go_guid)
1092{
1093    GameObject *obj = HashMapHolder<GameObject>::Find(go_guid);
1094    if(!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned())
1095        return;
1096
1097    //change buff type, when buff is used:
1098    int32 index = m_BgObjects.size() - 1;
1099    while (index >= 0 && m_BgObjects[index] != go_guid)
1100        index--;
1101    if (index < 0)
1102    {
1103        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());
1104        return;
1105    }
1106
1107    //randomly select new buff
1108    uint8 buff = urand(0, 2);
1109    uint32 entry = obj->GetEntry();
1110    if( m_BuffChange && entry != Buff_Entries[buff] )
1111    {
1112        //despawn current buff
1113        SpawnBGObject(index, RESPAWN_ONE_DAY);
1114        //set index for new one
1115        for (uint8 currBuffTypeIndex = 0; currBuffTypeIndex < 3; ++currBuffTypeIndex)
1116            if( entry == Buff_Entries[currBuffTypeIndex] )
1117            {
1118                index -= currBuffTypeIndex;
1119                index += buff;
1120            }
1121    }
1122
1123    SpawnBGObject(index, BUFF_RESPAWN_TIME);
1124}
1125
1126void BattleGround::HandleKillPlayer( Player *player, Player *killer )
1127{
1128    //keep in mind that for arena this will have to be changed a bit
1129
1130    // add +1 deaths
1131    UpdatePlayerScore(player, SCORE_DEATHS, 1);
1132
1133    // add +1 kills to group and +1 killing_blows to killer
1134    if( killer )
1135    {
1136        UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);
1137        UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1);
1138
1139        for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1140        {
1141            Player *plr = objmgr.GetPlayer(itr->first);
1142
1143            if(!plr || plr == killer)
1144                continue;
1145
1146            if( plr->GetTeam() == killer->GetTeam() && plr->IsAtGroupRewardDistance(player) )
1147                UpdatePlayerScore(plr, SCORE_HONORABLE_KILLS, 1);
1148        }
1149    }
1150
1151    // to be able to remove insignia
1152    player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
1153}
Note: See TracBrowser for help on using the browser.