From 49cb3541336506037e33b9020b8c2e3afb9b09fb Mon Sep 17 00:00:00 2001 From: Docker Build Date: Sat, 9 May 2026 16:07:01 -0400 Subject: [PATCH] mod-paragon: ignore item AllowableClass for class 12 (gear + glyphs) Paragon is a classless concept layered on top of WotLK class data: stock items and class glyphs gate equip / vendor visibility / loot rolls / AH 'usable' filter via ItemTemplate.AllowableClass, which never has the class-12 bit (0x800). Bypassing the gate at the five enforcement sites lets Paragon equip any class-restricted item -- including class glyphs, since EffectApplyGlyph itself has no class check beyond the item gate. Race / level / proficiency / skill / required-spell checks still apply, so Paragon can't skip baseline progression. Co-authored-by: Cursor --- .../game/AuctionHouse/AuctionHouseSearcher.cpp | 7 ++++++- src/server/game/Entities/Player/Player.cpp | 7 ++++++- .../game/Entities/Player/PlayerStorage.cpp | 17 +++++++++++++++-- src/server/game/Handlers/ItemHandler.cpp | 7 ++++++- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/server/game/AuctionHouse/AuctionHouseSearcher.cpp b/src/server/game/AuctionHouse/AuctionHouseSearcher.cpp index 909091d..7778d67 100644 --- a/src/server/game/AuctionHouse/AuctionHouseSearcher.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseSearcher.cpp @@ -669,7 +669,12 @@ bool AuctionHouseUsablePlayerInfo::PlayerCanUseItem(ItemTemplate const* proto) c return false; } - if ((proto->AllowableClass & classMask) == 0 || (proto->AllowableRace & raceMask) == 0) + // mod-paragon: class 12 (Paragon) ignores AllowableClass for AH "Usable" + // filter. classMask here is the searching player's mask; PARAGON_BIT 0x800 + // = (1 << (12 - 1)). Race restriction still applies. + bool const searcherIsParagon = (classMask & 0x800u) != 0; + if ((!searcherIsParagon && (proto->AllowableClass & classMask) == 0) + || (proto->AllowableRace & raceMask) == 0) return false; if (proto->RequiredSkill != 0) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 3a3dabe..f5d286f 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -10687,7 +10687,12 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin return false; } - if (!(pProto->AllowableClass & getClassMask()) && pProto->Bonding == BIND_WHEN_PICKED_UP && !IsGameMaster()) + // mod-paragon: class 12 ignores BoP buy-side AllowableClass gate, so + // class-restricted vendor items (e.g. class glyphs) can be purchased. + if (getClass() != CLASS_PARAGON + && !(pProto->AllowableClass & getClassMask()) + && pProto->Bonding == BIND_WHEN_PICKED_UP + && !IsGameMaster()) { SendBuyError(BUY_ERR_CANT_FIND_ITEM, nullptr, item, 0); return false; diff --git a/src/server/game/Entities/Player/PlayerStorage.cpp b/src/server/game/Entities/Player/PlayerStorage.cpp index 608a2e0..504172c 100644 --- a/src/server/game/Entities/Player/PlayerStorage.cpp +++ b/src/server/game/Entities/Player/PlayerStorage.cpp @@ -2364,7 +2364,16 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; } - if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0) + // mod-paragon: class 12 (Paragon) ignores AllowableClass entirely, so any + // class-restricted item (including class glyphs) can be equipped/used. + // Race restriction still applies; proficiency/level/skill checks below + // still gate it sensibly via the standard skill cascade. + if (getClass() != CLASS_PARAGON + && (proto->AllowableClass & getClassMask()) == 0) + { + return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + } + if ((proto->AllowableRace & getRaceMask()) == 0) { return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; } @@ -2430,7 +2439,11 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje SKILL_FISHING }; //Copy from function Item::GetSkill() - if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0) + // mod-paragon: class 12 ignores AllowableClass for LFG roll eligibility. + if (getClass() != CLASS_PARAGON + && (proto->AllowableClass & getClassMask()) == 0) + return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + if ((proto->AllowableRace & getRaceMask()) == 0) return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; if (proto->RequiredSpell != 0 && !HasSpell(proto->RequiredSpell)) diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 93430db..2f8db39 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -908,7 +908,12 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid, uint32 vendorEntry) { if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(item->item)) { - if (!(itemTemplate->AllowableClass & _player->getClassMask()) && itemTemplate->Bonding == BIND_WHEN_PICKED_UP && !_player->IsGameMaster()) + // mod-paragon: class 12 sees every BoP class-restricted item + // in vendor lists (class glyphs, class tier sets, ...). + if (_player->getClass() != CLASS_PARAGON + && !(itemTemplate->AllowableClass & _player->getClassMask()) + && itemTemplate->Bonding == BIND_WHEN_PICKED_UP + && !_player->IsGameMaster()) { continue; }