From c594487f5ea1bf6df2e8fc6c48c2896a11dcafc8 Mon Sep 17 00:00:00 2001
From: FloPinguin <25036848+FloPinguin@users.noreply.github.com>
Date: Fri, 6 Mar 2026 05:48:03 +0100
Subject: [PATCH] =?UTF-8?q?Starting=20gold=20input=20in=20millions=20with?=
=?UTF-8?q?=20decimal=20support=20=E2=9C=A8=20(#3349)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## Description:
**Starting gold input: use millions**
Changes the starting gold input in singleplayer and host lobby modals to
accept values in millions (e.g. enter `5` for 5M gold). Supports
decimals like `6.6` for 6.6M. The value is multiplied by 1,000,000
before being sent to the game config.
- Label updated to "Starting Gold (Millions)"
- Input uses float parsing with min 0.1, matching gold multiplier
behavior
- JoinLobbyModal shows clean values without unnecessary decimals (e.g.
"5M" not "5.00M")
Previous
Now
## Please complete the following:
- [X] I have added screenshots for all UI updates
- [X] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [X] I have added relevant tests to the test directory
- [X] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
FloPinguin
---
resources/lang/en.json | 4 ++--
src/client/HostLobbyModal.ts | 29 ++++++++++++++++++-----------
src/client/JoinLobbyModal.ts | 5 +++--
src/client/SinglePlayerModal.ts | 31 ++++++++++++++++++++-----------
src/client/Utils.ts | 8 +++++++-
5 files changed, 50 insertions(+), 27 deletions(-)
diff --git a/resources/lang/en.json b/resources/lang/en.json
index df702d507..60754c189 100644
--- a/resources/lang/en.json
+++ b/resources/lang/en.json
@@ -201,8 +201,8 @@
"options_changed_no_achievements": "Custom settings – achievements disabled",
"gold_multiplier": "Gold multiplier",
"gold_multiplier_placeholder": "2.0x",
- "starting_gold": "Starting gold",
- "starting_gold_placeholder": "5000000"
+ "starting_gold": "Starting Gold (Millions)",
+ "starting_gold_placeholder": "5"
},
"token_login_modal": {
"title": "Logging in...",
diff --git a/src/client/HostLobbyModal.ts b/src/client/HostLobbyModal.ts
index f82ad5b8e..f55e869f9 100644
--- a/src/client/HostLobbyModal.ts
+++ b/src/client/HostLobbyModal.ts
@@ -195,18 +195,18 @@ export class HostLobbyModal extends BaseModal {
.labelKey=${"single_modal.starting_gold"}
.checked=${this.startingGold}
.inputId=${"starting-gold-value"}
- .inputMin=${0}
- .inputMax=${1000000000}
- .inputStep=${100000}
+ .inputMin=${0.1}
+ .inputMax=${1000}
+ .inputStep=${"any"}
.inputValue=${this.startingGoldValue}
.inputAriaLabel=${translateText("single_modal.starting_gold")}
.inputPlaceholder=${translateText(
"single_modal.starting_gold_placeholder",
)}
- .defaultInputValue=${5000000}
- .minValidOnEnable=${0}
+ .defaultInputValue=${5}
+ .minValidOnEnable=${0.1}
.onToggle=${this.handleStartingGoldToggle}
- .onInput=${this.handleStartingGoldValueChanges}
+ .onChange=${this.handleStartingGoldValueChanges}
.onKeyDown=${this.handleStartingGoldValueKeyDown}
>`,
];
@@ -650,12 +650,17 @@ export class HostLobbyModal extends BaseModal {
private handleStartingGoldValueChanges = (e: Event) => {
const input = e.target as HTMLInputElement;
- const value = parseBoundedIntegerFromInput(input, {
- min: 0,
- max: 1000000000,
+ const value = parseBoundedFloatFromInput(input, {
+ min: 0.1,
+ max: 1000,
});
- this.startingGoldValue = value;
+ if (value === undefined) {
+ this.startingGoldValue = undefined;
+ input.value = "";
+ } else {
+ this.startingGoldValue = value;
+ }
this.putGameConfig();
};
@@ -787,7 +792,9 @@ export class HostLobbyModal extends BaseModal {
? this.goldMultiplierValue
: undefined,
startingGold:
- this.startingGold === true ? this.startingGoldValue : undefined,
+ this.startingGold === true && this.startingGoldValue !== undefined
+ ? Math.round(this.startingGoldValue * 1_000_000)
+ : undefined,
} satisfies Partial,
},
bubbles: true,
diff --git a/src/client/JoinLobbyModal.ts b/src/client/JoinLobbyModal.ts
index 892fe7537..7834045b7 100644
--- a/src/client/JoinLobbyModal.ts
+++ b/src/client/JoinLobbyModal.ts
@@ -432,9 +432,10 @@ export class JoinLobbyModal extends BaseModal {
(m) => html`
`,
)}
diff --git a/src/client/SinglePlayerModal.ts b/src/client/SinglePlayerModal.ts
index ba7508107..ce4d2ec3d 100644
--- a/src/client/SinglePlayerModal.ts
+++ b/src/client/SinglePlayerModal.ts
@@ -210,18 +210,18 @@ export class SinglePlayerModal extends BaseModal {
.labelKey=${"single_modal.starting_gold"}
.checked=${this.startingGold}
.inputId=${"starting-gold-value"}
- .inputMin=${0}
- .inputMax=${1000000000}
- .inputStep=${100000}
+ .inputMin=${0.1}
+ .inputMax=${1000}
+ .inputStep=${"any"}
.inputValue=${this.startingGoldValue}
.inputAriaLabel=${translateText("single_modal.starting_gold")}
.inputPlaceholder=${translateText(
"single_modal.starting_gold_placeholder",
)}
- .defaultInputValue=${5000000}
- .minValidOnEnable=${0}
+ .defaultInputValue=${5}
+ .minValidOnEnable=${0.1}
.onToggle=${this.handleStartingGoldToggle}
- .onInput=${this.handleStartingGoldValueChanges}
+ .onChange=${this.handleStartingGoldValueChanges}
.onKeyDown=${this.handleStartingGoldValueKeyDown}
>`,
];
@@ -591,12 +591,17 @@ export class SinglePlayerModal extends BaseModal {
private handleStartingGoldValueChanges = (e: Event) => {
const input = e.target as HTMLInputElement;
- const value = parseBoundedIntegerFromInput(input, {
- min: 0,
- max: 1000000000,
+ const value = parseBoundedFloatFromInput(input, {
+ min: 0.1,
+ max: 1000,
});
- this.startingGoldValue = value;
+ if (value === undefined) {
+ this.startingGoldValue = undefined;
+ input.value = "";
+ } else {
+ this.startingGoldValue = value;
+ }
};
private handleGameModeSelection(value: GameMode) {
@@ -685,7 +690,11 @@ export class SinglePlayerModal extends BaseModal {
? { goldMultiplier: this.goldMultiplierValue }
: {}),
...(this.startingGold && this.startingGoldValue !== undefined
- ? { startingGold: this.startingGoldValue }
+ ? {
+ startingGold: Math.round(
+ this.startingGoldValue * 1_000_000,
+ ),
+ }
: {}),
},
lobbyCreatedAt: Date.now(), // ms; server should be authoritative in MP
diff --git a/src/client/Utils.ts b/src/client/Utils.ts
index 92b106a38..7f394b564 100644
--- a/src/client/Utils.ts
+++ b/src/client/Utils.ts
@@ -115,6 +115,8 @@ export interface ModifierInfo {
badgeParams?: Record;
/** The raw value if applicable (e.g. startingGold amount) */
value?: number;
+ /** Pre-formatted display string (used instead of renderNumber when provided) */
+ formattedValue?: string;
}
/**
@@ -150,13 +152,17 @@ export function getActiveModifiers(
});
}
if (modifiers.startingGold) {
+ const millions = parseFloat(
+ (modifiers.startingGold / 1_000_000).toPrecision(12),
+ );
result.push({
labelKey: "host_modal.starting_gold",
badgeKey: "public_game_modifier.starting_gold",
badgeParams: {
- amount: Math.round(modifiers.startingGold / 1_000_000),
+ amount: millions,
},
value: modifiers.startingGold,
+ formattedValue: `${millions}M`,
});
}
return result;