From 8745ac9c2e5448b9866b63e7f22121cb58690a2c Mon Sep 17 00:00:00 2001 From: Kitzunu <24550914+Kitzunu@users.noreply.github.com> Date: Thu, 4 Jul 2024 19:21:00 +0200 Subject: [PATCH] =?UTF-8?q?fix(Core/Loot):=20implement=20automatic=20pass?= =?UTF-8?q?=20in=20group=20loot=20for=20items=20that=E2=80=A6=20(#19272)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(Core/Loot): implement automatic pass in group loot for items that cannot be looted * cherry-pick commit (https://github.com/TrinityCore/TrinityCore/commit/00fdf6e99a2516095889e13d4638efa049782ce5) * closes https://github.com/chromiecraft/chromiecraft/issues/4523 Co-Authored-By: Wyrserth <43747507+Wyrserth@users.noreply.github.com> * whoopise --------- Co-authored-by: Wyrserth <43747507+Wyrserth@users.noreply.github.com> --- src/server/game/Groups/Group.cpp | 114 +++++++++++++++++++------------ src/server/game/Groups/Group.h | 2 +- 2 files changed, 73 insertions(+), 43 deletions(-) diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 630856b7a..c9e8a5896 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -898,7 +898,7 @@ void Group::SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p, p->GetSession()->SendPacket(&data); } -void Group::SendLootRoll(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rollNumber, uint8 rollType, Roll const& roll) +void Group::SendLootRoll(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rollNumber, uint8 rollType, Roll const& roll, bool autoPass) { WorldPacket data(SMSG_LOOT_ROLL, (8 + 4 + 8 + 4 + 4 + 4 + 1 + 1 + 1)); data << sourceGuid; // guid of the item rolled @@ -909,7 +909,7 @@ void Group::SendLootRoll(ObjectGuid sourceGuid, ObjectGuid targetGuid, uint8 rol data << uint32(roll.itemRandomPropId); // Item random property ID data << uint8(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 + data << uint8(autoPass); // 1: "You automatically passed on: %s because you cannot loot that item." for (Roll::PlayerVote::const_iterator itr = roll.playerVote.begin(); itr != roll.playerVote.end(); ++itr) { @@ -986,6 +986,23 @@ void Group::SendLooter(Creature* creature, Player* groupLooter) BroadcastPacket(&data, false); } +bool CanRollOnItem(LootItem const& item, Player const* player, Loot* loot) +{ + // Players can't roll on unique items if they already reached the maximum quantity of that item + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid); + if (!proto) + return false; + + uint32 itemCount = player->GetItemCount(item.itemid); + if ((proto->MaxCount > 0 && static_cast(itemCount) >= proto->MaxCount) || (player->CanEquipUniqueItem(proto) != EQUIP_ERR_OK)) + return false; + + if (!item.AllowedForPlayer(player, loot->sourceWorldObjectGUID)) + return false; + + return true; +} + void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject) { std::vector::iterator i; @@ -1013,23 +1030,20 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject) for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* member = itr->GetSource(); - if (!member) + if (!member || !member->GetSession()) continue; if (member->IsAtLootRewardDistance(pLootedObject)) { - if (i->AllowedForPlayer(member, loot->sourceWorldObjectGUID)) - { - r->totalPlayersRolling++; + r->totalPlayersRolling++; - if (member->GetPassOnGroupLoot()) - { - r->playerVote[member->GetGUID()] = PASS; - r->totalPass++; - // can't broadcast the pass now. need to wait until all rolling players are known. - } - else - r->playerVote[member->GetGUID()] = NOT_EMITED_YET; + RollVote vote = member->GetPassOnGroupLoot() ? PASS : NOT_EMITED_YET; + if (!CanRollOnItem(*i, member, loot)) + { + vote = PASS; + ++r->totalPass; } + + r->playerVote[member->GetGUID()] = vote; } } @@ -1052,23 +1066,28 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject) continue; if (itr->second == PASS) - SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r); + SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r, true); } } - SendLootStartRoll(60000, pLootedObject->GetMapId(), *r); - - RollId.push_back(r); - - if (Creature* creature = pLootedObject->ToCreature()) + if (r->totalPass == r->totalPlayersRolling) + delete r; + else { - creature->m_groupLootTimer = 60000; - creature->lootingGroupLowGUID = GetGUID().GetCounter(); - } - else if (GameObject* go = pLootedObject->ToGameObject()) - { - go->m_groupLootTimer = 60000; - go->lootingGroupLowGUID = GetGUID().GetCounter(); + SendLootStartRoll(60000, pLootedObject->GetMapId(), *r); + + RollId.push_back(r); + + if (Creature* creature = pLootedObject->ToCreature()) + { + creature->m_groupLootTimer = 60000; + creature->lootingGroupLowGUID = GetGUID().GetCounter(); + } + else if (GameObject* go = pLootedObject->ToGameObject()) + { + go->m_groupLootTimer = 60000; + go->lootingGroupLowGUID = GetGUID().GetCounter(); + } } } else @@ -1096,16 +1115,18 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject) for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* member = itr->GetSource(); - if (!member) + if (!member || !member->GetSession()) continue; if (member->IsAtLootRewardDistance(pLootedObject)) { - if (i->AllowedForPlayer(member, loot->sourceWorldObjectGUID)) + RollVote vote = NOT_EMITED_YET; + if (!CanRollOnItem(*i, member, loot)) { - r->totalPlayersRolling++; - r->playerVote[member->GetGUID()] = NOT_EMITED_YET; + vote = PASS; + ++r->totalPass; } + r->playerVote[member->GetGUID()] = vote; } } @@ -1156,20 +1177,21 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject) for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* playerToRoll = itr->GetSource(); - if (!playerToRoll) + if (!playerToRoll || !playerToRoll->GetSession()) continue; - if (i->AllowedForPlayer(playerToRoll, loot->sourceWorldObjectGUID) && playerToRoll->IsAtLootRewardDistance(lootedObject)) + if (playerToRoll->IsAtGroupRewardDistance(lootedObject)) { r->totalPlayersRolling++; - if (playerToRoll->GetPassOnGroupLoot()) + + RollVote vote = playerToRoll->GetPassOnGroupLoot() ? PASS : NOT_EMITED_YET; + if (!CanRollOnItem(*i, playerToRoll, loot)) { - r->playerVote[playerToRoll->GetGUID()] = PASS; - r->totalPass++; - // can't broadcast the pass now. need to wait until all rolling players are known. + vote = PASS; + r->totalPass++; // Can't broadcast the pass now. need to wait until all rolling players are known } - else - r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET; + + r->playerVote[playerToRoll->GetGUID()] = vote; } } @@ -1230,13 +1252,21 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject) for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* playerToRoll = itr->GetSource(); - if (!playerToRoll) + if (!playerToRoll || !playerToRoll->GetSession()) continue; - if (i->AllowedForPlayer(playerToRoll, loot->sourceWorldObjectGUID) && playerToRoll->IsAtLootRewardDistance(lootedObject)) + if (playerToRoll->IsAtGroupRewardDistance(lootedObject)) { r->totalPlayersRolling++; - r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET; + + RollVote vote = playerToRoll->GetPassOnGroupLoot() ? PASS : NOT_EMITED_YET; + if (!CanRollOnItem(*i, playerToRoll, loot)) + { + vote = PASS; + r->totalPass++; // Can't broadcast the pass now. need to wait until all rolling players are known + } + + r->playerVote[playerToRoll->GetGUID()] = vote; } } diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 87317f376..f4afabf6f 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -286,7 +286,7 @@ public: bool isRollLootActive() const; 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 SendLootRoll(ObjectGuid SourceGuid, ObjectGuid TargetGuid, uint8 RollNumber, uint8 RollType, const Roll& r, bool autoPass = false); void SendLootRollWon(ObjectGuid SourceGuid, ObjectGuid TargetGuid, uint8 RollNumber, uint8 RollType, const Roll& r); void SendLootAllPassed(Roll const& roll); void SendLooter(Creature* creature, Player* pLooter);