root/trunk/src/arcemu-world/Group.cpp @ 2860

Revision 2860, 32.4 kB (checked in by Vlack, 12 months ago)

Notice: Trunk is now 3.2.0

FIXED: Mail sending (by providing a missing item for the world database, this item is necessary for the client - for the item, thanks goes to Darkgrööm)
FIXED: Battleground selection crash (now the server will queue you on Isle of Conquest - note: this does not mean you can play on it, but it solves the instant crash when players selected it)
FIXED: Glyphs (till we properly implement dual spec)
FIXED: A9 target GUID sending (on flags & UPDATEFLAG_HAS_TARGET - thanks Alleycat)
FIXED: Re-enabled ground targeted spells (on m_targetMask & TARGET_FLAG_DEST_LOCATION - if a spell where you can select the area of its effect crashes the client in the future, we'll revise this part)
FIXED: A9 (actually just moved the already existing code pieces up/down to better suit the required format, but to know the format right, I had looked into Mangos code too, as I haven't got months to figure out the right structure)
FIXED: TaxiMgr::GetGlobalTaxiNodeMask? (index check, as with the new DBCs we have a "to" with value "-1", and when that's used as an uint, it'll result in an index of 255, while the structure is from 0 to 11).
ADDED: Override support (this extends the core with special features for special gameobjects, like what's required for trams and transports, which include features as: "override update fields", "never despawn on same map", "announce on greater range" and "push to player on map entry").
FIXED: static map object pushing (repaired the buffer handling error which duplicated buffer content in a pretty unique way).
ADDED: SQL fixes for Deeprun and Ulduar Trams (retail data, but it works right only with the override system).
UPDATED: UpdateFields?.h
UPDATED: DBCs (thanks Xuni)
UPDATED: Error codes (thanks Hopla)
FIXED: various packets, especially the following ones: character enumeration, mail list, group details (raid difficulty), movement-related packets
FIXED: The display of quest rewards the player can choose from on the quest page before accepting it.
FIXED: A nasty bug when un-equipping an item to a bag and not to the backpack. The problem was that I have missed 2 for loops where the visible items get nulled out on unequip, it erased 17 fields instead of just 2, so it made the character pretty much naked.

  • Property svn:eol-style set to native
  • Property ff set to
    *.cpp = svn:eol-style=native
    Makefile = svn:eol-style=native
    README = svn:eol-style=native
    CHANGELOG = svn:eol-style=native
    LICENSE = svn:eol-style=native
Line 
1/*
2 * ArcEmu MMORPG Server
3 * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
4 * Copyright (C) 2008-2009 <http://www.ArcEmu.org/>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * 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 Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "StdAfx.h"
22
23enum PartyUpdateFlags
24{
25        GROUP_UPDATE_FLAG_NONE                                          = 0,            // 0x00000000
26        GROUP_UPDATE_FLAG_ONLINE                                        = 1,            // 0x00000001  uint8
27        GROUP_UPDATE_FLAG_HEALTH                                        = 2,            // 0x00000002  uint16
28        GROUP_UPDATE_FLAG_MAXHEALTH                                     = 4,            // 0x00000004  uint16
29        GROUP_UPDATE_FLAG_POWER_TYPE                            = 8,            // 0x00000008  uint16
30        GROUP_UPDATE_FLAG_POWER                                         = 16,           // 0x00000010  uint16
31        GROUP_UPDATE_FLAG_MAXPOWER                                      = 32,           // 0x00000020  uint16
32        GROUP_UPDATE_FLAG_LEVEL                                         = 64,           // 0x00000040  uint16
33        GROUP_UPDATE_FLAG_ZONEID                                        = 128,          // 0x00000080  uint16
34        GROUP_UPDATE_FLAG_POSITION                                      = 256,          // 0x00000100  uint16, uint16
35        GROUP_UPDATE_FLAG_PLAYER_AURAS                          = 512,          // 0x00000200  uint64, uint16 for each uint64
36        GROUP_UPDATE_FLAG_PET_GUID                                      = 1024,         // 0x00000400  uint64
37        GROUP_UPDATE_FLAG_PET_NAME                                      = 2048,         // 0x00000800  string
38        GROUP_UPDATE_FLAG_PET_DISPLAYID                         = 4096,         // 0x00001000  uint16
39        GROUP_UPDATE_FLAG_PET_HEALTH                            = 8192,         // 0x00002000  uint16
40        GROUP_UPDATE_FLAG_PET_MAXHEALTH                         = 16384,        // 0x00004000  uint16
41        GROUP_UPDATE_FLAG_PET_POWER_TYPE                        = 32768,        // 0x00008000  uint8
42        GROUP_UPDATE_FLAG_PET_POWER                                     = 65535,        // 0x00010000  uint16
43        GROUP_UPDATE_FLAG_PET_MAXPOWER                          = 131070,       // 0x00020000  uint16
44        GROUP_UPDATE_FLAG_PET_AURAS                                     = 262144,       // 0x00040000  uint64, uint16 for each uint64
45};
46
47enum PartyUpdateFlagGroups
48{
49        GROUP_UPDATE_TYPE_FULL_CREATE                           =       GROUP_UPDATE_FLAG_ONLINE | GROUP_UPDATE_FLAG_HEALTH | GROUP_UPDATE_FLAG_MAXHEALTH |
50                                                                                                        GROUP_UPDATE_FLAG_POWER | GROUP_UPDATE_FLAG_LEVEL |
51                                                                                                        GROUP_UPDATE_FLAG_ZONEID | GROUP_UPDATE_FLAG_MAXPOWER | GROUP_UPDATE_FLAG_POSITION,
52        GROUP_UPDATE_TYPE_FULL_REQUEST_REPLY            =   0x7FFC0BFF,
53};
54
55Group::Group(bool Assign)
56{
57        m_GroupType = GROUP_TYPE_PARTY;  // Always init as party
58
59        // Create initial subgroup
60    memset(m_SubGroups,0, sizeof(SubGroup*)*8);
61        m_SubGroups[0] = new SubGroup(this, 0);
62
63        memset(m_instanceIds, 0, sizeof(uint32) * NUM_MAPS * NUM_INSTANCE_MODES);
64
65        m_Leader = NULL;
66        m_Looter = NULL;
67        m_LootMethod = PARTY_LOOT_GROUP;
68        m_LootThreshold = 2;
69        m_SubGroupCount = 1;
70        m_MemberCount = 0;
71
72        if( Assign )
73        {
74                m_Id = objmgr.GenerateGroupId();
75                ObjectMgr::getSingleton().AddGroup(this);
76        }
77
78        m_dirty=false;
79        m_updateblock=false;
80        m_disbandOnNoMembers = true;
81        memset(m_targetIcons, 0, sizeof(uint64) * 8);
82        m_isqueued=false;
83        m_difficulty=0;
84        m_raiddifficulty=0;
85        m_assistantLeader=m_mainAssist=m_mainTank=NULL;
86#ifdef VOICE_CHAT
87        m_voiceChannelRequested = false;
88        m_voiceChannelId = 0;
89        m_voiceMemberCount = 0;
90        memset(m_voiceMembersList, 0, sizeof(Player*)*41);
91#endif
92}
93
94Group::~Group()
95{
96        for( uint32 j = 0; j < m_SubGroupCount; ++j ) 
97        {
98                SubGroup * sub = GetSubGroup( j );
99                if( sub )
100                        delete sub;
101        }
102
103        ObjectMgr::getSingleton().RemoveGroup(this);
104}
105
106SubGroup::~SubGroup()
107{
108
109}
110
111void SubGroup::RemovePlayer(PlayerInfo * info)
112{
113        m_GroupMembers.erase(info);
114        info->subGroup=-1;
115}
116
117bool SubGroup::AddPlayer(PlayerInfo * info)
118{
119        if(IsFull())
120                return false;
121
122        info->subGroup=(int8)GetID();
123        m_GroupMembers.insert(info);
124        return true;
125}
126
127bool SubGroup::HasMember(uint32 guid)
128{
129        for( GroupMembersSet::iterator itr = m_GroupMembers.begin(); itr != m_GroupMembers.end(); ++itr )
130                if( (*itr) != NULL )
131                        if( (*itr)->guid == guid )
132                                return true;
133
134        return false;
135}
136
137SubGroup * Group::FindFreeSubGroup()
138{
139        for(uint32 i = 0; i < m_SubGroupCount; i++)
140                if(!m_SubGroups[i]->IsFull())
141                        return m_SubGroups[i];
142
143        return NULL;
144}
145
146bool Group::AddMember(PlayerInfo * info, int32 subgroupid/* =-1 */)
147{
148        m_groupLock.Acquire();
149        Player * pPlayer = info->m_loggedInPlayer;
150
151        if(m_isqueued)
152        {
153                m_isqueued=false;
154                BattlegroundManager.RemoveGroupFromQueues(this);
155        }
156
157        if(!IsFull())
158        {
159                SubGroup* subgroup = (subgroupid>0) ? m_SubGroups[subgroupid] : FindFreeSubGroup();
160                if(subgroup == NULL)
161                {
162                        m_groupLock.Release();
163                        return false;
164                }
165
166                if(subgroup->AddPlayer(info))
167                {
168                        if(pPlayer)
169                                sEventMgr.AddEvent(pPlayer,&Player::EventGroupFullUpdate,EVENT_PLAYER_UPDATE,1500,1,EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
170           
171                        m_dirty=true;
172                        ++m_MemberCount;
173                        Update();       // Send group update
174                        if(info->m_Group && info->m_Group != this)
175                                info->m_Group->RemovePlayer(info);
176
177                        if(m_Leader==NULL && info->m_loggedInPlayer)
178                                m_Leader=info;
179
180                        info->m_Group=this;
181                        info->subGroup = (int8)subgroup->GetID();
182
183                        m_groupLock.Release();
184                        return true;
185                }
186                else
187                {
188                        m_groupLock.Release();
189                        info->m_Group=NULL;
190                        info->subGroup=-1;
191                        return false;
192                }
193
194        }
195        else
196        {
197                info->m_Group = NULL;
198                info->subGroup = -1;
199                m_groupLock.Release();
200                return false;
201        }
202}
203
204void Group::SetLeader(Player* pPlayer, bool silent)
205{
206        if( pPlayer != NULL )
207        {
208                m_Leader = pPlayer->getPlayerInfo();
209                m_dirty = true;
210                if( !silent )
211                {
212                        WorldPacket data( SMSG_GROUP_SET_LEADER, pPlayer->GetNameString()->size() + 1 );
213                        data << pPlayer->GetName();
214                        SendPacketToAll( &data );
215                }
216        }
217        Update();
218}
219
220void Group::Update()
221{
222        if( m_updateblock )
223                return;
224
225        Player* pNewLeader = NULL;
226
227        if( m_Leader == NULL || ( m_Leader != NULL && m_Leader->m_loggedInPlayer == NULL ) )
228        {
229                pNewLeader = FindFirstPlayer();
230                if( pNewLeader != NULL )
231                        m_Leader = pNewLeader->getPlayerInfo();
232        }
233
234        if( m_Looter != NULL && m_Looter->m_loggedInPlayer == NULL )
235        {
236                if( pNewLeader == NULL )
237                        pNewLeader = FindFirstPlayer();
238                if( pNewLeader != NULL )
239                        m_Looter = pNewLeader->getPlayerInfo();
240        }
241
242        WorldPacket data( 50 + ( m_MemberCount * 20 ) );
243        GroupMembersSet::iterator itr1, itr2;
244
245        uint32 i = 0, j = 0;
246        uint8 flags;
247        SubGroup *sg1 = NULL;
248        SubGroup *sg2 = NULL;
249        m_groupLock.Acquire();
250
251        for( i = 0; i < m_SubGroupCount; i++ )
252        {
253                sg1 = m_SubGroups[i];
254
255                if( sg1 != NULL)
256                {
257                        for( itr1 = sg1->GetGroupMembersBegin(); itr1 != sg1->GetGroupMembersEnd(); ++itr1 )
258                        {
259                                // should never happen but just in case
260                                if( (*itr1) == NULL )
261                                        continue;
262
263                                /* skip offline players */
264                                if( (*itr1)->m_loggedInPlayer == NULL )
265                                {
266#ifdef VOICE_CHAT
267                                        if( (*itr1)->groupVoiceId >= 0 )
268                                        {
269                                                // remove from voice members since that player is now offline
270                                                RemoveVoiceMember( (*itr1) );
271                                        }
272
273                                        continue;
274                                }
275
276                                if( (*itr1)->groupVoiceId < 0 && sVoiceChatHandler.CanUseVoiceChat() )
277                                {
278                                        (*itr1)->groupVoiceId = 0;
279                                        AddVoiceMember( (*itr1) );
280                                }
281#else
282                                        continue;
283                                }
284#endif
285
286                                data.Initialize(SMSG_GROUP_LIST);
287                                data << uint8(m_GroupType);     //0=party,1=raid
288                                data << uint8(0);   // 1 if battleground group
289                                data << uint8(sg1->GetID());
290                                data << uint8(0);       // unk2
291                                //data << uint64(0);    // unk3
292                                data << uint64(0x500000000004BC0CULL);
293                                data << uint32(m_MemberCount-1);        // we don't include self
294
295                                for( j = 0; j < m_SubGroupCount; j++ )
296                                {
297                                        sg2 = m_SubGroups[j];
298
299                                        if( sg2 != NULL)
300                                        {
301                                                for( itr2 = sg2->GetGroupMembersBegin(); itr2 != sg2->GetGroupMembersEnd(); ++itr2 )
302                                                {
303                                                        if( (*itr1) == (*itr2) )
304                                                                continue;
305
306                                                        // should never happen but just in case
307                                                        if( (*itr2) == NULL )
308                                                                continue;
309
310                                                        data << (*itr2)->name << (*itr2)->guid << uint32(0);    // highguid
311                                                       
312                                                        if( (*itr2)->m_loggedInPlayer != NULL )
313                                                                data << uint8( 1 );
314                                                        else
315                                                                data << uint8( 0 );
316
317                                                        data << uint8( sg2->GetID() );
318                                                       
319                                                        flags = 0;
320
321                                                        if( (*itr2) == m_assistantLeader )
322                                                                flags |= 1;
323                                                        if( (*itr2) == m_mainTank )
324                                                                flags |= 2;
325                                                        if( (*itr2) == m_mainAssist )
326                                                                flags |= 4;
327
328                                                        data << flags;
329                                                }
330                                        }
331                                }
332
333                                if( m_Leader != NULL )
334                                        data << m_Leader->guid << uint32( 0 );
335                                else
336                                        data << uint64( 0 );
337
338                                data << uint8( m_LootMethod );
339
340                                if( m_Looter != NULL )
341                                        data << m_Looter->guid << uint32( 0 );
342                                else
343                                        data << uint64( 0 );
344
345                                data << uint8( m_LootThreshold );
346                                data << uint8( m_difficulty );
347                                data << uint8( m_raiddifficulty );
348
349                                if( !(*itr1)->m_loggedInPlayer->IsInWorld() )
350                                        (*itr1)->m_loggedInPlayer->CopyAndSendDelayedPacket( &data );
351                                else
352                                        (*itr1)->m_loggedInPlayer->GetSession()->SendPacket( &data );
353                        }               
354                }
355        }
356
357        if( m_dirty )
358        {
359                m_dirty = false;
360                SaveToDB();
361        }
362
363        m_groupLock.Release();
364}
365
366void Group::Disband()
367{
368        m_groupLock.Acquire();
369        m_updateblock=true;
370
371        if(m_isqueued)
372        {
373                m_isqueued=false;
374                WorldPacket * data = sChatHandler.FillSystemMessageData("A change was made to your group. Removing the arena queue.");
375                SendPacketToAll(data);
376                delete data;
377
378                BattlegroundManager.RemoveGroupFromQueues(this);
379        }
380
381        uint32 i = 0;
382        for(i = 0; i < m_SubGroupCount; i++)
383        {
384                SubGroup *sg = m_SubGroups[i];
385                sg->Disband();
386        }
387
388        m_groupLock.Release();
389        CharacterDatabase.Execute("DELETE FROM groups WHERE group_id = %u", m_Id);
390        sInstanceMgr.OnGroupDestruction(this);
391        delete this;    // destroy ourselves, the destructor removes from eventmgr and objectmgr.
392}
393
394void SubGroup::Disband()
395{
396        WorldPacket data(SMSG_GROUP_DESTROYED, 1);
397        WorldPacket data2(SMSG_PARTY_COMMAND_RESULT, 12);
398        data2 << uint32(2) << uint8(0) << uint32(m_Parent == NULL ? 0 : m_Parent->m_difficulty);        // you leave the group
399
400        GroupMembersSet::iterator itr = m_GroupMembers.begin();
401        GroupMembersSet::iterator it2;
402        for(; itr != m_GroupMembers.end();)
403        {
404                if( (*itr) != NULL )
405                {
406                        if( (*itr)->m_loggedInPlayer )
407                        {
408                                if( (*itr)->m_loggedInPlayer->GetSession() != NULL )
409                                {
410                                        data2.put(5, uint32((*itr)->m_loggedInPlayer->iInstanceType));
411                                        (*itr)->m_loggedInPlayer->GetSession()->SendPacket(&data2);
412                                        (*itr)->m_loggedInPlayer->GetSession()->SendPacket(&data);
413          (*itr)->m_Group->SendNullUpdate( (*itr)->m_loggedInPlayer ); // cebernic: panel refresh.
414                                       
415                                }
416                        }
417
418                        (*itr)->m_Group = NULL;
419                        (*itr)->subGroup = -1;
420                }
421
422                m_Parent->m_MemberCount--;
423                it2 = itr;
424                ++itr;
425
426                m_GroupMembers.erase(it2);
427        }
428
429        m_Parent->m_SubGroups[m_Id] = NULL;
430        delete this;
431}
432
433Player* Group::FindFirstPlayer()
434{
435        GroupMembersSet::iterator itr;
436        m_groupLock.Acquire();
437
438        for( uint32 i = 0; i < m_SubGroupCount; i++ )
439        {
440                if( m_SubGroups[i] != NULL )
441                {
442                        for( itr = m_SubGroups[i]->GetGroupMembersBegin(); itr != m_SubGroups[i]->GetGroupMembersEnd(); ++itr )
443                        {
444                                if( (*itr) != NULL )
445                                {
446                                        if( (*itr)->m_loggedInPlayer != NULL )
447                                        {
448                                                m_groupLock.Release();
449                                                return (*itr)->m_loggedInPlayer;
450                                        }
451                                }
452                        }
453                }
454        }
455
456        m_groupLock.Release();
457        return NULL;
458}
459
460void Group::RemovePlayer(PlayerInfo * info)
461{
462        WorldPacket data(50);
463        Player * pPlayer = info->m_loggedInPlayer;
464
465        m_groupLock.Acquire();
466        if(m_isqueued)
467        {
468                m_isqueued=false;
469                BattlegroundManager.RemoveGroupFromQueues(this);
470        }
471       
472        SubGroup *sg=NULL;
473        if(info->subGroup >= 0 && info->subGroup <= 8)
474                sg = m_SubGroups[info->subGroup];
475
476        if(sg == NULL || sg->m_GroupMembers.find(info) == sg->m_GroupMembers.end())
477        {
478                for(uint32 i = 0; i < m_SubGroupCount; ++i)
479                {
480                        if(m_SubGroups[i] != NULL)
481                        {
482                                if(m_SubGroups[i]->m_GroupMembers.find(info) != m_SubGroups[i]->m_GroupMembers.end())
483                                {
484                                        sg = m_SubGroups[i];
485                                        break;
486                                }
487                        }
488                }
489        }
490
491        info->m_Group=NULL;
492        info->subGroup=-1;
493#ifdef VOICE_CHAT
494        if( info->groupVoiceId <= 0 )
495                RemoveVoiceMember(info);
496#endif
497
498        if(sg==NULL)
499        {
500                m_groupLock.Release();
501                return;
502        }
503
504        m_dirty=true;
505        sg->RemovePlayer(info);
506        --m_MemberCount;
507
508        if( info->m_loggedInPlayer != NULL )
509        {
510                sInstanceMgr.PlayerLeftGroup( this, info->m_loggedInPlayer );
511                info->m_loggedInPlayer->m_bg = NULL;
512        }
513
514        if( pPlayer != NULL )
515        {
516                if( pPlayer->GetSession() != NULL )
517                {
518                        SendNullUpdate( pPlayer );
519
520                        data.SetOpcode( SMSG_GROUP_DESTROYED );
521                        pPlayer->GetSession()->SendPacket( &data );
522
523                        data.Initialize( SMSG_PARTY_COMMAND_RESULT );
524                        data << uint32(2) << uint8(0) << uint32(0);  // you leave the group
525                        pPlayer->GetSession()->SendPacket( &data );
526                }
527
528                //Remove some party auras.
529                for (uint32 i=MAX_POSITIVE_AURAS_EXTEDED_START;i<MAX_POSITIVE_AURAS_EXTEDED_END;i++)
530                {
531                        if (pPlayer->m_auras[i] && 
532                                pPlayer->m_auras[i]->m_areaAura && 
533                                pPlayer->m_auras[i]->GetUnitCaster() &&
534                                (!pPlayer->m_auras[i]->GetUnitCaster() ||(pPlayer->m_auras[i]->GetUnitCaster()->IsPlayer() && pPlayer!=pPlayer->m_auras[i]->GetUnitCaster())))
535                                pPlayer->m_auras[i]->Remove();
536                }
537        }
538
539        if(m_MemberCount < 2)
540        {
541                if(m_disbandOnNoMembers)
542                {
543                        m_groupLock.Release();
544                        Disband();
545                        return;
546                }
547        }
548
549        /* eek! ;P */
550        Player *newPlayer = NULL;
551        if(m_Looter == info)
552        {
553                newPlayer = FindFirstPlayer();
554                if( newPlayer != NULL )
555            m_Looter = newPlayer->getPlayerInfo();
556                else
557                        m_Looter = NULL;
558        }
559
560        if(m_Leader == info)
561        {
562                if( newPlayer==NULL )
563                        newPlayer=FindFirstPlayer();
564
565                if( newPlayer != NULL )
566                        SetLeader(newPlayer, false);
567                else
568                        m_Leader = NULL;
569        }
570
571        Update();
572        m_groupLock.Release();
573}
574
575void Group::ExpandToRaid()
576{
577        if(m_isqueued)
578        {
579                m_isqueued=false;
580                WorldPacket * data = sChatHandler.FillSystemMessageData("A change was made to your group. Removing the arena queue.");
581                SendPacketToAll(data);
582                delete data;
583
584                BattlegroundManager.RemoveGroupFromQueues(this);
585        }
586        // Very simple ;)
587
588        uint32 i = 1;
589        m_groupLock.Acquire();
590        m_SubGroupCount = 8;
591
592        for(; i < m_SubGroupCount; i++)
593                m_SubGroups[i] = new SubGroup(this, i);
594
595        m_GroupType = GROUP_TYPE_RAID;
596        m_dirty=true;
597        Update();
598        m_groupLock.Release();
599}
600
601void Group::SetLooter(Player *pPlayer, uint8 method, uint16 threshold)
602{ 
603        if( pPlayer != NULL )
604        {
605                m_LootMethod = method;
606                m_Looter = pPlayer->getPlayerInfo();
607                m_LootThreshold  = threshold;
608                m_dirty = true;
609        }
610        Update();
611}
612
613void Group::SendPacketToAllButOne(WorldPacket *packet, Player *pSkipTarget)
614{
615        GroupMembersSet::iterator itr;
616        uint32 i = 0;
617        m_groupLock.Acquire();
618        for(; i < m_SubGroupCount; i++)
619        {
620                for(itr = m_SubGroups[i]->GetGroupMembersBegin(); itr != m_SubGroups[i]->GetGroupMembersEnd(); ++itr)
621                {
622                        if((*itr)->m_loggedInPlayer != NULL && (*itr)->m_loggedInPlayer != pSkipTarget && (*itr)->m_loggedInPlayer->GetSession())
623                                (*itr)->m_loggedInPlayer->GetSession()->SendPacket(packet);
624                }
625        }
626       
627        m_groupLock.Release();
628}
629
630void Group::OutPacketToAllButOne(uint16 op, uint16 len, const void* data, Player *pSkipTarget)
631{
632        GroupMembersSet::iterator itr;
633        uint32 i = 0;
634        m_groupLock.Acquire();
635        for(; i < m_SubGroupCount; i++)
636        {
637                for(itr = m_SubGroups[i]->GetGroupMembersBegin(); itr != m_SubGroups[i]->GetGroupMembersEnd(); ++itr)
638                {
639                        if((*itr)->m_loggedInPlayer != NULL && (*itr)->m_loggedInPlayer != pSkipTarget)
640                                (*itr)->m_loggedInPlayer->GetSession()->OutPacket( op, len, data );
641                }
642        }
643
644        m_groupLock.Release();
645}
646
647bool Group::HasMember(Player * pPlayer)
648{
649        if( !pPlayer )
650                return false;
651
652        GroupMembersSet::iterator itr;
653        m_groupLock.Acquire();
654
655        for( uint32 i = 0; i < m_SubGroupCount; i++ )
656        {
657                if( m_SubGroups[i] != NULL )
658                {
659                        if( m_SubGroups[i]->m_GroupMembers.find( pPlayer->getPlayerInfo() ) != m_SubGroups[i]->m_GroupMembers.end() )
660                        {
661                                m_groupLock.Release();
662                                return true;
663                        }
664                }
665        }
666
667        m_groupLock.Release();
668        return false;
669}
670
671bool Group::HasMember(PlayerInfo * info)
672{
673        GroupMembersSet::iterator itr;
674        uint32 i = 0;
675
676        m_groupLock.Acquire();
677
678        for(; i < m_SubGroupCount; i++)
679        {
680                if(m_SubGroups[i]->m_GroupMembers.find(info) != m_SubGroups[i]->m_GroupMembers.end())
681                {
682                        m_groupLock.Release();
683                        return true;
684                }
685        }
686
687        m_groupLock.Release();
688        return false;
689}
690
691void Group::MovePlayer(PlayerInfo *info, uint8 subgroup)
692{
693        if( subgroup >= m_SubGroupCount )
694                return;
695
696        if(m_SubGroups[subgroup]->IsFull())
697                return;
698
699        m_groupLock.Acquire();
700        SubGroup *sg=NULL;
701
702        if(info->subGroup > 0 && info->subGroup <= 8)
703                sg = m_SubGroups[info->subGroup];
704
705        if(sg == NULL || sg->m_GroupMembers.find(info) == sg->m_GroupMembers.end())
706        {
707                for(uint32 i = 0; i < m_SubGroupCount; ++i)
708                {
709                        if(m_SubGroups[i] != NULL)
710                        {
711                                if(m_SubGroups[i]->m_GroupMembers.find(info) != m_SubGroups[i]->m_GroupMembers.end())
712                                {
713                                        sg = m_SubGroups[i];
714                                        break;
715                                }
716                        }
717                }
718        }
719
720        if(!sg)
721        {
722                m_groupLock.Release();
723                return;
724        }
725       
726        sg->RemovePlayer(info);
727   
728        // Grab the new group, and insert
729        sg = m_SubGroups[subgroup];
730        if(!sg->AddPlayer(info))
731        {
732                RemovePlayer(info);
733                info->m_Group=NULL;
734        }
735        else
736        {
737                info->subGroup=(int8)sg->GetID();
738                info->m_Group=this;
739        }
740
741        Update();
742        m_groupLock.Release();
743}
744
745void Group::SendNullUpdate( Player *pPlayer )
746{
747        // this packet is 24 bytes long.                // AS OF 2.1.0
748        uint8 buffer[24];
749        memset(buffer, 0, 24);
750        pPlayer->GetSession()->OutPacket( SMSG_GROUP_LIST, 24, buffer );
751}
752
753// player is object class because its called from unit class
754void Group::SendPartyKillLog( Object * player, Object * Unit )
755{
756        if( !player || !Unit || !HasMember( static_cast< Player* >( player ) ) )
757                return;
758
759        WorldPacket data( SMSG_PARTYKILLLOG, 16 );
760        data << player->GetGUID();
761        data << Unit->GetGUID();
762        SendPacketToAll( &data );
763}
764
765void Group::LoadFromDB(Field *fields)
766{
767#define LOAD_ASSISTANT(__i, __d) g = fields[__i].GetUInt32(); if(g != 0) { __d = objmgr.GetPlayerInfo(g); }
768
769        uint32 g;
770        m_updateblock=true;
771        m_Id = fields[0].GetUInt32();
772
773        ObjectMgr::getSingleton().AddGroup( this );
774
775        m_GroupType = fields[1].GetUInt8();
776        m_SubGroupCount = fields[2].GetUInt8();
777        m_LootMethod = fields[3].GetUInt8();
778        m_LootThreshold = fields[4].GetUInt8();
779        m_difficulty = fields[5].GetUInt8();
780        m_raiddifficulty = fields[6].GetUInt8();
781
782        LOAD_ASSISTANT(6, m_assistantLeader);
783        LOAD_ASSISTANT(7, m_mainTank);
784        LOAD_ASSISTANT(8, m_mainAssist);
785
786        // create groups
787        for(int i = 1; i < m_SubGroupCount; ++i)
788                m_SubGroups[i] = new SubGroup(this, i);
789
790        // assign players into groups
791        for(int i = 0; i < m_SubGroupCount; ++i)
792        {
793                for(int j = 0; j < 5; ++j)
794                {
795                        uint32 guid = fields[9 + (i*5) + j].GetUInt32();
796                        if( guid == 0 )
797                                continue;
798
799                        PlayerInfo * inf = objmgr.GetPlayerInfo(guid);
800                        if(inf == NULL)
801                                continue;
802
803                        AddMember(inf);
804                        m_dirty=false;
805                }
806        }
807
808        char *ids = strdup(fields[50].GetString());
809        char *q = ids;
810        char *p = strchr(q, ' ');
811        while(p)
812        {
813                char *r = strchr(q, ':');
814                if(r == NULL || r > p)
815                        continue;
816                *p = 0;
817                *r = 0;
818                char *s = strchr(r+1, ':');
819                if(s == NULL || s > p)
820                        continue;
821                *s = 0;
822                uint32 mapId = atoi(q);
823                uint32 mode = atoi(r+1);
824                uint32 instanceId = atoi(s+1);
825
826                if(mapId >= NUM_MAPS)
827                        continue;
828
829                m_instanceIds[mapId][mode] = instanceId;
830
831                q = p+1;
832                p = strchr(q, ' ');
833        }
834        free(ids);
835
836        m_updateblock=false;
837}
838
839void Group::SaveToDB()
840{
841        if(!m_disbandOnNoMembers)       /* don't save bg groups */
842                return;
843
844        std::stringstream ss;
845        //uint32 i = 0;
846        uint32 fillers = 8 - m_SubGroupCount;
847
848        ss << "REPLACE INTO groups VALUES("
849                << m_Id << ","
850                << uint32(m_GroupType) << ","
851                << uint32(m_SubGroupCount) << ","
852                << uint32(m_LootMethod) << ","
853                << uint32(m_LootThreshold) << ","
854                << uint32(m_difficulty) << ","
855                << uint32(m_raiddifficulty) << ",";
856
857        if(m_assistantLeader)
858                ss << m_assistantLeader->guid << ",";
859        else
860                ss << "0,";
861       
862        if(m_mainTank)
863                ss << m_mainTank->guid << ",";
864        else
865                ss << "0,";
866
867        if(m_mainAssist)
868                ss << m_mainAssist->guid << ",";
869        else
870                ss << "0,";
871
872        for(uint32 i = 0; i < m_SubGroupCount; ++i)
873        {
874                uint32 j = 0;
875                for(GroupMembersSet::iterator itr = m_SubGroups[i]->GetGroupMembersBegin(); j<5 && itr != m_SubGroups[i]->GetGroupMembersEnd(); ++j, ++itr)
876                {
877                        ss << (*itr)->guid << ",";
878                }
879
880                for(; j < 5; ++j)
881                        ss << "0,";
882        }
883
884        for(uint32 i = 0; i < fillers; ++i)
885                ss << "0,0,0,0,0,";
886
887        ss << (uint32)UNIXTIME << ",'";
888        for(int i=0; i<NUM_MAPS; i++)
889        {
890                for(int j=0; j<NUM_INSTANCE_MODES; j++)
891                {
892                        if(m_instanceIds[i][j] > 0)
893                        {
894                                ss << i << ":" << j << ":" << m_instanceIds[i][j] << " ";
895                        }
896                }
897        }
898        ss << "')";
899        /*printf("==%s==\n", ss.str().c_str());*/
900        CharacterDatabase.Execute(ss.str().c_str());
901}
902
903void Group::UpdateOutOfRangePlayer(Player * pPlayer, uint32 Flags, bool Distribute, WorldPacket * Packet)
904{
905        uint8 member_flags = 0x01;
906        WorldPacket * data = Packet;
907        if(!Packet)
908                data = new WorldPacket(SMSG_PARTY_MEMBER_STATS, 500);
909
910        if(pPlayer->GetPowerType() != POWER_TYPE_MANA)
911                Flags |= GROUP_UPDATE_FLAG_POWER_TYPE;
912
913        /*Flags |= GROUP_UPDATE_FLAG_PET_NAME;
914        Flags |= GROUP_UPDATE_FLAG_PET_UNK_1;*/
915
916        data->Initialize(SMSG_PARTY_MEMBER_STATS);
917        if((Flags & GROUP_UPDATE_TYPE_FULL_REQUEST_REPLY) == GROUP_UPDATE_TYPE_FULL_REQUEST_REPLY)
918                *data << uint8(0);     
919        *data << pPlayer->GetNewGUID();
920        *data << Flags;
921
922        if(Flags & GROUP_UPDATE_FLAG_ONLINE)
923        {
924                if(pPlayer->IsPvPFlagged())
925                        member_flags |= 0x02;
926                if(pPlayer->getDeathState() == CORPSE)
927                        member_flags |= 0x08;
928                else if(pPlayer->IsDead())
929                        member_flags |= 0x10;
930
931                *data << member_flags << uint8(0);
932        }
933
934        if(Flags & GROUP_UPDATE_FLAG_HEALTH)
935                *data << uint32(pPlayer->GetUInt32Value(UNIT_FIELD_HEALTH));
936
937        if(Flags & GROUP_UPDATE_FLAG_MAXHEALTH)
938                *data << uint32(pPlayer->GetUInt32Value(UNIT_FIELD_MAXHEALTH));
939
940        if(Flags & GROUP_UPDATE_FLAG_POWER_TYPE)
941                *data << uint8(pPlayer->GetPowerType());
942
943        if(Flags & GROUP_UPDATE_FLAG_POWER)
944                *data << uint16(pPlayer->GetUInt32Value(UNIT_FIELD_POWER1 + pPlayer->GetPowerType()));
945
946        if(Flags & GROUP_UPDATE_FLAG_MAXPOWER)
947                *data << uint16(pPlayer->GetUInt32Value(UNIT_FIELD_MAXPOWER1 + pPlayer->GetPowerType()));
948
949        if(Flags & GROUP_UPDATE_FLAG_LEVEL)
950                *data << uint16(pPlayer->getLevel());
951
952        if(Flags & GROUP_UPDATE_FLAG_ZONEID) {
953                *data << uint16(pPlayer->GetAreaID());
954    }
955
956        if(Flags & GROUP_UPDATE_FLAG_POSITION)
957        {
958                *data << int16(pPlayer->GetPositionX()) << int16(pPlayer->GetPositionY());                      // wtf packed floats? O.o
959                pPlayer->m_last_group_position = pPlayer->GetPosition();
960        }
961
962        if(Flags & GROUP_UPDATE_TYPE_FULL_REQUEST_REPLY)
963        {
964                *data << uint64(0xFF00000000000000ULL);
965                *data << uint8(0);
966                *data << uint64(0xFF00000000000000ULL);
967        }
968
969        if(Distribute&&pPlayer->IsInWorld())
970        {
971                Player * plr;
972                float dist = pPlayer->GetMapMgr()->m_UpdateDistance;
973                m_groupLock.Acquire();
974                for(uint32 i = 0; i < m_SubGroupCount; ++i)
975                {
976                        if(m_SubGroups[i]==NULL)
977                                continue;
978
979                        for(GroupMembersSet::iterator itr = m_SubGroups[i]->GetGroupMembersBegin(); itr != m_SubGroups[i]->GetGroupMembersEnd();)
980                        {
981                                plr = (*itr)->m_loggedInPlayer;
982                                ++itr;
983
984                                if(plr && plr != pPlayer)
985                                {
986                                        if(plr->GetDistance2dSq(pPlayer) > dist)
987                                                plr->GetSession()->SendPacket(data);
988                                }
989                        }
990                }
991                m_groupLock.Release();
992        }
993
994        if(!Packet)
995                delete data;
996}
997
998void Group::UpdateAllOutOfRangePlayersFor(Player * pPlayer)
999{
1000        WorldPacket data(150);
1001        WorldPacket data2(150);
1002
1003        if(m_SubGroupCount>8)
1004                return;
1005
1006        /* tell the other players about us */
1007        UpdateOutOfRangePlayer(pPlayer, GROUP_UPDATE_TYPE_FULL_CREATE, true, &data2);
1008
1009        /* tell us any other players we don't know about */
1010        Player * plr;
1011        bool u1, u2;
1012        UpdateMask myMask;
1013        myMask.SetCount(PLAYER_END);
1014        UpdateMask hisMask;
1015        hisMask.SetCount(PLAYER_END);
1016
1017        m_groupLock.Acquire();
1018        for(uint32 i = 0; i < m_SubGroupCount; ++i)
1019        {
1020                if(m_SubGroups[i]==NULL)
1021                        continue;
1022
1023                for(GroupMembersSet::iterator itr = m_SubGroups[i]->GetGroupMembersBegin(); itr != m_SubGroups[i]->GetGroupMembersEnd(); ++itr)
1024                {
1025                        plr = (*itr)->m_loggedInPlayer;
1026                        if(!plr || plr == pPlayer) continue;
1027
1028                        if(!plr->IsVisible(pPlayer))
1029                        {
1030                                UpdateOutOfRangePlayer(plr, GROUP_UPDATE_TYPE_FULL_CREATE, false, &data);
1031                                pPlayer->GetSession()->SendPacket(&data);
1032                        }
1033                        else
1034                        {
1035                                if(pPlayer->GetSubGroup() == plr->GetSubGroup())
1036                                {
1037                                        /* distribute quest fields to other players */
1038                                        hisMask.Clear();
1039                                        myMask.Clear();
1040                                        u1 = u2 = false;
1041                                        for(uint32 i = PLAYER_QUEST_LOG_1_1; i < PLAYER_QUEST_LOG_25_1; ++i)
1042                                        {
1043                                                if(plr->GetUInt32Value(i))
1044                                                {
1045                                                        hisMask.SetBit(i);
1046                                                        u1 = true;
1047                                                }
1048
1049                                                if(pPlayer->GetUInt32Value(i))
1050                                                {
1051                                                        u2 = true;
1052                                                        myMask.SetBit(i);
1053                                                }
1054                                        }
1055
1056                                        if(u1)
1057                                        {
1058                                                data.clear();
1059                        plr->BuildValuesUpdateBlockForPlayer(&data, &hisMask);
1060                                                pPlayer->PushUpdateData(&data, 1);
1061                                        }
1062
1063                                        if(u2)
1064                                        {
1065                                                data.clear();
1066                                                pPlayer->BuildValuesUpdateBlockForPlayer(&data, &myMask);
1067                                                plr->PushUpdateData(&data, 1);
1068                                        }
1069                                }
1070                        }
1071                }
1072        }
1073
1074        m_groupLock.Release();
1075}
1076
1077void Group::HandleUpdateFieldChange(uint32 Index, Player * pPlayer)
1078{
1079        uint32 Flags = 0;
1080        m_groupLock.Acquire();
1081        switch(Index)
1082        {
1083        case UNIT_FIELD_HEALTH:
1084                Flags = GROUP_UPDATE_FLAG_HEALTH;
1085                break;
1086               
1087        case UNIT_FIELD_MAXHEALTH:
1088                Flags = GROUP_UPDATE_FLAG_MAXHEALTH;
1089                break;
1090
1091        case UNIT_FIELD_POWER1:
1092        case UNIT_FIELD_POWER2:
1093        case UNIT_FIELD_POWER3:
1094        case UNIT_FIELD_POWER4:
1095        case UNIT_FIELD_POWER7:
1096                Flags = GROUP_UPDATE_FLAG_POWER;
1097                break;
1098
1099        case UNIT_FIELD_MAXPOWER1:
1100        case UNIT_FIELD_MAXPOWER2:
1101        case UNIT_FIELD_MAXPOWER3:
1102        case UNIT_FIELD_MAXPOWER4:
1103        case UNIT_FIELD_MAXPOWER7:
1104                Flags = GROUP_UPDATE_FLAG_MAXPOWER;
1105                break;
1106
1107        case UNIT_FIELD_LEVEL:
1108                Flags = GROUP_UPDATE_FLAG_LEVEL;
1109                break;
1110        default:
1111                break;
1112        }
1113
1114        if( Flags != 0 )
1115                UpdateOutOfRangePlayer( pPlayer, Flags, true, 0 );
1116
1117        m_groupLock.Release();
1118}
1119
1120void Group::HandlePartialChange(uint32 Type, Player * pPlayer)
1121{
1122        uint32 Flags = 0;
1123        m_groupLock.Acquire();
1124
1125        switch(Type)
1126        {
1127        case PARTY_UPDATE_FLAG_POSITION:
1128                Flags = GROUP_UPDATE_FLAG_POSITION;
1129                break;
1130
1131        case PARTY_UPDATE_FLAG_ZONEID:
1132                Flags = GROUP_UPDATE_FLAG_ZONEID;
1133                break;
1134        }
1135
1136        if(Flags)
1137                UpdateOutOfRangePlayer(pPlayer, Flags, true, 0);
1138
1139        m_groupLock.Release();
1140}
1141
1142void WorldSession::HandlePartyMemberStatsOpcode(WorldPacket & recv_data)
1143{
1144        if(!_player->IsInWorld())
1145                return;
1146
1147        uint64 guid;
1148        recv_data >> guid;
1149
1150        Player * plr = _player->GetMapMgr()->GetPlayer((uint32)guid);
1151
1152        if(!_player->GetGroup() || !plr)
1153                return;
1154
1155        WorldPacket data(200);
1156        if(!_player->GetGroup()->HasMember(plr))
1157                return;                 // invalid player
1158
1159        if(_player->IsVisible(plr))
1160                return;
1161
1162        _player->GetGroup()->UpdateOutOfRangePlayer(plr, GROUP_UPDATE_TYPE_FULL_CREATE | GROUP_UPDATE_TYPE_FULL_REQUEST_REPLY, false, &data);
1163        data.SetOpcode(SMSG_PARTY_MEMBER_STATS_FULL);
1164        SendPacket(&data);
1165}
1166
1167Group* Group::Create()
1168{
1169        return new Group(true);
1170}
1171
1172void Group::SetMainAssist(PlayerInfo * pMember)
1173{
1174        if(m_mainAssist==pMember)
1175                return;
1176
1177        m_mainAssist = pMember;
1178        m_dirty = true;
1179        Update();
1180}
1181
1182void Group::SetMainTank(PlayerInfo * pMember)
1183{
1184        if(m_mainTank==pMember)
1185                return;
1186
1187        m_mainTank=pMember;
1188        m_dirty = true;
1189        Update();
1190}
1191
1192void Group::SetAssistantLeader(PlayerInfo * pMember)
1193{
1194        if(m_assistantLeader == pMember)
1195                return;
1196
1197        m_assistantLeader = pMember;
1198        m_dirty = true;
1199        Update();
1200}
1201
1202
1203/************************************************************************/
1204/* Voicechat                                                            */
1205/************************************************************************/
1206#ifdef VOICE_CHAT
1207
1208void Group::CreateVoiceSession()
1209{
1210        sVoiceChatHandler.CreateGroupChannel( this );
1211}
1212
1213void Group::VoiceChannelCreated(uint16 id)
1214{
1215        Log.Debug("Group", "voicechannelcreated: id %u", (uint32)id);
1216        m_voiceChannelId = id;
1217        if( id != 0 )
1218        {
1219                // so we just got a channel. we better activate the slots that are in use so people can talk
1220                uint32 i;
1221                for( i = 0; i <= 40; ++i )
1222                {
1223                        if( m_voiceMembersList[i] != NULL )
1224                                sVoiceChatHandler.ActivateChannelSlot(id, (uint8)i );
1225                }
1226
1227                SendVoiceUpdate();
1228        }
1229}
1230
1231void Group::AddVoiceMember(PlayerInfo * pPlayer)
1232{
1233        m_groupLock.Acquire();
1234        Log.Debug("Group", "adding voice member %u to group %u", pPlayer->guid, GetID());
1235        uint32 i;
1236
1237        // find him an id
1238        for( i = 1; i <= 40; ++i )
1239        {
1240                if( m_voiceMembersList[i] == NULL )
1241                        break;
1242        }
1243
1244        if( i == 41 )
1245        {
1246                // no free slots
1247                Log.Error("Group", "could not add voice member, no slots!");
1248                return;
1249        }
1250
1251        pPlayer->groupVoiceId = i;
1252        m_voiceMembersList[i] = pPlayer;
1253        ++m_voiceMemberCount;
1254
1255        if( !m_voiceChannelRequested )
1256        {
1257                /*uint32 count = 0;
1258                for( i = 0; i < 41; ++i )
1259                {
1260                        if( m_voiceMembersList[i] != NULL )
1261                        {
1262                                ++count;
1263                                if( count >= 2 )
1264                                        break;
1265                        }
1266                }*/
1267
1268                if( m_voiceMemberCount >= 2 )           // Don't create channels with only one member
1269                {
1270                        CreateVoiceSession();
1271                        m_voiceChannelRequested = true;
1272                }
1273        }
1274        else
1275        {
1276                if( m_voiceChannelId != 0 )
1277                {
1278                        // activate his slot
1279                        sVoiceChatHandler.ActivateChannelSlot(m_voiceChannelId, (uint8)i);
1280                        SendVoiceUpdate();
1281                }
1282        }
1283
1284        m_groupLock.Release();
1285}
1286
1287void Group::RemoveVoiceMember(PlayerInfo * pPlayer)
1288{
1289        if( pPlayer->groupVoiceId <= 0 )
1290                return;
1291
1292        Log.Debug("Group", "removing voice member %u from group %u", pPlayer->guid, GetID());
1293
1294        m_groupLock.Acquire();
1295        if( m_voiceMembersList[pPlayer->groupVoiceId] == pPlayer )
1296        {
1297                --m_voiceMemberCount;
1298                m_voiceMembersList[pPlayer->groupVoiceId] = NULL;
1299
1300                if( m_voiceChannelId != 0 )
1301                {
1302                        // turn off the slot
1303                        sVoiceChatHandler.DeactivateChannelSlot(m_voiceChannelId, pPlayer->groupVoiceId);
1304                        SendVoiceUpdate();
1305                }
1306
1307                if( m_voiceMemberCount < 2 )
1308                {
1309                        // destroy the channel
1310                        sVoiceChatHandler.DestroyGroupChannel(this);
1311                        m_voiceChannelId = 0;
1312                        m_voiceChannelRequested = false;
1313                }
1314        }
1315
1316        pPlayer->groupVoiceId = -1;
1317        m_groupLock.Release();
1318}
1319
1320void Group::SendVoiceUpdate()
1321{
1322        m_groupLock.Acquire();
1323        Log.Debug("Group", "sendgroupupdate id %u", (uint32)m_voiceChannelId);
1324
1325        //static uint8 EncryptionKey[16] = { 0x14, 0x60, 0xcf, 0xaf, 0x9e, 0xa2, 0x78, 0x38, 0xce, 0xc7, 0xaf, 0x0b, 0x3a, 0x23, 0x61, 0x44 };
1326        static uint8 EncryptionKey[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1327
1328        uint8 counter = 1;
1329        size_t pos;
1330        uint32 i,j;
1331        Player * pl;
1332
1333        WorldPacket data(SMSG_VOICE_SESSION, 100);
1334        data << uint32( 0x00000E9D );
1335        data << uint32( 0xE2500000 );           // this appears to be constant :S
1336
1337        data << uint16( m_voiceChannelId );             // voice channel id, used in udp packet
1338        data << uint8( 2 );                                             // party voice channel
1339        data << uint8( 0 );                                             // for channels this is name
1340        data.append( EncryptionKey, 16 );               // encryption key
1341
1342        // IP
1343        // these don't appear to be in network byte order.. gg
1344        data << uint32(htonl(sVoiceChatHandler.GetVoiceServerIP()));
1345        data << uint16(sVoiceChatHandler.GetVoiceServerPort());
1346       
1347        data << uint8( m_voiceMemberCount );
1348        pos = data.wpos();
1349
1350        for( i = 0; i <= 40; ++i )
1351        {
1352                if( m_voiceMembersList[i] == NULL )
1353                        continue;
1354
1355                if( m_voiceMembersList[i]->m_loggedInPlayer == NULL )
1356                {
1357                        // shouldn't happen
1358                        RemoveVoiceMember(m_voiceMembersList[i]);
1359                        continue;
1360                }
1361
1362                pl = m_voiceMembersList[i]->m_loggedInPlayer;
1363
1364                // Append ourself first, always.
1365                data << uint64 ( pl->GetGUID() );
1366                data << uint8( i );
1367
1368                if( pl->m_playerInfo == m_Leader )
1369                {
1370                        data << uint8(0x06);
1371                }
1372                else
1373                {
1374                        data << uint8(0x46);
1375                }
1376
1377                for( j = 0; j <= 40; ++j )
1378                {
1379                        if( i == j || m_voiceMembersList[j] == NULL )
1380                                continue;
1381
1382                        if( m_voiceMembersList[j]->m_loggedInPlayer == NULL )
1383                        {
1384                                // shouldn't happen
1385                                RemoveVoiceMember(m_voiceMembersList[j]);
1386                                continue;
1387                        }
1388
1389                        data << uint64( m_voiceMembersList[j]->guid );
1390                        data << uint8( j );
1391
1392                        if( m_voiceMembersList[j] == m_Leader )
1393                        {
1394                                data << uint8(0x80) << uint8(0x47);
1395                        }
1396                        else
1397                        {
1398                                data << uint8(0xC8) << uint8(0x47);
1399                        }
1400                }
1401
1402                //data << uint8( 0x47 );
1403
1404                pl->GetSession()->SendPacket( &data );
1405                data.wpos( pos );
1406        }
1407
1408        m_groupLock.Release();
1409}
1410
1411void Group::VoiceSessionDropped()
1412{
1413        Log.Debug("Group", "Voice session dropped");
1414        m_groupLock.Acquire();
1415        for(uint32 i = 0; i < 41; ++i)
1416        {
1417                if( m_voiceMembersList[i] != NULL )
1418                {
1419                        m_voiceMembersList[i]->groupVoiceId = -1;
1420                        m_voiceMembersList[i] = NULL;
1421                }
1422        }
1423        m_voiceChannelRequested = false;
1424        m_voiceChannelId = 0;
1425        m_voiceMemberCount = 0;
1426        m_groupLock.Release();
1427}
1428
1429void Group::VoiceSessionReconnected()
1430{
1431        if( !sVoiceChatHandler.CanUseVoiceChat() )
1432                return;
1433
1434        // try to recreate a group if one is needed
1435        GroupMembersSet::iterator itr1, itr2;
1436        Log.Debug("Group", "Attempting to recreate voice session for group %u", GetID());
1437
1438        uint32 i = 0, j = 0;
1439        SubGroup *sg1 = NULL;
1440        SubGroup *sg2 = NULL;
1441        m_groupLock.Acquire();
1442
1443        for( i = 0; i < m_SubGroupCount; i++ )
1444        {
1445                sg1 = m_SubGroups[i];
1446
1447                if( sg1 != NULL)
1448                {
1449                        for( itr1 = sg1->GetGroupMembersBegin(); itr1 != sg1->GetGroupMembersEnd(); ++itr1 )
1450                        {
1451                                // should never happen but just in case
1452                                if( (*itr1) == NULL )
1453                                        continue;
1454
1455                                /* skip offline players */
1456                                if( (*itr1)->m_loggedInPlayer == NULL )
1457                                {
1458                                        if( (*itr1)->groupVoiceId >= 0 )
1459                                        {
1460                                                // remove from voice members since that player is now offline
1461                                                RemoveVoiceMember( (*itr1) );
1462                                        }
1463
1464                                        continue;
1465                                }
1466
1467                                if( (*itr1)->groupVoiceId < 0 )
1468                                {
1469                                        (*itr1)->groupVoiceId = 0;
1470                                        AddVoiceMember( (*itr1) );
1471                                }
1472                        }
1473                }
1474        }
1475
1476        m_groupLock.Release();
1477}
1478#endif
Note: See TracBrowser for help on using the browser.