From 993b91a46bd726b2df58ae7777d13deac65af036 Mon Sep 17 00:00:00 2001 From: LeonardoVAC Date: Thu, 15 Oct 2026 23:55:19 -0300 Subject: [PATCH] feat: Add bank buttons under builder toggles --- src/TerraSharp/Core/Settings.Json.cs | 1 + src/TerraSharp/Core/Settings.cs | 2 +- src/TerraSharp/Patches/PlayerPatches.cs | 17 +++ src/TerraSharp/UI/BankButtons.cs | 141 +++++++++++++++++++++++ src/TerraSharp/UI/InterfaceLayers.cs | 20 ++++ src/TerraSharp/UI/MainWindow.Pages.cs | 1 + src/TerraSharp/UI/MainWindow.Tooltips.cs | 1 + src/TerraSharp/UI/Render.cs | 4 +- 8 files changed, 184 insertions(+), 3 deletions(-) create mode 100644 src/TerraSharp/UI/BankButtons.cs diff --git a/src/TerraSharp/Core/Settings.Json.cs b/src/TerraSharp/Core/Settings.Json.cs index 8cf6db1..ebba47e 100644 --- a/src/TerraSharp/Core/Settings.Json.cs +++ b/src/TerraSharp/Core/Settings.Json.cs @@ -59,6 +59,7 @@ public static partial class Settings [nameof(InstantBreak)] = "Items.InstantBreak", [nameof(InfItems)] = "Items.InfiniteItems", [nameof(ItemVacuum)] = "Items.Vacuum", + [nameof(BankButtons)] = "Items.BankButtons", [nameof(AutoFish)] = "Fishing.Enabled", [nameof(AutoRecast)] = "Fishing.Recast", diff --git a/src/TerraSharp/Core/Settings.cs b/src/TerraSharp/Core/Settings.cs index 6990c62..53fe4ee 100644 --- a/src/TerraSharp/Core/Settings.cs +++ b/src/TerraSharp/Core/Settings.cs @@ -38,7 +38,7 @@ public static partial class Settings public static bool Aimbot, AimPrediction = true, AimDrawTarget = true, AutoAttack, AimExact = true, ShotPreview; public static float AimFov = 250f, AimRange = 60f; - public static bool InstantBreak, InfItems, ItemVacuum; + public static bool InstantBreak, InfItems, ItemVacuum, BankButtons = true; public static bool AutoFish, AutoRecast = true, FishEnemies, Sonar; public static bool Esp, EspNames = true, EspHealth = true, EspHealthText, EspDistance, EspLines, EspProjPath = true; diff --git a/src/TerraSharp/Patches/PlayerPatches.cs b/src/TerraSharp/Patches/PlayerPatches.cs index 4993401..ba5ce88 100644 --- a/src/TerraSharp/Patches/PlayerPatches.cs +++ b/src/TerraSharp/Patches/PlayerPatches.cs @@ -15,6 +15,7 @@ internal static class PlayerPatches PlayerUpdatePatch.Install(hooks); PlayerItemCheckPatch.Install(hooks); PlayerMovementPatch.Install(hooks); + ChestRangePatch.Install(hooks); } } @@ -99,3 +100,19 @@ internal static class PlayerMovementPatch original(self); } } + +// Closes any open chest or bank once the player leaves range of chestX/chestY. +internal static class ChestRangePatch +{ + delegate void Original(Player self); + + internal static void Install(HookRegistry hooks) => hooks.Add(typeof(Player), "HandleBeingInChestRange", (Action)HandleRange); + + static void HandleRange(Original original, Player self) + { + if (Plugin.Active && self.whoAmI == Main.myPlayer && BankButtons.KeepsOpen(self)) + return; + + original(self); + } +} diff --git a/src/TerraSharp/UI/BankButtons.cs b/src/TerraSharp/UI/BankButtons.cs new file mode 100644 index 0000000..4eb53cb --- /dev/null +++ b/src/TerraSharp/UI/BankButtons.cs @@ -0,0 +1,141 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Terraria; +using Terraria.GameInput; +using Terraria.ID; +using Terraria.Localization; +using TerraSharp.Core; +using TerraSharp.Patches; +#if TMODLOADER +using Terraria.ModLoader; +#endif + +namespace TerraSharp.UI; + +public enum Bank +{ + PiggyBank = -2, + Safe = -3, + DefendersForge = -4, + VoidVault = -5, +} + +// Bank icons stacked under the builder accessory toggles, left of the inventory. +public static class BankButtons +{ + const int Size = 18; + const int Spacing = 24; + const float ColumnX = 10f; + + static readonly (Bank Bank, int Item)[] Banks = [(Bank.PiggyBank, ItemID.PiggyBank), (Bank.Safe, ItemID.Safe), (Bank.DefendersForge, ItemID.DefendersForge), (Bank.VoidVault, ItemID.VoidVault)]; + static readonly Action OpenChest = (Action)Delegate.CreateDelegate(typeof(Action), HookRegistry.Method(typeof(Player), "OpenChest", [typeof(int), typeof(int), typeof(int)])); + + // Bank opened by a button; HandleBeingInChestRange would close it for being out of range. + public static Bank? Remote { get; private set; } + + public static bool KeepsOpen(Player player) + { + if (Settings.BankButtons && Remote is { } bank && player.chest == (int)bank) + return true; + + Remote = null; + return false; + } + + public static void Draw(SpriteBatch spriteBatch) + { + Player player = Main.LocalPlayer; + if (!Main.playerInventory || player.sign >= 0) + return; + + float y = FirstSlotY(player); + var mouse = new Point(Main.mouseX, Main.mouseY); + foreach ((Bank bank, int item) in Banks) + { + var center = new Vector2(ColumnX, y); + y += Spacing; + + Rectangle bounds = Utils.CenteredRectangle(center, new Vector2(Size)); + bool hover = bounds.Contains(mouse) && !PlayerInput.IgnoreMouseInterface; + bool open = player.chest == (int)bank; + if (hover) + bounds.Inflate(2, 2); + Render.Item(spriteBatch, item, bounds, hover || open ? Color.White : new Color(180, 180, 180)); + + if (!hover) + continue; + + player.mouseInterface = true; + Main.instance.MouseText(Lang.GetItemNameValue(item), 0, 0, -1, -1, -1, -1, 0); + Main.mouseText = true; + + if (Main.mouseLeft && Main.mouseLeftRelease) + { + Main.mouseLeftRelease = false; + Toggle(player, bank); + } + } + } + + // Center of the slot after the last builder toggle; mirrors Main.DrawBuilderAccToggles. + static float FirstSlotY(Player player) + { +#if TMODLOADER + int count = BuilderToggleLoader.ActiveBuilderToggles(), page = BuilderToggleLoader.BuilderTogglePage; + bool shiftHotbarLock = count / 12 != page || count % 12 >= 10; + int start = 0, end = count; + bool previousArrow = false, nextArrow = false; + if (count > 12) + { + start = 12 * page; + end = count - start < 12 ? count : start == 0 ? start + 12 : start + 11; + previousArrow = page != 0; + nextArrow = page != count / 12; + } + + return 77f - (shiftHotbarLock ? 42 : 21) + Spacing * (end - start + previousArrow.ToInt() + nextArrow.ToInt()); +#else + int torchIcons = player.unlockedBiomeTorches.ToInt(); + int toggles = player.InfoAccMechShowWires.ToInt() * 6 + player.rulerLine.ToInt() + player.rulerGrid.ToInt() + player.autoActuator.ToInt() + player.autoPaint.ToInt(); + bool pushUp = toggles + 1 + torchIcons >= 10; + return 77f + Spacing * (torchIcons + toggles - pushUp.ToInt()); +#endif + } + + static void Toggle(Player player, Bank bank) + { + if (player.chest == (int)bank) + { + player.chest = -1; + Remote = null; + Widgets.Sound(11); + return; + } + + bool wasClosed = player.chest == -1; + player.SetTalkNPC(-1); + Main.npcChatCornerItem = 0; + Main.npcChatText = ""; + if (Main.editChest) + { + Widgets.Sound(12); + Main.editChest = false; + } + + if (player.editedChestName && player.chest >= 0) + { + NetMessage.SendData(MessageID.ChestName, -1, -1, NetworkText.FromLiteral(Main.chest[player.chest].name), player.chest, 1f); + player.editedChestName = false; + } + + player.piggyBankProjTracker.Clear(); + player.voidLensChest.Clear(); + Main.stackSplit = 600; + + var tile = new Point((int)(player.Center.X / 16f), (int)(player.Center.Y / 16f)); + OpenChest(player, tile.X, tile.Y, (int)bank); + Remote = bank; + Widgets.Sound(wasClosed ? 10 : 12); + } +} diff --git a/src/TerraSharp/UI/InterfaceLayers.cs b/src/TerraSharp/UI/InterfaceLayers.cs index 74412b9..a81b6b1 100644 --- a/src/TerraSharp/UI/InterfaceLayers.cs +++ b/src/TerraSharp/UI/InterfaceLayers.cs @@ -37,6 +37,10 @@ public static class InterfaceLayers int healthBarIndex = layers.FindIndex(l => l.Name == "Vanilla: Entity Health Bars"); layers.Insert(healthBarIndex < 0 ? 1 : healthBarIndex + 1, new LegacyGameInterfaceLayer(Prefix + "Health Bars", DrawHealthBars, InterfaceScaleType.Game)); + int builderIndex = layers.FindIndex(l => l.Name == "Vanilla: Builder Accessories Bar"); + if (builderIndex >= 0) + layers.Insert(builderIndex + 1, new LegacyGameInterfaceLayer(Prefix + "Bank Buttons", DrawBankButtons, InterfaceScaleType.UI)); + int mouseTextIndex = layers.FindIndex(l => l.Name == "Vanilla: Mouse Text"); layers.Insert(mouseTextIndex < 0 ? layers.Count : mouseTextIndex, new LegacyGameInterfaceLayer(Prefix + "Windows", DrawWindows, InterfaceScaleType.UI)); } @@ -81,6 +85,22 @@ public static class InterfaceLayers return true; } + static bool DrawBankButtons() + { + try + { + if (Plugin.Active && !Main.gameMenu && Settings.BankButtons) + BankButtons.Draw(Main.spriteBatch); + } + catch (Exception e) + { + Log.Error("Bank buttons layer", e); + Widgets.Recover(Main.spriteBatch, Main.UIScaleMatrix); + } + + return true; + } + static bool DrawWindows() { Unblock(); diff --git a/src/TerraSharp/UI/MainWindow.Pages.cs b/src/TerraSharp/UI/MainWindow.Pages.cs index 3b680f1..9b44729 100644 --- a/src/TerraSharp/UI/MainWindow.Pages.cs +++ b/src/TerraSharp/UI/MainWindow.Pages.cs @@ -121,6 +121,7 @@ public sealed partial class MainWindow void ItemsPage() { Group("Items"); + Toggle("Bank Buttons", ref Settings.BankButtons); Toggle("Infinite Items", ref Settings.InfItems); Toggle("Instant Break", ref Settings.InstantBreak); Toggle("Item Vacuum", ref Settings.ItemVacuum); diff --git a/src/TerraSharp/UI/MainWindow.Tooltips.cs b/src/TerraSharp/UI/MainWindow.Tooltips.cs index 4ab1e7d..d99ed43 100644 --- a/src/TerraSharp/UI/MainWindow.Tooltips.cs +++ b/src/TerraSharp/UI/MainWindow.Tooltips.cs @@ -34,6 +34,7 @@ public sealed partial class MainWindow ["Instant Break"] = "Break blocks in one hit with your held pickaxe, axe or hammer.", ["Infinite Items"] = "Keeps inventory stacks from shrinking.", ["Item Vacuum"] = "Pulls all dropped items to you.", + ["Bank Buttons"] = "Piggy Bank, Safe, Defender's Forge and Void Vault buttons left of the inventory.", ["Auto Fishing"] = "Reels in on a bite while you hold a fishing pole.", ["Recast"] = "Casts again where you last cast by hand.", ["Catch enemies"] = "Reels in enemy catches too.", diff --git a/src/TerraSharp/UI/Render.cs b/src/TerraSharp/UI/Render.cs index d39bad9..340e8e4 100644 --- a/src/TerraSharp/UI/Render.cs +++ b/src/TerraSharp/UI/Render.cs @@ -127,7 +127,7 @@ public static class Render return text + "..."; } - public static void Item(SpriteBatch spriteBatch, int type, Rectangle bounds) + public static void Item(SpriteBatch spriteBatch, int type, Rectangle bounds, Color? color = null) { if (type <= 0) return; @@ -139,7 +139,7 @@ public static class Render float scale = Math.Min(1f, Math.Min(bounds.Width / (float)frame.Width, bounds.Height / (float)frame.Height)); Vector2 size = new Vector2(frame.Width, frame.Height) * scale; - spriteBatch.Draw(texture, new Vector2(bounds.X + (bounds.Width - size.X) / 2f, bounds.Y + (bounds.Height - size.Y) / 2f), frame, Color.White, 0f, Vector2.Zero, scale, SpriteEffects.None, 0f); + spriteBatch.Draw(texture, new Vector2(bounds.X + (bounds.Width - size.X) / 2f, bounds.Y + (bounds.Height - size.Y) / 2f), frame, color ?? Color.White, 0f, Vector2.Zero, scale, SpriteEffects.None, 0f); } public static Vector2 ToScreen(Vector2 world) => Vector2.Transform(world - Main.screenPosition, Main.GameViewMatrix.TransformationMatrix);