From 1908db36277ee6416dc39e1c65069a9161f956f7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Jul 2026 13:49:54 +0000 Subject: [PATCH 1/2] Make all in-game text configurable via config.yml messages section --- .../command/FastSellAllCommand.java | 2 +- .../sellplugin/command/SellAllCommand.java | 2 +- .../sellplugin/command/SellCommand.java | 7 +- .../sellplugin/command/TopSellCommand.java | 2 +- .../sellplugin/gui/CategoryItemsGUI.java | 17 ++-- .../sellplugin/gui/CategoryProgressGUI.java | 44 +++++----- .../sellplugin/gui/ConfirmSellAllGUI.java | 17 ++-- .../sellplugin/gui/ConfirmSellGUI.java | 21 ++--- .../yourname/sellplugin/gui/ShopMainGUI.java | 19 +++-- .../yourname/sellplugin/gui/TopSellGUI.java | 21 +++-- .../sellplugin/manager/ConfigManager.java | 9 ++ .../sellplugin/manager/SellManager.java | 16 ++-- src/main/resources/config.yml | 83 +++++++++++++++++++ 13 files changed, 182 insertions(+), 78 deletions(-) diff --git a/src/main/java/com/yourname/sellplugin/command/FastSellAllCommand.java b/src/main/java/com/yourname/sellplugin/command/FastSellAllCommand.java index 592fe25..fe376a7 100644 --- a/src/main/java/com/yourname/sellplugin/command/FastSellAllCommand.java +++ b/src/main/java/com/yourname/sellplugin/command/FastSellAllCommand.java @@ -17,7 +17,7 @@ public FastSellAllCommand(SellPlugin plugin) { @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if (!(sender instanceof Player player)) { - sender.sendMessage("Only players can use this command."); + sender.sendMessage(plugin.getConfigManager().getText("player-only-command", "&cOnly players can use this command.")); return true; } diff --git a/src/main/java/com/yourname/sellplugin/command/SellAllCommand.java b/src/main/java/com/yourname/sellplugin/command/SellAllCommand.java index dc3c832..1f1da7e 100644 --- a/src/main/java/com/yourname/sellplugin/command/SellAllCommand.java +++ b/src/main/java/com/yourname/sellplugin/command/SellAllCommand.java @@ -17,7 +17,7 @@ public SellAllCommand(SellPlugin plugin) { @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if (!(sender instanceof Player player)) { - sender.sendMessage("Only players can use this command."); + sender.sendMessage(plugin.getConfigManager().getText("player-only-command", "&cOnly players can use this command.")); return true; } diff --git a/src/main/java/com/yourname/sellplugin/command/SellCommand.java b/src/main/java/com/yourname/sellplugin/command/SellCommand.java index 78114a6..cd573ed 100644 --- a/src/main/java/com/yourname/sellplugin/command/SellCommand.java +++ b/src/main/java/com/yourname/sellplugin/command/SellCommand.java @@ -2,7 +2,6 @@ import com.yourname.sellplugin.SellPlugin; import com.yourname.sellplugin.gui.ShopMainGUI; -import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; @@ -20,16 +19,16 @@ public boolean onCommand(CommandSender sender, Command command, String label, St // Handle /sell reload if (args.length > 0 && args[0].equalsIgnoreCase("reload")) { if (!sender.hasPermission("sellplugin.reload")) { - sender.sendMessage(ChatColor.RED + "You do not have permission to reload the config."); + sender.sendMessage(plugin.getConfigManager().getText("reload-no-permission", "&cYou do not have permission to reload the config.")); return true; } plugin.getConfigManager().reload(); - sender.sendMessage(ChatColor.GREEN + "SellPlugin configuration reloaded."); + sender.sendMessage(plugin.getConfigManager().getText("reload-success", "&aSellPlugin configuration reloaded.")); return true; } if (!(sender instanceof Player player)) { - sender.sendMessage("Only players can use this command."); + sender.sendMessage(plugin.getConfigManager().getText("player-only-command", "&cOnly players can use this command.")); return true; } diff --git a/src/main/java/com/yourname/sellplugin/command/TopSellCommand.java b/src/main/java/com/yourname/sellplugin/command/TopSellCommand.java index eabfaf6..b1ffd00 100644 --- a/src/main/java/com/yourname/sellplugin/command/TopSellCommand.java +++ b/src/main/java/com/yourname/sellplugin/command/TopSellCommand.java @@ -18,7 +18,7 @@ public TopSellCommand(SellPlugin plugin) { @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if (!(sender instanceof Player player)) { - sender.sendMessage("Only players can use this command."); + sender.sendMessage(plugin.getConfigManager().getText("player-only-command", "&cOnly players can use this command.")); return true; } diff --git a/src/main/java/com/yourname/sellplugin/gui/CategoryItemsGUI.java b/src/main/java/com/yourname/sellplugin/gui/CategoryItemsGUI.java index a1c1848..61c9a63 100644 --- a/src/main/java/com/yourname/sellplugin/gui/CategoryItemsGUI.java +++ b/src/main/java/com/yourname/sellplugin/gui/CategoryItemsGUI.java @@ -60,7 +60,7 @@ public CategoryItemsGUI(SellPlugin plugin, Player player, String categoryId, int ConfigManager cfg = plugin.getConfigManager(); String title = cfg.getCategoryDisplayName(categoryId) - + ChatColor.DARK_GRAY + " – Items"; + + cfg.getText("category-items.title-suffix", "&8 – Items"); this.inv = Bukkit.createInventory(this, 54, title); populate(); } @@ -121,10 +121,13 @@ private void populate() { // ── Page indicator ───────────────────────────────────────────────── int totalPages = Math.max(1, (int) Math.ceil((double) itemKeys.size() / ITEMS_PER_PAGE)); List infoLore = Collections.singletonList( - ChatColor.GRAY + "Total items: " + itemKeys.size()); + cfg.getText("category-items.total-items", "&7Total items: {count}") + .replace("{count}", String.valueOf(itemKeys.size()))); inv.setItem(SLOT_INFO, makeItem( cfg.getIconMaterial("page-indicator", Material.PAPER), - ChatColor.WHITE + "Page " + (page + 1) + " / " + totalPages, + cfg.getText("category-items.page-indicator", "&fPage {page} / {total}") + .replace("{page}", String.valueOf(page + 1)) + .replace("{total}", String.valueOf(totalPages)), infoLore)); // ── Next page ────────────────────────────────────────────────────── @@ -141,15 +144,15 @@ private void populate() { double catValue = plugin.getSellManager().calculateCategoryValue(player, categoryId); int catCount = plugin.getSellManager().countCategoryItems(player, categoryId); List sellLore = new ArrayList<>(); - sellLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("category: ") + sellLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("category-items.category-label", "category: ")) + ChatColor.WHITE + ChatColor.stripColor(cfg.getCategoryDisplayName(categoryId))); if (catCount > 0) { - sellLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("items: ") + sellLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("category-items.items-label", "items: ")) + ChatColor.WHITE + NumberFormatter.format(catCount)); - sellLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("earn: ") + sellLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("category-items.earn-label", "earn: ")) + ChatColor.GREEN + "$" + NumberFormatter.format(catValue)); } else { - sellLore.add(ChatColor.RED + " ▸ " + SmallCaps.convert("no items to sell.")); + sellLore.add(ChatColor.RED + " ▸ " + SmallCaps.convert(cfg.getText("category-items.no-items-to-sell", "no items to sell."))); } inv.setItem(SLOT_SELL_ALL, makeItem( cfg.getIconMaterial("sell-category", Material.GOLD_INGOT), diff --git a/src/main/java/com/yourname/sellplugin/gui/CategoryProgressGUI.java b/src/main/java/com/yourname/sellplugin/gui/CategoryProgressGUI.java index 17290ad..7738e62 100644 --- a/src/main/java/com/yourname/sellplugin/gui/CategoryProgressGUI.java +++ b/src/main/java/com/yourname/sellplugin/gui/CategoryProgressGUI.java @@ -117,22 +117,23 @@ private void populate() { // ── Daily bonus indicator (slot 4, top centre) ───────────────────── if (dailyBonus > 0) { + String separator = cfg.getText("lore-separator", "&8━━━━━━━━━━━━━━━━━━━"); List boostLore = new ArrayList<>(); - boostLore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━"); - boostLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("bonus: ") + boostLore.add(separator); + boostLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("category-progress.daily-boost-bonus-label", "bonus: ")) + ChatColor.YELLOW + "+" + String.format("%.2f", dailyBonus) + "x"); - boostLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("effective: ") + boostLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("category-progress.daily-boost-effective-label", "effective: ")) + ChatColor.GREEN + String.format("%.2fx", mult + dailyBonus)); - boostLore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━"); - boostLore.add(ChatColor.GRAY + SmallCaps.convert("resets at midnight.")); + boostLore.add(separator); + boostLore.add(ChatColor.GRAY + SmallCaps.convert(cfg.getText("category-progress.daily-boost-resets", "resets at midnight."))); inv.setItem(4, makeItem(Material.BLAZE_POWDER, - ChatColor.GOLD + "" + ChatColor.BOLD + "\uD83D\uDD25 " + SmallCaps.convert("Daily Boost Active!"), + SmallCaps.convert(cfg.getText("category-progress.daily-boost-title", "&6&l\uD83D\uDD25 Daily Boost Active!")), boostLore)); } // ── Back button (bottom-right) ────────────────────────────────────── List backLore = cfg.getIconLore("back", - Collections.singletonList(ChatColor.GRAY + " ▸ " + SmallCaps.convert("return to the main menu."))); + Collections.singletonList(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("category-progress.back-lore", "return to the main menu.")))); inv.setItem(SLOT_BACK, makeItem(cfg.getIconMaterial("back", Material.ARROW), cfg.getIconName("back", "&c&l" + SmallCaps.convert("back")), @@ -159,15 +160,15 @@ private void buildSnakePath(double currentMultiplier, double moneyEarned) { if (completed) { paneMat = cfg.getProgressBarCompletedColor(); nameColour = ChatColor.GREEN; - status = SmallCaps.convert("completed"); + status = SmallCaps.convert(cfg.getText("category-progress.node-status-completed", "completed")); } else if (inProgress) { paneMat = cfg.getProgressBarInProgressColor(); nameColour = ChatColor.YELLOW; - status = SmallCaps.convert("in progress"); + status = SmallCaps.convert(cfg.getText("category-progress.node-status-in-progress", "in progress")); } else { paneMat = cfg.getProgressBarLockedColor(); nameColour = ChatColor.DARK_GRAY; - status = SmallCaps.convert("locked"); + status = SmallCaps.convert(cfg.getText("category-progress.node-status-locked", "locked")); } // First node uses the category icon instead of glass @@ -176,15 +177,16 @@ private void buildSnakePath(double currentMultiplier, double moneyEarned) { String label = nameColour + "" + ChatColor.BOLD + String.format("%.1fx", milestone) - + " " + SmallCaps.convert("multiplier"); + + " " + SmallCaps.convert(cfg.getText("category-progress.node-multiplier-suffix", "multiplier")); + String separator = cfg.getText("lore-separator", "&8━━━━━━━━━━━━━━━━━━━"); List lore = new ArrayList<>(); - lore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━"); - lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("status: ") + nameColour + status); + lore.add(separator); + lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("category-progress.node-status-label", "status: ")) + nameColour + status); if (isStart) { - lore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━"); - lore.add(ChatColor.YELLOW + " ✦ " + SmallCaps.convert("click to view items & prices")); + lore.add(separator); + lore.add(ChatColor.YELLOW + " ✦ " + SmallCaps.convert(cfg.getText("category-progress.node-click-to-view", "click to view items & prices"))); } if (inProgress) { @@ -192,12 +194,12 @@ private void buildSnakePath(double currentMultiplier, double moneyEarned) { double moneyRequired = plugin.getMultiplierManager().getCumulativeThreshold(i + 1); if (moneyRequired > 0) { double percentage = Math.min(100.0, (moneyEarned / moneyRequired) * 100.0); - lore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━"); - lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("earned: ") + lore.add(separator); + lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("category-progress.node-earned-label", "earned: ")) + ChatColor.GREEN + "$" + NumberFormatter.format(moneyEarned)); - lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("required: ") + lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("category-progress.node-required-label", "required: ")) + ChatColor.GREEN + "$" + NumberFormatter.format(moneyRequired)); - lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("progress: ") + lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("category-progress.node-progress-label", "progress: ")) + ChatColor.YELLOW + String.format("%.1f%%", percentage)); } } @@ -207,9 +209,9 @@ private void buildSnakePath(double currentMultiplier, double moneyEarned) { double moneyNeeded = plugin.getMultiplierManager().getCumulativeThreshold(i); double remaining = Math.max(0, moneyNeeded - moneyEarned); if (remaining > 0) { - lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("need: ") + lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("category-progress.node-need-label", "need: ")) + ChatColor.GREEN + "$" + NumberFormatter.format(remaining) - + ChatColor.GRAY + " " + SmallCaps.convert("more to unlock")); + + ChatColor.GRAY + " " + SmallCaps.convert(cfg.getText("category-progress.node-need-suffix", "more to unlock"))); } } diff --git a/src/main/java/com/yourname/sellplugin/gui/ConfirmSellAllGUI.java b/src/main/java/com/yourname/sellplugin/gui/ConfirmSellAllGUI.java index 14d8fbc..96e5c29 100644 --- a/src/main/java/com/yourname/sellplugin/gui/ConfirmSellAllGUI.java +++ b/src/main/java/com/yourname/sellplugin/gui/ConfirmSellAllGUI.java @@ -34,7 +34,7 @@ public class ConfirmSellAllGUI implements InventoryHolder { public ConfirmSellAllGUI(SellPlugin plugin, Player player) { ConfigManager cfg = plugin.getConfigManager(); String title = ChatColor.DARK_GRAY + "" + ChatColor.BOLD - + SmallCaps.convert("confirm sell all"); + + SmallCaps.convert(cfg.getText("confirm-sell-all.title", "confirm sell all")); this.inv = Bukkit.createInventory(this, SIZE, title); populate(plugin, cfg, player); } @@ -50,13 +50,14 @@ private void populate(SellPlugin plugin, ConfigManager cfg, Player player) { int itemCount = preview.itemCount; double value = preview.value; + String separator = cfg.getText("lore-separator", "&8━━━━━━━━━━━━━━━━━━━"); List infoLore = new ArrayList<>(); - infoLore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━"); - infoLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("items: ") + infoLore.add(separator); + infoLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("confirm-sell-all.items-label", "items: ")) + ChatColor.WHITE + NumberFormatter.format(itemCount)); - infoLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("value: ") + infoLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("confirm-sell-all.value-label", "value: ")) + ChatColor.GREEN + "$" + NumberFormatter.format(value)); - infoLore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━"); + infoLore.add(separator); inv.setItem(13, makeItem( cfg.getIconMaterial("sell-all-info", Material.CHEST), @@ -65,9 +66,9 @@ private void populate(SellPlugin plugin, ConfigManager cfg, Player player) { // Confirm button List confirmLore = new ArrayList<>(); - confirmLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("sell all items from your inventory.")); + confirmLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("confirm-sell-all.confirm-lore", "sell all items from your inventory."))); if (itemCount > 0) { - confirmLore.add(ChatColor.GREEN + " ▸ " + SmallCaps.convert("you will earn: $") + NumberFormatter.format(value)); + confirmLore.add(ChatColor.GREEN + " ▸ " + SmallCaps.convert(cfg.getText("confirm-sell-all.confirm-earn", "you will earn: $")) + NumberFormatter.format(value)); } inv.setItem(SLOT_CONFIRM, makeItem( cfg.getIconMaterial("confirm", Material.LIME_STAINED_GLASS_PANE), @@ -76,7 +77,7 @@ private void populate(SellPlugin plugin, ConfigManager cfg, Player player) { // Cancel button List cancelLore = cfg.getIconLore("cancel", - Collections.singletonList(ChatColor.GRAY + SmallCaps.convert("go back without selling."))); + Collections.singletonList(ChatColor.GRAY + SmallCaps.convert(cfg.getText("confirm-sell-all.cancel-lore", "go back without selling.")))); inv.setItem(SLOT_CANCEL, makeItem( cfg.getIconMaterial("cancel", Material.RED_STAINED_GLASS_PANE), cfg.getIconName("cancel", "&c&l" + SmallCaps.convert("cancel")), diff --git a/src/main/java/com/yourname/sellplugin/gui/ConfirmSellGUI.java b/src/main/java/com/yourname/sellplugin/gui/ConfirmSellGUI.java index e1e4da9..ae6a05d 100644 --- a/src/main/java/com/yourname/sellplugin/gui/ConfirmSellGUI.java +++ b/src/main/java/com/yourname/sellplugin/gui/ConfirmSellGUI.java @@ -40,7 +40,7 @@ public ConfirmSellGUI(SellPlugin plugin, Player player, String categoryId, int r ConfigManager cfg = plugin.getConfigManager(); String title = ChatColor.DARK_GRAY + "" + ChatColor.BOLD - + SmallCaps.convert("sell your ") + + SmallCaps.convert(cfg.getText("confirm-sell.title-prefix", "sell your ")) + cfg.getCategoryDisplayName(categoryId); this.inv = Bukkit.createInventory(this, SIZE, title); populate(player); @@ -58,25 +58,26 @@ private void populate(Player player) { double value = plugin.getSellManager().calculateCategoryValue(player, categoryId); int itemCount = plugin.getSellManager().countCategoryItems(player, categoryId); + String separator = cfg.getText("lore-separator", "&8━━━━━━━━━━━━━━━━━━━"); List infoLore = new ArrayList<>(); - infoLore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━"); - infoLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("items: ") + infoLore.add(separator); + infoLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("confirm-sell.items-label", "items: ")) + ChatColor.WHITE + NumberFormatter.format(itemCount)); - infoLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("value: ") + infoLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("confirm-sell.value-label", "value: ")) + ChatColor.GREEN + "$" + NumberFormatter.format(value)); - infoLore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━"); + infoLore.add(separator); inv.setItem(13, makeItem(cfg.getCategoryMaterial(categoryId), cfg.getCategoryDisplayName(categoryId), infoLore)); // Confirm button List confirmLore = new ArrayList<>(); - confirmLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("sell all ") + confirmLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("confirm-sell.confirm-lore-line1", "sell all ")) + cfg.getCategoryDisplayName(categoryId) - + ChatColor.GRAY + SmallCaps.convert(" items")); - confirmLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("from your inventory.")); + + ChatColor.GRAY + SmallCaps.convert(cfg.getText("confirm-sell.confirm-lore-line2", " items"))); + confirmLore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("confirm-sell.confirm-lore-line3", "from your inventory."))); if (itemCount > 0) { - confirmLore.add(ChatColor.GREEN + " ▸ " + SmallCaps.convert("you will earn: $") + NumberFormatter.format(value)); + confirmLore.add(ChatColor.GREEN + " ▸ " + SmallCaps.convert(cfg.getText("confirm-sell.confirm-earn", "you will earn: $")) + NumberFormatter.format(value)); } inv.setItem(SLOT_CONFIRM, makeItem( cfg.getIconMaterial("confirm", Material.LIME_STAINED_GLASS_PANE), @@ -85,7 +86,7 @@ private void populate(Player player) { // Cancel button List cancelLore = cfg.getIconLore("cancel", - Collections.singletonList(ChatColor.GRAY + SmallCaps.convert("go back without selling."))); + Collections.singletonList(ChatColor.GRAY + SmallCaps.convert(cfg.getText("confirm-sell.cancel-lore", "go back without selling.")))); inv.setItem(SLOT_CANCEL, makeItem( cfg.getIconMaterial("cancel", Material.RED_STAINED_GLASS_PANE), cfg.getIconName("cancel", "&c&l" + SmallCaps.convert("cancel")), diff --git a/src/main/java/com/yourname/sellplugin/gui/ShopMainGUI.java b/src/main/java/com/yourname/sellplugin/gui/ShopMainGUI.java index 79c6576..2716dba 100644 --- a/src/main/java/com/yourname/sellplugin/gui/ShopMainGUI.java +++ b/src/main/java/com/yourname/sellplugin/gui/ShopMainGUI.java @@ -38,8 +38,9 @@ public class ShopMainGUI implements InventoryHolder { public ShopMainGUI(SellPlugin plugin, Player player) { this.plugin = plugin; this.player = player; - // Title in small caps: "put items here to sell" - String title = ChatColor.DARK_GRAY + "" + ChatColor.BOLD + SmallCaps.convert("put items here to sell"); + // Title in small caps (configurable via messages.shop.title) + String title = ChatColor.DARK_GRAY + "" + ChatColor.BOLD + + SmallCaps.convert(plugin.getConfigManager().getText("shop.title", "put items here to sell")); this.inv = Bukkit.createInventory(this, SIZE, title); populate(); } @@ -69,18 +70,20 @@ private ItemStack buildCategoryButton(String catId) { double dailyBonus = plugin.getDailyBonusManager().getDailyBonus(catId); double effective = multiplier + dailyBonus; + String separator = cfg.getText("lore-separator", "&8━━━━━━━━━━━━━━━━━━━"); + List lore = new ArrayList<>(); - lore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━"); - lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("value: ") + lore.add(separator); + lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("shop.value-label", "value: ")) + ChatColor.GREEN + "$" + NumberFormatter.format(value)); - lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("multiplier: ") + lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("shop.multiplier-label", "multiplier: ")) + ChatColor.AQUA + String.format("%.2fx", effective)); if (dailyBonus > 0) { - lore.add(ChatColor.GOLD + " ▸ \uD83D\uDD25 " + SmallCaps.convert("daily boost: ") + lore.add(ChatColor.GOLD + " ▸ \uD83D\uDD25 " + SmallCaps.convert(cfg.getText("shop.daily-boost-label", "daily boost: ")) + ChatColor.YELLOW + "+" + String.format("%.2f", dailyBonus) + "x"); } - lore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━"); - lore.add(ChatColor.YELLOW + " ✦ " + SmallCaps.convert("click to view items & prices!")); + lore.add(separator); + lore.add(ChatColor.YELLOW + " ✦ " + SmallCaps.convert(cfg.getText("shop.click-to-view", "click to view items & prices!"))); List extraLore = cfg.getCategoryLore(catId); if (!extraLore.isEmpty()) lore.addAll(extraLore); diff --git a/src/main/java/com/yourname/sellplugin/gui/TopSellGUI.java b/src/main/java/com/yourname/sellplugin/gui/TopSellGUI.java index 77f9656..80b89d1 100644 --- a/src/main/java/com/yourname/sellplugin/gui/TopSellGUI.java +++ b/src/main/java/com/yourname/sellplugin/gui/TopSellGUI.java @@ -64,7 +64,7 @@ public TopSellGUI(SellPlugin plugin, Player viewer, int page) { ConfigManager cfg = plugin.getConfigManager(); String title = ChatColor.DARK_GRAY + "" + ChatColor.BOLD - + SmallCaps.convert("top sellers"); + + SmallCaps.convert(cfg.getText("top-sell.title", "top sellers")); this.inv = Bukkit.createInventory(this, SIZE, title); populate(); } @@ -100,7 +100,7 @@ private void populate() { // Close button List closeLore = cfg.getIconLore("topsell-close", - Collections.singletonList(ChatColor.GRAY + SmallCaps.convert("close the leaderboard."))); + Collections.singletonList(ChatColor.GRAY + SmallCaps.convert(cfg.getText("top-sell.close-lore", "close the leaderboard.")))); inv.setItem(SLOT_CLOSE, makeItem( cfg.getIconMaterial("topsell-close", Material.BARRIER), cfg.getIconName("topsell-close", "&c&l" + SmallCaps.convert("close")), @@ -109,7 +109,7 @@ private void populate() { // Previous page if (page > 0) { List prevLore = cfg.getIconLore("prev-page", - Collections.singletonList(ChatColor.GRAY + SmallCaps.convert("previous page."))); + Collections.singletonList(ChatColor.GRAY + SmallCaps.convert(cfg.getText("top-sell.prev-page-lore", "previous page.")))); inv.setItem(SLOT_PREV, makeItem( cfg.getIconMaterial("prev-page", Material.ARROW), cfg.getIconName("prev-page", "&e← " + SmallCaps.convert("previous")), @@ -119,16 +119,18 @@ private void populate() { // Page indicator int totalPages = Math.max(1, (int) Math.ceil((double) entries.size() / ENTRIES_PER_PAGE)); List infoLore = Collections.singletonList( - ChatColor.GRAY + SmallCaps.convert("total players: ") + entries.size()); + ChatColor.GRAY + SmallCaps.convert(cfg.getText("top-sell.total-players", "total players: ")) + entries.size()); inv.setItem(SLOT_INFO, makeItem( cfg.getIconMaterial("page-indicator", Material.PAPER), - ChatColor.WHITE + SmallCaps.convert("page ") + (page + 1) + " / " + totalPages, + ChatColor.WHITE + SmallCaps.convert(cfg.getText("top-sell.page-indicator", "page {page} / {total}") + .replace("{page}", String.valueOf(page + 1)) + .replace("{total}", String.valueOf(totalPages))), infoLore)); // Next page if ((page + 1) * ENTRIES_PER_PAGE < entries.size()) { List nextLore = cfg.getIconLore("next-page", - Collections.singletonList(ChatColor.GRAY + SmallCaps.convert("next page."))); + Collections.singletonList(ChatColor.GRAY + SmallCaps.convert(cfg.getText("top-sell.next-page-lore", "next page.")))); inv.setItem(SLOT_NEXT, makeItem( cfg.getIconMaterial("next-page", Material.ARROW), cfg.getIconName("next-page", "&e" + SmallCaps.convert("next") + " →"), @@ -153,10 +155,11 @@ private ItemStack buildEntryHead(LeaderboardEntry entry, int rank) { // Lore: total earnings List lore = new ArrayList<>(); - lore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━"); - lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert("total earned: ") + String separator = plugin.getConfigManager().getText("lore-separator", "&8━━━━━━━━━━━━━━━━━━━"); + lore.add(separator); + lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(plugin.getConfigManager().getText("top-sell.total-earned-label", "total earned: ")) + ChatColor.GREEN + "$" + NumberFormatter.format(entry.totalEarnings)); - lore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━"); + lore.add(separator); meta.setLore(lore); skull.setItemMeta(meta); diff --git a/src/main/java/com/yourname/sellplugin/manager/ConfigManager.java b/src/main/java/com/yourname/sellplugin/manager/ConfigManager.java index b402892..c78c9dc 100644 --- a/src/main/java/com/yourname/sellplugin/manager/ConfigManager.java +++ b/src/main/java/com/yourname/sellplugin/manager/ConfigManager.java @@ -184,6 +184,15 @@ public String getMessage(String path) { return color(prefix + msg); } + /** + * Returns an arbitrary configurable text under {@code messages.}, + * colour-translated, falling back to {@code def} if absent. + * Used for all customisable GUI/command text that isn't a chat "message". + */ + public String getText(String path, String def) { + return color(plugin.getConfig().getString("messages." + path, def)); + } + // ---- Icons ---------------------------------------------------------------- /** * Returns the configured Material for an icon key, falling back to diff --git a/src/main/java/com/yourname/sellplugin/manager/SellManager.java b/src/main/java/com/yourname/sellplugin/manager/SellManager.java index d7a9a00..cb528f4 100644 --- a/src/main/java/com/yourname/sellplugin/manager/SellManager.java +++ b/src/main/java/com/yourname/sellplugin/manager/SellManager.java @@ -2,7 +2,6 @@ import com.yourname.sellplugin.SellPlugin; import com.yourname.sellplugin.util.NumberFormatter; -import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.block.ShulkerBox; @@ -270,17 +269,18 @@ private SellResult finalizeSell(Player player, double totalEarned, int totalItem public void sendSellNotification(Player player, double amount, int itemCount) { String formatted = NumberFormatter.format(amount); - // Action bar: always shown – lime color (&a) "+$amount" - String actionBarText = ChatColor.GREEN + "+$" + formatted; + // Action bar: always shown – "+$amount" + String actionBarText = plugin.getConfigManager().getText("action-bar", "&a+${amount}") + .replace("{amount}", formatted); player.sendActionBar(actionBarText); // Title notification: only if enabled in config if (plugin.getConfigManager().isTitleNotificationEnabled()) { - player.sendTitle( - ChatColor.GREEN + "+$" + formatted, - ChatColor.GRAY + "You sold " + NumberFormatter.format(itemCount) + " item" + (itemCount == 1 ? "" : "s"), - 10, 40, 20 - ); + String titleText = plugin.getConfigManager().getText("sell-title", "&a+${amount}") + .replace("{amount}", formatted); + String subtitleText = plugin.getConfigManager().getText("sell-subtitle", "&7You sold {count} item(s)") + .replace("{count}", NumberFormatter.format(itemCount)); + player.sendTitle(titleText, subtitleText, 10, 40, 20); } // Play sound if enabled diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 0016b74..3b8d7a4 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -214,9 +214,92 @@ icons: - "&7Close the leaderboard." # ---- Messages ---------------------------------------------- # +# Every piece of text shown to players can be customised here. +# & colour codes are supported. Placeholders are listed per entry. messages: prefix: "&8[&aSellPlugin&8] " no-permission: "&cYou do not have permission for this." sold-items: "&aYou sold &e{amount} &aitems for &e${price}&a!" nothing-to-sell: "&cYou have no sellable items in your inventory." economy-error: "&cAn economy error occurred. Please contact an admin." + + # ── Commands / console messages ─────────────────────────────── + player-only-command: "&cOnly players can use this command." + reload-no-permission: "&cYou do not have permission to reload the config." + reload-success: "&aSellPlugin configuration reloaded." + + # ── Shared decorative separator used in lots of lore lists ──── + lore-separator: "&8━━━━━━━━━━━━━━━━━━━" + + # ── Sell notification (title pop-up, {count} = items sold) ──── + action-bar: "&a+${amount}" + sell-title: "&a+${amount}" + sell-subtitle: "&7You sold {count} item(s)" + + # ── Main Shop GUI (/sell) ────────────────────────────────────── + shop: + # Inventory title. Rendered in small caps automatically. + title: "put items here to sell" + value-label: "value: " + multiplier-label: "multiplier: " + daily-boost-label: "daily boost: " + click-to-view: "click to view items & prices!" + + # ── Category Items GUI (list of items in a category) ────────── + category-items: + title-suffix: "&8 – Items" + total-items: "&7Total items: {count}" + page-indicator: "&fPage {page} / {total}" + category-label: "category: " + items-label: "items: " + earn-label: "earn: " + no-items-to-sell: "no items to sell." + + # ── Category Progress GUI (multiplier snake path) ───────────── + category-progress: + daily-boost-title: "&6&l\uD83D\uDD25 Daily Boost Active!" + daily-boost-bonus-label: "bonus: " + daily-boost-effective-label: "effective: " + daily-boost-resets: "resets at midnight." + back-lore: "return to the main menu." + node-multiplier-suffix: "multiplier" + node-status-label: "status: " + node-status-completed: "completed" + node-status-in-progress: "in progress" + node-status-locked: "locked" + node-click-to-view: "click to view items & prices" + node-earned-label: "earned: " + node-required-label: "required: " + node-progress-label: "progress: " + node-need-label: "need: " + node-need-suffix: "more to unlock" + + # ── Confirm Sell (category) GUI ──────────────────────────────── + confirm-sell: + title-prefix: "sell your " + items-label: "items: " + value-label: "value: " + confirm-lore-line1: "sell all " + confirm-lore-line2: " items" + confirm-lore-line3: "from your inventory." + confirm-earn: "you will earn: $" + cancel-lore: "go back without selling." + + # ── Confirm Sell-All GUI ─────────────────────────────────────── + confirm-sell-all: + title: "confirm sell all" + items-label: "items: " + value-label: "value: " + confirm-lore: "sell all items from your inventory." + confirm-earn: "you will earn: $" + cancel-lore: "go back without selling." + + # ── Top Sellers Leaderboard GUI ──────────────────────────────── + top-sell: + title: "top sellers" + close-lore: "close the leaderboard." + prev-page-lore: "previous page." + next-page-lore: "next page." + total-players: "total players: " + page-indicator: "page {page} / {total}" + total-earned-label: "total earned: " From d9311708bc5d388dc3cd3e3d542b3d88d786c54f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Jul 2026 08:46:34 +0000 Subject: [PATCH 2/2] Revamp sell GUI, add /sellmulti and /sellworth commands - /sell is now a clean 6-row inventory with Sell button (lime glass pane) in bottom-right corner showing sell value on hover. Close-to-sell still works. - /sellmulti opens a 1x9 GUI showing all category multipliers - /sellworth (aliases: /worth, /prices) opens a paginated item prices browser with category filter cycling - All new text, materials, and settings are fully configurable in config.yml - Category progress/items GUIs now navigate back to /sellmulti instead of /sell --- .../com/yourname/sellplugin/SellPlugin.java | 4 + .../sellplugin/command/SellMultiCommand.java | 32 ++ .../sellplugin/command/WorthCommand.java | 32 ++ .../yourname/sellplugin/gui/GUIListener.java | 142 ++++++++- .../yourname/sellplugin/gui/SellMultiGUI.java | 111 +++++++ .../yourname/sellplugin/gui/ShopMainGUI.java | 96 +++--- .../com/yourname/sellplugin/gui/WorthGUI.java | 287 ++++++++++++++++++ src/main/resources/config.yml | 50 ++- src/main/resources/plugin.yml | 14 +- 9 files changed, 707 insertions(+), 61 deletions(-) create mode 100644 src/main/java/com/yourname/sellplugin/command/SellMultiCommand.java create mode 100644 src/main/java/com/yourname/sellplugin/command/WorthCommand.java create mode 100644 src/main/java/com/yourname/sellplugin/gui/SellMultiGUI.java create mode 100644 src/main/java/com/yourname/sellplugin/gui/WorthGUI.java diff --git a/src/main/java/com/yourname/sellplugin/SellPlugin.java b/src/main/java/com/yourname/sellplugin/SellPlugin.java index e766b20..2bb669a 100644 --- a/src/main/java/com/yourname/sellplugin/SellPlugin.java +++ b/src/main/java/com/yourname/sellplugin/SellPlugin.java @@ -2,8 +2,10 @@ import com.yourname.sellplugin.command.SellAllCommand; import com.yourname.sellplugin.command.SellCommand; +import com.yourname.sellplugin.command.SellMultiCommand; import com.yourname.sellplugin.command.FastSellAllCommand; import com.yourname.sellplugin.command.TopSellCommand; +import com.yourname.sellplugin.command.WorthCommand; import com.yourname.sellplugin.economy.EconomyManager; import com.yourname.sellplugin.gui.GUIListener; import com.yourname.sellplugin.listener.WorthPacketListener; @@ -47,6 +49,8 @@ public void onEnable() { getCommand("sellall").setExecutor(new SellAllCommand(this)); getCommand("fastsellall").setExecutor(new FastSellAllCommand(this)); getCommand("topsell").setExecutor(new TopSellCommand(this)); + getCommand("sellmulti").setExecutor(new SellMultiCommand(this)); + getCommand("sellworth").setExecutor(new WorthCommand(this)); getServer().getPluginManager().registerEvents(new GUIListener(this), this); worthPacketListener = new WorthPacketListener(this); diff --git a/src/main/java/com/yourname/sellplugin/command/SellMultiCommand.java b/src/main/java/com/yourname/sellplugin/command/SellMultiCommand.java new file mode 100644 index 0000000..a3bf6f5 --- /dev/null +++ b/src/main/java/com/yourname/sellplugin/command/SellMultiCommand.java @@ -0,0 +1,32 @@ +package com.yourname.sellplugin.command; + +import com.yourname.sellplugin.SellPlugin; +import com.yourname.sellplugin.gui.SellMultiGUI; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class SellMultiCommand implements CommandExecutor { + private final SellPlugin plugin; + + public SellMultiCommand(SellPlugin plugin) { + this.plugin = plugin; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player player)) { + sender.sendMessage(plugin.getConfigManager().getText("player-only-command", "&cOnly players can use this command.")); + return true; + } + + if (!player.hasPermission("sellplugin.use")) { + player.sendMessage(plugin.getConfigManager().getMessage("no-permission")); + return true; + } + + new SellMultiGUI(plugin, player).open(player); + return true; + } +} diff --git a/src/main/java/com/yourname/sellplugin/command/WorthCommand.java b/src/main/java/com/yourname/sellplugin/command/WorthCommand.java new file mode 100644 index 0000000..0c4d521 --- /dev/null +++ b/src/main/java/com/yourname/sellplugin/command/WorthCommand.java @@ -0,0 +1,32 @@ +package com.yourname.sellplugin.command; + +import com.yourname.sellplugin.SellPlugin; +import com.yourname.sellplugin.gui.WorthGUI; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class WorthCommand implements CommandExecutor { + private final SellPlugin plugin; + + public WorthCommand(SellPlugin plugin) { + this.plugin = plugin; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player player)) { + sender.sendMessage(plugin.getConfigManager().getText("player-only-command", "&cOnly players can use this command.")); + return true; + } + + if (!player.hasPermission("sellplugin.use")) { + player.sendMessage(plugin.getConfigManager().getMessage("no-permission")); + return true; + } + + new WorthGUI(plugin, player, "all", 0).open(player); + return true; + } +} diff --git a/src/main/java/com/yourname/sellplugin/gui/GUIListener.java b/src/main/java/com/yourname/sellplugin/gui/GUIListener.java index bd86855..c1af6ec 100644 --- a/src/main/java/com/yourname/sellplugin/gui/GUIListener.java +++ b/src/main/java/com/yourname/sellplugin/gui/GUIListener.java @@ -32,11 +32,11 @@ public GUIListener(SellPlugin plugin) { public void onDrag(InventoryDragEvent e) { InventoryHolder holder = e.getView().getTopInventory().getHolder(); - // ShopMainGUI: allow drags in the item-placement area (0-35), - // cancel if any slot touches the protected bottom row (36-44). + // ShopMainGUI: allow drags in the item-placement area (0-44), + // cancel if any slot touches the protected bottom row (45-53). if (holder instanceof ShopMainGUI) { for (int slot : e.getRawSlots()) { - if (slot >= ShopMainGUI.BOTTOM_ROW_START && slot <= 44) { + if (slot >= ShopMainGUI.BOTTOM_ROW_START && slot <= 53) { e.setCancelled(true); return; } @@ -50,7 +50,9 @@ public void onDrag(InventoryDragEvent e) { || holder instanceof SellAllGUI || holder instanceof ConfirmSellGUI || holder instanceof ConfirmSellAllGUI - || holder instanceof TopSellGUI) { + || holder instanceof TopSellGUI + || holder instanceof SellMultiGUI + || holder instanceof WorthGUI) { e.setCancelled(true); } } @@ -76,17 +78,19 @@ public void onClick(InventoryClickEvent e) { if (clicked != null && clicked.getHolder() instanceof ShopMainGUI) { int slot = e.getSlot(); - // Bottom row (36-44): protected – handle category clicks + // Bottom row (45-53): protected – handle sell button if (slot >= ShopMainGUI.BOTTOM_ROW_START) { e.setCancelled(true); - String catId = shopGUI.getCategoryAtSlot(slot); - if (catId != null) { - new CategoryItemsGUI(plugin, player, catId, 0).open(player); + if (slot == ShopMainGUI.SLOT_SELL_BUTTON) { + // Sell all items in the GUI + sellGuiItems(player, shopGUI); } return; } - // Slots 0-35: allow item placement / removal + // Slots 0-44: allow item placement / removal + // After any click, schedule a sell button refresh + plugin.getServer().getScheduler().runTaskLater(plugin, shopGUI::refreshSellButton, 1L); return; } @@ -94,6 +98,51 @@ public void onClick(InventoryClickEvent e) { return; } + // ── SellMultiGUI ───────────────────────────────────────────────────── + if (holder instanceof SellMultiGUI multiGUI) { + e.setCancelled(true); + if (e.getClickedInventory() == null + || !(e.getClickedInventory().getHolder() instanceof SellMultiGUI)) return; + + int slot = e.getSlot(); + String catId = multiGUI.getCategoryAtSlot(slot); + if (catId != null) { + new CategoryProgressGUI(plugin, player, catId).open(player); + } + return; + } + + // ── WorthGUI ───────────────────────────────────────────────────────── + if (holder instanceof WorthGUI worthGUI) { + e.setCancelled(true); + if (e.getClickedInventory() == null + || !(e.getClickedInventory().getHolder() instanceof WorthGUI)) return; + + int slot = e.getSlot(); + + if (slot == WorthGUI.SLOT_CLOSE) { + player.closeInventory(); + return; + } + + if (slot == WorthGUI.SLOT_PREV && worthGUI.hasPrevPage()) { + worthGUI.prevPage().open(player); + return; + } + + if (slot == WorthGUI.SLOT_NEXT && worthGUI.hasNextPage()) { + worthGUI.nextPage().open(player); + return; + } + + if (slot == WorthGUI.SLOT_FILTER) { + String nextFilter = worthGUI.getNextFilter(); + new WorthGUI(plugin, player, nextFilter, 0).open(player); + return; + } + return; + } + // ── CategoryProgressGUI ────────────────────────────────────────────── if (holder instanceof CategoryProgressGUI catProgressGUI) { e.setCancelled(true); @@ -103,7 +152,7 @@ public void onClick(InventoryClickEvent e) { int slot = e.getSlot(); if (slot == CategoryProgressGUI.SLOT_BACK) { - new ShopMainGUI(plugin, player).open(player); + new SellMultiGUI(plugin, player).open(player); return; } @@ -145,7 +194,7 @@ public void onClick(InventoryClickEvent e) { int slot = e.getSlot(); if (slot == CategoryItemsGUI.SLOT_BACK) { - new ShopMainGUI(plugin, player).open(player); + new SellMultiGUI(plugin, player).open(player); return; } @@ -229,6 +278,75 @@ public void onClick(InventoryClickEvent e) { } } + // ── Sell items placed in the ShopMainGUI (via button click) ───────────── + + private void sellGuiItems(Player player, ShopMainGUI shopGUI) { + Inventory top = shopGUI.getInventory(); + SellPlugin pl = shopGUI.getPlugin(); + + double totalEarned = 0.0; + int totalItems = 0; + Map categoryEarnings = new HashMap<>(); + List sellableItems = new ArrayList<>(); + List nonSellableItems = new ArrayList<>(); + + for (int i = 0; i < ShopMainGUI.ITEM_AREA_END; i++) { + ItemStack item = top.getItem(i); + if (item == null || item.getType() == Material.AIR) continue; + + // Shulker box: sell its contents, return the shulker + if (SellManager.isShulkerBox(item)) { + SellManager.ShulkerSellData data = pl.getSellManager().sellShulkerContents(player, item, null, null); + totalEarned += data.earned; + totalItems += data.items; + data.categoryEarnings.forEach((cat, val) -> categoryEarnings.merge(cat, val, Double::sum)); + nonSellableItems.add(item); // return shulker box + top.setItem(i, null); + continue; + } + + String key = pl.getPriceManager().getItemKey(item); + if (key == null || pl.getPriceManager().getPrice(key) <= 0) { + nonSellableItems.add(item); + top.setItem(i, null); + continue; + } + + double base = pl.getPriceManager().getPrice(key); + String cat = pl.getPriceManager().getCategory(key); + double mult = pl.getMultiplierManager().getEffectiveMultiplier(player, cat); + int amount = item.getAmount(); + double earned = base * mult * amount; + totalEarned += earned; + totalItems += amount; + categoryEarnings.merge(cat, earned, Double::sum); + sellableItems.add(item); + top.setItem(i, null); + } + + for (ItemStack item : nonSellableItems) { + returnItem(player, item); + } + + if (totalEarned > 0) { + boolean ok = pl.getEconomyManager().deposit(player, totalEarned); + if (ok) { + for (Map.Entry entry : categoryEarnings.entrySet()) { + pl.getMultiplierManager().addEarnings(player, entry.getKey(), entry.getValue()); + } + pl.getSellManager().sendSellNotification(player, totalEarned, totalItems); + } else { + player.sendMessage(pl.getConfigManager().getMessage("economy-error")); + for (ItemStack item : sellableItems) { + returnItem(player, item); + } + } + } + + // Refresh the sell button after selling + shopGUI.refreshSellButton(); + } + // ── Close handling – sell items placed in ShopMainGUI ──────────────────── @EventHandler @@ -247,7 +365,7 @@ public void onClose(InventoryCloseEvent e) { List sellableItems = new ArrayList<>(); List nonSellableItems = new ArrayList<>(); - for (int i = 0; i < ShopMainGUI.BOTTOM_ROW_START; i++) { + for (int i = 0; i < ShopMainGUI.ITEM_AREA_END; i++) { ItemStack item = top.getItem(i); if (item == null || item.getType() == Material.AIR) continue; diff --git a/src/main/java/com/yourname/sellplugin/gui/SellMultiGUI.java b/src/main/java/com/yourname/sellplugin/gui/SellMultiGUI.java new file mode 100644 index 0000000..b92d4f7 --- /dev/null +++ b/src/main/java/com/yourname/sellplugin/gui/SellMultiGUI.java @@ -0,0 +1,111 @@ +package com.yourname.sellplugin.gui; + +import com.yourname.sellplugin.SellPlugin; +import com.yourname.sellplugin.manager.ConfigManager; +import com.yourname.sellplugin.util.SmallCaps; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 1×9 multiplier overview GUI opened via /sellmulti. + * Shows all category multipliers at a glance. + */ +public class SellMultiGUI implements InventoryHolder { + + private static final int SIZE = 9; + + private final Inventory inv; + private final SellPlugin plugin; + private final Player player; + + public SellMultiGUI(SellPlugin plugin, Player player) { + this.plugin = plugin; + this.player = player; + + ConfigManager cfg = plugin.getConfigManager(); + String title = cfg.getText("sellmulti.title", "&8&lMultipliers"); + this.inv = Bukkit.createInventory(this, SIZE, title); + populate(); + } + + private void populate() { + ConfigManager cfg = plugin.getConfigManager(); + List catOrder = cfg.getCategoryOrder(); + + // Fill with filler + Material fillerMat = cfg.getFillerBlock(); + ItemStack bg = makeItem(fillerMat, " ", Collections.emptyList()); + for (int i = 0; i < SIZE; i++) inv.setItem(i, bg); + + for (int i = 0; i < Math.min(SIZE, catOrder.size()); i++) { + inv.setItem(i, buildMultiplierIcon(catOrder.get(i))); + } + } + + private ItemStack buildMultiplierIcon(String catId) { + ConfigManager cfg = plugin.getConfigManager(); + + double multiplier = plugin.getMultiplierManager().getMultiplier(player, catId); + double dailyBonus = plugin.getDailyBonusManager().getDailyBonus(catId); + double effective = multiplier + dailyBonus; + + String separator = cfg.getText("lore-separator", "&8━━━━━━━━━━━━━━━━━━━"); + + List lore = new ArrayList<>(); + lore.add(separator); + lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("sellmulti.earned-label", "earned: ")) + + ChatColor.AQUA + String.format("%.2fx", multiplier)); + if (dailyBonus > 0) { + lore.add(ChatColor.GOLD + " ▸ \uD83D\uDD25 " + SmallCaps.convert(cfg.getText("sellmulti.daily-boost-label", "daily boost: ")) + + ChatColor.YELLOW + "+" + String.format("%.2f", dailyBonus) + "x"); + } + lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("sellmulti.effective-label", "effective: ")) + + ChatColor.GREEN + String.format("%.2fx", effective)); + lore.add(separator); + lore.add(ChatColor.YELLOW + " ✦ " + SmallCaps.convert(cfg.getText("sellmulti.click-to-view", "click to view progress"))); + + return makeItem(cfg.getCategoryMaterial(catId), cfg.getCategoryDisplayName(catId), lore); + } + + /** Returns the category ID for a slot, or null if not a category slot. */ + public String getCategoryAtSlot(int slot) { + if (slot < 0 || slot >= SIZE) return null; + List order = plugin.getConfigManager().getCategoryOrder(); + if (slot < order.size()) return order.get(slot); + return null; + } + + private ItemStack makeItem(Material mat, String name, List lore) { + ItemStack item = new ItemStack(mat); + ItemMeta meta = item.getItemMeta(); + if (meta != null) { + meta.setDisplayName(name); + if (!lore.isEmpty()) meta.setLore(lore); + item.setItemMeta(meta); + } + return item; + } + + @Override + public Inventory getInventory() { + return inv; + } + + public void open(Player p) { + p.openInventory(inv); + } + + public SellPlugin getPlugin() { + return plugin; + } +} diff --git a/src/main/java/com/yourname/sellplugin/gui/ShopMainGUI.java b/src/main/java/com/yourname/sellplugin/gui/ShopMainGUI.java index 2716dba..c4dfae7 100644 --- a/src/main/java/com/yourname/sellplugin/gui/ShopMainGUI.java +++ b/src/main/java/com/yourname/sellplugin/gui/ShopMainGUI.java @@ -16,20 +16,27 @@ import java.util.*; /** - * Main 9×5 shop GUI. - * Rows 1-4 (slots 0-35): empty area – players can place items here to sell. - * Row 5 (slots 36-44): up to 9 category buttons with proper icons. + * Main 9×6 sell GUI. + * Rows 0-4 (slots 0-44): empty area – players can place items here to sell. + * Row 5 (slot 53): Sell button (lime glass pane, bottom-right). * - * When the GUI is closed, every sellable item left in slots 0-35 is sold + * When the GUI is closed, every sellable item left in the placement area is sold * automatically and non-sellable items are returned to the player. + * Clicking the Sell button also triggers selling all items. */ public class ShopMainGUI implements InventoryHolder { - private static final int ROWS = 5; - private static final int SIZE = ROWS * 9; // 45 + private static final int ROWS = 6; + private static final int SIZE = ROWS * 9; // 54 - /** First slot of the protected bottom row (category buttons). */ - public static final int BOTTOM_ROW_START = 36; + /** First slot of the protected bottom row (Sell button row). */ + public static final int BOTTOM_ROW_START = 45; + + /** The Sell button slot (bottom-right corner). */ + public static final int SLOT_SELL_BUTTON = 53; + + /** Number of item placement slots (rows 0-4). */ + public static final int ITEM_AREA_END = 45; private final Inventory inv; private final SellPlugin plugin; @@ -48,47 +55,61 @@ public ShopMainGUI(SellPlugin plugin, Player player) { private void populate() { ConfigManager cfg = plugin.getConfigManager(); - // Rows 1-4 (slots 0-35) are left EMPTY for item placement. + // Rows 0-4 (slots 0-44) are left EMPTY for item placement. - // --- Category buttons in bottom row (slots 36-44) --- - List catOrder = cfg.getCategoryOrder(); + // Fill bottom row with filler glass + Material fillerMat = cfg.getFillerBlock(); + ItemStack bg = makeItem(fillerMat, " ", Collections.emptyList()); + for (int slot = BOTTOM_ROW_START; slot < SIZE; slot++) inv.setItem(slot, bg); - // Fill bottom row with dark-gray glass as spacer - ItemStack catBg = makeItem(Material.GRAY_STAINED_GLASS_PANE, " ", Collections.emptyList()); - for (int slot = BOTTOM_ROW_START; slot <= 44; slot++) inv.setItem(slot, catBg); + // Sell button in bottom-right corner (slot 53) + inv.setItem(SLOT_SELL_BUTTON, buildSellButton()); + } - for (int i = 0; i < Math.min(9, catOrder.size()); i++) { - inv.setItem(BOTTOM_ROW_START + i, buildCategoryButton(catOrder.get(i))); - } + /** + * Rebuild the sell button with updated value preview. + * Call this to refresh the hover text showing sell value. + */ + public void refreshSellButton() { + inv.setItem(SLOT_SELL_BUTTON, buildSellButton()); } - private ItemStack buildCategoryButton(String catId) { + private ItemStack buildSellButton() { ConfigManager cfg = plugin.getConfigManager(); - double value = plugin.getSellManager().calculateCategoryValue(player, catId); - double multiplier = plugin.getMultiplierManager().getMultiplier(player, catId); - double dailyBonus = plugin.getDailyBonusManager().getDailyBonus(catId); - double effective = multiplier + dailyBonus; + // Calculate the value of items currently in the GUI + double totalValue = calculateGuiItemsValue(); String separator = cfg.getText("lore-separator", "&8━━━━━━━━━━━━━━━━━━━"); List lore = new ArrayList<>(); lore.add(separator); - lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("shop.value-label", "value: ")) - + ChatColor.GREEN + "$" + NumberFormatter.format(value)); - lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("shop.multiplier-label", "multiplier: ")) - + ChatColor.AQUA + String.format("%.2fx", effective)); - if (dailyBonus > 0) { - lore.add(ChatColor.GOLD + " ▸ \uD83D\uDD25 " + SmallCaps.convert(cfg.getText("shop.daily-boost-label", "daily boost: ")) - + ChatColor.YELLOW + "+" + String.format("%.2f", dailyBonus) + "x"); + if (totalValue > 0) { + lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("shop.sell-value-label", "value: ")) + + ChatColor.GREEN + "$" + NumberFormatter.format(totalValue)); + } else { + lore.add(ChatColor.GRAY + " ▸ " + SmallCaps.convert(cfg.getText("shop.sell-empty", "no sellable items"))); } lore.add(separator); - lore.add(ChatColor.YELLOW + " ✦ " + SmallCaps.convert(cfg.getText("shop.click-to-view", "click to view items & prices!"))); + lore.add(ChatColor.YELLOW + " ✦ " + SmallCaps.convert(cfg.getText("shop.sell-click", "click to sell all items!"))); - List extraLore = cfg.getCategoryLore(catId); - if (!extraLore.isEmpty()) lore.addAll(extraLore); + String sellButtonName = cfg.getText("shop.sell-button-name", "&a&lSell"); - return makeItem(cfg.getCategoryMaterial(catId), cfg.getCategoryDisplayName(catId), lore); + Material sellMat = cfg.getIconMaterial("sell-button", Material.LIME_STAINED_GLASS_PANE); + return makeItem(sellMat, sellButtonName, lore); + } + + /** + * Calculate the total sell value of all items currently placed in the GUI. + */ + public double calculateGuiItemsValue() { + double totalValue = 0.0; + for (int i = 0; i < ITEM_AREA_END; i++) { + ItemStack item = inv.getItem(i); + if (item == null || item.getType() == Material.AIR) continue; + totalValue += plugin.getSellManager().calculateItemWorth(player, item); + } + return totalValue; } private ItemStack makeItem(Material mat, String name, List lore) { @@ -115,12 +136,7 @@ public SellPlugin getPlugin() { return plugin; } - /** Returns the category ID for a bottom-row slot (36-44), or null if not a category slot. */ - public String getCategoryAtSlot(int slot) { - if (slot < BOTTOM_ROW_START || slot > 44) return null; - List order = plugin.getConfigManager().getCategoryOrder(); - int idx = slot - BOTTOM_ROW_START; - if (idx < order.size()) return order.get(idx); - return null; + public Player getPlayer() { + return player; } } diff --git a/src/main/java/com/yourname/sellplugin/gui/WorthGUI.java b/src/main/java/com/yourname/sellplugin/gui/WorthGUI.java new file mode 100644 index 0000000..3c4524a --- /dev/null +++ b/src/main/java/com/yourname/sellplugin/gui/WorthGUI.java @@ -0,0 +1,287 @@ +package com.yourname.sellplugin.gui; + +import com.yourname.sellplugin.SellPlugin; +import com.yourname.sellplugin.manager.ConfigManager; +import com.yourname.sellplugin.manager.PriceManager; +import com.yourname.sellplugin.util.ItemNameFormatter; +import com.yourname.sellplugin.util.NumberFormatter; +import com.yourname.sellplugin.util.SmallCaps; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionData; +import org.bukkit.potion.PotionType; + +import java.util.*; + +/** + * Item Prices GUI opened via /sellworth or /worth. + * Paginated 6×9 (54 slots) with category filter support. + * + * Layout: + * Rows 0-4 (slots 0-44): item display + * Row 5 (slots 45-53): navigation bar + * 45 – Back/Close + * 47 – Previous page + * 48 – Filter button + * 49 – Page indicator + * 50 – Filter button (right) + * 51 – Next page + * 53 – (unused) + */ +public class WorthGUI implements InventoryHolder { + + private static final int ITEMS_PER_PAGE = 45; + + // Navigation slots + public static final int SLOT_CLOSE = 45; + public static final int SLOT_PREV = 47; + public static final int SLOT_FILTER = 48; + public static final int SLOT_INFO = 49; + public static final int SLOT_NEXT = 51; + + // Filter categories (null = all) + private static final String FILTER_ALL = "all"; + + private final Inventory inv; + private final SellPlugin plugin; + private final Player player; + private final String filter; // category filter or "all" + private final List itemKeys; + private int page; + + public WorthGUI(SellPlugin plugin, Player player, String filter, int page) { + this.plugin = plugin; + this.player = player; + this.filter = filter != null ? filter : FILTER_ALL; + this.page = page; + this.itemKeys = buildItemKeyList(); + + ConfigManager cfg = plugin.getConfigManager(); + String titleBase = cfg.getText("worth-gui.title", "&8&lItem Prices"); + String pageStr = " (Page " + (page + 1) + ")"; + this.inv = Bukkit.createInventory(this, 54, titleBase + pageStr); + populate(); + } + + private List buildItemKeyList() { + PriceManager pm = plugin.getPriceManager(); + List keys = new ArrayList<>(); + for (String key : pm.getAllItemKeys()) { + if (FILTER_ALL.equals(filter) || filter.equalsIgnoreCase(pm.getCategory(key))) { + keys.add(key); + } + } + Collections.sort(keys); + return keys; + } + + private void populate() { + inv.clear(); + ConfigManager cfg = plugin.getConfigManager(); + + // Background for navigation row + Material fillerMat = cfg.getFillerBlock(); + ItemStack bg = makeItem(fillerMat, " ", Collections.emptyList()); + for (int i = 45; i < 54; i++) inv.setItem(i, bg); + + // Items area + int start = page * ITEMS_PER_PAGE; + int end = Math.min(start + ITEMS_PER_PAGE, itemKeys.size()); + for (int i = start; i < end; i++) { + inv.setItem(i - start, buildItemDisplay(itemKeys.get(i))); + } + + // Fill remaining item area + ItemStack filler = makeItem(Material.GRAY_STAINED_GLASS_PANE, " ", Collections.emptyList()); + for (int i = (end - start); i < 45; i++) inv.setItem(i, filler); + + // Close button + List closeLore = cfg.getIconLore("topsell-close", + Collections.singletonList(ChatColor.GRAY + "Close the menu.")); + inv.setItem(SLOT_CLOSE, makeItem( + cfg.getIconMaterial("topsell-close", Material.BARRIER), + cfg.getIconName("topsell-close", "&c&lClose"), + closeLore)); + + // Previous page + if (page > 0) { + List prevLore = cfg.getIconLore("prev-page", + Collections.singletonList(ChatColor.GRAY + "Previous page.")); + inv.setItem(SLOT_PREV, makeItem( + cfg.getIconMaterial("prev-page", Material.ARROW), + cfg.getIconName("prev-page", "&e← Previous"), + prevLore)); + } + + // Filter button + List filterLore = buildFilterLore(); + String filterName = FILTER_ALL.equals(filter) + ? cfg.getText("worth-gui.filter-all", "&e&lFILTER: &fAll") + : cfg.getText("worth-gui.filter-category", "&e&lFILTER: &f") + cfg.getCategoryDisplayName(filter); + inv.setItem(SLOT_FILTER, makeItem( + Material.HOPPER, + filterName, + filterLore)); + + // Page indicator + int totalPages = Math.max(1, (int) Math.ceil((double) itemKeys.size() / ITEMS_PER_PAGE)); + List infoLore = Collections.singletonList( + ChatColor.GRAY + "Total items: " + itemKeys.size()); + inv.setItem(SLOT_INFO, makeItem( + cfg.getIconMaterial("page-indicator", Material.PAPER), + ChatColor.WHITE + "Page " + (page + 1) + " / " + totalPages, + infoLore)); + + // Next page + if ((page + 1) * ITEMS_PER_PAGE < itemKeys.size()) { + List nextLore = cfg.getIconLore("next-page", + Collections.singletonList(ChatColor.GRAY + "Next page.")); + inv.setItem(SLOT_NEXT, makeItem( + cfg.getIconMaterial("next-page", Material.ARROW), + cfg.getIconName("next-page", "&eNext →"), + nextLore)); + } + } + + private List buildFilterLore() { + ConfigManager cfg = plugin.getConfigManager(); + List lore = new ArrayList<>(); + lore.add(ChatColor.GRAY + "Click to cycle filter."); + lore.add(""); + + List categories = cfg.getCategoryOrder(); + // Show current filter highlighted + if (FILTER_ALL.equals(filter)) { + lore.add(ChatColor.GREEN + " • All"); + } else { + lore.add(ChatColor.GRAY + " • All"); + } + for (String cat : categories) { + String displayName = ChatColor.stripColor(cfg.getCategoryDisplayName(cat)); + if (cat.equalsIgnoreCase(filter)) { + lore.add(ChatColor.GREEN + " • " + displayName); + } else { + lore.add(ChatColor.GRAY + " • " + displayName); + } + } + return lore; + } + + private ItemStack buildItemDisplay(String itemKey) { + PriceManager pm = plugin.getPriceManager(); + double base = pm.getPrice(itemKey); + String category = pm.getCategory(itemKey); + double effectiveMultiplier = plugin.getMultiplierManager().getEffectiveMultiplier(player, category); + double effective = base * effectiveMultiplier; + + ItemStack item = resolveItemStack(itemKey); + + List lore = new ArrayList<>(); + lore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━━━"); + lore.add(ChatColor.GRAY + " ▸ " + ChatColor.WHITE + "Base: " + + ChatColor.GREEN + "$" + NumberFormatter.format(base)); + lore.add(ChatColor.GRAY + " ▸ " + ChatColor.WHITE + "Mult: " + + ChatColor.AQUA + String.format("%.2fx", effectiveMultiplier)); + lore.add(ChatColor.GRAY + " ▸ " + ChatColor.WHITE + "Price: " + + ChatColor.GREEN + "$" + NumberFormatter.format(effective)); + lore.add(ChatColor.DARK_GRAY + "━━━━━━━━━━━━━━━━━━━━━"); + lore.add(ChatColor.GRAY + " Category: " + ChatColor.WHITE + + ChatColor.stripColor(plugin.getConfigManager().getCategoryDisplayName(category))); + + String displayName = ChatColor.WHITE + ItemNameFormatter.formatKey(itemKey); + + ItemMeta meta = item.getItemMeta(); + if (meta != null) { + meta.setDisplayName(displayName); + meta.setLore(lore); + item.setItemMeta(meta); + } + return item; + } + + private ItemStack resolveItemStack(String itemKey) { + if (itemKey.contains(":")) { + String[] parts = itemKey.split(":", 2); + Material mat = Material.matchMaterial(parts[0]); + if (mat == null) return new ItemStack(Material.BARRIER); + + ItemStack item = new ItemStack(mat); + ItemMeta meta = item.getItemMeta(); + if (meta instanceof PotionMeta potionMeta) { + try { + PotionType type = PotionType.valueOf(parts[1]); + potionMeta.setBasePotionData(new PotionData(type)); + item.setItemMeta(meta); + } catch (IllegalArgumentException ignored) {} + } + return item; + } + Material mat = Material.matchMaterial(itemKey); + return new ItemStack(mat != null ? mat : Material.BARRIER); + } + + /** Cycle to the next filter category. */ + public String getNextFilter() { + List categories = plugin.getConfigManager().getCategoryOrder(); + if (FILTER_ALL.equals(filter)) { + return categories.isEmpty() ? FILTER_ALL : categories.get(0); + } + int idx = -1; + for (int i = 0; i < categories.size(); i++) { + if (categories.get(i).equalsIgnoreCase(filter)) { + idx = i; + break; + } + } + if (idx < 0 || idx >= categories.size() - 1) { + return FILTER_ALL; + } + return categories.get(idx + 1); + } + + // ── Navigation ─────────────────────────────────────────────────────────── + + public boolean hasPrevPage() { return page > 0; } + + public boolean hasNextPage() { + return (page + 1) * ITEMS_PER_PAGE < itemKeys.size(); + } + + public WorthGUI prevPage() { + return new WorthGUI(plugin, player, filter, page - 1); + } + + public WorthGUI nextPage() { + return new WorthGUI(plugin, player, filter, page + 1); + } + + public String getFilter() { return filter; } + public int getPage() { return page; } + + private ItemStack makeItem(Material mat, String name, List lore) { + ItemStack item = new ItemStack(mat); + ItemMeta meta = item.getItemMeta(); + if (meta != null) { + meta.setDisplayName(name); + if (!lore.isEmpty()) meta.setLore(lore); + item.setItemMeta(meta); + } + return item; + } + + @Override + public Inventory getInventory() { + return inv; + } + + public void open(Player p) { + p.openInventory(inv); + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 3b8d7a4..27db1a3 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -65,11 +65,13 @@ worth: format: "&7Worth &a&l${worth}" # ---- Main Shop GUI (/sell) ---------------------------------- # -# This opens the 9x5 category browsing menu. +# This opens the 9x6 sell GUI where players place items to sell. +# The bottom-right corner has a "Sell" button (lime glass pane). +# Closing the GUI also sells all items inside. gui: title: "&8&lShop" - size: 45 + size: 54 # ---- Sell All GUI (/sellall) -------------------------------- # # Simple one-button GUI to sell everything in your inventory. @@ -88,9 +90,24 @@ sell-all-gui: - "&eYour current Multipliers:" - "{multipliers}" -# ---- Category order (bottom row of /sell GUI, left to right) # +# ---- Sell Multi GUI (/sellmulti) ----------------------------- # +# 1x9 GUI showing all category multipliers at a glance. +# Clicking a category opens its progress path. + +sell-multi-gui: + title: "&8&lMultipliers" + +# ---- Worth GUI (/sellworth, /worth) -------------------------- # +# Paginated item prices browser with category filter. + +worth-gui: + title: "&8&lItem Prices" + filter-all: "&e&lFILTER: &fAll" + filter-category: "&e&lFILTER: &f" + +# ---- Category order (shown in /sellmulti and /sellworth) ---- # # These must match the top-level keys in price.yml. -# Up to 9 entries shown. +# Up to 9 entries shown in the multiplier GUI. category-order: - armortools - blocks @@ -196,6 +213,11 @@ icons: lore: - "&7Go back without selling." + # ── Sell button (in /sell GUI, bottom-right) ────────────────── + sell-button: + material: "LIME_STAINED_GLASS_PANE" + name: "&a&lSell" + # ── Category Items GUI ───────────────────────────────────────── sell-category: material: "GOLD_INGOT" @@ -240,10 +262,18 @@ messages: shop: # Inventory title. Rendered in small caps automatically. title: "put items here to sell" - value-label: "value: " - multiplier-label: "multiplier: " + sell-button-name: "&a&lSell" + sell-value-label: "value: " + sell-empty: "no sellable items" + sell-click: "click to sell all items!" + + # ── Sell Multi GUI (/sellmulti) ──────────────────────────────── + sellmulti: + title: "&8&lMultipliers" + earned-label: "earned: " daily-boost-label: "daily boost: " - click-to-view: "click to view items & prices!" + effective-label: "effective: " + click-to-view: "click to view progress" # ── Category Items GUI (list of items in a category) ────────── category-items: @@ -303,3 +333,9 @@ messages: total-players: "total players: " page-indicator: "page {page} / {total}" total-earned-label: "total earned: " + + # ── Worth GUI (/sellworth, /worth) ───────────────────────────── + worth-gui: + title: "&8&lItem Prices" + filter-all: "&e&lFILTER: &fAll" + filter-category: "&e&lFILTER: &f" diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 9f1829a..14835d3 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,15 +1,25 @@ name: SellPlugin -version: 2.1.0 +version: 2.2.0 main: com.yourname.sellplugin.SellPlugin api-version: 1.13 softdepend: [Vault, CoinsEngine, ProtocolLib] commands: sell: - description: Opens the category shop menu. Use /sell reload to reload config. + description: Opens the sell GUI where you can place items to sell. usage: /sell [reload] aliases: [sellmenu, sellgui, shop] permission: sellplugin.use + sellmulti: + description: Opens the multiplier overview GUI. + usage: /sellmulti + aliases: [multipliers, sellmultiplier] + permission: sellplugin.use + sellworth: + description: Opens the item prices GUI to browse item values. + usage: /sellworth + aliases: [worth, prices, itemprices] + permission: sellplugin.use sellall: description: Opens the quick sell-all GUI. usage: /sellall