Skip to content

Private lobby toggle donation - #1752

Merged
drillskibo merged 20 commits into
openfrontio:mainfrom
camclark:private-lobby-toggle-donation
Aug 12, 2025
Merged

Private lobby toggle donation#1752
drillskibo merged 20 commits into
openfrontio:mainfrom
camclark:private-lobby-toggle-donation

Conversation

@camclark

@camclark camclark commented Aug 8, 2025

Copy link
Copy Markdown
Contributor

Description:

Resolve #1652

  1. Add the ability to toggle gold donations and troop donations for private lobbies
    2. Add relevant translations.
  2. Refactor canDonate to be specific to gold and troop donations
  3. Add placeholders for singleplayer mode if this is to be extended to support that too.
  4. Add Tests for Donate logic

Screenshots:

image

Private Lobby

Smoke Tests

donatetroopsprivatelobby
Testing Troop Send In Private Lobby

donatetroopsprivatelobby2

Troop Send Complete In Private Lobby

testtradepublicteams
Confirming that public teams still works

Please complete the following:

  • I have added screenshots for all UI updates
  • I process any text displayed to the user through translateText() and I've added it to the en.json file
  • I have added relevant tests to the test directory
  • I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced
  • I have read and accepted the CLA agreement (only required once).

Please put your Discord username so you can be contacted if a bug or regression is found:

DISCORD_USERNAME: cool_clarky

@CLAassistant

CLAassistant commented Aug 8, 2025

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 4 committers have signed the CLA.

✅ camclark
❌ Cameron Clark
❌ drillskibo
❌ scottanderson


Cameron Clark seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Aug 8, 2025

Copy link
Copy Markdown
Contributor

Caution

Review failed

The head commit changed during the review from 2aaf00b to f27fc8c.

Walkthrough

This change introduces separate configuration options and permissions for donating gold and troops in the game. It updates UI components, backend logic, schemas, and tests to support toggling these donation features independently. The donation logic and related interfaces are refactored to handle gold and troop donations separately throughout the codebase.

Changes

Cohort / File(s) Change Summary
Frontend Modals & UI
src/client/HostLobbyModal.ts, src/client/SinglePlayerModal.ts
Added donateGold and donateTroops state properties and UI elements for toggling donation options. Integrated these options into game configuration payloads.
Frontend Graphics & Menus
src/client/graphics/layers/PlayerPanel.ts, src/client/graphics/layers/RadialMenuElements.ts
Refactored donation button logic to use separate flags for gold and troop donation. Updated menu element enabling/disabling conditions to use the new flags.
Backend Logic & Interfaces
src/core/game/Game.ts, src/core/game/PlayerImpl.ts, src/core/GameRunner.ts, src/core/execution/DonateGoldExecution.ts, src/core/execution/DonateTroopExecution.ts
Split single donation permission into canDonateGold and canDonateTroops methods and properties. Updated execution logic to use the new methods.
Configuration & Schemas
src/core/Schemas.ts, src/core/configuration/Config.ts, src/core/configuration/DefaultConfig.ts, src/server/GameManager.ts, src/server/GameServer.ts, src/server/MapPlaylist.ts, tests/util/Setup.ts
Added donateGold and donateTroops to config schemas, interfaces, and default values. Updated config handling in server and test setup.
Localization
resources/lang/debug.json, resources/lang/en.json
Added translation keys for "donate_gold" and "donate_troops" under relevant modal sections.
Testing
tests/Donate.test.ts, tests/client/graphics/RadialMenuElements.test.ts
Added new tests for gold and troop donation logic, including ally and non-ally cases. Updated test mocks to use separate donation flags.

Sequence Diagram(s)

sequenceDiagram
    participant HostLobbyModal
    participant GameServer
    participant GameConfig
    participant Player
    participant UI

    UI->>HostLobbyModal: Toggle "Donate Gold" or "Donate Troops"
    HostLobbyModal->>GameServer: putGameConfig({donateGold, donateTroops})
    GameServer->>GameConfig: Update donateGold, donateTroops
    Player->>GameConfig: Check donateGold(), donateTroops() before donation
    Player->>UI: Enable/disable donation buttons based on config
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
Allow toggling all donations on/off and/or toggling gold/troop donations separately (#1652)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes found.

Possibly related PRs

Suggested labels

Feature - Frontend, Feature - Backend

Suggested reviewers

  • evanpelle
  • scottanderson

Poem

Two buttons now, where once was one,
Gold and troops, their toggles spun.
Host and player, choose your fate,
Give or keep, now separate!
Code refactored, tests anew—
Donations split, more choice for you!
💰🪖✨


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🔭 Outside diff range comments (5)
src/core/execution/DonateGoldExecution.ts (1)

15-17: Update warning to use correct class name

I’ve confirmed there are no leftover canDonate references in the repo. Please adjust the log in DonateGoldExecution:

• File: src/core/execution/DonateGoldExecution.ts, around line 15

-      console.warn(`DonateExecution recipient ${this.recipientID} not found`);
+      console.warn(`DonateGoldExecution recipient ${this.recipientID} not found`);
src/core/execution/DonateTroopExecution.ts (1)

23-26: Guard against zero/negative donation amounts before attempting donation

If recipient is at or above max troops, maxDonation can be ≤ 0. Avoid calling donateTroops in that case to reduce noise and no-op work.

Apply this diff:

   this.recipient = mg.player(this.recipientID);
   this.troops ??= mg.config().defaultDonationAmount(this.sender);
   const maxDonation =
     mg.config().maxTroops(this.recipient) - this.recipient.troops();
-  this.troops = Math.min(this.troops, maxDonation);
+  this.troops = Math.min(this.troops, maxDonation);
+  if (this.troops <= 0) {
+    this.active = false;
+    return;
+  }

Optionally add a defensive early-exit in tick:

   tick(ticks: number): void {
     if (this.troops === null) throw new Error("not initialized");
+    if (this.troops <= 0) {
+      this.active = false;
+      return;
+    }
     if (
       this.sender.canDonateTroops(this.recipient) &&
       this.sender.donateTroops(this.recipient, this.troops)
     ) {

Also applies to: 28-33

src/server/GameServer.ts (1)

80-120: Prevent config changes after game start to avoid desync

Consider guarding updateGameConfig so toggles cannot change mid-game. This keeps all clients in sync and matches typical lobby-only config changes.

Apply:

   public updateGameConfig(gameConfig: Partial<GameConfig>): void {
+    // Disallow updates once the game has started to prevent desyncs
+    if (this._hasStarted) {
+      this.log.warn("updateGameConfig ignored after game start", { gameID: this.id });
+      return;
+    }
src/core/game/PlayerImpl.ts (2)

629-634: Enforce permission in donate and show the actual transferred amount.*

  • donateTroops/donateGold don’t re-check canDonate*. Any caller that bypasses the predicate can still donate.
  • The messages use the requested amount, not the actual transferred amount (removeTroops/removeGold may transfer less).

Apply:

@@
   donateTroops(recipient: Player, troops: number): boolean {
-    if (troops <= 0) return false;
+    if (troops <= 0) return false;
+    if (!this.canDonateTroops(recipient)) return false;
     const removed = this.removeTroops(troops);
     if (removed === 0) return false;
     recipient.addTroops(removed);
@@
-    this.mg.displayMessage(
-      `Sent ${renderTroops(troops)} troops to ${recipient.name()}`,
+    this.mg.displayMessage(
+      `Sent ${renderTroops(removed)} troops to ${recipient.name()}`,
       MessageType.SENT_TROOPS_TO_PLAYER,
       this.id(),
     );
-    this.mg.displayMessage(
-      `Received ${renderTroops(troops)} troops from ${this.name()}`,
+    this.mg.displayMessage(
+      `Received ${renderTroops(removed)} troops from ${this.name()}`,
       MessageType.RECEIVED_TROOPS_FROM_PLAYER,
       recipient.id(),
     );
@@
   donateGold(recipient: Player, gold: Gold): boolean {
-    if (gold <= 0n) return false;
+    if (gold <= 0n) return false;
+    if (!this.canDonateGold(recipient)) return false;
     const removed = this.removeGold(gold);
     if (removed === 0n) return false;
     recipient.addGold(removed);
@@
-    this.mg.displayMessage(
-      `Sent ${renderNumber(gold)} gold to ${recipient.name()}`,
+    this.mg.displayMessage(
+      `Sent ${renderNumber(removed)} gold to ${recipient.name()}`,
       MessageType.SENT_GOLD_TO_PLAYER,
       this.id(),
     );
-    this.mg.displayMessage(
-      `Received ${renderNumber(gold)} gold from ${this.name()}`,
+    this.mg.displayMessage(
+      `Received ${renderNumber(removed)} gold from ${this.name()}`,
       MessageType.RECEIVED_GOLD_FROM_PLAYER,
       recipient.id(),
-      gold,
+      removed,
     );

If you keep shared cooldown, make it explicit in code comments for clarity.

Also applies to: 636-646, 649-653, 656-666


575-600: Fix Public FFA rule, display messages, missing guards, and shared cooldown

We need to tighten up four areas in PlayerImpl.ts:

• Public FFA rule in canDonateGold/canDonateTroops
• Guard calls in donateGold/donateTroops
• Display messages using the actual sent amount
• Separate cooldowns (typed union + pruning) instead of one shared list


  1. Update Public FFA checks in both canDonateGold and canDonateTroops (lines 581–588 & 607–614):
-  if (
-    recipient.type() === PlayerType.Human &&
-    this.mg.config().gameConfig().gameMode === GameMode.FFA &&
-    this.mg.config().gameConfig().gameType === GameType.Public
-  ) {
-    return false;
-  }
+  const isPublicFFA =
+    this.mg.config().gameConfig().gameMode === GameMode.FFA &&
+    this.mg.config().gameConfig().gameType === GameType.Public;
+  // Block only human↔human donations in Public FFA
+  if (isPublicFFA &&
+      this.type() === PlayerType.Human &&
+      recipient.type() === PlayerType.Human) {
+    return false;
+  }
  1. Add guard at the top of both donateGold and donateTroops (lines 649 & 629):
  donateGold(recipient: Player, gold: Gold): boolean {
+   if (!this.canDonateGold(recipient)) return false;
    if (gold <= 0n) return false;
    
  }
  
  donateTroops(recipient: Player, troops: number): boolean {
+   if (!this.canDonateTroops(recipient)) return false;
    if (troops <= 0) return false;
    
  }
  1. Fix display messages to use the actual removed amount:
- this.mg.displayMessage(
-   `Sent ${renderNumber(gold)} gold to ${recipient.name()}`, …
+ this.mg.displayMessage(
+   `Sent ${renderNumber(removed)} gold to ${recipient.name()}`, …

- this.mg.displayMessage(
-   `Sent ${renderTroops(troops)} troops to ${recipient.name()}`, …
+ this.mg.displayMessage(
+   `Sent ${renderTroops(removed)} troops to ${recipient.name()}`, …
  1. Replace sentDonations: Donation[] with a typed union & prune expired entries:
type DonationKind = 'gold' | 'troops';

interface DonationRecord {
  recipient: Player;
  tick: Tick;
  kind: DonationKind;
}

private sentDonations: DonationRecord[] = [];

private pruneSentDonations(): void {
  const cutoff = this.mg.ticks() - this.mg.config().donateCooldown();
  this.sentDonations = this.sentDonations.filter(d => d.tick > cutoff);
}

// In canDonateGold/canDonateTroops:
this.pruneSentDonations();
const onCooldown = this.sentDonations.some(d =>
  d.kind === 'gold' /* or 'troops' */ &&
  d.recipient === recipient &&
  this.mg.ticks() - d.tick < this.mg.config().donateCooldown()
);

// In donateGold/donateTroops:
this.sentDonations.push({ recipient, tick: this.mg.ticks(), kind: 'gold' });

These changes ensure the Public FFA rule is correct, prevent bypass by calling donate* directly, display accurate numbers, and keep cooldown tracking efficient.

🧹 Nitpick comments (10)
src/core/execution/DonateTroopExecution.ts (1)

16-16: Nit: clarify log message prefix

Message says “DonateExecution …” but the class is DonateTroopsExecution. Minor clarity fix.

- console.warn(`DonateExecution recipient ${this.recipientID} not found`);
+ console.warn(`[DonateTroopsExecution] recipient ${this.recipientID} not found`);
src/client/SinglePlayerModal.ts (1)

40-43: donateGold/donateTroops states added but not exposed — confirm placeholder

These booleans are not surfaced in the UI (no checkboxes). If this is an intentional placeholder for future singleplayer, add a short TODO to reduce confusion.

Optional tiny note:

-  @state() private donateGold: boolean = false;
+  // TODO: Placeholder for future singleplayer options. Not exposed in UI yet.
+  @state() private donateGold: boolean = false;
-  @state() private donateTroops: boolean = false;
+  // TODO: Placeholder for future singleplayer options. Not exposed in UI yet.
+  @state() private donateTroops: boolean = false;
resources/lang/ar.json (2)

104-104: Arabic value for donate_troops looks malformed (missing space/odd wording)

It reads as one glued word and uses “contribution” wording. To stay consistent with this file’s earlier usage (“ally_donate”: تبرع بالجنود), consider aligning:

-    "donate_troops": "المساهمةبقوات",
+    "donate_troops": "تبرع بالجنود",

If localization policy prefers leaving non-English updates to translators, alternatively keep the English placeholder here and let the translation team adjust later.


175-175: Arabic value for donate_troops in host_modal likely needs the same fix as single_modal

Suggest matching the established wording used elsewhere in this file:

-    "donate_troops": "المساهمةبقوات",
+    "donate_troops": "تبرع بالجنود",

Or keep English placeholder pending translator review, per project localization process.

src/client/graphics/layers/RadialMenuElements.ts (2)

211-212: Good: use specific permission flag (canDonateGold).

This matches the feature split and avoids over-enabling the gold donate action.

For extra safety/clarity (matching other items like ally_target), consider guarding null selection explicitly:

-  disabled: (params: MenuElementParams) =>
-    !params.playerActions?.interaction?.canDonateGold,
+  disabled: (params: MenuElementParams) => {
+    if (params.selected === null) return true;
+    return !params.playerActions?.interaction?.canDonateGold;
+  },

224-225: Good: use specific permission flag (canDonateTroops).

Consistent with canDonateGold change.

Mirror the explicit null-selection guard as above for consistency:

-  disabled: (params: MenuElementParams) =>
-    !params.playerActions?.interaction?.canDonateTroops,
+  disabled: (params: MenuElementParams) => {
+    if (params.selected === null) return true;
+    return !params.playerActions?.interaction?.canDonateTroops;
+  },
src/client/graphics/layers/PlayerPanel.ts (1)

425-450: Accessibility: add aria-label/title and distinct alt text for donate buttons

Small a11y win: label the buttons and make alt text specific (gold vs troops). Reuse existing i18n keys.

 ${canDonateTroops
-  ? html`<button
+  ? html`<button
+      aria-label=${translateText("single_modal.donate_troops")}
+      title=${translateText("single_modal.donate_troops")}
       @click=${(e: MouseEvent) =>
         this.handleDonateTroopClick(e, myPlayer, other)}
       class="w-10 h-10 flex items-center justify-center
            bg-opacity-50 bg-gray-700 hover:bg-opacity-70
            text-white rounded-lg transition-colors"
     >
       <img
         src=${donateTroopIcon}
-        alt="Donate"
+        alt=${translateText("single_modal.donate_troops")}
         class="w-6 h-6"
       />
     </button>`
   : ""}
 ${canDonateGold
-  ? html`<button
+  ? html`<button
+      aria-label=${translateText("single_modal.donate_gold")}
+      title=${translateText("single_modal.donate_gold")}
       @click=${(e: MouseEvent) =>
         this.handleDonateGoldClick(e, myPlayer, other)}
       class="w-10 h-10 flex items-center justify-center
           bg-opacity-50 bg-gray-700 hover:bg-opacity-70
           text-white rounded-lg transition-colors"
     >
-      <img src=${donateGoldIcon} alt="Donate" class="w-6 h-6" />
+      <img
+        src=${donateGoldIcon}
+        alt=${translateText("single_modal.donate_gold")}
+        class="w-6 h-6"
+      />
     </button>`
   : ""}
src/client/HostLobbyModal.ts (2)

44-46: State for donation toggles added: sync with server defaults after lobby creation

Good addition. One risk: on opening an existing lobby, local defaults (false) could overwrite server defaults on first PUT. Consider fetching the current GameInfo (or config) right after lobby creation (or when opening for edit) and initializing donateGold/donateTroops from it before the first PUT.


599-603: Reduce handler duplication (optional)

Both handlers set a boolean and call putGameConfig(). You can DRY this up with a tiny helper to keep things idiomatic and readable.

Example:

private setFlag(next: boolean, apply: () => void) {
  apply();
  this.putGameConfig();
}

// Usage:
private handleDonateGoldChange = (e: Event) =>
  this.setFlag((e.target as HTMLInputElement).checked, () => {
    this.donateGold = Boolean((e.target as HTMLInputElement).checked);
  });

private handleDonateTroopsChange = (e: Event) =>
  this.setFlag((e.target as HTMLInputElement).checked, () => {
    this.donateTroops = Boolean((e.target as HTMLInputElement).checked);
  });

Also applies to: 609-613

tests/Donate.test.ts (1)

1-254: Add explicit tests for toggles disabled paths (both gold and troops)

Please add two small tests asserting that when donateGold: false (and allied), a donation attempt fails/no transfer, and likewise for donateTroops: false. This guards the new config flags.

I can draft these tests if you want me to push a follow‑up commit.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b0701c and d11d318.

📒 Files selected for processing (47)
  • resources/lang/ar.json (2 hunks)
  • resources/lang/bg.json (2 hunks)
  • resources/lang/bn.json (2 hunks)
  • resources/lang/cs.json (2 hunks)
  • resources/lang/da.json (2 hunks)
  • resources/lang/de.json (2 hunks)
  • resources/lang/debug.json (2 hunks)
  • resources/lang/en.json (2 hunks)
  • resources/lang/eo.json (2 hunks)
  • resources/lang/es.json (2 hunks)
  • resources/lang/fi.json (2 hunks)
  • resources/lang/fr.json (2 hunks)
  • resources/lang/gl.json (2 hunks)
  • resources/lang/he.json (2 hunks)
  • resources/lang/hi.json (2 hunks)
  • resources/lang/it.json (2 hunks)
  • resources/lang/ja.json (2 hunks)
  • resources/lang/ko.json (2 hunks)
  • resources/lang/nl.json (2 hunks)
  • resources/lang/pl.json (2 hunks)
  • resources/lang/pt-BR.json (2 hunks)
  • resources/lang/ru.json (2 hunks)
  • resources/lang/sh.json (2 hunks)
  • resources/lang/sl.json (2 hunks)
  • resources/lang/sv-SE.json (2 hunks)
  • resources/lang/tp.json (2 hunks)
  • resources/lang/tr.json (2 hunks)
  • resources/lang/uk.json (2 hunks)
  • resources/lang/zh-CN.json (2 hunks)
  • src/client/HostLobbyModal.ts (5 hunks)
  • src/client/SinglePlayerModal.ts (2 hunks)
  • src/client/graphics/layers/PlayerPanel.ts (3 hunks)
  • src/client/graphics/layers/RadialMenuElements.ts (2 hunks)
  • src/core/GameRunner.ts (1 hunks)
  • src/core/Schemas.ts (1 hunks)
  • src/core/configuration/Config.ts (1 hunks)
  • src/core/configuration/DefaultConfig.ts (1 hunks)
  • src/core/execution/DonateGoldExecution.ts (1 hunks)
  • src/core/execution/DonateTroopExecution.ts (1 hunks)
  • src/core/game/Game.ts (2 hunks)
  • src/core/game/PlayerImpl.ts (2 hunks)
  • src/server/GameManager.ts (1 hunks)
  • src/server/GameServer.ts (1 hunks)
  • src/server/MapPlaylist.ts (1 hunks)
  • tests/Donate.test.ts (1 hunks)
  • tests/client/graphics/RadialMenuElements.test.ts (1 hunks)
  • tests/util/Setup.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (16)
📓 Common learnings
Learnt from: Egraveline
PR: openfrontio/OpenFrontIO#1012
File: src/core/execution/UpgradeStructureExecution.ts:49-54
Timestamp: 2025-06-05T02:34:45.899Z
Learning: In the upgrade system, gold deduction for structure upgrades is handled internally by the `upgradeUnit` method in PlayerImpl, not in the UpgradeStructureExecution class. The UpgradeStructureExecution only needs to check if the player has sufficient gold before calling `upgradeUnit`.
📚 Learning: 2025-05-31T18:15:03.445Z
Learnt from: 1brucben
PR: openfrontio/OpenFrontIO#977
File: src/core/execution/AttackExecution.ts:123-125
Timestamp: 2025-05-31T18:15:03.445Z
Learning: The removeTroops function in PlayerImpl.ts already prevents negative troop counts by using minInt(this._troops, toInt(troops)) to ensure it never removes more troops than available.

Applied to files:

  • src/core/execution/DonateTroopExecution.ts
  • src/client/graphics/layers/RadialMenuElements.ts
  • src/core/configuration/DefaultConfig.ts
  • tests/util/Setup.ts
  • src/server/GameManager.ts
  • src/core/GameRunner.ts
  • src/client/SinglePlayerModal.ts
  • src/core/configuration/Config.ts
  • src/client/graphics/layers/PlayerPanel.ts
  • tests/Donate.test.ts
  • src/core/game/PlayerImpl.ts
  • src/core/game/Game.ts
  • src/client/HostLobbyModal.ts
📚 Learning: 2025-06-02T14:27:37.609Z
Learnt from: andrewNiziolek
PR: openfrontio/OpenFrontIO#1007
File: resources/lang/de.json:115-115
Timestamp: 2025-06-02T14:27:37.609Z
Learning: For OpenFrontIO project: When localization keys are renamed in language JSON files, the maintainers separate technical changes from translation content updates. They wait for community translators to update the actual translation values rather than attempting to translate in the same PR. This allows technical changes to proceed while ensuring accurate translations from native speakers.

Applied to files:

  • resources/lang/bn.json
  • resources/lang/pl.json
  • resources/lang/de.json
  • resources/lang/pt-BR.json
  • resources/lang/debug.json
  • resources/lang/sv-SE.json
  • resources/lang/ja.json
  • resources/lang/hi.json
  • resources/lang/gl.json
  • resources/lang/tr.json
  • resources/lang/zh-CN.json
  • resources/lang/uk.json
  • resources/lang/en.json
  • resources/lang/it.json
  • resources/lang/nl.json
  • resources/lang/eo.json
  • resources/lang/tp.json
  • resources/lang/he.json
  • resources/lang/bg.json
  • resources/lang/fr.json
  • resources/lang/ru.json
  • resources/lang/ar.json
  • resources/lang/ko.json
  • resources/lang/fi.json
  • resources/lang/da.json
  • resources/lang/sh.json
  • resources/lang/es.json
  • resources/lang/sl.json
  • resources/lang/cs.json
📚 Learning: 2025-05-30T03:53:52.231Z
Learnt from: scottanderson
PR: openfrontio/OpenFrontIO#949
File: resources/lang/en.json:8-10
Timestamp: 2025-05-30T03:53:52.231Z
Learning: For the OpenFrontIO project, do not suggest updating translation files in resources/lang/*.json except for en.json. The project has a dedicated translation team that handles all other locale files.

Applied to files:

  • resources/lang/bn.json
  • resources/lang/pl.json
  • resources/lang/de.json
  • resources/lang/pt-BR.json
  • resources/lang/debug.json
  • resources/lang/sv-SE.json
  • resources/lang/ja.json
  • resources/lang/hi.json
  • resources/lang/gl.json
  • resources/lang/tr.json
  • resources/lang/zh-CN.json
  • resources/lang/uk.json
  • resources/lang/en.json
  • resources/lang/it.json
  • resources/lang/nl.json
  • resources/lang/eo.json
  • resources/lang/tp.json
  • resources/lang/he.json
  • resources/lang/bg.json
  • resources/lang/fr.json
  • resources/lang/ru.json
  • resources/lang/ar.json
  • resources/lang/ko.json
  • resources/lang/fi.json
  • resources/lang/da.json
  • resources/lang/sh.json
  • resources/lang/es.json
  • resources/lang/sl.json
  • resources/lang/cs.json
📚 Learning: 2025-06-05T02:34:45.899Z
Learnt from: Egraveline
PR: openfrontio/OpenFrontIO#1012
File: src/core/execution/UpgradeStructureExecution.ts:49-54
Timestamp: 2025-06-05T02:34:45.899Z
Learning: In the upgrade system, gold deduction for structure upgrades is handled internally by the `upgradeUnit` method in PlayerImpl, not in the UpgradeStructureExecution class. The UpgradeStructureExecution only needs to check if the player has sufficient gold before calling `upgradeUnit`.

Applied to files:

  • src/core/execution/DonateGoldExecution.ts
  • src/core/GameRunner.ts
  • src/client/graphics/layers/PlayerPanel.ts
  • src/core/game/PlayerImpl.ts
  • src/core/game/Game.ts
📚 Learning: 2025-06-02T14:27:23.893Z
Learnt from: andrewNiziolek
PR: openfrontio/OpenFrontIO#1007
File: resources/lang/he.json:138-138
Timestamp: 2025-06-02T14:27:23.893Z
Learning: andrewNiziolek's project uses community translation for internationalization. When updating map names or other user-facing text, they update the keys programmatically but wait for community translators to provide accurate translations in each language rather than using machine translations.

Applied to files:

  • resources/lang/pl.json
  • resources/lang/eo.json
📚 Learning: 2025-07-12T08:41:35.101Z
Learnt from: Aotumuri
PR: openfrontio/OpenFrontIO#1357
File: resources/lang/de.json:523-540
Timestamp: 2025-07-12T08:41:35.101Z
Learning: In OpenFrontIO project localization files, always check the en.json source file before flagging potential spelling errors in other language files, as some keys may intentionally use non-standard spellings that need to be consistent across all translations.

Applied to files:

  • resources/lang/pl.json
  • resources/lang/de.json
  • resources/lang/pt-BR.json
  • resources/lang/debug.json
  • resources/lang/ja.json
  • resources/lang/gl.json
  • resources/lang/zh-CN.json
  • resources/lang/uk.json
  • resources/lang/en.json
  • resources/lang/nl.json
  • resources/lang/eo.json
  • resources/lang/bg.json
  • resources/lang/fr.json
  • resources/lang/ru.json
  • resources/lang/fi.json
  • resources/lang/da.json
  • resources/lang/es.json
📚 Learning: 2025-06-16T03:03:59.778Z
Learnt from: VariableVince
PR: openfrontio/OpenFrontIO#1192
File: src/client/graphics/layers/RadialMenuElements.ts:312-314
Timestamp: 2025-06-16T03:03:59.778Z
Learning: In RadialMenuElements.ts, when fixing undefined params errors in subMenu functions, use explicit checks like `if (params === undefined || params.selected === null)` rather than optional chaining, as it makes the intent clearer and matches the specific error scenarios where params can be undefined during spawn phase operations.

Applied to files:

  • src/client/graphics/layers/RadialMenuElements.ts
  • tests/client/graphics/RadialMenuElements.test.ts
📚 Learning: 2025-06-10T09:56:44.473Z
Learnt from: Ble4Ch
PR: openfrontio/OpenFrontIO#1063
File: src/core/configuration/PastelThemeDark.ts:53-53
Timestamp: 2025-06-10T09:56:44.473Z
Learning: In ColorAllocator class in src/core/configuration/Colors.ts, the correct method names are assignColor(id: string): Colord for general color assignment and assignTeamColor(team: Team): Colord for team-specific colors. There are no assignPlayerColor() or assignBotColor() methods.

Applied to files:

  • src/client/graphics/layers/RadialMenuElements.ts
  • src/core/configuration/DefaultConfig.ts
  • tests/client/graphics/RadialMenuElements.test.ts
  • src/core/GameRunner.ts
  • src/client/SinglePlayerModal.ts
  • src/core/configuration/Config.ts
  • src/client/graphics/layers/PlayerPanel.ts
  • src/core/game/PlayerImpl.ts
  • src/core/game/Game.ts
  • src/client/HostLobbyModal.ts
📚 Learning: 2025-05-19T06:00:38.007Z
Learnt from: scottanderson
PR: openfrontio/OpenFrontIO#784
File: src/core/game/StatsImpl.ts:125-134
Timestamp: 2025-05-19T06:00:38.007Z
Learning: In StatsImpl.ts, unused parameters in boat/stats-related methods are intentionally kept for future use and shouldn't be removed.

Applied to files:

  • tests/util/Setup.ts
📚 Learning: 2025-06-09T02:20:43.637Z
Learnt from: VariableVince
PR: openfrontio/OpenFrontIO#1110
File: src/client/Main.ts:293-295
Timestamp: 2025-06-09T02:20:43.637Z
Learning: In src/client/Main.ts, during game start in the handleJoinLobby callback, UI elements are hidden using direct DOM manipulation with classList.add("hidden") for consistency. This includes modals, buttons, and error divs. The codebase follows this pattern rather than using component APIs for hiding elements during game transitions.

Applied to files:

  • tests/client/graphics/RadialMenuElements.test.ts
  • src/client/SinglePlayerModal.ts
  • src/client/graphics/layers/PlayerPanel.ts
  • src/client/HostLobbyModal.ts
📚 Learning: 2025-07-12T08:42:02.109Z
Learnt from: Aotumuri
PR: openfrontio/OpenFrontIO#1357
File: resources/lang/zh_cn.json:527-539
Timestamp: 2025-07-12T08:42:02.109Z
Learning: In OpenFrontIO project, the territory pattern key "embelem" is the correct spelling used in all language files, not "emblem". This is the technical identifier that appears in en.json and must be consistent across all localization files.

Applied to files:

  • resources/lang/eo.json
📚 Learning: 2025-05-16T12:06:01.732Z
Learnt from: Aotumuri
PR: openfrontio/OpenFrontIO#709
File: src/client/Main.ts:276-296
Timestamp: 2025-05-16T12:06:01.732Z
Learning: In the OpenFrontIO codebase, `checkPermission()` function's return values need to be handled with defensive checks using `Array.isArray()`, even though its TypeScript signature indicates it returns arrays. Removing these checks breaks functionality.

Applied to files:

  • src/client/graphics/layers/PlayerPanel.ts
📚 Learning: 2025-06-22T05:48:19.241Z
Learnt from: scottanderson
PR: openfrontio/OpenFrontIO#786
File: src/client/TerritoryPatternsModal.ts:337-338
Timestamp: 2025-06-22T05:48:19.241Z
Learning: In src/client/TerritoryPatternsModal.ts, the bit shifting operators (<<) used in coordinate calculations with decoder.getScale() are intentional and should not be changed to multiplication. The user scottanderson confirmed this is functioning as intended.

Applied to files:

  • src/client/graphics/layers/PlayerPanel.ts
📚 Learning: 2025-05-21T04:10:33.435Z
Learnt from: scottanderson
PR: openfrontio/OpenFrontIO#784
File: src/core/game/StatsImpl.ts:34-38
Timestamp: 2025-05-21T04:10:33.435Z
Learning: In the codebase, PlayerStats is defined as `z.infer<typeof PlayerStatsSchema>` where PlayerStatsSchema has `.optional()` applied at the object level, making PlayerStats a union type that already includes undefined (PlayerStats | undefined).

Applied to files:

  • src/core/Schemas.ts
📚 Learning: 2025-05-21T04:10:33.435Z
Learnt from: scottanderson
PR: openfrontio/OpenFrontIO#784
File: src/core/game/StatsImpl.ts:34-38
Timestamp: 2025-05-21T04:10:33.435Z
Learning: In the codebase, PlayerStats is defined as a type inferred from a Zod schema that is marked as optional, which means PlayerStats already includes undefined as a possible type (PlayerStats | undefined).

Applied to files:

  • src/core/Schemas.ts
🧬 Code Graph Analysis (3)
src/server/GameServer.ts (1)
src/server/MapPlaylist.ts (1)
  • gameConfig (72-95)
src/client/graphics/layers/PlayerPanel.ts (1)
src/core/game/PlayerImpl.ts (2)
  • canDonateGold (575-600)
  • canDonateTroops (602-627)
src/core/game/PlayerImpl.ts (3)
src/core/game/AllianceRequestImpl.ts (1)
  • recipient (17-19)
src/core/game/AllianceImpl.ts (1)
  • recipient (30-32)
src/core/game/Game.ts (1)
  • Player (498-632)
🪛 GitHub Check: 🔍 ESLint
tests/util/Setup.ts

[failure] 69-69:
Expected object keys to be in ascending order. 'donateTroops' should be before 'infiniteTroops'.


[failure] 67-67:
Expected object keys to be in ascending order. 'donateGold' should be before 'infiniteGold'.

src/server/GameManager.ts

[failure] 52-52:
Expected object keys to be in ascending order. 'donateTroops' should be before 'infiniteTroops'.


[failure] 50-50:
Expected object keys to be in ascending order. 'donateGold' should be before 'infiniteGold'.

src/server/MapPlaylist.ts

[failure] 90-90:
Expected object keys to be in ascending order. 'donateTroops' should be before 'infiniteTroops'.


[failure] 88-88:
Expected object keys to be in ascending order. 'donateGold' should be before 'infiniteGold'.

src/core/Schemas.ts

[failure] 157-157:
Expected object keys to be in ascending order. 'donateTroops' should be before 'infiniteTroops'.


[failure] 155-155:
Expected object keys to be in ascending order. 'donateGold' should be before 'infiniteGold'.

🔇 Additional comments (59)
tests/client/graphics/RadialMenuElements.test.ts (1)

132-134: No leftover canDonate references found
Ran a repo-wide search for canDonate and only saw the new canDonateGold / canDonateTroops flags in tests, core logic, and UI layers. Everything aligns with the refactor.

src/core/execution/DonateGoldExecution.ts (1)

28-30: Correct permission check for gold donations

Using canDonateGold(recipient) is the right change after the split.

resources/lang/pt-BR.json (1)

92-92: Add donate_gold key: looks good

Key name matches en.json and the new feature. No changes requested for non-English locales per project convention.

Also applies to: 148-148

src/core/execution/DonateTroopExecution.ts (1)

31-31: Correct API usage

Switch to canDonateTroops is the right move and aligns with the new split permissions.

resources/lang/debug.json (1)

97-99: Debug keys for donation toggles: looks good

Both keys added in single and host modals. Consistent with the new feature flags.

Also applies to: 152-154

resources/lang/en.json (1)

133-135: Add English strings for donation toggles: looks good

Strings are clear and match existing casing (“Infinite gold”, “Infinite troops”). No further changes needed.

Also applies to: 217-219

resources/lang/sv-SE.json (2)

130-133: Keys added correctly (single player modal).

New keys donate_gold and donate_troops are present with consistent naming. Content review is deferred to translators per project policy.


211-214: Keys added correctly (host lobby modal).

New keys donate_gold and donate_troops align with the UI toggles. No issues on structure; translation content left to the localization team.

src/core/configuration/Config.ts (1)

85-88: Interface extension looks good.

Adding donateGold() and donateTroops() keeps config accessors consistent with existing style.

Please confirm DefaultConfig implements both getters and that GameConfig schema includes donateGold/donateTroops (build should fail otherwise, but a quick ack helps).

src/server/GameManager.ts (1)

42-55: Confirm default differences are intended (public vs private).

Here (private games) donateGold/donateTroops default to false, while MapPlaylist (public games) sets them true. Looks intentional for lobby control—please confirm this is by design.

resources/lang/tr.json (2)

92-95: Keys added correctly (single player modal).

donate_gold and donate_troops are present with consistent keys. Deferring content to localization team as per project practice.


149-152: Keys added correctly (host lobby modal).

Key names align with other locales and new UI toggles. No structural issues.

resources/lang/pl.json (1)

102-104: Locale keys and code integration for donation toggles validated — ready to merge

Entries for "donate_gold" and "donate_troops" in resources/lang/pl.json (lines 102–104) are correctly formatted. Matching keys exist in resources/lang/en.json, and code references in Schemas.ts, Transport.ts, ExecutionManager.ts, RadialMenuElements.ts, HostLobbyModal.ts, and HelpModal.ts confirm proper integration. No further changes needed.

resources/lang/uk.json (1)

130-133: Donation keys added in correct places — looks good

Names match expected: donate_gold, donate_troops in both single_modal and host_modal.

Also applies to: 211-213

resources/lang/zh-CN.json (1)

130-133: Chinese locale: donation toggles present and well-placed

Keys align with the new feature and follow existing option ordering.

Also applies to: 211-213

resources/lang/fr.json (1)

130-133: French locale updates align with feature — OK

Correct keys, correct sections, consistent naming.

Also applies to: 211-213

resources/lang/hi.json (1)

99-102: Hindi locale: donate keys added as required

Key names and placement are correct for the new toggles.

Also applies to: 159-162

resources/lang/nl.json (2)

130-132: Translation keys placement correct in nl.json

I’ve verified that:

  • resources/lang/en.json includes the same donate_gold and donate_troops keys.
  • All UI code paths reference these keys (Transport.ts, HostLobbyModal.ts, HelpModal.ts, RadialMenuElements.ts, Schemas.ts, ExecutionManager.ts).

No changes needed. Everything lines up.


211-213: Check donation key placement under modals
I couldn’t locate any single_modal or host_modal sections containing the new donate_gold/donate_troops keys. Please manually verify in resources/lang/nl.json (lines 211–213) and across all resources/lang/*.json files that:

  • donate_gold and donate_troops are nested under the correct JSON object (single_modal for the lobby UI and host_modal for hosts)
  • They appear immediately before or after infinite_troops, matching the existing ordering in other locales

Example of the expected grouping in nl.json:

"host_modal": {
  …,
  "infinite_troops": "Oneindige troepen",
  "donate_gold":      "Goud doneren",
  "donate_troops":    "Troepen doneren"
  
}
src/server/GameServer.ts (1)

96-104: Verified donateGold & donateTroops coverage — ready to merge

All uses of donateGold and donateTroops are in place:

  • Schema & types:
    • src/core/Schemas.ts (z.boolean)
    • src/core/game/Game.ts (method signatures)
  • Player logic: src/core/game/PlayerImpl.ts (checks & methods)
  • Config interfaces & defaults:
    • src/core/configuration/Config.ts
    • src/core/configuration/DefaultConfig.ts
  • Server defaults & update:
    • src/server/MapPlaylist.ts
    • src/server/GameManager.ts
    • src/server/GameServer.ts (updateGameConfig)
  • Client UI components
  • All related tests in tests/Donate.test.ts and setup helpers

No missing references or defaults—LGTM.

src/client/SinglePlayerModal.ts (1)

456-459: donateGold & donateTroops defaults are intentional – no changes needed

I verified in src/client/SinglePlayerModal.ts that both flags are declared as

@state() private donateGold: boolean = false;
@state() private donateTroops: boolean = false;

and there’s no visible toggle in the single-player UI. Keeping them false-by-default matches the multiplayer schema parity and current design.

resources/lang/it.json (2)

187-190: Add missing troop donation keys to other locale files

To keep all locale files in sync with the Italian update, please add the infinite_troops and donate_troops keys (using placeholder values) right after each donate_gold entry in these files:

• resources/lang/tr.json
• resources/lang/pt-BR.json
• resources/lang/debug.json

Example diff for each file (insert after the donate_gold line):

     "donate_gold": "...",
+    "infinite_troops": "host_modal.infinite_troops",
+    "donate_troops": "host_modal.donate_troops",
⛔ Skipped due to learnings
Learnt from: andrewNiziolek
PR: openfrontio/OpenFrontIO#1007
File: resources/lang/de.json:115-115
Timestamp: 2025-06-02T14:27:37.609Z
Learning: For OpenFrontIO project: When localization keys are renamed in language JSON files, the maintainers separate technical changes from translation content updates. They wait for community translators to update the actual translation values rather than attempting to translate in the same PR. This allows technical changes to proceed while ensuring accurate translations from native speakers.
Learnt from: scottanderson
PR: openfrontio/OpenFrontIO#949
File: resources/lang/en.json:8-10
Timestamp: 2025-05-30T03:53:52.231Z
Learning: For the OpenFrontIO project, do not suggest updating translation files in resources/lang/*.json except for en.json. The project has a dedicated translation team that handles all other locale files.
Learnt from: Aotumuri
PR: openfrontio/OpenFrontIO#1357
File: resources/lang/de.json:523-540
Timestamp: 2025-07-12T08:41:35.101Z
Learning: In OpenFrontIO project localization files, always check the en.json source file before flagging potential spelling errors in other language files, as some keys may intentionally use non-standard spellings that need to be consistent across all translations.
Learnt from: Aotumuri
PR: openfrontio/OpenFrontIO#1357
File: resources/lang/zh_cn.json:527-539
Timestamp: 2025-07-12T08:42:02.109Z
Learning: In OpenFrontIO project, the territory pattern key "embelem" is the correct spelling used in all language files, not "emblem". This is the technical identifier that appears in en.json and must be consistent across all localization files.

115-118: Missing host_modal translation keys

I verified that resources/lang/en.json defines donate_gold and donate_troops under both single_modal and host_modal, and client code calls them in each context. In resources/lang/it.json you only added the single_modal entries. Please add the matching keys under the host_modal section so the Italian file stays in parity:

File: resources/lang/it.json
Location: inside the "host_modal": { … } object

Suggested diff:

--- a/resources/lang/it.json
+++ b/resources/lang/it.json
@@ "host_modal": {
   // … existing host_modal keys …
+  "donate_gold":   "Dona oro",
+  "donate_troops": "Dona truppe",
   // … next host_modal keys …
}
⛔ Skipped due to learnings
Learnt from: andrewNiziolek
PR: openfrontio/OpenFrontIO#1007
File: resources/lang/de.json:115-115
Timestamp: 2025-06-02T14:27:37.609Z
Learning: For OpenFrontIO project: When localization keys are renamed in language JSON files, the maintainers separate technical changes from translation content updates. They wait for community translators to update the actual translation values rather than attempting to translate in the same PR. This allows technical changes to proceed while ensuring accurate translations from native speakers.
Learnt from: Aotumuri
PR: openfrontio/OpenFrontIO#1357
File: resources/lang/de.json:523-540
Timestamp: 2025-07-12T08:41:35.101Z
Learning: In OpenFrontIO project localization files, always check the en.json source file before flagging potential spelling errors in other language files, as some keys may intentionally use non-standard spellings that need to be consistent across all translations.
Learnt from: scottanderson
PR: openfrontio/OpenFrontIO#949
File: resources/lang/en.json:8-10
Timestamp: 2025-05-30T03:53:52.231Z
Learning: For the OpenFrontIO project, do not suggest updating translation files in resources/lang/*.json except for en.json. The project has a dedicated translation team that handles all other locale files.
Learnt from: Aotumuri
PR: openfrontio/OpenFrontIO#1357
File: resources/lang/ja.json:0-0
Timestamp: 2025-07-12T06:35:10.457Z
Learning: In OpenFrontIO project, "giantworldmap" is the correct localization key name for the giant world map, used consistently across all language files and TypeScript code. Do not suggest renaming this key.
Learnt from: Aotumuri
PR: openfrontio/OpenFrontIO#1357
File: resources/lang/zh_cn.json:527-539
Timestamp: 2025-07-12T08:42:02.109Z
Learning: In OpenFrontIO project, the territory pattern key "embelem" is the correct spelling used in all language files, not "emblem". This is the technical identifier that appears in en.json and must be consistent across all localization files.
resources/lang/de.json (2)

126-128: New keys added in single player modal look correct and consistent with en.json

Placement after infinite_gold and before infinite_troops is consistent. No further action.


207-209: New keys added in host modal look correct and consistent with en.json

Ordering matches other locales. Good to go.

src/core/GameRunner.ts (1)

193-195: Verified removal of legacy canDonate; UI layers updated

  • No matches for canDonate remain in the codebase.
  • Both canDonateGold and canDonateTroops are used in UI layers:
    • src/client/graphics/layers/RadialMenuElements.ts (lines 211, 224)
    • src/client/graphics/layers/PlayerPanel.ts (lines 235, 236, 425, 440)

The permission split looks clean and complete.

resources/lang/eo.json (2)

130-133: Single player modal: keys added correctly

Keys and placement look consistent with other locales.


211-214: Host modal: keys added correctly

Looks good and consistent.

resources/lang/he.json (2)

126-128: Potential spacing issue in Hebrew strings (donation labels) in single player modal

Observed: "לתרוםזהב" and "לתרוםכוחות" (no space). Host modal uses a space for gold ("לתרום זהב"). For consistency/legibility, please have the translation team confirm whether these should be "לתרום זהב" and "לתרום כוחות".

Per project practice, leave content updates to translators. Please ping Hebrew translators to review these two keys in single_modal.


207-209: Potential spacing inconsistency in Hebrew strings in host modal

"donate_gold" has a space ("לתרום זהב"), but "donate_troops" is "לתרוםכוחות" (no space). Please ask the translators to confirm whether it should be "לתרום כוחות".

Following locale policy, do not edit here—just flagging for translator review.

resources/lang/tp.json (2)

102-105: Single player modal: keys added and placed correctly

Consistent with the new feature set. No issues.


173-176: Host modal: keys added and placed correctly

Looks good and consistent with other locales.

resources/lang/ar.json (2)

102-102: LGTM: donate_gold key added in single_modal

Key name and placement look correct.


173-173: LGTM: donate_gold key added in host_modal

Key name and placement look correct.

resources/lang/es.json (1)

115-118: LGTM: Spanish donate_ keys added and consistent across both modals*

"Donar oro" and "Donar tropas" read correctly and match usage in both sections.

Also applies to: 187-190

resources/lang/fi.json (1)

130-133: LGTM: Finnish donate_ keys added and consistent*

"Lahjoita kultaa" / "Lahjoita joukkoja" look correct and aligned across single and host modals.

Also applies to: 211-214

resources/lang/da.json (1)

211-214: LGTM: Danish donate_ keys in host_modal*

Values look correct and consistent (“Doner guld” / “Bidrag med tropper”).

resources/lang/cs.json (2)

187-190: Host modal keys added properly.

donate_gold and donate_troops are present under host_modal. Looks good.


115-118: All locale updates are validated and ready to merge

  • resources/lang/cs.json was parsed as valid JSON and includes the new keys at lines 115 & 117.
  • resources/lang/en.json defines donate_gold and donate_troops under both single_modal and host_modal.
  • Code references for these flags exist in core schemas, execution manager, transport layer, and UI modals.

No further changes required.

resources/lang/ko.json (2)

130-133: Korean single_modal keys added correctly.

Matches new feature split; leaving translation content as-is per locale workflow.

Use the same script from cs.json comment to validate JSON and presence in en.json.


211-214: Korean host_modal keys added correctly.

Consistent naming and placement. No further action.

resources/lang/ja.json (2)

130-133: Japanese single_modal keys added correctly.

donate_gold and donate_troops align with the new toggles. No translation feedback here (non-en handled by translators).

Use the validation script from cs.json comment if needed.


211-213: Japanese host_modal keys added correctly.

Placement and naming are consistent with other locales.

src/client/graphics/layers/RadialMenuElements.ts (1)

572-586: Donate menu items appear unreachable — they’re not added to any menu.

allyDonateGoldElement and allyDonateTroopsElement are defined but never included in root or any submenu, so players cannot access them from the radial menu.

Add them when the selected player is an ally and the relevant permission is true:

   const menuItems: (MenuElement | null)[] = [
     infoMenuElement,
     boatMenuElement,
     ally,
   ];

+  // Show donate actions for allies when allowed
+  if (params.selected?.isAlliedWith(params.myPlayer)) {
+    const canDonateGold = !!params.playerActions?.interaction?.canDonateGold;
+    const canDonateTroops = !!params.playerActions?.interaction?.canDonateTroops;
+    if (canDonateGold) menuItems.push(allyDonateGoldElement);
+    if (canDonateTroops) menuItems.push(allyDonateTroopsElement);
+  }

To confirm current reachability and usage across the codebase:

#!/bin/bash
set -euo pipefail

# Find where these elements are referenced
rg -n 'allyDonateGoldElement|allyDonateTroopsElement|ally_donate_gold|ally_donate_troops'

# Ensure the handler methods exist and are wired
rg -n 'handleDonateGold|handleDonateTroops' src

# Sanity: check that interaction flags are set by the view-layer
rg -n 'canDonateGold|canDonateTroops' src

Likely an incorrect or invalid review comment.

resources/lang/bg.json (2)

130-130: Keys added in single_modal; please let translators verify string quality

The new keys are in the right place. The donate_troops value looks concatenated (“Предоставяненавойски”). Recommend a localization pass rather than changing it here, per project policy.

Also applies to: 132-132


211-211: Keys added in host_modal; please let translators verify string quality

Same note as above: donate_troops appears to miss spacing. Please route to the translation team; no code changes in this PR.

Also applies to: 213-213

src/client/graphics/layers/PlayerPanel.ts (1)

235-236: LGTM: split permission flags improve clarity

Using separate canDonateGold and canDonateTroops is clear and lines up with core checks.

resources/lang/gl.json (2)

130-130: Keys added in single_modal; please have localization verify

Placement looks good. donate_troops value (“Achegartropas”) seems to miss a space. Please leave as-is here and let translators adjust.

Also applies to: 132-132


211-211: Keys added in host_modal; translation check recommended

Same potential spacing issue for donate_troops. Forward to translation team; no change requested in this PR.

Also applies to: 213-213

resources/lang/sh.json (2)

99-101: LGTM: single_modal keys added consistently

Keys and placement match the new feature flags.


160-162: LGTM: host_modal keys added consistently

Consistent with single_modal and other locales.

resources/lang/sl.json (2)

211-213: Host modal keys added correctly.

No structural issues detected. Mirrors single_modal.


130-132: Confirmed matching keys in en.json

  • “donate_gold” found at lines 133, 217 in resources/lang/en.json
  • “donate_troops” found at lines 135, 219 in resources/lang/en.json

No further changes needed.

resources/lang/ru.json (2)

130-132: Single-player modal: keys added in the correct place.

Shape-only change acknowledged.


211-213: Host modal: keys added in the correct place.

Duplicates the single modal structure.

src/core/game/Game.ts (1)

596-598: Old canDonate API fully replaced—safe to remove legacy method
All call sites and tests now use canDonateGold and canDonateTroops; no references to the old canDonate remain. No further action needed.

src/client/HostLobbyModal.ts (3)

645-648: Including donation flags in payload: LGTM

Fields are correctly added to the PUT body. Matches the schema updates described in the PR.


415-429: Translation key verified: no action needed

The host_modal.donate_troops key is present in all locale files under resources/lang (e.g., in en.json, zh-CN.json, etc.). No further changes are required here.


383-397: Translation key confirmed
The key host_modal.donate_gold is already defined in resources/lang/en.json (and mirrored in every locale), so no missing translation will appear at runtime. No further action needed.

Comment thread resources/lang/bn.json Outdated
Comment thread resources/lang/da.json Outdated
Comment thread src/core/configuration/DefaultConfig.ts
Comment thread src/core/game/Game.ts
Comment thread src/core/Schemas.ts Outdated
Comment thread tests/Donate.test.ts
Comment thread tests/Donate.test.ts Outdated
Comment thread tests/Donate.test.ts Outdated
Comment thread tests/Donate.test.ts Outdated
Comment thread tests/util/Setup.ts Outdated
@github-project-automation github-project-automation Bot moved this from Triage to Development in OpenFront Release Management Aug 8, 2025

@drillskibo drillskibo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Please remove all changes to translation files except adding keys to en.json
  • Please fix ESLint errors (keys not in order in objects)

@drillskibo
drillskibo disabled auto-merge August 12, 2025 01:45
@drillskibo
drillskibo enabled auto-merge August 12, 2025 01:45
@drillskibo
drillskibo removed the request for review from Duwibi August 12, 2025 01:46
@scottanderson
scottanderson dismissed Duwibi’s stale review August 12, 2025 01:47

The review comment has been addressed

@drillskibo
drillskibo added this pull request to the merge queue Aug 12, 2025
Merged via the queue into openfrontio:main with commit 8a41919 Aug 12, 2025
7 of 8 checks passed
@github-project-automation github-project-automation Bot moved this from Development to Complete in OpenFront Release Management Aug 12, 2025
@camclark
camclark deleted the private-lobby-toggle-donation branch August 12, 2025 06:51
@scottanderson scottanderson added Gameplay Features that affect gameplay and removed Gameplay Features that affect gameplay labels Aug 18, 2025
evanpelle pushed a commit that referenced this pull request Sep 4, 2025
Resolve #1652

1. Add the ability to toggle **gold donations** and **troop donations**
for private lobbies
~2. Add relevant translations.~
3. Refactor `canDonate` to be specific to gold and troop donations
4. Add placeholders for singleplayer mode if this is to be extended to
support that too.
5. Add Tests for Donate logic
<img width="1643" height="1788" alt="image"
src="https://github.com/user-attachments/assets/82b93400-a1f0-45f0-8b2b-a7f78dc0c3e9"
/>

_Private Lobby_

![donatetroopsprivatelobby](https://github.com/user-attachments/assets/c6690bbc-958e-48a1-9cf1-e2b361dfb1b2)
_Testing Troop Send In Private Lobby_

![donatetroopsprivatelobby2](https://github.com/user-attachments/assets/698c7603-6b4b-4da7-91ab-7bdc38bb49a5)

_Troop Send Complete In Private Lobby_

![testtradepublicteams](https://github.com/user-attachments/assets/1010332c-3f38-4644-9218-46aa7141f578)
Confirming that public teams still works

- [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
- [X] I have read and accepted the CLA agreement (only required once).
regression is found:

DISCORD_USERNAME: cool_clarky

---------

Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
Co-authored-by: Drills Kibo <59177241+drillskibo@users.noreply.github.com>
TheGiraffe3 pushed a commit that referenced this pull request Sep 4, 2025
## Description:
Resolve #1652 

1. Add the ability to toggle **gold donations** and **troop donations**
for private lobbies
~2. Add relevant translations.~
3. Refactor `canDonate` to be specific to gold and troop donations 
4. Add placeholders for singleplayer mode if this is to be extended to
support that too.
5. Add Tests for Donate logic

### Screenshots:
<img width="1643" height="1788" alt="image"
src="https://github.com/user-attachments/assets/82b93400-a1f0-45f0-8b2b-a7f78dc0c3e9"
/>

_Private Lobby_

### Smoke Tests


![donatetroopsprivatelobby](https://github.com/user-attachments/assets/c6690bbc-958e-48a1-9cf1-e2b361dfb1b2)
_Testing Troop Send In Private Lobby_


![donatetroopsprivatelobby2](https://github.com/user-attachments/assets/698c7603-6b4b-4da7-91ab-7bdc38bb49a5)

_Troop Send Complete In Private Lobby_


![testtradepublicteams](https://github.com/user-attachments/assets/1010332c-3f38-4644-9218-46aa7141f578)
Confirming that public teams still works


## 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
- [X] I have read and accepted the CLA agreement (only required once).

## Please put your Discord username so you can be contacted if a bug or
regression is found:

DISCORD_USERNAME: cool_clarky

---------

Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
Co-authored-by: Drills Kibo <59177241+drillskibo@users.noreply.github.com>
mokizzz pushed a commit to mokizzz/OpenFrontIO that referenced this pull request Sep 4, 2025
## Description:
Resolve openfrontio#1652 

1. Add the ability to toggle **gold donations** and **troop donations**
for private lobbies
~2. Add relevant translations.~
3. Refactor `canDonate` to be specific to gold and troop donations 
4. Add placeholders for singleplayer mode if this is to be extended to
support that too.
5. Add Tests for Donate logic

### Screenshots:
<img width="1643" height="1788" alt="image"
src="https://github.com/user-attachments/assets/82b93400-a1f0-45f0-8b2b-a7f78dc0c3e9"
/>

_Private Lobby_

### Smoke Tests


![donatetroopsprivatelobby](https://github.com/user-attachments/assets/c6690bbc-958e-48a1-9cf1-e2b361dfb1b2)
_Testing Troop Send In Private Lobby_


![donatetroopsprivatelobby2](https://github.com/user-attachments/assets/698c7603-6b4b-4da7-91ab-7bdc38bb49a5)

_Troop Send Complete In Private Lobby_


![testtradepublicteams](https://github.com/user-attachments/assets/1010332c-3f38-4644-9218-46aa7141f578)
Confirming that public teams still works


## 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
- [X] I have read and accepted the CLA agreement (only required once).

## Please put your Discord username so you can be contacted if a bug or
regression is found:

DISCORD_USERNAME: cool_clarky

---------

Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
Co-authored-by: Drills Kibo <59177241+drillskibo@users.noreply.github.com>
@coderabbitai coderabbitai Bot mentioned this pull request Sep 9, 2025
4 tasks
@coderabbitai coderabbitai Bot mentioned this pull request Oct 7, 2025
4 tasks
This was referenced Oct 30, 2025
@coderabbitai coderabbitai Bot mentioned this pull request Nov 11, 2025
4 tasks
This was referenced Nov 26, 2025
@coderabbitai coderabbitai Bot mentioned this pull request Jan 1, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Gameplay Features that affect gameplay

Projects

Status: Complete

Development

Successfully merging this pull request may close these issues.

Private lobby setting - Toggle donation

5 participants