using Chickensoft.Collections; using Chickensoft.GodotNodeInterfaces; using Godot; using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace GameJamDungeon; public interface IInventory : INode { public List Items { get; } public IAutoProp EquippedWeapon { get; } public IAutoProp EquippedArmor { get; } public IAutoProp EquippedAccessory { get; } public bool TryAdd(IInventoryItem inventoryItem); public void Remove(IInventoryItem inventoryItem); public void Equip(IEquipableItem equipable); public void Unequip(IEquipableItem equipable); public bool IsEquipped(IEquipableItem equipable); public void Sort(); event Inventory.InventoryAtCapacityEventHandler InventoryAtCapacity; event Inventory.AccessoryUnequippedEventHandler AccessoryUnequipped; } public partial class Inventory : Node, IInventory { // TODO: Constants class with export private const int _maxInventorySize = 20; [Signal] public delegate void InventoryAtCapacityEventHandler(string rejectedItemName); [Signal] public delegate void AccessoryUnequippedEventHandler(AccessoryStats unequippedAccessory); [Signal] public delegate void RaiseStatRequestEventHandler(ConsumableItemStats consumableItemStats); public Inventory() { Items = []; } public List Items { get; private set; } public IAutoProp EquippedWeapon => _equippedWeapon; private AutoProp _equippedWeapon { get; set; } = new AutoProp(new Weapon()); public IAutoProp EquippedArmor => _equippedArmor; private AutoProp _equippedArmor { get; set; } = new AutoProp(new Armor()); public IAutoProp EquippedAccessory => _equippedAccessory; private AutoProp _equippedAccessory { get; set; } = new AutoProp(new Accessory()); public bool TryAdd(IInventoryItem inventoryItem) { if (Items.Count >= _maxInventorySize) { EmitSignal(SignalName.InventoryAtCapacity, inventoryItem.Info.Name); return false; } Items.Add(inventoryItem); return true; } public void Remove(IInventoryItem inventoryItem) => Items.Remove(inventoryItem); public void Equip(IEquipableItem equipable) { if (equipable is Weapon weapon) _equippedWeapon.OnNext(weapon); else if (equipable is Armor armor) _equippedArmor.OnNext(armor); else if (equipable is Accessory accessory) _equippedAccessory.OnNext(accessory); else throw new NotImplementedException("Item type is not supported."); } public void Unequip(IEquipableItem equipable) { if (equipable is Weapon weapon) { _equippedWeapon.OnNext(new Weapon()); if (weapon.WeaponStats.WeaponTags.Contains(WeaponTag.BreaksOnChange)) Items.Remove(weapon); } else if (equipable is Armor armor) _equippedArmor.OnNext(new Armor()); else if (equipable is Accessory accessory) { EmitSignal(SignalName.AccessoryUnequipped, _equippedAccessory.Value.AccessoryStats); _equippedAccessory.OnNext(new Accessory()); } else throw new NotImplementedException("Item type is not supported."); } public bool IsEquipped(IEquipableItem equipable) { if (equipable is Weapon weapon) return _equippedWeapon.Value.Equals(weapon); else if (equipable is Armor armor) return _equippedArmor.Value.Equals(armor); else if (equipable is Accessory accessory) return _equippedAccessory.Value.Equals(accessory); else throw new NotImplementedException("Item type is not supported."); } public void Sort() { var equippedWeapon = Items.OfType().Where(IsEquipped); var equippedArmor = Items.OfType().Where(IsEquipped); var equippedAccessory = Items.OfType().Where(IsEquipped); var equippedItems = new List(); equippedItems.AddRange(equippedWeapon); equippedItems.AddRange(equippedArmor); equippedItems.AddRange(equippedAccessory); var listToSort = Items.Except(equippedItems); var weapons = listToSort.Where(x => x is Weapon).OrderBy(x => x as Weapon, new WeaponComparer()); var armor = listToSort.Where(x => x is Armor).OrderBy(x => x as Armor, new ArmorComparer()); var accessories = listToSort.Where(x => x is Accessory).OrderBy(x => x as Accessory, new AccessoryComparer()); var consumables = listToSort.Where(x => x is ConsumableItem).OrderBy(x => x as ConsumableItem, new ConsumableComparer()); var throwables = listToSort.Where(x => x is ThrowableItem).OrderBy(x => x as ThrowableItem, new ThrowableComparer()); Items = [.. equippedItems, .. weapons, .. armor, .. accessories, .. consumables, .. throwables]; } public class WeaponComparer : IComparer { public int Compare(Weapon x, Weapon y) { if (x.WeaponStats.Damage == y.WeaponStats.Damage) return x.WeaponStats.Name.CompareTo(y.WeaponStats.Name); return x.WeaponStats.Damage < y.WeaponStats.Damage ? 1 : -1; } } public class ArmorComparer : IComparer { public int Compare(Armor x, Armor y) { if (x.ArmorStats.Defense == y.ArmorStats.Defense) return x.ArmorStats.Name.CompareTo(y.ArmorStats.Name); return x.ArmorStats.Defense < y.ArmorStats.Defense ? 1 : -1; } } public class AccessoryComparer : IComparer { public int Compare(Accessory x, Accessory y) { return x.AccessoryStats.Name.CompareTo(y.AccessoryStats.Name); } } public class ConsumableComparer : IComparer { public int Compare(ConsumableItem x, ConsumableItem y) { return x.ConsumableItemInfo.Name.CompareTo(y.ConsumableItemInfo.Name); } } public class ThrowableComparer : IComparer { public int Compare(ThrowableItem x, ThrowableItem y) { return x.ThrowableItemInfo.Name.CompareTo(y.ThrowableItemInfo.Name); } } }