Files
TCPlayerbotCore/src/server/game/Handlers/GroupHandler.cpp
T
Elron103 88ecc9533a Core/Entities: Fix combat state setting when FFA PvP flag is set
Description:
Currently there is an issue, when you are in FFA areas, but you dont have PvP flag activated.

You should get the PvP-In-Combat delay timer, but instead you just get the usual timer as if you would not fight in PvP.

Reproduction:
1) Get two players in FFA area Gurubashi arena down in the battle area (.tele Gurubashi)

2) Fight each other

3) When stopping combat, the combat state will switch off immediately. But it is supposed to switch off after some delay, because it was a PvP fight.

Closes #11103

Signed-off-by: Duarte Duarte <[email protected]>
2014-01-13 17:03:43 +00:00

1057 lines
31 KiB
C++

/*
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Common.h"
#include "DatabaseEnv.h"
#include "Group.h"
#include "GroupMgr.h"
#include "Log.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
#include "Pet.h"
#include "Player.h"
#include "SocialMgr.h"
#include "SpellAuras.h"
#include "Util.h"
#include "Vehicle.h"
#include "World.h"
#include "WorldPacket.h"
#include "WorldSession.h"
class Aura;
/* differeces from off:
-you can uninvite yourself - is is useful
-you can accept invitation even if leader went offline
*/
/* todo:
-group_destroyed msg is sent but not shown
-reduce xp gaining when in raid group
-quest sharing has to be corrected
-FIX sending PartyMemberStats
*/
void WorldSession::SendPartyResult(PartyOperation operation, const std::string& member, PartyResult res, uint32 val /* = 0 */)
{
WorldPacket data(SMSG_PARTY_COMMAND_RESULT, 4 + member.size() + 1 + 4 + 4);
data << uint32(operation);
data << member;
data << uint32(res);
data << uint32(val); // LFD cooldown related (used with ERR_PARTY_LFG_BOOT_COOLDOWN_S and ERR_PARTY_LFG_BOOT_NOT_ELIGIBLE_S)
SendPacket(&data);
}
void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_INVITE");
std::string membername;
recvData >> membername;
recvData.read_skip<uint32>();
// attempt add selected player
// cheating
if (!normalizePlayerName(membername))
{
SendPartyResult(PARTY_OP_INVITE, membername, ERR_BAD_PLAYER_NAME_S);
return;
}
Player* player = sObjectAccessor->FindPlayerByName(membername);
// no player
if (!player)
{
SendPartyResult(PARTY_OP_INVITE, membername, ERR_BAD_PLAYER_NAME_S);
return;
}
// restrict invite to GMs
if (!sWorld->getBoolConfig(CONFIG_ALLOW_GM_GROUP) && !GetPlayer()->IsGameMaster() && player->IsGameMaster())
{
SendPartyResult(PARTY_OP_INVITE, membername, ERR_BAD_PLAYER_NAME_S);
return;
}
// can't group with
if (!GetPlayer()->IsGameMaster() && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && GetPlayer()->GetTeam() != player->GetTeam())
{
SendPartyResult(PARTY_OP_INVITE, membername, ERR_PLAYER_WRONG_FACTION);
return;
}
if (GetPlayer()->GetInstanceId() != 0 && player->GetInstanceId() != 0 && GetPlayer()->GetInstanceId() != player->GetInstanceId() && GetPlayer()->GetMapId() == player->GetMapId())
{
SendPartyResult(PARTY_OP_INVITE, membername, ERR_TARGET_NOT_IN_INSTANCE_S);
return;
}
// just ignore us
if (player->GetInstanceId() != 0 && player->GetDungeonDifficulty() != GetPlayer()->GetDungeonDifficulty())
{
SendPartyResult(PARTY_OP_INVITE, membername, ERR_IGNORING_YOU_S);
return;
}
if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()))
{
SendPartyResult(PARTY_OP_INVITE, membername, ERR_IGNORING_YOU_S);
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 (group2 || player->GetGroupInvite())
{
SendPartyResult(PARTY_OP_INVITE, membername, ERR_ALREADY_IN_GROUP_S);
if (group2)
{
// tell the player that they were invited but it failed as they were already in a group
WorldPacket data(SMSG_GROUP_INVITE, 10); // guess size
data << uint8(0); // invited/already in group flag
data << GetPlayer()->GetName(); // max len 48
data << uint32(0); // unk
data << uint8(0); // count
data << uint32(0); // unk
player->GetSession()->SendPacket(&data);
}
return;
}
if (group)
{
// not have permissions for invite
if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID()))
{
SendPartyResult(PARTY_OP_INVITE, "", ERR_NOT_LEADER);
return;
}
// not have place
if (group->IsFull())
{
SendPartyResult(PARTY_OP_INVITE, "", ERR_GROUP_FULL);
return;
}
}
// ok, but group not exist, start a new group
// but don't create and save the group to the DB until
// at least one person joins
if (!group)
{
group = new Group;
// new group: if can't add then delete
if (!group->AddLeaderInvite(GetPlayer()))
{
delete group;
return;
}
if (!group->AddInvite(player))
{
delete group;
return;
}
}
else
{
// already existed group: if can't add then just leave
if (!group->AddInvite(player))
{
return;
}
}
// ok, we do it
WorldPacket data(SMSG_GROUP_INVITE, 10); // guess size
data << uint8(1); // invited/already in group flag
data << GetPlayer()->GetName(); // max len 48
data << uint32(0); // unk
data << uint8(0); // count
data << uint32(0); // unk
player->GetSession()->SendPacket(&data);
SendPartyResult(PARTY_OP_INVITE, membername, ERR_PARTY_RESULT_OK);
}
void WorldSession::HandleGroupAcceptOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_ACCEPT");
recvData.read_skip<uint32>();
Group* group = GetPlayer()->GetGroupInvite();
if (!group)
return;
// Remove player from invitees in any case
group->RemoveInvite(GetPlayer());
if (group->GetLeaderGUID() == GetPlayer()->GetGUID())
{
TC_LOG_ERROR("network", "HandleGroupAcceptOpcode: player %s(%d) tried to accept an invite to his own group", GetPlayer()->GetName().c_str(), GetPlayer()->GetGUIDLow());
return;
}
// Group is full
if (group->IsFull())
{
SendPartyResult(PARTY_OP_INVITE, "", ERR_GROUP_FULL);
return;
}
Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID());
// Forming a new group, create it
if (!group->IsCreated())
{
// This can happen if the leader is zoning. To be removed once delayed actions for zoning are implemented
if (!leader)
{
group->RemoveAllInvites();
return;
}
// If we're about to create a group there really should be a leader present
ASSERT(leader);
group->RemoveInvite(leader);
group->Create(leader);
sGroupMgr->AddGroup(group);
}
// Everything is fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!!
if (!group->AddMember(GetPlayer()))
return;
group->BroadcastGroupUpdate();
}
void WorldSession::HandleGroupDeclineOpcode(WorldPacket & /*recvData*/)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_DECLINE");
Group* group = GetPlayer()->GetGroupInvite();
if (!group)
return;
// Remember leader if online (group pointer will be invalid if group gets disbanded)
Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID());
// uninvite, group can be deleted
GetPlayer()->UninviteFromGroup();
if (!leader || !leader->GetSession())
return;
// report
WorldPacket data(SMSG_GROUP_DECLINE, GetPlayer()->GetName().length());
data << GetPlayer()->GetName();
leader->GetSession()->SendPacket(&data);
}
void WorldSession::HandleGroupUninviteGuidOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_UNINVITE_GUID");
uint64 guid;
std::string reason;
recvData >> guid;
recvData >> reason;
//can't uninvite yourself
if (guid == GetPlayer()->GetGUID())
{
TC_LOG_ERROR("network", "WorldSession::HandleGroupUninviteGuidOpcode: leader %s(%d) tried to uninvite himself from the group.",
GetPlayer()->GetName().c_str(), GetPlayer()->GetGUIDLow());
return;
}
PartyResult res = GetPlayer()->CanUninviteFromGroup();
if (res != ERR_PARTY_RESULT_OK)
{
SendPartyResult(PARTY_OP_UNINVITE, "", res);
return;
}
Group* grp = GetPlayer()->GetGroup();
if (!grp)
return;
if (grp->IsLeader(guid))
{
SendPartyResult(PARTY_OP_UNINVITE, "", ERR_NOT_LEADER);
return;
}
if (grp->IsMember(guid))
{
Player::RemoveFromGroup(grp, guid, GROUP_REMOVEMETHOD_KICK, GetPlayer()->GetGUID(), reason.c_str());
return;
}
if (Player* player = grp->GetInvited(guid))
{
player->UninviteFromGroup();
return;
}
SendPartyResult(PARTY_OP_UNINVITE, "", ERR_TARGET_NOT_IN_GROUP_S);
}
void WorldSession::HandleGroupUninviteOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_UNINVITE");
std::string membername;
recvData >> membername;
// player not found
if (!normalizePlayerName(membername))
return;
// can't uninvite yourself
if (GetPlayer()->GetName() == membername)
{
TC_LOG_ERROR("network", "WorldSession::HandleGroupUninviteOpcode: leader %s(%d) tried to uninvite himself from the group.",
GetPlayer()->GetName().c_str(), GetPlayer()->GetGUIDLow());
return;
}
PartyResult res = GetPlayer()->CanUninviteFromGroup();
if (res != ERR_PARTY_RESULT_OK)
{
SendPartyResult(PARTY_OP_UNINVITE, "", res);
return;
}
Group* grp = GetPlayer()->GetGroup();
if (!grp)
return;
if (uint64 guid = grp->GetMemberGUID(membername))
{
Player::RemoveFromGroup(grp, guid, GROUP_REMOVEMETHOD_KICK, GetPlayer()->GetGUID());
return;
}
if (Player* player = grp->GetInvited(membername))
{
player->UninviteFromGroup();
return;
}
SendPartyResult(PARTY_OP_UNINVITE, membername, ERR_TARGET_NOT_IN_GROUP_S);
}
void WorldSession::HandleGroupSetLeaderOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_SET_LEADER");
uint64 guid;
recvData >> guid;
Player* player = ObjectAccessor::FindPlayer(guid);
Group* group = GetPlayer()->GetGroup();
if (!group || !player)
return;
if (!group->IsLeader(GetPlayer()->GetGUID()) || player->GetGroup() != group)
return;
// Everything's fine, accepted.
group->ChangeLeader(guid);
group->SendUpdate();
}
void WorldSession::HandleGroupDisbandOpcode(WorldPacket & /*recvData*/)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_DISBAND");
Group* grp = GetPlayer()->GetGroup();
if (!grp)
return;
if (_player->InBattleground())
{
SendPartyResult(PARTY_OP_INVITE, "", ERR_INVITE_RESTRICTED);
return;
}
/** error handling **/
/********************/
// everything's fine, do it
SendPartyResult(PARTY_OP_LEAVE, GetPlayer()->GetName(), ERR_PARTY_RESULT_OK);
GetPlayer()->RemoveFromGroup(GROUP_REMOVEMETHOD_LEAVE);
}
void WorldSession::HandleLootMethodOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_LOOT_METHOD");
uint32 lootMethod;
uint64 lootMaster;
uint32 lootThreshold;
recvData >> lootMethod >> lootMaster >> lootThreshold;
Group* group = GetPlayer()->GetGroup();
if (!group)
return;
/** error handling **/
if (!group->IsLeader(GetPlayer()->GetGUID()))
return;
/********************/
// everything's fine, do it
group->SetLootMethod((LootMethod)lootMethod);
group->SetLooterGuid(lootMaster);
group->SetLootThreshold((ItemQualities)lootThreshold);
group->SendUpdate();
}
void WorldSession::HandleLootRoll(WorldPacket& recvData)
{
uint64 guid;
uint32 itemSlot;
uint8 rollType;
recvData >> guid; // guid of the item rolled
recvData >> itemSlot;
recvData >> rollType; // 0: pass, 1: need, 2: greed
Group* group = GetPlayer()->GetGroup();
if (!group)
return;
group->CountRollVote(GetPlayer()->GetGUID(), guid, rollType);
switch (rollType)
{
case ROLL_NEED:
GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED, 1);
break;
case ROLL_GREED:
GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED, 1);
break;
}
}
void WorldSession::HandleMinimapPingOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received MSG_MINIMAP_PING");
if (!GetPlayer()->GetGroup())
return;
float x, y;
recvData >> x;
recvData >> y;
//TC_LOG_DEBUG("Received opcode MSG_MINIMAP_PING X: %f, Y: %f", x, y);
/** error handling **/
/********************/
// everything's fine, do it
WorldPacket data(MSG_MINIMAP_PING, (8+4+4));
data << uint64(GetPlayer()->GetGUID());
data << float(x);
data << float(y);
GetPlayer()->GetGroup()->BroadcastPacket(&data, true, -1, GetPlayer()->GetGUID());
}
void WorldSession::HandleRandomRollOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received MSG_RANDOM_ROLL");
uint32 minimum, maximum, roll;
recvData >> minimum;
recvData >> maximum;
/** error handling **/
if (minimum > maximum || maximum > 10000) // < 32768 for urand call
return;
/********************/
// everything's fine, do it
roll = urand(minimum, maximum);
//TC_LOG_DEBUG("ROLL: MIN: %u, MAX: %u, ROLL: %u", minimum, maximum, roll);
WorldPacket data(MSG_RANDOM_ROLL, 4+4+4+8);
data << uint32(minimum);
data << uint32(maximum);
data << uint32(roll);
data << uint64(GetPlayer()->GetGUID());
if (GetPlayer()->GetGroup())
GetPlayer()->GetGroup()->BroadcastPacket(&data, false);
else
SendPacket(&data);
}
void WorldSession::HandleRaidTargetUpdateOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received MSG_RAID_TARGET_UPDATE");
Group* group = GetPlayer()->GetGroup();
if (!group)
return;
uint8 x;
recvData >> x;
/** error handling **/
/********************/
// everything's fine, do it
if (x == 0xFF) // target icon request
{
group->SendTargetIconList(this);
}
else // target icon update
{
if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID()))
return;
uint64 guid;
recvData >> guid;
group->SetTargetIcon(x, _player->GetGUID(), guid);
}
}
void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket & /*recvData*/)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_RAID_CONVERT");
Group* group = GetPlayer()->GetGroup();
if (!group)
return;
if (_player->InBattleground())
return;
/** error handling **/
if (!group->IsLeader(GetPlayer()->GetGUID()) || group->GetMembersCount() < 2)
return;
/********************/
// everything's fine, do it (is it 0 (PARTY_OP_INVITE) correct code)
SendPartyResult(PARTY_OP_INVITE, "", ERR_PARTY_RESULT_OK);
group->ConvertToRaid();
}
void WorldSession::HandleGroupChangeSubGroupOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_CHANGE_SUB_GROUP");
// 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;
std::string name;
uint8 groupNr;
recvData >> name;
recvData >> groupNr;
if (groupNr >= MAX_RAID_SUBGROUPS)
return;
uint64 senderGuid = GetPlayer()->GetGUID();
if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid))
return;
if (!group->HasFreeSlotSubGroup(groupNr))
return;
Player* movedPlayer = sObjectAccessor->FindPlayerByName(name);
uint64 guid;
if (movedPlayer)
{
guid = movedPlayer->GetGUID();
}
else
{
CharacterDatabase.EscapeString(name);
guid = sObjectMgr->GetPlayerGUIDByName(name.c_str());
}
group->ChangeMembersGroup(guid, groupNr);
}
void WorldSession::HandleGroupAssistantLeaderOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_ASSISTANT_LEADER");
Group* group = GetPlayer()->GetGroup();
if (!group)
return;
if (!group->IsLeader(GetPlayer()->GetGUID()))
return;
uint64 guid;
bool apply;
recvData >> guid;
recvData >> apply;
group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_ASSISTANT);
group->SendUpdate();
}
void WorldSession::HandlePartyAssignmentOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received MSG_PARTY_ASSIGNMENT");
Group* group = GetPlayer()->GetGroup();
if (!group)
return;
uint64 senderGuid = GetPlayer()->GetGUID();
if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid))
return;
uint8 assignment;
bool apply;
uint64 guid;
recvData >> assignment >> apply;
recvData >> guid;
switch (assignment)
{
case GROUP_ASSIGN_MAINASSIST:
group->RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINASSIST);
group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_MAINASSIST);
break;
case GROUP_ASSIGN_MAINTANK:
group->RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINTANK); // Remove main assist flag from current if any.
group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_MAINTANK);
default:
break;
}
group->SendUpdate();
}
void WorldSession::HandleRaidReadyCheckOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received MSG_RAID_READY_CHECK");
Group* group = GetPlayer()->GetGroup();
if (!group)
return;
if (recvData.empty()) // request
{
/** error handling **/
if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID()))
return;
/********************/
// everything's fine, do it
WorldPacket data(MSG_RAID_READY_CHECK, 8);
data << GetPlayer()->GetGUID();
group->BroadcastPacket(&data, false, -1);
group->OfflineReadyCheck();
}
else // answer
{
uint8 state;
recvData >> state;
// everything's fine, do it
WorldPacket data(MSG_RAID_READY_CHECK_CONFIRM, 9);
data << uint64(GetPlayer()->GetGUID());
data << uint8(state);
group->BroadcastReadyCheck(&data);
}
}
void WorldSession::HandleRaidReadyCheckFinishedOpcode(WorldPacket & /*recvData*/)
{
//Group* group = GetPlayer()->GetGroup();
//if (!group)
// return;
//if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID()))
// return;
// Is any reaction need?
}
void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacket* data)
{
uint32 mask = player->GetGroupUpdateFlag();
if (mask == GROUP_UPDATE_FLAG_NONE)
return;
if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) // if update power type, update current/max power also
mask |= (GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER);
if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) // same for pets
mask |= (GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER);
uint32 byteCount = 0;
for (int i = 1; i < GROUP_UPDATE_FLAGS_COUNT; ++i)
if (mask & (1 << i))
byteCount += GroupUpdateLength[i];
data->Initialize(SMSG_PARTY_MEMBER_STATS, 8 + 4 + byteCount);
data->append(player->GetPackGUID());
*data << uint32(mask);
if (mask & GROUP_UPDATE_FLAG_STATUS)
{
uint16 playerStatus = MEMBER_STATUS_ONLINE;
if (player->IsPvP())
playerStatus |= MEMBER_STATUS_PVP;
if (!player->IsAlive())
{
if (player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
playerStatus |= MEMBER_STATUS_GHOST;
else
playerStatus |= MEMBER_STATUS_DEAD;
}
if (player->IsFFAPvP())
playerStatus |= MEMBER_STATUS_PVP_FFA;
if (player->isAFK())
playerStatus |= MEMBER_STATUS_AFK;
if (player->isDND())
playerStatus |= MEMBER_STATUS_DND;
*data << uint16(playerStatus);
}
if (mask & GROUP_UPDATE_FLAG_CUR_HP)
*data << uint32(player->GetHealth());
if (mask & GROUP_UPDATE_FLAG_MAX_HP)
*data << uint32(player->GetMaxHealth());
Powers powerType = player->getPowerType();
if (mask & GROUP_UPDATE_FLAG_POWER_TYPE)
*data << uint8(powerType);
if (mask & GROUP_UPDATE_FLAG_CUR_POWER)
*data << uint16(player->GetPower(powerType));
if (mask & GROUP_UPDATE_FLAG_MAX_POWER)
*data << uint16(player->GetMaxPower(powerType));
if (mask & GROUP_UPDATE_FLAG_LEVEL)
*data << uint16(player->getLevel());
if (mask & GROUP_UPDATE_FLAG_ZONE)
*data << uint16(player->GetZoneId());
if (mask & GROUP_UPDATE_FLAG_POSITION)
{
*data << uint16(player->GetPositionX());
*data << uint16(player->GetPositionY());
}
if (mask & GROUP_UPDATE_FLAG_AURAS)
{
uint64 auramask = player->GetAuraUpdateMaskForRaid();
*data << uint64(auramask);
for (uint32 i = 0; i < MAX_AURAS; ++i)
{
if (auramask & (uint64(1) << i))
{
AuraApplication const* aurApp = player->GetVisibleAura(i);
*data << uint32(aurApp ? aurApp->GetBase()->GetId() : 0);
*data << uint8(1);
}
}
}
Pet* pet = player->GetPet();
if (mask & GROUP_UPDATE_FLAG_PET_GUID)
{
if (pet)
*data << (uint64) pet->GetGUID();
else
*data << (uint64) 0;
}
if (mask & GROUP_UPDATE_FLAG_PET_NAME)
{
if (pet)
*data << pet->GetName();
else
*data << uint8(0);
}
if (mask & GROUP_UPDATE_FLAG_PET_MODEL_ID)
{
if (pet)
*data << uint16(pet->GetDisplayId());
else
*data << uint16(0);
}
if (mask & GROUP_UPDATE_FLAG_PET_CUR_HP)
{
if (pet)
*data << uint32(pet->GetHealth());
else
*data << uint32(0);
}
if (mask & GROUP_UPDATE_FLAG_PET_MAX_HP)
{
if (pet)
*data << uint32(pet->GetMaxHealth());
else
*data << uint32(0);
}
if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE)
{
if (pet)
*data << uint8(pet->getPowerType());
else
*data << uint8(0);
}
if (mask & GROUP_UPDATE_FLAG_PET_CUR_POWER)
{
if (pet)
*data << uint16(pet->GetPower(pet->getPowerType()));
else
*data << uint16(0);
}
if (mask & GROUP_UPDATE_FLAG_PET_MAX_POWER)
{
if (pet)
*data << uint16(pet->GetMaxPower(pet->getPowerType()));
else
*data << uint16(0);
}
if (mask & GROUP_UPDATE_FLAG_PET_AURAS)
{
if (pet)
{
uint64 auramask = pet->GetAuraUpdateMaskForRaid();
*data << uint64(auramask);
for (uint32 i = 0; i < MAX_AURAS; ++i)
{
if (auramask & (uint64(1) << i))
{
AuraApplication const* aurApp = pet->GetVisibleAura(i);
*data << uint32(aurApp ? aurApp->GetBase()->GetId() : 0);
*data << uint8(aurApp ? aurApp->GetFlags() : 0);
}
}
}
else
*data << uint64(0);
}
if (mask & GROUP_UPDATE_FLAG_VEHICLE_SEAT)
{
if (Vehicle* veh = player->GetVehicle())
*data << uint32(veh->GetVehicleInfo()->m_seatID[player->m_movementInfo.transport.seat]);
else
*data << uint32(0);
}
}
/*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/
void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket &recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_REQUEST_PARTY_MEMBER_STATS");
uint64 Guid;
recvData >> Guid;
Player* player = HashMapHolder<Player>::Find(Guid);
if (!player)
{
WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 3+4+2);
data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related
data.appendPackGUID(Guid);
data << uint32(GROUP_UPDATE_FLAG_STATUS);
data << uint16(MEMBER_STATUS_OFFLINE);
SendPacket(&data);
return;
}
Pet* pet = player->GetPet();
Powers powerType = player->getPowerType();
WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 4+2+2+2+1+2*6+8+1+8);
data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related
data.append(player->GetPackGUID());
uint32 updateFlags = GROUP_UPDATE_FLAG_STATUS | GROUP_UPDATE_FLAG_CUR_HP | GROUP_UPDATE_FLAG_MAX_HP
| GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER | GROUP_UPDATE_FLAG_LEVEL
| GROUP_UPDATE_FLAG_ZONE | GROUP_UPDATE_FLAG_POSITION | GROUP_UPDATE_FLAG_AURAS
| GROUP_UPDATE_FLAG_PET_NAME | GROUP_UPDATE_FLAG_PET_MODEL_ID | GROUP_UPDATE_FLAG_PET_AURAS;
if (powerType != POWER_MANA)
updateFlags |= GROUP_UPDATE_FLAG_POWER_TYPE;
if (pet)
updateFlags |= GROUP_UPDATE_FLAG_PET_GUID | GROUP_UPDATE_FLAG_PET_CUR_HP | GROUP_UPDATE_FLAG_PET_MAX_HP
| GROUP_UPDATE_FLAG_PET_POWER_TYPE | GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER;
if (player->GetVehicle())
updateFlags |= GROUP_UPDATE_FLAG_VEHICLE_SEAT;
uint16 playerStatus = MEMBER_STATUS_ONLINE;
if (player->IsPvP())
playerStatus |= MEMBER_STATUS_PVP;
if (!player->IsAlive())
{
if (player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
playerStatus |= MEMBER_STATUS_GHOST;
else
playerStatus |= MEMBER_STATUS_DEAD;
}
if (player->IsFFAPvP())
playerStatus |= MEMBER_STATUS_PVP_FFA;
if (player->isAFK())
playerStatus |= MEMBER_STATUS_AFK;
if (player->isDND())
playerStatus |= MEMBER_STATUS_DND;
data << uint32(updateFlags);
data << uint16(playerStatus); // GROUP_UPDATE_FLAG_STATUS
data << uint32(player->GetHealth()); // GROUP_UPDATE_FLAG_CUR_HP
data << uint32(player->GetMaxHealth()); // GROUP_UPDATE_FLAG_MAX_HP
if (updateFlags & GROUP_UPDATE_FLAG_POWER_TYPE)
data << uint8(powerType);
data << uint16(player->GetPower(powerType)); // GROUP_UPDATE_FLAG_CUR_POWER
data << uint16(player->GetMaxPower(powerType)); // GROUP_UPDATE_FLAG_MAX_POWER
data << uint16(player->getLevel()); // GROUP_UPDATE_FLAG_LEVEL
data << uint16(player->GetZoneId()); // GROUP_UPDATE_FLAG_ZONE
data << uint16(player->GetPositionX()); // GROUP_UPDATE_FLAG_POSITION
data << uint16(player->GetPositionY()); // GROUP_UPDATE_FLAG_POSITION
uint64 auraMask = 0;
size_t maskPos = data.wpos();
data << uint64(auraMask); // placeholder
for (uint8 i = 0; i < MAX_AURAS; ++i)
{
if (AuraApplication const* aurApp = player->GetVisibleAura(i))
{
auraMask |= uint64(1) << i;
data << uint32(aurApp->GetBase()->GetId());
data << uint8(aurApp->GetFlags());
}
}
data.put<uint64>(maskPos, auraMask); // GROUP_UPDATE_FLAG_AURAS
if (updateFlags & GROUP_UPDATE_FLAG_PET_GUID)
data << uint64(pet->GetGUID());
data << std::string(pet ? pet->GetName() : ""); // GROUP_UPDATE_FLAG_PET_NAME
data << uint16(pet ? pet->GetDisplayId() : 0); // GROUP_UPDATE_FLAG_PET_MODEL_ID
if (updateFlags & GROUP_UPDATE_FLAG_PET_CUR_HP)
data << uint32(pet->GetHealth());
if (updateFlags & GROUP_UPDATE_FLAG_PET_MAX_HP)
data << uint32(pet->GetMaxHealth());
if (updateFlags & GROUP_UPDATE_FLAG_PET_POWER_TYPE)
data << (uint8)pet->getPowerType();
if (updateFlags & GROUP_UPDATE_FLAG_PET_CUR_POWER)
data << uint16(pet->GetPower(pet->getPowerType()));
if (updateFlags & GROUP_UPDATE_FLAG_PET_MAX_POWER)
data << uint16(pet->GetMaxPower(pet->getPowerType()));
uint64 petAuraMask = 0;
maskPos = data.wpos();
data << uint64(petAuraMask); // placeholder
if (pet)
{
for (uint8 i = 0; i < MAX_AURAS; ++i)
{
if (AuraApplication const* aurApp = pet->GetVisibleAura(i))
{
petAuraMask |= uint64(1) << i;
data << uint32(aurApp->GetBase()->GetId());
data << uint8(aurApp->GetFlags());
}
}
}
data.put<uint64>(maskPos, petAuraMask); // GROUP_UPDATE_FLAG_PET_AURAS
if (updateFlags & GROUP_UPDATE_FLAG_VEHICLE_SEAT)
data << uint32(player->GetVehicle()->GetVehicleInfo()->m_seatID[player->m_movementInfo.transport.seat]);
SendPacket(&data);
}
/*!*/void WorldSession::HandleRequestRaidInfoOpcode(WorldPacket & /*recvData*/)
{
// every time the player checks the character screen
_player->SendRaidInfo();
}
/*void WorldSession::HandleGroupCancelOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("WORLD: got CMSG_GROUP_CANCEL.");
}*/
void WorldSession::HandleOptOutOfLootOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_OPT_OUT_OF_LOOT");
uint32 passOnLoot;
recvData >> passOnLoot; // 1 always pass, 0 do not pass
// ignore if player not loaded
if (!GetPlayer()) // needed because STATUS_AUTHED
{
if (passOnLoot != 0)
TC_LOG_ERROR("network", "CMSG_OPT_OUT_OF_LOOT value<>0 for not-loaded character!");
return;
}
GetPlayer()->SetPassOnGroupLoot(passOnLoot);
}