0.6.2: Adventurer's Journal — bounties/rates/plots + smart Back button
Build / build (push) Has been cancelled
Build / build (push) Has been cancelled
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 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -19,5 +19,5 @@ loader_version_range=[1,)
|
|||||||
mod_id=bnstoolkit
|
mod_id=bnstoolkit
|
||||||
mod_name=Brass and Sigil Toolkit
|
mod_name=Brass and Sigil Toolkit
|
||||||
mod_license=All Rights Reserved
|
mod_license=All Rights Reserved
|
||||||
mod_version=0.6.1
|
mod_version=0.6.2
|
||||||
mod_group_id=uk.sijbers.bnstoolkit
|
mod_group_id=uk.sijbers.bnstoolkit
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package uk.sijbers.bnstoolkit.client.screens;
|
package uk.sijbers.bnstoolkit.client.screens;
|
||||||
|
|
||||||
import dev.ftb.mods.ftblibrary.icon.Color4I;
|
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.BaseScreen;
|
||||||
|
import dev.ftb.mods.ftblibrary.ui.SimpleTextButton;
|
||||||
import dev.ftb.mods.ftblibrary.ui.Theme;
|
import dev.ftb.mods.ftblibrary.ui.Theme;
|
||||||
import dev.ftb.mods.ftblibrary.ui.WidgetType;
|
import dev.ftb.mods.ftblibrary.ui.WidgetType;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
@@ -59,4 +61,20 @@ public abstract class BaseBnsScreen extends BaseScreen {
|
|||||||
protected int contentBottom() {
|
protected int contentBottom() {
|
||||||
return getHeight() - 24;
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import dev.ftb.mods.ftblibrary.ui.Panel;
|
|||||||
import dev.ftb.mods.ftblibrary.ui.SimpleTextButton;
|
import dev.ftb.mods.ftblibrary.ui.SimpleTextButton;
|
||||||
import dev.ftb.mods.ftblibrary.ui.Theme;
|
import dev.ftb.mods.ftblibrary.ui.Theme;
|
||||||
import dev.ftb.mods.ftblibrary.ui.Widget;
|
import dev.ftb.mods.ftblibrary.ui.Widget;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import uk.sijbers.bnstoolkit.client.ClientBnsState;
|
import uk.sijbers.bnstoolkit.client.ClientBnsState;
|
||||||
import uk.sijbers.bnstoolkit.data.CivicTier;
|
import uk.sijbers.bnstoolkit.data.CivicTier;
|
||||||
@@ -43,8 +45,14 @@ public final class HubScreen extends BaseBnsScreen {
|
|||||||
sp.setSize(getWidth() - 16, getHeight() - 50);
|
sp.setSize(getWidth() - 16, getHeight() - 50);
|
||||||
add(sp);
|
add(sp);
|
||||||
|
|
||||||
add(SimpleTextButton.create(this, Component.literal("Quest Log"), Icons.INFO,
|
add(SimpleTextButton.create(this, Component.literal("Journal"), Icons.INFO,
|
||||||
btn -> { NetSend.requestSnapshot("ALL"); new QuestLogScreen().openGui(); }));
|
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,
|
add(SimpleTextButton.create(this, Component.literal("Refresh"), Icons.REFRESH,
|
||||||
btn -> NetSend.requestSnapshot("ALL")));
|
btn -> NetSend.requestSnapshot("ALL")));
|
||||||
add(SimpleTextButton.create(this, Component.literal("Close"), Icons.CLOSE,
|
add(SimpleTextButton.create(this, Component.literal("Close"), Icons.CLOSE,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package uk.sijbers.bnstoolkit.client.screens;
|
package uk.sijbers.bnstoolkit.client.screens;
|
||||||
|
|
||||||
import dev.ftb.mods.ftblibrary.icon.Color4I;
|
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.Icons;
|
||||||
import dev.ftb.mods.ftblibrary.ui.Panel;
|
import dev.ftb.mods.ftblibrary.ui.Panel;
|
||||||
import dev.ftb.mods.ftblibrary.ui.SimpleTextButton;
|
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 dev.ftb.mods.ftblibrary.ui.Widget;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import uk.sijbers.bnstoolkit.client.ClientBnsState;
|
import uk.sijbers.bnstoolkit.client.ClientBnsState;
|
||||||
import uk.sijbers.bnstoolkit.data.Bounty;
|
import uk.sijbers.bnstoolkit.data.Bounty;
|
||||||
import uk.sijbers.bnstoolkit.data.CivicTier;
|
|
||||||
import uk.sijbers.bnstoolkit.data.Plot;
|
import uk.sijbers.bnstoolkit.data.Plot;
|
||||||
|
import uk.sijbers.bnstoolkit.data.SellCatalogue;
|
||||||
import uk.sijbers.bnstoolkit.network.NetSend;
|
import uk.sijbers.bnstoolkit.network.NetSend;
|
||||||
|
|
||||||
import java.util.Map;
|
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
|
* <p>Three sections, top to bottom:
|
||||||
* sections: active bounties with progress bars, owned plots, and the
|
* <ul>
|
||||||
* shop fee preview. FTB Quests integration deferred — when the quest
|
* <li><b>Active Bounties</b> — kills in progress, with progress bars
|
||||||
* book lands we'll add a fourth section that mirrors the player's
|
* and turn-in rewards. Primary use case.</li>
|
||||||
* current chapter progress here.
|
* <li><b>Counting House Rates</b> — current per-unit spur payout for
|
||||||
|
* each wealth-token after the player's tier fee + lifetime DR.
|
||||||
|
* Lets players check rates from the field without travelling to
|
||||||
|
* the Counting House.</li>
|
||||||
|
* <li><b>Owned Plots</b> — what you own + your slot cap.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>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 final class QuestLogScreen extends BaseBnsScreen {
|
||||||
public QuestLogScreen() {
|
public QuestLogScreen() {
|
||||||
@@ -32,58 +44,84 @@ public final class QuestLogScreen extends BaseBnsScreen {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addWidgets() {
|
public void addWidgets() {
|
||||||
SummaryPanel summary = new SummaryPanel(this);
|
// Pre-size the content panel so its children get correct
|
||||||
summary.setPos(8, contentTop());
|
// dimensions during the recursive refreshWidgets.
|
||||||
summary.setSize(getWidth() - 16, getHeight() - 30);
|
ContentPanel content = new ContentPanel(this);
|
||||||
add(summary);
|
content.setPos(8, contentTop());
|
||||||
|
content.setSize(getWidth() - 16, getHeight() - 32);
|
||||||
|
add(content);
|
||||||
|
|
||||||
add(SimpleTextButton.create(this, Component.literal("Refresh"), Icons.REFRESH,
|
add(SimpleTextButton.create(this, Component.literal("Refresh"), Icons.REFRESH,
|
||||||
btn -> NetSend.requestSnapshot("ALL")));
|
btn -> NetSend.requestSnapshot("ALL")));
|
||||||
|
add(BaseBnsScreen.makeBackOrClose(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void alignWidgets() {
|
public void alignWidgets() {
|
||||||
Widget rf = getWidgets().get(1);
|
int btnY = getHeight() - 22;
|
||||||
rf.setSize(60, 16);
|
Widget refresh = getWidgets().get(1);
|
||||||
rf.setPos(getWidth() - 68, getHeight() - 22);
|
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 {
|
/** Three-section journal body. */
|
||||||
SummaryPanel(Panel parent) { super(parent); }
|
private static final class ContentPanel extends Panel {
|
||||||
|
ContentPanel(Panel parent) { super(parent); }
|
||||||
|
|
||||||
@Override public void addWidgets() {
|
@Override public void addWidgets() {
|
||||||
CivicTier cfg = CivicTier.byId(ClientBnsState.tier);
|
// Section 1: Active Bounties
|
||||||
add(new Header(this, "§e=== Status ==="));
|
int activeCount = ClientBnsState.activeBounties.size();
|
||||||
add(new Header(this, "Tier: §" + cfg.colour().getChar() + cfg.name() + "§r ("
|
int cap = ClientBnsState.bountySlotCap;
|
||||||
+ ClientBnsState.tier + " / " + CivicTier.MAX + ")"));
|
add(new Header(this,"§e=== Active Bounties (" + activeCount + " / " + cap + ") ==="));
|
||||||
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 ==="));
|
|
||||||
if (ClientBnsState.activeBounties.isEmpty()) {
|
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 {
|
} else {
|
||||||
for (Map.Entry<String, ClientBnsState.ActiveBounty> e : ClientBnsState.activeBounties.entrySet()) {
|
for (Map.Entry<String, ClientBnsState.ActiveBounty> e : ClientBnsState.activeBounties.entrySet()) {
|
||||||
Bounty b = Bounty.byId(e.getKey());
|
Bounty b = Bounty.byId(e.getKey());
|
||||||
if (b == null) continue;
|
if (b == null) continue;
|
||||||
ClientBnsState.ActiveBounty ab = e.getValue();
|
ClientBnsState.ActiveBounty ab = e.getValue();
|
||||||
String bar = progressBar(ab.progress(), ab.target(), 14);
|
String bar = progressBar(ab.progress(), ab.target(), 10);
|
||||||
String line = " " + b.name() + " " + bar + " §7" + ab.progress() + "/" + ab.target() + "§r";
|
String line = " " + b.name() + " " + bar
|
||||||
|
+ " §7" + ab.progress() + "/" + ab.target()
|
||||||
|
+ "§r §6+" + ab.reward() + "§r";
|
||||||
add(new Header(this,line));
|
add(new Header(this,line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add(new Header(this,""));
|
add(new Header(this,""));
|
||||||
add(new Header(this, "§e=== Owned plots ==="));
|
|
||||||
|
// 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<ResourceLocation, Long> 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()) {
|
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 {
|
} else {
|
||||||
for (String pid : ClientBnsState.ownedPlotIds) {
|
for (String pid : ClientBnsState.ownedPlotIds) {
|
||||||
Plot p = Plot.byId(pid);
|
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() {
|
@Override public void alignWidgets() {
|
||||||
@@ -104,13 +142,28 @@ public final class QuestLogScreen extends BaseBnsScreen {
|
|||||||
sb.append("§r");
|
sb.append("§r");
|
||||||
return sb.toString();
|
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 static final class Header extends Widget {
|
||||||
private final String text;
|
private final String text;
|
||||||
Header(Panel parent, String text) { super(parent); this.text = 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) {
|
@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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"screen.bnstoolkit.hub": "Brass and Sigil",
|
"screen.bnstoolkit.hub": "Brass and Sigil",
|
||||||
"screen.bnstoolkit.tier_upgrade": "Civic Tier",
|
"screen.bnstoolkit.tier_upgrade": "Civic Tier",
|
||||||
"screen.bnstoolkit.bounty_board": "Bounty Board",
|
"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.plot_purchase": "Plot Office",
|
||||||
"screen.bnstoolkit.shop_browser": "Counting House",
|
"screen.bnstoolkit.shop_browser": "Counting House",
|
||||||
"screen.bnstoolkit.counting_house": "Counting House"
|
"screen.bnstoolkit.counting_house": "Counting House"
|
||||||
|
|||||||
Reference in New Issue
Block a user