diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs b/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs
index adc2a2b417..66d828909a 100644
--- a/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs
+++ b/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs
@@ -156,8 +156,8 @@ namespace PerfectWorld.Scripts.Managers
if (currentSelectedItem == null) return;
// For equipping, we need to find an empty equipment slot
- // The equip location should be determined by the item type or use a default
- byte equipLocation = EC_IvtrType.GetEquipLocationForItem(currentSelectedItem.TemplateId);
+ // Use the new method that checks for available slots (especially for finger items)
+ byte equipLocation = EC_IvtrType.GetAvailableEquipLocationForItem(currentSelectedItem.TemplateId);
if (equipLocation >= (byte)EC_IvtrType.IndexOfIteminEquipmentInventory.SIZE_EQUIPIVTR)
{
Debug.LogWarning($"[InventoryUI] Could not determine equip location for item {currentSelectedItem.TemplateId}");
diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrType.cs b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrType.cs
index 3cdbafa880..d42c58746d 100644
--- a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrType.cs
+++ b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrType.cs
@@ -172,6 +172,139 @@ namespace PerfectWorld.Scripts.Managers
}
}
+ ///
+ /// Gets the best available equipment slot for an item, checking for empty slots when multiple options exist (like finger slots)
+ ///
+ public static byte GetAvailableEquipLocationForItem(int templateId)
+ {
+ try
+ {
+ var edm = ElementDataManProvider.GetElementDataMan();
+ if (edm == null)
+ {
+ Debug.LogWarning("[IvtrType] ElementDataMan not initialized");
+ return (byte)IndexOfIteminEquipmentInventory.SIZE_EQUIPIVTR;
+ }
+
+ uint id = unchecked((uint)templateId);
+
+ // Weapons
+ foreach (var it in edm.weapon_essence_array)
+ {
+ if (it.id == id) return (byte)IndexOfIteminEquipmentInventory.EQUIPIVTR_WEAPON;
+ }
+
+ // Projectiles (quiver / projectile essence)
+ foreach (var it in edm.quiver_essence_array)
+ {
+ if (it.id == id) return (byte)IndexOfIteminEquipmentInventory.EQUIPIVTR_PROJECTILE;
+ }
+ foreach (var it in edm.projectile_essence_array)
+ {
+ if (it.id == id) return (byte)IndexOfIteminEquipmentInventory.EQUIPIVTR_PROJECTILE;
+ }
+
+ // Flysword
+ foreach (var it in edm.flysword_essence_array)
+ {
+ if (it.id == id) return (byte)IndexOfIteminEquipmentInventory.EQUIPIVTR_FLYSWORD;
+ }
+
+ // Armor -> derive from sub-type mask
+ foreach (var it in edm.armor_essence_array)
+ {
+ if (it.id == id)
+ {
+ var slot = ResolveAvailableArmorSlotBySubtype(edm, it.id_sub_type);
+ if (slot < IndexOfIteminEquipmentInventory.SIZE_EQUIPIVTR)
+ {
+ return (byte)slot;
+ }
+ break;
+ }
+ }
+
+ // Decoration -> derive from sub-type mask (neck, waist, etc.)
+ foreach (var it in edm.decoration_essence_array)
+ {
+ if (it.id == id)
+ {
+ var slot = ResolveAvailableDecorationSlotBySubtype(edm, it.id_sub_type);
+ if (slot < IndexOfIteminEquipmentInventory.SIZE_EQUIPIVTR)
+ {
+ return (byte)slot;
+ }
+ break;
+ }
+ }
+
+ // Fashion -> derive from sub-type mask
+ foreach (var it in edm.fashion_essence_array)
+ {
+ if (it.id == id)
+ {
+ var slot = ResolveFashionSlotBySubtype(edm, it.id_sub_type);
+ if (slot < IndexOfIteminEquipmentInventory.SIZE_EQUIPIVTR)
+ {
+ return (byte)slot;
+ }
+ break;
+ }
+ }
+
+ // Runes
+ foreach (var it in edm.damagerune_essence_array)
+ {
+ if (it.id == id) return (byte)IndexOfIteminEquipmentInventory.EQUIPIVTR_RUNE;
+ }
+ foreach (var it in edm.armorrune_essence_array)
+ {
+ if (it.id == id) return (byte)IndexOfIteminEquipmentInventory.EQUIPIVTR_RUNE;
+ }
+
+ // Special slots
+ foreach (var it in edm.bible_essence_array)
+ {
+ if (it.id == id) return (byte)IndexOfIteminEquipmentInventory.EQUIPIVTR_BIBLE;
+ }
+ foreach (var it in edm.speaker_essence_array)
+ {
+ if (it.id == id) return (byte)IndexOfIteminEquipmentInventory.EQUIPIVTR_SPEAKER;
+ }
+ foreach (var it in edm.autohp_essence_array)
+ {
+ if (it.id == id) return (byte)IndexOfIteminEquipmentInventory.EQUIPIVTR_AUTOHP;
+ }
+ foreach (var it in edm.goblin_essence_array)
+ {
+ if (it.id == id) return (byte)IndexOfIteminEquipmentInventory.EQUIPIVTR_GOBLIN;
+ }
+ foreach (var it in edm.automp_essence_array)
+ {
+ if (it.id == id) return (byte)IndexOfIteminEquipmentInventory.EQUIPIVTR_AUTOMP;
+ }
+ foreach (var it in edm.force_token_essence_array)
+ {
+ if (it.id == id) return (byte)IndexOfIteminEquipmentInventory.EQUIPIVTR_FORCE_TOKEN;
+ }
+ foreach (var it in edm.sell_certificate_essence_array)
+ {
+ if (it.id == id) return (byte)IndexOfIteminEquipmentInventory.EQUIPIVTR_CERTIFICATE;
+ }
+
+ // Fashion weapon (if present in your data as essence/config)
+ // If you add a dedicated essence array for fashion weapons, map it here
+
+ Debug.LogWarning($"[IvtrType] Equip index not found for template {templateId}");
+ return (byte)IndexOfIteminEquipmentInventory.SIZE_EQUIPIVTR;
+ }
+ catch (Exception ex)
+ {
+ Debug.LogWarning($"[IvtrType] Error resolving equip index for template {templateId}: {ex.Message}");
+ return (byte)IndexOfIteminEquipmentInventory.SIZE_EQUIPIVTR;
+ }
+ }
+
private static IndexOfIteminEquipmentInventory ResolveArmorSlotBySubtype(elementdataman edm, uint armorSubTypeId)
{
foreach (var sub in edm.armor_sub_type_array)
@@ -224,6 +357,97 @@ namespace PerfectWorld.Scripts.Managers
}
return IndexOfIteminEquipmentInventory.SIZE_EQUIPIVTR;
}
+
+ ///
+ /// Resolves armor slot by subtype, checking for available finger slots when applicable
+ ///
+ private static IndexOfIteminEquipmentInventory ResolveAvailableArmorSlotBySubtype(elementdataman edm, uint armorSubTypeId)
+ {
+ foreach (var sub in edm.armor_sub_type_array)
+ {
+ if (sub.id != armorSubTypeId) continue;
+ uint mask = sub.equip_mask;
+
+ // Check finger slots first - try to find an empty one
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER1)) != 0 ||
+ (mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER2)) != 0)
+ {
+ var availableFingerSlot = GetAvailableFingerSlot();
+ if (availableFingerSlot != IndexOfIteminEquipmentInventory.SIZE_EQUIPIVTR)
+ {
+ return availableFingerSlot;
+ }
+ }
+
+ // For other slots, return the first matching one (original behavior)
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_HEAD)) != 0) return IndexOfIteminEquipmentInventory.EQUIPIVTR_HEAD;
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_SHOULDER)) != 0) return IndexOfIteminEquipmentInventory.EQUIPIVTR_SHOULDER;
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_BODY)) != 0) return IndexOfIteminEquipmentInventory.EQUIPIVTR_BODY;
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_WAIST)) != 0) return IndexOfIteminEquipmentInventory.EQUIPIVTR_WAIST;
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_LEG)) != 0) return IndexOfIteminEquipmentInventory.EQUIPIVTR_LEG;
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FOOT)) != 0) return IndexOfIteminEquipmentInventory.EQUIPIVTR_FOOT;
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_WRIST)) != 0) return IndexOfIteminEquipmentInventory.EQUIPIVTR_WRIST;
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER1)) != 0) return IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER1;
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER2)) != 0) return IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER2;
+ break;
+ }
+ return IndexOfIteminEquipmentInventory.SIZE_EQUIPIVTR;
+ }
+
+ ///
+ /// Resolves decoration slot by subtype, checking for available finger slots when applicable
+ ///
+ private static IndexOfIteminEquipmentInventory ResolveAvailableDecorationSlotBySubtype(elementdataman edm, uint decorationSubTypeId)
+ {
+ foreach (var sub in edm.decoration_sub_type_array)
+ {
+ if (sub.id != decorationSubTypeId) continue;
+ uint mask = sub.equip_mask;
+
+ // Check finger slots first - try to find an empty one
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER1)) != 0 ||
+ (mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER2)) != 0)
+ {
+ var availableFingerSlot = GetAvailableFingerSlot();
+ if (availableFingerSlot != IndexOfIteminEquipmentInventory.SIZE_EQUIPIVTR)
+ {
+ return availableFingerSlot;
+ }
+ }
+
+ // For other slots, return the first matching one (original behavior)
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_NECK)) != 0) return IndexOfIteminEquipmentInventory.EQUIPIVTR_NECK;
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_WAIST)) != 0) return IndexOfIteminEquipmentInventory.EQUIPIVTR_WAIST;
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER1)) != 0) return IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER1;
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER2)) != 0) return IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER2;
+ if ((mask & (1u << (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_WRIST)) != 0) return IndexOfIteminEquipmentInventory.EQUIPIVTR_WRIST;
+ break;
+ }
+ return IndexOfIteminEquipmentInventory.SIZE_EQUIPIVTR;
+ }
+
+ ///
+ /// Gets an available finger slot, preferring FINGER1 if both are empty, otherwise returning the empty one
+ ///
+ private static IndexOfIteminEquipmentInventory GetAvailableFingerSlot()
+ {
+ // Check if FINGER1 slot is empty
+ var finger1Item = EC_Inventory.GetItem(EC_Inventory.PACK_EQUIPMENT, (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER1, false);
+ if (finger1Item == null)
+ {
+ return IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER1;
+ }
+
+ // Check if FINGER2 slot is empty
+ var finger2Item = EC_Inventory.GetItem(EC_Inventory.PACK_EQUIPMENT, (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER2, false);
+ if (finger2Item == null)
+ {
+ return IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER2;
+ }
+
+ // Both slots are occupied, return FINGER1 as fallback (original behavior)
+ return IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER1;
+ }
}
}