using System; using System.Linq; using RPGCore.BackpackEquipment.ObjectModules.Content; using RPGCore.BackpackEquipment.ObjectModules.UnitBackpack.Events; using RPGCore.BackpackEquipment.Objects; using RPGCore.Core; using RPGCore.Core.Objects; using RPGCoreCommon.Helpers.PropertyAttributeDrawers; using UnityEngine; namespace RPGCore.BackpackEquipment.ObjectModules.UnitBackpack { [RequireComponent(typeof(UnitObject))] [RequireComponent(typeof(ContentModule))] [DisallowMultipleComponent] public sealed class UnitBackpackModule : ObjectModule, IContentOwner { // TODO: implementacja stackowania tutaj [SerializeField] private ItemObject[] _serializedItems; [SerializeField] public bool isLimited = true; [SerializeField] public int itemsLimit = 5; [SerializeField] public int itemsPerChunk = 5; [SerializeField] public int minimumChunks = 3; [SerializeField] public int additionalChunks = 1; private ItemObject[] _items; public ItemObject[] items => _items.ToArray(); private void Awake() { _items = _serializedItems.ToArray(); Resize(); } private void Start() { InitializeItems(); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// private void InitializeItems() { // TODO: inicjalizacja serializowanych itemkow + ich eventy } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// public bool CanAdd(ItemObject item, int index) { return !isLimited || _items.Any(i => i == null); } bool IContentOwner.Add(ItemObject item, int index) { if (index < 0) index = Array.IndexOf(_items, false); if (index < 0) return false; if (isLimited && index >= itemsLimit) return false; _items[index] = item; Resize(); parent.events.Invoke(new BackpackAddEvent { unit = parent, item = item, index = index }); return true; } bool IContentOwner.Remove(ItemObject item) { var index = Array.IndexOf(_items, item); if (index < 0) return false; _items[index] = null; Resize(); parent.events.Invoke(new BackpackRemoveEvent { unit = parent, item = item, index = index }); return true; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void Swap(int firstItemIndex, int secondItemIndex) { var wantedSize = Math.Max(firstItemIndex, secondItemIndex) + 1; if (isLimited && wantedSize > itemsLimit) return; Resize(wantedSize); (items[firstItemIndex], items[secondItemIndex]) = (items[secondItemIndex], items[firstItemIndex]); parent.events.Invoke(new BackpackSwapEvent { unit = parent, firstSlotIndex = firstItemIndex, firstItem = items[firstItemIndex], secondSlotIndex = secondItemIndex, secondItem = items[secondItemIndex], }); } private void Resize(int wantedSize = 0) { if (isLimited) { // TODO: obsłużyć itemki w miejscach, które zaraz zostaną "ucięte" (przy zmniejszaniu slotów) - TYLKO w limitowanym plecaku if (_items.Length != itemsLimit) { Array.Resize(ref _items, itemsLimit); } return; } var limitBefore = items.Length; var lastItemIndex = Array.FindLastIndex(items, item => item); var limitMinimum = Mathf.Max(wantedSize, lastItemIndex, minimumChunks * itemsPerChunk); var limitAfter = Mathf.CeilToInt((float)limitMinimum / itemsPerChunk + additionalChunks) * itemsPerChunk; // Size not changed, do nothing if (limitBefore == limitAfter) return; // Resize backpack's arrays Array.Resize(ref _items, limitAfter); parent.events.Invoke(new BackpackResizeEvent { unit = parent, beforeSlotCount = limitBefore, afterSlotCount = limitAfter }); } public void Sort(Func valueGetter, bool sortDescending = false) { Array.Sort(items, (item1, item2) => { // NULLS always to the end if (!item1 && !item2) return 0; if (!item1) return 1; if (!item2) return -1; // Existing items sort by given value getter with given sort direction var result = valueGetter(item1).CompareTo(valueGetter(item2)); if (sortDescending) result *= - 1; return result; }); parent.events.Invoke(new BackpackSortEvent { unit = parent }); Resize(); } } }