diff --git a/ItemChecklistGlobalItem.cs b/ItemChecklistGlobalItem.cs index 13e2bdb..a33b49d 100644 --- a/ItemChecklistGlobalItem.cs +++ b/ItemChecklistGlobalItem.cs @@ -30,10 +30,10 @@ namespace ItemChecklist itemChecklistPlayer.foundItems.Add(newItem); itemChecklistPlayer.totalItemsFound++; itemChecklistPlayer.foundItem[item.type] = true; - ItemChecklist.instance.ItemChecklistUI.UpdateNeeded(); + ItemChecklist.instance.ItemChecklistUI.UpdateNeeded(item.type); if (ItemChecklistUI.announce) { - Main.NewText($"Congrats: You found your first {item.name}. Total Progress: {itemChecklistPlayer.totalItemsFound}/{itemChecklistPlayer.totalItemsToFind}"); + Main.NewText($"You obtained your first {item.name}. {itemChecklistPlayer.totalItemsFound}/{itemChecklistPlayer.totalItemsToFind} {(100f*itemChecklistPlayer.totalItemsFound/itemChecklistPlayer.totalItemsToFind).ToString("0.00")}%"); } } } diff --git a/ItemChecklistPlayer.cs b/ItemChecklistPlayer.cs index e143176..c142200 100644 --- a/ItemChecklistPlayer.cs +++ b/ItemChecklistPlayer.cs @@ -26,6 +26,11 @@ namespace ItemChecklist internal int totalItemsToFind; internal int totalItemsFound; // eh, property? dunno. + // Because of save, these values inherit the last used setting while loading + internal SortModes sortModePreference = SortModes.TerrariaSort; + internal bool announcePreference; + internal int showCompletedPreference; + public override void ProcessTriggers(TriggersSet triggersSet) { if (ItemChecklist.ToggleChecklistHotKey.JustPressed) @@ -42,34 +47,47 @@ namespace ItemChecklist { var itemChecklistPlayer = Main.LocalPlayer.GetModPlayer(mod); ItemChecklistUI.visible = false; + ItemChecklistUI.announce = announcePreference; + ItemChecklistUI.sortMode = sortModePreference; + ItemChecklistUI.showCompleted = showCompletedPreference; + ItemChecklist.instance.ItemChecklistUI.RefreshPreferences(); ItemChecklist.instance.ItemChecklistUI.UpdateNeeded(); } // Do I need to use Initialize? I think so because of cloning. public override void Initialize() { - foundItems = new List(); - foundItem = new bool[Main.itemName.Length]; - findableItems = new bool[Main.itemName.Length]; - for (int i = 0; i < Main.itemName.Length; i++) + if (!Main.dedServ) { - if (i > 0 && !ItemID.Sets.Deprecated[i] && i != ItemID.Count) // TODO, is this guaranteed? + foundItems = new List(); + foundItem = new bool[Main.itemName.Length]; + findableItems = new bool[Main.itemName.Length]; + for (int i = 0; i < Main.itemName.Length; i++) { - totalItemsToFind++; - findableItems[i] = true; + if (i > 0 && !ItemID.Sets.Deprecated[i] && i != ItemID.Count && ItemChecklistUI.vanillaIDsInSortOrder[i] != -1) // TODO, is this guaranteed? + { + totalItemsToFind++; + findableItems[i] = true; + } } + + announcePreference = true; + sortModePreference = SortModes.TerrariaSort; + showCompletedPreference = 0; } - // localInstance = this; } public override void PreUpdate() { - var itemChecklistPlayer = Main.LocalPlayer.GetModPlayer(mod); - for (int i = 0; i < 59; i++) + if (!Main.dedServ) { - if (!player.inventory[i].IsAir && !itemChecklistPlayer.foundItem[player.inventory[i].type] && itemChecklistPlayer.findableItems[player.inventory[i].type]) + var itemChecklistPlayer = Main.LocalPlayer.GetModPlayer(mod); + for (int i = 0; i < 59; i++) { - ((ItemChecklistGlobalItem)mod.GetGlobalItem("ItemChecklistGlobalItem")).ItemReceived(player.inventory[i]); + if (!player.inventory[i].IsAir && !itemChecklistPlayer.foundItem[player.inventory[i].type] && itemChecklistPlayer.findableItems[player.inventory[i].type]) + { + ((ItemChecklistGlobalItem)mod.GetGlobalItem("ItemChecklistGlobalItem")).ItemReceived(player.inventory[i]); + } } } } @@ -80,12 +98,18 @@ namespace ItemChecklist return new TagCompound { ["FoundItems"] = foundItems.Select(ItemIO.Save).ToList(), + ["SortMode"] = (int)ItemChecklistUI.sortMode, + ["Announce"] = ItemChecklistUI.announce, + ["ShowCompleted"] = ItemChecklistUI.showCompleted, }; } public override void Load(TagCompound tag) { foundItems = tag.GetList("FoundItems").Select(ItemIO.Load).ToList(); + sortModePreference = (SortModes)tag.GetInt("SortMode"); + announcePreference = tag.GetBool("Announce"); + showCompletedPreference = tag.GetInt("ShowCompleted"); foreach (var item in foundItems) { diff --git a/ItemChecklistUI.cs b/ItemChecklistUI.cs index 33f7c92..502a04b 100644 --- a/ItemChecklistUI.cs +++ b/ItemChecklistUI.cs @@ -4,6 +4,9 @@ using Terraria; using Terraria.GameContent.UI.Elements; using Terraria.UI; using Terraria.ID; +using System; +using System.Reflection; +using System.Linq; namespace ItemChecklist.UI { @@ -11,22 +14,25 @@ namespace ItemChecklist.UI { public UIHoverImageButton toggleButton; public UIToggleHoverImageButton muteButton; + public UIHoverImageButton sortButton; public UIPanel checklistPanel; - public UIGrid checklistList; + public UIGrid checklistGrid; + public static SortModes sortMode = SortModes.TerrariaSort; float spacing = 8f; public static bool visible = false; - public static bool showCompleted = true; + public static int showCompleted = 0; // 0: both, 1: unfound, 2: found public static bool announce = true; public static string hoverText = ""; ItemSlot[] itemSlots; + internal static int[] vanillaIDsInSortOrder; public override void OnInitialize() { // Is initialize called? (Yes it is called on reload) I want to reset nicely with new character or new loaded mods: visible = false; - announce = true; + announce = true; // overwritten by modplayer checklistPanel = new UIPanel(); checklistPanel.SetPadding(10); @@ -37,7 +43,7 @@ namespace ItemChecklist.UI checklistPanel.Height.Set(-100, 1f); checklistPanel.BackgroundColor = new Color(73, 94, 171); - toggleButton = new UIHoverImageButton(Main.itemTexture[ItemID.Book], "Toggle Found"); + toggleButton = new UIHoverImageButton(Main.itemTexture[ItemID.Book], "Cycle Found Filter"); toggleButton.OnClick += ToggleButtonClicked; checklistPanel.Append(toggleButton); @@ -47,12 +53,18 @@ namespace ItemChecklist.UI muteButton.Top.Pixels = 4; checklistPanel.Append(muteButton); - checklistList = new UIGrid(5); - checklistList.Top.Pixels = 32f + spacing; - checklistList.Width.Set(-25f, 1f); - checklistList.Height.Set(-32f, 1f); - checklistList.ListPadding = 12f; - checklistPanel.Append(checklistList); + sortButton = new UIHoverImageButton(Main.itemTexture[ItemID.ToxicFlask], "Cycle Sort Method: ID"); + sortButton.OnClick += ToggleSortButtonClicked; + sortButton.Left.Pixels = spacing * 4 + 28 * 2; + sortButton.Top.Pixels = 4; + checklistPanel.Append(sortButton); + + checklistGrid = new UIGrid(5); + checklistGrid.Top.Pixels = 32f + spacing; + checklistGrid.Width.Set(-25f, 1f); + checklistGrid.Height.Set(-32f, 1f); + checklistGrid.ListPadding = 12f; + checklistPanel.Append(checklistGrid); FixedUIScrollbar checklistListScrollbar = new FixedUIScrollbar(); checklistListScrollbar.SetView(100f, 1000f); @@ -60,7 +72,7 @@ namespace ItemChecklist.UI checklistListScrollbar.Height.Set(-32f - spacing, 1f); checklistListScrollbar.HAlign = 1f; checklistPanel.Append(checklistListScrollbar); - checklistList.SetScrollbar(checklistListScrollbar); + checklistGrid.SetScrollbar(checklistListScrollbar); // Checklistlist populated when the panel is shown: UpdateCheckboxes() @@ -68,17 +80,39 @@ namespace ItemChecklist.UI // load time impact, do this on first show? itemSlots = new ItemSlot[Main.itemName.Length]; + Item[] itemSlotItems = new Item[Main.itemName.Length]; for (int i = 0; i < Main.itemName.Length; i++) { itemSlots[i] = new ItemSlot(i); + itemSlotItems[i] = itemSlots[i].item; } + + FieldInfo inventoryGlowHue = typeof(Terraria.UI.ItemSlot).GetField("inventoryGlowHue", BindingFlags.Static | BindingFlags.NonPublic); + FieldInfo inventoryGlowTime = typeof(Terraria.UI.ItemSlot).GetField("inventoryGlowTime", BindingFlags.Static | BindingFlags.NonPublic); + + MethodInfo SortMethod = typeof(ItemSorting).GetMethod("Sort", BindingFlags.Static | BindingFlags.NonPublic); + object[] parametersArray = new object[] { itemSlotItems, new int[0] }; + + inventoryGlowHue.SetValue(null, new float[Main.itemName.Length]); + inventoryGlowTime.SetValue(null, new int[Main.itemName.Length]); + SortMethod.Invoke(null, parametersArray); + inventoryGlowHue.SetValue(null, new float[58]); + inventoryGlowTime.SetValue(null, new int[58]); + + int[] vanillaIDsInSortOrderTemp = itemSlotItems.Select((x) => x.type).ToArray(); + vanillaIDsInSortOrder = new int[Main.itemName.Length]; + for (int i = 0; i < Main.itemName.Length; i++) + { + vanillaIDsInSortOrder[i] = Array.FindIndex(vanillaIDsInSortOrderTemp, x => x == i); + } + updateneeded = true; } private void ToggleButtonClicked(UIMouseEvent evt, UIElement listeningElement) { Main.PlaySound(10, -1, -1, 1); - showCompleted = !showCompleted; + showCompleted = ++showCompleted % 3; UpdateNeeded(); } @@ -89,10 +123,30 @@ namespace ItemChecklist.UI muteButton.SetEnabled(announce); } + private void ToggleSortButtonClicked(UIMouseEvent evt, UIElement listeningElement) + { + Main.PlaySound(10, -1, -1, 1); + sortMode = sortMode.Next(); + sortButton.hoverText = "Cycle Sort Method: " + sortMode.ToFriendlyString(); + UpdateNeeded(); + } + + internal void RefreshPreferences() + { + sortButton.hoverText = "Cycle Sort Method: " + sortMode.ToFriendlyString(); + muteButton.SetEnabled(announce); + UpdateNeeded(); + } + private bool updateneeded; - internal void UpdateNeeded() + private int lastfoundID = -1; + internal void UpdateNeeded(int lastfoundID = -1) { updateneeded = true; + if (lastfoundID > 0) + { + this.lastfoundID = lastfoundID; + } } // todo, items on load. @@ -100,27 +154,38 @@ namespace ItemChecklist.UI { if (!updateneeded) { return; } updateneeded = false; - checklistList.Clear(); + checklistGrid.Clear(); var itemChecklistPlayer = Main.LocalPlayer.GetModPlayer(ItemChecklist.instance); - UIElement element = new UIElement(); for (int i = 0; i < itemChecklistPlayer.findableItems.Length; i++) { if (itemChecklistPlayer.findableItems[i]) { - if (showCompleted || !itemChecklistPlayer.foundItem[i]) + // filters here + if ((showCompleted != 1 && itemChecklistPlayer.foundItem[i]) || (showCompleted != 2 && !itemChecklistPlayer.foundItem[i])) { ItemSlot box = itemSlots[i]; - checklistList._items.Add(box); - checklistList._innerList.Append(box); + checklistGrid._items.Add(box); + checklistGrid._innerList.Append(box); } } } - checklistList.UpdateOrder(); - checklistList._innerList.Recalculate(); + checklistGrid.UpdateOrder(); + checklistGrid._innerList.Recalculate(); + + if (lastfoundID > 0) + { + checklistGrid.Recalculate(); + checklistGrid.Goto(delegate (UIElement element) + { + ItemSlot itemSlot = element as ItemSlot; + return itemSlot != null && itemSlot.id == lastfoundID; + }, true); + lastfoundID = -1; + } } protected override void DrawSelf(SpriteBatch spriteBatch) @@ -135,6 +200,15 @@ namespace ItemChecklist.UI } } + public enum SortModes + { + ID, + Value, + AZ, + Rare, + TerrariaSort, + } + public class FixedUIScrollbar : UIScrollbar { protected override void DrawSelf(SpriteBatch spriteBatch) @@ -153,4 +227,34 @@ namespace ItemChecklist.UI UserInterface.ActiveInstance = temp; } } + + public static class Extensions + { + public static T Next(this T src) where T : struct + { + if (!typeof(T).IsEnum) throw new ArgumentException(String.Format("Argumnent {0} is not an Enum", typeof(T).FullName)); + + T[] Arr = (T[])Enum.GetValues(src.GetType()); + int j = Array.IndexOf(Arr, src) + 1; + return (Arr.Length == j) ? Arr[0] : Arr[j]; + } + + public static string ToFriendlyString(this SortModes sortmode) + { + switch (sortmode) + { + case SortModes.AZ: + return "Alphabetically"; + case SortModes.ID: + return "ID"; + case SortModes.Value: + return "Value"; + case SortModes.Rare: + return "Rarity"; + case SortModes.TerrariaSort: + return "Terraria Sort"; + } + return "Unknown Sort"; + } + } } diff --git a/ItemSlot.cs b/ItemSlot.cs index 388ccdf..ea84aa8 100644 --- a/ItemSlot.cs +++ b/ItemSlot.cs @@ -15,8 +15,8 @@ namespace ItemChecklist // private float _visibilityActive = 1f; // private float _visibilityInactive = 0.4f; private float scale = 0.6f; - private int id; - private Item item; + internal int id; + internal Item item; public ItemSlot(int id) { @@ -32,6 +32,27 @@ namespace ItemChecklist public override int CompareTo(object obj) { ItemSlot other = obj as ItemSlot; + int result; + switch (ItemChecklistUI.sortMode) + { + case SortModes.ID: + return id.CompareTo(other.id); + case SortModes.AZ: + return item.name.CompareTo(other.item.name); + case SortModes.Value: + result = item.value.CompareTo(other.item.value); + if (result == 0) + result = item.name.CompareTo(other.item.name); + return result; + case SortModes.Rare: + result = item.rare.CompareTo(other.item.rare); + if (result == 0) + result = item.name.CompareTo(other.item.name); + return result; + case SortModes.TerrariaSort: + return ItemChecklistUI.vanillaIDsInSortOrder[id].CompareTo(ItemChecklistUI.vanillaIDsInSortOrder[other.id]); + } + return id.CompareTo(other.id); } diff --git a/UIGrid.cs b/UIGrid.cs index 42b75ec..0c5f4e5 100644 --- a/UIGrid.cs +++ b/UIGrid.cs @@ -66,13 +66,17 @@ namespace ItemChecklist return this._innerListHeight; } - public void Goto(UIGrid.ElementSearchMethod searchMethod) + public void Goto(UIGrid.ElementSearchMethod searchMethod, bool center = false) { for (int i = 0; i < this._items.Count; i++) { if (searchMethod(this._items[i])) { this._scrollbar.ViewPosition = this._items[i].Top.Pixels; + if (center) + { + this._scrollbar.ViewPosition = this._items[i].Top.Pixels - GetInnerDimensions().Height/2 + _items[i].GetOuterDimensions().Height/2; + } return; } } @@ -124,7 +128,7 @@ namespace ItemChecklist this._items[i].Top.Set(top, 0f); this._items[i].Left.Set(left, 0f); this._items[i].Recalculate(); - if(i%cols == cols - 1) + if (i % cols == cols - 1) { top += this._items[i].GetOuterDimensions().Height + this.ListPadding; left = 0; @@ -135,6 +139,10 @@ namespace ItemChecklist } //num += this._items[i].GetOuterDimensions().Height + this.ListPadding; } + if (_items.Count > 0) + { + top += ListPadding + _items[0].GetOuterDimensions().Height; + } this._innerListHeight = top; } diff --git a/build.txt b/build.txt index d4d2cea..8838969 100644 --- a/build.txt +++ b/build.txt @@ -1,5 +1,5 @@ author = jopojelly -version = 0.1.0.2 +version = 0.2.0.1 displayName = Item Checklist homepage = https://forums.terraria.org/index.php?threads/item-checklist-in-game-100-item-collection-checklist.52786/ hideCode = false