From bce27f1a6b666ce88c5ed118889fdc04dd5e07bb Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 14 Oct 2025 13:55:30 -0700 Subject: [PATCH 1/6] don't show ads if skin has been purchased, fixed ads not getting removed sometimes (#2196) ## Description: Now checks if player has any "pattern" flares and does not show ads. Also set visible=false when hiding ads, sometimes the ads were not getting destroyed properly. ## 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: evan --- src/client/GutterAds.ts | 1 + src/client/Main.ts | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/client/GutterAds.ts b/src/client/GutterAds.ts index f0f2f779f..b47f2939b 100644 --- a/src/client/GutterAds.ts +++ b/src/client/GutterAds.ts @@ -49,6 +49,7 @@ export class GutterAds extends LitElement { } public hide(): void { + this.isVisible = false; console.log("hiding GutterAds"); this.destroyAds(); this.requestUpdate(); diff --git a/src/client/Main.ts b/src/client/Main.ts index 37ae29027..2d61e78b6 100644 --- a/src/client/Main.ts +++ b/src/client/Main.ts @@ -350,6 +350,13 @@ class Client { "Sharing this ID will allow others to view your game history and stats.", ); this.patternsModal.onUserMe(userMeResponse); + const flares = (userMeResponse.player.flares ?? []).filter((flare) => + flare.startsWith("pattern:"), + ); + if (flares.length > 0) { + console.log("Hiding gutter ads because you have patterns"); + this.gutterAds.hide(); + } } }; From 090b0756b7a36bb0ec796b1093a94c9700a1ec33 Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 14 Oct 2025 16:10:32 -0700 Subject: [PATCH 2/6] Allow donation in team games. (#2198) ## Description: Was a bug disabling donation in public team games. ## 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: evan --- src/server/MapPlaylist.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/MapPlaylist.ts b/src/server/MapPlaylist.ts index 3ce5dfd65..acb14cce0 100644 --- a/src/server/MapPlaylist.ts +++ b/src/server/MapPlaylist.ts @@ -79,8 +79,8 @@ export class MapPlaylist { // Create the default public game config (from your GameManager) return { - donateGold: false, - donateTroops: false, + donateGold: mode === GameMode.Team, + donateTroops: mode === GameMode.Team, gameMap: map, maxPlayers: config.lobbyMaxPlayers(map, mode, playerTeams), gameType: GameType.Public, From 5579fcf91b31ca5eb3243fe484d552193f95b21e Mon Sep 17 00:00:00 2001 From: evanpelle Date: Tue, 14 Oct 2025 18:01:16 -0700 Subject: [PATCH 3/6] update win_modal territory pattern to say go ad free --- resources/lang/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/en.json b/resources/lang/en.json index c31101bc9..a8a130767 100644 --- a/resources/lang/en.json +++ b/resources/lang/en.json @@ -500,7 +500,7 @@ }, "win_modal": { "support_openfront": "Support OpenFront!", - "territory_pattern": "Purchase a territory pattern to support OpenFront!", + "territory_pattern": "Purchase a territory skin to go ad-free!", "died": "You died", "your_team": "Your team won!", "other_team": "{team} team has won!", From 9ab35a04365f8381b20759a66417b4c366264caf Mon Sep 17 00:00:00 2001 From: evanpelle Date: Tue, 14 Oct 2025 19:05:53 -0700 Subject: [PATCH 4/6] bugfix: don't use bigint for zod schema as it causes json parsing issues --- src/client/Transport.ts | 2 +- src/core/Schemas.ts | 2 +- src/core/execution/DonateGoldExecution.ts | 8 ++++++-- tests/Donate.test.ts | 4 ++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/client/Transport.ts b/src/client/Transport.ts index 3cb6c71c6..b5d9bf9b1 100644 --- a/src/client/Transport.ts +++ b/src/client/Transport.ts @@ -496,7 +496,7 @@ export class Transport { type: "donate_gold", clientID: this.lobbyConfig.clientID, recipient: event.recipient.id(), - gold: event.gold, + gold: event.gold ? Number(event.gold) : null, }); } diff --git a/src/core/Schemas.ts b/src/core/Schemas.ts index 270cc2297..b13f8ac17 100644 --- a/src/core/Schemas.ts +++ b/src/core/Schemas.ts @@ -278,7 +278,7 @@ export const EmbargoIntentSchema = BaseIntentSchema.extend({ export const DonateGoldIntentSchema = BaseIntentSchema.extend({ type: z.literal("donate_gold"), recipient: ID, - gold: z.bigint().nullable(), + gold: z.number().nullable(), }); export const DonateTroopIntentSchema = BaseIntentSchema.extend({ diff --git a/src/core/execution/DonateGoldExecution.ts b/src/core/execution/DonateGoldExecution.ts index 214c7e915..51b60ce0a 100644 --- a/src/core/execution/DonateGoldExecution.ts +++ b/src/core/execution/DonateGoldExecution.ts @@ -1,15 +1,19 @@ import { Execution, Game, Gold, Player, PlayerID } from "../game/Game"; +import { toInt } from "../Util"; export class DonateGoldExecution implements Execution { private recipient: Player; private active = true; + private gold: Gold; constructor( private sender: Player, private recipientID: PlayerID, - private gold: Gold | null, - ) {} + goldNum: number | null, + ) { + this.gold = toInt(goldNum ?? 0); + } init(mg: Game, ticks: number): void { if (!mg.hasPlayer(this.recipientID)) { diff --git a/tests/Donate.test.ts b/tests/Donate.test.ts index bbbccd4f9..966f9d493 100644 --- a/tests/Donate.test.ts +++ b/tests/Donate.test.ts @@ -120,7 +120,7 @@ describe("Donate gold to an ally", () => { donor.addGold(6000n); const donorGoldBefore = donor.gold(); const recipientGoldBefore = recipient.gold(); - game.addExecution(new DonateGoldExecution(donor, recipientInfo.id, 5000n)); + game.addExecution(new DonateGoldExecution(donor, recipientInfo.id, 5000)); for (let i = 0; i < 5; i++) { game.executeNextTick(); @@ -242,7 +242,7 @@ describe("Donate Gold to a non ally", () => { const donorGoldBefore = donor.gold(); const recipientGoldBefore = donor.gold(); - game.addExecution(new DonateGoldExecution(donor, recipientInfo.id, 5000n)); + game.addExecution(new DonateGoldExecution(donor, recipientInfo.id, 5000)); game.executeNextTick(); // Gold should not be donated since they are not allies From eea8db7a06aed50c005db35ad55ece026f7a3643 Mon Sep 17 00:00:00 2001 From: evanpelle Date: Tue, 14 Oct 2025 19:51:58 -0700 Subject: [PATCH 5/6] delete warship when player is afk --- src/core/execution/WarshipExecution.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/execution/WarshipExecution.ts b/src/core/execution/WarshipExecution.ts index f573a8a47..67cb17aef 100644 --- a/src/core/execution/WarshipExecution.ts +++ b/src/core/execution/WarshipExecution.ts @@ -55,6 +55,11 @@ export class WarshipExecution implements Execution { this.warship.delete(); return; } + if (this.warship.owner().isDisconnected()) { + this.warship.delete(); + return; + } + const hasPort = this.warship.owner().unitCount(UnitType.Port) > 0; if (hasPort) { this.warship.modifyHealth(1); From 349e7acb616df325461a9a2970583bfc2361d445 Mon Sep 17 00:00:00 2001 From: evanpelle Date: Tue, 14 Oct 2025 20:07:05 -0700 Subject: [PATCH 6/6] bugfix: have Privilege support flags --- src/server/Privilege.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/server/Privilege.ts b/src/server/Privilege.ts index 380dcfb14..402b4c3c7 100644 --- a/src/server/Privilege.ts +++ b/src/server/Privilege.ts @@ -41,6 +41,12 @@ export class PrivilegeCheckerImpl implements PrivilegeChecker { return { type: "forbidden", reason: "invalid color: " + e.message }; } } + if (refs.flag) { + cosmetics.flag = cosmetics.flag = refs.flag.replace( + /[^a-z0-9-_ ()]/gi, + "", + ); + } return { type: "allowed", cosmetics }; }