using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Assets.HeroEditor4D.Common.Scripts.Common; using Assets.HeroEditor4D.InventorySystem.Scripts.Data; using Assets.HeroEditor4D.InventorySystem.Scripts.Enums; using UnityEngine; using UnityEngine.UI; namespace Assets.HeroEditor4D.InventorySystem.Scripts.Elements { /// /// Scrollable item container that can display item list. Automatic vertical scrolling. /// public class ScrollInventory : ItemContainer { [Tooltip("Sort items automatically using SortingFunc (can be redefined).")] public bool AutoSorting; [Tooltip("Add an extra empty row or a column at the end.")] public bool Extend; [Header("UI")] public ScrollRect ScrollRect; public GridLayoutGroup Grid; public InventoryItem ItemPrefab; public Func SortingFunc = item => TypePriority.IndexOf(item.Params.Type); // You can override this. public Func FilterFunc; // You can override this. public Action OnRefresh; #if TAP_HEROES public TMPro.TextMeshProUGUI Gold; #endif private static readonly List TypePriority = new List { ItemType.Currency, ItemType.Container, ItemType.Booster, ItemType.Supply, ItemType.Weapon, ItemType.Helmet, ItemType.Armor, ItemType.Vest, ItemType.Bracers, ItemType.Leggings, ItemType.Shield, ItemType.Fragment, ItemType.Backpack, ItemType.Jewelry, ItemType.Loot, ItemType.Recipe, ItemType.Material }; private readonly List _itemInstances = new List(); // Reusing instances to reduce Instantiate() calls. public void Initialize(ref List items, Item selected, bool reset = false) { base.Initialize(ref items, selected); } public void Initialize(ref List items) { base.Initialize(ref items); ResetNormalizedPosition(); } public void SelectItem(Item item) { _itemInstances.FirstOrDefault(i => i.Item == item)?.Select(true); } public bool SelectAny() { var any = _itemInstances.FirstOrDefault(i => i.Item != null); if (any == null) return false; any.Select(true); return true; } public void SetTypeFilter(string input) { var type = input.ToEnum(); SetTypeFilter(new List { type }); } public void SetTypeFilter(List types) { FilterFunc = item => types.Contains(item.Params.Type); Refresh(null); } public void UnsetFilter() { FilterFunc = null; Refresh(null); } public override void Refresh(Item selected) { if (Items == null) return; List items; if (AutoSorting && SortingFunc != null) { items = new List(); var groups = Items.OrderBy(SortingFunc).ToList().GroupBy(i => i.Params.Type); foreach (var group in groups) { items.AddRange(group.OrderBy(i => i.Params.Class).ThenBy(i => i.Params.Price)); } } else { items = Items.ToList(); } if (FilterFunc != null) { items.RemoveAll(i => !FilterFunc(i)); } foreach (var instance in _itemInstances) { instance.Reset(); instance.SetActive(false); } var toggleGroup = GetComponentInParent(includeInactive: true); for (var i = 0; i < items.Count; i++) { var instance = GetItemInstance(); instance.transform.SetSiblingIndex(i); instance.Initialize(items[i], toggleGroup); instance.Count.SetActive(Stacked); if (AutoSelect) instance.Select(items[i] == selected); } var columns = 0; var rows = 0; switch (Grid.constraint) { case GridLayoutGroup.Constraint.FixedColumnCount: { var height = Mathf.FloorToInt((ScrollRect.GetComponent().rect.height + Grid.spacing.y) / (Grid.cellSize.y + Grid.spacing.y)); columns = Grid.constraintCount; rows = Mathf.Max(height, Mathf.FloorToInt((float) items.Count / columns)); if (Extend) rows++; break; } case GridLayoutGroup.Constraint.FixedRowCount: { var width = Mathf.FloorToInt((ScrollRect.GetComponent().rect.width + Grid.spacing.x) / (Grid.cellSize.x + Grid.spacing.x)); rows = Grid.constraintCount; columns = Mathf.Max(width, Mathf.FloorToInt((float) items.Count / rows)); if (Extend) columns++; break; } } for (var i = items.Count; i < columns * rows; i++) { var instance = GetItemInstance(); instance.Initialize(null); } OnRefresh?.Invoke(); #if TAP_HEROES var gold = Items.Where(i => i.Id == "Gold").Sum(i => i.Count); Gold?.SetText($"{gold} "); TapHeroes.Scripts.Interface.Elements.ItemComparer.Compare(_itemInstances); #endif } private InventoryItem GetItemInstance() { var instance = _itemInstances.FirstOrDefault(i => !i.gameObject.activeSelf); if (instance == null) { instance = Instantiate(ItemPrefab, Grid.transform); _itemInstances.Add(instance); } else { instance.gameObject.SetActive(true); } return instance; } public InventoryItem FindItem(Item item) { return _itemInstances.SingleOrDefault(i => i.gameObject.activeSelf && i.Item != null && i.Item.Hash == item.Hash); } public InventoryItem FindItem(string itemId) { return _itemInstances.SingleOrDefault(i => i.gameObject.activeSelf && i.Item != null && i.Item.Id == itemId); } public void ResetNormalizedPosition() { if (ScrollRect.horizontal) ScrollRect.horizontalNormalizedPosition = 0; if (ScrollRect.vertical) ScrollRect.verticalNormalizedPosition = 1; } public IEnumerator SnapTo(RectTransform target, bool horizontal = true, bool vertical = true) { yield return null; Canvas.ForceUpdateCanvases(); var pos = (Vector2) ScrollRect.transform.InverseTransformPoint(ScrollRect.content.position) - (Vector2) ScrollRect.transform.InverseTransformPoint(target.position); if (!horizontal) pos.x = ScrollRect.content.anchoredPosition.x; if (!vertical) pos.y = ScrollRect.content.anchoredPosition.y; ScrollRect.content.anchoredPosition = pos; } } }