From 8cc2e45011e152e380eb0edbd8d90b6d460ee5b6 Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 8 Jun 2026 16:19:43 +0000 Subject: [PATCH] =?UTF-8?q?0.6.2:=20Adventurer's=20Journal=20=E2=80=94=20b?= =?UTF-8?q?ounties/rates/plots=20+=20smart=20Back=20button?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QuestLogScreen reworked from a generic status summary into a proper adventure journal. Three sections, top to bottom: - Active Bounties (N / cap) with progress bars + reward preview - Counting House Rates — every wealth-token's effective per-unit spur payout for the player's tier fee + lifetime DR. Lets players check rates from the field instead of travelling to the Counting House. - Owned Plots (N / cap) - Footer: "FTB Quests is a separate mod — open your Quest Book item" Lang title changed to "Adventurer's Journal" so it's distinct from the FTB Quests system. Internal class + key stay QuestLog* for backward-compat of /bns open questlog. BaseBnsScreen.makeBackOrClose(screen) — labels the close button "Back" with a back-arrow when FTB Library's previous-screen is set, "Close" otherwise. Hub now passes the current screen wrapper as the previous screen when opening the Journal, so close-from-Journal returns to Hub. Bug fix: sub-panel children now pass `this` correctly to their parent (was missing — same FTB Library latent bug). Co-Authored-By: Claude Opus 4.7 --- gradle.properties | 2 +- .../client/screens/BaseBnsScreen.java | 18 +++ .../bnstoolkit/client/screens/HubScreen.java | 12 +- .../client/screens/QuestLogScreen.java | 121 +++++++++++++----- .../assets/bnstoolkit/lang/en_us.json | 2 +- 5 files changed, 117 insertions(+), 38 deletions(-) diff --git a/gradle.properties b/gradle.properties index 9fd3025..e3e61d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -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.6.1 +mod_version=0.6.2 mod_group_id=uk.sijbers.bnstoolkit diff --git a/src/main/java/uk/sijbers/bnstoolkit/client/screens/BaseBnsScreen.java b/src/main/java/uk/sijbers/bnstoolkit/client/screens/BaseBnsScreen.java index 87e47d2..5ceda35 100644 --- a/src/main/java/uk/sijbers/bnstoolkit/client/screens/BaseBnsScreen.java +++ b/src/main/java/uk/sijbers/bnstoolkit/client/screens/BaseBnsScreen.java @@ -1,7 +1,9 @@ package uk.sijbers.bnstoolkit.client.screens; import dev.ftb.mods.ftblibrary.icon.Color4I; +import dev.ftb.mods.ftblibrary.icon.Icons; import dev.ftb.mods.ftblibrary.ui.BaseScreen; +import dev.ftb.mods.ftblibrary.ui.SimpleTextButton; import dev.ftb.mods.ftblibrary.ui.Theme; import dev.ftb.mods.ftblibrary.ui.WidgetType; import net.minecraft.client.gui.GuiGraphics; @@ -59,4 +61,20 @@ public abstract class BaseBnsScreen extends BaseScreen { protected int contentBottom() { return getHeight() - 24; } + + /** + * Build a smart close button: labelled "Back" with a back-arrow icon + * if there's a previous screen registered (e.g. opened from the Hub), + * otherwise labelled "Close". In both cases the button calls + * {@code closeGui()} — FTB Library's BaseScreen returns to the + * registered previous screen automatically when one was set. + */ + public static SimpleTextButton makeBackOrClose(BaseBnsScreen screen) { + boolean hasPrev = screen.getPrevScreen() != null; + String label = hasPrev ? "Back" : "Close"; + return SimpleTextButton.create(screen, + Component.literal(label), + hasPrev ? Icons.BACK : Icons.CLOSE, + btn -> screen.closeGui()); + } } diff --git a/src/main/java/uk/sijbers/bnstoolkit/client/screens/HubScreen.java b/src/main/java/uk/sijbers/bnstoolkit/client/screens/HubScreen.java index cfc365a..2277f0b 100644 --- a/src/main/java/uk/sijbers/bnstoolkit/client/screens/HubScreen.java +++ b/src/main/java/uk/sijbers/bnstoolkit/client/screens/HubScreen.java @@ -6,7 +6,9 @@ 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 net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; import uk.sijbers.bnstoolkit.client.ClientBnsState; import uk.sijbers.bnstoolkit.data.CivicTier; @@ -43,8 +45,14 @@ public final class HubScreen extends BaseBnsScreen { sp.setSize(getWidth() - 16, getHeight() - 50); add(sp); - add(SimpleTextButton.create(this, Component.literal("Quest Log"), Icons.INFO, - btn -> { NetSend.requestSnapshot("ALL"); new QuestLogScreen().openGui(); })); + add(SimpleTextButton.create(this, Component.literal("Journal"), Icons.INFO, + btn -> { + NetSend.requestSnapshot("ALL"); + QuestLogScreen ql = new QuestLogScreen(); + Screen prev = Minecraft.getInstance().screen; // current screen wrapper + if (prev != null) ql.setPreviousScreen(prev); + ql.openGui(); + })); add(SimpleTextButton.create(this, Component.literal("Refresh"), Icons.REFRESH, btn -> NetSend.requestSnapshot("ALL"))); add(SimpleTextButton.create(this, Component.literal("Close"), Icons.CLOSE, diff --git a/src/main/java/uk/sijbers/bnstoolkit/client/screens/QuestLogScreen.java b/src/main/java/uk/sijbers/bnstoolkit/client/screens/QuestLogScreen.java index 73a1144..57a9b26 100644 --- a/src/main/java/uk/sijbers/bnstoolkit/client/screens/QuestLogScreen.java +++ b/src/main/java/uk/sijbers/bnstoolkit/client/screens/QuestLogScreen.java @@ -1,6 +1,7 @@ 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.ui.Panel; import dev.ftb.mods.ftblibrary.ui.SimpleTextButton; @@ -8,22 +9,33 @@ import dev.ftb.mods.ftblibrary.ui.Theme; import dev.ftb.mods.ftblibrary.ui.Widget; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; import uk.sijbers.bnstoolkit.client.ClientBnsState; import uk.sijbers.bnstoolkit.data.Bounty; -import uk.sijbers.bnstoolkit.data.CivicTier; import uk.sijbers.bnstoolkit.data.Plot; +import uk.sijbers.bnstoolkit.data.SellCatalogue; import uk.sijbers.bnstoolkit.network.NetSend; import java.util.Map; /** - * Read-only "what am I doing right now" overview. + * Adventurer's Journal — at-a-glance overview of the player's active + * adventure. Read-only; no economy mutation happens here. * - * Shows the player's tier + balance summary at the top, then three - * sections: active bounties with progress bars, owned plots, and the - * shop fee preview. FTB Quests integration deferred — when the quest - * book lands we'll add a fourth section that mirrors the player's - * current chapter progress here. + *

Three sections, top to bottom: + *

+ * + *

Not to be confused with FTB Quests, which is a separate + * chapter-based progression mod with its own Quest Book item. A footer + * line points players there. */ public final class QuestLogScreen extends BaseBnsScreen { public QuestLogScreen() { @@ -32,58 +44,84 @@ public final class QuestLogScreen extends BaseBnsScreen { @Override public void addWidgets() { - SummaryPanel summary = new SummaryPanel(this); - summary.setPos(8, contentTop()); - summary.setSize(getWidth() - 16, getHeight() - 30); - add(summary); + // 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); + add(content); add(SimpleTextButton.create(this, Component.literal("Refresh"), Icons.REFRESH, btn -> NetSend.requestSnapshot("ALL"))); + add(BaseBnsScreen.makeBackOrClose(this)); } @Override public void alignWidgets() { - Widget rf = getWidgets().get(1); - rf.setSize(60, 16); - rf.setPos(getWidth() - 68, getHeight() - 22); + 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); } - private static final class SummaryPanel extends Panel { - SummaryPanel(Panel parent) { super(parent); } + /** Three-section journal body. */ + private static final class ContentPanel extends Panel { + ContentPanel(Panel parent) { super(parent); } @Override public void addWidgets() { - CivicTier cfg = CivicTier.byId(ClientBnsState.tier); - add(new Header(this, "§e=== Status ===")); - add(new Header(this, "Tier: §" + cfg.colour().getChar() + cfg.name() + "§r (" - + ClientBnsState.tier + " / " + CivicTier.MAX + ")")); - add(new Header(this, "Balance: §6" + TierUpgradeScreen.formatSpurs(ClientBnsState.spurs) + " spurs§r")); - add(new Header(this, "Shop fee: §c" + ClientBnsState.effectiveFeePct + "%§r")); - - add(new Header(this, "")); - add(new Header(this, "§e=== Active bounties ===")); + // Section 1: Active Bounties + int activeCount = ClientBnsState.activeBounties.size(); + int cap = ClientBnsState.bountySlotCap; + add(new Header(this,"§e=== Active Bounties (" + activeCount + " / " + cap + ") ===")); if (ClientBnsState.activeBounties.isEmpty()) { - add(new Header(this, "§7none — visit the Bounty Board (B)")); + add(new Header(this,"§8 none — visit the Bounty Board at spawn")); } else { for (Map.Entry e : ClientBnsState.activeBounties.entrySet()) { Bounty b = Bounty.byId(e.getKey()); if (b == null) continue; ClientBnsState.ActiveBounty ab = e.getValue(); - String bar = progressBar(ab.progress(), ab.target(), 14); - String line = " " + b.name() + " " + bar + " §7" + ab.progress() + "/" + ab.target() + "§r"; - add(new Header(this, line)); + String bar = progressBar(ab.progress(), ab.target(), 10); + String line = " " + b.name() + " " + bar + + " §7" + ab.progress() + "/" + ab.target() + + "§r §6+" + ab.reward() + "§r"; + add(new Header(this,line)); } } - add(new Header(this, "")); - add(new Header(this, "§e=== Owned plots ===")); + add(new Header(this,"")); + + // Section 2: Counting House rates + add(new Header(this,"§e=== Counting House Rates ===")); + int fee = ClientBnsState.effectiveFeePct; + add(new Header(this,"§7 Your tier fee: §c" + fee + "%§r")); + for (Map.Entry entry : SellCatalogue.PRICES.entrySet()) { + ResourceLocation id = entry.getKey(); + long base = entry.getValue(); + long sold = ClientBnsState.lifetimeSoldOf(id); + long current = SellCatalogue.singleUnitPriceDisplay(id, sold, fee); + String name = displayName(id); + String line = String.format(" %s§r §7%d§r → §a%d§r spurs", name, base, current); + if (sold > 0) line += " §8(sold " + sold + ")§r"; + add(new Header(this,line)); + } + + add(new Header(this,"")); + + // Section 3: Owned Plots + int owned = ClientBnsState.ownedPlotIds.size(); + add(new Header(this,"§e=== Owned Plots (" + owned + " / " + ClientBnsState.plotSlotCap + ") ===")); if (ClientBnsState.ownedPlotIds.isEmpty()) { - add(new Header(this, "§7none — visit the Plot Office (P)")); + add(new Header(this,"§8 none — visit the Plot Office at spawn")); } else { for (String pid : ClientBnsState.ownedPlotIds) { Plot p = Plot.byId(pid); - if (p != null) add(new Header(this, " §a★§r " + p.name() + " §7(" + p.size() + ")§r")); + if (p != null) add(new Header(this," §a★§r " + p.name() + " §7(" + p.size() + ")§r")); } } + + add(new Header(this,"")); + add(new Header(this,"§8FTB Quests is a separate mod — open your Quest Book item for chapters.")); } @Override public void alignWidgets() { @@ -104,13 +142,28 @@ public final class QuestLogScreen extends BaseBnsScreen { sb.append("§r"); return sb.toString(); } + + private static String displayName(ResourceLocation id) { + String path = id.getPath(); + // Friendly-cased name from the id: "ancient_debris" -> "Ancient Debris" + String[] parts = path.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(); + } } private static final class Header extends Widget { private final String text; Header(Panel parent, String text) { super(parent); this.text = text; } @Override public void draw(GuiGraphics gfx, Theme theme, int x, int y, int w, int h) { - theme.drawString(gfx, Component.literal(text), x, y + 2, Color4I.WHITE, Theme.SHADOW); + theme.drawString(gfx, Component.literal(text), x + 2, y + 2, Color4I.WHITE, Theme.SHADOW); } } + } diff --git a/src/main/resources/assets/bnstoolkit/lang/en_us.json b/src/main/resources/assets/bnstoolkit/lang/en_us.json index 58a636c..e28e4ad 100644 --- a/src/main/resources/assets/bnstoolkit/lang/en_us.json +++ b/src/main/resources/assets/bnstoolkit/lang/en_us.json @@ -10,7 +10,7 @@ "screen.bnstoolkit.hub": "Brass and Sigil", "screen.bnstoolkit.tier_upgrade": "Civic Tier", "screen.bnstoolkit.bounty_board": "Bounty Board", - "screen.bnstoolkit.quest_log": "Quest Log", + "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"