* Counting House screen:
- 4-cell grid (was 5-col 5x2 wasted slots) with item icons centered
- Inventory count badge bottom-right of each item cell
- Detail pane: friendly display name, item id, on-hand count,
list price, lifetime sold, effective fee, payout per unit
- Sell 1/16/64 buttons grey out (and no-op) when you don't have
enough of the selected item in inventory
* Bottom action row on all transactional screens: replaced "Refresh"
with a single smart Back/Close button that returns to the Hub when
opened from there. Fixes the overlap with sub-panel internal buttons
that were caused by Refresh sitting at bottom-right.
* Panel heights reduced from (height - 30) to (height - 50) so the
internal sell/action buttons don't clash with the screen-level
action row.
* Same Back/Close pattern applied to TierUpgrade, Bounty, Plot, Journal.
* Removed "shop" alias from OpenScreenDispatcher — Counting House
responds only to "counthouse" now. (No NPCs exist yet so this is safe.)
* Added "journal" as the canonical screen name for the Adventurer's
Journal (replaces "questlog" — both keys still accepted in the
command suggestion list for now).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -19,5 +19,5 @@ loader_version_range=[1,)
|
||||
mod_id=bnstoolkit
|
||||
mod_name=Brass and Sigil Toolkit
|
||||
mod_license=All Rights Reserved
|
||||
mod_version=0.8.0
|
||||
mod_version=0.8.1
|
||||
mod_group_id=uk.sijbers.bnstoolkit
|
||||
|
||||
@@ -25,9 +25,8 @@ public final class OpenScreenDispatcher {
|
||||
case "tier" -> { NetSend.requestSnapshot("TIER"); new TierUpgradeScreen().openGui(); }
|
||||
case "bounty" -> { NetSend.requestSnapshot("BOUNTY"); new BountyBoardScreen().openGui(); }
|
||||
case "plot" -> { NetSend.requestSnapshot("PLOT"); new PlotPurchaseScreen().openGui(); }
|
||||
case "counthouse", "shop"
|
||||
-> { NetSend.requestSnapshot("SELL"); new CountingHouseScreen().openGui(); }
|
||||
case "questlog" -> { NetSend.requestSnapshot("ALL"); new QuestLogScreen().openGui(); }
|
||||
case "counthouse" -> { NetSend.requestSnapshot("SELL"); new CountingHouseScreen().openGui(); }
|
||||
case "journal" -> { NetSend.requestSnapshot("ALL"); new QuestLogScreen().openGui(); }
|
||||
case "hub" -> { NetSend.requestSnapshot("ALL"); new HubScreen().openGui(); }
|
||||
default -> BnsToolkit.LOG.warn("[bnstoolkit] unknown screen requested: {}", which);
|
||||
}
|
||||
|
||||
@@ -36,25 +36,22 @@ public final class BountyBoardScreen extends BaseBnsScreen {
|
||||
public void addWidgets() {
|
||||
BountyList list = new BountyList(this);
|
||||
list.setPos(8, contentTop());
|
||||
list.setSize(170, getHeight() - 30);
|
||||
list.setSize(170, getHeight() - 50);
|
||||
add(list);
|
||||
|
||||
BountyDetail detail = new BountyDetail(this);
|
||||
detail.setPos(186, contentTop());
|
||||
detail.setSize(getWidth() - 194, getHeight() - 30);
|
||||
detail.setSize(getWidth() - 194, getHeight() - 50);
|
||||
add(detail);
|
||||
|
||||
add(SimpleTextButton.create(this,
|
||||
Component.literal("Refresh"),
|
||||
Icons.REFRESH,
|
||||
btn -> NetSend.requestSnapshot("BOUNTY")));
|
||||
add(BaseBnsScreen.makeBackOrClose(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void alignWidgets() {
|
||||
Widget rf = getWidgets().get(2);
|
||||
rf.setSize(60, 16);
|
||||
rf.setPos(getWidth() - 68, getHeight() - 22);
|
||||
Widget close = getWidgets().get(2);
|
||||
close.setSize(72, 16);
|
||||
close.setPos(getWidth() - 80, getHeight() - 22);
|
||||
}
|
||||
|
||||
private static final class BountyList extends Panel {
|
||||
|
||||
@@ -2,13 +2,12 @@ package uk.sijbers.bnstoolkit.client.screens;
|
||||
|
||||
import dev.ftb.mods.ftblibrary.icon.Color4I;
|
||||
import dev.ftb.mods.ftblibrary.icon.Icon;
|
||||
import dev.ftb.mods.ftblibrary.icon.Icons;
|
||||
import dev.ftb.mods.ftblibrary.icon.ItemIcon;
|
||||
import dev.ftb.mods.ftblibrary.ui.Panel;
|
||||
import dev.ftb.mods.ftblibrary.ui.SimpleTextButton;
|
||||
import dev.ftb.mods.ftblibrary.ui.Theme;
|
||||
import dev.ftb.mods.ftblibrary.ui.Widget;
|
||||
import dev.ftb.mods.ftblibrary.ui.input.MouseButton;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
@@ -17,26 +16,23 @@ import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import uk.sijbers.bnstoolkit.client.ClientBnsState;
|
||||
import uk.sijbers.bnstoolkit.data.SellCatalogue;
|
||||
import uk.sijbers.bnstoolkit.data.SpurBalance;
|
||||
import uk.sijbers.bnstoolkit.network.NetSend;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The Counting House — wealth exchange screen.
|
||||
*
|
||||
* Not a general shop. Players bring diamonds / netherite / ancient
|
||||
* debris and convert them to spurs, credited straight to their bank
|
||||
* account. Iron / gold / coal / etc. are NOT here — they belong on
|
||||
* player-run Numismatics Vendor blocks at market prices.
|
||||
* Players bring diamonds / netherite / ancient debris and convert them
|
||||
* to spurs credited directly to their bank. Reached via the Counting
|
||||
* House Clerk NPC at spawn (not openable remotely by default).
|
||||
*
|
||||
* Right pane shows current effective price for the selected wealth
|
||||
* token after the player's tier fee + DR. Quick-exchange buttons cover
|
||||
* 1 / 16 / 64.
|
||||
*
|
||||
* Reached via the Counting House Clerk NPC at spawn — not openable from
|
||||
* anywhere via keybind. The sell action sends a {@code RunBnsCommand}
|
||||
* packet which calls Java-side {@code /bns sell}; that handler pulls
|
||||
* items, computes payout, and deposits to the Numismatics bank.
|
||||
* <p>Left grid: 4 wealth-token icons. Click to select.
|
||||
* <p>Right pane: selected item's name, list price, lifetime sales,
|
||||
* effective fee%, payout per unit, AND how many of that
|
||||
* item the player has in their inventory right now.
|
||||
* <p>Quick-exchange buttons: 1 / 16 / 64.
|
||||
* <p>Bottom-right: Back (returns to Hub if opened from there) /
|
||||
* Close (NPC-opened path).
|
||||
*/
|
||||
public final class CountingHouseScreen extends BaseBnsScreen {
|
||||
public CountingHouseScreen() {
|
||||
@@ -47,27 +43,27 @@ public final class CountingHouseScreen extends BaseBnsScreen {
|
||||
|
||||
@Override
|
||||
public void addWidgets() {
|
||||
// Pre-size sub-panels so refreshWidgets recursion sees correct dims.
|
||||
// Panel height = screen height - 50 so there's room below for the
|
||||
// Back/Close action row without overlapping internal buttons.
|
||||
ItemGrid grid = new ItemGrid(this);
|
||||
grid.setPos(8, contentTop());
|
||||
grid.setSize(170, getHeight() - 30);
|
||||
grid.setSize(170, getHeight() - 50);
|
||||
add(grid);
|
||||
|
||||
SellDetail detail = new SellDetail(this);
|
||||
detail.setPos(186, contentTop());
|
||||
detail.setSize(getWidth() - 194, getHeight() - 30);
|
||||
detail.setSize(getWidth() - 194, getHeight() - 50);
|
||||
add(detail);
|
||||
|
||||
add(SimpleTextButton.create(this,
|
||||
Component.literal("Refresh"),
|
||||
Icons.REFRESH,
|
||||
btn -> NetSend.requestSnapshot("SELL")));
|
||||
add(BaseBnsScreen.makeBackOrClose(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void alignWidgets() {
|
||||
Widget rf = getWidgets().get(2);
|
||||
rf.setSize(60, 16);
|
||||
rf.setPos(getWidth() - 68, getHeight() - 22);
|
||||
Widget close = getWidgets().get(2);
|
||||
close.setSize(72, 16);
|
||||
close.setPos(getWidth() - 80, getHeight() - 22);
|
||||
}
|
||||
|
||||
// ─── Item grid ───────────────────────────────────────────────────
|
||||
@@ -78,7 +74,7 @@ public final class CountingHouseScreen extends BaseBnsScreen {
|
||||
for (ResourceLocation id : SellCatalogue.PRICES.keySet()) add(new ItemCell(this, id));
|
||||
}
|
||||
@Override public void alignWidgets() {
|
||||
int cols = 5, cell = 32, gap = 2;
|
||||
int cols = 4, cell = 36, gap = 4;
|
||||
int i = 0;
|
||||
for (Widget w : getWidgets()) {
|
||||
int col = i % cols;
|
||||
@@ -104,10 +100,15 @@ public final class CountingHouseScreen extends BaseBnsScreen {
|
||||
Color4I bg = isSelected ? Color4I.rgba(0x80FFD700) :
|
||||
isMouseOver ? Color4I.rgba(0x40FFFFFF) : Color4I.rgba(0x40000000);
|
||||
bg.draw(gfx, x, y, w, h);
|
||||
theme.drawString(gfx, Component.empty(), x, y, Color4I.WHITE, 0);
|
||||
// Render the item icon centered
|
||||
if (!stack.isEmpty()) {
|
||||
gfx.renderItem(stack, x + 8, y + 8);
|
||||
gfx.renderItem(stack, x + (w - 16) / 2, y + (h - 16) / 2);
|
||||
}
|
||||
// Inventory count badge bottom-right of the cell
|
||||
int count = localInventoryCount(itemId);
|
||||
if (count > 0) {
|
||||
String label = String.valueOf(count);
|
||||
theme.drawString(gfx, Component.literal("§f" + label), x + w - 4 - theme.getFont().width(label),
|
||||
y + h - 10, Color4I.WHITE, Theme.SHADOW);
|
||||
}
|
||||
}
|
||||
@Override public boolean mousePressed(MouseButton button) {
|
||||
@@ -130,21 +131,30 @@ public final class CountingHouseScreen extends BaseBnsScreen {
|
||||
long sold = ClientBnsState.lifetimeSoldOf(selected);
|
||||
int feePct = ClientBnsState.effectiveFeePct;
|
||||
long perUnit = SellCatalogue.singleUnitPriceDisplay(selected, sold, feePct);
|
||||
int onHand = localInventoryCount(selected);
|
||||
|
||||
add(new LabelRow(this, "§e" + selected.toString() + "§r"));
|
||||
add(new LabelRow(this, "§e" + displayName(selected) + "§r"));
|
||||
add(new LabelRow(this, "§7" + selected + "§r"));
|
||||
add(new LabelRow(this, ""));
|
||||
add(new LabelRow(this, "On hand: §f" + onHand + "§r"));
|
||||
add(new LabelRow(this, "List price: §6" + base + "§r"));
|
||||
add(new LabelRow(this, "Sold lifetime: §7" + sold + "§r"));
|
||||
add(new LabelRow(this, "Lifetime sold: §7" + sold + "§r"));
|
||||
add(new LabelRow(this, "Effective fee: §c" + feePct + "%§r"));
|
||||
add(new LabelRow(this, "You get: §a" + perUnit + " spurs / unit§r"));
|
||||
add(new LabelRow(this, "You get: §a" + perUnit + " sp/unit§r"));
|
||||
add(new LabelRow(this, ""));
|
||||
|
||||
for (int n : new int[]{1, 16, 64}) {
|
||||
final int count = n;
|
||||
boolean haveEnough = onHand >= count;
|
||||
Component label = Component.literal((haveEnough ? "§a" : "§8") + "Sell " + count);
|
||||
add(SimpleTextButton.create(this,
|
||||
Component.literal("Sell " + count),
|
||||
label,
|
||||
Icon.empty(),
|
||||
btn -> {
|
||||
if (!haveEnough) {
|
||||
TierUpgradeScreen.playClick();
|
||||
return;
|
||||
}
|
||||
NetSend.runBns("sell " + selected + " " + count);
|
||||
TierUpgradeScreen.playClick();
|
||||
}));
|
||||
@@ -177,4 +187,24 @@ public final class CountingHouseScreen extends BaseBnsScreen {
|
||||
theme.drawString(gfx, Component.literal(text), x, y + 2, Color4I.WHITE, Theme.SHADOW);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── helpers ────────────────────────────────────────────────────
|
||||
|
||||
private static int localInventoryCount(ResourceLocation itemId) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc == null || mc.player == null) return 0;
|
||||
return SpurBalance.countItem(mc.player, itemId);
|
||||
}
|
||||
|
||||
private static String displayName(ResourceLocation id) {
|
||||
String[] parts = id.getPath().split("_");
|
||||
StringBuilder out = new StringBuilder();
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
if (parts[i].isEmpty()) continue;
|
||||
out.append(Character.toUpperCase(parts[i].charAt(0)));
|
||||
if (parts[i].length() > 1) out.append(parts[i].substring(1));
|
||||
if (i + 1 < parts.length) out.append(' ');
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,25 +35,22 @@ public final class PlotPurchaseScreen extends BaseBnsScreen {
|
||||
public void addWidgets() {
|
||||
PlotList list = new PlotList(this);
|
||||
list.setPos(8, contentTop());
|
||||
list.setSize(170, getHeight() - 30);
|
||||
list.setSize(170, getHeight() - 50);
|
||||
add(list);
|
||||
|
||||
PlotDetail detail = new PlotDetail(this);
|
||||
detail.setPos(186, contentTop());
|
||||
detail.setSize(getWidth() - 194, getHeight() - 30);
|
||||
detail.setSize(getWidth() - 194, getHeight() - 50);
|
||||
add(detail);
|
||||
|
||||
add(SimpleTextButton.create(this,
|
||||
Component.literal("Refresh"),
|
||||
Icons.REFRESH,
|
||||
btn -> NetSend.requestSnapshot("PLOT")));
|
||||
add(BaseBnsScreen.makeBackOrClose(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void alignWidgets() {
|
||||
Widget rf = getWidgets().get(2);
|
||||
rf.setSize(60, 16);
|
||||
rf.setPos(getWidth() - 68, getHeight() - 22);
|
||||
Widget close = getWidgets().get(2);
|
||||
close.setSize(72, 16);
|
||||
close.setPos(getWidth() - 80, getHeight() - 22);
|
||||
}
|
||||
|
||||
private static final class PlotList extends Panel {
|
||||
|
||||
@@ -44,25 +44,19 @@ public final class QuestLogScreen extends BaseBnsScreen {
|
||||
|
||||
@Override
|
||||
public void addWidgets() {
|
||||
// Pre-size the content panel so its children get correct
|
||||
// dimensions during the recursive refreshWidgets.
|
||||
ContentPanel content = new ContentPanel(this);
|
||||
content.setPos(8, contentTop());
|
||||
content.setSize(getWidth() - 16, getHeight() - 32);
|
||||
content.setSize(getWidth() - 16, getHeight() - 50);
|
||||
add(content);
|
||||
|
||||
add(SimpleTextButton.create(this, Component.literal("Refresh"), Icons.REFRESH,
|
||||
btn -> NetSend.requestSnapshot("ALL")));
|
||||
add(BaseBnsScreen.makeBackOrClose(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void alignWidgets() {
|
||||
int btnY = getHeight() - 22;
|
||||
Widget refresh = getWidgets().get(1);
|
||||
refresh.setSize(60, 16); refresh.setPos(8, btnY);
|
||||
Widget close = getWidgets().get(2);
|
||||
close.setSize(60, 16); close.setPos(getWidth() - 68, btnY);
|
||||
Widget close = getWidgets().get(1);
|
||||
close.setSize(72, 16);
|
||||
close.setPos(getWidth() - 80, getHeight() - 22);
|
||||
}
|
||||
|
||||
/** Three-section journal body. */
|
||||
|
||||
@@ -37,12 +37,9 @@ public final class TierUpgradeScreen extends BaseBnsScreen {
|
||||
|
||||
@Override
|
||||
public void addWidgets() {
|
||||
// Pre-size sub-panels so their addWidgets/alignWidgets (called
|
||||
// via the recursive Panel.refreshWidgets BEFORE our own
|
||||
// alignWidgets) see the correct dimensions.
|
||||
LadderPanel ladder = new LadderPanel(this);
|
||||
ladder.setPos(8, contentTop());
|
||||
ladder.setSize(180, getHeight() - 28);
|
||||
ladder.setSize(180, getHeight() - 50);
|
||||
add(ladder);
|
||||
|
||||
DetailPanel detail = new DetailPanel(this);
|
||||
@@ -50,18 +47,14 @@ public final class TierUpgradeScreen extends BaseBnsScreen {
|
||||
detail.setSize(getWidth() - 204, getHeight() - 50);
|
||||
add(detail);
|
||||
|
||||
add(SimpleTextButton.create(this,
|
||||
Component.literal("Refresh"),
|
||||
Icons.REFRESH,
|
||||
btn -> NetSend.requestSnapshot("TIER")));
|
||||
add(BaseBnsScreen.makeBackOrClose(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void alignWidgets() {
|
||||
// Sub-panels are sized in addWidgets; only position the refresh button here.
|
||||
Widget rf = getWidgets().get(2);
|
||||
rf.setSize(60, 16);
|
||||
rf.setPos(getWidth() - 68, getHeight() - 22);
|
||||
Widget close = getWidgets().get(2);
|
||||
close.setSize(72, 16);
|
||||
close.setPos(getWidth() - 80, getHeight() - 22);
|
||||
}
|
||||
|
||||
// ─── Sub-panels ──────────────────────────────────────────────────
|
||||
|
||||
@@ -35,7 +35,7 @@ public final class BnsServerCommands {
|
||||
private BnsServerCommands() {}
|
||||
|
||||
private static final String[] SCREEN_NAMES = {
|
||||
"hub", "tier", "bounty", "plot", "counthouse", "shop", "questlog"
|
||||
"hub", "tier", "bounty", "plot", "counthouse", "journal"
|
||||
};
|
||||
|
||||
@SubscribeEvent
|
||||
@@ -74,7 +74,7 @@ public final class BnsServerCommands {
|
||||
for (String s : SCREEN_NAMES) if (s.equals(which)) { ok = true; break; }
|
||||
if (!ok) {
|
||||
src.sendFailure(Component.literal("Unknown screen: " + which
|
||||
+ ". Options: hub, tier, bounty, plot, shop, questlog"));
|
||||
+ ". Options: hub, tier, bounty, plot, counthouse, journal"));
|
||||
return 0;
|
||||
}
|
||||
ServerEconomyBridge.openScreen(sp, which);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"key.bnstoolkit.bounties": "Open Bounty Board (direct)",
|
||||
"key.bnstoolkit.plots": "Open Plot Office (direct)",
|
||||
"key.bnstoolkit.shop": "Open Counting House (direct)",
|
||||
"key.bnstoolkit.journal": "Open Adventurer's Journal (direct)",
|
||||
"key.bnstoolkit.questlog": "Open Quest Log (direct)",
|
||||
|
||||
"screen.bnstoolkit.hub": "Brass and Sigil",
|
||||
@@ -12,6 +13,5 @@
|
||||
"screen.bnstoolkit.bounty_board": "Bounty Board",
|
||||
"screen.bnstoolkit.quest_log": "Adventurer's Journal",
|
||||
"screen.bnstoolkit.plot_purchase": "Plot Office",
|
||||
"screen.bnstoolkit.shop_browser": "Counting House",
|
||||
"screen.bnstoolkit.counting_house": "Counting House"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user