diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index a2c192ad7..45ab6cf8d 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -1159,7 +1159,7 @@ void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid, if(group->IsMember(plr_guid)) { uint8 subgroup = group->GetMemberGroup(plr_guid); - plr->SetGroup(group, subgroup); + plr->SetBattleGroundRaid(group, subgroup); } else GetBgRaid(team)->AddMember(plr_guid, plr->GetName()); diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp index fceb9c015..1dfed434c 100644 --- a/src/game/BattleGroundHandler.cpp +++ b/src/game/BattleGroundHandler.cpp @@ -430,8 +430,6 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) _player->GetMotionMaster()->MovementExpired(); _player->m_taxi.ClearTaxiDestinations(); } - //TODO FIX ME this call must be removed! - _player->RemoveFromGroup(); sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType()); _player->GetSession()->SendPacket(&data); diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cpp index 1bde9d37d..76069aee6 100644 --- a/src/game/ChatHandler.cpp +++ b/src/game/ChatHandler.cpp @@ -232,13 +232,15 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if(msg.empty()) break; - Group *group = GetPlayer()->GetGroup(); - if(!group) + // if player is in battleground, he cannot say to battleground members by /p + Group *group = GetPlayer()->GetOriginalGroup(); + // so if player hasn't OriginalGroup and his player->GetGroup() is BG raid, then return + if( !group && (!(group = GetPlayer()->GetGroup()) || group->isBGGroup()) ) return; WorldPacket data; ChatHandler::FillMessageData(&data, this, CHAT_MSG_PARTY, lang, NULL, 0, msg.c_str(),NULL); - group->BroadcastPacket(&data, group->GetMemberGroup(GetPlayer()->GetGUID())); + group->BroadcastPacket(&data, false, group->GetMemberGroup(GetPlayer()->GetGUID())); } break; case CHAT_MSG_GUILD: @@ -312,13 +314,15 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if(msg.empty()) break; - Group *group = GetPlayer()->GetGroup(); - if(!group || !group->isRaidGroup()) + // if player is in battleground, he cannot say to battleground members by /ra + Group *group = GetPlayer()->GetOriginalGroup(); + // so if player hasn't OriginalGroup and his player->GetGroup() is BG raid or his group isn't raid, then return + if( !group && !(group = GetPlayer()->GetGroup()) || group->isBGGroup() || !group->isRaidGroup() ) return; WorldPacket data; ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, "", 0, msg.c_str(),NULL); - group->BroadcastPacket(&data); + group->BroadcastPacket(&data, false); } break; case CHAT_MSG_RAID_LEADER: { @@ -338,13 +342,14 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if(msg.empty()) break; - Group *group = GetPlayer()->GetGroup(); - if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID())) + // if player is in battleground, he cannot say to battleground members by /ra + Group *group = GetPlayer()->GetOriginalGroup(); + if( !group && !(group = GetPlayer()->GetGroup()) || group->isBGGroup() || !group->isRaidGroup() ) return; WorldPacket data; ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, "", 0, msg.c_str(),NULL); - group->BroadcastPacket(&data); + group->BroadcastPacket(&data, false); } break; case CHAT_MSG_RAID_WARNING: { @@ -363,8 +368,9 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) return; WorldPacket data; + //in battleground, raid warning is sent only to players in battleground - code is ok ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, "", 0, msg.c_str(),NULL); - group->BroadcastPacket(&data); + group->BroadcastPacket(&data, false); } break; case CHAT_MSG_BATTLEGROUND: @@ -379,13 +385,14 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if(msg.empty()) break; + //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() Group *group = GetPlayer()->GetGroup(); - if(!group || !group->isRaidGroup()) + if(!group || !group->isBGGroup()) return; WorldPacket data; ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, "", 0, msg.c_str(),NULL); - group->BroadcastPacket(&data); + group->BroadcastPacket(&data, false); } break; case CHAT_MSG_BATTLEGROUND_LEADER: @@ -400,13 +407,14 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if(msg.empty()) break; + //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() Group *group = GetPlayer()->GetGroup(); - if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID())) + if(!group || !group->isBGGroup() || !group->IsLeader(GetPlayer()->GetGUID())) return; WorldPacket data; ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, "", 0, msg.c_str(),NULL); - group->BroadcastPacket(&data); + group->BroadcastPacket(&data, false); } break; case CHAT_MSG_CHANNEL: diff --git a/src/game/Group.cpp b/src/game/Group.cpp index 21695b754..de26cb666 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -201,7 +201,8 @@ void Group::ConvertToRaid() _initRaidSubGroupsCounter(); - if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET isRaid = 1 WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid)); + if(!isBGGroup()) + CharacterDatabase.PExecute("UPDATE groups SET isRaid = 1 WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid)); SendUpdate(); // update quest related GO states (quest activity dependent from raid membership) @@ -212,7 +213,12 @@ void Group::ConvertToRaid() bool Group::AddInvite(Player *player) { - if(!player || player->GetGroupInvite() || player->GetGroup()) + if( !player || player->GetGroupInvite() ) + return false; + Group* group = player->GetGroup(); + if( group && group->isBGGroup() ) + group = player->GetOriginalGroup(); + if( group ) return false; RemoveInvite(player); @@ -323,9 +329,17 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method) player->GetSession()->SendPacket( &data ); } - data.Initialize(SMSG_GROUP_LIST, 24); - data << uint64(0) << uint64(0) << uint64(0); - player->GetSession()->SendPacket(&data); + //we already removed player from group and in player->GetGroup() is his original group! + if( Group* group = player->GetGroup() ) + { + group->SendUpdate(); + } + else + { + data.Initialize(SMSG_GROUP_LIST, 24); + data << uint64(0) << uint64(0) << uint64(0); + player->GetSession()->SendPacket(&data); + } _homebindIfInstance(player); } @@ -334,7 +348,7 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method) { WorldPacket data(SMSG_GROUP_SET_LEADER, (m_memberSlots.front().name.size()+1)); data << m_memberSlots.front().name; - BroadcastPacket(&data); + BroadcastPacket(&data, true); } SendUpdate(); @@ -357,7 +371,7 @@ void Group::ChangeLeader(const uint64 &guid) WorldPacket data(SMSG_GROUP_SET_LEADER, slot->name.size()+1); data << slot->name; - BroadcastPacket(&data); + BroadcastPacket(&data, true); SendUpdate(); } @@ -371,13 +385,26 @@ void Group::Disband(bool hideDestroy) if(!player) continue; - player->SetGroup(NULL); + //we cannot call _removeMember because it would invalidate member iterator + if (player) + { + //if we are removing player from battleground raid + if( isBGGroup() ) + player->RemoveFromBattleGroundRaid(); + else + { + //we can remove player who is in battleground from his original group + if( player->GetOriginalGroup() == this ) + player->SetOriginalGroup(NULL); + else + player->SetGroup(NULL); + } + } // quest related GO state dependent from raid membership if(isRaidGroup()) player->UpdateForQuestsGO(); - if(!player->GetSession()) continue; @@ -388,9 +415,17 @@ void Group::Disband(bool hideDestroy) player->GetSession()->SendPacket(&data); } - data.Initialize(SMSG_GROUP_LIST, 24); - data << uint64(0) << uint64(0) << uint64(0); - player->GetSession()->SendPacket(&data); + //we already removed player from group and in player->GetGroup() is his original group, send update + if( Group* group = player->GetGroup() ) + { + group->SendUpdate(); + } + else + { + data.Initialize(SMSG_GROUP_LIST, 24); + data << uint64(0) << uint64(0) << uint64(0); + player->GetSession()->SendPacket(&data); + } _homebindIfInstance(player); } @@ -838,7 +873,7 @@ void Group::SetTargetIcon(uint8 id, uint64 guid) data << (uint8)0; data << id; data << guid; - BroadcastPacket(&data); + BroadcastPacket(&data, true); } void Group::GetDataForXPAtKill(Unit const* victim, uint32& count,uint32& sum_level, Player* & member_with_max_level, Player* & not_gray_member_with_max_level) @@ -891,7 +926,7 @@ void Group::SendUpdate() for(member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) { player = objmgr.GetPlayer(citr->guid); - if(!player || !player->GetSession()) + if(!player || !player->GetSession() || player->GetGroup() != this ) continue; // guess size WorldPacket data(SMSG_GROUP_LIST, (1+1+1+1+8+4+GetMembersCount()*20)); @@ -905,11 +940,14 @@ void Group::SendUpdate() { if(citr->guid == citr2->guid) continue; + Player* member = objmgr.GetPlayer(citr2->guid); + uint8 onlineState = (member) ? MEMBER_STATUS_ONLINE : MEMBER_STATUS_OFFLINE; + onlineState = onlineState | ((isBGGroup()) ? MEMBER_STATUS_PVP : 0); data << citr2->name; data << (uint64)citr2->guid; // online-state - data << (uint8)(objmgr.GetPlayer(citr2->guid) ? 1 : 0); + data << (uint8)(onlineState); data << (uint8)(citr2->group); // groupid data << (uint8)(citr2->assistant?0x01:0); // 0x2 main assist, 0x4 main tank } @@ -943,12 +981,12 @@ void Group::UpdatePlayerOutOfRange(Player* pPlayer) } } -void Group::BroadcastPacket(WorldPacket *packet, int group, uint64 ignore) +void Group::BroadcastPacket(WorldPacket *packet, bool ignorePlayersInBGRaid, int group, uint64 ignore) { for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) { Player *pl = itr->getSource(); - if(!pl || (ignore != 0 && pl->GetGUID() == ignore)) + if(!pl || (ignore != 0 && pl->GetGUID() == ignore) || (ignorePlayersInBGRaid && pl->GetGroup() != this) ) continue; if (pl->GetSession() && (group==-1 || itr->getSubGroup()==group)) @@ -1027,7 +1065,15 @@ bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant, u if(player) { player->SetGroupInvite(NULL); - player->SetGroup(this, group); + //if player is in group and he is being added to BG raid group, then call SetBattleGroundRaid() + if( player->GetGroup() && isBGGroup() ) + player->SetBattleGroundRaid(this, group); + //if player is in bg raid and we are adding him to normal group, then call SetOriginalGroup() + else if ( player->GetGroup() ) + player->SetOriginalGroup(this, group); + //if player is not in group, then call set group + else + player->SetGroup(this, group); // if the same group invites the player back, cancel the homebind timer InstanceGroupBind *bind = GetBoundInstance(player->GetMapId(), player->GetDifficulty()); if(bind && bind->save->GetInstanceId() == player->GetInstanceId()) @@ -1054,7 +1100,17 @@ bool Group::_removeMember(const uint64 &guid) Player *player = objmgr.GetPlayer(guid); if (player) { - player->SetGroup(NULL); + //if we are removing player from battleground raid + if( isBGGroup() ) + player->RemoveFromBattleGroundRaid(); + else + { + //we can remove player who is in battleground from his original group + if( player->GetOriginalGroup() == this ) + player->SetOriginalGroup(NULL); + else + player->SetGroup(NULL); + } } _removeRolls(guid); @@ -1246,12 +1302,17 @@ void Group::ChangeMembersGroup(Player *player, const uint8 &group) return; if(_setMembersGroup(player->GetGUID(), group)) { - uint8 prevSubGroup; - prevSubGroup = player->GetSubGroup(); - + uint8 prevSubGroup = player->GetSubGroup(); + if( player->GetGroup() == this ) + player->GetGroupRef().setSubGroup(group); + //if player is in BG raid, it is possible that he is also in normal raid - and that normal raid is stored in m_originalGroup reference + else + { + prevSubGroup = player->GetOriginalSubGroup(); + player->GetOriginalGroupRef().setSubGroup(group); + } SubGroupCounterDecrease(prevSubGroup); - player->GetGroupRef().setSubGroup(group); SendUpdate(); } } diff --git a/src/game/Group.h b/src/game/Group.h index 0fb107735..478b7c5cb 100644 --- a/src/game/Group.h +++ b/src/game/Group.h @@ -291,7 +291,7 @@ class MANGOS_DLL_SPEC Group void SendUpdate(); void UpdatePlayerOutOfRange(Player* pPlayer); // ignore: GUID of player that will be ignored - void BroadcastPacket(WorldPacket *packet, int group=-1, uint64 ignore=0); + void BroadcastPacket(WorldPacket *packet, bool ignorePlayersInBGRaid, int group=-1, uint64 ignore=0); void BroadcastReadyCheck(WorldPacket *packet); void OfflineReadyCheck(); diff --git a/src/game/GroupHandler.cpp b/src/game/GroupHandler.cpp index 44fa9c290..d1de13ad3 100644 --- a/src/game/GroupHandler.cpp +++ b/src/game/GroupHandler.cpp @@ -55,12 +55,6 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data ) std::string membername; recv_data >> membername; - if(_player->InBattleGround()) - { - SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_INVITE_RESTRICTED); - return; - } - // attempt add selected player // cheating @@ -97,15 +91,20 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data ) return; } + Group *group = GetPlayer()->GetGroup(); + if( group && group->isBGGroup() ) + group = GetPlayer()->GetOriginalGroup(); + + Group *group2 = player->GetGroup(); + if( group2 && group2->isBGGroup() ) + group2 = player->GetOriginalGroup(); // player already in another group or invited - if(player->GetGroup() || player->GetGroupInvite() ) + if( group2 || player->GetGroupInvite() ) { SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_ALREADY_IN_GROUP); return; } - Group *group = GetPlayer()->GetGroup(); - if(group) { // not have permissions for invite @@ -114,7 +113,6 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data ) SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_YOU_NOT_LEADER); return; } - // not have place if(group->IsFull()) { @@ -185,27 +183,20 @@ void WorldSession::HandleGroupAcceptOpcode( WorldPacket & /*recv_data*/ ) Player* leader = objmgr.GetPlayer(group->GetLeaderGUID()); - if(leader && leader->InBattleGround()) - { - SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_INVITE_RESTRICTED); - return; - } - // forming a new group, create it if(!group->IsCreated()) { - if(leader) group->RemoveInvite(leader); + if( leader ) + group->RemoveInvite(leader); group->Create(group->GetLeaderGUID(), group->GetLeaderName()); objmgr.AddGroup(group); } - // everything's fine, do it + // everything's fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!! if(!group->AddMember(GetPlayer()->GetGUID(), GetPlayer()->GetName())) return; uint8 subgroup = group->GetMemberGroup(GetPlayer()->GetGUID()); - - GetPlayer()->SetGroup(group, subgroup); } void WorldSession::HandleGroupDeclineOpcode( WorldPacket & /*recv_data*/ ) @@ -424,7 +415,7 @@ void WorldSession::HandleMinimapPingOpcode(WorldPacket& recv_data) data << GetPlayer()->GetGUID(); data << x; data << y; - GetPlayer()->GetGroup()->BroadcastPacket(&data, -1, GetPlayer()->GetGUID()); + GetPlayer()->GetGroup()->BroadcastPacket(&data, true, -1, GetPlayer()->GetGUID()); } void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data) @@ -451,7 +442,7 @@ void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data) data << roll; data << GetPlayer()->GetGUID(); if(GetPlayer()->GetGroup()) - GetPlayer()->GetGroup()->BroadcastPacket(&data); + GetPlayer()->GetGroup()->BroadcastPacket(&data, false); else SendPacket(&data); } @@ -512,6 +503,7 @@ void WorldSession::HandleGroupChangeSubGroupOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,1+1); + // we will get correct pointer for group here, so we don't have to check if group is BG raid Group *group = GetPlayer()->GetGroup(); if(!group) return; @@ -604,7 +596,7 @@ void WorldSession::HandleRaidReadyCheckOpcode( WorldPacket & recv_data ) // everything's fine, do it WorldPacket data(MSG_RAID_READY_CHECK, 8); data << GetPlayer()->GetGUID(); - group->BroadcastPacket(&data, -1); + group->BroadcastPacket(&data, false, -1); group->OfflineReadyCheck(); } diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 1a2f91053..9cbcafa21 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -12286,7 +12286,7 @@ void Player::SendNewItem(Item *item, uint32 count, bool received, bool created, data << GetItemCount(item->GetEntry()); // count of items in inventory if (broadcast && GetGroup()) - GetGroup()->BroadcastPacket(&data); + GetGroup()->BroadcastPacket(&data, true); else GetSession()->SendPacket(&data); } @@ -18319,7 +18319,8 @@ void Player::ClearComboPoints() void Player::SetGroup(Group *group, int8 subgroup) { - if(group == NULL) m_group.unlink(); + if(group == NULL) + m_group.unlink(); else { // never use SetGroup without a subgroup unless you specify NULL for group @@ -19414,6 +19415,41 @@ PartyResult Player::CanUninviteFromGroup() const return PARTY_RESULT_OK; } +void Player::SetBattleGroundRaid(Group* group, int8 subgroup) +{ + //we must move references from m_group to m_originalGroup + SetOriginalGroup(GetGroup(), GetSubGroup()); + + m_group.unlink(); + m_group.link(group, this); + m_group.setSubGroup((uint8)subgroup); +} + +void Player::RemoveFromBattleGroundRaid() +{ + //remove existing reference + m_group.unlink(); + if( Group* group = GetOriginalGroup() ) + { + m_group.link(group, this); + m_group.setSubGroup(GetOriginalSubGroup()); + } + SetOriginalGroup(NULL); +} + +void Player::SetOriginalGroup(Group *group, int8 subgroup) +{ + if( group == NULL ) + m_originalGroup.unlink(); + else + { + // never use SetOriginalGroup without a subgroup unless you specify NULL for group + assert(subgroup >= 0); + m_originalGroup.link(group, this); + m_originalGroup.setSubGroup((uint8)subgroup); + } +} + void Player::UpdateUnderwaterState( Map* m, float x, float y, float z ) { LiquidData liquid_status; diff --git a/src/game/Player.h b/src/game/Player.h index 4bea09710..5a0b1560f 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -2131,6 +2131,13 @@ class MANGOS_DLL_SPEC Player : public Unit void SetAuraUpdateMask(uint8 slot) { m_auraUpdateMask |= (uint64(1) << slot); } Player* GetNextRandomRaidMember(float radius); PartyResult CanUninviteFromGroup() const; + // BattleGround Group System + void SetBattleGroundRaid(Group *group, int8 subgroup = -1); + void RemoveFromBattleGroundRaid(); + Group * GetOriginalGroup() { return m_originalGroup.getTarget(); } + GroupReference& GetOriginalGroupRef() { return m_originalGroup; } + uint8 GetOriginalSubGroup() const { return m_originalGroup.getSubGroup(); } + void SetOriginalGroup(Group *group, int8 subgroup = -1); GridReference &GetGridRef() { return m_gridRef; } MapReference &GetMapRef() { return m_mapRef; } @@ -2374,6 +2381,7 @@ class MANGOS_DLL_SPEC Player : public Unit // Groups GroupReference m_group; + GroupReference m_originalGroup; Group *m_groupInvite; uint32 m_groupUpdateMask; uint64 m_auraUpdateMask; diff --git a/src/game/Unit.h b/src/game/Unit.h index 0c7bc672b..633700600 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -75,7 +75,7 @@ enum SpellAuraInterruptFlags AURA_INTERRUPT_FLAG_MOUNTING = 0x00020000, // 17 removed by mounting AURA_INTERRUPT_FLAG_NOT_SEATED = 0x00040000, // 18 removed by standing up AURA_INTERRUPT_FLAG_CHANGE_MAP = 0x00080000, // 19 leaving map/getting teleported - AURA_INTERRUPT_FLAG_UNK20 = 0x00100000, // 20 + AURA_INTERRUPT_FLAG_IMMUNE_OR_STEALTH = 0x00100000, // 20 removed when player on himself casts immunity spell or vanish? AURA_INTERRUPT_FLAG_UNK21 = 0x00200000, // 21 AURA_INTERRUPT_FLAG_UNK22 = 0x00400000, // 22 AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT = 0x00800000, // 23 removed by entering pvp combat diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index b2abad1cc..d8329e68d 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7454" + #define REVISION_NR "7455" #endif // __REVISION_NR_H__