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 (00fdf6e99a)

* 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

View File

@@ -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<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)
{
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())
{
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;
}
}