aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Player/Player.cpp3
-rw-r--r--src/server/game/Groups/Group.cpp205
-rw-r--r--src/server/game/Groups/Group.h27
-rw-r--r--src/server/game/Handlers/GroupHandler.cpp2
-rw-r--r--src/server/game/Handlers/LootHandler.cpp3
-rw-r--r--src/server/game/Loot/LootMgr.cpp22
-rw-r--r--src/server/game/Loot/LootMgr.h1
-rw-r--r--src/server/game/Server/Packets/LootPackets.cpp78
-rw-r--r--src/server/game/Server/Packets/LootPackets.h67
-rw-r--r--src/server/game/Server/Packets/PartyPackets.h8
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp20
11 files changed, 292 insertions, 144 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 77e2870a24e..52e4369123a 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -8423,8 +8423,7 @@ void Player::SendNotifyLootItemRemoved(ObjectGuid owner, ObjectGuid lootObj, uin
WorldPackets::Loot::LootRemoved packet;
packet.Owner = owner;
packet.LootObj = lootObj;
- // Since 6.x client expects loot to be starting from 1 hence the +1
- packet.LootListID = lootSlot+1;
+ packet.LootListID = lootSlot + 1;
GetSession()->SendPacket(packet.Write());
}
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index d855776fa3a..947c54357c8 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -38,7 +38,7 @@
#include "PartyPackets.h"
#include "LootPackets.h"
-Roll::Roll(ObjectGuid _guid, LootItem const& li) : itemGUID(_guid), itemid(li.itemid),
+Roll::Roll(LootItem const& li) : itemid(li.itemid),
itemRandomPropId(li.randomPropertyId), itemRandomSuffix(li.randomSuffix), itemCount(li.count),
totalPlayersRolling(0), totalNeed(0), totalGreed(0), totalPass(0), itemSlot(0),
rollVoteMask(ROLL_ALL_TYPE_NO_DISENCHANT) { }
@@ -598,7 +598,11 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R
roll->playerVote.erase(itr2);
- CountRollVote(guid, roll->itemGUID, MAX_ROLL_TYPE);
+ if (roll->totalPass + roll->totalNeed + roll->totalGreed >= roll->totalPlayersRolling)
+ {
+ CountTheRoll(it);
+ it = RollId.begin();
+ }
}
// Update subgroups
@@ -785,12 +789,8 @@ void Group::Disband(bool hideDestroy /* = false */)
if (!player->GetSession())
continue;
- WorldPacket data;
if (!hideDestroy)
- {
- data.Initialize(SMSG_GROUP_DESTROYED, 0);
- player->GetSession()->SendPacket(&data);
- }
+ player->SendDirectMessage(WorldPackets::Party::GroupDestroyed().Write());
//we already removed player from group and in player->GetGroup() is his original group, send update
if (Group* group = player->GetGroup())
@@ -799,10 +799,14 @@ void Group::Disband(bool hideDestroy /* = false */)
}
else
{
- data.Initialize(SMSG_PARTY_UPDATE, 1+1+1+1+8+4+4+8);
- data << uint8(0x10) << uint8(0) << uint8(0) << uint8(0);
- data << m_guid << uint32(m_counter) << uint32(0) << uint64(0);
- player->GetSession()->SendPacket(&data);
+ WorldPackets::Party::PartyUpdate partyUpdate;
+ partyUpdate.PartyFlags = GROUP_FLAG_DESTROYED;
+ partyUpdate.PartyIndex = 1; // 0 = original group, 1 = instance/bg group
+ partyUpdate.PartyType = GROUP_TYPE_NONE;
+ partyUpdate.PartyGUID = m_guid;
+ partyUpdate.MyIndex = -1;
+ partyUpdate.SequenceNum = m_counter;
+ player->GetSession()->SendPacket(partyUpdate.Write());
}
_homebindIfInstance(player);
@@ -844,67 +848,52 @@ void Group::Disband(bool hideDestroy /* = false */)
/*********************************************************/
/*** LOOT SYSTEM ***/
/*********************************************************/
+void Group::SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p, bool canNeed, Roll const& r) const
+{
+ WorldPackets::Loot::StartLootRoll startLootRoll;
+ startLootRoll.LootObj = r->GetGUID();
+ startLootRoll.MapID = mapId;
+ startLootRoll.RollTime = countDown;
+ startLootRoll.ValidRolls = r.rollVoteMask;
+ if (!canNeed)
+ startLootRoll.ValidRolls &= ~ROLL_FLAG_TYPE_NEED;
+ startLootRoll.Method = GetLootMethod();
+ r.FillPacket(startLootRoll.Item);
+
+ p->GetSession()->SendPacket(startLootRoll.Write());
+}
-void Group::SendLootStartRoll(uint32 countDown, uint32 mapid, const Roll &r)
+void Group::SendLootRoll(ObjectGuid playerGuid, int32 rollNumber, uint8 rollType, Roll const& roll) const
{
- WorldPacket data(SMSG_START_LOOT_ROLL, (8+4+4+4+4+4+4+1));
- data << r.itemGUID; // guid of rolled item
- data << uint32(mapid); // 3.3.3 mapid
- data << uint32(r.itemSlot); // itemslot
- data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for
- data << uint32(r.itemRandomSuffix); // randomSuffix
- data << uint32(r.itemRandomPropId.Id); // item random property ID
- data << uint32(r.itemCount); // items in stack
- data << uint32(countDown); // the countdown time to choose "need" or "greed"
- data << uint8(r.rollVoteMask); // roll type mask
- data << uint8(r.totalPlayersRolling); // maybe the number of players rolling for it???
+ WorldPackets::Loot::LootRollBroadcast lootRoll;
+ lootRoll.LootObj = roll->GetGUID();
+ lootRoll.Player = playerGuid;
+ lootRoll.Roll = rollNumber;
+ lootRoll.RollType = rollType;
+ roll.FillPacket(lootRoll.Item);
+ lootRoll.Write();
- for (Roll::PlayerVote::const_iterator itr=r.playerVote.begin(); itr != r.playerVote.end(); ++itr)
+ for (Roll::PlayerVote::const_iterator itr = roll.playerVote.begin(); itr != roll.playerVote.end(); ++itr)
{
Player* p = ObjectAccessor::FindConnectedPlayer(itr->first);
if (!p || !p->GetSession())
continue;
- if (itr->second == NOT_EMITED_YET)
- p->GetSession()->SendPacket(&data);
+ if (itr->second != NOT_VALID)
+ p->GetSession()->SendPacket(lootRoll.GetRawPacket());
}
}
-void Group::SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p, bool canNeed, Roll const& r)
+void Group::SendLootRollWon(ObjectGuid winnerGuid, int32 rollNumber, uint8 rollType, Roll const& roll) const
{
- if (!p || !p->GetSession())
- return;
-
- WorldPacket data(SMSG_START_LOOT_ROLL, (8 + 4 + 4 + 4 + 4 + 4 + 4 + 1));
- data << r.itemGUID; // guid of rolled item
- data << uint32(mapId); // 3.3.3 mapid
- data << uint32(r.itemSlot); // itemslot
- data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for
- data << uint32(r.itemRandomSuffix); // randomSuffix
- data << uint32(r.itemRandomPropId.Id); // item random property ID
- data << uint32(r.itemCount); // items in stack
- data << uint32(countDown); // the countdown time to choose "need" or "greed"
- uint8 voteMask = r.rollVoteMask;
- if (!canNeed)
- voteMask &= ~ROLL_FLAG_TYPE_NEED;
- data << uint8(voteMask); // roll type mask
- data << uint8(r.totalPlayersRolling); // maybe the number of players rolling for it???
-
- p->GetSession()->SendPacket(&data);
-}
-
-void Group::SendLootRoll(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rollNumber, uint8 rollType, Roll const& roll)
-{
- WorldPacket data(SMSG_LOOT_ROLL, (8+4+8+4+4+4+1+1+1));
- data << sourceGuid; // guid of the item rolled
- data << uint32(roll.itemSlot); // slot
- data << targetGuid;
- data << uint32(roll.itemid); // the itemEntryId for the item that shall be rolled for
- data << uint32(roll.itemRandomSuffix); // randomSuffix
- data << uint32(roll.itemRandomPropId.Id); // Item random property ID
- data << uint32(rollNumber); // 0: "Need for: [item name]" > 127: "you passed on: [item name]" Roll number
- data << uint8(rollType); // 0: "Need for: [item name]" 0: "You have selected need for [item name] 1: need roll 2: greed roll
- data << uint8(0); // 1: "You automatically passed on: %s because you cannot loot that item." - Possibly used in need befor greed
+ WorldPackets::Loot::LootRollWon lootRollWon;
+ lootRollWon.LootObj = roll->GetGUID();
+ lootRollWon.Winner = winnerGuid;
+ lootRollWon.Roll = rollNumber;
+ lootRollWon.RollType = rollType;
+ roll.FillPacket(lootRollWon.Item);
+ lootRollWon.MainSpec = true; // offspec rolls not implemented
+ lootRollWon.Write();
for (Roll::PlayerVote::const_iterator itr = roll.playerVote.begin(); itr != roll.playerVote.end(); ++itr)
{
@@ -913,41 +902,34 @@ void Group::SendLootRoll(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rol
continue;
if (itr->second != NOT_VALID)
- p->GetSession()->SendPacket(&data);
+ p->GetSession()->SendPacket(lootRollWon.GetRawPacket());
}
}
-void Group::SendLootRollWon(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rollNumber, uint8 rollType, Roll const& roll)
+void Group::SendLootAllPassed(Roll const& roll) const
{
- WorldPacket data(SMSG_LOOT_ROLL_WON, (8+4+4+4+4+8+1+1));
- data << sourceGuid; // guid of the item rolled
- data << uint32(roll.itemSlot); // slot
- data << uint32(roll.itemid); // the itemEntryId for the item that shall be rolled for
- data << uint32(roll.itemRandomSuffix); // randomSuffix
- data << uint32(roll.itemRandomPropId.Id); // Item random property
- data << targetGuid; // guid of the player who won.
- data << uint32(rollNumber); // rollnumber realted to SMSG_LOOT_ROLL
- data << uint8(rollType); // rollType related to SMSG_LOOT_ROLL
+ WorldPackets::Loot::LootAllPassed lootAllPassed;
+ lootAllPassed.LootObj = roll->GetGUID();
+ roll.FillPacket(lootAllPassed.Item);
+ lootAllPassed.Write();
for (Roll::PlayerVote::const_iterator itr = roll.playerVote.begin(); itr != roll.playerVote.end(); ++itr)
{
- Player* p = ObjectAccessor::FindConnectedPlayer(itr->first);
- if (!p || !p->GetSession())
+ Player* player = ObjectAccessor::FindConnectedPlayer(itr->first);
+ if (!player || !player->GetSession())
continue;
if (itr->second != NOT_VALID)
- p->GetSession()->SendPacket(&data);
+ player->GetSession()->SendPacket(lootAllPassed.GetRawPacket());
}
}
-void Group::SendLootAllPassed(Roll const& roll)
+void Group::SendLootRollsComplete(Roll const& roll) const
{
- WorldPacket data(SMSG_LOOT_ALL_PASSED, (8+4+4+4+4));
- data << roll.itemGUID; // Guid of the item rolled
- data << uint32(roll.itemSlot); // Item loot slot
- data << uint32(roll.itemid); // The itemEntryId for the item that shall be rolled for
- data << uint32(roll.itemRandomPropId.Id); // Item random property ID
- data << uint32(roll.itemRandomSuffix); // Item random suffix ID
+ WorldPackets::Loot::LootRollsComplete lootRollsComplete;
+ lootRollsComplete.LootObj = roll->GetGUID();
+ lootRollsComplete.LootListID = roll.itemSlot + 1;
+ lootRollsComplete.Write();
for (Roll::PlayerVote::const_iterator itr = roll.playerVote.begin(); itr != roll.playerVote.end(); ++itr)
{
@@ -956,7 +938,7 @@ void Group::SendLootAllPassed(Roll const& roll)
continue;
if (itr->second != NOT_VALID)
- player->GetSession()->SendPacket(&data);
+ player->GetSession()->SendPacket(lootRollsComplete.GetRawPacket());
}
}
@@ -992,8 +974,7 @@ void Group::GroupLoot(Loot* loot, WorldObject* lootedObject)
//roll for over-threshold item if it's one-player loot
if (item->GetQuality() >= uint32(m_lootThreshold))
{
- ObjectGuid newitemGUID = ObjectGuid::Create<HighGuid::Item>(sObjectMgr->GetGenerator<HighGuid::Item>().Generate());
- Roll* r = new Roll(newitemGUID, *i);
+ Roll* r = new Roll(*i);
for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
@@ -1036,7 +1017,7 @@ void Group::GroupLoot(Loot* loot, WorldObject* lootedObject)
continue;
if (itr->second == PASS)
- SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r);
+ SendLootRoll(p->GetGUID(), -1, ROLL_PASS, *r);
else
SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, p->CanRollForItemInLFG(item, lootedObject) == EQUIP_ERR_OK, *r);
}
@@ -1067,8 +1048,7 @@ void Group::GroupLoot(Loot* loot, WorldObject* lootedObject)
continue;
item = sObjectMgr->GetItemTemplate(i->itemid);
- ObjectGuid newitemGUID = ObjectGuid::Create<HighGuid::Item>(sObjectMgr->GetGenerator<HighGuid::Item>().Generate());
- Roll* r = new Roll(newitemGUID, *i);
+ Roll* r = new Roll(*i);
for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
@@ -1099,7 +1079,7 @@ void Group::GroupLoot(Loot* loot, WorldObject* lootedObject)
continue;
if (itr->second == PASS)
- SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r);
+ SendLootRoll(p->GetGUID(), -1, ROLL_PASS, *r);
else
SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, p->CanRollForItemInLFG(item, lootedObject) == EQUIP_ERR_OK, *r);
}
@@ -1170,14 +1150,14 @@ void Group::MasterLoot(Loot* loot, WorldObject* pLootedObject)
}
}
-void Group::CountRollVote(ObjectGuid playerGUID, ObjectGuid Guid, uint8 Choice)
+void Group::CountRollVote(ObjectGuid playerGuid, ObjectGuid lootObjectGuid, uint8 lootListId, uint8 choice)
{
- Rolls::iterator rollI = GetRoll(Guid);
+ Rolls::iterator rollI = GetRoll(lootObjectGuid, lootListId);
if (rollI == RollId.end())
return;
Roll* roll = *rollI;
- Roll::PlayerVote::iterator itr = roll->playerVote.find(playerGUID);
+ Roll::PlayerVote::iterator itr = roll->playerVote.find(playerGuid);
// this condition means that player joins to the party after roll begins
if (itr == roll->playerVote.end())
return;
@@ -1186,25 +1166,25 @@ void Group::CountRollVote(ObjectGuid playerGUID, ObjectGuid Guid, uint8 Choice)
if (roll->getLoot()->items.empty())
return;
- switch (Choice)
+ switch (choice)
{
case ROLL_PASS: // Player choose pass
- SendLootRoll(ObjectGuid::Empty, playerGUID, 128, ROLL_PASS, *roll);
+ SendLootRoll(playerGuid, -1, ROLL_PASS, *roll);
++roll->totalPass;
itr->second = PASS;
break;
case ROLL_NEED: // player choose Need
- SendLootRoll(ObjectGuid::Empty, playerGUID, 0, 0, *roll);
+ SendLootRoll(playerGuid, 0, ROLL_NEED, *roll);
++roll->totalNeed;
itr->second = NEED;
break;
case ROLL_GREED: // player choose Greed
- SendLootRoll(ObjectGuid::Empty, playerGUID, 128, ROLL_GREED, *roll);
+ SendLootRoll(playerGuid, -7, ROLL_GREED, *roll);
++roll->totalGreed;
itr->second = GREED;
break;
case ROLL_DISENCHANT: // player choose Disenchant
- SendLootRoll(ObjectGuid::Empty, playerGUID, 128, ROLL_DISENCHANT, *roll);
+ SendLootRoll(playerGuid, -8, ROLL_DISENCHANT, *roll);
++roll->totalGreed;
itr->second = DISENCHANT;
break;
@@ -1219,7 +1199,8 @@ void Group::EndRoll(Loot* pLoot)
{
for (Rolls::iterator itr = RollId.begin(); itr != RollId.end();)
{
- if ((*itr)->getLoot() == pLoot) {
+ if ((*itr)->getLoot() == pLoot)
+ {
CountTheRoll(itr); //i don't have to edit player votes, who didn't vote ... he will pass
itr = RollId.begin();
}
@@ -1253,14 +1234,14 @@ void Group::CountTheRoll(Rolls::iterator rollI)
continue;
uint8 randomN = urand(1, 100);
- SendLootRoll(ObjectGuid::Empty, itr->first, randomN, ROLL_NEED, *roll);
+ SendLootRoll(itr->first, randomN, ROLL_NEED, *roll);
if (maxresul < randomN)
{
maxguid = itr->first;
maxresul = randomN;
}
}
- SendLootRollWon(ObjectGuid::Empty, maxguid, maxresul, ROLL_NEED, *roll);
+ SendLootRollWon(maxguid, maxresul, ROLL_NEED, *roll);
player = ObjectAccessor::FindConnectedPlayer(maxguid);
if (player && player->GetSession())
@@ -1301,7 +1282,7 @@ void Group::CountTheRoll(Rolls::iterator rollI)
continue;
uint8 randomN = urand(1, 100);
- SendLootRoll(ObjectGuid::Empty, itr->first, randomN, itr->second, *roll);
+ SendLootRoll(itr->first, randomN, itr->second, *roll);
if (maxresul < randomN)
{
maxguid = itr->first;
@@ -1309,7 +1290,7 @@ void Group::CountTheRoll(Rolls::iterator rollI)
rollvote = itr->second;
}
}
- SendLootRollWon(ObjectGuid::Empty, maxguid, maxresul, rollvote, *roll);
+ SendLootRollWon(maxguid, maxresul, rollvote, *roll);
player = ObjectAccessor::FindConnectedPlayer(maxguid);
if (player && player->GetSession())
@@ -1374,6 +1355,8 @@ void Group::CountTheRoll(Rolls::iterator rollI)
item->is_blocked = false;
}
+ SendLootRollsComplete(*roll);
+
RollId.erase(rollI);
delete roll;
}
@@ -1862,6 +1845,18 @@ void Roll::targetObjectBuildLink()
getTarget()->addLootValidatorRef(this);
}
+void Roll::FillPacket(WorldPackets::Loot::LootItemData& lootItem) const
+{
+ lootItem.UIType = (totalPlayersRolling > totalNeed + totalGreed + totalPass) ? LOOT_SLOT_TYPE_ROLL_ONGOING : LOOT_SLOT_TYPE_ALLOW_LOOT;
+ lootItem.Quantity = itemCount;
+ lootItem.LootListID = itemSlot + 1;
+ if (LootItem const* lootItemInSlot = (*this)->GetItemInSlot(itemSlot))
+ {
+ lootItem.CanTradeToTapList = lootItemInSlot->allowedGUIDs.size() > 1;
+ lootItem.Loot.Initialize(*lootItemInSlot);
+ }
+}
+
void Group::SetDungeonDifficultyID(Difficulty difficulty)
{
m_dungeonDifficulty = difficulty;
@@ -2525,12 +2520,12 @@ void Group::SetGroupMemberFlag(ObjectGuid guid, bool apply, GroupMemberFlags fla
SendUpdate();
}
-Group::Rolls::iterator Group::GetRoll(ObjectGuid Guid)
+Group::Rolls::iterator Group::GetRoll(ObjectGuid lootObjectGuid, uint8 lootListId)
{
- Rolls::iterator iter;
- for (iter=RollId.begin(); iter != RollId.end(); ++iter)
- if ((*iter)->itemGUID == Guid && (*iter)->isValid())
+ for (Rolls::iterator iter = RollId.begin(); iter != RollId.end(); ++iter)
+ if ((**iter)->GetGUID() == lootObjectGuid && (*iter)->itemSlot == lootListId && (*iter)->isValid())
return iter;
+
return RollId.end();
}
diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h
index bf29b8f8a50..93292fe4582 100644
--- a/src/server/game/Groups/Group.h
+++ b/src/server/game/Groups/Group.h
@@ -39,6 +39,14 @@ class WorldSession;
struct MapEntry;
+namespace WorldPackets
+{
+ namespace Loot
+ {
+ struct LootItemData;
+ }
+}
+
#define MAX_GROUP_SIZE 5
#define MAX_RAID_SIZE 40
#define MAX_RAID_SUBGROUPS MAX_RAID_SIZE / MAX_GROUP_SIZE
@@ -100,6 +108,7 @@ enum GroupFlags
GROUP_FLAG_RAID = 0x002,
GROUP_FLAG_LFG_RESTRICTED = 0x004, // Script_HasLFGRestrictions()
GROUP_FLAG_LFG = 0x008,
+ GROUP_FLAG_DESTROYED = 0x010,
GROUP_FLAG_ONE_PERSON_PARTY = 0x020, // Script_IsOnePersonParty()
GROUP_FLAG_EVERYONE_ASSISTANT = 0x040, // Script_IsEveryoneAssistant()
GROUP_FLAG_GUILD_GROUP = 0x100,
@@ -154,13 +163,13 @@ enum GroupUpdatePetFlags
class Roll : public LootValidatorRef
{
public:
- Roll(ObjectGuid _guid, LootItem const& li);
+ explicit Roll(LootItem const& li);
~Roll();
void setLoot(Loot* pLoot);
Loot* getLoot();
void targetObjectBuildLink() override;
+ void FillPacket(WorldPackets::Loot::LootItemData& lootItem) const;
- ObjectGuid itemGUID;
uint32 itemid;
ItemRandomEnchantmentId itemRandomPropId;
uint32 itemRandomSuffix;
@@ -361,17 +370,17 @@ class TC_GAME_API Group
/*********************************************************/
bool isRollLootActive() const { return !RollId.empty(); }
- void SendLootStartRoll(uint32 CountDown, uint32 mapid, const Roll &r);
- void SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p, bool canNeed, Roll const& r);
- void SendLootRoll(ObjectGuid SourceGuid, ObjectGuid TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r);
- void SendLootRollWon(ObjectGuid SourceGuid, ObjectGuid TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r);
- void SendLootAllPassed(Roll const& roll);
+ void SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p, bool canNeed, Roll const& r) const;
+ void SendLootRoll(ObjectGuid playerGuid, int32 rollNumber, uint8 rollType, Roll const& roll) const;
+ void SendLootRollWon(ObjectGuid winnerGuid, int32 rollNumber, uint8 rollType, Roll const& roll) const;
+ void SendLootAllPassed(Roll const& roll) const;
+ void SendLootRollsComplete(Roll const& roll) const;
void SendLooter(Creature* creature, Player* pLooter);
void GroupLoot(Loot* loot, WorldObject* pLootedObject);
void MasterLoot(Loot* loot, WorldObject* pLootedObject);
- Rolls::iterator GetRoll(ObjectGuid Guid);
+ Rolls::iterator GetRoll(ObjectGuid lootObjectGuid, uint8 lootListId);
void CountTheRoll(Rolls::iterator roll);
- void CountRollVote(ObjectGuid playerGUID, ObjectGuid Guid, uint8 Choise);
+ void CountRollVote(ObjectGuid playerGuid, ObjectGuid lootObjectGuid, uint8 lootListId, uint8 choice);
void EndRoll(Loot* loot);
// related to disenchant rolls
diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp
index 7a148ff624c..2b13a814244 100644
--- a/src/server/game/Handlers/GroupHandler.cpp
+++ b/src/server/game/Handlers/GroupHandler.cpp
@@ -379,7 +379,7 @@ void WorldSession::HandleLootRoll(WorldPackets::Loot::LootRoll& packet)
if (!group)
return;
- group->CountRollVote(GetPlayer()->GetGUID(), packet.LootObj, packet.RollType);
+ group->CountRollVote(GetPlayer()->GetGUID(), packet.LootObj, packet.LootListID - 1, packet.RollType);
switch (packet.RollType)
{
diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp
index ea72586a4d8..9b6a8923615 100644
--- a/src/server/game/Handlers/LootHandler.cpp
+++ b/src/server/game/Handlers/LootHandler.cpp
@@ -91,8 +91,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPackets::Loot::LootItem& p
loot = &creature->loot;
}
- // Since 6.x client sends loot starting from 1 hence the -1
- player->StoreLootItem(req.LootListID-1, loot);
+ player->StoreLootItem(req.LootListID - 1, loot);
// If player is removing the last LootItem, delete the empty container.
if (loot->isLooted() && lguid.IsItem())
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index caf06cfb3a5..e4a9ef76a1e 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -447,6 +447,18 @@ void Loot::AddItem(LootStoreItem const& item)
}
}
+LootItem const* Loot::GetItemInSlot(uint32 lootSlot) const
+{
+ if (lootSlot < items.size())
+ return &items[lootSlot];
+
+ lootSlot -= uint32(items.size());
+ if (lootSlot < quest_items.size())
+ return &quest_items[lootSlot];
+
+ return nullptr;
+}
+
// Calls processor of corresponding LootTemplate (which handles everything including references)
bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError, uint16 lootMode /*= LOOT_MODE_DEFAULT*/)
{
@@ -913,7 +925,7 @@ void Loot::BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player* v
continue;
WorldPackets::Loot::LootItemData lootItem;
- lootItem.LootListID = packet.Items.size()+1;
+ lootItem.LootListID = i + 1;
lootItem.UIType = slot_type;
lootItem.Quantity = items[i].count;
lootItem.Loot.Initialize(items[i]);
@@ -930,7 +942,7 @@ void Loot::BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player* v
if (!items[i].is_looted && !items[i].freeforall && items[i].conditions.empty() && items[i].AllowedForPlayer(viewer))
{
WorldPackets::Loot::LootItemData lootItem;
- lootItem.LootListID = packet.Items.size()+1;
+ lootItem.LootListID = i + 1;
lootItem.UIType = permission == OWNER_PERMISSION ? LOOT_SLOT_TYPE_OWNER : LOOT_SLOT_TYPE_ALLOW_LOOT;
lootItem.Quantity = items[i].count;
lootItem.Loot.Initialize(items[i]);
@@ -955,7 +967,7 @@ void Loot::BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player* v
if (!qi->is_looted && !item.is_looted)
{
WorldPackets::Loot::LootItemData lootItem;
- lootItem.LootListID = packet.Items.size()+1;
+ lootItem.LootListID = items.size() + qi->index + 1;
lootItem.Quantity = item.count;
lootItem.Loot.Initialize(item);
@@ -999,7 +1011,7 @@ void Loot::BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player* v
if (!fi->is_looted && !item.is_looted)
{
WorldPackets::Loot::LootItemData lootItem;
- lootItem.LootListID = packet.Items.size()+1;
+ lootItem.LootListID = items.size() + fi->index + 1;
lootItem.UIType = slotType;
lootItem.Quantity = item.count;
lootItem.Loot.Initialize(item);
@@ -1019,7 +1031,7 @@ void Loot::BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player* v
if (!ci->is_looted && !item.is_looted)
{
WorldPackets::Loot::LootItemData lootItem;
- lootItem.LootListID = packet.Items.size()+1;
+ lootItem.LootListID = items.size() + ci->index + 1;
lootItem.Quantity = item.count;
lootItem.Loot.Initialize(item);
diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h
index b7d3ba2123b..e64661aa337 100644
--- a/src/server/game/Loot/LootMgr.h
+++ b/src/server/game/Loot/LootMgr.h
@@ -384,6 +384,7 @@ struct TC_GAME_API Loot
// Inserts the item into the loot (called by LootTemplate processors)
void AddItem(LootStoreItem const & item);
+ LootItem const* GetItemInSlot(uint32 lootSlot) const;
LootItem* LootItemInSlot(uint32 lootslot, Player* player, QuestItem** qitem = NULL, QuestItem** ffaitem = NULL, QuestItem** conditem = NULL);
uint32 GetMaxSlotInLootFor(Player* player) const;
bool hasItemFor(Player* player) const;
diff --git a/src/server/game/Server/Packets/LootPackets.cpp b/src/server/game/Server/Packets/LootPackets.cpp
index 9e1dfb719a1..ff61790e2fe 100644
--- a/src/server/game/Server/Packets/LootPackets.cpp
+++ b/src/server/game/Server/Packets/LootPackets.cpp
@@ -17,6 +17,19 @@
#include "LootPackets.h"
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Loot::LootItemData const& lootItem)
+{
+ data.WriteBits(lootItem.Type, 2);
+ data.WriteBits(lootItem.UIType, 3);
+ data.WriteBit(lootItem.CanTradeToTapList);
+ data.FlushBits();
+ data << lootItem.Loot; // WorldPackets::Item::ItemInstance
+ data << uint32(lootItem.Quantity);
+ data << uint8(lootItem.LootItemType);
+ data << uint8(lootItem.LootListID);
+ return data;
+}
+
void WorldPackets::Loot::LootUnit::Read()
{
_worldPacket >> Unit;
@@ -39,16 +52,7 @@ WorldPacket const* WorldPackets::Loot::LootResponse::Write()
_worldPacket.FlushBits();
for (LootItemData const& item : Items)
- {
- _worldPacket.WriteBits(item.Type, 2);
- _worldPacket.WriteBits(item.UIType, 3);
- _worldPacket.WriteBit(item.CanTradeToTapList);
- _worldPacket.FlushBits();
- _worldPacket << item.Loot; // WorldPackets::Item::ItemInstance
- _worldPacket << uint32(item.Quantity);
- _worldPacket << uint8(item.LootItemType);
- _worldPacket << uint8(item.LootListID);
- }
+ _worldPacket << item;
for (LootCurrency const& currency : Currencies)
{
@@ -142,3 +146,57 @@ void WorldPackets::Loot::SetLootSpecialization::Read()
{
_worldPacket >> SpecID;
}
+
+WorldPacket const* WorldPackets::Loot::StartLootRoll::Write()
+{
+ _worldPacket << LootObj;
+ _worldPacket << int32(MapID);
+ _worldPacket << uint32(RollTime);
+ _worldPacket << uint8(ValidRolls);
+ _worldPacket << uint8(Method);
+ _worldPacket << Item;
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Loot::LootRollBroadcast::Write()
+{
+ _worldPacket << LootObj;
+ _worldPacket << Player;
+ _worldPacket << int32(Roll);
+ _worldPacket << uint8(RollType);
+ _worldPacket << Item;
+ _worldPacket.WriteBit(Autopassed);
+ _worldPacket.FlushBits();
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Loot::LootRollWon::Write()
+{
+ _worldPacket << LootObj;
+ _worldPacket << Winner;
+ _worldPacket << int32(Roll);
+ _worldPacket << uint8(RollType);
+ _worldPacket << Item;
+ _worldPacket.WriteBit(MainSpec);
+ _worldPacket.FlushBits();
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Loot::LootAllPassed::Write()
+{
+ _worldPacket << LootObj;
+ _worldPacket << Item;
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Loot::LootRollsComplete::Write()
+{
+ _worldPacket << LootObj;
+ _worldPacket << uint8(LootListID);
+
+ return &_worldPacket;
+}
diff --git a/src/server/game/Server/Packets/LootPackets.h b/src/server/game/Server/Packets/LootPackets.h
index cbe900211a3..9074b58bab1 100644
--- a/src/server/game/Server/Packets/LootPackets.h
+++ b/src/server/game/Server/Packets/LootPackets.h
@@ -188,6 +188,73 @@ namespace WorldPackets
uint32 SpecID = 0;
};
+
+ class StartLootRoll final : public ServerPacket
+ {
+ public:
+ StartLootRoll() : ServerPacket(SMSG_START_LOOT_ROLL) { }
+
+ WorldPacket const* Write() override;
+
+ ObjectGuid LootObj;
+ int32 MapID = 0;
+ uint32 RollTime = 0;
+ uint8 Method = 0;
+ uint8 ValidRolls = 0;
+ LootItemData Item;
+ };
+
+ class LootRollBroadcast : public ServerPacket
+ {
+ public:
+ LootRollBroadcast() : ServerPacket(SMSG_LOOT_ROLL) { }
+
+ WorldPacket const* Write() override;
+
+ ObjectGuid LootObj;
+ ObjectGuid Player;
+ int32 Roll = 0; ///< Roll value can be negative, it means that it is an "offspec" roll but only during roll selection broadcast (not when sending the result)
+ uint8 RollType = 0;
+ LootItemData Item;
+ bool Autopassed = false; ///< Triggers message |HlootHistory:%d|h[Loot]|h: You automatically passed on: %s because you cannot loot that item.
+ };
+
+ class LootRollWon : public ServerPacket
+ {
+ public:
+ LootRollWon() : ServerPacket(SMSG_LOOT_ROLL_WON) { }
+
+ WorldPacket const* Write() override;
+
+ ObjectGuid LootObj;
+ ObjectGuid Winner;
+ int32 Roll = 0;
+ uint8 RollType = 0;
+ LootItemData Item;
+ bool MainSpec = false;
+ };
+
+ class LootAllPassed : public ServerPacket
+ {
+ public:
+ LootAllPassed() : ServerPacket(SMSG_LOOT_ALL_PASSED) { }
+
+ WorldPacket const* Write() override;
+
+ ObjectGuid LootObj;
+ LootItemData Item;
+ };
+
+ class LootRollsComplete : public ServerPacket
+ {
+ public:
+ LootRollsComplete() : ServerPacket(SMSG_LOOT_ROLLS_COMPLETE, 16 + 1) { }
+
+ WorldPacket const* Write() override;
+
+ ObjectGuid LootObj;
+ uint8 LootListID = 0;
+ };
}
}
diff --git a/src/server/game/Server/Packets/PartyPackets.h b/src/server/game/Server/Packets/PartyPackets.h
index 847a024138e..757fbdb0e78 100644
--- a/src/server/game/Server/Packets/PartyPackets.h
+++ b/src/server/game/Server/Packets/PartyPackets.h
@@ -614,6 +614,14 @@ namespace WorldPackets
ObjectGuid Player;
ObjectGuid Victim;
};
+
+ class GroupDestroyed final : public ServerPacket
+ {
+ public:
+ GroupDestroyed() : ServerPacket(SMSG_GROUP_DESTROYED, 0) { }
+
+ WorldPacket const* Write() override { return &_worldPacket; }
+ };
}
}
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index 1bb358f7f73..74d59b96e78 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -1321,17 +1321,17 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_COMPLETE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOG_XP_GAIN, STATUS_NEVER, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ALL_PASSED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ITEM_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_LIST, STATUS_NEVER, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_MONEY_NOTIFY, STATUS_NEVER, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RELEASE, STATUS_NEVER, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RELEASE_ALL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ALL_PASSED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ITEM_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_LIST, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_MONEY_NOTIFY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RELEASE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RELEASE_ALL, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_REMOVED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ROLL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ROLLS_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ROLL_WON, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ROLL, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ROLLS_COMPLETE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ROLL_WON, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOSS_OF_CONTROL_AURA_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAIL_COMMAND_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAIL_LIST_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM);
@@ -1694,7 +1694,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_STAND_STATE_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_ELAPSED_TIMER, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_ELAPSED_TIMERS, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_LOOT_ROLL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_LOOT_ROLL, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_MIRROR_TIMER, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_START_TIMER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_STOP_ELAPSED_TIMER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);