root/trunk/src/game/BattleGroundHandler.cpp @ 6

Revision 2, 21.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

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 "Common.h"
20#include "WorldPacket.h"
21#include "Opcodes.h"
22#include "Log.h"
23#include "Player.h"
24#include "ObjectMgr.h"
25#include "WorldSession.h"
26#include "MapManager.h"
27#include "ObjectAccessor.h"
28#include "Object.h"
29#include "BattleGroundMgr.h"
30#include "BattleGroundWS.h"
31#include "BattleGround.h"
32
33void WorldSession::HandleBattleGroundHelloOpcode( WorldPacket & recv_data )
34{
35    CHECK_PACKET_SIZE(recv_data, 8);
36
37    uint64 guid;
38    recv_data >> guid;
39    sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from: " I64FMT, guid);
40
41    Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
42    if(!unit)
43        return;
44
45    if(!unit->isBattleMaster())                             // it's not battlemaster
46        return;
47
48    // Stop the npc if moving
49    unit->StopMoving();
50
51    uint32 bgTypeId = objmgr.GetBattleMasterBG(unit->GetEntry());
52
53    if(!_player->GetBGAccessByLevel(bgTypeId))
54    {
55                                                            // temp, must be gossip message...
56        SendNotification("You don't meet Battleground level requirements");
57        return;
58    }
59
60    SendBattlegGroundList(guid, bgTypeId);
61}
62
63void WorldSession::SendBattlegGroundList( uint64 guid, uint32 bgTypeId )
64{
65    WorldPacket data;
66    sBattleGroundMgr.BuildBattleGroundListPacket(&data, guid, _player, bgTypeId);
67    SendPacket( &data );
68}
69
70void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
71{
72    CHECK_PACKET_SIZE(recv_data, 8+4+4+1);
73
74    uint64 guid;
75    uint32 bgTypeId;
76    uint32 instanceId;
77    uint8 joinAsGroup;
78
79    recv_data >> guid;                                      // battlemaster guid
80    recv_data >> bgTypeId;                                  // battleground type id (DBC id)
81    recv_data >> instanceId;                                // instance id, 0 if First Available selected
82    recv_data >> joinAsGroup;                               // join as group
83
84    sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from: " I64FMT " for BG (Type: %u)", guid, bgTypeId);
85
86    if(bgTypeId >= MAX_BATTLEGROUND_TYPES)                  // cheating?
87        return;
88
89    // ignore if we already in BG or BG queue
90    if(_player->InBattleGround())
91        return;
92
93    Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
94    if(!unit)
95        return;
96
97    if(!unit->isBattleMaster())                             // it's not battlemaster
98        return;
99
100    // check Deserter debuff
101    if( !_player->CanJoinToBattleground() )
102    {
103        WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
104        data << (uint32) 0xFFFFFFFE;
105        _player->GetSession()->SendPacket(&data);
106        return;
107    }
108
109    // check existence
110    BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);
111    if(!bg)
112        return;
113
114    if(joinAsGroup && _player->GetGroup())
115    {
116        Group *grp = _player->GetGroup();
117        for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
118        {
119            Player *member = itr->getSource();
120            if(!member) continue;
121
122            if( !member->CanJoinToBattleground() )
123            {
124                WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
125                data << (uint32) 0xFFFFFFFE;
126                _player->GetSession()->SendPacket(&data);
127                continue;
128            }
129            if (member->InBattleGroundQueueForBattleGroundType(bgTypeId))
130                //player is already in this queue
131                continue;
132
133            WorldPacket data;
134                                                            // add to queue
135            uint32 queueSlot = member->AddBattleGroundQueueId(bgTypeId);
136            if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
137            {
138                // fill data packet
139                //member->GetSession()->SendPacket(data);
140                continue;
141            }
142
143            // store entry point coords (same as leader entry point)
144            member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
145
146                                                            // send status packet (in queue)
147            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
148            member->GetSession()->SendPacket(&data);
149            sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
150            member->GetSession()->SendPacket(&data);
151            sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddPlayer(member, bgTypeId);
152        }
153    }
154    else
155    {
156        if (_player->InBattleGroundQueueForBattleGroundType(bgTypeId))
157            //player is already in this queue
158            return;
159        uint32 queueSlot = _player->AddBattleGroundQueueId(bgTypeId);
160        if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
161        {
162            WorldPacket data;
163            // fill data packet
164            //SendPacket(data);
165            return;
166        }
167
168        // store entry point coords
169        _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
170
171        WorldPacket data;
172                                                            // send status packet (in queue)
173        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
174        SendPacket(&data);
175        sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddPlayer(_player, bgTypeId);
176    }
177}
178
179void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv_data*/ )
180{
181                                                            // empty opcode
182    sLog.outDebug("WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message");
183
184    BattleGround *bg = _player->GetBattleGround();
185    if(!bg)                                                 // can't be received if player not in battleground
186        return;
187
188    if(bg->GetTypeID() == BATTLEGROUND_WS)
189    {
190        uint32 count1 = 0;
191        uint32 count2 = 0;
192
193        Player *ap = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID());
194        if(ap) ++count2;
195
196        Player *hp = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetHordeFlagPickerGUID());
197        if(hp) ++count2;
198
199        WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4+16*count1+16*count2));
200        data << count1;                                     // alliance flag holders count
201        /*for(uint8 i = 0; i < count1; i++)
202        {
203            data << uint64(0);                              // guid
204            data << (float)0;                               // x
205            data << (float)0;                               // y
206        }*/
207        data << count2;                                     // horde flag holders count
208        if(ap)
209        {
210            data << (uint64)ap->GetGUID();
211            data << (float)ap->GetPositionX();
212            data << (float)ap->GetPositionY();
213        }
214        if(hp)
215        {
216            data << (uint64)hp->GetGUID();
217            data << (float)hp->GetPositionX();
218            data << (float)hp->GetPositionY();
219        }
220
221        SendPacket(&data);
222    }
223}
224
225void WorldSession::HandleBattleGroundPVPlogdataOpcode( WorldPacket & /*recv_data*/ )
226{
227    sLog.outDebug( "WORLD: Recvd MSG_PVP_LOG_DATA Message");
228
229    BattleGround *bg = _player->GetBattleGround();
230    if(!bg)
231        return;
232
233    WorldPacket data;
234    sBattleGroundMgr.BuildPvpLogDataPacket(&data, bg);
235    SendPacket(&data);
236
237    sLog.outDebug( "WORLD: Sent MSG_PVP_LOG_DATA Message");
238}
239
240void WorldSession::HandleBattleGroundListOpcode( WorldPacket &recv_data )
241{
242    CHECK_PACKET_SIZE(recv_data, 4);
243
244    sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message");
245
246    uint32 bgTypeId;
247    recv_data >> bgTypeId;                                  // id from DBC
248
249    if(bgTypeId >= MAX_BATTLEGROUND_TYPES)                  // cheating?
250        return;
251
252    // can't be received if player not in BG queue
253    if(!_player->InBattleGroundQueueForBattleGroundType(bgTypeId))
254        return;
255
256    BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
257
258    if(!bl)
259        return;
260
261    WorldPacket data;
262    sBattleGroundMgr.BuildBattleGroundListPacket(&data, _player->GetGUID(), _player, bgTypeId);
263    SendPacket( &data );
264}
265
266void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
267{
268    CHECK_PACKET_SIZE(recv_data, 1+1+4+2+1);
269
270    sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message");
271
272    uint8 unk1;
273    uint8 unk2;                                             // unk, can be 0x0 (may be if was invited?) and 0x1
274    uint32 bgTypeId;                                        // type id from dbc
275    uint16 unk;                                             // 0x1F90 constant?
276    uint8 action;                                           // enter battle 0x1, leave queue 0x0
277
278    recv_data >> unk1 >> unk2 >> bgTypeId >> unk >> action;
279
280    if(bgTypeId >= MAX_BATTLEGROUND_TYPES)                  // cheating?
281        return;
282
283    if(!_player->InBattleGroundQueueForBattleGroundType(bgTypeId))
284        return;
285
286    BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);
287    if(!bg)
288        return;
289
290    uint32 queueSlot = 0;
291    WorldPacket data;
292    switch(action)
293    {
294        case 1:                                             // port to battleground
295            // cheating?
296            if(!_player->IsInvitedForBattleGroundType(bgTypeId))
297                return;
298
299            // check if player is not deserter
300            if( !_player->CanJoinToBattleground() )
301            {
302                WorldPacket data2;
303                data2.Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
304                data2 << (uint32) 0xFFFFFFFE;
305                SendPacket(&data2);
306                return;
307            }
308
309            // if the player is dead, resurrect him before teleport
310            if(!_player->isAlive())
311            {
312                _player->ResurrectPlayer(1.0f,false);
313                _player->SpawnCorpseBones();
314            }
315
316            // leave current group
317            _player->RemoveFromGroup();
318
319            // packet to player about BG status
320            queueSlot = _player->GetBattleGroundQueueIndex(bgTypeId);
321            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
322            _player->GetSession()->SendPacket(&data);
323
324            // remove battleground queue status from BGmgr
325            sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].RemovePlayer(_player->GetGUID(), false);
326
327            // this is still needed here if battleground "jumping" shouldn't add deserter debuff
328            // also this required to prevent stuck at old battleground after SetBattleGroundId set to new
329            if (BattleGround *currentBg = _player->GetBattleGround())
330                currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
331
332            _player->SetBattleGroundId(bg->GetTypeID());
333            sBattleGroundMgr.SendToBattleGround(_player, bgTypeId);
334            bg->AddPlayer(_player);
335            break;
336        case 0:                                             // leave queue
337            queueSlot = _player->GetBattleGroundQueueIndex(bgTypeId);
338            _player->RemoveBattleGroundQueueId(bgTypeId);   // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
339            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
340            sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].RemovePlayer(_player->GetGUID(), true);
341            SendPacket(&data);
342            break;
343        default:
344            sLog.outError("Battleground port: unknown action %u", action);
345            break;
346    }
347}
348
349void WorldSession::HandleBattleGroundLeaveOpcode( WorldPacket & /*recv_data*/ )
350{
351    //CHECK_PACKET_SIZE(recv_data, 1+1+4+2);
352
353    sLog.outDebug( "WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message");
354
355    //uint8 unk1, unk2;
356    //uint32 bgTypeId;                                        // id from DBC
357    //uint16 unk3;
358
359    //recv_data >> unk1 >> unk2 >> bgTypeId >> unk3; - no used currently
360
361    //if(bgTypeId >= MAX_BATTLEGROUND_TYPES)                  // cheating? but not important in this case
362    //    return;
363
364    // not allow leave battleground in combat
365    if(_player->isInCombat())
366        if(BattleGround* bg = _player->GetBattleGround())
367            if(bg->GetStatus() != STATUS_WAIT_LEAVE)
368                return;
369
370    _player->LeaveBattleground();
371}
372
373void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
374{
375    // empty opcode
376    sLog.outDebug( "WORLD: Battleground status" );
377
378    WorldPacket data;
379
380    // TODO: we must put player back to battleground in case disconnect (< 5 minutes offline time) or teleport player on login(!) from battleground map to entry point
381    if(_player->InBattleGround())
382    {
383        BattleGround *bg = _player->GetBattleGround();
384        if(bg)
385        {
386            uint32 queueSlot = _player->GetBattleGroundQueueIndex(bg->GetTypeID());
387            if((bg->GetStatus() <= STATUS_IN_PROGRESS))
388            {
389                sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
390                SendPacket(&data);
391            }
392            for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
393            {
394                uint32 queue_id = _player->GetBattleGroundQueueId(i);
395                if (i == queueSlot || !queue_id)
396                    continue;
397                BattleGround *bg2 = sBattleGroundMgr.GetBattleGround(queue_id);
398                if(bg2)
399                {
400                    //in this call is small bug, this call should be filled by player's waiting time in queue
401                    //this call nulls all timers for client :
402                    sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0);
403                    SendPacket(&data);
404                }
405            }
406        }
407    }
408    else
409    {
410        // we should update all queues? .. i'm not sure if this code is correct
411        for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
412        {
413            if(uint32 queue_id = _player->GetBattleGroundQueueId(i))
414            {
415                if(BattleGround *bg = sBattleGroundMgr.GetBattleGround(queue_id))
416                {
417                    sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0);
418                    SendPacket(&data);
419                }
420            }
421        }
422    }
423}
424
425void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data )
426{
427    sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY");
428
429    CHECK_PACKET_SIZE(recv_data, 8);
430
431    BattleGround *bg = _player->GetBattleGround();
432    if(!bg)
433        return;
434
435    uint64 guid;
436    recv_data >> guid;
437
438    Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
439    if(!unit)
440        return;
441
442    if(!unit->isSpiritService())                            // it's not spirit service
443        return;
444
445    sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, guid);
446}
447
448void WorldSession::HandleAreaSpiritHealerQueueOpcode( WorldPacket & recv_data )
449{
450    sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE");
451
452    CHECK_PACKET_SIZE(recv_data, 8);
453
454    BattleGround *bg = _player->GetBattleGround();
455    if(!bg)
456        return;
457
458    uint64 guid;
459    recv_data >> guid;
460
461    Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
462    if(!unit)
463        return;
464
465    if(!unit->isSpiritService())                            // it's not spirit service
466        return;
467
468    bg->AddPlayerToResurrectQueue(guid, _player->GetGUID());
469}
470
471void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
472{
473    CHECK_PACKET_SIZE(recv_data, 8+1+1+1);
474
475    sLog.outDebug("WORLD: CMSG_BATTLEMASTER_JOIN_ARENA");
476    recv_data.hexlike();
477
478    // ignore if we already in BG or BG queue
479    if(_player->InBattleGround())
480        return;
481
482    for(int qId = 0; qId < PLAYER_MAX_BATTLEGROUND_QUEUES; ++qId)
483    {
484        if(_player->GetBattleGroundQueueId(qId) != 0)
485            return;
486    }
487
488    uint64 guid;                                            // arena Battlemaster guid
489    uint8 type;                                             // 2v2, 3v3 or 5v5
490    uint8 asGroup;                                          // asGroup
491    uint8 isRated;                                          // isRated
492    recv_data >> guid >> type >> asGroup >> isRated;
493
494    Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
495    if(!unit)
496        return;
497
498    if(!unit->isBattleMaster())                             // it's not battle master
499        return;
500
501    uint8 arenatype = 0;
502
503    switch(type)
504    {
505        case 0:
506            arenatype = ARENA_TYPE_2v2;
507            break;
508        case 1:
509            arenatype = ARENA_TYPE_3v3;
510            break;
511        case 2:
512            arenatype = ARENA_TYPE_5v5;
513            break;
514        default:
515            sLog.outError("Unknown arena type %u at HandleBattleGroundArenaJoin()", type);
516            return;
517    }
518
519    if(isRated && !_player->GetArenaTeamId(type))           // player not in arena team of that size
520    {
521        _player->GetSession()->SendNotInArenaTeamPacket(arenatype);
522        return;
523    }
524
525    if(asGroup && !_player->GetGroup())                     // player not in group
526        return;
527
528    // check existence
529    BattleGround *bg = sBattleGroundMgr.GetBattleGround(BATTLEGROUND_AA);
530    if(!bg)
531        return;
532
533    bg->SetArenaType(arenatype);
534    bg->SetRated(isRated);
535
536    if(asGroup && _player->GetGroup())
537    {
538        Group *grp = _player->GetGroup();
539        for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
540        {
541            Player *member = itr->getSource();
542            if(!member) continue;
543
544            /*if (!member->CanJoinToBattleground())
545                //player has deserter aura .. do nothing
546            */
547
548            if (member->InBattleGroundQueueForBattleGroundType(BATTLEGROUND_AA))
549                //player is already in this queue
550                continue;
551
552                                                            // add to queue
553            uint32 queueSlot = member->AddBattleGroundQueueId(BATTLEGROUND_AA);
554            if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
555            {
556                WorldPacket data;
557                //fill data
558                //member->GetSession()->SendPacket(data);
559                continue;
560            }
561
562            // store entry point coords (same as leader entry point)
563            member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
564
565            WorldPacket data;
566            // send status packet (in queue)
567            sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
568            member->GetSession()->SendPacket(&data);
569            sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, BATTLEGROUND_AA);
570            member->GetSession()->SendPacket(&data);
571            sBattleGroundMgr.m_BattleGroundQueues[BATTLEGROUND_AA].AddPlayer(member, BATTLEGROUND_AA);
572        }
573    }
574    else
575    {
576        /*if (!member->CanJoinToBattleground())
577            //player has deserter aura .. do nothing
578        */
579
580        if (_player->InBattleGroundQueueForBattleGroundType(BATTLEGROUND_AA))
581            //player is already in this queue
582            return;
583
584        uint32 queueSlot = _player->AddBattleGroundQueueId(BATTLEGROUND_AA);
585        if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES)
586        {
587            WorldPacket data;
588            //fill data (player is in 3 queues already)
589            //SendPacket(data);
590            return;
591        }
592
593        // store entry point coords
594        _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
595
596        WorldPacket data;
597        // send status packet (in queue)
598        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
599        SendPacket(&data);
600        sBattleGroundMgr.m_BattleGroundQueues[BATTLEGROUND_AA].AddPlayer(_player, BATTLEGROUND_AA);
601    }
602}
603
604void WorldSession::HandleBattleGroundReportAFK( WorldPacket & recv_data )
605{
606    CHECK_PACKET_SIZE(recv_data, 8);
607
608    uint64 playerGuid;
609    recv_data >> playerGuid;
610    Player *reportedPlayer = objmgr.GetPlayer(playerGuid);
611
612    if(!reportedPlayer)
613    {
614        sLog.outDebug("WorldSession::HandleBattleGroundReportAFK: player not found");
615        return;
616    }
617
618    sLog.outDebug("WorldSession::HandleBattleGroundReportAFK: %s reported %s", _player->GetName(), reportedPlayer->GetName());
619
620    reportedPlayer->ReportedAfkBy(_player);
621}
Note: See TracBrowser for help on using the browser.