From 6d89d242a7480dddd0f97d28d2b339db2cd4513f Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Sun, 11 Sep 2022 11:30:59 +0200 Subject: [PATCH] Core/Loot: no longer restrict need before greed rules to lfg parties only and no longer allow players to roll on mounts and companions they already have --- src/server/game/Entities/Player/Player.cpp | 140 +++++++++++---------- src/server/game/Entities/Player/Player.h | 3 +- src/server/game/Groups/Group.cpp | 4 +- 3 files changed, 76 insertions(+), 71 deletions(-) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 5f43a5a297..451edbca17 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -11502,81 +11502,87 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const return EQUIP_ERR_OK; } -InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObject const* lootedObject) const +static constexpr std::array ItemWeaponSkills = { - if (!GetGroup() || !GetGroup()->isLFGGroup()) - return EQUIP_ERR_OK; // not in LFG group + SKILL_AXES, SKILL_2H_AXES, SKILL_BOWS, SKILL_GUNS, SKILL_MACES, + SKILL_2H_MACES, SKILL_POLEARMS, SKILL_SWORDS, SKILL_2H_SWORDS, 0, + SKILL_STAVES, 0, 0, SKILL_FIST_WEAPONS, 0, + SKILL_DAGGERS, SKILL_THROWN, SKILL_ASSASSINATION, SKILL_CROSSBOWS, SKILL_WANDS, + SKILL_FISHING +}; - // check if looted object is inside the lfg dungeon - Map const* map = lootedObject->GetMap(); - if (!sLFGMgr->inLfgDungeonMap(GetGroup()->GetGUID(), map->GetId(), map->GetDifficulty())) - return EQUIP_ERR_OK; +// Patch 3.3.0 applied additional rules to ensure quality. We will go over them now. +bool Player::CanRollNeedForItem(ItemTemplate const* itemTemplate) const +{ + if (!GetGroup()) + return true; - if (!proto) - return EQUIP_ERR_ITEM_NOT_FOUND; - // Used by group, function NeedBeforeGreed, to know if a prototype can be used by a player + if (!itemTemplate) + return false; - const static uint32 item_weapon_skills[MAX_ITEM_SUBCLASS_WEAPON] = + // Race and class requirement checks + if ((itemTemplate->GetAllowableClass() & getClassMask()) == 0 || (itemTemplate->GetAllowableRace() & getRaceMask()) == 0) + return false; + + // Spell requirement check + if (itemTemplate->GetRequiredSpell() != 0 && !HasSpell(itemTemplate->GetRequiredSpell())) + return false; + + // Skill requirement check + if (itemTemplate->GetRequiredSkill() != 0 && (!GetSkillValue(itemTemplate->GetRequiredSkill()) || GetSkillValue(itemTemplate->GetRequiredSkill()) < itemTemplate->GetRequiredSkillRank())) + return false; + + // Profiency check + if (itemTemplate->GetClass() == ITEM_CLASS_WEAPON && GetSkillValue(ItemWeaponSkills[itemTemplate->GetSubClass()]) == 0) + return false; + + // Armor type checks + if (itemTemplate->GetClass() == ITEM_CLASS_ARMOR + && itemTemplate->GetSubClass() > ITEM_SUBCLASS_ARMOR_MISCELLANEOUS + && itemTemplate->GetSubClass() < ITEM_SUBCLASS_ARMOR_BUCKLER + && itemTemplate->GetInventoryType() != INVTYPE_CLOAK) { - SKILL_AXES, SKILL_2H_AXES, SKILL_BOWS, SKILL_GUNS, SKILL_MACES, - SKILL_2H_MACES, SKILL_POLEARMS, SKILL_SWORDS, SKILL_2H_SWORDS, 0, - SKILL_STAVES, 0, 0, SKILL_FIST_WEAPONS, 0, - SKILL_DAGGERS, SKILL_THROWN, SKILL_ASSASSINATION, SKILL_CROSSBOWS, SKILL_WANDS, - SKILL_FISHING - }; //Copy from function Item::GetSkill() - - if ((proto->GetAllowableClass() & getClassMask()) == 0 || (proto->GetAllowableRace() & getRaceMask()) == 0) - return EQUIP_ERR_CANT_EQUIP_EVER; - - if (proto->GetRequiredSpell() != 0 && !HasSpell(proto->GetRequiredSpell())) - return EQUIP_ERR_PROFICIENCY_NEEDED; - - if (proto->GetRequiredSkill() != 0) - { - if (!GetSkillValue(proto->GetRequiredSkill())) - return EQUIP_ERR_PROFICIENCY_NEEDED; - else if (GetSkillValue(proto->GetRequiredSkill()) < proto->GetRequiredSkillRank()) - return EQUIP_ERR_CANT_EQUIP_SKILL; + switch (getClass()) + { + // Paladins, Warriors and Death Knights can no longer roll for mail when >= level 40 and can only roll for plate + case CLASS_WARRIOR: + case CLASS_DEATH_KNIGHT: + case CLASS_PALADIN: + if (getLevel() < 40 && itemTemplate->GetSubClass() != ITEM_SUBCLASS_ARMOR_MAIL) + return false; + else if (itemTemplate->GetSubClass() != ITEM_SUBCLASS_ARMOR_PLATE) + return false; + break; + // Hunter and Shamans can no longer roll for leather when >= level 40 and can only roll for mail + case CLASS_HUNTER: + case CLASS_SHAMAN: + if (getLevel() < 40 && itemTemplate->GetSubClass() != ITEM_SUBCLASS_ARMOR_LEATHER) + return false; + else if (itemTemplate->GetSubClass() != ITEM_SUBCLASS_ARMOR_MAIL) + return false; + break; + case CLASS_DRUID: + case CLASS_ROGUE: + if (itemTemplate->GetSubClass() != ITEM_SUBCLASS_ARMOR_LEATHER) + return false; + break; + case CLASS_MAGE: + case CLASS_PRIEST: + case CLASS_WARLOCK: + if (itemTemplate->GetSubClass() != ITEM_SUBCLASS_ARMOR_CLOTH) + return false; + break; + default: + break; + } } - uint8 _class = getClass(); + // Mount and companion checks. Players that already have these cannot roll need again. + if (itemTemplate->Effects[0].SpellID == 55884) + if (HasSpell(itemTemplate->Effects[1].SpellID)) + return false; - if (proto->GetClass() == ITEM_CLASS_WEAPON && GetSkillValue(item_weapon_skills[proto->GetSubClass()]) == 0) - return EQUIP_ERR_PROFICIENCY_NEEDED; - - if (proto->GetClass() == ITEM_CLASS_ARMOR && proto->GetSubClass() > ITEM_SUBCLASS_ARMOR_MISCELLANEOUS && proto->GetSubClass() < ITEM_SUBCLASS_ARMOR_BUCKLER && proto->GetInventoryType() != INVTYPE_CLOAK) - { - if (_class == CLASS_WARRIOR || _class == CLASS_PALADIN || _class == CLASS_DEATH_KNIGHT) - { - if (getLevel() < 40) - { - if (proto->GetSubClass() != ITEM_SUBCLASS_ARMOR_MAIL) - return EQUIP_ERR_CLIENT_LOCKED_OUT; - } - else if (proto->GetSubClass() != ITEM_SUBCLASS_ARMOR_PLATE) - return EQUIP_ERR_CLIENT_LOCKED_OUT; - } - else if (_class == CLASS_HUNTER || _class == CLASS_SHAMAN) - { - if (getLevel() < 40) - { - if (proto->GetSubClass() != ITEM_SUBCLASS_ARMOR_LEATHER) - return EQUIP_ERR_CLIENT_LOCKED_OUT; - } - else if (proto->GetSubClass() != ITEM_SUBCLASS_ARMOR_MAIL) - return EQUIP_ERR_CLIENT_LOCKED_OUT; - } - - if (_class == CLASS_ROGUE || _class == CLASS_DRUID) - if (proto->GetSubClass() != ITEM_SUBCLASS_ARMOR_LEATHER) - return EQUIP_ERR_CLIENT_LOCKED_OUT; - - if (_class == CLASS_MAGE || _class == CLASS_PRIEST || _class == CLASS_WARLOCK) - if (proto->GetSubClass() != ITEM_SUBCLASS_ARMOR_CLOTH) - return EQUIP_ERR_CLIENT_LOCKED_OUT; - } - - return EQUIP_ERR_OK; + return true; } // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case. diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 06c9a8c28e..970f86eaf4 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1189,8 +1189,7 @@ class TC_GAME_API Player : public Unit, public GridObject InventoryResult CanUseItem(Item* pItem, bool not_loading = true) const; bool HasItemTotemCategory(uint32 TotemCategory) const; InventoryResult CanUseItem(ItemTemplate const* pItem) const; - InventoryResult CanUseAmmo(uint32 item) const; - InventoryResult CanRollForItemInLFG(ItemTemplate const* item, WorldObject const* lootedObject) const; + bool CanRollNeedForItem(ItemTemplate const* itemTemplate) const; Item* StoreNewItem(ItemPosCountVec const& pos, uint32 item, bool update, ItemRandomEnchantmentId const& randomPropertyId = {}, GuidSet const& allowedLooters = GuidSet()); Item* StoreItem(ItemPosCountVec const& pos, Item* pItem, bool update); Item* EquipNewItem(uint16 pos, uint32 item, bool update); diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index cc7ad12051..f05e199258 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -1248,7 +1248,7 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject) if (itr->second == PASS) SendLootRoll(newitemGUID, p->GetGUID(), -1, ROLL_PASS, *r); else - SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, p->CanRollForItemInLFG(item, lootedObject) == EQUIP_ERR_OK, *r); + SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, p->CanRollNeedForItem(item), *r); } RollId.push_back(r); @@ -1311,7 +1311,7 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject) if (itr->second == PASS) SendLootRoll(newitemGUID, p->GetGUID(), -1, ROLL_PASS, *r); else - SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, p->CanRollForItemInLFG(item, lootedObject) == EQUIP_ERR_OK, *r); + SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, p->CanRollNeedForItem(item) == EQUIP_ERR_OK, *r); } RollId.push_back(r);