root/trunk/src/game/BattleGroundAB.cpp @ 9

Revision 9, 27.7 kB (checked in by yumileroy, 17 years ago)

[svn] -enabled instantiated battlegrounds
-enabled arena matches
-rewritten battleground queuing to support joining as group
-removed queue announcements

Original author: w12x
Date: 2008-10-05 08:48:32-05:00

Line 
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 "BattleGroundAB.h"
23#include "Creature.h"
24#include "Chat.h"
25#include "ObjectMgr.h"
26#include "MapManager.h"
27#include "Language.h"
28#include "Util.h"
29
30BattleGroundAB::BattleGroundAB()
31{
32    m_BuffChange = true;
33    m_BgObjects.resize(BG_AB_OBJECT_MAX);
34    m_BgCreatures.resize(BG_AB_ALL_NODES_COUNT);
35}
36
37BattleGroundAB::~BattleGroundAB()
38{
39}
40
41void BattleGroundAB::Update(time_t diff)
42{
43    BattleGround::Update(diff);
44
45    if( GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize() )
46    {
47        ModifyStartDelayTime(diff);
48
49        if( !(m_Events & 0x01) )
50        {
51            m_Events |= 0x01;
52
53            // setup here, only when at least one player has ported to the map
54            if(!SetupBattleGround())
55            {
56                EndNow();
57                return;
58            }
59
60            sLog.outDebug("Arathi Basin: entering state STATUS_WAIT_JOIN ...");
61
62            // despawn banners, auras and buffs
63            for (int obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_DYNAMIC_NODES_COUNT * 8; ++obj)
64                SpawnBGObject(obj, RESPAWN_ONE_DAY);
65            for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT * 3; ++i)
66                SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + i, RESPAWN_ONE_DAY);
67
68            // Starting doors
69            SpawnBGObject(BG_AB_OBJECT_GATE_A, RESPAWN_IMMEDIATELY);
70            SpawnBGObject(BG_AB_OBJECT_GATE_H, RESPAWN_IMMEDIATELY);
71            DoorClose(BG_AB_OBJECT_GATE_A);
72            DoorClose(BG_AB_OBJECT_GATE_H);
73
74            // Starting base spirit guides
75            _NodeOccupied(BG_AB_SPIRIT_ALIANCE,ALLIANCE);
76            _NodeOccupied(BG_AB_SPIRIT_HORDE,HORDE);
77
78            SetStartDelayTime(START_DELAY0);
79        }
80        // After 1 minute, warning is signalled
81        else if( GetStartDelayTime() <= START_DELAY1 && !(m_Events & 0x04) )
82        {
83            m_Events |= 0x04;
84            SendMessageToAll(GetMangosString(LANG_BG_AB_ONEMINTOSTART));
85        }
86        // After 1,5 minute, warning is signalled
87        else if( GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x08) )
88        {
89            m_Events |= 0x08;
90            SendMessageToAll(GetMangosString(LANG_BG_AB_HALFMINTOSTART));
91        }
92        // After 2 minutes, gates OPEN ! x)
93        else if( GetStartDelayTime() < 0 && !(m_Events & 0x10) )
94        {
95            m_Events |= 0x10;
96            SendMessageToAll(GetMangosString(LANG_BG_AB_STARTED));
97
98            // spawn neutral banners
99            for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i)
100                SpawnBGObject(banner, RESPAWN_IMMEDIATELY);
101            for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
102            {
103                //randomly select buff to spawn
104                uint8 buff = urand(0, 2);
105                SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + buff + i * 3, RESPAWN_IMMEDIATELY);
106            }
107            DoorOpen(BG_AB_OBJECT_GATE_A);
108            DoorOpen(BG_AB_OBJECT_GATE_H);
109
110            PlaySoundToAll(SOUND_BG_START);
111            SetStatus(STATUS_IN_PROGRESS);
112
113            for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
114                if(Player* plr = objmgr.GetPlayer(itr->first))
115                    plr->RemoveAurasDueToSpell(SPELL_PREPARATION);
116        }
117
118    }
119    else if( GetStatus() == STATUS_IN_PROGRESS )
120    {
121        int team_points[2] = { 0, 0 };
122
123        for (int node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
124        {
125            // 3 sec delay to spawn new banner instead previous despawned one
126            if( m_BannerTimers[node].timer )
127            {
128                if( m_BannerTimers[node].timer > diff )
129                    m_BannerTimers[node].timer -= diff;
130                else
131                {
132                    m_BannerTimers[node].timer = 0;
133                    _CreateBanner(node, m_BannerTimers[node].type, m_BannerTimers[node].teamIndex, false);
134                }
135            }
136
137            // 1-minute to occupy a node from contested state
138            if( m_NodeTimers[node] )
139            {
140                if( m_NodeTimers[node] > diff )
141                    m_NodeTimers[node] -= diff;
142                else
143                {
144                    m_NodeTimers[node] = 0;
145                    // Change from contested to occupied !
146                    uint8 teamIndex = m_Nodes[node]-1;
147                    m_prevNodes[node] = m_Nodes[node];
148                    m_Nodes[node] += 2;
149                    // burn current contested banner
150                    _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex);
151                    // create new occupied banner
152                    _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
153                    _SendNodeUpdate(node);
154                    _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE);
155                    // Message to chatlog
156                    char buf[256];
157                    uint8 type = (teamIndex == 0) ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
158                    sprintf(buf, GetMangosString(LANG_BG_AB_NODE_TAKEN), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE), _GetNodeName(node));
159                    WorldPacket data;
160                    ChatHandler::FillMessageData(&data, NULL, type, LANG_UNIVERSAL, NULL, 0, buf, NULL);
161                    SendPacketToAll(&data);
162                    PlaySoundToAll((teamIndex == 0) ? SOUND_NODE_CAPTURED_ALLIANCE : SOUND_NODE_CAPTURED_HORDE);
163                }
164            }
165
166            for (int team = 0; team < 2; ++team)
167                if( m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED )
168                    ++team_points[team];
169        }
170
171        // Accumulate points
172        for (int team = 0; team < 2; ++team)
173        {
174            int points = team_points[team];
175            if( !points )
176                continue;
177            m_lastTick[team] += diff;
178            if( m_lastTick[team] > BG_AB_TickIntervals[points] )
179            {
180                m_lastTick[team] -= BG_AB_TickIntervals[points];
181                m_TeamScores[team] += BG_AB_TickPoints[points];
182                m_HonorScoreTics[team] += BG_AB_TickPoints[points];
183                m_ReputationScoreTics[team] += BG_AB_TickPoints[points];
184                if( m_ReputationScoreTics[team] >= 200 )
185                {
186                    (team == BG_TEAM_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE);
187                    m_ReputationScoreTics[team] -= 200;
188                }
189                if( m_HonorScoreTics[team] >= BG_HONOR_SCORE_TICKS )
190                {
191                    (team == BG_TEAM_ALLIANCE) ? RewardHonorToTeam(20, ALLIANCE) : RewardHonorToTeam(20, HORDE);
192                    m_HonorScoreTics[team] -= BG_HONOR_SCORE_TICKS;
193                }
194                if( !m_IsInformedNearVictory && m_TeamScores[team] > 1800 )
195                {
196                    if( team == BG_TEAM_ALLIANCE )
197                        SendMessageToAll(GetMangosString(LANG_BG_AB_A_NEAR_VICTORY));
198                    else
199                        SendMessageToAll(GetMangosString(LANG_BG_AB_H_NEAR_VICTORY));
200                    PlaySoundToAll(SOUND_NEAR_VICTORY);
201                    m_IsInformedNearVictory = true;
202                }
203
204                if( m_TeamScores[team] > 2000 )
205                    m_TeamScores[team] = 2000;
206                if( team == BG_TEAM_ALLIANCE )
207                    UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]);
208                if( team == BG_TEAM_HORDE )
209                    UpdateWorldState(BG_AB_OP_RESOURCES_HORDE, m_TeamScores[team]);
210            }
211        }
212
213        // Test win condition
214        if( m_TeamScores[BG_TEAM_ALLIANCE] >= 2000 )
215            EndBattleGround(ALLIANCE);
216        if( m_TeamScores[BG_TEAM_HORDE] >= 2000 )
217            EndBattleGround(HORDE);
218    }
219}
220
221void BattleGroundAB::AddPlayer(Player *plr)
222{
223    BattleGround::AddPlayer(plr);
224    //create score and add it to map, default values are set in the constructor
225    BattleGroundABScore* sc = new BattleGroundABScore;
226
227    m_PlayerScores[plr->GetGUID()] = sc;
228}
229
230void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/)
231{
232
233}
234
235void BattleGroundAB::HandleAreaTrigger(Player *Source, uint32 Trigger)
236{
237    if( GetStatus() != STATUS_IN_PROGRESS )
238        return;
239
240    switch(Trigger)
241    {
242        case 3948:                                          // Arathi Basin Alliance Exit.
243            if( Source->GetTeam() != ALLIANCE )
244                Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal");
245            else
246                Source->LeaveBattleground();
247            break;
248        case 3949:                                          // Arathi Basin Horde Exit.
249            if( Source->GetTeam() != HORDE )
250                Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal");
251            else
252                Source->LeaveBattleground();
253            break;
254        case 3866:                                          // Stables
255        case 3869:                                          // Gold Mine
256        case 3867:                                          // Farm
257        case 3868:                                          // Lumber Mill
258        case 3870:                                          // Black Smith
259        case 4020:                                          // Unk1
260        case 4021:                                          // Unk2
261            //break;
262        default:
263            //sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
264            //Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
265            break;
266    }
267}
268
269/*  type: 0-neutral, 1-contested, 3-occupied
270    teamIndex: 0-ally, 1-horde                        */
271void BattleGroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay)
272{
273    // Just put it into the queue
274    if( delay )
275    {
276        m_BannerTimers[node].timer = 2000;
277        m_BannerTimers[node].type = type;
278        m_BannerTimers[node].teamIndex = teamIndex;
279        return;
280    }
281
282    uint8 obj = node*8 + type + teamIndex;
283
284    SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
285
286    // handle aura with banner
287    if( !type )
288        return;
289    obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
290    SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
291}
292
293void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex)
294{
295    uint8 obj = node*8 + type + teamIndex;
296    SpawnBGObject(obj, RESPAWN_ONE_DAY);
297
298    // handle aura with banner
299    if( !type )
300        return;
301    obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
302    SpawnBGObject(obj, RESPAWN_ONE_DAY);
303}
304
305const char* BattleGroundAB::_GetNodeName(uint8 node)
306{
307    switch (node)
308    {
309        case BG_AB_NODE_STABLES:
310            return GetMangosString(LANG_BG_AB_NODE_STABLES);
311        case BG_AB_NODE_BLACKSMITH:
312            return GetMangosString(LANG_BG_AB_NODE_BLACKSMITH);
313        case BG_AB_NODE_FARM:
314            return GetMangosString(LANG_BG_AB_NODE_FARM);
315        case BG_AB_NODE_LUMBER_MILL:
316            return GetMangosString(LANG_BG_AB_NODE_LUMBER_MILL);
317        case BG_AB_NODE_GOLD_MINE:
318            return GetMangosString(LANG_BG_AB_NODE_GOLD_MINE);
319        default:
320            ASSERT(0);
321    }
322    return "";
323}
324
325void BattleGroundAB::FillInitialWorldStates(WorldPacket& data)
326{
327    const uint8 plusArray[] = {0, 2, 3, 0, 1};
328
329    // Node icons
330    for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
331        data << uint32(BG_AB_OP_NODEICONS[node]) << uint32((m_Nodes[node]==0)?1:0);
332
333    // Node occupied states
334    for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
335        for (uint8 i = 1; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
336            data << uint32(BG_AB_OP_NODESTATES[node] + plusArray[i]) << uint32((m_Nodes[node]==i)?1:0);
337
338    // How many bases each team owns
339    uint8 ally = 0, horde = 0;
340    for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
341        if( m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_OCCUPIED )
342            ++ally;
343        else if( m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED )
344            ++horde;
345
346    data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY)  << uint32(ally);
347    data << uint32(BG_AB_OP_OCCUPIED_BASES_HORDE) << uint32(horde);
348
349    // Team scores
350    data << uint32(BG_AB_OP_RESOURCES_MAX)      << uint32(BG_AB_MAX_TEAM_SCORE);
351    data << uint32(BG_AB_OP_RESOURCES_WARNING)  << uint32(BG_AB_WARNING_SCORE);
352    data << uint32(BG_AB_OP_RESOURCES_ALLY)     << uint32(m_TeamScores[BG_TEAM_ALLIANCE]);
353    data << uint32(BG_AB_OP_RESOURCES_HORDE)    << uint32(m_TeamScores[BG_TEAM_HORDE]);
354
355    // other unknown
356    data << uint32(0x745) << uint32(0x2);           // 37 1861 unk
357}
358
359void BattleGroundAB::_SendNodeUpdate(uint8 node)
360{
361    // Send node owner state update to refresh map icons on client
362    const uint8 plusArray[] = {0, 2, 3, 0, 1};
363
364    if( m_prevNodes[node] )
365        UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_prevNodes[node]], 0);
366    else
367        UpdateWorldState(BG_AB_OP_NODEICONS[node], 0);
368
369    UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_Nodes[node]], 1);
370
371    // How many bases each team owns
372    uint8 ally = 0, horde = 0;
373    for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
374        if( m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED )
375            ++ally;
376        else if( m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED )
377            ++horde;
378
379    UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_ALLY, ally);
380    UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_HORDE, horde);
381}
382
383void BattleGroundAB::_NodeOccupied(uint8 node,Team team)
384{
385   if( !AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team) )
386        sLog.outError("Failed to spawn spirit guide! point: %u, team: %u,", node, team);
387
388    uint8 capturedNodes = 0;
389    for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
390    {
391        if( m_Nodes[node] == GetTeamIndexByTeamId(team) + BG_AB_NODE_TYPE_OCCUPIED && !m_NodeTimers[i])
392            ++capturedNodes;
393    }
394    if(capturedNodes >= 5)
395        CastSpellOnTeam(SPELL_AB_QUEST_REWARD_5_BASES, team);
396    if(capturedNodes >= 4)
397        CastSpellOnTeam(SPELL_AB_QUEST_REWARD_4_BASES, team);
398}
399
400void BattleGroundAB::_NodeDeOccupied(uint8 node)
401{
402    if( node >= BG_AB_DYNAMIC_NODES_COUNT)
403        return;
404
405    // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard
406    std::vector<uint64> ghost_list = m_ReviveQueue[m_BgCreatures[node]];
407    if( !ghost_list.empty() )
408    {
409        WorldSafeLocsEntry const *ClosestGrave = NULL;
410        Player *plr;
411        for (std::vector<uint64>::iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr)
412        {
413            plr = objmgr.GetPlayer(*ghost_list.begin());
414            if( !plr )
415                continue;
416            if( !ClosestGrave )
417                ClosestGrave = GetClosestGraveYard(plr->GetPositionX(), plr->GetPositionY(), plr->GetPositionZ(), plr->GetTeam());
418
419            plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation());
420        }
421    }
422
423     if( m_BgCreatures[node] )
424        DelCreature(node);
425
426    // buff object isn't despawned
427}
428
429/* Invoked if a player used a banner as a gameobject */
430void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*target_obj*/)
431{
432    if( GetStatus() != STATUS_IN_PROGRESS )
433        return;
434
435    uint8 node = BG_AB_NODE_STABLES;
436    GameObject* obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+7]);
437    while ( (node < BG_AB_DYNAMIC_NODES_COUNT) && ((!obj) || (!source->IsWithinDistInMap(obj,10))))
438    {
439        ++node;
440        obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+BG_AB_OBJECT_AURA_CONTESTED]);
441    }
442
443    if( node == BG_AB_DYNAMIC_NODES_COUNT)
444    {
445        // this means our player isn't close to any of banners - maybe cheater ??
446        return;
447    }
448
449    uint8 teamIndex = GetTeamIndexByTeamId(source->GetTeam());
450
451    // Message to chatlog
452    char buf[256];
453    uint8 type = (teamIndex == 0) ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
454
455    // Check if player really could use this banner, not cheated
456    if( !(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2) )
457        return;
458
459    source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
460    uint32 sound = 0;
461    // If node is neutral, change to contested
462    if( m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL )
463    {
464        UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
465        m_prevNodes[node] = m_Nodes[node];
466        m_Nodes[node] = teamIndex + 1;
467        // burn current neutral banner
468        _DelBanner(node, BG_AB_NODE_TYPE_NEUTRAL, 0);
469        // create new contested banner
470        _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
471        _SendNodeUpdate(node);
472        m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
473        sprintf(buf, GetMangosString(LANG_BG_AB_NODE_CLAIMED), _GetNodeName(node), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE));
474        sound = SOUND_NODE_CLAIMED;
475    }
476    // If node is contested
477    else if( (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED) )
478    {
479        // If last state is NOT occupied, change node to enemy-contested
480        if( m_prevNodes[node] < BG_AB_NODE_TYPE_OCCUPIED )
481        {
482            UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
483            m_prevNodes[node] = m_Nodes[node];
484            m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
485            // burn current contested banner
486            _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
487            // create new contested banner
488            _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
489            _SendNodeUpdate(node);
490            m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
491            sprintf(buf, GetMangosString(LANG_BG_AB_NODE_ASSAULTED), _GetNodeName(node));
492        }
493        // If contested, change back to occupied
494        else
495        {
496            UpdatePlayerScore(source, SCORE_BASES_DEFENDED, 1);
497            m_prevNodes[node] = m_Nodes[node];
498            m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_OCCUPIED;
499            // burn current contested banner
500            _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
501            // create new occupied banner
502            _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
503            _SendNodeUpdate(node);
504            m_NodeTimers[node] = 0;
505            _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE);
506            sprintf(buf, GetMangosString(LANG_BG_AB_NODE_DEFENDED), _GetNodeName(node));
507        }
508        sound = (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE;
509    }
510    // If node is occupied, change to enemy-contested
511    else
512    {
513        UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
514        m_prevNodes[node] = m_Nodes[node];
515        m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
516        // burn current occupied banner
517        _DelBanner(node, BG_AB_NODE_TYPE_OCCUPIED, !teamIndex);
518        // create new contested banner
519        _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
520        _SendNodeUpdate(node);
521        _NodeDeOccupied(node);
522        m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
523        sprintf(buf, GetMangosString(LANG_BG_AB_NODE_ASSAULTED), _GetNodeName(node));
524        sound = (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE;
525    }
526    WorldPacket data;
527    ChatHandler::FillMessageData(&data, source->GetSession(), type, LANG_UNIVERSAL, NULL, source->GetGUID(), buf, NULL);
528    SendPacketToAll(&data);
529    // If node is occupied again, send "X has taken the Y" msg.
530    if( m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED )
531    {
532        sprintf(buf, GetMangosString(LANG_BG_AB_NODE_TAKEN), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE), _GetNodeName(node));
533        ChatHandler::FillMessageData(&data, NULL, type, LANG_UNIVERSAL, NULL, 0, buf, NULL);
534        SendPacketToAll(&data);
535    }
536    PlaySoundToAll(sound);
537}
538
539bool BattleGroundAB::SetupBattleGround()
540{
541    for (int i = 0 ; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
542    {
543        if(    !AddObject(BG_AB_OBJECT_BANNER_NEUTRAL + 8*i,BG_AB_OBJECTID_NODE_BANNER_0 + i,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
544            || !AddObject(BG_AB_OBJECT_BANNER_CONT_A + 8*i,BG_AB_OBJECTID_BANNER_CONT_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
545            || !AddObject(BG_AB_OBJECT_BANNER_CONT_H + 8*i,BG_AB_OBJECTID_BANNER_CONT_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
546            || !AddObject(BG_AB_OBJECT_BANNER_ALLY + 8*i,BG_AB_OBJECTID_BANNER_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
547            || !AddObject(BG_AB_OBJECT_BANNER_HORDE + 8*i,BG_AB_OBJECTID_BANNER_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
548            || !AddObject(BG_AB_OBJECT_AURA_ALLY + 8*i,BG_AB_OBJECTID_AURA_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
549            || !AddObject(BG_AB_OBJECT_AURA_HORDE + 8*i,BG_AB_OBJECTID_AURA_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
550            || !AddObject(BG_AB_OBJECT_AURA_CONTESTED + 8*i,BG_AB_OBJECTID_AURA_C,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
551        )
552        {
553            sLog.outErrorDb("BatteGroundAB: Failed to spawn some object BattleGround not created!");
554            return false;
555        }
556    }
557    if(    !AddObject(BG_AB_OBJECT_GATE_A,BG_AB_OBJECTID_GATE_A,BG_AB_DoorPositions[0][0],BG_AB_DoorPositions[0][1],BG_AB_DoorPositions[0][2],BG_AB_DoorPositions[0][3],BG_AB_DoorPositions[0][4],BG_AB_DoorPositions[0][5],BG_AB_DoorPositions[0][6],BG_AB_DoorPositions[0][7],RESPAWN_IMMEDIATELY)
558        || !AddObject(BG_AB_OBJECT_GATE_H,BG_AB_OBJECTID_GATE_H,BG_AB_DoorPositions[1][0],BG_AB_DoorPositions[1][1],BG_AB_DoorPositions[1][2],BG_AB_DoorPositions[1][3],BG_AB_DoorPositions[1][4],BG_AB_DoorPositions[1][5],BG_AB_DoorPositions[1][6],BG_AB_DoorPositions[1][7],RESPAWN_IMMEDIATELY)
559        )
560    {
561        sLog.outErrorDb("BatteGroundAB: Failed to spawn door object BattleGround not created!");
562        return false;
563    }
564    //buffs
565    for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
566    {
567        if(    !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i, Buff_Entries[0], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
568            || !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 1, Buff_Entries[1], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
569            || !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 2, Buff_Entries[2], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
570            )
571            sLog.outErrorDb("BatteGroundAB: Failed to spawn buff object!");
572    }
573
574    return true;
575}
576
577void BattleGroundAB::ResetBGSubclass()
578{
579    m_TeamScores[BG_TEAM_ALLIANCE]          = 0;
580    m_TeamScores[BG_TEAM_HORDE]             = 0;
581    m_lastTick[BG_TEAM_ALLIANCE]            = 0;
582    m_lastTick[BG_TEAM_HORDE]               = 0;
583    m_HonorScoreTics[BG_TEAM_ALLIANCE]      = 0;
584    m_HonorScoreTics[BG_TEAM_HORDE]         = 0;
585    m_ReputationScoreTics[BG_TEAM_ALLIANCE] = 0;
586    m_ReputationScoreTics[BG_TEAM_HORDE]    = 0;
587    m_IsInformedNearVictory                 = false;
588    for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
589    {
590        m_Nodes[i] = 0;
591        m_prevNodes[i] = 0;
592        m_NodeTimers[i] = 0;
593        m_BannerTimers[i].timer = 0;
594    }
595
596    for (uint8 i = 0; i < BG_AB_ALL_NODES_COUNT; ++i)
597        if(m_BgCreatures[i])
598            DelCreature(i);
599}
600
601WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(float x, float y, float /*z*/, uint32 team)
602{
603    uint8 teamIndex = GetTeamIndexByTeamId(team);
604
605    // Is there any occupied node for this team?
606    std::vector<uint8> nodes;
607    for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
608        if( m_Nodes[i] == teamIndex + 3 )
609            nodes.push_back(i);
610
611    WorldSafeLocsEntry const* good_entry = NULL;
612    // If so, select the closest node to place ghost on
613    if( !nodes.empty() )
614    {
615        float mindist = 999999.0f;
616        for (uint8 i = 0; i < nodes.size(); ++i)
617        {
618            WorldSafeLocsEntry const*entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[nodes[i]] );
619            if( !entry )
620                continue;
621            float dist = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y);
622            if( mindist > dist )
623            {
624                mindist = dist;
625                good_entry = entry;
626            }
627        }
628        nodes.clear();
629    }
630    // If not, place ghost on starting location
631    if( !good_entry )
632        good_entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[teamIndex+5] );
633
634    return good_entry;
635}
636
637void BattleGroundAB::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
638{
639    std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
640
641    if( itr == m_PlayerScores.end() )                         // player not found...
642        return;
643
644    switch(type)
645    {
646        case SCORE_BASES_ASSAULTED:
647            ((BattleGroundABScore*)itr->second)->BasesAssaulted += value;
648            break;
649        case SCORE_BASES_DEFENDED:
650            ((BattleGroundABScore*)itr->second)->BasesDefended += value;
651            break;
652        default:
653            BattleGround::UpdatePlayerScore(Source,type,value);
654            break;
655    }
656}
Note: See TracBrowser for help on using the browser.