package items import ( "fmt" "log" ) // NewEquipmentItemList creates a new equipment item list func NewEquipmentItemList() *EquipmentItemList { return &EquipmentItemList{ items: [NumSlots]*Item{}, appearanceType: BaseEquipment, } } // NewEquipmentItemListFromCopy creates a copy of an equipment list func NewEquipmentItemListFromCopy(source *EquipmentItemList) *EquipmentItemList { if source == nil { return NewEquipmentItemList() } source.mutex.RLock() defer source.mutex.RUnlock() equipment := &EquipmentItemList{ appearanceType: source.appearanceType, } // Copy all equipped items for i, item := range source.items { if item != nil { equipment.items[i] = item.Copy() } } return equipment } // GetAllEquippedItems returns all equipped items func (eil *EquipmentItemList) GetAllEquippedItems() []*Item { eil.mutex.RLock() defer eil.mutex.RUnlock() var equippedItems []*Item for _, item := range eil.items { if item != nil { equippedItems = append(equippedItems, item) } } return equippedItems } // ResetPackets resets packet data func (eil *EquipmentItemList) ResetPackets() { eil.mutex.Lock() defer eil.mutex.Unlock() eil.xorPacket = nil eil.origPacket = nil } // HasItem checks if a specific item ID is equipped func (eil *EquipmentItemList) HasItem(itemID int32) bool { eil.mutex.RLock() defer eil.mutex.RUnlock() for _, item := range eil.items { if item != nil && item.Details.ItemID == itemID { return true } } return false } // GetNumberOfItems returns the number of equipped items func (eil *EquipmentItemList) GetNumberOfItems() int8 { eil.mutex.RLock() defer eil.mutex.RUnlock() count := int8(0) for _, item := range eil.items { if item != nil { count++ } } return count } // GetWeight returns the total weight of equipped items func (eil *EquipmentItemList) GetWeight() int32 { eil.mutex.RLock() defer eil.mutex.RUnlock() totalWeight := int32(0) for _, item := range eil.items { if item != nil { totalWeight += item.GenericInfo.Weight * int32(item.Details.Count) } } return totalWeight } // GetItemFromUniqueID gets an equipped item by unique ID func (eil *EquipmentItemList) GetItemFromUniqueID(uniqueID int32) *Item { eil.mutex.RLock() defer eil.mutex.RUnlock() for _, item := range eil.items { if item != nil && int32(item.Details.UniqueID) == uniqueID { return item } } return nil } // GetItemFromItemID gets an equipped item by item template ID func (eil *EquipmentItemList) GetItemFromItemID(itemID int32) *Item { eil.mutex.RLock() defer eil.mutex.RUnlock() for _, item := range eil.items { if item != nil && item.Details.ItemID == itemID { return item } } return nil } // SetItem sets an item in a specific equipment slot func (eil *EquipmentItemList) SetItem(slotID int8, item *Item, locked bool) { if slotID < 0 || slotID >= NumSlots { return } if !locked { eil.mutex.Lock() defer eil.mutex.Unlock() } eil.items[slotID] = item if item != nil { item.Details.SlotID = int16(slotID) item.Details.AppearanceType = int16(eil.appearanceType) } } // RemoveItem removes an item from a specific slot func (eil *EquipmentItemList) RemoveItem(slot int8, deleteItem bool) { if slot < 0 || slot >= NumSlots { return } eil.mutex.Lock() defer eil.mutex.Unlock() item := eil.items[slot] eil.items[slot] = nil if deleteItem && item != nil { item.NeedsDeletion = true } } // GetItem gets an item from a specific slot func (eil *EquipmentItemList) GetItem(slotID int8) *Item { if slotID < 0 || slotID >= NumSlots { return nil } eil.mutex.RLock() defer eil.mutex.RUnlock() return eil.items[slotID] } // AddItem adds an item to the equipment (finds appropriate slot) func (eil *EquipmentItemList) AddItem(slot int8, item *Item) bool { if item == nil { return false } // Check if the specific slot is requested and valid if slot >= 0 && slot < NumSlots { eil.mutex.Lock() defer eil.mutex.Unlock() if eil.items[slot] == nil { eil.items[slot] = item item.Details.SlotID = int16(slot) item.Details.AppearanceType = int16(eil.appearanceType) return true } } // Find a free slot that the item can be equipped in freeSlot := eil.GetFreeSlot(item, slot, 0) if freeSlot < NumSlots { eil.SetItem(freeSlot, item, false) return true } return false } // CheckEquipSlot checks if an item can be equipped in a specific slot func (eil *EquipmentItemList) CheckEquipSlot(item *Item, slot int8) bool { if item == nil || slot < 0 || slot >= NumSlots { return false } // Check if item has the required slot data return item.HasSlot(slot, -1) } // CanItemBeEquippedInSlot checks if an item can be equipped in a slot func (eil *EquipmentItemList) CanItemBeEquippedInSlot(item *Item, slot int8) bool { if item == nil || slot < 0 || slot >= NumSlots { return false } // Check slot compatibility if !eil.CheckEquipSlot(item, slot) { return false } // Check if slot is already occupied eil.mutex.RLock() defer eil.mutex.RUnlock() return eil.items[slot] == nil } // GetFreeSlot finds a free slot for an item func (eil *EquipmentItemList) GetFreeSlot(item *Item, preferredSlot int8, version int16) int8 { if item == nil { return NumSlots // Invalid slot } eil.mutex.RLock() defer eil.mutex.RUnlock() // If preferred slot is specified and available, use it if preferredSlot >= 0 && preferredSlot < NumSlots { if eil.items[preferredSlot] == nil && item.HasSlot(preferredSlot, -1) { return preferredSlot } } // Search through all possible slots for this item for slot := int8(0); slot < NumSlots; slot++ { if eil.items[slot] == nil && item.HasSlot(slot, -1) { return slot } } return NumSlots // No free slot found } // CheckSlotConflict checks for slot conflicts (lore items, etc.) func (eil *EquipmentItemList) CheckSlotConflict(item *Item, checkLoreOnly bool, loreStackCount *int16) int32 { if item == nil { return 0 } eil.mutex.RLock() defer eil.mutex.RUnlock() // Check for lore conflicts if item.CheckFlag(Lore) || item.CheckFlag(LoreEquip) { stackCount := int16(0) for _, equippedItem := range eil.items { if equippedItem != nil && equippedItem.Details.ItemID == item.Details.ItemID { stackCount++ } } if loreStackCount != nil { *loreStackCount = stackCount } if stackCount > 0 { return 1 // Lore conflict } } return 0 // No conflict } // GetSlotByItem finds the slot an item is equipped in func (eil *EquipmentItemList) GetSlotByItem(item *Item) int8 { if item == nil { return NumSlots } eil.mutex.RLock() defer eil.mutex.RUnlock() for slot, equippedItem := range eil.items { if equippedItem == item { return int8(slot) } } return NumSlots // Not found } // CalculateEquipmentBonuses calculates stat bonuses from all equipped items func (eil *EquipmentItemList) CalculateEquipmentBonuses() *ItemStatsValues { eil.mutex.RLock() defer eil.mutex.RUnlock() totalBonuses := &ItemStatsValues{} for _, item := range eil.items { if item != nil { // TODO: Implement item bonus calculation // This should be handled by the master item list itemBonuses := &ItemStatsValues{} // placeholder if itemBonuses != nil { // Add item bonuses to total totalBonuses.Str += itemBonuses.Str totalBonuses.Sta += itemBonuses.Sta totalBonuses.Agi += itemBonuses.Agi totalBonuses.Wis += itemBonuses.Wis totalBonuses.Int += itemBonuses.Int totalBonuses.VsSlash += itemBonuses.VsSlash totalBonuses.VsCrush += itemBonuses.VsCrush totalBonuses.VsPierce += itemBonuses.VsPierce totalBonuses.VsPhysical += itemBonuses.VsPhysical totalBonuses.VsHeat += itemBonuses.VsHeat totalBonuses.VsCold += itemBonuses.VsCold totalBonuses.VsMagic += itemBonuses.VsMagic totalBonuses.VsMental += itemBonuses.VsMental totalBonuses.VsDivine += itemBonuses.VsDivine totalBonuses.VsDisease += itemBonuses.VsDisease totalBonuses.VsPoison += itemBonuses.VsPoison totalBonuses.Health += itemBonuses.Health totalBonuses.Power += itemBonuses.Power totalBonuses.Concentration += itemBonuses.Concentration totalBonuses.AbilityModifier += itemBonuses.AbilityModifier totalBonuses.CriticalMitigation += itemBonuses.CriticalMitigation totalBonuses.ExtraShieldBlockChance += itemBonuses.ExtraShieldBlockChance totalBonuses.BeneficialCritChance += itemBonuses.BeneficialCritChance totalBonuses.CritBonus += itemBonuses.CritBonus totalBonuses.Potency += itemBonuses.Potency totalBonuses.HateGainMod += itemBonuses.HateGainMod totalBonuses.AbilityReuseSpeed += itemBonuses.AbilityReuseSpeed totalBonuses.AbilityCastingSpeed += itemBonuses.AbilityCastingSpeed totalBonuses.AbilityRecoverySpeed += itemBonuses.AbilityRecoverySpeed totalBonuses.SpellReuseSpeed += itemBonuses.SpellReuseSpeed totalBonuses.SpellMultiAttackChance += itemBonuses.SpellMultiAttackChance totalBonuses.DPS += itemBonuses.DPS totalBonuses.AttackSpeed += itemBonuses.AttackSpeed totalBonuses.MultiAttackChance += itemBonuses.MultiAttackChance totalBonuses.Flurry += itemBonuses.Flurry totalBonuses.AEAutoattackChance += itemBonuses.AEAutoattackChance totalBonuses.Strikethrough += itemBonuses.Strikethrough totalBonuses.Accuracy += itemBonuses.Accuracy totalBonuses.OffensiveSpeed += itemBonuses.OffensiveSpeed totalBonuses.UncontestedParry += itemBonuses.UncontestedParry totalBonuses.UncontestedBlock += itemBonuses.UncontestedBlock totalBonuses.UncontestedDodge += itemBonuses.UncontestedDodge totalBonuses.UncontestedRiposte += itemBonuses.UncontestedRiposte totalBonuses.SizeMod += itemBonuses.SizeMod } } } return totalBonuses } // SetAppearanceType sets the appearance type (normal or appearance equipment) func (eil *EquipmentItemList) SetAppearanceType(appearanceType int8) { eil.mutex.Lock() defer eil.mutex.Unlock() eil.appearanceType = appearanceType // Update all equipped items with new appearance type for _, item := range eil.items { if item != nil { item.Details.AppearanceType = int16(appearanceType) } } } // GetAppearanceType gets the current appearance type func (eil *EquipmentItemList) GetAppearanceType() int8 { eil.mutex.RLock() defer eil.mutex.RUnlock() return eil.appearanceType } // ValidateEquipment validates all equipped items func (eil *EquipmentItemList) ValidateEquipment() *ItemValidationResult { eil.mutex.RLock() defer eil.mutex.RUnlock() result := &ItemValidationResult{Valid: true} for slot, item := range eil.items { if item != nil { // Validate item itemResult := item.Validate() if !itemResult.Valid { result.Valid = false for _, err := range itemResult.Errors { result.Errors = append(result.Errors, fmt.Sprintf("Slot %d: %s", slot, err)) } } // Check slot compatibility if !item.HasSlot(int8(slot), -1) { result.Valid = false result.Errors = append(result.Errors, fmt.Sprintf("Item %s cannot be equipped in slot %d", item.Name, slot)) } } } return result } // GetEquippedItemsByType returns equipped items of a specific type func (eil *EquipmentItemList) GetEquippedItemsByType(itemType int8) []*Item { eil.mutex.RLock() defer eil.mutex.RUnlock() var matchingItems []*Item for _, item := range eil.items { if item != nil && item.GenericInfo.ItemType == itemType { matchingItems = append(matchingItems, item) } } return matchingItems } // GetWeapons returns all equipped weapons func (eil *EquipmentItemList) GetWeapons() []*Item { return eil.GetEquippedItemsByType(ItemTypeWeapon) } // GetArmor returns all equipped armor pieces func (eil *EquipmentItemList) GetArmor() []*Item { return eil.GetEquippedItemsByType(ItemTypeArmor) } // GetJewelry returns all equipped jewelry func (eil *EquipmentItemList) GetJewelry() []*Item { eil.mutex.RLock() defer eil.mutex.RUnlock() var jewelry []*Item // Check ring slots if eil.items[EQ2LRingSlot] != nil { jewelry = append(jewelry, eil.items[EQ2LRingSlot]) } if eil.items[EQ2RRingSlot] != nil { jewelry = append(jewelry, eil.items[EQ2RRingSlot]) } // Check ear slots if eil.items[EQ2EarsSlot1] != nil { jewelry = append(jewelry, eil.items[EQ2EarsSlot1]) } if eil.items[EQ2EarsSlot2] != nil { jewelry = append(jewelry, eil.items[EQ2EarsSlot2]) } // Check neck slot if eil.items[EQ2NeckSlot] != nil { jewelry = append(jewelry, eil.items[EQ2NeckSlot]) } // Check wrist slots if eil.items[EQ2LWristSlot] != nil { jewelry = append(jewelry, eil.items[EQ2LWristSlot]) } if eil.items[EQ2RWristSlot] != nil { jewelry = append(jewelry, eil.items[EQ2RWristSlot]) } return jewelry } // HasWeaponEquipped checks if any weapon is equipped func (eil *EquipmentItemList) HasWeaponEquipped() bool { weapons := eil.GetWeapons() return len(weapons) > 0 } // HasShieldEquipped checks if a shield is equipped func (eil *EquipmentItemList) HasShieldEquipped() bool { item := eil.GetItem(EQ2SecondarySlot) return item != nil && item.IsShield() } // HasTwoHandedWeapon checks if a two-handed weapon is equipped func (eil *EquipmentItemList) HasTwoHandedWeapon() bool { primaryItem := eil.GetItem(EQ2PrimarySlot) if primaryItem != nil && primaryItem.IsWeapon() && primaryItem.WeaponInfo != nil { return primaryItem.WeaponInfo.WieldType == ItemWieldTypeTwoHand } return false } // CanDualWield checks if dual wielding is possible with current equipment func (eil *EquipmentItemList) CanDualWield() bool { primaryItem := eil.GetItem(EQ2PrimarySlot) secondaryItem := eil.GetItem(EQ2SecondarySlot) if primaryItem != nil && secondaryItem != nil { // Both items must be weapons that can be dual wielded if primaryItem.IsWeapon() && secondaryItem.IsWeapon() { if primaryItem.WeaponInfo != nil && secondaryItem.WeaponInfo != nil { return primaryItem.WeaponInfo.WieldType == ItemWieldTypeDual && secondaryItem.WeaponInfo.WieldType == ItemWieldTypeDual } } } return false } // String returns a string representation of the equipment list func (eil *EquipmentItemList) String() string { eil.mutex.RLock() defer eil.mutex.RUnlock() equippedCount := 0 for _, item := range eil.items { if item != nil { equippedCount++ } } return fmt.Sprintf("EquipmentItemList{Equipped: %d/%d, AppearanceType: %d}", equippedCount, NumSlots, eil.appearanceType) } func init() { log.Printf("Equipment item list system initialized") }