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

Revision 50, 28.3 kB (checked in by yumileroy, 17 years ago)

[svn] Enabled game events to change the honor and reputation gaining speed in battlegrounds. This is done by a new table in the world database, game_event_battleground_holiday. Structure is the following:
event - id of the game event
bgflag - bitmask, used to set which battleground(s) give extra honor/reputation when the event is active. To add extra honor on a battleground, use 2 bgTypeId as mask. Multiple battlegrounds can be set by logical 'or' ('|') operation.
You will need database data for the table, please check trinitydatabase.org.

Original author: w12x
Date: 2008-10-17 16:36:07-05:00

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