fix(Core/Loot): Items below group threshold should not be blocked by master looter. (#5041)

This commit is contained in:
UltraNix
2021-04-07 13:30:34 +02:00
committed by GitHub
parent 4f3c21b55c
commit c19ea1f7ad
4 changed files with 44 additions and 14 deletions

View File

@@ -25705,9 +25705,9 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot)
return;
}
// Xinef: exploit protection, dont allow to loot normal items if player is not master loot
// Xinef: exploit protection, dont allow to loot normal items if player is not master loot and not below loot threshold
// Xinef: only quest, ffa and conditioned items
if (!IS_ITEM_GUID(GetLootGUID()) && GetGroup() && GetGroup()->GetLootMethod() == MASTER_LOOT && GetGUID() != GetGroup()->GetMasterLooterGuid())
if (!item->is_underthreshold && !IS_ITEM_GUID(GetLootGUID()) && GetGroup() && GetGroup()->GetLootMethod() == MASTER_LOOT && GetGUID() != GetGroup()->GetMasterLooterGuid())
if (qitem == nullptr && ffaitem == nullptr && conditem == nullptr)
{
SendLootRelease(GetLootGUID());

View File

@@ -474,7 +474,7 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData)
ItemPosCountVec dest;
InventoryResult msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count);
if (item.follow_loot_rules && !item.AllowedForPlayer(target))
if (!item.AllowedForPlayer(target, true))
msg = EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
if (msg != EQUIP_ERR_OK)
{
@@ -485,7 +485,6 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData)
else
_player->SendLootError(lootguid, LOOT_ERROR_MASTER_OTHER);
target->SendEquipError(msg, nullptr, nullptr, item.itemid);
return;
}

View File

@@ -387,19 +387,28 @@ LootItem::LootItem(LootStoreItem const& li)
}
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
bool LootItem::AllowedForPlayer(Player const* player) const
bool LootItem::AllowedForPlayer(Player const* player, bool isGivenByMasterLooter /*= false*/, bool allowQuestLoot /*= true*/) const
{
// DB conditions check
if (!sConditionMgr->IsObjectMeetToConditions(const_cast<Player*>(player), conditions))
return false;
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid);
if (!pProto)
return false;
// not show loot for players without profession or those who already know the recipe
if ((pProto->Flags & ITEM_FLAG_HIDE_UNUSABLE_RECIPE) && (!player->HasSkill(pProto->RequiredSkill) || player->HasSpell(pProto->Spells[1].SpellId)))
bool isMasterLooter = player->GetGroup() && player->GetGroup()->GetMasterLooterGuid() == player->GetGUID();
// DB conditions check
if (!sConditionMgr->IsObjectMeetToConditions(const_cast<Player*>(player), conditions))
{
// Master Looter can see conditioned recipes
if (!isGivenByMasterLooter && isMasterLooter)
{
if ((pProto->Flags & ITEM_FLAG_HIDE_UNUSABLE_RECIPE) || (pProto->Class == ITEM_CLASS_RECIPE && pProto->Bonding == BIND_WHEN_PICKED_UP && pProto->Spells[1].SpellId != 0))
{
return true;
}
}
return false;
}
// not show loot for not own team
if ((pProto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && player->GetTeamId(true) != TEAM_HORDE)
@@ -408,6 +417,26 @@ bool LootItem::AllowedForPlayer(Player const* player) const
if ((pProto->Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) && player->GetTeamId(true) != TEAM_ALLIANCE)
return false;
// Master looter can see certain items even if the character can't loot them
if (!isGivenByMasterLooter && isMasterLooter && allowQuestLoot)
{
// check quest requirements (exclude items not under threshold)
if (!(pProto->FlagsCu & ITEM_FLAGS_CU_IGNORE_QUEST_STATUS) && (needs_quest || pProto->StartQuest))
{
return !is_underthreshold;
}
return true;
}
// Don't allow loot for players without profession or those who already know the recipe
if ((pProto->Flags & ITEM_FLAG_HIDE_UNUSABLE_RECIPE) && (!player->HasSkill(pProto->RequiredSkill) || player->HasSpell(pProto->Spells[1].SpellId)))
return false;
// Don't allow to loot soulbound recipes that the player has already learned
if (pProto->Class == ITEM_CLASS_RECIPE && pProto->Bonding == BIND_WHEN_PICKED_UP && pProto->Spells[1].SpellId != 0 && player->HasSpell(pProto->Spells[1].SpellId))
return false;
// check quest requirements
if (!(pProto->FlagsCu & ITEM_FLAGS_CU_IGNORE_QUEST_STATUS) && ((needs_quest || (pProto->StartQuest && player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE)) && !player->HasQuestForItem(itemid)))
return false;
@@ -571,7 +600,7 @@ QuestItemList* Loot::FillQuestLoot(Player* player)
{
LootItem& item = quest_items[i];
if (!item.is_looted && (item.AllowedForPlayer(player) || (item.follow_loot_rules && player->GetGroup() && ((player->GetGroup()->GetLootMethod() == MASTER_LOOT && player->GetGroup()->GetMasterLooterGuid() == player->GetGUID()) || player->GetGroup()->GetLootMethod() != MASTER_LOOT ))))
if (!item.is_looted && (item.AllowedForPlayer(player, false, false) || (item.follow_loot_rules && player->GetGroup() && ((player->GetGroup()->GetLootMethod() == MASTER_LOOT && player->GetGroup()->GetMasterLooterGuid() == player->GetGUID()) || player->GetGroup()->GetLootMethod() != MASTER_LOOT ))))
{
ql->push_back(QuestItem(i));
@@ -887,11 +916,13 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
case MASTER_PERMISSION:
case RESTRICTED_PERMISSION:
{
bool isMasterLooter = lv.viewer->GetGroup() && lv.viewer->GetGroup()->GetMasterLooterGuid() == lv.viewer->GetGUID();
// if you are not the round-robin group looter, you can only see
// blocked rolled items and quest items, and !ffa items
for (uint8 i = 0; i < l.items.size(); ++i)
{
if (!l.items[i].is_looted && !l.items[i].freeforall && l.items[i].conditions.empty() && l.items[i].AllowedForPlayer(lv.viewer))
if (!l.items[i].is_looted && !l.items[i].freeforall && (l.items[i].conditions.empty() || isMasterLooter) && l.items[i].AllowedForPlayer(lv.viewer))
{
uint8 slot_type = 0;

View File

@@ -161,7 +161,7 @@ struct LootItem
LootItem() = default;
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
bool AllowedForPlayer(Player const* player) const;
bool AllowedForPlayer(Player const* player, bool isGivenByMasterLooter = false, bool allowQuestLoot = true) const;
void AddAllowedLooter(Player const* player);
[[nodiscard]] const AllowedLooterSet& GetAllowedLooters() const { return allowedGUIDs; }