diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..18f23676 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +[code] +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..cb7d9c23 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.csproj +*.sln +*.user +obj/ +bin/ +.vs/ \ No newline at end of file diff --git a/Components/TEAbstractStorageUnit.cs b/Components/TEAbstractStorageUnit.cs index d5dc7f85..41ea38e7 100644 --- a/Components/TEAbstractStorageUnit.cs +++ b/Components/TEAbstractStorageUnit.cs @@ -56,7 +56,7 @@ public TEStorageHeart GetHeart() public abstract bool HasSpaceInStackFor(Item check, bool locked = false); - public abstract bool HasItem(Item check, bool locked = false); + public abstract bool HasItem(Item check, bool locked = false, bool ignorePrefix = false); public abstract IEnumerable GetItems(); @@ -95,4 +95,4 @@ public override void NetReceive(BinaryReader reader, bool lightReceive) center = new Point16(reader.ReadInt16(), reader.ReadInt16()); } } -} \ No newline at end of file +} diff --git a/Components/TECreativeStorageUnit.cs b/Components/TECreativeStorageUnit.cs index f9f503b9..ac37895f 100644 --- a/Components/TECreativeStorageUnit.cs +++ b/Components/TECreativeStorageUnit.cs @@ -29,7 +29,7 @@ public override bool HasSpaceInStackFor(Item check, bool locked = false) return false; } - public override bool HasItem(Item check, bool locked = false) + public override bool HasItem(Item check, bool locked = false, bool ignorePrefix = false) { return !Inactive; } @@ -125,4 +125,4 @@ public void Dispose() { } } -} \ No newline at end of file +} diff --git a/Components/TEStorageHeart.cs b/Components/TEStorageHeart.cs index bc19a849..b8242c5b 100644 --- a/Components/TEStorageHeart.cs +++ b/Components/TEStorageHeart.cs @@ -20,7 +20,14 @@ public class TEStorageHeart : TEStorageCenter private int updateTimer = 60; private int compactStage = 0; - public override bool ValidTile(Tile tile) + public bool IsAlive { get; private set; } = true; + + public override void OnKill() + { + IsAlive = false; + } + + public override bool ValidTile(Tile tile) { return tile.type == mod.TileType("StorageHeart") && tile.frameX == 0 && tile.frameY == 0; } @@ -256,7 +263,10 @@ public void ResetCompactStage(int stage = 0) } } - public void DepositItem(Item toDeposit) + ItemTypeOrderedSet _uniqueItemsPutHistory = new ItemTypeOrderedSet("UniqueItemsPutHistory"); + public IEnumerable UniqueItemsPutHistory { get { return _uniqueItemsPutHistory.Items; } } + + public void DepositItem(Item toDeposit) { if (Main.netMode == 2) { @@ -265,6 +275,7 @@ public void DepositItem(Item toDeposit) int oldStack = toDeposit.stack; try { + var remember = toDeposit.type; foreach (TEAbstractStorageUnit storageUnit in GetStorageUnits()) { if (!storageUnit.Inactive && storageUnit.HasSpaceInStackFor(toDeposit, true)) @@ -276,17 +287,21 @@ public void DepositItem(Item toDeposit) } } } - foreach (TEAbstractStorageUnit storageUnit in GetStorageUnits()) + var prevNewAndShiny = toDeposit.newAndShiny; + toDeposit.newAndShiny = !_uniqueItemsPutHistory.Contains(toDeposit); + foreach (TEAbstractStorageUnit storageUnit in GetStorageUnits()) { if (!storageUnit.Inactive && !storageUnit.IsFull) { storageUnit.DepositItem(toDeposit, true); if (toDeposit.IsAir) { - return; + _uniqueItemsPutHistory.Add(remember); + return; } } } + toDeposit.newAndShiny = prevNewAndShiny; } finally { @@ -352,6 +367,30 @@ public Item TryWithdraw(Item lookFor) } } + public bool HasItem(Item lookFor, bool ignorePrefix = false) + { + if (Main.netMode == 2) + { + EnterReadLock(); + } + try + { + foreach (TEAbstractStorageUnit storageUnit in GetStorageUnits()) + { + if (storageUnit.HasItem(lookFor, true, ignorePrefix)) + return true; + } + return false; + } + finally + { + if (Main.netMode == 2) + { + ExitReadLock(); + } + } + } + public override TagCompound Save() { TagCompound tag = base.Save(); @@ -364,6 +403,7 @@ public override TagCompound Save() tagRemotes.Add(tagRemote); } tag.Set("RemoteAccesses", tagRemotes); + _uniqueItemsPutHistory.Save(tag); return tag; } @@ -374,6 +414,7 @@ public override void Load(TagCompound tag) { remoteAccesses.Add(new Point16(tagRemote.GetShort("X"), tagRemote.GetShort("Y"))); } + _uniqueItemsPutHistory.Load(tag); } public override void NetSend(BinaryWriter writer, bool lightSend) @@ -397,4 +438,4 @@ public override void NetReceive(BinaryReader reader, bool lightReceive) } } } -} \ No newline at end of file +} diff --git a/Components/TEStorageUnit.cs b/Components/TEStorageUnit.cs index b20d34d7..e5434263 100644 --- a/Components/TEStorageUnit.cs +++ b/Components/TEStorageUnit.cs @@ -21,6 +21,7 @@ public class TEStorageUnit : TEAbstractStorageUnit //metadata private HashSet hasSpaceInStack = new HashSet(); private HashSet hasItem = new HashSet(); + private HashSet hasItemNoPrefix = new HashSet(); public int Capacity { @@ -106,7 +107,7 @@ public bool HasSpaceFor(Item check, bool locked = false) return !IsFull || HasSpaceInStackFor(check, locked); } - public override bool HasItem(Item check, bool locked = false) + public override bool HasItem(Item check, bool locked = false, bool ignorePrefix = false) { if (Main.netMode == 2 && !locked) { @@ -114,8 +115,9 @@ public override bool HasItem(Item check, bool locked = false) } try { + if (ignorePrefix) return hasItemNoPrefix.Contains(check.type); ItemData data = new ItemData(check); - return hasItem.Contains(data); + return hasItem.Contains(data); } finally { @@ -143,7 +145,7 @@ public override void DepositItem(Item toDeposit, bool locked = false) } try { - Item original = toDeposit.Clone(); + Item original = toDeposit.Clone(); bool finished = false; bool hasChange = false; foreach (Item item in items) @@ -157,6 +159,7 @@ public override void DepositItem(Item toDeposit, bool locked = false) newStack = item.maxStack; } item.stack = newStack; + if (toDeposit.newAndShiny) item.newAndShiny = true; hasChange = true; toDeposit.stack = total - newStack; if (toDeposit.stack <= 0) @@ -316,8 +319,11 @@ internal static void SwapItems(TEStorageUnit unit1, TEStorageUnit unit2) unit1.hasSpaceInStack = unit2.hasSpaceInStack; unit2.hasSpaceInStack = dict; dict = unit1.hasItem; - unit1.hasItem = unit2.hasItem; - unit2.hasItem = dict; + unit1.hasItem = unit2.hasItem; + unit2.hasItem = dict; + var temp = unit1.hasItemNoPrefix; + unit1.hasItemNoPrefix = unit2.hasItemNoPrefix; + unit2.hasItemNoPrefix = temp; if (Main.netMode == 2) { unit1.netQueue.Clear(); @@ -375,6 +381,7 @@ public override void Load(TagCompound tag) hasSpaceInStack.Add(data); } hasItem.Add(data); + hasItemNoPrefix.Add(data.Type); } if (Main.netMode == 2) { @@ -447,6 +454,7 @@ public override void NetReceive(BinaryReader trueReader, bool lightReceive) items = other.items; hasSpaceInStack = other.hasSpaceInStack; hasItem = other.hasItem; + hasItemNoPrefix = other.hasItemNoPrefix; } receiving = true; int count = reader.ReadUInt16(); @@ -473,12 +481,14 @@ private void ClearItemsData() items.Clear(); hasSpaceInStack.Clear(); hasItem.Clear(); + hasItemNoPrefix.Clear(); } private void RepairMetadata() { hasSpaceInStack.Clear(); hasItem.Clear(); + hasItemNoPrefix.Clear(); foreach (Item item in items) { ItemData data = new ItemData(item); @@ -487,6 +497,7 @@ private void RepairMetadata() hasSpaceInStack.Add(data); } hasItem.Add(data); + hasItemNoPrefix.Add(data.Type); } } @@ -578,6 +589,7 @@ protected override bool ReceiveData(BinaryReader reader, TEStorageUnit unit) unit.hasSpaceInStack.Add(data); } unit.hasItem.Add(data); + unit.hasItemNoPrefix.Add(data.Type); } return false; } @@ -625,3 +637,4 @@ protected override bool ReceiveData(BinaryReader reader, TEStorageUnit unit) } } } + diff --git a/CraftingGUI.cs b/CraftingGUI.cs index 6baf4aa6..eeca7bbc 100644 --- a/CraftingGUI.cs +++ b/CraftingGUI.cs @@ -18,14 +18,21 @@ namespace MagicStorage { - public static class CraftingGUI + public static class CraftingGUI { - private const int padding = 4; + const int RecipeButtonsNewChoice = 0; + const int RecipeButtonsBlacklistChoice = 3; + const int RecipeButtonsFavoritesChoice = 2; + private const int padding = 4; private const int numColumns = 10; private const int numColumns2 = 7; private const float inventoryScale = 0.85f; private const float smallScale = 0.7f; + static HashSet threadCheckListFoundItems; + static Mod _checkListMod; + static volatile bool wasItemChecklistRetrieved; + public static MouseState curMouse; public static MouseState oldMouse; public static bool MouseClicked @@ -36,23 +43,31 @@ public static bool MouseClicked } } - private static UIPanel basePanel; + public static bool RightMouseClicked + { + get + { + return curMouse.RightButton == ButtonState.Pressed && oldMouse.RightButton == ButtonState.Released; + } + } + + private static UIPanel basePanel = new UIPanel(); private static float panelTop; private static float panelLeft; private static float panelWidth; private static float panelHeight; - private static UIElement topBar; + private static UIElement topBar = new UIElement(); internal static UISearchBar searchBar; private static UIButtonChoice sortButtons; private static UIButtonChoice recipeButtons; - private static UIElement topBar2; + private static UIElement topBar2 = new UIElement(); private static UIButtonChoice filterButtons; - internal static UISearchBar searchBar2; - + internal static UISearchBar searchBar2; + private static UIText stationText; - private static UISlotZone stationZone = new UISlotZone(HoverStation, GetStation, inventoryScale); - private static UIText recipeText; + private static UISlotZone stationZone = new UISlotZone(HoverStation, GetStation, inventoryScale); + private static UIText recipeText; private static UISlotZone recipeZone = new UISlotZone(HoverRecipe, GetRecipe, inventoryScale); internal static UIScrollbar scrollBar = new UIScrollbar(); @@ -80,15 +95,17 @@ public static bool MouseClicked private static UIElement bottomBar = new UIElement(); private static UIText capacityText; - private static UIPanel recipePanel; + private static UIPanel recipePanel = new UIPanel(); + private static float recipeTop; private static float recipeLeft; private static float recipeWidth; private static float recipeHeight; - private static UIText recipePanelHeader; + private static UIText recipePanelHeader; private static UIText ingredientText; private static UISlotZone ingredientZone = new UISlotZone(HoverItem, GetIngredient, smallScale); + private static UISlotZone recipeHeaderZone = new UISlotZone(HoverHeader, GetHeader, smallScale); private static UIText reqObjText; private static UIText reqObjText2; private static UIText storedItemsText; @@ -104,14 +121,15 @@ public static bool MouseClicked private static float scrollBar2MaxViewSize = 2f; internal static UITextPanel craftButton; - private static Item result = null; + private static Item result = null; private static UISlotZone resultZone = new UISlotZone(HoverResult, GetResult, inventoryScale); private static int craftTimer = 0; private const int startMaxCraftTimer = 20; private static int maxCraftTimer = startMaxCraftTimer; private static int rightClickTimer = 0; private const int startMaxRightClickTimer = 20; - private static int maxRightClickTimer = startMaxRightClickTimer; + + private static int maxRightClickTimer = startMaxRightClickTimer; private static Object threadLock = new Object(); private static Object recipeLock = new Object(); @@ -124,7 +142,7 @@ public static bool MouseClicked private static List threadRecipeAvailable = new List(); private static List nextRecipes = new List(); private static List nextRecipeAvailable = new List(); - + public static void Initialize() { lock (recipeLock) @@ -132,8 +150,8 @@ public static void Initialize() recipes = nextRecipes; recipeAvailable = nextRecipeAvailable; } - - InitLangStuff(); + + InitLangStuff(); float itemSlotWidth = Main.inventoryBackTexture.Width * inventoryScale; float itemSlotHeight = Main.inventoryBackTexture.Height * inventoryScale; float smallSlotWidth = Main.inventoryBackTexture.Width * smallScale; @@ -141,7 +159,6 @@ public static void Initialize() panelTop = Main.instance.invBottom + 60; panelLeft = 20f; - basePanel = new UIPanel(); float innerPanelLeft = panelLeft + basePanel.PaddingLeft; float innerPanelWidth = numColumns * (itemSlotWidth + padding) + 20f + padding; panelWidth = basePanel.PaddingLeft + innerPanelWidth + basePanel.PaddingRight; @@ -152,7 +169,6 @@ public static void Initialize() basePanel.Height.Set(panelHeight, 0f); basePanel.Recalculate(); - recipePanel = new UIPanel(); recipeTop = panelTop; recipeLeft = panelLeft + panelWidth; recipeWidth = numColumns2 * (smallSlotWidth + padding) + 20f + padding; @@ -164,7 +180,6 @@ public static void Initialize() recipePanel.Height.Set(recipeHeight, 0f); recipePanel.Recalculate(); - topBar = new UIElement(); topBar.Width.Set(0f, 1f); topBar.Height.Set(32f, 0f); basePanel.Append(topBar); @@ -173,7 +188,7 @@ public static void Initialize() topBar.Append(sortButtons); float sortButtonsRight = sortButtons.GetDimensions().Width + padding; InitRecipeButtons(); - float recipeButtonsLeft = sortButtonsRight + 32f + 3 * padding; + float recipeButtonsLeft = sortButtonsRight + 3 * padding; recipeButtons.Left.Set(recipeButtonsLeft, 0f); topBar.Append(recipeButtons); float recipeButtonsRight = recipeButtonsLeft + recipeButtons.GetDimensions().Width + padding; @@ -183,7 +198,6 @@ public static void Initialize() searchBar.Height.Set(0f, 1f); topBar.Append(searchBar); - topBar2 = new UIElement(); topBar2.Width.Set(0f, 1f); topBar2.Height.Set(32f, 0f); topBar2.Top.Set(36f, 0f); @@ -191,23 +205,23 @@ public static void Initialize() InitFilterButtons(); float filterButtonsRight = filterButtons.GetDimensions().Width + padding; - topBar2.Append(filterButtons); - searchBar2.Left.Set(filterButtonsRight + padding, 0f); - searchBar2.Width.Set(-filterButtonsRight - 2 * padding, 1f); - searchBar2.Height.Set(0f, 1f); - topBar2.Append(searchBar2); + topBar2.Append(filterButtons); + searchBar2.Left.Set(filterButtonsRight + padding, 0f); + searchBar2.Width.Set(-filterButtonsRight - 2 * padding, 1f); + searchBar2.Height.Set(0f, 1f); + topBar2.Append(searchBar2); stationText.Top.Set(76f, 0f); basePanel.Append(stationText); stationZone.Width.Set(0f, 1f); stationZone.Top.Set(100f, 0f); - stationZone.Height.Set(70f, 0f); - stationZone.SetDimensions(numColumns, 1); + stationZone.Height.Set(90f, 0f); + stationZone.SetDimensions(numColumns, 1); basePanel.Append(stationZone); - - recipeText.Top.Set(152f, 0f); - basePanel.Append(recipeText); + + recipeText.Top.Set(152f, 0f); + basePanel.Append(recipeText); recipeZone.Width.Set(0f, 1f); recipeZone.Top.Set(176f, 0f); @@ -253,9 +267,16 @@ public static void Initialize() capacityText.SetText(numItems + "/" + capacity + " Items"); bottomBar.Append(capacityText); - recipePanel.Append(recipePanelHeader); - ingredientText.Top.Set(30f, 0f); - recipePanel.Append(ingredientText); + recipePanelHeader.Left.Set(60, 0f); + recipePanel.Append(recipePanelHeader); + + ingredientText.Top.Set(30f, 0f); + ingredientText.Left.Set(60, 0f); + + recipeHeaderZone.SetDimensions(1, 1); + recipePanel.Append(recipeHeaderZone); + + recipePanel.Append(ingredientText); ingredientZone.SetDimensions(numColumns2, 2); ingredientZone.Top.Set(54f, 0f); @@ -287,14 +308,14 @@ public static void Initialize() scrollBar2.Left.Set(-20f, 1f); scrollBar2.SetView(scrollBar2ViewSize, scrollBar2MaxViewSize); storageZone.Append(scrollBar2); - + craftButton.Top.Set(-32f, 1f); craftButton.Width.Set(100f, 0f); craftButton.Height.Set(24f, 0f); craftButton.PaddingTop = 8f; craftButton.PaddingBottom = 8f; recipePanel.Append(craftButton); - + resultZone.SetDimensions(1, 1); resultZone.Left.Set(-itemSlotWidth, 1f); resultZone.Top.Set(-itemSlotHeight, 1f); @@ -307,20 +328,20 @@ private static void InitLangStuff() { if (searchBar == null) { - searchBar = new UISearchBar(Language.GetText("Mods.MagicStorage.SearchName")); - } - if (searchBar2 == null) - { - searchBar2 = new UISearchBar(Language.GetText("Mods.MagicStorage.SearchMod")); + searchBar = new UISearchBar(Language.GetText("Mods.MagicStorage.SearchName"), RefreshItems); } + if (searchBar2 == null) + { + searchBar2 = new UISearchBar(Language.GetText("Mods.MagicStorage.SearchMod"), RefreshItems); + } if (stationText == null) { stationText = new UIText(Language.GetText("Mods.MagicStorage.CraftingStations")); } - if (recipeText == null) - { - recipeText = new UIText(Language.GetText("Mods.MagicStorage.Recipes")); - } + if (recipeText == null) + { + recipeText = new UIText(Language.GetText("Mods.MagicStorage.Recipes")); + } if (capacityText == null) { capacityText = new UIText("Items"); @@ -351,29 +372,11 @@ private static void InitLangStuff() } } - internal static void Unload() - { - sortButtons = null; - filterButtons = null; - recipeButtons = null; - } - private static void InitSortButtons() { if (sortButtons == null) { - sortButtons = new UIButtonChoice(new Texture2D[] - { - Main.inventorySortTexture[0], - MagicStorage.Instance.GetTexture("SortID"), - MagicStorage.Instance.GetTexture("SortName") - }, - new LocalizedText[] - { - Language.GetText("Mods.MagicStorage.SortDefault"), - Language.GetText("Mods.MagicStorage.SortID"), - Language.GetText("Mods.MagicStorage.SortName") - }); + sortButtons = GUIHelpers.MakeSortButtons(CraftingGUI.RefreshItems); } } @@ -381,16 +384,21 @@ private static void InitRecipeButtons() { if (recipeButtons == null) { - recipeButtons = new UIButtonChoice(new Texture2D[] + recipeButtons = new UIButtonChoice(CraftingGUI.RefreshItems, new Texture2D[] { MagicStorage.Instance.GetTexture("RecipeAvailable"), - MagicStorage.Instance.GetTexture("RecipeAll") - }, + MagicStorage.Instance.GetTexture("RecipeAll"), + MagicStorage.Instance.GetTexture("FilterMisc"), + MagicStorage.Instance.GetTexture("RecipeAll"), + }, new LocalizedText[] { Language.GetText("Mods.MagicStorage.RecipeAvailable"), - Language.GetText("Mods.MagicStorage.RecipeAll") - }); + Language.GetText("Mods.MagicStorage.RecipeAll"), + Language.GetText("Mods.MagicStorage.ShowOnlyFavorited"), + Language.GetText("Mods.MagicStorage.RecipeBlacklist"), + + }) { Choice = 1 }; } } @@ -398,31 +406,13 @@ private static void InitFilterButtons() { if (filterButtons == null) { - filterButtons = new UIButtonChoice(new Texture2D[] - { - MagicStorage.Instance.GetTexture("FilterAll"), - MagicStorage.Instance.GetTexture("FilterMelee"), - MagicStorage.Instance.GetTexture("FilterPickaxe"), - MagicStorage.Instance.GetTexture("FilterArmor"), - MagicStorage.Instance.GetTexture("FilterPotion"), - MagicStorage.Instance.GetTexture("FilterTile"), - MagicStorage.Instance.GetTexture("FilterMisc"), - }, - new LocalizedText[] - { - Language.GetText("Mods.MagicStorage.FilterAll"), - Language.GetText("Mods.MagicStorage.FilterWeapons"), - Language.GetText("Mods.MagicStorage.FilterTools"), - Language.GetText("Mods.MagicStorage.FilterEquips"), - Language.GetText("Mods.MagicStorage.FilterPotions"), - Language.GetText("Mods.MagicStorage.FilterTiles"), - Language.GetText("Mods.MagicStorage.FilterMisc") - }); + filterButtons = GUIHelpers.MakeFilterButtons(false, CraftingGUI.RefreshItems); } } public static void Update(GameTime gameTime) - {try{ + { + try { oldMouse = StorageGUI.oldMouse; curMouse = StorageGUI.curMouse; if (Main.playerInventory && Main.player[Main.myPlayer].GetModPlayer(MagicStorage.Instance).ViewingStorage().X >= 0 && StoragePlayer.IsStorageCrafting()) @@ -431,6 +421,7 @@ public static void Update(GameTime gameTime) { ResetSlotFocus(); } + if (basePanel != null) { basePanel.Update(gameTime); @@ -443,42 +434,50 @@ public static void Update(GameTime gameTime) else { scrollBarFocus = 0; - selectedRecipe = null; craftTimer = 0; maxCraftTimer = startMaxCraftTimer; ResetSlotFocus(); }}catch(Exception e){Main.NewTextMultiline(e.ToString());} } - public static void Draw(TEStorageHeart heart) - {try{ - Player player = Main.player[Main.myPlayer]; - StoragePlayer modPlayer = player.GetModPlayer(MagicStorage.Instance); - Initialize(); - if (Main.mouseX > panelLeft && Main.mouseX < recipeLeft + panelWidth && Main.mouseY > panelTop && Main.mouseY < panelTop + panelHeight) - { - player.mouseInterface = true; - player.showItemIcon = false; - InterfaceHelper.HideItemIconCache(); - } - basePanel.Draw(Main.spriteBatch); - recipePanel.Draw(Main.spriteBatch); - Vector2 pos = recipeZone.GetDimensions().Position(); - if (threadRunning) - { - Utils.DrawBorderString(Main.spriteBatch, "Loading", pos + new Vector2(8f, 8f), Color.White); - } - stationZone.DrawText(); - recipeZone.DrawText(); - ingredientZone.DrawText(); - storageZone.DrawText(); - resultZone.DrawText(); - sortButtons.DrawText(); - recipeButtons.DrawText(); - filterButtons.DrawText();}catch(Exception e){Main.NewTextMultiline(e.ToString());} - } - - private static Item GetStation(int slot, ref int context) + public static void Draw(TEStorageHeart heart) + { + try + { + Player player = Main.player[Main.myPlayer]; + Initialize(); + if (Main.mouseX > panelLeft && Main.mouseX < recipeLeft + panelWidth && Main.mouseY > panelTop && Main.mouseY < panelTop + panelHeight) + { + player.mouseInterface = true; + player.showItemIcon = false; + InterfaceHelper.HideItemIconCache(); + } + + basePanel.Draw(Main.spriteBatch); + recipePanel.Draw(Main.spriteBatch); + Vector2 pos = recipeZone.GetDimensions().Position(); + if (threadRunning) + { + Utils.DrawBorderString(Main.spriteBatch, "Loading", pos + new Vector2(8f, 8f), Color.White); + } + + stationZone.DrawText(); + recipeZone.DrawText(); + ingredientZone.DrawText(); + recipeHeaderZone.DrawText(); + storageZone.DrawText(); + resultZone.DrawText(); + sortButtons.DrawText(); + recipeButtons.DrawText(); + filterButtons.DrawText(); + } + catch (Exception e) + { + Main.NewTextMultiline(e.ToString()); + } + } + + private static Item GetStation(int slot, ref int context) { Item[] stations = GetCraftingStations(); if (stations == null || slot >= stations.Length) @@ -496,24 +495,54 @@ private static Item GetRecipe(int slot, ref int context) } int index = slot + numColumns * (int)Math.Round(scrollBar.ViewPosition); Item item = index < recipes.Count ? recipes[index].createItem : new Item(); - if (!item.IsAir && recipes[index] == selectedRecipe) - { - context = 6; - } - if (!item.IsAir && !recipeAvailable[index]) - { - context = recipes[index] == selectedRecipe ? 4 : 3; + if (!item.IsAir) + { + if (recipes[index] == selectedRecipe) + { + context = 6; + } + if (!recipeAvailable[index]) + { + context = recipes[index] == selectedRecipe ? 4 : 3; + } + if (ModPlayer.FavoritedRecipes.Contains(item)) + { + item = item.Clone(); + item.favorited = true; + } + + if (!ModPlayer.SeenRecipes.Contains(item)) + { + item = item.Clone(); + item.newAndShiny = true; + } } + return item; } - private static Item GetIngredient(int slot, ref int context) + private static Item GetHeader(int slot, ref int context) + { + if (selectedRecipe == null) + return new Item(); + + var item = selectedRecipe.createItem; + if (item.IsAir) + { + int t = item.type; + item = new Item(); + item.SetDefaults(t); + item.stack = 0; + } + return item; + } + + private static Item GetIngredient(int slot, ref int context) { - if (selectedRecipe == null || slot >= selectedRecipe.requiredItem.Length) - { - return new Item(); - } - Item item = selectedRecipe.requiredItem[slot].Clone(); + if (selectedRecipe == null || slot >= selectedRecipe.requiredItem.Length) + return new Item(); + + Item item = selectedRecipe.requiredItem[slot].Clone(); if (selectedRecipe.anyWood && item.type == ItemID.Wood) { item.SetNameOverride(Lang.misc[37].Value + " " + Lang.GetItemNameValue(ItemID.Wood)); @@ -563,10 +592,10 @@ private static void UpdateRecipeText() if (selectedRecipe == null) { reqObjText2.SetText(""); - } + } else { - bool isEmpty = true; + bool isEmpty = true; string text = ""; for (int k = 0; k < selectedRecipe.requiredTile.Length; k++) { @@ -622,7 +651,7 @@ private static void UpdateRecipeText() text = Language.GetTextValue("LegacyInterface.23"); } reqObjText2.SetText(text); - } + } } private static void UpdateScrollBar() @@ -687,25 +716,25 @@ private static void UpdateCraftButton() if (curMouse.X > dim.X && curMouse.X < dim.X + dim.Width && curMouse.Y > dim.Y && curMouse.Y < dim.Y + dim.Height) { craftButton.BackgroundColor = new Color(73, 94, 171); - if (curMouse.LeftButton == ButtonState.Pressed) + if (curMouse.LeftButton == ButtonState.Pressed && selectedRecipe != null && IsAvailable(selectedRecipe) && PassesBlock(selectedRecipe)) { - if (selectedRecipe != null && IsAvailable(selectedRecipe) && PassesBlock(selectedRecipe)) - { - if (craftTimer <= 0) - { - craftTimer = maxCraftTimer; - maxCraftTimer = maxCraftTimer * 3 / 4; - if (maxCraftTimer <= 0) - { - maxCraftTimer = 1; - } - TryCraft(); - RefreshItems(); - Main.PlaySound(7, -1, -1, 1); - } - craftTimer--; - flag = true; - } + if (craftTimer <= 0) + { + craftTimer = maxCraftTimer; + maxCraftTimer = maxCraftTimer * 3 / 4; + if (maxCraftTimer <= 0) + { + maxCraftTimer = 1; + } + TryCraft(); + RefreshItems(); + Main.PlaySound(7, -1, -1, 1); + } + craftTimer--; + flag = true; + StoragePlayer modPlayer = Main.player[Main.myPlayer].GetModPlayer(); + if (modPlayer.AddToCraftedRecipes(selectedRecipe.createItem)) + RefreshItems(); } } else @@ -723,7 +752,7 @@ private static void UpdateCraftButton() } } - private static TEStorageHeart GetHeart() + private static TEStorageHeart GetHeart() { Player player = Main.player[Main.myPlayer]; StoragePlayer modPlayer = player.GetModPlayer(); @@ -745,131 +774,303 @@ private static Item[] GetCraftingStations() public static void RefreshItems() { + var modPlayer = ModPlayer; + if (modPlayer.SeenRecipes.Count == 0) + { + foreach (var item in GetKnownItems()) + modPlayer.SeenRecipes.Add(item); + } items.Clear(); TEStorageHeart heart = GetHeart(); if (heart == null) { return; } - items.AddRange(ItemSorter.SortAndFilter(heart.GetStoredItems(), SortMode.Id, FilterMode.All, "", "")); + + items.AddRange(ItemSorter.SortAndFilter(heart.GetStoredItems(), SortMode.Id, FilterMode.All, searchBar2.Text, "")); AnalyzeIngredients(); InitLangStuff(); InitSortButtons(); InitRecipeButtons(); InitFilterButtons(); - SortMode sortMode; - switch (sortButtons.Choice) - { - case 0: - sortMode = SortMode.Default; - break; - case 1: - sortMode = SortMode.Id; - break; - case 2: - sortMode = SortMode.Name; - break; - default: - sortMode = SortMode.Default; - break; - } - FilterMode filterMode; - switch (filterButtons.Choice) - { - case 0: - filterMode = FilterMode.All; - break; - case 1: - filterMode = FilterMode.Weapons; - break; - case 2: - filterMode = FilterMode.Tools; - break; - case 3: - filterMode = FilterMode.Equipment; - break; - case 4: - filterMode = FilterMode.Potions; - break; - case 5: - filterMode = FilterMode.Placeables; - break; - case 6: - filterMode = FilterMode.Misc; - break; - default: - filterMode = FilterMode.All; - break; - } + SortMode sortMode = (SortMode)sortButtons.Choice; + FilterMode filterMode = (FilterMode)filterButtons.Choice; + RefreshStorageItems(); - lock (threadLock) + + HashSet foundItems; + HashSet hiddenRecipes; + HashSet craftedRecipes; + HashSet asKnownRecipes; + GetKnownItems(out foundItems, out hiddenRecipes, out craftedRecipes, out asKnownRecipes); + foundItems.UnionWith(asKnownRecipes); + + var favoritesCopy = new HashSet(modPlayer.FavoritedRecipes.Items.Select(x => x.type)); + + EnsureProductToRecipesInited(); + + lock (threadLock) { threadNeedsRestart = true; threadSortMode = sortMode; threadFilterMode = filterMode; - if (!threadRunning) - { - threadRunning = true; - Thread thread = new Thread(RefreshRecipes); - thread.Start(); - } + threadCheckListFoundItems = foundItems; + if (!threadRunning) + { + threadRunning = true; + Thread thread = new Thread(_ => RefreshRecipes(hiddenRecipes, craftedRecipes, favoritesCopy)); + thread.Start(); + } } } - private static void RefreshRecipes() - { - while (true) - {try{ - SortMode sortMode; - FilterMode filterMode; - lock (threadLock) - { - threadNeedsRestart = false; - sortMode = threadSortMode; - filterMode = threadFilterMode; - } - var temp = ItemSorter.GetRecipes(sortMode, filterMode, searchBar2.Text, searchBar.Text); - threadRecipes.Clear(); - threadRecipeAvailable.Clear(); - try - { - if (recipeButtons.Choice == 0) - { - threadRecipes.AddRange(temp.Where(recipe => IsAvailable(recipe))); - threadRecipeAvailable.AddRange(threadRecipes.Select(recipe => true)); - } - else - { - threadRecipes.AddRange(temp); - threadRecipeAvailable.AddRange(threadRecipes.Select(recipe => IsAvailable(recipe))); - } - } - catch (InvalidOperationException) - { - } - catch (KeyNotFoundException) - { - } - lock (recipeLock) - { - nextRecipes = new List(); - nextRecipeAvailable = new List(); - nextRecipes.AddRange(threadRecipes); - nextRecipeAvailable.AddRange(threadRecipeAvailable); - - } - lock (threadLock) - { - if (!threadNeedsRestart) - { - threadRunning = false; - return; - } - }}catch(Exception e){Main.NewTextMultiline(e.ToString());} - } - } - - private static void AnalyzeIngredients() + public static HashSet GetKnownItems() + { + HashSet a, b, c, d; + GetKnownItems(out a, out b, out c, out d); + a.UnionWith(b); + a.UnionWith(c); + a.UnionWith(d); + return a; + } + + static void GetKnownItems(out HashSet foundItems, out HashSet hiddenRecipes, out HashSet craftedRecipes, out HashSet asKnownRecipes) + { + foundItems = new HashSet(RetrieveFoundItemsCheckList()); + + StoragePlayer modPlayer = ModPlayer; + hiddenRecipes = new HashSet(modPlayer.HiddenRecipes.Select(x => x.type)); + craftedRecipes = new HashSet(modPlayer.CraftedRecipes.Select(x => x.type)); + asKnownRecipes = new HashSet(modPlayer.AsKnownRecipes.Items.Select(x => x.type)); + } + + static StoragePlayer ModPlayer { get { return Main.player[Main.myPlayer].GetModPlayer(); } } + + static IEnumerable RetrieveFoundItemsCheckList() + { + if (_checkListMod == null) + _checkListMod = ModLoader.GetMod("ItemChecklist"); + + var foundItems = _checkListMod != null ? _checkListMod.Call("RequestFoundItems") as bool[] : new bool[0]; + if (foundItems.Length > 0) wasItemChecklistRetrieved = true; + return foundItems.Select((v, type) => new { WasFound = v, type }).Where(x => x.WasFound).Select(x => x.type); + } + + static void EnsureProductToRecipesInited() + { + if (_productToRecipes == null) + { + var allRecipes = ItemSorter.GetRecipes(SortMode.Id, FilterMode.All, "", "").Where(x => x != null && x.createItem != null && x.createItem.type > 0).ToArray(); + _productToRecipes = allRecipes.GroupBy(x => x.createItem.type).ToDictionary(x => x.Key, x => x.ToList()); + } + } + + static Dictionary> _productToRecipes; + + /// + /// Checks all crafting tree until it finds already available ingredients + /// + static bool IsKnownRecursively(Recipe recipe, HashSet availableSet) + { + return IsKnownRecursively(recipe, availableSet, new HashSet(), new Dictionary()); + } + + /// + /// Checks all crafting tree until it finds already available ingredients + /// + static bool IsKnownRecursively(Recipe recipe, HashSet availableSet, HashSet recursionTree, Dictionary cache) + { + bool v; + if (cache.TryGetValue(recipe, out v)) return v; + + + foreach (int tile in recipe.requiredTile) + { + if (tile == -1) + break; + + List possibleItems; + if (!StorageWorld.TileToCreatingItem.TryGetValue(tile, out possibleItems)) + continue; + + if (!possibleItems.Any(x => IsKnownRecursively_CheckIngredient(x, availableSet, recursionTree, cache))) + { + cache[recipe] = false; + return false; + } + } + + int ingredients = 0; + for (int i = 0; i < Recipe.maxRequirements; i++) + { + var t = recipe.requiredItem[i].type; + if (t <= 0) continue; + ingredients++; + if (IsKnownRecursively_CheckIngredient(t, availableSet, recursionTree, cache)) continue; + if (IsKnownRecursively_CheckAcceptedGroupsForIngredient(recipe, availableSet, recursionTree, cache, t)) continue; + cache[recipe] = false; + return false; + } + + if (ingredients > 0) + { + cache[recipe] = true; + return true; + } + + cache[recipe] = false; + return false; + } + + static bool IsKnownRecursively_CheckAcceptedGroupsForIngredient(Recipe recipe, HashSet availableSet, HashSet recursionTree, Dictionary cache, int t) + { + foreach (var g in recipe.acceptedGroups.Select(j => RecipeGroup.recipeGroups[j])) + { + if (g.ContainsItem(t)) + { + foreach (var groupItemType in g.ValidItems) + { + if (groupItemType != t && IsKnownRecursively_CheckIngredient(groupItemType, availableSet, recursionTree, cache)) + { + return true; + } + } + } + } + return false; + } + + static bool IsKnownRecursively_CheckIngredient(int t, HashSet availableSet, HashSet recursionTree, Dictionary cache) + { + if (availableSet.Contains(t)) return true; + if (!recursionTree.Add(t)) return false; + try + { + List ingredientRecipes; + if (!_productToRecipes.TryGetValue(t, out ingredientRecipes)) return false; + if (ingredientRecipes.Count == 0 || ingredientRecipes.All(x => !IsKnownRecursively(x, availableSet, recursionTree, cache))) return false; + } + finally + { + recursionTree.Remove(t); + } + + return true; + } + + private static void RefreshRecipes(HashSet hiddenRecipes, HashSet craftedRecipes, HashSet favorited) + { + while (true) + { + try + { + SortMode sortMode; + FilterMode filterMode; + HashSet foundItems; + lock (threadLock) + { + threadNeedsRestart = false; + sortMode = threadSortMode; + filterMode = threadFilterMode; + foundItems = threadCheckListFoundItems; + } + + var availableItemsMutable = new HashSet(hiddenRecipes + .Concat(craftedRecipes) + .Concat(foundItems)); + + var notNewItems = new HashSet(availableItemsMutable); + + var temp = new HashSet(); + var tempCache = new Dictionary(); + + var modFilter = searchBar2.Text; + + IEnumerable filteredRecipes = null; + + Action doFiltering = () => + { + filteredRecipes = ItemSorter.GetRecipes(sortMode, filterMode, modFilter, searchBar.Text).Where(x => x != null) + // show only blacklisted recipes only if choice = 2, otherwise show all other + .Where(x => (recipeButtons.Choice == RecipeButtonsBlacklistChoice) == hiddenRecipes.Contains(x.createItem.type)) + // show only new items if selected + .Where(x => (recipeButtons.Choice != RecipeButtonsNewChoice) || !notNewItems.Contains(x.createItem.type)) + // show only favorited items if selected + .Where(x => (recipeButtons.Choice != RecipeButtonsFavoritesChoice) || favorited.Contains(x.createItem.type)) + // hard check if this item can be crafted from available items and their recursive products + .Where(x => !wasItemChecklistRetrieved || IsKnownRecursively(x, availableItemsMutable, temp, tempCache)); + + threadRecipes.Clear(); + threadRecipeAvailable.Clear(); + try + { + threadRecipes.AddRange(filteredRecipes); + threadRecipeAvailable.AddRange(threadRecipes.Select(IsAvailable)); + } + catch (InvalidOperationException) + { + } + catch (KeyNotFoundException) + { + } + }; + + doFiltering(); + + // now if nothing found we disable filters one by one + if (searchBar.Text.Length > 0) + { + if (threadRecipes.Count == 0 && recipeButtons.Choice == RecipeButtonsNewChoice) + { + // search old recipes too + notNewItems = new HashSet(); + doFiltering(); + } + + if (threadRecipes.Count == 0 && hiddenRecipes.Count > 0) + { + // search hidden recipes too + hiddenRecipes = new HashSet(); + doFiltering(); + } + + if (threadRecipes.Count == 0 && filterMode != FilterMode.All) + { + // any category + filterMode = FilterMode.All; + doFiltering(); + } + + if (threadRecipes.Count == 0 && modFilter != "") + { + // search all mods + modFilter = ""; + doFiltering(); + } + } + + lock (recipeLock) + { + nextRecipes = new List(); + nextRecipeAvailable = new List(); + nextRecipes.AddRange(threadRecipes); + nextRecipeAvailable.AddRange(threadRecipeAvailable); + + } + lock (threadLock) + { + if (!threadNeedsRestart) + { + threadRunning = false; + return; + } + } + } + catch (Exception e) { Main.NewTextMultiline(e.ToString()); } + } + } + + private static void AnalyzeIngredients() { Player player = Main.player[Main.myPlayer]; itemCounts.Clear(); @@ -1180,20 +1381,101 @@ private static void HoverRecipe(int slot, ref int hoverSlot) slot += numColumns * (int)Math.Round(scrollBar.ViewPosition); if (slot < recipes.Count) { - if (MouseClicked) - { - selectedRecipe = recipes[slot]; - RefreshStorageItems(); - blockStorageItems.Clear(); - } - hoverSlot = visualSlot; + var recipe = recipes[slot]; + if (MouseClicked) + { + if (Main.keyState.IsKeyDown(Keys.LeftAlt)) + { + if (!ModPlayer.FavoritedRecipes.Add(recipe.createItem)) + ModPlayer.FavoritedRecipes.Remove(recipe.createItem); + } + else if (Main.keyState.IsKeyDown(Keys.LeftControl)) + { + if (recipeButtons.Choice == RecipeButtonsBlacklistChoice) + { + if (ModPlayer.RemoveFromHiddenRecipes(recipe.createItem)) + RefreshItems(); + } + else + { + if (ModPlayer.AddToHiddenRecipes(recipe.createItem)) + RefreshItems(); + } + } + else + SetSelectedRecipe(recipe); + } + else if (RightMouseClicked && (recipe == selectedRecipe || recipeButtons.Choice != RecipeButtonsNewChoice)) + { + if (recipeButtons.Choice == RecipeButtonsNewChoice) + { + ModPlayer.AsKnownRecipes.Add(recipe.createItem); + RefreshItems(); + } + else + ModPlayer.AsKnownRecipes.Remove(recipe.createItem); + } + + hoverSlot = visualSlot; } } - private static void HoverItem(int slot, ref int hoverSlot) - { - hoverSlot = slot; - } + static void SetSelectedRecipe(Recipe recipe) + { + if (recipe != null) ModPlayer.SeenRecipes.Add(recipe.createItem); + selectedRecipe = recipe; + RefreshStorageItems(); + blockStorageItems.Clear(); + } + + private static void HoverHeader(int slot, ref int hoverSlot) + { + hoverSlot = slot; + } + + private static void HoverItem(int slot, ref int hoverSlot) + { + if (selectedRecipe == null) + { + hoverSlot = slot; + return; + } + int visualSlot = slot; + slot += numColumns2 * (int)Math.Round(scrollBar2.ViewPosition); + var count = selectedRecipe.requiredItem.Select((x, i) => new { x, i }).First(x => x.x.type == 0).i + 1; + + if (slot < count) + { + // select ingredient recipe by right clicking + if (RightMouseClicked) + { + var item = selectedRecipe.requiredItem[slot]; + EnsureProductToRecipesInited(); + List itemRecipes; + if (_productToRecipes.TryGetValue(item.type, out itemRecipes)) + { + var knownItems = GetKnownItems(); + + var recursionTree = new HashSet(); + var cache = new Dictionary(); + + Recipe selected = null; + + foreach (var r in itemRecipes.Where(x => IsKnownRecursively(x, knownItems, recursionTree, cache))) + { + if (selected == null) selected = r; + if (IsAvailable(r)) + { + selected = r; + break; + } + } + if (selected != null) SetSelectedRecipe(selected); + } + } + hoverSlot = visualSlot; + } + } private static void HoverStorage(int slot, ref int hoverSlot) { @@ -1201,9 +1483,11 @@ private static void HoverStorage(int slot, ref int hoverSlot) slot += numColumns2 * (int)Math.Round(scrollBar2.ViewPosition); if (slot < storageItems.Count) { - if (MouseClicked) + var item = storageItems[slot]; + item.newAndShiny = false; + if (MouseClicked) { - ItemData data = new ItemData(storageItems[slot]); + ItemData data = new ItemData(item); if (blockStorageItems.Contains(data)) { blockStorageItems.Remove(data); @@ -1224,7 +1508,10 @@ private static void HoverResult(int slot, ref int hoverSlot) return; } - Player player = Main.player[Main.myPlayer]; + if (Main.mouseItem.IsAir && result != null && !result.IsAir) + result.newAndShiny = false; + + Player player = Main.player[Main.myPlayer]; if (MouseClicked) { bool changed = false; @@ -1237,17 +1524,22 @@ private static void HoverResult(int slot, ref int hoverSlot) } else if (Main.mouseItem.IsAir && result != null && !result.IsAir) { - Item toWithdraw = result.Clone(); - if (toWithdraw.stack > toWithdraw.maxStack) - { - toWithdraw.stack = toWithdraw.maxStack; - } - Main.mouseItem = DoWithdrawResult(toWithdraw, ItemSlot.ShiftInUse); - if (ItemSlot.ShiftInUse) - { - Main.mouseItem = player.GetItem(Main.myPlayer, Main.mouseItem, false, true); - } - changed = true; + if (Main.keyState.IsKeyDown(Keys.LeftAlt)) + result.favorited = !result.favorited; + else + { + Item toWithdraw = result.Clone(); + if (toWithdraw.stack > toWithdraw.maxStack) + { + toWithdraw.stack = toWithdraw.maxStack; + } + Main.mouseItem = DoWithdrawResult(toWithdraw, ItemSlot.ShiftInUse); + if (ItemSlot.ShiftInUse) + { + Main.mouseItem = player.GetItem(Main.myPlayer, Main.mouseItem, false, true); + } + changed = true; + } } if (changed) { diff --git a/GUIHelpers.cs b/GUIHelpers.cs new file mode 100644 index 00000000..0510049d --- /dev/null +++ b/GUIHelpers.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework.Graphics; +using Terraria; +using Terraria.Localization; + +namespace MagicStorage +{ + public class GUIHelpers + { + + public static UIButtonChoice MakeSortButtons(Action onChanged) + { + return new UIButtonChoice(onChanged, new Texture2D[] + { + Main.inventorySortTexture[0], + MagicStorage.Instance.GetTexture("SortID"), + MagicStorage.Instance.GetTexture("SortName"), + MagicStorage.Instance.GetTexture("SortNumber"), + MagicStorage.Instance.GetTexture("SortNumber"), + MagicStorage.Instance.GetTexture("SortNumber") + }, + new LocalizedText[] + { + Language.GetText("Mods.MagicStorage.SortDefault"), + Language.GetText("Mods.MagicStorage.SortID"), + Language.GetText("Mods.MagicStorage.SortName"), + Language.GetText("Mods.MagicStorage.SortValue"), + Language.GetText("Mods.MagicStorage.SortStack"), + Language.GetText("Mods.MagicStorage.SortDps"), + }); + } + + public static UIButtonChoice MakeFilterButtons(bool withHistory, Action onChanged) + { + var textures = new List + { + MagicStorage.Instance.GetTexture("FilterAll"), + MagicStorage.Instance.GetTexture("FilterMelee"), + MagicStorage.Instance.GetTexture("FilterRanged"), + MagicStorage.Instance.GetTexture("FilterMagic"), + MagicStorage.Instance.GetTexture("FilterSummon"), + MagicStorage.Instance.GetTexture("FilterThrowing"), + MagicStorage.Instance.GetTexture("FilterThrowing"), + MagicStorage.Instance.GetTexture("FilterPickaxe"), + MagicStorage.Instance.GetTexture("FilterArmor"), + MagicStorage.Instance.GetTexture("FilterArmor"), + MagicStorage.Instance.GetTexture("FilterArmor"), + MagicStorage.Instance.GetTexture("FilterPotion"), + MagicStorage.Instance.GetTexture("FilterTile"), + MagicStorage.Instance.GetTexture("FilterMisc"), + }; + var texts = new List + { + Language.GetText("Mods.MagicStorage.FilterAll"), + Language.GetText("Mods.MagicStorage.FilterWeaponsMelee"), + Language.GetText("Mods.MagicStorage.FilterWeaponsRanged"), + Language.GetText("Mods.MagicStorage.FilterWeaponsMagic"), + Language.GetText("Mods.MagicStorage.FilterWeaponsSummon"), + Language.GetText("Mods.MagicStorage.FilterWeaponsThrown"), + Language.GetText("Mods.MagicStorage.FilterAmmo"), + Language.GetText("Mods.MagicStorage.FilterTools"), + Language.GetText("Mods.MagicStorage.FilterArmor"), + Language.GetText("Mods.MagicStorage.FilterEquips"), + Language.GetText("Mods.MagicStorage.FilterVanity"), + Language.GetText("Mods.MagicStorage.FilterPotions"), + Language.GetText("Mods.MagicStorage.FilterTiles"), + Language.GetText("Mods.MagicStorage.FilterMisc") + }; + if (withHistory) + { + textures.Add(MagicStorage.Instance.GetTexture("FilterAll")); + texts.Add(Language.GetText("Mods.MagicStorage.FilterRecent")); + } + return new UIButtonChoice(onChanged, textures.ToArray(), texts.ToArray()); + } + + } +} diff --git a/ItemTypeOrderedSet.cs b/ItemTypeOrderedSet.cs new file mode 100644 index 00000000..98b9b357 --- /dev/null +++ b/ItemTypeOrderedSet.cs @@ -0,0 +1,112 @@ +using System.Collections.Generic; +using System.Linq; +using Terraria; +using Terraria.ModLoader.IO; + +namespace MagicStorage +{ + public class ItemTypeOrderedSet + { + readonly string _name; + List _items = new List(); + HashSet _set = new HashSet(); + public int Count { get { return _items.Count; } } + + public ItemTypeOrderedSet(string name) + { + _name = name; + } + + public IEnumerable Items { get { return _items; } } + + public bool Add(Item item) + { + return Add(item.type); + } + + public bool Add(int type) + { + var item = new Item(); + item.SetDefaults(type); + if (_set.Add(item.type)) + { + _items.Add(item); + return true; + } + + return false; + } + + public bool Contains(int type) + { + return _set.Contains(type); + } + + public bool Contains(Item item) + { + return _set.Contains(item.type); + } + + public bool Remove(Item item) + { + var type = item.type; + return Remove(type); + } + + public bool Remove(int type) + { + if (_set.Remove(type)) + { + _items.RemoveAll(x => x.type == type); + return true; + } + + return false; + } + + public bool RemoveAt(int index) + { + var item = _items[index]; + if (_set.Remove(item.type)) + { + _items.RemoveAt(index); + return true; + } + + return false; + } + + const string Suffix = "~v2"; + + public void Save(TagCompound c) + { + c.Add(_name + Suffix, _items.Select(x => (int) x.type).ToList()); + } + + public void Load(TagCompound tag) + { + var list = tag.GetList(_name); + if (list != null && list.Count > 0) + _items = list.Select(ItemIO.Load).ToList(); + else + { + var listV2 = tag.GetList(_name + Suffix); + if (listV2 != null) + { + _items = listV2 + .Select(x => + { + var item = new Item(); + item.SetDefaults(x); + item.type = x; + return item; + }).ToList(); + } + else + _items = new List(); + } + + _set = new HashSet(_items.Select(x => x.type)); + } + } +} diff --git a/MagicStorage.cs b/MagicStorage.cs index 9dff4b75..ff9cc64c 100644 --- a/MagicStorage.cs +++ b/MagicStorage.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Reflection; using Terraria; using Terraria.ID; using Terraria.ModLoader; @@ -15,7 +17,7 @@ public class MagicStorage : Mod public static MagicStorage Instance; public static Mod bluemagicMod; public static Mod legendMod; - + public static readonly Version requiredVersion = new Version(0, 9, 2, 2); public override void Load() @@ -28,7 +30,7 @@ public override void Load() InterfaceHelper.Initialize(); legendMod = ModLoader.GetMod("LegendOfTerraria3"); bluemagicMod = ModLoader.GetMod("Bluemagic"); - AddTranslations(); + AddTranslations(); } public override void Unload() @@ -36,8 +38,6 @@ public override void Unload() Instance = null; bluemagicMod = null; legendMod = null; - StorageGUI.Unload(); - CraftingGUI.Unload(); } private void AddTranslations() @@ -57,7 +57,7 @@ private void AddTranslations() AddTranslation(text); text = CreateTranslation("DepositAll"); - text.SetDefault("Deposit All"); + text.SetDefault("Transfer All"); text.AddTranslation(GameCulture.Russian, "Переместить всё"); text.AddTranslation(GameCulture.French, "Déposer tout"); text.AddTranslation(GameCulture.Spanish, "Depositar todo"); @@ -104,12 +104,16 @@ private void AddTranslations() text.AddTranslation(GameCulture.French, "Trier par nom"); text.AddTranslation(GameCulture.Spanish, "Ordenar por nombre"); AddTranslation(text); - - text = CreateTranslation("SortStack"); - text.SetDefault("Sort by Stacks"); - text.AddTranslation(GameCulture.Russian, "Сортировка по стакам"); - text.AddTranslation(GameCulture.French, "Trier par piles"); - text.AddTranslation(GameCulture.Spanish, "Ordenar por pilas"); + + text = CreateTranslation("SortStack"); + text.SetDefault("Sort by Stacks"); + text.AddTranslation(GameCulture.Russian, "Сортировка по стакам"); + text.AddTranslation(GameCulture.French, "Trier par piles"); + text.AddTranslation(GameCulture.Spanish, "Ordenar por pilas"); + AddTranslation(text); + + text = CreateTranslation("SortValue"); + text.SetDefault("Sort by Price"); AddTranslation(text); text = CreateTranslation("FilterAll"); @@ -140,7 +144,40 @@ private void AddTranslations() text.AddTranslation(GameCulture.Spanish, "Filtrar por equipamiento"); AddTranslation(text); - text = CreateTranslation("FilterPotions"); + text = CreateTranslation("FilterWeaponsMelee"); + text.SetDefault("Filter Melee Weapons"); + AddTranslation(text); + + text = CreateTranslation("FilterWeaponsRanged"); + text.SetDefault("Filter Ranged Weapons"); + AddTranslation(text); + + text = CreateTranslation("FilterWeaponsMagic"); + text.SetDefault("Filter Magic Weapons"); + AddTranslation(text); + + text = CreateTranslation("FilterWeaponsSummon"); + text.SetDefault("Filter Summons"); + AddTranslation(text); + + text = CreateTranslation("FilterWeaponsThrown"); + text.SetDefault("Filter Throwing Weapons"); + AddTranslation(text); + + text = CreateTranslation("FilterAmmo"); + text.SetDefault("Filter Ammo"); + AddTranslation(text); + + text = CreateTranslation("FilterArmor"); + text.SetDefault("Filter Armor"); + AddTranslation(text); + + text = CreateTranslation("FilterVanity"); + text.SetDefault("Filter Vanity Items"); + AddTranslation(text); + + + text = CreateTranslation("FilterPotions"); text.SetDefault("Filter Potions"); text.AddTranslation(GameCulture.Russian, "Фильтр (Зелья)"); text.AddTranslation(GameCulture.French, "Filtrer par potions"); @@ -161,6 +198,10 @@ private void AddTranslations() text.AddTranslation(GameCulture.Spanish, "Filtrar por otros"); AddTranslation(text); + text = CreateTranslation("FilterRecent"); + text.SetDefault("Filter New Recently Added Items"); + AddTranslation(text); + text = CreateTranslation("CraftingStations"); text.SetDefault("Crafting Stations"); text.AddTranslation(GameCulture.Russian, "Станции создания"); @@ -194,24 +235,31 @@ private void AddTranslations() AddTranslation(text); text = CreateTranslation("RecipeAvailable"); - text.SetDefault("Show available recipes"); - text.AddTranslation(GameCulture.French, "Afficher les recettes disponibles"); - text.AddTranslation(GameCulture.Spanish, "Mostrar recetas disponibles"); + text.SetDefault("Show new recipes (right click to remove \"new\" flag)"); AddTranslation(text); text = CreateTranslation("RecipeAll"); - text.SetDefault("Show all recipes"); - text.AddTranslation(GameCulture.French, "Afficher toutes les recettes"); - text.AddTranslation(GameCulture.Spanish, "Mostrar todas las recetas"); + text.SetDefault("Show all known recipes"); AddTranslation(text); - } - public override void PostSetupContent() - { - - } + text = CreateTranslation("RecipeBlacklist"); + text.SetDefault("Show hidden recipes (ctrl+click on recipe to (un)hide)"); + AddTranslation(text); + + text = CreateTranslation("SortDps"); + text.SetDefault("Sort by DPS"); + AddTranslation(text); + + text = CreateTranslation("ShowOnlyFavorited"); + text.SetDefault("Only Favorited"); + AddTranslation(text); - public override void AddRecipeGroups() + text = CreateTranslation("DepositTooltip"); + text.SetDefault("Quick Stack - click, Deposit All - ctrl+click, Restock - right click"); + AddTranslation(text); + } + + public override void AddRecipeGroups() { RecipeGroup group = new RecipeGroup(() => Lang.misc[37] + " Chest", ItemID.Chest, @@ -305,3 +353,4 @@ public override void PostUpdateInput() } } + diff --git a/Sorting/BTree.cs b/Sorting/BTree.cs deleted file mode 100644 index b861e95b..00000000 --- a/Sorting/BTree.cs +++ /dev/null @@ -1,298 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Terraria; - -namespace MagicStorage.Sorting -{ - public class BTree - { - private BTreeNode root; - private CompareFunction func; - - public BTree(CompareFunction func) - { - this.root = new BTreeNode(func, true); - this.func = func; - } - - public void Insert(T item) - { - T pushedItem; - BTreeNode pushedBranch; - if (root.Insert(item, out pushedItem, out pushedBranch)) - { - BTreeNode newRoot = new BTreeNode(func, root, pushedItem, pushedBranch); - root = newRoot; - } - } - - public IEnumerable GetSortedItems() - { - return root.GetSortedItems(); - } - } - - class BTreeNode - { - private const int branchFactor = 32; - private CompareFunction func; - private List elements = new List(branchFactor); - private List> branches = new List>(branchFactor + 1); - private bool isLeaf; - - internal BTreeNode(CompareFunction func, bool isLeaf) - { - this.func = func; - this.isLeaf = isLeaf; - } - - internal BTreeNode(CompareFunction func, BTreeNode branch1, T element, BTreeNode branch2) - { - this.func = func; - this.isLeaf = false; - this.branches.Add(branch1); - this.elements.Add(element); - this.branches.Add(branch2); - } - - internal bool Insert(T item, out T pushItem, out BTreeNode pushBranch) - { - if (isLeaf) - { - InsertIntoElements(item); - if (elements.Count == branchFactor) - { - Split(out pushItem, out pushBranch); - return true; - } - pushItem = default(T); - pushBranch = null; - return false; - } - else - { - T pushedItem; - BTreeNode pushedBranch; - int splitBranch = InsertIntoBranch(item, out pushedItem, out pushedBranch); - if (splitBranch >= 0) - { - branches.Insert(splitBranch + 1, pushedBranch); - elements.Insert(splitBranch, pushedItem); - if (elements.Count == branchFactor) - { - Split(out pushItem, out pushBranch); - return true; - } - } - pushItem = default(T); - pushBranch = null; - return false; - } - } - - private int InsertIntoElements(T item) - { - int min = 0; - int max = elements.Count; - while (min < max) - { - int check = (min + max) / 2; - int result = func.Compare(item, elements[check]); - if (result < 0) - { - max = check; - } - else if (result > 0) - { - min = check + 1; - } - else if (item is Item) - { - result = ItemData.Compare((Item)(object)item, (Item)(object)elements[check]); - if (result < 0) - { - max = check; - } - else if (result > 0) - { - min = check + 1; - } - else - { - ((Item)(object)elements[check]).stack += ((Item)(object)item).stack; - return -1; - } - } - else - { - min = check + 1; - } - } - elements.Insert(min, item is Item ? (T)(object)((Item)(object)item).Clone() : item); - return min; - } - - private int InsertIntoBranch(T item, out T pushItem, out BTreeNode pushNode) - { - int min = 0; - int max = elements.Count; - while (min < max) - { - int check = (min + max) / 2; - int result = func.Compare(item, elements[check]); - if (result < 0) - { - max = check; - } - else if (result > 0) - { - min = check + 1; - } - else if (item is Item) - { - result = ItemData.Compare((Item)(object)item, (Item)(object)elements[check]); - if (result < 0) - { - max = check; - } - else if (result > 0) - { - min = check + 1; - } - else - { - ((Item)(object)elements[check]).stack += ((Item)(object)item).stack; - pushItem = default(T); - pushNode = null; - return -1; - } - } - else - { - min = check + 1; - } - } - if (branches[min].Insert(item, out pushItem, out pushNode)) - { - return min; - } - return -1; - } - - private void Split(out T pushItem, out BTreeNode pushBranch) - { - BTreeNode newNeighbor = new BTreeNode(func, isLeaf); - newNeighbor.elements.AddRange(elements.GetRange(branchFactor / 2 + 1, branchFactor / 2 - 1)); - pushItem = elements[branchFactor / 2]; - elements.RemoveRange(branchFactor / 2, branchFactor / 2); - if (!isLeaf) - { - newNeighbor.branches.AddRange(branches.GetRange(branchFactor / 2 + 1, branchFactor / 2)); - branches.RemoveRange(branchFactor / 2 + 1, branchFactor / 2); - } - pushBranch = newNeighbor; - } - - internal IEnumerable GetSortedItems() - { - if (isLeaf) - { - return elements; - } - else - { - return elements.SelectMany((element, index) => new AppendEnumerable(branches[index].GetSortedItems(), element)).Concat(branches[elements.Count].GetSortedItems()); - } - } - } - - public class AppendEnumerable : IEnumerable - { - private IEnumerable enumerable; - private T element; - - public AppendEnumerable(IEnumerable enumerable, T element) - { - this.enumerable = enumerable; - this.element = element; - } - - public IEnumerator GetEnumerator() - { - return new AppendEnumerator(enumerable, element); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } - - public class AppendEnumerator : IEnumerator - { - private IEnumerator enumerator; - private T element; - private bool enumeratorFinished; - private bool finished; - - public AppendEnumerator(IEnumerable enumerable, T element) - { - this.enumerator = enumerable.GetEnumerator(); - this.element = element; - this.finished = false; - } - - public T Current - { - get - { - if (!enumeratorFinished) - { - return enumerator.Current; - } - if (!finished) - { - return element; - } - throw new InvalidOperationException(); - } - } - - object IEnumerator.Current - { - get - { - return Current; - } - } - - public bool MoveNext() - { - if (!enumerator.MoveNext()) - { - if (enumeratorFinished) - { - finished = true; - return false; - } - enumeratorFinished = true; - return true; - } - return true; - } - - public void Reset() - { - enumerator.Reset(); - finished = false; - enumeratorFinished = false; - } - - public void Dispose() - { - enumerator.Dispose(); - } - } -} \ No newline at end of file diff --git a/Sorting/CompareFunction.cs b/Sorting/CompareFunction.cs index 478543de..48b9f628 100644 --- a/Sorting/CompareFunction.cs +++ b/Sorting/CompareFunction.cs @@ -1,10 +1,11 @@ using System; using System.Collections.Generic; using Terraria; +using Terraria.ModLoader; namespace MagicStorage.Sorting { - public abstract class CompareFunction + public abstract class CompareFunction : IComparer { public abstract int Compare(Item item1, Item item2); @@ -45,4 +46,48 @@ public override int Compare(Item item1, Item item2) return (int)Math.Ceiling((float)item2.stack / (float)item2.maxStack) - (int)Math.Ceiling((float)item1.stack / (float)item1.maxStack); } } -} \ No newline at end of file + + public class CompareValue : CompareFunction + { + public override int Compare(Item item1, Item item2) + { + return item1.value - item2.value; + } + } + + public class CompareDps : CompareFunction + { + public override int Compare(Item item1, Item item2) + { + return (int)((GetDps(item1) - GetDps(item2)) * 100); + } + + public static float GetDps(Item item) + { + if (item.damage <= 0) return 0f; + int defence; + if (NPC.downedMoonlord) + defence = 50; + else if (NPC.downedAncientCultist) + defence = 43; + else if (NPC.downedGolemBoss) + defence = 38; + else if (NPC.downedPlantBoss) + defence = 32; + else if (NPC.downedMechBossAny) + defence = 26; + else if (Main.hardMode) + defence = 22; + else if (NPC.downedBoss3) + defence = 16; + else if (NPC.downedBoss2) + defence = 14; + else if (NPC.downedBoss1) + defence = 10; + else + defence = 8; + + return Math.Max(item.damage - defence * 0.5f, 1) / Math.Max((item.useTime + item.reuseDelay) / 60f, 0.001f) * (1f + item.crit / 100f); + } + } +} diff --git a/Sorting/DefaultSorting.cs b/Sorting/DefaultSorting.cs index 049a1ab2..80ed29fc 100644 --- a/Sorting/DefaultSorting.cs +++ b/Sorting/DefaultSorting.cs @@ -56,13 +56,13 @@ public static void Initialize() { return; } - classes.Add(new DefaultSortClass(MeleeWeapon, CompareRarity)); - classes.Add(new DefaultSortClass(RangedWeapon, CompareRarity)); - classes.Add(new DefaultSortClass(MagicWeapon, CompareRarity)); - classes.Add(new DefaultSortClass(SummonWeapon, CompareRarity)); - classes.Add(new DefaultSortClass(ThrownWeapon, CompareRarity)); - classes.Add(new DefaultSortClass(Weapon, CompareRarity)); - classes.Add(new DefaultSortClass(Ammo, CompareRarity)); + classes.Add(new DefaultSortClass(MeleeWeapon, CompareDps)); + classes.Add(new DefaultSortClass(RangedWeapon, CompareDps)); + classes.Add(new DefaultSortClass(MagicWeapon, CompareDps)); + classes.Add(new DefaultSortClass(SummonWeapon, CompareValue)); + classes.Add(new DefaultSortClass(ThrownWeapon, CompareDps)); + classes.Add(new DefaultSortClass(Weapon, CompareDps)); + classes.Add(new DefaultSortClass(Ammo, CompareValue)); classes.Add(new DefaultSortClass(Picksaw, ComparePicksaw)); classes.Add(new DefaultSortClass(Hamaxe, CompareHamaxe)); classes.Add(new DefaultSortClass(Pickaxe, ComparePickaxe)); @@ -185,32 +185,32 @@ private static bool Grapple(Item item) return Main.projHook[item.shoot]; } - private static bool Mount(Item item) + public static bool Mount(Item item) { return item.mountType != -1 && !MountID.Sets.Cart[item.mountType]; } - private static bool Cart(Item item) + public static bool Cart(Item item) { return item.mountType != -1 && MountID.Sets.Cart[item.mountType]; } - private static bool LightPet(Item item) + public static bool LightPet(Item item) { return item.buffType > 0 && Main.lightPet[item.buffType]; } - private static bool VanityPet(Item item) + public static bool VanityPet(Item item) { return item.buffType > 0 && Main.vanityPet[item.buffType]; } - private static bool Dye(Item item) + public static bool Dye(Item item) { return item.dye > 0; } - private static bool HairDye(Item item) + public static bool HairDye(Item item) { return item.hairDye >= 0; } @@ -235,7 +235,7 @@ private static bool BuffPotion(Item item) return item.consumable && item.buffType > 0; } - private static bool BossSpawn(Item item) + public static bool BossSpawn(Item item) { return ItemID.Sets.SortingPriorityBossSpawns[item.type] >= 0; } @@ -282,10 +282,23 @@ private static bool CommonTile(Item item) private static int CompareRarity(Item item1, Item item2) { - return item2.rare - item1.rare; + return item1.rare - item2.rare; } - private static int ComparePicksaw(Item item1, Item item2) + private static int CompareValue(Item item1, Item item2) + { + return item1.value - item2.value; + } + + static readonly CompareDps _dps = new Sorting.CompareDps(); + + private static int CompareDps(Item item1, Item item2) + { + int r = _dps.Compare(item1, item2); + return r != 0 ? r : CompareValue(item1, item2); + } + + private static int ComparePicksaw(Item item1, Item item2) { int result = item1.pick - item2.pick; if (result == 0) @@ -330,7 +343,7 @@ private static int CompareAccessory(Item item1, Item item2) int result = item1.vanity.CompareTo(item2.vanity); if (result == 0) { - result = CompareRarity(item1, item2); + result = CompareValue(item1, item2); } return result; } @@ -415,7 +428,7 @@ private static int CompareExtractible(Item item1, Item item2) return ItemID.Sets.SortingPriorityExtractibles[item2.type] - ItemID.Sets.SortingPriorityExtractibles[item1.type]; } - private static int CompareMisc(Item item1, Item item2) + public static int CompareMisc(Item item1, Item item2) { int result = CompareRarity(item1, item2); if (result == 0) @@ -452,4 +465,4 @@ public int Compare(Item item1, Item item2) return compareFunc(item1, item2); } } -} \ No newline at end of file +} diff --git a/Sorting/FilterMode.cs b/Sorting/FilterMode.cs index 93cb978e..842a217c 100644 --- a/Sorting/FilterMode.cs +++ b/Sorting/FilterMode.cs @@ -4,12 +4,20 @@ namespace MagicStorage.Sorting { public enum FilterMode { - All, - Weapons, - Tools, + All = 0, + WeaponsMelee, + WeaponsRanged, + WeaponsMagic, + WeaponsSummon, + WeaponsThrown, + Ammo, + Tools, + Armor, Equipment, - Potions, + Vanity, + Potions, Placeables, - Misc + Misc, + Recent } -} \ No newline at end of file +} diff --git a/Sorting/ItemFilter.cs b/Sorting/ItemFilter.cs index 000237f2..889d3514 100644 --- a/Sorting/ItemFilter.cs +++ b/Sorting/ItemFilter.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using MagicStorage.Components; using Terraria; +using Terraria.ID; +using Terraria.UI; namespace MagicStorage.Sorting { @@ -30,43 +33,82 @@ public override bool Passes(Item item) } } - public class FilterMelee : ItemFilter + public class FilterWeaponMelee : ItemFilter { public override bool Passes(Item item) { - return item.melee && item.pick == 0 && item.axe == 0 && item.hammer == 0; + return (item.melee || (item.thrown && !item.consumable)) && item.pick == 0 && item.axe == 0 && item.hammer == 0 && item.damage > 0; } } - public class FilterRanged : ItemFilter + public class FilterWeaponRanged : ItemFilter { + readonly FilterWeaponThrown _thrown = new FilterWeaponThrown(); + public override bool Passes(Item item) { - return item.ranged; + return item.ranged && item.damage > 0 && item.ammo <= 0 && !_thrown.Passes(item); } } - public class FilterMagic : ItemFilter + public class FilterWeaponMagic : ItemFilter { public override bool Passes(Item item) { - return item.magic; + return (item.magic || item.mana > 0) && !item.summon && !item.consumable; } } - public class FilterSummon : ItemFilter + public class FilterWeaponSummon : ItemFilter { public override bool Passes(Item item) { - return item.summon; + switch (item.type) + { + case 109:// mana or heart crystal + case 29: + case ItemID.CellPhone: + case ItemID.PDA: + case ItemID.MagicMirror: + case ItemID.IceMirror: + return false; + } + + return item.summon || SortClassList.BossSpawn(item) || SortClassList.Cart(item) || SortClassList.LightPet(item) || SortClassList.Mount(item) || item.sentry; } } - public class FilterThrown : ItemFilter + public class FilterWeaponThrown : ItemFilter { public override bool Passes(Item item) { - return item.thrown; + switch (item.type) + { + case 167: // dynamite + case 3547: + case 2896: + case 166: // bomb + case 235: + case 3115: + return true; + } + return (item.thrown && item.damage > 0) || (item.consumable && item.Name.ToLowerInvariant().EndsWith(" coating")); + } + } + + public class FilterAmmo : ItemFilter + { + public override bool Passes(Item item) + { + return item.ammo > 0 && item.damage > 0 && item.ammo != AmmoID.Coin; + } + } + + public class FilterVanity : ItemFilter + { + public override bool Passes(Item item) + { + return item.vanity || SortClassList.Dye(item) || SortClassList.HairDye(item) || SortClassList.VanityPet(item); } } @@ -81,9 +123,9 @@ public override bool Passes(Item item) public class FilterWeapon : ItemFilter { public override bool Passes(Item item) - { - return item.damage > 0 && item.pick == 0 && item.axe == 0 && item.hammer == 0; - } + { + return !(item.consumable && item.thrown) && (item.damage > 0 || (item.magic && item.healLife > 0 && item.mana > 0)) && item.pick == 0 && item.axe == 0 && item.hammer == 0; + } } public class FilterPickaxe : ItemFilter @@ -118,11 +160,19 @@ public override bool Passes(Item item) } } + public class FilterArmor : ItemFilter + { + public override bool Passes(Item item) + { + return !item.vanity && (item.headSlot >= 0 || item.bodySlot >= 0 || item.legSlot >= 0); + } + } + public class FilterEquipment : ItemFilter { public override bool Passes(Item item) { - return item.headSlot >= 0 || item.bodySlot >= 0 || item.legSlot >= 0 || item.accessory || Main.projHook[item.shoot] || item.mountType >= 0 || (item.buffType > 0 && (Main.lightPet[item.buffType] || Main.vanityPet[item.buffType])); + return !item.vanity && (item.accessory || Main.projHook[item.shoot] || item.mountType >= 0 || (item.buffType > 0 && (Main.lightPet[item.buffType] || Main.vanityPet[item.buffType]))); } } @@ -130,7 +180,7 @@ public class FilterPotion : ItemFilter { public override bool Passes(Item item) { - return item.consumable && (item.healLife > 0 || item.healMana > 0 || item.buffType > 0); + return item.consumable && (item.healLife > 0 || item.healMana > 0 || item.buffType > 0 || item.potion || item.Name.ToLowerInvariant().Contains("potion") || item.Name.ToLowerInvariant().Contains("elixir")); } } @@ -145,8 +195,16 @@ public override bool Passes(Item item) public class FilterMisc : ItemFilter { private static List blacklist = new List { - new FilterWeapon(), + new FilterWeaponMelee(), + new FilterWeaponRanged(), + new FilterWeaponMagic(), + new FilterWeaponSummon(), + new FilterWeaponThrown(), + new FilterAmmo(), + new FilterWeaponThrown(), + new FilterVanity(), new FilterTool(), + new FilterArmor(), new FilterEquipment(), new FilterPotion(), new FilterPlaceable() @@ -164,4 +222,4 @@ public override bool Passes(Item item) return true; } } -} \ No newline at end of file +} diff --git a/Sorting/ItemSorter.cs b/Sorting/ItemSorter.cs index 9ce16eea..e63421d2 100644 --- a/Sorting/ItemSorter.cs +++ b/Sorting/ItemSorter.cs @@ -7,138 +7,129 @@ namespace MagicStorage.Sorting { public static class ItemSorter { - public static IEnumerable SortAndFilter(IEnumerable items, SortMode sortMode, FilterMode filterMode, string modFilter, string nameFilter) + public static IEnumerable SortAndFilter(IEnumerable items, SortMode sortMode, FilterMode filterMode, string modFilter, string nameFilter, int? takeCount = null) { - ItemFilter filter; - switch (filterMode) - { - case FilterMode.All: - filter = new FilterAll(); - break; - case FilterMode.Weapons: - filter = new FilterWeapon(); - break; - case FilterMode.Tools: - filter = new FilterTool(); - break; - case FilterMode.Equipment: - filter = new FilterEquipment(); - break; - case FilterMode.Potions: - filter = new FilterPotion(); - break; - case FilterMode.Placeables: - filter = new FilterPlaceable(); - break; - case FilterMode.Misc: - filter = new FilterMisc(); - break; - default: - filter = new FilterAll(); - break; - } - IEnumerable filteredItems = items.Where((item) => filter.Passes(item) && FilterName(item, modFilter, nameFilter)); - CompareFunction func; - switch (sortMode) - { - case SortMode.Default: - func = new CompareDefault(); - break; - case SortMode.Id: - func = new CompareID(); - break; - case SortMode.Name: - func = new CompareName(); - break; - case SortMode.Quantity: - func = new CompareID(); - break; - default: - return filteredItems; - } - BTree sortedTree = new BTree(func); - foreach (Item item in filteredItems) - { - sortedTree.Insert(item); - } - if (sortMode == SortMode.Quantity) - { - BTree oldTree = sortedTree; - sortedTree = new BTree(new CompareQuantity()); - foreach (Item item in oldTree.GetSortedItems()) - { - sortedTree.Insert(item); - } - } - return sortedTree.GetSortedItems(); + ItemFilter filter = MakeFilter(filterMode); + IEnumerable filteredItems = items.Where((item) => filter.Passes(item) && FilterName(item, modFilter, nameFilter)); + if (takeCount != null) filteredItems = filteredItems.Take(takeCount.Value); + var func = MakeSortFunction(sortMode); + if (func == null) return filteredItems; + return filteredItems.OrderBy(x => x, func).ThenBy(x => x.type).ThenBy(x => x.value); } public static IEnumerable GetRecipes(SortMode sortMode, FilterMode filterMode, string modFilter, string nameFilter) { - ItemFilter filter; - switch (filterMode) - { - case FilterMode.All: - filter = new FilterAll(); - break; - case FilterMode.Weapons: - filter = new FilterWeapon(); - break; - case FilterMode.Tools: - filter = new FilterTool(); - break; - case FilterMode.Equipment: - filter = new FilterEquipment(); - break; - case FilterMode.Potions: - filter = new FilterPotion(); - break; - case FilterMode.Placeables: - filter = new FilterPlaceable(); - break; - case FilterMode.Misc: - filter = new FilterMisc(); - break; - default: - filter = new FilterAll(); - break; - } - IEnumerable filteredRecipes = Main.recipe.Where((recipe, index) => index < Recipe.numRecipes && filter.Passes(recipe) && FilterName(recipe.createItem, modFilter, nameFilter)); - CompareFunction func; - switch (sortMode) - { - case SortMode.Default: - func = new CompareDefault(); - break; - case SortMode.Id: - func = new CompareID(); - break; - case SortMode.Name: - func = new CompareName(); - break; - default: - return filteredRecipes; - } - BTree sortedTree = new BTree(func); - foreach (Recipe recipe in filteredRecipes) - { - sortedTree.Insert(recipe); - if (CraftingGUI.threadNeedsRestart) - { - return new List(); - } - } - return sortedTree.GetSortedItems(); + var filter = MakeFilter(filterMode); + IEnumerable filteredRecipes = Main.recipe.Where((recipe, index) => index < Recipe.numRecipes && filter.Passes(recipe) && FilterName(recipe.createItem, modFilter, nameFilter)); + var func = MakeSortFunction(sortMode); + if (func == null) return filteredRecipes; + return filteredRecipes.OrderBy(x => x.createItem, func).ThenBy(x => x.createItem.type).ThenBy(x => x.createItem.value); } - private static bool FilterName(Item item, string modFilter, string filter) - { - string modName = "Terraria"; - if (item.modItem != null) - { - modName = item.modItem.mod.DisplayName; - } - return modName.ToLowerInvariant().IndexOf(modFilter.ToLowerInvariant()) >= 0 && item.Name.ToLowerInvariant().IndexOf(filter.ToLowerInvariant()) >= 0; - } + static CompareFunction MakeSortFunction(SortMode sortMode) + { + CompareFunction func; + switch (sortMode) + { + case SortMode.Default: + func = new CompareDefault(); + break; + case SortMode.Id: + func = new CompareID(); + break; + case SortMode.Name: + func = new CompareName(); + break; + case SortMode.Value: + func = new CompareValue(); + break; + case SortMode.Quantity: + func = new CompareQuantity(); + break; + case SortMode.Dps: + func = new CompareDps(); + break; + default: + func = null; + break; + } + + return func; + } + + static ItemFilter MakeFilter(FilterMode filterMode) + { + ItemFilter filter; + switch (filterMode) + { + case FilterMode.All: + filter = new FilterAll(); + break; + case FilterMode.WeaponsMelee: + filter = new FilterWeaponMelee(); + break; + case FilterMode.WeaponsRanged: + filter = new FilterWeaponRanged(); + break; + case FilterMode.WeaponsMagic: + filter = new FilterWeaponMagic(); + break; + case FilterMode.WeaponsSummon: + filter = new FilterWeaponSummon(); + break; + case FilterMode.Ammo: + filter = new FilterAmmo(); + break; + case FilterMode.WeaponsThrown: + filter = new FilterWeaponThrown(); + break; + case FilterMode.Tools: + filter = new FilterTool(); + break; + case FilterMode.Armor: + filter = new FilterArmor(); + break; + case FilterMode.Vanity: + filter = new FilterVanity(); + break; + case FilterMode.Equipment: + filter = new FilterEquipment(); + break; + case FilterMode.Potions: + filter = new FilterPotion(); + break; + case FilterMode.Placeables: + filter = new FilterPlaceable(); + break; + case FilterMode.Misc: + filter = new FilterMisc(); + break; + case FilterMode.Recent: + throw new NotSupportedException(); + default: + filter = new FilterAll(); + break; + } + + return filter; + } + + + static bool FilterName(Item item, string filter) + { + if (filter.Trim().Length == 0) filter = string.Empty; + return item.Name.ToLowerInvariant().IndexOf(filter.Trim().ToLowerInvariant()) >= 0; + } + + private static bool FilterName(Item item, string modFilter, string filter) + { + string modName = "Terraria"; + if (item.modItem != null) + { + modName = item.modItem.mod.DisplayName; + } + return modName.ToLowerInvariant().IndexOf(modFilter.ToLowerInvariant()) >= 0 && item.Name.ToLowerInvariant().IndexOf(filter.ToLowerInvariant()) >= 0; + } } } + diff --git a/Sorting/SortMode.cs b/Sorting/SortMode.cs index 3f222aa8..d9212ce2 100644 --- a/Sorting/SortMode.cs +++ b/Sorting/SortMode.cs @@ -7,6 +7,9 @@ public enum SortMode Default, Id, Name, - Quantity + Value, + Quantity, + Dps, + AsIs } -} \ No newline at end of file +} diff --git a/StorageGUI.cs b/StorageGUI.cs index 8896ad12..a67afdfc 100644 --- a/StorageGUI.cs +++ b/StorageGUI.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; @@ -30,21 +31,22 @@ public static bool MouseClicked } } - private static UIPanel basePanel; + private static UIPanel basePanel = new UIPanel(); private static float panelTop; private static float panelLeft; private static float panelWidth; private static float panelHeight; - private static UIElement topBar; + private static UIElement topBar = new UIElement(); internal static UISearchBar searchBar; private static UIButtonChoice sortButtons; internal static UITextPanel depositButton; - private static UIElement topBar2; + internal static UITextPanel restockButton; + private static UIElement topBar2 = new UIElement(); private static UIButtonChoice filterButtons; - internal static UISearchBar searchBar2; - - private static UISlotZone slotZone = new UISlotZone(HoverItemSlot, GetItem, inventoryScale); + internal static UISearchBar searchBar2; + + private static UISlotZone slotZone = new UISlotZone(HoverItemSlot, GetItem, inventoryScale); private static int slotFocus = -1; private static int rightClickTimer = 0; private const int startMaxRightClickTimer = 20; @@ -64,7 +66,7 @@ public static bool MouseClicked private static UIElement bottomBar = new UIElement(); private static UIText capacityText; - + public static void Initialize() { InitLangStuff(); @@ -73,7 +75,6 @@ public static void Initialize() panelTop = Main.instance.invBottom + 60; panelLeft = 20f; - basePanel = new UIPanel(); float innerPanelLeft = panelLeft + basePanel.PaddingLeft; float innerPanelWidth = numColumns * (itemSlotWidth + padding) + 20f + padding; panelWidth = basePanel.PaddingLeft + innerPanelWidth + basePanel.PaddingRight; @@ -84,7 +85,6 @@ public static void Initialize() basePanel.Height.Set(panelHeight, 0f); basePanel.Recalculate(); - topBar = new UIElement(); topBar.Width.Set(0f, 1f); topBar.Height.Set(32f, 0f); basePanel.Append(topBar); @@ -92,31 +92,36 @@ public static void Initialize() InitSortButtons(); topBar.Append(sortButtons); - depositButton.Left.Set(sortButtons.GetDimensions().Width + 2 * padding, 0f); + var x = sortButtons.GetDimensions().Width + 2 * padding; + + depositButton.Left.Set(x, 0f); depositButton.Width.Set(128f, 0f); depositButton.Height.Set(-2 * padding, 1f); depositButton.PaddingTop = 8f; depositButton.PaddingBottom = 8f; topBar.Append(depositButton); - float depositButtonRight = sortButtons.GetDimensions().Width + 2 * padding + depositButton.GetDimensions().Width; + x += depositButton.GetDimensions().Width; + + float depositButtonRight = x; searchBar.Left.Set(depositButtonRight + padding, 0f); searchBar.Width.Set(-depositButtonRight - 2 * padding, 1f); searchBar.Height.Set(0f, 1f); topBar.Append(searchBar); - topBar2 = new UIElement(); topBar2.Width.Set(0f, 1f); topBar2.Height.Set(32f, 0f); topBar2.Top.Set(36f, 0f); basePanel.Append(topBar2); InitFilterButtons(); - topBar2.Append(filterButtons); - searchBar2.Left.Set(depositButtonRight + padding, 0f); - searchBar2.Width.Set(-depositButtonRight - 2 * padding, 1f); - searchBar2.Height.Set(0f, 1f); - topBar2.Append(searchBar2); + + float filterButtonsRight = filterButtons.GetDimensions().Width + padding; + topBar2.Append(filterButtons); + searchBar2.Left.Set(filterButtonsRight + padding, 0f); + searchBar2.Width.Set(-filterButtonsRight - 2 * padding, 1f); + searchBar2.Height.Set(0f, 1f); + topBar2.Append(searchBar2); slotZone.Width.Set(0f, 1f); slotZone.Top.Set(76f, 0f); @@ -161,7 +166,8 @@ public static void Initialize() } capacityText.SetText(numItems + "/" + capacity + " Items"); bottomBar.Append(capacityText); - } + + } private static void InitLangStuff() { @@ -171,73 +177,35 @@ private static void InitLangStuff() } if (searchBar == null) { - searchBar = new UISearchBar(Language.GetText("Mods.MagicStorage.SearchName")); - } - if (searchBar2 == null) - { - searchBar2 = new UISearchBar(Language.GetText("Mods.MagicStorage.SearchMod")); + searchBar = new UISearchBar(Language.GetText("Mods.MagicStorage.SearchName"), RefreshItems); } + if (searchBar2 == null) + { + searchBar2 = new UISearchBar(Language.GetText("Mods.MagicStorage.SearchMod"), RefreshItems); + } if (capacityText == null) { capacityText = new UIText("Items"); } } - internal static void Unload() - { - sortButtons = null; - filterButtons = null; - } - private static void InitSortButtons() { if (sortButtons == null) { - sortButtons = new UIButtonChoice(new Texture2D[] - { - Main.inventorySortTexture[0], - MagicStorage.Instance.GetTexture("SortID"), - MagicStorage.Instance.GetTexture("SortName"), - MagicStorage.Instance.GetTexture("SortNumber") - }, - new LocalizedText[] - { - Language.GetText("Mods.MagicStorage.SortDefault"), - Language.GetText("Mods.MagicStorage.SortID"), - Language.GetText("Mods.MagicStorage.SortName"), - Language.GetText("Mods.MagicStorage.SortStack") - }); + sortButtons = GUIHelpers.MakeSortButtons(RefreshItems); } } - private static void InitFilterButtons() + private static void InitFilterButtons() { if (filterButtons == null) { - filterButtons = new UIButtonChoice(new Texture2D[] - { - MagicStorage.Instance.GetTexture("FilterAll"), - MagicStorage.Instance.GetTexture("FilterMelee"), - MagicStorage.Instance.GetTexture("FilterPickaxe"), - MagicStorage.Instance.GetTexture("FilterArmor"), - MagicStorage.Instance.GetTexture("FilterPotion"), - MagicStorage.Instance.GetTexture("FilterTile"), - MagicStorage.Instance.GetTexture("FilterMisc"), - }, - new LocalizedText[] - { - Language.GetText("Mods.MagicStorage.FilterAll"), - Language.GetText("Mods.MagicStorage.FilterWeapons"), - Language.GetText("Mods.MagicStorage.FilterTools"), - Language.GetText("Mods.MagicStorage.FilterEquips"), - Language.GetText("Mods.MagicStorage.FilterPotions"), - Language.GetText("Mods.MagicStorage.FilterTiles"), - Language.GetText("Mods.MagicStorage.FilterMisc") - }); + filterButtons = GUIHelpers.MakeFilterButtons(true, RefreshItems); } } - public static void Update(GameTime gameTime) + public static void Update(GameTime gameTime) { oldMouse = curMouse; curMouse = Mouse.GetState(); @@ -255,7 +223,6 @@ public static void Update(GameTime gameTime) else { scrollBarFocus = false; - scrollBar.ViewPosition = 0f; ResetSlotFocus(); } } @@ -275,6 +242,7 @@ public static void Draw(TEStorageHeart heart) slotZone.DrawText(); sortButtons.DrawText(); filterButtons.DrawText(); + DrawDepositButton(); } private static Item GetItem(int slot, ref int context) @@ -335,78 +303,74 @@ private static TEStorageHeart GetHeart() return modPlayer.GetStorageHeart(); } - public static void RefreshItems() - { - if (StoragePlayer.IsStorageCrafting()) - { - CraftingGUI.RefreshItems(); - return; - } - items.Clear(); - didMatCheck.Clear(); - TEStorageHeart heart = GetHeart(); - if (heart == null) - { - return; - } - InitLangStuff(); - InitSortButtons(); - InitFilterButtons(); - SortMode sortMode; - switch (sortButtons.Choice) - { - case 0: - sortMode = SortMode.Default; - break; - case 1: - sortMode = SortMode.Id; - break; - case 2: - sortMode = SortMode.Name; - break; - case 3: - sortMode = SortMode.Quantity; - break; - default: - sortMode = SortMode.Default; - break; - } - FilterMode filterMode; - switch (filterButtons.Choice) - { - case 0: - filterMode = FilterMode.All; - break; - case 1: - filterMode = FilterMode.Weapons; - break; - case 2: - filterMode = FilterMode.Tools; - break; - case 3: - filterMode = FilterMode.Equipment; - break; - case 4: - filterMode = FilterMode.Potions; - break; - case 5: - filterMode = FilterMode.Placeables; - break; - case 6: - filterMode = FilterMode.Misc; - break; - default: - filterMode = FilterMode.All; - break; - } - items.AddRange(ItemSorter.SortAndFilter(heart.GetStoredItems(), sortMode, filterMode, searchBar2.Text, searchBar.Text)); - for (int k = 0; k < items.Count; k++) - { - didMatCheck.Add(false); - } - } - - private static void UpdateDepositButton() + public static void RefreshItems() + { + if (StoragePlayer.IsStorageCrafting()) + { + CraftingGUI.RefreshItems(); + return; + } + + items.Clear(); + didMatCheck.Clear(); + TEStorageHeart heart = GetHeart(); + if (heart == null) + { + return; + } + + InitLangStuff(); + InitSortButtons(); + InitFilterButtons(); + SortMode sortMode = (SortMode) sortButtons.Choice; + + FilterMode filterMode = (FilterMode) filterButtons.Choice; + var modFilter = searchBar2.Text; + + Action doFiltering = () => + { + IEnumerable itemsLocal; + if (filterMode == FilterMode.Recent) + { + var stored = heart.GetStoredItems().GroupBy(x => x.type).ToDictionary(x => x.Key, x => x.First()); + + var toFilter = heart.UniqueItemsPutHistory.Reverse().Where(x => stored.ContainsKey(x.type)).Select(x => stored[x.type]); + itemsLocal = ItemSorter.SortAndFilter(toFilter, sortMode == SortMode.Default ? SortMode.AsIs : sortMode, + FilterMode.All, modFilter, searchBar.Text, 100); + } + else + itemsLocal = ItemSorter.SortAndFilter(heart.GetStoredItems(), sortMode, filterMode, modFilter, searchBar.Text); + + items.AddRange(itemsLocal); + }; + + doFiltering(); + + // now if nothing found we disable filters one by one + if (searchBar.Text.Trim().Length > 0) + { + if (items.Count == 0 && filterMode != FilterMode.All) + { + // search all categories + filterMode = FilterMode.All; + doFiltering(); + } + + if (items.Count == 0 && modFilter != "") + { + // search all mods + modFilter = ""; + doFiltering(); + } + } + + for (int k = 0; k < items.Count; k++) + { + didMatCheck.Add(false); + } + } + + private static void UpdateDepositButton() { Rectangle dim = InterfaceHelper.GetFullRectangle(depositButton); if (curMouse.X > dim.X && curMouse.X < dim.X + dim.Width && curMouse.Y > dim.Y && curMouse.Y < dim.Y + dim.Height) @@ -414,18 +378,35 @@ private static void UpdateDepositButton() depositButton.BackgroundColor = new Color(73, 94, 171); if (MouseClicked) { - if (TryDepositAll()) + if (TryDepositAll(!Main.keyState.IsKeyDown(Keys.LeftControl) && !Main.keyState.IsKeyDown(Keys.RightControl))) { RefreshItems(); Main.PlaySound(7, -1, -1, 1); } } + else if (CraftingGUI.RightMouseClicked) + { + if (TryRestock()) + { + RefreshItems(); + Main.PlaySound(7, -1, -1, 1); + } + } } else { depositButton.BackgroundColor = new Color(63, 82, 151) * 0.7f; } } + + private static void DrawDepositButton() + { + Rectangle dim = InterfaceHelper.GetFullRectangle(depositButton); + if (curMouse.X > dim.X && curMouse.X < dim.X + dim.Width && curMouse.Y > dim.Y && curMouse.Y < dim.Y + dim.Height) + { + Main.instance.MouseText(Language.GetText("Mods.MagicStorage.DepositTooltip").Value); + } + } private static void ResetSlotFocus() { @@ -439,7 +420,8 @@ private static void HoverItemSlot(int slot, ref int hoverSlot) Player player = Main.player[Main.myPlayer]; int visualSlot = slot; slot += numColumns * (int)Math.Round(scrollBar.ViewPosition); - if (MouseClicked) + + if (MouseClicked) { bool changed = false; if (!Main.mouseItem.IsAir && (player.itemAnimation == 0 && player.itemTime == 0)) @@ -451,17 +433,17 @@ private static void HoverItemSlot(int slot, ref int hoverSlot) } else if (Main.mouseItem.IsAir && slot < items.Count && !items[slot].IsAir) { - Item toWithdraw = items[slot].Clone(); - if (toWithdraw.stack > toWithdraw.maxStack) - { - toWithdraw.stack = toWithdraw.maxStack; - } - Main.mouseItem = DoWithdraw(toWithdraw, ItemSlot.ShiftInUse); - if (ItemSlot.ShiftInUse) - { - Main.mouseItem = player.GetItem(Main.myPlayer, Main.mouseItem, false, true); - } - changed = true; + Item toWithdraw = items[slot].Clone(); + if (toWithdraw.stack > toWithdraw.maxStack) + { + toWithdraw.stack = toWithdraw.maxStack; + } + Main.mouseItem = DoWithdraw(toWithdraw, ItemSlot.ShiftInUse); + if (ItemSlot.ShiftInUse) + { + Main.mouseItem = player.GetItem(Main.myPlayer, Main.mouseItem, false, true); + } + changed = true; } if (changed) { @@ -478,7 +460,9 @@ private static void HoverItemSlot(int slot, ref int hoverSlot) if (slot < items.Count && !items[slot].IsAir) { hoverSlot = visualSlot; - } + items[slot].newAndShiny = false; + + } if (slotFocus >= 0) { @@ -543,20 +527,22 @@ private static void DoDeposit(Item item) } } - private static bool TryDepositAll() + private static bool TryDepositAll(bool quickStack) { Player player = Main.player[Main.myPlayer]; TEStorageHeart heart = GetHeart(); bool changed = false; + Predicate filter = item => !item.IsAir && !item.favorited && (!quickStack || heart.HasItem(item, true)); if (Main.netMode == 0) { for (int k = 10; k < 50; k++) { - if (!player.inventory[k].IsAir && !player.inventory[k].favorited) + var item = player.inventory[k]; + if (filter(item)) { - int oldStack = player.inventory[k].stack; - heart.DepositItem(player.inventory[k]); - if (oldStack != player.inventory[k].stack) + int oldStack = item.stack; + heart.DepositItem(item); + if (oldStack != item.stack) { changed = true; } @@ -568,9 +554,10 @@ private static bool TryDepositAll() List items = new List(); for (int k = 10; k < 50; k++) { - if (!player.inventory[k].IsAir && !player.inventory[k].favorited) + var item = player.inventory[k]; + if (filter(item)) { - items.Add(player.inventory[k]); + items.Add(item); } } NetHelper.SendDepositAll(heart.ID, items); @@ -583,6 +570,31 @@ private static bool TryDepositAll() return changed; } + private static bool TryRestock() + { + Player player = Main.player[Main.myPlayer]; + TEStorageHeart heart = GetHeart(); + bool changed = false; + + foreach (var item in player.inventory) + { + if (item != null && !item.IsAir && item.stack < item.maxStack) + { + var toWithdraw = item.Clone(); + toWithdraw.stack = item.maxStack - item.stack; + toWithdraw = DoWithdraw(toWithdraw, true); + if (!toWithdraw.IsAir) + { + item.stack += toWithdraw.stack; + toWithdraw.TurnToAir(); + changed = true; + } + } + + } + return changed; + } + private static Item DoWithdraw(Item item, bool toInventory = false) { TEStorageHeart heart = GetHeart(); @@ -596,5 +608,6 @@ private static Item DoWithdraw(Item item, bool toInventory = false) return new Item(); } } + } -} \ No newline at end of file +} diff --git a/StoragePlayer.cs b/StoragePlayer.cs index aa6d8112..a406c64a 100644 --- a/StoragePlayer.cs +++ b/StoragePlayer.cs @@ -1,10 +1,14 @@ using System; using System.Collections.Generic; +using System.Linq; using Terraria; using Terraria.DataStructures; using Terraria.ModLoader; using Terraria.UI; using MagicStorage.Components; +using Terraria.GameInput; +using Terraria.ID; +using Terraria.ModLoader.IO; namespace MagicStorage { @@ -14,7 +18,57 @@ public class StoragePlayer : ModPlayer private Point16 storageAccess = new Point16(-1, -1); public bool remoteAccess = false; - public override void UpdateDead() + ItemTypeOrderedSet _hiddenRecipes = new ItemTypeOrderedSet("HiddenItems"); + ItemTypeOrderedSet _craftedRecipes = new ItemTypeOrderedSet("CraftedRecipes"); + + public IEnumerable HiddenRecipes { get { return _hiddenRecipes.Items; } } + public IEnumerable CraftedRecipes { get { return _craftedRecipes.Items; } } + + public ItemTypeOrderedSet FavoritedRecipes { get; private set; } = new ItemTypeOrderedSet("FavoritedRecipes"); + public ItemTypeOrderedSet SeenRecipes { get; private set; } = new ItemTypeOrderedSet("SeenRecipes"); + public ItemTypeOrderedSet AsKnownRecipes { get; private set; } = new ItemTypeOrderedSet("AsKnownRecipes"); + + public bool IsRecipeHidden(Item item) + { + return _hiddenRecipes.Contains(item); + } + + public bool AddToHiddenRecipes(Item item) + { + return _hiddenRecipes.Add(item); + } + + public bool RemoveFromHiddenRecipes(Item item) + { + return _hiddenRecipes.Remove(item); + } + + public bool AddToCraftedRecipes(Item item) + { + return _craftedRecipes.Add(item); + } + + public override TagCompound Save() + { + var c = new TagCompound(); + _hiddenRecipes.Save(c); + _craftedRecipes.Save(c); + FavoritedRecipes.Save(c); + SeenRecipes.Save(c); + AsKnownRecipes.Save(c); + return c; + } + + public override void Load(TagCompound tag) + { + _hiddenRecipes.Load(tag); + _craftedRecipes.Load(tag); + FavoritedRecipes.Load(tag); + SeenRecipes.Load(tag); + AsKnownRecipes.Load(tag); + } + + public override void UpdateDead() { if (player.whoAmI == Main.myPlayer) { @@ -57,11 +111,14 @@ public override void ResetEffects() } } } + + TEStorageHeart _latestAccessedStorage; + public TEStorageHeart LatestAccessedStorage => _latestAccessedStorage != null && _latestAccessedStorage.IsAlive ? _latestAccessedStorage : null; - public void OpenStorage(Point16 point, bool remote = false) + public void OpenStorage(Point16 point, bool remote = false) { - storageAccess = point; - remoteAccess = remote; + storageAccess = point;remoteAccess = remote; + _latestAccessedStorage = GetStorageHeart(); StorageGUI.RefreshItems(); } @@ -69,22 +126,6 @@ public void CloseStorage() { storageAccess = new Point16(-1, -1); Main.blockInput = false; - if (StorageGUI.searchBar != null) - { - StorageGUI.searchBar.Reset(); - } - if (StorageGUI.searchBar2 != null) - { - StorageGUI.searchBar2.Reset(); - } - if (CraftingGUI.searchBar != null) - { - CraftingGUI.searchBar.Reset(); - } - if (CraftingGUI.searchBar2 != null) - { - CraftingGUI.searchBar2.Reset(); - } } public Point16 ViewingStorage() @@ -140,15 +181,19 @@ public override bool ShiftClickSlot(Item[] inventory, int context, int slot) int oldStack = item.stack; if (StorageCrafting()) { - if (Main.netMode == 0) - { - GetCraftingAccess().TryDepositStation(item); - } - else - { - NetHelper.SendDepositStation(GetCraftingAccess().ID, item); - item.SetDefaults(0, true); - } + // I suggest to not use shift clicking for this because I often misused it trying to put things into a storage while crafting window is open + if (false) + { + if (Main.netMode == 0) + { + GetCraftingAccess().TryDepositStation(item); + } + else + { + NetHelper.SendDepositStation(GetCraftingAccess().ID, item); + item.SetDefaults(0, true); + } + } } else { @@ -214,4 +259,4 @@ public static bool IsStorageCrafting() return Main.player[Main.myPlayer].GetModPlayer().StorageCrafting(); } } -} \ No newline at end of file +} diff --git a/StorageWorld.cs b/StorageWorld.cs index 7d78f467..43212f97 100644 --- a/StorageWorld.cs +++ b/StorageWorld.cs @@ -1,5 +1,8 @@ using System.IO; using System.Collections.Generic; +using System.Linq; +using System.Threading; +using MagicStorage.Items; using Terraria; using Terraria.ID; using Terraria.ModLoader; @@ -24,6 +27,7 @@ public class StorageWorld : ModWorld public static bool fishronDiamond = false; public static bool ancientCultistDiamond = false; public static bool moonlordDiamond = false; + public static Dictionary> TileToCreatingItem = new Dictionary>(); public override void Initialize() { @@ -63,8 +67,8 @@ public override TagCompound Save() tag["moonlordDiamond"] = moonlordDiamond; return tag; } - - public override void Load(TagCompound tag) + + public override void Load(TagCompound tag) { kingSlimeDiamond = tag.GetBool("kingSlimeDiamond"); boss1Diamond = tag.GetBool("boss1Diamond"); @@ -80,6 +84,74 @@ public override void Load(TagCompound tag) fishronDiamond = tag.GetBool("fishronDiamond"); ancientCultistDiamond = tag.GetBool("ancientCultistDiamond"); moonlordDiamond = tag.GetBool("moonlordDiamond"); + + Volatile.Write(ref TileToCreatingItem, new Dictionary>()); // used from threaded RefreshRecipes } + + public override void PostUpdate() + { + if (TileToCreatingItem.Count == 0) + { + #region Initialize TileToCreatingItem + + var tileToCreatingItem = Enumerable.Range(0, 10000 + MagicStorage.Instance.ItemType()).Select((x, i) => + { + var item = new Item(); + // provide items + try + { + item.SetDefaults(i, true); + } + catch + { + item.SetDefaults(); + } + + return item; + }) + .Where(x => x.type > 0 && x.createTile >= 0) + .Select(x => + { + // provide item and its tiles + var tiles = new List { x.createTile }; + if (x.createTile == TileID.GlassKiln || x.createTile == TileID.Hellforge || x.createTile == TileID.AdamantiteForge) + { + tiles.Add(TileID.Furnaces); + } + + if (x.createTile == TileID.AdamantiteForge) + { + tiles.Add(TileID.Hellforge); + } + + if (x.createTile == TileID.MythrilAnvil) + { + tiles.Add(TileID.Anvils); + } + + if (x.createTile == TileID.BewitchingTable || x.createTile == TileID.Tables2) + { + tiles.Add(TileID.Tables); + } + + if (x.createTile == TileID.AlchemyTable) + { + tiles.Add(TileID.Bottles); + tiles.Add(TileID.Tables); + } + + return new { item = x, tiles = tiles }; + }) + // flatten - tile, item + .SelectMany(x => x.tiles.Select(t => new { tile = t, x.item })) + .GroupBy(x => x.tile) + .ToDictionary(x => x.Key, x => x.Select(y => y.item.type).ToList()); + + Volatile.Write(ref TileToCreatingItem, tileToCreatingItem); + + #endregion + } + } } } + diff --git a/UIButtonChoice.cs b/UIButtonChoice.cs index aa923105..10a01e83 100644 --- a/UIButtonChoice.cs +++ b/UIButtonChoice.cs @@ -12,27 +12,37 @@ namespace MagicStorage { public class UIButtonChoice : UIElement { - private const int buttonSize = 32; - private const int buttonPadding = 8; + readonly Action _onChanged; + private int buttonSize; + private int buttonPadding; private Texture2D[] buttons; private LocalizedText[] names; - private int choice = 0; - + + private int choice = 0; + public int Choice { get { return choice; } + set + { + choice = value; + } } - public UIButtonChoice(Texture2D[] buttons, LocalizedText[] names) + public UIButtonChoice(Action onChanged, Texture2D[] buttons, LocalizedText[] names, int buttonSize = 21, int buttonPadding = 1) { if (buttons.Length != names.Length || buttons.Length == 0) { throw new ArgumentException(); } + + _onChanged = onChanged; + this.buttonSize = buttonSize; + this.buttonPadding = buttonPadding; this.buttons = buttons; this.names = names; int width = buttonSize * buttons.Length + buttonPadding * (buttons.Length - 1); @@ -58,7 +68,7 @@ public override void Update(GameTime gameTime) } if (oldChoice != choice) { - StorageGUI.RefreshItems(); + _onChanged?.Invoke(); } } @@ -82,8 +92,8 @@ protected override void DrawSelf(SpriteBatch spriteBatch) Texture2D texture = k == choice ? backTextureActive : backTexture; Vector2 drawPos = new Vector2(dim.X + k * (buttonSize + buttonPadding), dim.Y); Color color = MouseOverButton(StorageGUI.curMouse.X, StorageGUI.curMouse.Y, k) ? Color.Silver : Color.White; - Main.spriteBatch.Draw(texture, drawPos, color); - Main.spriteBatch.Draw(buttons[k], drawPos + new Vector2(1f), Color.White); + Main.spriteBatch.Draw(texture, new Rectangle((int)drawPos.X,(int)drawPos.Y,buttonSize,buttonSize), color); + Main.spriteBatch.Draw(buttons[k], new Rectangle((int)drawPos.X + 1, (int)drawPos.Y + 1, buttonSize - 1, buttonSize - 1), Color.White); } } @@ -98,4 +108,4 @@ public void DrawText() } } } -} \ No newline at end of file +} diff --git a/UISearchBar.cs b/UISearchBar.cs index bf32262d..4fd3f4ca 100644 --- a/UISearchBar.cs +++ b/UISearchBar.cs @@ -18,7 +18,8 @@ public class UISearchBar : UIElement private const int padding = 4; private LocalizedText defaultText = Language.GetText("Mods.MagicStorage.Search"); - private string text = string.Empty; + readonly Action _clearedEvent; + private string text = string.Empty; private int cursorPosition = 0; private bool hasFocus = false; private int cursorTimer = 0; @@ -29,9 +30,10 @@ public UISearchBar() searchBars.Add(this); } - public UISearchBar(LocalizedText defaultText) : this() + public UISearchBar(LocalizedText defaultText, Action clearedEvent) : this() { - this.defaultText = defaultText; + this.defaultText = defaultText; + _clearedEvent = clearedEvent; } public string Text @@ -55,54 +57,89 @@ public override void Update(GameTime gameTime) cursorTimer++; cursorTimer %= 60; - if (StorageGUI.MouseClicked && Parent != null) - { - Rectangle dim = InterfaceHelper.GetFullRectangle(this); - MouseState mouse = StorageGUI.curMouse; - bool mouseOver = mouse.X > dim.X && mouse.X < dim.X + dim.Width && mouse.Y > dim.Y && mouse.Y < dim.Y + dim.Height; - if (!hasFocus && mouseOver) - { - hasFocus = true; - CheckBlockInput(); - } - else if (hasFocus && !mouseOver) - { - hasFocus = false; - CheckBlockInput(); - cursorPosition = text.Length; - } - } - else if (StorageGUI.curMouse.RightButton == ButtonState.Pressed && StorageGUI.oldMouse.RightButton == ButtonState.Released && Parent != null && hasFocus) - { - Rectangle dim = InterfaceHelper.GetFullRectangle(this); - MouseState mouse = StorageGUI.curMouse; - bool mouseOver = mouse.X > dim.X && mouse.X < dim.X + dim.Width && mouse.Y > dim.Y && mouse.Y < dim.Y + dim.Height; - if (!mouseOver) - { - hasFocus = false; - cursorPosition = text.Length; - CheckBlockInput(); - } - } + Rectangle dim = InterfaceHelper.GetFullRectangle(this); + MouseState mouse = StorageGUI.curMouse; + bool mouseOver = mouse.X > dim.X && mouse.X < dim.X + dim.Width && mouse.Y > dim.Y && mouse.Y < dim.Y + dim.Height; + if (StorageGUI.MouseClicked && Parent != null) + { + if (!hasFocus && mouseOver) + { + hasFocus = true; + CheckBlockInput(); + } + else if (hasFocus && !mouseOver) + { + hasFocus = false; + CheckBlockInput(); + cursorPosition = text.Length; + } + } + else if (StorageGUI.curMouse.RightButton == ButtonState.Pressed && StorageGUI.oldMouse.RightButton == ButtonState.Released && Parent != null && hasFocus && !mouseOver) + { + hasFocus = false; + cursorPosition = text.Length; + CheckBlockInput(); + } + else if (StorageGUI.curMouse.RightButton == ButtonState.Pressed && StorageGUI.oldMouse.RightButton == ButtonState.Released && mouseOver) + { + if (text.Length > 0) + { + text = string.Empty; + cursorPosition = 0; + _clearedEvent?.Invoke(); + } + } - if (hasFocus) + if (hasFocus) { PlayerInput.WritingText = true; Main.instance.HandleIME(); - string newString = Main.GetInputText(text); - if (!newString.Equals(text)) + string prev = text; + if (cursorPosition < text.Length && text.Length > 0) + prev = prev.Remove(cursorPosition); + string newString = Main.GetInputText(prev); + bool changed = false; + if (!newString.Equals(prev)) { - text = newString; - cursorPosition = text.Length; - StorageGUI.RefreshItems(); + int newStringLength = newString.Length; + if (prev != text) newString += text.Substring(cursorPosition); + text = newString; + cursorPosition = newStringLength; + changed = true; } - if (KeyTyped(Keys.Enter) || KeyTyped(Keys.Tab) || KeyTyped(Keys.Escape)) - { - hasFocus = false; - CheckBlockInput(); - } - } - base.Update(gameTime); + if (KeyTyped(Keys.Delete)) + { + if (text.Length > 0 && cursorPosition < text.Length) + { + text = text.Remove(cursorPosition, 1); + changed = true; + } + } + if (KeyTyped(Keys.Left)) + { + if (cursorPosition > 0) cursorPosition--; + } + if (KeyTyped(Keys.Right)) + { + if (cursorPosition < text.Length) cursorPosition++; + } + if (KeyTyped(Keys.Home)) + { + cursorPosition = 0; + } + if (KeyTyped(Keys.End)) + { + cursorPosition = text.Length; + } + if (changed) StorageGUI.RefreshItems(); + if (KeyTyped(Keys.Enter) || KeyTyped(Keys.Tab) || KeyTyped(Keys.Escape)) + { + hasFocus = false; + CheckBlockInput(); + } + +} + base.Update(gameTime); } protected override void DrawSelf(SpriteBatch spriteBatch) @@ -162,4 +199,4 @@ private static void CheckBlockInput() } } } -} \ No newline at end of file +} diff --git a/UIToggleButton.cs b/UIToggleButton.cs new file mode 100644 index 00000000..c7581675 --- /dev/null +++ b/UIToggleButton.cs @@ -0,0 +1,92 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Terraria; +using Terraria.Localization; +using Terraria.UI; + +namespace MagicStorage +{ + public class UIToggleButton : UIElement + { + private int buttonSize; + private int buttonPadding; + private readonly Action onChanged; + private Texture2D _button; + private LocalizedText _name; + + private bool _value; + + public bool Value + { + get + { + return _value; + } + set + { + _value = value; + } + } + + public UIToggleButton(Action onChanged, Texture2D button, LocalizedText name, int buttonSize = 21, int buttonPadding = 1) + { + this.buttonSize = buttonSize; + this.buttonPadding = buttonPadding; + this.onChanged = onChanged; + this._button = button; + this._name = name; + this.Width.Set(buttonSize, 0f); + this.MinWidth.Set(buttonSize, 0f); + this.Height.Set(buttonSize, 0f); + this.MinHeight.Set(buttonSize, 0f); + } + + public override void Update(GameTime gameTime) + { + var oldValue = _value; + if (StorageGUI.MouseClicked && Parent != null) + { + if (MouseOverButton(StorageGUI.curMouse.X, StorageGUI.curMouse.Y)) + { + _value = !_value; + } + } + + if (oldValue != _value) + { + onChanged?.Invoke(); + } + } + + private bool MouseOverButton(int mouseX, int mouseY) + { + Rectangle dim = InterfaceHelper.GetFullRectangle(this); + float left = dim.X; + float right = left + buttonSize * Main.UIScale; + float top = dim.Y; + float bottom = top + buttonSize * Main.UIScale; + return mouseX > left && mouseX < right && mouseY > top && mouseY < bottom; + } + + protected override void DrawSelf(SpriteBatch spriteBatch) + { + Texture2D backTexture = MagicStorage.Instance.GetTexture("SortButtonBackground"); + Texture2D backTextureActive = MagicStorage.Instance.GetTexture("SortButtonBackgroundActive"); + CalculatedStyle dim = GetDimensions(); + Texture2D texture = _value ? backTextureActive : backTexture; + Vector2 drawPos = new Vector2(dim.X, dim.Y); + Color color = MouseOverButton(StorageGUI.curMouse.X, StorageGUI.curMouse.Y) ? Color.Silver : Color.White; + Main.spriteBatch.Draw(texture, new Rectangle((int) drawPos.X, (int) drawPos.Y, buttonSize, buttonSize), color); + Main.spriteBatch.Draw(_button, new Rectangle((int) drawPos.X + 1, (int) drawPos.Y + 1, buttonSize - 1, buttonSize - 1), Color.White); + } + + public void DrawText() + { + if (MouseOverButton(StorageGUI.curMouse.X, StorageGUI.curMouse.Y)) + { + Main.instance.MouseText(_name.Value); + } + } + } +} diff --git a/build.txt b/build.txt index 6c650742..45c20a9f 100644 --- a/build.txt +++ b/build.txt @@ -5,4 +5,5 @@ homepage = https://forums.terraria.org/index.php?threads/magic-storage.56294/ hideCode = false hideResources = false includeSource = true -buildIgnore = OldArt\*, .git\* \ No newline at end of file +buildIgnore = OldArt\*, .git\* +languageVersion = 6 \ No newline at end of file