From 7b768fde2c096f9eb5a330451deecb75abc2d6e6 Mon Sep 17 00:00:00 2001 From: LeonardoVAC Date: Fri, 16 Oct 2026 00:38:57 -0300 Subject: [PATCH] feat: Add auto sell list --- src/TerraSharp/Core/Hotkeys.cs | 1 + src/TerraSharp/Core/Settings.Json.cs | 3 +++ src/TerraSharp/Core/Settings.cs | 22 +++++++++++++++- src/TerraSharp/Features/ItemFeatures.cs | 22 ++++++++++++++++ src/TerraSharp/Features/PlayerFeatures.cs | 2 ++ src/TerraSharp/UI/ItemPicker.cs | 32 +++++++++++++++++++++++ src/TerraSharp/UI/MainWindow.Pages.cs | 7 +++++ src/TerraSharp/UI/MainWindow.Tooltips.cs | 1 + src/TerraSharp/UI/MainWindow.cs | 2 +- src/TerraSharp/UI/WindowManager.cs | 3 ++- 10 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 src/TerraSharp/UI/ItemPicker.cs diff --git a/src/TerraSharp/Core/Hotkeys.cs b/src/TerraSharp/Core/Hotkeys.cs index 90eed4d..adf48ea 100644 --- a/src/TerraSharp/Core/Hotkeys.cs +++ b/src/TerraSharp/Core/Hotkeys.cs @@ -63,6 +63,7 @@ public static class Hotkeys Toggle("Items", "ItemVacuum", "Item Vacuum", () => Settings.ItemVacuum, v => Settings.ItemVacuum = v), Toggle("Items", "InstantBreak", "Instant Break", () => Settings.InstantBreak, v => Settings.InstantBreak = v), Toggle("Items", "InfItems", "Infinite Items", () => Settings.InfItems, v => Settings.InfItems = v), + Toggle("Items", "AutoSell", "Auto Sell", () => Settings.AutoSell, v => Settings.AutoSell = v), new("Items", "MaxStack", "Max Stack", ItemFeatures.MaxStack), new("Items", "Duplicate", "Duplicate Item", ItemFeatures.Duplicate), diff --git a/src/TerraSharp/Core/Settings.Json.cs b/src/TerraSharp/Core/Settings.Json.cs index 851836a..7c1f2c4 100644 --- a/src/TerraSharp/Core/Settings.Json.cs +++ b/src/TerraSharp/Core/Settings.Json.cs @@ -62,6 +62,7 @@ public static partial class Settings [nameof(InstantBreak)] = "Items.InstantBreak", [nameof(InfItems)] = "Items.InfiniteItems", [nameof(ItemVacuum)] = "Items.Vacuum", + [nameof(AutoSell)] = "Items.AutoSell.Enabled", [nameof(BankButtons)] = "Items.BankButtons", [nameof(AutoFish)] = "Fishing.Enabled", @@ -127,6 +128,8 @@ public static partial class Settings [nameof(LogBallistics)] = "Ballistics.Log", }; + static readonly string[] ListPaths = ["Items.AutoSell.Items"]; + static void SetValue(Dictionary document, string path, object value) { string[] parts = path.Split('.'); diff --git a/src/TerraSharp/Core/Settings.cs b/src/TerraSharp/Core/Settings.cs index 490b6d5..ece8938 100644 --- a/src/TerraSharp/Core/Settings.cs +++ b/src/TerraSharp/Core/Settings.cs @@ -38,7 +38,8 @@ 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, BankButtons = true; + public static bool InstantBreak, InfItems, ItemVacuum, AutoSell, BankButtons = true; + public static readonly HashSet SellList = []; public static bool AutoFish, AutoRecast = true, FishEnemies, Sonar; public static bool Esp, EspNames = true, EspHealth = true, EspHealthText, EspDistance, EspLines, EspProjPath = true; @@ -95,6 +96,8 @@ public static partial class Settings binds[bind.Key] = bind.Value.ToString(); document["Binds"] = binds; + SetValue(document, ListPaths[0], SortedList(SellList)); + var windows = new Dictionary(); foreach (Window window in WindowManager.All) windows[window.Id] = [(int)window.Pos.X, (int)window.Pos.Y]; @@ -124,6 +127,8 @@ public static partial class Settings if (TryGetValue(document, setting.Value, out object? value)) TryLoad(setting.Value, () => Apply(setting.Key, Convert.ToString(value, CultureInfo.InvariantCulture) ?? "")); + LoadList(document, ListPaths[0], SellList); + foreach (KeyValuePair bind in Section(document, "Binds")) TryLoad("Binds." + bind.Key, () => Binds[bind.Key] = (Keys)Enum.Parse(typeof(Keys), (string)bind.Value)); @@ -152,6 +157,20 @@ public static partial class Settings } } + static int[] SortedList(HashSet list) + { + int[] ids = [.. list]; + Array.Sort(ids); + return ids; + } + + static void LoadList(Dictionary document, string path, HashSet list) + { + list.Clear(); + if (TryGetValue(document, path, out object? value)) + TryLoad(path, () => list.UnionWith(Json.ConvertTo(value!))); + } + static void TryLoad(string key, Action load) { try @@ -211,6 +230,7 @@ public static partial class Settings { foreach (KeyValuePair pair in Defaults) typeof(Settings).GetField(pair.Key)!.SetValue(null, pair.Value); + SellList.Clear(); } public static string Hex(Color color) => $"{color.R:X2}{color.G:X2}{color.B:X2}{color.A:X2}"; diff --git a/src/TerraSharp/Features/ItemFeatures.cs b/src/TerraSharp/Features/ItemFeatures.cs index 9004ccc..edfce11 100644 --- a/src/TerraSharp/Features/ItemFeatures.cs +++ b/src/TerraSharp/Features/ItemFeatures.cs @@ -1,5 +1,6 @@ using Microsoft.Xna.Framework; using Terraria; +using TerraSharp.Core; using TerraSharp.UI; namespace TerraSharp.Features; @@ -27,6 +28,7 @@ public static class ItemFeatures } const int InventorySlots = 50; + const int CoinSound = 18; // The cursor item, or the held item when the cursor is empty. public static Item EditTarget => Main.mouseItem.type != 0 ? Main.mouseItem : Main.LocalPlayer.inventory[Main.LocalPlayer.selectedItem]; @@ -59,4 +61,24 @@ public static class ItemFeatures return; } } + + // Items worth nothing are deleted; items worth something stay when no slot can take the coins. + public static void AutoSell(Player player) + { + bool sold = false; + for (int i = 0; i < InventorySlots; i++) + { + Item item = player.inventory[i]; + if (item.type == 0 || item.favorited || !Settings.SellList.Contains(item.type) || (i == player.selectedItem && player.itemAnimation > 0)) + continue; + if (!player.SellItem(item) && item.value > 0) + continue; + + item.TurnToAir(); + sold = true; + } + + if (sold) + Widgets.Sound(CoinSound); + } } diff --git a/src/TerraSharp/Features/PlayerFeatures.cs b/src/TerraSharp/Features/PlayerFeatures.cs index b283252..afd0d92 100644 --- a/src/TerraSharp/Features/PlayerFeatures.cs +++ b/src/TerraSharp/Features/PlayerFeatures.cs @@ -143,6 +143,8 @@ public static class PlayerFeatures if (Settings.InfBreath) player.breath = player.breathMax; AutoPotions(player); + if (Settings.AutoSell) + ItemFeatures.AutoSell(player); } if (Settings.InfFlight) diff --git a/src/TerraSharp/UI/ItemPicker.cs b/src/TerraSharp/UI/ItemPicker.cs new file mode 100644 index 0000000..32b6352 --- /dev/null +++ b/src/TerraSharp/UI/ItemPicker.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; + +namespace TerraSharp.UI; + +// Edits a persisted set of item types, such as the auto sell list. +public sealed class ItemPicker(string id, string title, Vector2 position, HashSet list) : ItemGrid(id, title, position, 534, 520, [new("Selected", list.Contains)]) +{ + protected override void DrawContent(Rectangle body) + { + DrawSearchGrid(body, body.Y, body.Bottom - 40); + var footer = new Rectangle(body.X + 4, body.Bottom - 34, body.Width - 4, 32); + Render.TextMid(Widgets.SpriteBatch, $"{list.Count} selected Click: add or remove", footer, Widgets.Dim, 0.72f); + if (!Widgets.Button(new Rectangle(footer.Right - 100, footer.Y + 1, 100, 30), "Clear", false, 0.8f)) + return; + + list.Clear(); + Index.Refresh(); + } + + protected override void DrawSlot(int type, Rectangle bounds, bool hot) + { + DrawItem(type, bounds, hot, list.Contains(type)); + if (!hot || !Widgets.Click) + return; + + if (!list.Remove(type)) + list.Add(type); + Index.Refresh(); + Widgets.Sound(12); + } +} diff --git a/src/TerraSharp/UI/MainWindow.Pages.cs b/src/TerraSharp/UI/MainWindow.Pages.cs index d99760a..5b2c719 100644 --- a/src/TerraSharp/UI/MainWindow.Pages.cs +++ b/src/TerraSharp/UI/MainWindow.Pages.cs @@ -125,6 +125,13 @@ public sealed partial class MainWindow void ItemsPage() { Group("Items"); + if (Toggle("Auto Sell", ref Settings.AutoSell)) + Sub(() => + { + Note($"{Settings.SellList.Count} items listed. Favorited items are never sold."); + if (Buttons(WindowManager.SellList.Open ? "Close Sell List" : "Edit Sell List") == 0) + WindowManager.Toggle(WindowManager.SellList); + }); Toggle("Bank Buttons", ref Settings.BankButtons); Toggle("Infinite Items", ref Settings.InfItems); Toggle("Instant Break", ref Settings.InstantBreak); diff --git a/src/TerraSharp/UI/MainWindow.Tooltips.cs b/src/TerraSharp/UI/MainWindow.Tooltips.cs index 87957c5..ef81ed9 100644 --- a/src/TerraSharp/UI/MainWindow.Tooltips.cs +++ b/src/TerraSharp/UI/MainWindow.Tooltips.cs @@ -37,6 +37,7 @@ public sealed partial class MainWindow ["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 Sell"] = "Turns listed items in your inventory into coins. Items worth nothing are deleted.", ["Item Editor"] = "Change the prefix, stats and stack of the held or cursor item.", ["Auto Fishing"] = "Reels in on a bite while you hold a fishing pole.", ["Recast"] = "Casts again where you last cast by hand.", diff --git a/src/TerraSharp/UI/MainWindow.cs b/src/TerraSharp/UI/MainWindow.cs index 316812a..0b97c17 100644 --- a/src/TerraSharp/UI/MainWindow.cs +++ b/src/TerraSharp/UI/MainWindow.cs @@ -33,7 +33,7 @@ public sealed partial class MainWindow : Window new Page("Player", PlayerPage, () => Count(Settings.GodMode, Settings.InfHealth, Settings.InfMana, Settings.InfBreath, Settings.InfFlight, Settings.InstantRespawn, Settings.AutoHeal, Settings.AutoMana, Settings.GhostMode, Settings.DefenseBoost)), new Page("Movement", MovementPage, () => Count(Settings.Fly, Settings.SuperSpeed, Settings.HighJump, Settings.GravityFlip, Settings.NoFallDamage, Settings.LavaImmune, Settings.WaterWalk, Settings.NoKnockback, Settings.ExtendedReach)), new Page("Combat", CombatPage, () => Count(Settings.RapidAttack, Settings.AutoSwing, Settings.DamageBoost, Settings.NoManaCost, Settings.NoSpread, Settings.Aimbot, Settings.AutoAttack, Settings.KillAura, Settings.HitMagnet, Settings.FreezeEnemies, Settings.WeakenEnemies)), - new Page("Items", ItemsPage, () => Count(Settings.InstantBreak, Settings.InfItems, Settings.ItemVacuum, Settings.AutoFish, Settings.Sonar)), + new Page("Items", ItemsPage, () => Count(Settings.InstantBreak, Settings.InfItems, Settings.ItemVacuum, Settings.AutoSell, Settings.AutoFish, Settings.Sonar)), new Page("Visuals", VisualsPage, () => Count(Settings.Esp, Settings.Spelunker, Settings.Hunter, Settings.Shine, Settings.NightOwl, Settings.DangerSense, Settings.BiomeSight, Settings.FullBright, Settings.ExtendedZoom)), new Page("World", WorldPage, () => Count(Settings.FreezeTime, Settings.SpawnRateBoost, Settings.MapTeleport)), new Page("Keys", KeysPage, () => 0), diff --git a/src/TerraSharp/UI/WindowManager.cs b/src/TerraSharp/UI/WindowManager.cs index 0eb8bc2..c630096 100644 --- a/src/TerraSharp/UI/WindowManager.cs +++ b/src/TerraSharp/UI/WindowManager.cs @@ -15,11 +15,12 @@ public static class WindowManager public static readonly BuffBrowser Buffs = new(); public static readonly NpcBrowser Npcs = new(); public static readonly ItemEditor Editor = new(); + public static readonly ItemPicker SellList = new("sellList", "Auto Sell List", new Vector2(680, 130), Settings.SellList); const int TitleHeight = 40; const int MaxInputLength = 40; - static readonly List Stack = [Items, Buffs, Npcs, Editor, Menu]; + static readonly List Stack = [Items, Buffs, Npcs, Editor, SellList, Menu]; static Window? _dragging; static Vector2 _dragOffset;