diff options
author | Shauren <shauren.trinity@gmail.com> | 2016-12-27 21:36:40 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2016-12-27 21:36:40 +0100 |
commit | fe26f8ae48bd2da160ba4cf42900e0983575b96c (patch) | |
tree | 043ec6e36594d2df4ea4c873b51e3f593a5d9348 /src/server/game | |
parent | 87427321497aad5ba3c6dbc1b7f4838f255e052b (diff) |
Core/Loot: Fixed group loot
Closes #17696
Diffstat (limited to 'src/server/game')
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Groups/Group.cpp | 205 | ||||
-rw-r--r-- | src/server/game/Groups/Group.h | 27 | ||||
-rw-r--r-- | src/server/game/Handlers/GroupHandler.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Handlers/LootHandler.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Loot/LootMgr.cpp | 22 | ||||
-rw-r--r-- | src/server/game/Loot/LootMgr.h | 1 | ||||
-rw-r--r-- | src/server/game/Server/Packets/LootPackets.cpp | 78 | ||||
-rw-r--r-- | src/server/game/Server/Packets/LootPackets.h | 67 | ||||
-rw-r--r-- | src/server/game/Server/Packets/PartyPackets.h | 8 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 20 |
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); |