fix(Core/Loot): implement automatic pass in group loot for items that… (#19272)

* 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>
This commit is contained in:
Kitzunu
2024-07-04 19:21:00 +02:00
committed by GitHub
parent e878cedb7f
commit 8745ac9c2e
2 changed files with 73 additions and 43 deletions
+58 -28
View File
@@ -898,7 +898,7 @@ void Group::SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p,
p->GetSession()->SendPacket(&data); 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)); WorldPacket data(SMSG_LOOT_ROLL, (8 + 4 + 8 + 4 + 4 + 4 + 1 + 1 + 1));
data << sourceGuid; // guid of the item rolled 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 << 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(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(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) 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); 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<int32>(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) void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject)
{ {
std::vector<LootItem>::iterator i; std::vector<LootItem>::iterator i;
@@ -1013,23 +1030,20 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject)
for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
{ {
Player* member = itr->GetSource(); Player* member = itr->GetSource();
if (!member) if (!member || !member->GetSession())
continue; continue;
if (member->IsAtLootRewardDistance(pLootedObject)) if (member->IsAtLootRewardDistance(pLootedObject))
{
if (i->AllowedForPlayer(member, loot->sourceWorldObjectGUID))
{ {
r->totalPlayersRolling++; r->totalPlayersRolling++;
if (member->GetPassOnGroupLoot()) RollVote vote = member->GetPassOnGroupLoot() ? PASS : NOT_EMITED_YET;
if (!CanRollOnItem(*i, member, loot))
{ {
r->playerVote[member->GetGUID()] = PASS; vote = PASS;
r->totalPass++; ++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;
} }
r->playerVote[member->GetGUID()] = vote;
} }
} }
@@ -1052,10 +1066,14 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject)
continue; continue;
if (itr->second == PASS) if (itr->second == PASS)
SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r); SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r, true);
} }
} }
if (r->totalPass == r->totalPlayersRolling)
delete r;
else
{
SendLootStartRoll(60000, pLootedObject->GetMapId(), *r); SendLootStartRoll(60000, pLootedObject->GetMapId(), *r);
RollId.push_back(r); RollId.push_back(r);
@@ -1071,6 +1089,7 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject)
go->lootingGroupLowGUID = GetGUID().GetCounter(); go->lootingGroupLowGUID = GetGUID().GetCounter();
} }
} }
}
else else
delete r; delete r;
} }
@@ -1096,16 +1115,18 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject)
for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
{ {
Player* member = itr->GetSource(); Player* member = itr->GetSource();
if (!member) if (!member || !member->GetSession())
continue; continue;
if (member->IsAtLootRewardDistance(pLootedObject)) if (member->IsAtLootRewardDistance(pLootedObject))
{ {
if (i->AllowedForPlayer(member, loot->sourceWorldObjectGUID)) RollVote vote = NOT_EMITED_YET;
if (!CanRollOnItem(*i, member, loot))
{ {
r->totalPlayersRolling++; vote = PASS;
r->playerVote[member->GetGUID()] = NOT_EMITED_YET; ++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()) for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
{ {
Player* playerToRoll = itr->GetSource(); Player* playerToRoll = itr->GetSource();
if (!playerToRoll) if (!playerToRoll || !playerToRoll->GetSession())
continue; continue;
if (i->AllowedForPlayer(playerToRoll, loot->sourceWorldObjectGUID) && playerToRoll->IsAtLootRewardDistance(lootedObject)) if (playerToRoll->IsAtGroupRewardDistance(lootedObject))
{ {
r->totalPlayersRolling++; r->totalPlayersRolling++;
if (playerToRoll->GetPassOnGroupLoot())
RollVote vote = playerToRoll->GetPassOnGroupLoot() ? PASS : NOT_EMITED_YET;
if (!CanRollOnItem(*i, playerToRoll, loot))
{ {
r->playerVote[playerToRoll->GetGUID()] = PASS; vote = PASS;
r->totalPass++; r->totalPass++; // Can't broadcast the pass now. need to wait until all rolling players are known
// 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()) for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
{ {
Player* playerToRoll = itr->GetSource(); Player* playerToRoll = itr->GetSource();
if (!playerToRoll) if (!playerToRoll || !playerToRoll->GetSession())
continue; continue;
if (i->AllowedForPlayer(playerToRoll, loot->sourceWorldObjectGUID) && playerToRoll->IsAtLootRewardDistance(lootedObject)) if (playerToRoll->IsAtGroupRewardDistance(lootedObject))
{ {
r->totalPlayersRolling++; 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;
} }
} }
+1 -1
View File
@@ -286,7 +286,7 @@ public:
bool isRollLootActive() const; bool isRollLootActive() const;
void SendLootStartRoll(uint32 CountDown, uint32 mapid, const Roll& r); void SendLootStartRoll(uint32 CountDown, uint32 mapid, const Roll& r);
void SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p, bool canNeed, Roll const& 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 SendLootRollWon(ObjectGuid SourceGuid, ObjectGuid TargetGuid, uint8 RollNumber, uint8 RollType, const Roll& r);
void SendLootAllPassed(Roll const& roll); void SendLootAllPassed(Roll const& roll);
void SendLooter(Creature* creature, Player* pLooter); void SendLooter(Creature* creature, Player* pLooter);