diff options
-rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 118 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.h | 4 | ||||
-rw-r--r-- | src/server/game/Handlers/ItemHandler.cpp | 16 |
3 files changed, 114 insertions, 24 deletions
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index f87343b8670..d2b1a7e6c16 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -1329,9 +1329,9 @@ bool Item::CheckSoulboundTradeExpire() return false; } -bool Item::CanBeTransmogrified(WorldPackets::Item::ItemInstance const& transmogrifier, BonusData const* bonus) +bool Item::IsValidTransmogrificationTarget() const { - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(transmogrifier.ItemID); + ItemTemplate const* proto = GetTemplate(); if (!proto) return false; @@ -1348,15 +1348,15 @@ bool Item::CanBeTransmogrified(WorldPackets::Item::ItemInstance const& transmogr if (proto->GetFlags2() & ITEM_FLAG2_CANNOT_BE_TRANSMOG) return false; - if (!HasStats(transmogrifier, bonus)) + if (!HasStats()) return false; return true; } -bool Item::CanTransmogrify() const +bool Item::IsValidTransmogrificationSource(WorldPackets::Item::ItemInstance const& transmogrifier, BonusData const* bonus) { - ItemTemplate const* proto = GetTemplate(); + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(transmogrifier.ItemID); if (!proto) return false; @@ -1376,7 +1376,7 @@ bool Item::CanTransmogrify() const if (proto->GetFlags2() & ITEM_FLAG2_CAN_TRANSMOG) return true; - if (!HasStats()) + if (!HasStats(transmogrifier, bonus)) return false; return true; @@ -1408,35 +1408,109 @@ bool Item::HasStats(WorldPackets::Item::ItemInstance const& itemInstance, BonusD return false; } +enum class ItemTransmogrificationWeaponCategory : uint8 +{ + // Two-handed + AXE_MACE_SWORD_2H, + STAFF_POLEARM, + RANGED, + + // One-handed + AXE_MACE_SWORD_1H, + DAGGER, + FIST, + + INVALID +}; + +static ItemTransmogrificationWeaponCategory GetTransmogrificationWeaponCategory(ItemTemplate const* proto) +{ + if (proto->GetClass() == ITEM_CLASS_WEAPON) + { + switch (proto->GetSubClass()) + { + case ITEM_SUBCLASS_WEAPON_AXE2: + case ITEM_SUBCLASS_WEAPON_MACE2: + case ITEM_SUBCLASS_WEAPON_SWORD2: + return ItemTransmogrificationWeaponCategory::AXE_MACE_SWORD_2H; + case ITEM_SUBCLASS_WEAPON_STAFF: + case ITEM_SUBCLASS_WEAPON_POLEARM: + return ItemTransmogrificationWeaponCategory::STAFF_POLEARM; + case ITEM_SUBCLASS_WEAPON_BOW: + case ITEM_SUBCLASS_WEAPON_GUN: + case ITEM_SUBCLASS_WEAPON_CROSSBOW: + return ItemTransmogrificationWeaponCategory::RANGED; + case ITEM_SUBCLASS_WEAPON_AXE: + case ITEM_SUBCLASS_WEAPON_MACE: + case ITEM_SUBCLASS_WEAPON_SWORD: + return ItemTransmogrificationWeaponCategory::AXE_MACE_SWORD_1H; + case ITEM_SUBCLASS_WEAPON_DAGGER: + return ItemTransmogrificationWeaponCategory::DAGGER; + case ITEM_SUBCLASS_WEAPON_FIST_WEAPON: + return ItemTransmogrificationWeaponCategory::FIST; + default: + break; + } + } + + return ItemTransmogrificationWeaponCategory::INVALID; +} + +InventoryType GetTransmogrificationInventoryType(ItemTemplate const* proto) +{ + InventoryType inventoryType = proto->GetInventoryType(); + switch (proto->GetClass()) + { + case ITEM_CLASS_WEAPON: + if (inventoryType == INVTYPE_WEAPONMAINHAND || inventoryType == INVTYPE_WEAPONOFFHAND) + inventoryType = INVTYPE_WEAPON; + break; + case ITEM_CLASS_ARMOR: + if (inventoryType == INVTYPE_ROBE) + inventoryType = INVTYPE_CHEST; + default: + break; + } + return inventoryType; +} + bool Item::CanTransmogrifyItemWithItem(Item const* transmogrified, WorldPackets::Item::ItemInstance const& transmogrifier, BonusData const* bonus) { - ItemTemplate const* proto1 = sObjectMgr->GetItemTemplate(transmogrifier.ItemID); // source - ItemTemplate const* proto2 = transmogrified->GetTemplate(); // dest + ItemTemplate const* source = sObjectMgr->GetItemTemplate(transmogrifier.ItemID); // source + ItemTemplate const* target = transmogrified->GetTemplate(); // dest - if (sDB2Manager.GetItemDisplayId(proto1->GetId(), bonus->AppearanceModID) == transmogrified->GetDisplayId()) + if (!source || !target) return false; - if (!transmogrified->CanTransmogrify() || !CanBeTransmogrified(transmogrifier, bonus)) + if (sDB2Manager.GetItemDisplayId(source->GetId(), bonus->AppearanceModID) == transmogrified->GetDisplayId()) return false; - if (proto1->GetInventoryType() == INVTYPE_BAG || - proto1->GetInventoryType() == INVTYPE_RELIC || - proto1->GetInventoryType() == INVTYPE_BODY || - proto1->GetInventoryType() == INVTYPE_FINGER || - proto1->GetInventoryType() == INVTYPE_TRINKET || - proto1->GetInventoryType() == INVTYPE_AMMO || - proto1->GetInventoryType() == INVTYPE_QUIVER) + if (!IsValidTransmogrificationSource(transmogrifier, bonus) || !transmogrified->IsValidTransmogrificationTarget()) return false; - if (proto1->GetSubClass() != proto2->GetSubClass() && (proto1->GetClass() != ITEM_CLASS_WEAPON || !proto2->IsRangedWeapon() || !proto1->IsRangedWeapon())) + if (source->GetClass() != target->GetClass()) return false; - if (proto1->GetInventoryType() != proto2->GetInventoryType() && - (proto1->GetClass() != ITEM_CLASS_WEAPON || (proto2->GetInventoryType() != INVTYPE_WEAPONMAINHAND && proto2->GetInventoryType() != INVTYPE_WEAPONOFFHAND)) && - (proto1->GetClass() != ITEM_CLASS_ARMOR || (proto1->GetInventoryType() != INVTYPE_CHEST && proto2->GetInventoryType() != INVTYPE_ROBE && proto1->GetInventoryType() != INVTYPE_ROBE && proto2->GetInventoryType() != INVTYPE_CHEST))) + if (source->GetInventoryType() == INVTYPE_TABARD || + source->GetInventoryType() == INVTYPE_BAG || + source->GetInventoryType() == INVTYPE_RELIC || + source->GetInventoryType() == INVTYPE_BODY || + source->GetInventoryType() == INVTYPE_FINGER || + source->GetInventoryType() == INVTYPE_TRINKET || + source->GetInventoryType() == INVTYPE_AMMO || + source->GetInventoryType() == INVTYPE_QUIVER) return false; - return true; + if (source->GetSubClass() != target->GetSubClass()) + { + if (source->GetClass() != ITEM_CLASS_WEAPON) + return false; + + if (GetTransmogrificationWeaponCategory(source) != GetTransmogrificationWeaponCategory(target)) + return false; + } + + return GetTransmogrificationInventoryType(source) == GetTransmogrificationInventoryType(target); } // used by mail items, transmog cost, stationeryinfo and others diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index e1cf177cc5b..7d1c3761430 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -424,8 +424,8 @@ class Item : public Object uint32 GetScriptId() const { return GetTemplate()->ScriptId; } - static bool CanBeTransmogrified(WorldPackets::Item::ItemInstance const& transmogrifier, BonusData const* bonus); - bool CanTransmogrify() const; + bool IsValidTransmogrificationTarget() const; + static bool IsValidTransmogrificationSource(WorldPackets::Item::ItemInstance const& transmogrifier, BonusData const* bonus); bool HasStats() const; static bool HasStats(WorldPackets::Item::ItemInstance const& itemInstance, BonusData const* bonus); static bool CanTransmogrifyItemWithItem(Item const* transmogrified, WorldPackets::Item::ItemInstance const& transmogrifier, BonusData const* bonus); diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index c2ae990e6c9..a85f6788e3a 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -1140,6 +1140,11 @@ void WorldSession::HandleTransmogrifyItems(WorldPackets::Item::TransmogrifyItems TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify an invalid item in a valid slot (slot: %u).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.Slot); return; } + if (player->CanUseItem(itemTransmogrified->GetTemplate()) != EQUIP_ERR_OK) + { + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify an unequippable item in a valid slot (slot: %u).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.Slot); + return; + } WorldPackets::Item::ItemInstance itemInstance; BonusData const* bonus = nullptr; @@ -1152,6 +1157,11 @@ void WorldSession::HandleTransmogrifyItems(WorldPackets::Item::TransmogrifyItems TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an invalid item (%s).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.SrcItemGUID->ToString().c_str()); return; } + if (player->CanUseItem(itemTransmogrifier->GetTemplate()) != EQUIP_ERR_OK) + { + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an unequippable item (%s).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.SrcItemGUID->ToString().c_str()); + return; + } itemInstance.Initialize(itemTransmogrifier); bonus = itemTransmogrifier->GetBonus(); @@ -1167,6 +1177,12 @@ void WorldSession::HandleTransmogrifyItems(WorldPackets::Item::TransmogrifyItems TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an invalid void storage item (%s).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.SrcVoidItemGUID->ToString().c_str()); return; } + ItemTemplate const * transmogrifierTemplate = sObjectMgr->GetItemTemplate(itemTransmogrifier->ItemEntry); + if (player->CanUseItem(transmogrifierTemplate) != EQUIP_ERR_OK) + { + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an unequippable void storage item (%s).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.SrcVoidItemGUID->ToString().c_str()); + return; + } itemInstance.Initialize(itemTransmogrifier); std::pair<VoidStorageItem*, BonusData>& transmogData = transmogVoidItems[itemTransmogrified]; |