Skip to content

Oil Rig Feature PR#3711

Open
ldnelson16 wants to merge 19 commits intoopenfrontio:mainfrom
ldnelson16:oil-rig
Open

Oil Rig Feature PR#3711
ldnelson16 wants to merge 19 commits intoopenfrontio:mainfrom
ldnelson16:oil-rig

Conversation

@ldnelson16
Copy link
Copy Markdown

@ldnelson16 ldnelson16 commented Apr 18, 2026

Resolves #(3129)

Description:

THE OIL RIG FEATURE:

Features Added:

  • new structure added: Oil Rig
    • Oil Rig icon art added [x]
    • Unit tests added
  • new terrain: Oil
    • map World (+oil) has also been added with world-accurate oil deposits
  • new class of train: Freight
    • used to transport oil to nearest factory for cash-in

How does the new feature work:
Oil rigs can be placed onto oil terrain, and spawn a freight class train every 10 seconds which pathfinds to the user's nearest factory (it will not spawn unless the user has a connected factory). At the factory, the train grants value proportional to the amount of stacked oil rigs that the freight train came from. The oil rig fits into the existing {port, railroad} category of structure cost since they are all economic structures.

Code changes made to implement:
Terrain:

  • Map generation was made to adapt any (24,24,24) pixel in the inputted map to the map generated as an oil terrain (which was added as a new Terrain type).

Maps:

  • A new map was created which is a world accurate map of the world map with oil deposites, name: World (+oil)

Tests:

  • Various tests were updated to test the gold delivery of oil rigs, test their ability to be added to train networks, etc. There was also a specific unit test created for oil rigs at tests/OilRigExecution.test.ts. Game was also tested rigorously in development mode.

Structures:

  • New oil rig structure and accompanying execution was added to src/core/OilRigExecution.ts, required art was added to various locations, translations and text for structures was also added.

UI Images:

Screenshot from 2026-04-17 19-11-30
Build Wheel
Screenshot from 2026-04-17 19-10-49
Build Menu Hover
Screenshot from 2026-04-17 19-10-27
Oil Rig Close Icon
Screenshot from 2026-04-17 19-10-13
Oil Rig Far Icon + Money Animation
Screenshot from 2026-04-17 19-09-23
Build Menu Icon
Screenshot from 2026-04-17 19-09-15
Oil Rig Far Icon
Screenshot from 2026-04-17 19-07-25

Oil Terrain on New World Map

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

Discord username: lukewinsfantasy

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 18, 2026

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 18, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f93b1a12-d9bb-4887-910b-263e9ec9f184

📥 Commits

Reviewing files that changed from the base of the PR and between 9050b93 and 3741730.

📒 Files selected for processing (1)
  • src/core/game/GameUpdates.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/core/game/GameUpdates.ts

Walkthrough

Adds an Oil Rig feature and a "World (+oil)" map: map assets and generator tooling, oil terrain and tile classification, oil-rig execution spawning freight trains for periodic gold, client UI and rendering updates, configuration and defaults, and tests for placement, income, and assets.

Changes

Cohort / File(s) Summary
Map generator & assets
map-generator/main.go, map-generator/map_generator.go, map-generator/requirements.txt, map-generator/assets/maps/worldoil/apply_oil_reference.py, map-generator/assets/maps/worldoil/info.json, resources/maps/worldoil/manifest.json
Added World (+oil) map entries, Pillow dependency, a Python tool to transfer oil overlays, and map manifest/info files.
Core types & configuration
src/core/game/Game.ts, src/core/game/GameMap.ts, src/core/game/GameUpdates.ts, src/core/StatsSchemas.ts, src/core/configuration/Config.ts, src/core/configuration/DefaultConfig.ts, src/core/configuration/PastelTheme.ts, src/core/configuration/PastelThemeDark.ts
Introduced TerrainType.Oil, UnitType.OilRig, GameMapType.WorldOil, TrainMission union, bonus icon support, oil income config methods, and theme colors for oil.
Oil rig logic & trains
src/core/execution/OilRigExecution.ts, src/core/execution/TrainExecution.ts, src/core/execution/ConstructionExecution.ts, src/core/execution/FactoryExecution.ts, src/core/execution/nation/NationStructureBehavior.ts, src/core/execution/nation/NationNukeBehavior.ts
New OilRigExecution, train mission "freight", construction wiring, factory/station discovery, AI placement scoring, and nuke weighting for oil rigs.
Rail, stations & delivery
src/core/game/RailNetworkImpl.ts, src/core/game/TrainStation.ts
Treat OilRig as station-capable, add cluster nearest-factory search and railroad distance; freight stop handling unloads cargo and credits oil income.
Player & spawn behavior
src/core/game/PlayerImpl.ts, src/core/game/GameMap.ts, src/core/game/UserSettings.ts
Player.addGold accepts optional icon; added oilRigSpawn helper; default keybind buildOilRig set.
Client UI & input
src/client/HelpModal.ts, src/client/InputHandler.ts, src/client/JoinLobbyModal.ts, src/client/UserSettingModal.ts, src/client/components/GameConfigSettings.ts, src/client/components/map/MapPicker.ts, src/server/MapPlaylist.ts
Added Oil Rig entries to help, keybinds, lobby text, user settings UI, game config unit options, featured maps, and server playlist frequency.
Client graphics & indicators
src/client/graphics/SpriteLoader.ts, src/client/graphics/layers/StructureDrawingUtils.ts, src/client/graphics/layers/StructureLayer.ts, src/client/graphics/layers/PlayerInfoOverlay.ts, src/client/graphics/layers/BuildMenu.ts, src/client/graphics/layers/UnitDisplay.ts, src/client/graphics/layers/UILayer.ts, src/client/graphics/layers/FxLayer.ts, src/client/graphics/layers/DynamicUILayer.ts, src/client/graphics/layers/TerrainLayer.ts, src/client/graphics/ui/TextIndicator.ts
Rendered Oil Rig (septagon shape), build menu/unit UI, freight tint for loaded trains, oil-drop icon and indicators, progress bar support for OilRig, and terrain smoothing change.
Schemas, defaults & costs
src/core/StatsSchemas.ts, src/core/configuration/DefaultConfig.ts
Added "oilr" other-unit mapping and default config methods for oil income/timing; included OilRig in cost escalation logic.
Tests
tests/OilRigExecution.test.ts, tests/NationStructureBehavior.test.ts, tests/economy/ConstructionGold.test.ts, tests/core/game/TrainStation.test.ts, tests/MapConsistency.test.ts, tests/TranslationSystem.test.ts
New and updated tests for OilRig execution and delivery, placement scoring, shared construction cost escalation, train station behavior, map-asset consistency (allowing overlay files), and increased translation test timeout.
Localization
resources/lang/*.json (many files)
Added build_oil_rig and build_oil_rig_desc across locales; English includes map.worldoil, unit_type.oil_rig, and unit labels.
Runtime & unit internals
src/core/game/UnitImpl.ts, src/core/execution/AttackExecution.ts, src/core/execution/FactoryExecution.ts, src/core/game/GameUpdates.ts
Integrated OilRig into unit lifecycle stats, attack handling (as Plains), factory nearby-structure logic, and bonus-event updates.

Sequence Diagram(s)

sequenceDiagram
    participant OilRig as OilRigExecution
    participant Station as TrainStation
    participant Rail as RailNetworkImpl
    participant Factory as FactoryExecution
    participant Owner as Player

    rect rgba(100,150,200,0.5)
    Note over OilRig,Owner: Oil rig periodic income flow

    OilRig->>OilRig: tick() at configured interval
    OilRig->>Station: ensure station exists / create if missing
    Station-->>OilRig: station reference
    OilRig->>Rail: get cluster for station
    Rail-->>OilRig: cluster
    OilRig->>Rail: find nearest owned factory in cluster
    Rail-->>OilRig: factory station (if any)
    OilRig->>OilRig: spawn TrainExecution(mission: "freight", loaded: true)
    end

    rect rgba(150,200,100,0.5)
    Note over Factory,Owner: Freight delivery & payment

    Factory->>Factory: onTrainStop() for freight
    Factory->>Owner: addGold(amount, tile, icon: "oil")
    Owner-->>Factory: emit BonusEventUpdate(icon: "oil")
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🛢️ On maps where hidden black fields gleam,
A septagon rig wakes the rail-bound dream,
Trains haul freight through iron and loam,
Factories hum and gold finds home,
New maps, new rigs — the world goes steam.

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title "Oil Rig Feature PR" is vague and generic, using non-descriptive terms that don't convey specific details about what was implemented. Use a more specific title that highlights the main feature, such as "Add Oil Rig structure with freight trains and oil terrain" or "Implement Oil Rig feature with new terrain type and World (+oil) map".
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly explains the Oil Rig feature, including new structures, terrain, trains, gameplay mechanics, code changes, tests, and UI additions related to the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (7)
src/core/execution/nation/NationStructureBehavior.ts (2)

459-462: ⚠️ Potential issue | 🟠 Major

Sample oil tiles directly for Oil Rig placement.

OilRig currently samples 25 random territory tiles and then filters with canBuild(). Since oil deposits are sparse and Oil Rigs must be built on oil terrain, nations can fail to build even when they own valid oil tiles. Sample owned oil tiles for this unit type.

Proposed fix
     const tiles =
       type === UnitType.Port
         ? this.randCoastalTileArray(25)
+        : type === UnitType.OilRig
+          ? this.randOilTileArray(25)
         : randTerritoryTileArray(this.random, this.game, this.player, 25);
   private randCoastalTileArray(numTiles: number): TileRef[] {
     const shared = this._sharedWaterComponents;
     const tiles = Array.from(this.player.borderTiles()).filter((t) => {
       if (!this.game.isShore(t)) return false;
       if (shared === null) return false;
@@
     return Array.from(this.arraySampler(tiles, numTiles));
   }
+
+  private randOilTileArray(numTiles: number): TileRef[] {
+    const tiles = Array.from(this.player.tiles()).filter(
+      (tile) => this.game.terrainType(tile) === TerrainType.Oil,
+    );
+    return Array.from(this.arraySampler(tiles, numTiles));
+  }

Also applies to: 591-617

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/execution/nation/NationStructureBehavior.ts` around lines 459 - 462,
The current selection of candidate tiles for building structures uses a generic
territory sampler (randTerritoryTileArray) and then relies on canBuild(), which
causes OilRig to miss sparse oil tiles; update the logic in
NationStructureBehavior where tiles is chosen (the branch using UnitType.Port
and the cases handling OilRig around the 591-617 region) so that when the unit
type is OilRig you sample only tiles that are both owned by this.player and have
oil (e.g., add/use a helper like randOwnedOilTileArray(count) or filter
randTerritoryTileArray(this.random, this.game, this.player, count) by
tile.hasOil && tile.owner===this.player) before calling canBuild(), ensuring
OilRig candidates are valid oil-bearing owned tiles.

116-116: ⚠️ Potential issue | 🔴 Critical

Fix the release-blocking sharedWaterComponents crash.

CI shows handleStructures() throws before any nation structure logic runs because this.game.sharedWaterComponents is missing in the active game object or test mock. Please add/align the Game implementation and mocks, or switch this code to the existing water-component API.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/execution/nation/NationStructureBehavior.ts` at line 116,
handleStructures is crashing because NationStructureBehavior uses
this.game.sharedWaterComponents which doesn't exist on the active Game/mocks;
either add/align that method on the Game class and all test mocks (implement
sharedWaterComponents(player): WaterComponent[] and return appropriate mock
data) or change NationStructureBehavior to call the existing water-component API
used elsewhere (e.g., replace this.game.sharedWaterComponents(this.player) with
the canonical method your codebase exposes such as
this.game.getSharedWaterComponents(this.player) or
this.game.getWaterComponents(this.player)); ensure tests/mocks are updated to
match whichever API you choose so this._sharedWaterComponents is always defined
before handleStructures runs.
tests/core/game/TrainStation.test.ts (2)

88-99: ⚠️ Potential issue | 🟡 Minor

Use separate owners so this test covers the ally path.

Right now the station owner and train owner are the same player mock, so the test can pass through self-trade and never prove that isAlliedWith() drives the ally branch.

Proposed test strengthening
   it("handles allied trade", () => {
+    const stationOwner = {
+      addGold: vi.fn(),
+      id: 1,
+      canTrade: vi.fn().mockReturnValue(true),
+      isOnSameTeam: vi.fn().mockReturnValue(false),
+      isAlliedWith: vi.fn().mockReturnValue(true),
+    } as any;
+    const trainOwner = {
+      addGold: vi.fn(),
+      id: 2,
+      canTrade: vi.fn().mockReturnValue(true),
+      isOnSameTeam: vi.fn().mockReturnValue(false),
+      isAlliedWith: vi.fn().mockReturnValue(true),
+    } as any;
     unit.type.mockReturnValue(UnitType.City);
-    player.isAlliedWith.mockReturnValue(true);
+    unit.owner.mockReturnValue(stationOwner);
+    trainExecution.owner.mockReturnValue(trainOwner);
     const station = new TrainStation(game, unit);
 
     station.onTrainStop(trainExecution);
 
-    expect(unit.owner().addGold).toHaveBeenCalledWith(1000n, unit.tile());
-    expect(trainExecution.owner().addGold).toHaveBeenCalledWith(
+    expect(stationOwner.addGold).toHaveBeenCalledWith(1000n, unit.tile());
+    expect(trainOwner.addGold).toHaveBeenCalledWith(
       1000n,
       unit.tile(),
     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/core/game/TrainStation.test.ts` around lines 88 - 99, The test uses the
same mock `player` for both the station owner and the train owner so it can pass
via self-trade; change the setup so the station's owner and
`trainExecution.owner()` are different mock players (e.g., `stationOwner` and
`trainOwner`), keep `player.isAlliedWith` behavior targeted so
`stationOwner.isAlliedWith(stationOwner, trainOwner)` (or the equivalent mock)
returns true, then construct `new TrainStation(game, unit)` with `stationOwner`
and set `trainExecution.owner()` to `trainOwner`; this ensures the
`TrainStation.onTrainStop` ally branch (use of `player.isAlliedWith`) is
exercised and both `unit.owner().addGold` and `trainExecution.owner().addGold`
are asserted called.

51-60: ⚠️ Potential issue | 🟡 Minor

Remove the duplicate mock keys from the player object.

Lines 58–59 repeat isOnSameTeam and isAlliedWith that are already declared on lines 55–56. In object literals, the second declarations silently overwrite the first ones, making the code redundant.

Suggested fix
     player = {
       addGold: vi.fn(),
       id: 1,
       canTrade: vi.fn().mockReturnValue(true),
       isAlliedWith: vi.fn().mockReturnValue(false),
       isOnSameTeam: vi.fn().mockReturnValue(false),
       isFriendly: vi.fn().mockReturnValue(false),
-      isOnSameTeam: vi.fn().mockReturnValue(false),
-      isAlliedWith: vi.fn().mockReturnValue(false),
     } as any;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/core/game/TrainStation.test.ts` around lines 51 - 60, The player test
fixture contains duplicate mock properties for isOnSameTeam and isAlliedWith on
the player object; remove the repeated declarations so each mock (isOnSameTeam,
isAlliedWith, and the other mocks like canTrade, isFriendly) is defined only
once in the player object used by TrainStation.test.ts (locate the player = {
... } block) to avoid redundant overwrites and keep the single intended mock
implementations.
tests/economy/ConstructionGold.test.ts (1)

1-144: ⚠️ Potential issue | 🟡 Minor

Run Prettier so CI can pass.

The new test looks useful, but the pipeline reports a Prettier mismatch for this file.

#!/bin/bash
# Format only the changed test file.
npx prettier --write tests/economy/ConstructionGold.test.ts
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/economy/ConstructionGold.test.ts` around lines 1 - 144, Run Prettier to
fix formatting in the new test file tests/economy/ConstructionGold.test.ts so CI
passes; format the file (e.g. run `npx prettier --write
tests/economy/ConstructionGold.test.ts` or your project's formatting script) and
commit the formatted changes — the failing file contains the "Construction
economy" tests and symbols like ConstructionExecution, NukeExecution,
SpawnExecution, and the test cases "City charges gold once..." and "MIRV gets
more expensive..." referenced in the diff.
map-generator/map_generator.go (1)

85-87: ⚠️ Potential issue | 🟡 Minor

Update the pixel-decoding comment for RGB oil detection.

The comment still says red/green values have no impact, but oil detection now uses red, green, and blue. This can mislead map authors.

📝 Proposed comment fix
-// Red/green pixel values have no impact, only blue values are used
-// For Land tiles, "Magnitude" is determined by `(Blue - 140) / 2“.
+// Near-black red/green/blue pixels are reserved for oil.
+// For other Land tiles, "Magnitude" is determined by `(Blue - 140) / 2`.

Also applies to: 94-94

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@map-generator/map_generator.go` around lines 85 - 87, The comment above the
pixel-decoding logic incorrectly states that red/green values have no impact;
update the comment near the pixel decoding in map_generator.go (the lines
describing "Magnitude" and blue-based calculations) to explain that oil
detection uses red, green, and blue channels and describe how each channel is
interpreted (e.g., which channel(s) indicate oil presence/strength versus
land/water magnitude) so map authors aren’t misled by the old “red/green have no
impact” note; ensure the updated comment also appears where the similar note
exists (around the second occurrence at line ~94).
src/core/game/PlayerImpl.ts (1)

908-918: ⚠️ Potential issue | 🟡 Minor

Use an explicit tile check so tile 0 still emits bonus events.

if (tile) skips valid tile 0, so gold popups from that tile will not be sent.

Proposed fix
-    if (tile) {
+    if (tile !== undefined) {
       this.mg.addUpdate({
         type: GameUpdateType.BonusEvent,
         player: this.id(),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/game/PlayerImpl.ts` around lines 908 - 918, The addGold method uses
a truthy check "if (tile)" which skips valid tile 0; change the conditional in
PlayerImpl.addGold to an explicit null/undefined check (e.g., if (tile !==
undefined && tile !== null) or if (typeof tile !== 'undefined')) so a tile value
of 0 still triggers the mg.addUpdate BonusEvent with tile, gold and icon; keep
the rest of the payload the same.
🟠 Major comments (24)
resources/lang/hu.json-102-103 (1)

102-103: ⚠️ Potential issue | 🟠 Major

Please move Hungarian translation changes to dedicated localization PRs.

Line 102 and Line 103 add non-English locale values in this feature PR. Please revert these here and ship the key additions through en.json; translators can then update hu.json in the localization workflow.

Based on learnings: OpenFrontIO handles non-English locale updates in dedicated translation PRs, while regular PRs update only en.json.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/hu.json` around lines 102 - 103, Revert the Hungarian
translations for the keys "build_oil_rig" and "build_oil_rig_desc" from this PR
and instead add those keys with English values to en.json; keep only the key
additions in this feature PR (no non-English locale changes), then open a
separate localization PR where translators will update hu.json with the
Hungarian strings.
resources/lang/tp.json-74-75 (1)

74-75: ⚠️ Potential issue | 🟠 Major

Route these locale additions through translation PRs only.

Line 74 and Line 75 modify a non-English locale file in a feature PR. Please keep this PR to en.json key/value changes and move these locale strings to the translation team workflow.

Based on learnings: For OpenFrontIO, non-English files in resources/lang/*.json are handled by dedicated translation PRs, not regular feature PRs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/tp.json` around lines 74 - 75, Remove the non-English locale
additions from this feature PR by reverting the changes to the tp.json keys
"build_oil_rig" and "build_oil_rig_desc" so only en.json is modified in this
branch; then create a separate translation PR (or submit the strings to the
translation workflow) containing these two keys and their translated values so
the translation team can review and merge them via the dedicated translation
process.
resources/lang/de-CH.json-159-160 (1)

159-160: ⚠️ Potential issue | 🟠 Major

Please remove non-English locale edits from this feature PR.

Line 159 and Line 160 add de-CH translations directly. This should be split out into the dedicated translation process; feature PRs should keep localization key changes in en.json only.

Based on learnings: In OpenFrontIO, only dedicated translation PRs should update non-English locale files under resources/lang/.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/de-CH.json` around lines 159 - 160, Remove the non-English
entries added in this feature PR by deleting the "build_oil_rig" and
"build_oil_rig_desc" keys from resources/lang/de-CH.json (they should exist only
in en.json); leave the localization key additions in the English locale and
submit any German translations via the dedicated translation PR/process instead
of modifying de-CH.json in this feature branch.
resources/lang/hi.json-71-72 (1)

71-72: ⚠️ Potential issue | 🟠 Major

Please avoid updating resources/lang/hi.json in this PR.

Line 71 and Line 72 introduce Hindi translations directly in a feature PR. Per project process, keep only en.json updates here and move non-English locale updates to the translation PR path.

Based on learnings: In OpenFrontIO, translation files in resources/lang/*.json except en.json are updated only in dedicated translation PRs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/hi.json` around lines 71 - 72, This PR added Hindi locale keys
"build_oil_rig" and "build_oil_rig_desc" in resources/lang/hi.json but
non-English locale changes must not be included here; revert the changes in
resources/lang/hi.json so it matches the branch baseline, ensure the new strings
exist only in resources/lang/en.json (using the keys "build_oil_rig" and
"build_oil_rig_desc"), and open or move the Hindi translations into the
dedicated translation PR/path for localization updates.
resources/lang/uk.json-159-160 (1)

159-160: ⚠️ Potential issue | 🟠 Major

This non-English locale update should be split out.

Line 159 and Line 160 add Ukrainian translation content in a feature PR. Please keep this PR focused on English source keys and move locale translations to the project’s translation PR workflow.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/uk.json` around lines 159 - 160, The PR added Ukrainian locale
entries "build_oil_rig" and "build_oil_rig_desc" to resources/lang/uk.json which
must be removed from this feature PR; revert or remove these two keys from this
branch and instead submit them via the project's translation workflow (a
separate translation PR) so this feature PR contains only English source keys
and code changes. Ensure you reference and remove the exact keys "build_oil_rig"
and "build_oil_rig_desc" when reverting the change before opening the dedicated
translation PR with the Ukrainian translations.
resources/lang/ca.json-156-157 (1)

156-157: ⚠️ Potential issue | 🟠 Major

Keep translation content in dedicated translation flow.

Line 156 and Line 157 add Catalan translations in a feature PR. Please keep technical key rollout separate and let community translation updates happen in the dedicated localization process.

Based on learnings: For OpenFrontIO, technical changes and translation content updates are separated so native translators can update locale values in dedicated translation work.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/ca.json` around lines 156 - 157, Remove the Catalan
translations from the PR and keep only the technical keys so localization stays
in the translation workflow: revert the values for the keys "build_oil_rig" and
"build_oil_rig_desc" to their default/placeholder (e.g., English strings or
empty strings) instead of adding localized Catalan text, so the keys are present
but actual translations are left to the dedicated localization process; do not
add new translated content in this feature change.
resources/lang/cs.json-85-86 (1)

85-86: ⚠️ Potential issue | 🟠 Major

Please move non-English translation edits out of this feature PR.

Line 85 and Line 86 add Czech locale content. In this repo workflow, regular feature PRs should only update resources/lang/en.json; non-English locale files are handled in dedicated translation PRs. Please revert these lines here and let translation follow-up handle them.

Based on learnings: In OpenFrontIO, translation files in resources/lang/*.json (except en.json) should not be updated in regular PRs; only dedicated translation PRs should update non-English locales.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/cs.json` around lines 85 - 86, Revert the non-English
additions to resources/lang/cs.json by removing the "build_oil_rig" and
"build_oil_rig_desc" keys (the Czech translations added in this PR), restoring
that file to its prior state; ensure the only locale changes in this feature PR
are made in resources/lang/en.json and leave foreign-language updates to a
dedicated translation PR.
resources/lang/sh.json-71-72 (1)

71-72: ⚠️ Potential issue | 🟠 Major

Please keep sh.json out of this feature PR.

Line 71 and Line 72 add Serbo-Croatian translations directly. In this repository, this should be handled by the dedicated translation process, not mixed into feature delivery PRs.

Based on learnings: For OpenFrontIO, translation files in resources/lang/*.json except en.json are handled by a dedicated translation team and workflow.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/sh.json` around lines 71 - 72, This PR erroneously adds
Serbo-Croatian translations ("build_oil_rig" and "build_oil_rig_desc") directly;
revert the additions for those keys from the changeset (remove "build_oil_rig"
and "build_oil_rig_desc" entries) and ensure no other non-en JSON language files
are modified, then update the PR description or commit message to state
translations must be submitted via the dedicated translation workflow and notify
the translation team so they can add these keys through the proper process.
resources/lang/nl.json-131-132 (1)

131-132: ⚠️ Potential issue | 🟠 Major

Dutch locale additions should be deferred to translation PRs

Line 131 and Line 132 update resources/lang/nl.json in a regular feature PR. Please keep this change to en.json here and move Dutch text to the translation workflow PR.

Based on learnings: non-English locale files are maintained by the dedicated translation flow; regular PRs should update only en.json.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/nl.json` around lines 131 - 132, This change improperly
updates the Dutch locale file resources/lang/nl.json; remove the Dutch entries
for "build_oil_rig" and "build_oil_rig_desc" from this feature PR and instead
keep only the corresponding English keys in en.json, deferring any nl.json
translations to the dedicated translation workflow/PR so non-English locale
files remain untouched in this branch.
resources/lang/es.json-85-86 (1)

85-86: ⚠️ Potential issue | 🟠 Major

Spanish locale changes should not be in this regular feature PR

Line 85 and Line 86 add Spanish translations directly. This should be handled by the dedicated translation process; keep this PR limited to en.json for new keys.

Based on learnings: in OpenFrontIO, only en.json should be updated in regular PRs; non-English locale updates are reserved for dedicated translation PRs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/es.json` around lines 85 - 86, Remove the Spanish entries
"build_oil_rig" and "build_oil_rig_desc" from resources/lang/es.json and instead
add the new keys and English text to resources/lang/en.json (use the same key
names: build_oil_rig and build_oil_rig_desc); keep this feature PR limited to
en.json only and leave non-English locale updates to the dedicated translation
workflow.
resources/lang/fi.json-102-103 (1)

102-103: ⚠️ Potential issue | 🟠 Major

Finnish locale changes should follow the translation-only PR path

Line 102 and Line 103 add Finnish translations in a feature PR. This repo expects non-English locale updates in dedicated translation PRs, not in gameplay feature PRs.

Based on learnings: regular PRs should modify en.json only; updates to other locale files are handled separately by the translation workflow.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/fi.json` around lines 102 - 103, The Finnish locale additions
for keys "build_oil_rig" and "build_oil_rig_desc" were added in a feature PR but
this repo requires non-English locale changes to go through the translation-only
PR path; revert the changes to resources/lang/fi.json in this branch (remove the
"build_oil_rig" and "build_oil_rig_desc" entries) and ensure only the
corresponding en.json key(s) are touched in this feature PR, then open a
separate translation PR for the Finnish translations referencing these keys.
resources/lang/sk.json-102-103 (1)

102-103: ⚠️ Potential issue | 🟠 Major

Slovak translation updates should be excluded from this feature PR

Line 102 and Line 103 modify resources/lang/sk.json, which is translator-managed. Please keep only en.json key additions in this PR and route Slovak text through the dedicated localization process.

Based on learnings: non-English locale files are not updated in regular PRs; dedicated translation PRs handle those changes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/sk.json` around lines 102 - 103, Revert the Slovak locale
edits for the keys "build_oil_rig" and "build_oil_rig_desc" in
resources/lang/sk.json so this PR only contains the English key additions;
ensure the en.json contains the new keys/strings and remove or undo any changes
to resources/lang/sk.json (leave it unchanged) so localization updates are
routed through the dedicated translation PR/process.
resources/lang/fr.json-159-160 (1)

159-160: ⚠️ Potential issue | 🟠 Major

French translation additions should be handled outside this feature PR

Line 159 and Line 160 update a non-English locale file directly. Please move this to the dedicated translation pipeline and keep only en.json key updates in this PR.

Based on learnings: non-English files under resources/lang/*.json are maintained via dedicated translation PRs, while regular PRs should update en.json only.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/fr.json` around lines 159 - 160, Revert the direct edits to
the French locale keys "build_oil_rig" and "build_oil_rig_desc" in
resources/lang/fr.json and remove them from this PR; instead add or keep the
corresponding keys updated only in resources/lang/en.json, and submit the French
translations through the dedicated translation pipeline/translation PR process
so non-English locale changes are not included in this feature branch.
resources/lang/fa.json-112-113 (1)

112-113: ⚠️ Potential issue | 🟠 Major

Move Persian locale changes to the translation PR workflow

Line 112 and Line 113 add Persian strings in this feature PR. Per repo workflow, this should not be done in regular PRs; keep the key additions in en.json and let the translation process update fa.json.

Based on learnings: regular PRs should only update en.json; non-English resources/lang/*.json updates are done in dedicated translation PRs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/fa.json` around lines 112 - 113, The Persian locale file has
direct additions "build_oil_rig" and "build_oil_rig_desc" in fa.json which
violates the translation workflow; revert or remove these two keys from
resources/lang/fa.json in this PR and ensure the corresponding key additions
exist only in en.json (add them there if missing) so that language maintainers
can update fa.json in a dedicated translation PR.
resources/lang/et.json-156-157 (1)

156-157: ⚠️ Potential issue | 🟠 Major

Please avoid updating translator-managed locale files in this PR

Line 156 and Line 157 modify Estonian locale content in a normal feature PR. This should be limited to en.json here and moved to the dedicated translation flow for non-English locales.

Based on learnings: non-English files in resources/lang/*.json are handled by dedicated translation PRs, while regular PRs should update only en.json.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/et.json` around lines 156 - 157, Revert the edits to the
Estonian locale keys "build_oil_rig" and "build_oil_rig_desc" (undo changes to
those keys in the non-English locale) and ensure the feature text is added only
to the English locale key equivalents in en.json; if translations are needed,
leave the non-English keys unchanged and submit the new strings via the
dedicated translation workflow so translators can update "build_oil_rig" and
"build_oil_rig_desc" in the translation PR instead.
resources/lang/eo.json-102-103 (1)

102-103: ⚠️ Potential issue | 🟠 Major

Non-English locale update should be moved out of this feature PR

Line 102 and Line 103 add Esperanto strings in a regular feature PR. In this repo, non-English locale files are handled by the translation workflow, so this should stay in en.json only here and be synced later in the dedicated translation process.

Based on learnings: In OpenFrontIO, resources/lang/*.json (except en.json) should not be updated in regular PRs; non-English updates are handled in dedicated translation PRs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/eo.json` around lines 102 - 103, The Esperanto strings
"build_oil_rig" and "build_oil_rig_desc" were added in this feature PR but
non-English locale files must not be changed here; revert the changes in
resources/lang/eo.json (remove the two keys/values) so this PR only updates
en.json, and ensure new string keys are present in the English file (e.g.,
"build_oil_rig" and "build_oil_rig_desc") to be picked up by the translation
workflow later.
src/core/execution/nation/NationStructureBehavior.ts-141-146 (1)

141-146: ⚠️ Potential issue | 🟠 Major

Do not skip Oil Rigs when there are no coastal tiles.

Oil rigs are placed on oil terrain, not shore tiles. This gate blocks nations with inland oil deposits from ever trying to build one.

Proposed fix
-      // Skip coastal structures if no coastal tiles
+      // Skip coastal structures if no coastal tiles
       if (
-        (structureType === UnitType.Port ||
-          structureType === UnitType.OilRig) &&
+        structureType === UnitType.Port &&
         !hasCoastalTiles
       ) {
         continue;
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/execution/nation/NationStructureBehavior.ts` around lines 141 - 146,
The current gate incorrectly skips both UnitType.Port and UnitType.OilRig when
hasCoastalTiles is false; change the condition in NationStructureBehavior (the
block that checks structureType and hasCoastalTiles) to only skip Port (i.e.
check structureType === UnitType.Port && !hasCoastalTiles) so OilRig placement
is not blocked by lack of coastal tiles (oil rigs should rely on oil-terrain
checks elsewhere).
map-generator/map_generator.go-143-144 (1)

143-144: ⚠️ Potential issue | 🟠 Major

Preserve oil when creating 4x/16x maps.

Oil is encoded only as land magnitude 31, but createMiniMap() currently keeps whichever non-water land tile is visited last. If a 2x2 block has one oil pixel and normal land after it, the oil disappears from map4x, map16x, and the thumbnail.

🛢️ Proposed downscale fix
 func createMiniMap(tm [][]Terrain) [][]Terrain {
@@
 			if miniX < miniWidth && miniY < miniHeight {
-				// If any of the 4 tiles has water, mini tile is water
-				if miniMap[miniX][miniY].Type != Water {
-					miniMap[miniX][miniY] = tm[x][y]
-				}
+				source := tm[x][y]
+				current := miniMap[miniX][miniY]
+
+				// Water still has top priority.
+				if current.Type == Water {
+					continue
+				}
+				if source.Type == Water {
+					miniMap[miniX][miniY] = source
+					continue
+				}
+
+				// Preserve oil when any source land tile in the block is oil.
+				if source.Magnitude >= 31 || current.Magnitude < 31 {
+					miniMap[miniX][miniY] = source
+				}
 			}
 		}
 	}

Also applies to: 264-295

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@map-generator/map_generator.go` around lines 143 - 144, The downscale
routines (createMiniMap and the similar 4x/16x map creation logic around the
block handling at 264-295) currently overwrite oil tiles because oil is encoded
as land magnitude 31 and later pixels in a block can replace it; change the
block-aggregation logic to treat Magnitude==31 as highest-priority (if any pixel
in the source block has Terrain{Type: Land, Magnitude: 31} the destination must
be set to that oil value) instead of keeping the last visited non-water
tile—implement by scanning the block for oil first, otherwise choose the highest
magnitude land tile as before. Ensure you update the code paths that set
terrain[x][y] (and any variables used in createMiniMap/createMap4x/createMap16x)
so oil is preserved during downscale.
resources/lang/cb.json-59-59 (1)

59-59: ⚠️ Potential issue | 🟠 Major

Remove the copied script text from the user-facing string.

This long pasted passage creates avoidable copyright/compliance risk in a shipped localization file.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/cb.json` at line 59, The "copied_to_clipboard" localization
value contains a long pasted movie/script excerpt that must be removed and
replaced with a short, user-facing message; update the "copied_to_clipboard"
string (key: copied_to_clipboard) to a concise, non-copyrighted phrase such as
"Copied to clipboard" or "Info copied to clipboard" and remove the entire pasted
passage and any informal text (e.g., "btw", "ur", Discord mention).
tests/NationStructureBehavior.test.ts-364-377 (1)

364-377: ⚠️ Potential issue | 🟠 Major

Add sharedWaterComponents to this game mock.

The CI failure shows handleStructures() now reaches code that calls this.game.sharedWaterComponents(...), so this partial mock crashes before the oil-rig assertion runs.

Proposed test mock fix
     const game = {
       config: () => ({
         isUnitDisabled: vi.fn(() => false),
         gameConfig: () => ({ difficulty: Difficulty.Medium }),
         unitInfo: vi.fn(() => ({ upgradable: false })),
       }),
       unitInfo: vi.fn(() => ({
         cost: vi.fn(() => 100n),
       })),
       isOceanShore: vi.fn((tile: unknown) => tile === coastalTile),
+      sharedWaterComponents: vi.fn(() => new Set()),
       addExecution: vi.fn((execution: unknown) => {
         queuedExecutions.push(execution);
       }),
     };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/NationStructureBehavior.test.ts` around lines 364 - 377, The game mock
used in the test is missing the sharedWaterComponents method which causes
handleStructures() to crash; add a sharedWaterComponents mock on the game object
(the same mock named game in the test) that returns an appropriate value for the
test (e.g., vi.fn(() => /* desired shared water result */)) so
handleStructures() can call this.game.sharedWaterComponents(...) without
throwing and the oil-rig assertion can run; update the mock alongside existing
methods like isOceanShore, unitInfo, and addExecution.
resources/lang/cb.json-1-544 (1)

1-544: ⚠️ Potential issue | 🟠 Major

Remove this non-English locale file from the feature PR.

Regular feature PRs should update only resources/lang/en.json; non-English locale files are handled by the dedicated translation workflow. Based on learnings, translation files in resources/lang/*.json except en.json should not be updated in regular PRs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/cb.json` around lines 1 - 544, The PR includes a non-English
locale file (cb.json) that should not be part of a feature change; remove/revert
the added/modified cb.json from the commit so only en.json is changed, and
ensure no references to the "cb" locale remain (check top-level keys like
"common" and "main" in the removed file); if translation content is required,
leave a note/TODO and open the translation workflow/issue instead.
src/core/execution/OilRigExecution.ts-81-89 (1)

81-89: ⚠️ Potential issue | 🟠 Major

Only count factories owned by the oil rig owner.

Line 82 checks for any nearby factory. That means an enemy or ally factory can trigger rail-station creation for this oil rig, even though freight delivery later requires an owned factory.

Scope the nearby factory check to the owner
     const nearbyFactory = this.mg.hasUnitNearby(
       this.oilRig.tile(),
       this.mg.config().trainStationMaxRange(),
       UnitType.Factory,
+      this.oilRig.owner().id(),
     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/execution/OilRigExecution.ts` around lines 81 - 89, The nearby
factory check in createStation currently counts any nearby factory; restrict it
to factories owned by the same owner as this.oilRig by changing the
hasUnitNearby call to filter by ownership (or use an owned-specific helper).
Specifically, update the logic around mg.hasUnitNearby(this.oilRig.tile(),
this.mg.config().trainStationMaxRange(), UnitType.Factory) so it only returns
true for units whose owner matches the oil rig owner (e.g., compare unit.owner
or unit.ownerId to this.oilRig.owner()/ownerId), then keep adding
TrainStationExecution(this.oilRig) only when that owned factory exists.
src/core/execution/OilRigExecution.ts-12-43 (1)

12-43: ⚠️ Potential issue | 🟠 Major

Fix the freight interval calculation.

With + this.checkOffset, rigs created on non-zero ticks can spawn early. For example, with interval 5 and init tick 1, the first spawn happens at tick 4, not after 5 ticks.

Use an explicit next-spawn tick
   private active = true;
   private mg!: Game;
-  private checkOffset = 0;
+  private nextFreightTick = 0;
@@
   init(mg: Game, ticks: number): void {
     this.mg = mg;
-    this.checkOffset =
-      mg.ticks() % Math.max(1, mg.config().oilRigIncomeInterval());
+    this.nextFreightTick =
+      ticks + Math.max(1, mg.config().oilRigIncomeInterval());
   }
@@
   private shouldSpawnFreightTrain(ticks: number): boolean {
     const interval = Math.max(1, this.mg.config().oilRigIncomeInterval());
-    void ticks;
-    return (this.mg.ticks() + this.checkOffset) % interval === 0;
+    if (ticks < this.nextFreightTick) {
+      return false;
+    }
+    this.nextFreightTick = ticks + interval;
+    return true;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/execution/OilRigExecution.ts` around lines 12 - 43, The spawn timing
logic uses checkOffset and modulo which causes early spawns for rigs created
mid-interval; replace that with an explicit nextSpawnTick field: in init(mg:
Game, ticks: number) compute this.nextSpawnTick = mg.ticks() + Math.max(1,
mg.config().oilRigIncomeInterval()); change shouldSpawnFreightTrain(ticks) to
return mg.ticks() >= this.nextSpawnTick (no modulo/checkOffset and you can
ignore the ticks param), and after spawnFreightTrain(...) succeeds advance
this.nextSpawnTick by adding the interval (or set to mg.ticks() + interval) so
future spawns occur exactly interval ticks apart; remove/stop using checkOffset.
src/core/game/TrainStation.ts-314-343 (1)

314-343: ⚠️ Potential issue | 🟠 Major

Return when the destination is dequeued, not when first discovered.

Line 341 can return a non-shortest route. Example: a direct rail to the factory costs 100, but an indirect path through another station costs 2; if the direct factory neighbor is seen first, this returns 100.

Fix the Dijkstra exit condition
   while (queue.length > 0) {
     queue.sort((a, b) => a.distance - b.distance);
     const current = queue.shift()!;
+    if (current.station === to) {
+      return current.distance;
+    }
     if (
       current.distance >
       (bestDistance.get(current.station) ?? Number.POSITIVE_INFINITY)
     ) {
       continue;
@@
 
       const nextDistance = current.distance + rail.tiles.length;
-      if (neighbor === to) {
-        return nextDistance;
-      }
-
       if (
         nextDistance >= (bestDistance.get(neighbor) ?? Number.POSITIVE_INFINITY)
       ) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/game/TrainStation.ts` around lines 314 - 343, The Dijkstra
implementation in railroadDistance incorrectly returns when the destination is
first discovered (neighbor === to), which can be suboptimal; instead, update
bestDistance for the neighbor (using nextDistance) and push it to queue as you
do for other neighbors, and only return when the destination is dequeued and
processed (i.e., when current.station === to), ensuring you compare
current.distance to bestDistance[current.station] before returning; adjust logic
around bestDistance, queue push, and the early return to use current.station ===
to as the exit condition.
🟡 Minor comments (9)
src/client/HelpModal.ts-969-984 (1)

969-984: ⚠️ Potential issue | 🟡 Minor

Trailing space on Oil Rig src line likely breaks Prettier.

Line 975 has a trailing space after ${assetUrl("images/OilRigIcon.svg")} — that is the most probable cause of the CI Prettier warning. Easy fix:

🧹 Proposed fix
-                        src=${assetUrl("images/OilRigIcon.svg")} 
+                        src=${assetUrl("images/OilRigIcon.svg")}

Run npx prettier --write src/client/HelpModal.ts to be sure no other whitespace gremlins are hiding.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/HelpModal.ts` around lines 969 - 984, Remove the trailing space
after the src attribute value in the Oil Rig img tag inside
HelpModal.ts—specifically fix the img element that uses
assetUrl("images/OilRigIcon.svg") so there is no extra space before the closing
`>`; then run npx prettier --write src/client/HelpModal.ts to reformat the file
and ensure no other whitespace issues remain (look for the <img ...
src=${assetUrl("images/OilRigIcon.svg")} ... /> entry in the HelpModal markup).
resources/lang/de.json-112-113 (1)

112-113: ⚠️ Potential issue | 🟡 Minor

Non-English locale changes should be left to the translation team.

Based on learnings, translation files in resources/lang/*.json (except en.json) are updated only via dedicated "mls" translation PRs by the translation team. Please drop the German string changes from this PR and keep just the en.json additions; the translators will pick them up later.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/de.json` around lines 112 - 113, This PR accidentally modifies
non-English locale entries ("build_oil_rig" and "build_oil_rig_desc") in
resources/lang/de.json; revert those German key-value pairs back to their
previous state (remove the new/changed German strings) so only the English
additions remain in en.json, leaving translations to the translation team (do
not add or change any non-en.json files).
src/client/graphics/layers/UILayer.ts-118-118 (1)

118-118: ⚠️ Potential issue | 🟡 Minor

Add Oil Rig to deletion progress calculation.

Line 118 creates a loading bar for deleted Oil Rigs, but getProgress() falls through to return 1, so the bar is cleared on the next update.

🐛 Proposed fix
       case UnitType.City:
       case UnitType.Factory:
       case UnitType.Port:
       case UnitType.DefensePost:
+      case UnitType.OilRig:
         return this.deletionProgress(this.game, unit);

Also applies to: 329-340

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/graphics/layers/UILayer.ts` at line 118, getProgress() is missing
a case for UnitType.OilRig so deletion bars for Oil Rigs immediately fall
through to return 1 and disappear; add a UnitType.OilRig branch to the switch in
getProgress() that computes and returns the deletion progress the same way other
deletable units do (use the same fields/logic used for e.g.
UnitType.Factory/other units in that switch). Also apply the same addition to
the corresponding deletion-progress handling block around the later code (the
block covering the same logic at the 329-340 region) so Oil Rig deletion bars
are calculated and rendered consistently.
resources/lang/ar.json-74-75 (1)

74-75: ⚠️ Potential issue | 🟡 Minor

Remove non-English translation changes from this feature PR.

Please keep the new text in en.json only and let the normal translation flow add Arabic later.

🧹 Proposed cleanup
-    "build_oil_rig": "منصة نفطية",
-    "build_oil_rig_desc": "لا يمكن بناؤها إلا على حقول النفط. تولّد الذهب مع الوقت، ويمكن للقطارات زيارتها إذا كان هناك مصنع قريب.",

Based on learnings, translation files in resources/lang/*.json except en.json should not be updated in regular PRs; only dedicated translation PRs titled "mls" and made by Aotumori should update non-English locale files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/ar.json` around lines 74 - 75, Revert the Arabic locale edits
introduced here by removing the added/modified keys "build_oil_rig" and
"build_oil_rig_desc" from resources/lang/ar.json so that only en.json contains
the new strings; leave the new text in en.json intact and ensure non-English
locale files (resources/lang/*.json other than en.json) are not changed in this
PR per the translation workflow.
resources/maps/worldoil/manifest.json-1-508 (1)

1-508: ⚠️ Potential issue | 🟡 Minor

Run Prettier on the new manifest.

The manifest data looks consistent, but CI reports a Prettier mismatch for this file.

#!/bin/bash
# Format only the new manifest.
npx prettier --write resources/maps/worldoil/manifest.json
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/maps/worldoil/manifest.json` around lines 1 - 508, CI reports a
Prettier formatting mismatch for the manifest.json file; run Prettier to
reformat the JSON (e.g., npx prettier --write manifest.json), or use your
editor/IDE formatting integration, then stage and commit the updated manifest
(the top-level keys like "map" and "nations" should remain unchanged).
resources/lang/pt-PT.json-102-103 (1)

102-103: ⚠️ Potential issue | 🟡 Minor

Add the Oil Rig keys used by the build menu too.

This file adds the help text, but the build menu uses unit_type.oil_rig and build_menu.desc.oil_rig. Without those keys, Portuguese users may see raw key names or fallback text.

🌍 Proposed localization key additions
   "unit_type": {
     "city": "Cidade",
     "defense_post": "Posto de Defesa",
     "port": "Porto",
+    "oil_rig": "Plataforma petrolífera",
     "warship": "Naves de Guerra",
   "build_menu": {
     "desc": {
       "atom_bomb": "Pequena explosão",
       "hydrogen_bomb": "Grande explosão",
       "mirv": "Explosão gigantesca, apenas tem como alvo o jogador selecionado",
       "missile_silo": "Usado para lançar bombas nucleares",
       "sam_launcher": "Defende contra bombas nucleares que se aproximam",
       "warship": "Captura navios de comércio, destrói outros navios e barcos",
       "port": "Envia navios de comércio para gerar ouro",
+      "oil_rig": "Gera ouro em jazidas de petróleo",
       "defense_post": "Aumenta as defesas de fronteiras próximas",
       "city": "Aumenta a população máxima",
       "factory": "Cria ferrovias e comboios"
     },

Based on learnings, localization PRs can keep translation content simple while still adding the required technical keys for UI coverage.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/lang/pt-PT.json` around lines 102 - 103, Add the missing
localization keys used by the build menu: create "unit_type.oil_rig" and
"build_menu.desc.oil_rig" entries in the pt-PT JSON (alongside the existing
"build_oil_rig" and "build_oil_rig_desc") so UI lookups for unit_type.oil_rig
and build_menu.desc.oil_rig resolve; use simple Portuguese text consistent with
the existing strings (e.g., short label for unit_type.oil_rig and a concise
description for build_menu.desc.oil_rig).
src/client/graphics/layers/StructureDrawingUtils.ts-72-72 (1)

72-72: ⚠️ Potential issue | 🟡 Minor

Remove the trailing space so Prettier passes.

CI is failing the Prettier check on this file.

Proposed formatting fix
-    [UnitType.OilRig, { iconPath: oilRigIcon, image: null }], 
+    [UnitType.OilRig, { iconPath: oilRigIcon, image: null }],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/graphics/layers/StructureDrawingUtils.ts` at line 72, Remove the
trailing whitespace at the end of the array entry for UnitType.OilRig in
StructureDrawingUtils.ts so Prettier passes; locate the tuple "[UnitType.OilRig,
{ iconPath: oilRigIcon, image: null }]," (in the map/array that builds unit icon
definitions) and delete the extra space after the closing comma, then save and
run Prettier/format to confirm the file is clean.
src/client/graphics/layers/UnitDisplay.ts-30-30 (1)

30-30: ⚠️ Potential issue | 🟡 Minor

Remove the trailing spaces so Prettier passes.

CI is failing the Prettier check on this file.

Proposed formatting fix
-const oilRigIcon = assetUrl("images/OilRigIcon.svg"); 
+const oilRigIcon = assetUrl("images/OilRigIcon.svg");
...
-    this._oilRig = player.totalUnitLevels(UnitType.OilRig); 
+    this._oilRig = player.totalUnitLevels(UnitType.OilRig);

Also applies to: 132-132

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/graphics/layers/UnitDisplay.ts` at line 30, Remove the trailing
whitespace characters at the ends of the affected lines so Prettier passes:
delete the extra spaces after the const oilRigIcon =
assetUrl("images/OilRigIcon.svg"); declaration and the other trailing-space
occurrence later in the UnitDisplay component/file (ensure the UnitDisplay
component/export lines are trimmed too), then re-run Prettier/format to confirm
no remaining trailing spaces.
map-generator/assets/maps/worldoil/OIL_EDITING.md-1-28 (1)

1-28: ⚠️ Potential issue | 🟡 Minor

Use repo-relative paths and run Prettier.

Line 4 points to a local /home/luke/... path, so the link will be broken for other contributors. CI also reports this Markdown file is not Prettier-formatted.

Suggested cleanup
- Open [image.png](/home/luke/CLASS/EECS/481/final/map-generator/assets/maps/worldoil/image.png) in an image editor that preserves exact RGBA values.
+ Open [`image.png`](./image.png) in an image editor that preserves exact RGBA values.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@map-generator/assets/maps/worldoil/OIL_EDITING.md` around lines 1 - 28,
Replace the absolute local path in the Markdown (the link pointing to
/home/luke/.../image.png referenced in the OIL_EDITING.md instructions) with a
repo-relative path (e.g., assets/maps/worldoil/image.png) and update any other
absolute references (such as scripts like apply_oil_reference.py) to use
repo-relative links; then run Prettier on OIL_EDITING.md to fix
formatting/whitespace so CI passes. Ensure the link text still points to the
correct filename (image.png) and that any example commands remain valid after
changing the path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d165151d-2bf6-4e70-b8ea-a14536780118

📥 Commits

Reviewing files that changed from the base of the PR and between 4e04bed and 0e91601.

⛔ Files ignored due to path filters (8)
  • map-generator/assets/maps/worldoil/image.png is excluded by !**/*.png
  • map-generator/assets/maps/worldoil/oil_reference.png is excluded by !**/*.png
  • resources/images/OilDropIcon.png is excluded by !**/*.png
  • resources/images/OilRigIcon.svg is excluded by !**/*.svg
  • resources/images/buildings/oilRig1.png is excluded by !**/*.png
  • resources/maps/worldoil/map.bin is excluded by !**/*.bin
  • resources/maps/worldoil/map16x.bin is excluded by !**/*.bin
  • resources/maps/worldoil/map4x.bin is excluded by !**/*.bin
📒 Files selected for processing (87)
  • map-generator/assets/maps/worldoil/OIL_EDITING.md
  • map-generator/assets/maps/worldoil/apply_oil_reference.py
  • map-generator/assets/maps/worldoil/info.json
  • map-generator/main.go
  • map-generator/map_generator.go
  • resources/lang/ar.json
  • resources/lang/bg.json
  • resources/lang/bn.json
  • resources/lang/ca.json
  • resources/lang/cb.json
  • resources/lang/cs.json
  • resources/lang/da.json
  • resources/lang/de-CH.json
  • resources/lang/de.json
  • resources/lang/el.json
  • resources/lang/en.json
  • resources/lang/eo.json
  • resources/lang/es.json
  • resources/lang/et.json
  • resources/lang/fa.json
  • resources/lang/fi.json
  • resources/lang/fr.json
  • resources/lang/gl.json
  • resources/lang/he.json
  • resources/lang/hi.json
  • resources/lang/hu.json
  • resources/lang/id.json
  • resources/lang/it.json
  • resources/lang/ja.json
  • resources/lang/ko.json
  • resources/lang/mk.json
  • resources/lang/nl.json
  • resources/lang/pl.json
  • resources/lang/pt-BR.json
  • resources/lang/pt-PT.json
  • resources/lang/ru.json
  • resources/lang/sh.json
  • resources/lang/sk.json
  • resources/lang/sl.json
  • resources/lang/sv-SE.json
  • resources/lang/tp.json
  • resources/lang/tr.json
  • resources/lang/uk.json
  • resources/lang/zh-CN.json
  • resources/maps/worldoil/manifest.json
  • resources/maps/worldoil/thumbnail.webp
  • src/client/HelpModal.ts
  • src/client/InputHandler.ts
  • src/client/JoinLobbyModal.ts
  • src/client/UserSettingModal.ts
  • src/client/components/GameConfigSettings.ts
  • src/client/components/map/MapPicker.ts
  • src/client/graphics/SpriteLoader.ts
  • src/client/graphics/layers/BuildMenu.ts
  • src/client/graphics/layers/DynamicUILayer.ts
  • src/client/graphics/layers/FxLayer.ts
  • src/client/graphics/layers/PlayerInfoOverlay.ts
  • src/client/graphics/layers/StructureDrawingUtils.ts
  • src/client/graphics/layers/StructureLayer.ts
  • src/client/graphics/layers/TerrainLayer.ts
  • src/client/graphics/layers/UILayer.ts
  • src/client/graphics/layers/UnitDisplay.ts
  • src/client/graphics/ui/TextIndicator.ts
  • src/core/StatsSchemas.ts
  • src/core/configuration/Config.ts
  • src/core/configuration/DefaultConfig.ts
  • src/core/configuration/PastelTheme.ts
  • src/core/configuration/PastelThemeDark.ts
  • src/core/execution/AttackExecution.ts
  • src/core/execution/ConstructionExecution.ts
  • src/core/execution/FactoryExecution.ts
  • src/core/execution/OilRigExecution.ts
  • src/core/execution/TrainExecution.ts
  • src/core/execution/nation/NationNukeBehavior.ts
  • src/core/execution/nation/NationStructureBehavior.ts
  • src/core/game/Game.ts
  • src/core/game/GameMap.ts
  • src/core/game/GameUpdates.ts
  • src/core/game/PlayerImpl.ts
  • src/core/game/RailNetworkImpl.ts
  • src/core/game/TrainStation.ts
  • src/core/game/UnitImpl.ts
  • src/core/game/UserSettings.ts
  • tests/NationStructureBehavior.test.ts
  • tests/OilRigExecution.test.ts
  • tests/core/game/TrainStation.test.ts
  • tests/economy/ConstructionGold.test.ts

Comment thread map-generator/assets/maps/worldoil/apply_oil_reference.py
Comment thread src/core/game/Game.ts
@github-project-automation github-project-automation bot moved this from Triage to Development in OpenFront Release Management Apr 18, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/client/graphics/layers/StructureDrawingUtils.ts (1)

373-395: Looks good — septagon mirrors the existing polygon shapes.

The new septagon branch follows the same pattern as pentagon and octagon (center, radius, step of 2π/n, start angle -π/2). Rendering, closing, fill, and stroke are all consistent.

Optional nit: the three branches pentagon / octagon / septagon are now near-duplicates. If you feel like tidying up later, a small helper like drawRegularPolygon(ctx, cx, cy, r, sides, startAngle) would remove the copy-paste without adding any dependency.

♻️ Optional helper refactor
+        function drawRegularPolygon(
+          ctx: CanvasRenderingContext2D,
+          cx: number,
+          cy: number,
+          r: number,
+          sides: number,
+          startAngle: number,
+        ) {
+          const step = (Math.PI * 2) / sides;
+          ctx.beginPath();
+          for (let i = 0; i < sides; i++) {
+            const angle = startAngle + step * i;
+            const x = cx + r * Math.cos(angle);
+            const y = cy + r * Math.sin(angle);
+            if (i === 0) ctx.moveTo(x, y);
+            else ctx.lineTo(x, y);
+          }
+          ctx.closePath();
+          ctx.fill();
+          ctx.stroke();
+        }

Then each case becomes a single call, e.g. drawRegularPolygon(context, halfIconSize, halfIconSize, halfIconSize - 1, 7, -Math.PI / 2);.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/graphics/layers/StructureDrawingUtils.ts` around lines 373 - 395,
The three near-duplicate cases "pentagon", "octagon", and "septagon" in
StructureDrawingUtils.ts should be replaced by a small helper to avoid
copy/paste: add a drawRegularPolygon(context, cx, cy, r, sides, startAngle)
function that begins a path, loops sides times computing angle = startAngle +
i*(2*Math.PI/sides), uses moveTo for i==0 and lineTo otherwise, then
closePath(), fill() and stroke(); then replace each case body with a single call
like drawRegularPolygon(context, halfIconSize, halfIconSize, halfIconSize - 1,
N, -Math.PI/2) where N is 5, 7, or 8 for pentagon/septagon/octagon respectively.
tests/MapConsistency.test.ts (1)

138-154: Nit: lift the per-map allowlist into a lookup.

Hard-coding a branch on key === "WorldOil" inside the loop will get noisy the next time another map needs extra assets. A small Record<GameMapName, string[]> (or Partial<...>) keyed by map name keeps this table-driven and the loop body boring.

♻️ Sketch
+const EXTRA_MAP_ASSETS: Partial<Record<GameMapName, string[]>> = {
+  WorldOil: ["OIL_EDITING.md", "apply_oil_reference.py", "oil_reference.png"],
+};
...
-      const expected = ["image.png", "info.json"];
-      const allowedFiles =
-        key === "WorldOil"
-          ? [
-              ...expected,
-              "OIL_EDITING.md",
-              "apply_oil_reference.py",
-              "oil_reference.png",
-            ].sort()
-          : expected;
+      const baseFiles = ["image.png", "info.json"];
+      const allowedFiles = [
+        ...baseFiles,
+        ...(EXTRA_MAP_ASSETS[key] ?? []),
+      ].sort();

Also worth asking: do OIL_EDITING.md, apply_oil_reference.py, and oil_reference.png really need to live under map-generator/assets/maps/worldoil/ (and thus ship as map assets), or do they belong alongside the generator source where authoring tools usually sit? Shipping authoring docs/scripts as map assets is unusual.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/MapConsistency.test.ts` around lines 138 - 154, Replace the inline
branch that special-cases WorldOil inside the loop with a small lookup table:
create a Record/Partial (e.g., extraAssetsByMap or perMapAllowlist) mapping
GameMapName keys to arrays of extra filenames, then compute allowedFiles as
allowedFiles = [...expected, ...(perMapAllowlist[key] || [])].sort() (or just
expected when none). Update the comparison that uses files and errors.push
unchanged; remove the key === "WorldOil" conditional so future maps can be
handled by adding entries to the lookup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@map-generator/assets/maps/worldoil/OIL_EDITING.md`:
- Line 5: Replace the hard-coded absolute local path in the markdown link "Open
[image.png](/home/luke/CLASS/EECS/481/final/map-generator/assets/maps/worldoil/image.png)"
with a repo-relative path so others can access the image; update that link to
use a relative reference such as "./image.png" (i.e., "Open
[image.png](./image.png)") in the OIL_EDITING.md file.

In `@tests/NationStructureBehavior.test.ts`:
- Around line 2-9: Remove the unused imports ConstructionExecution and UnitType
from the import block that references ConstructionExecution and Game
(Difficulty, PlayerType, TerrainType, UnitType); update the import for Game to
only include the used symbols (Difficulty, PlayerType, TerrainType) so
ESLint/Prettier stop flagging unused imports and the Game import collapses
cleanly.

---

Nitpick comments:
In `@src/client/graphics/layers/StructureDrawingUtils.ts`:
- Around line 373-395: The three near-duplicate cases "pentagon", "octagon", and
"septagon" in StructureDrawingUtils.ts should be replaced by a small helper to
avoid copy/paste: add a drawRegularPolygon(context, cx, cy, r, sides,
startAngle) function that begins a path, loops sides times computing angle =
startAngle + i*(2*Math.PI/sides), uses moveTo for i==0 and lineTo otherwise,
then closePath(), fill() and stroke(); then replace each case body with a single
call like drawRegularPolygon(context, halfIconSize, halfIconSize, halfIconSize -
1, N, -Math.PI/2) where N is 5, 7, or 8 for pentagon/septagon/octagon
respectively.

In `@tests/MapConsistency.test.ts`:
- Around line 138-154: Replace the inline branch that special-cases WorldOil
inside the loop with a small lookup table: create a Record/Partial (e.g.,
extraAssetsByMap or perMapAllowlist) mapping GameMapName keys to arrays of extra
filenames, then compute allowedFiles as allowedFiles = [...expected,
...(perMapAllowlist[key] || [])].sort() (or just expected when none). Update the
comparison that uses files and errors.push unchanged; remove the key ===
"WorldOil" conditional so future maps can be handled by adding entries to the
lookup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 78608d04-f0a2-4866-b63a-156684d11858

📥 Commits

Reviewing files that changed from the base of the PR and between 0e91601 and def2454.

📒 Files selected for processing (12)
  • map-generator/assets/maps/worldoil/OIL_EDITING.md
  • resources/maps/worldoil/manifest.json
  • src/client/HelpModal.ts
  • src/client/graphics/layers/StructureDrawingUtils.ts
  • src/client/graphics/layers/UnitDisplay.ts
  • src/core/game/Game.ts
  • src/server/MapPlaylist.ts
  • tests/MapConsistency.test.ts
  • tests/NationStructureBehavior.test.ts
  • tests/TranslationSystem.test.ts
  • tests/core/game/TrainStation.test.ts
  • tests/economy/ConstructionGold.test.ts
✅ Files skipped from review due to trivial changes (3)
  • src/server/MapPlaylist.ts
  • resources/maps/worldoil/manifest.json
  • src/client/HelpModal.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/economy/ConstructionGold.test.ts
  • src/client/graphics/layers/UnitDisplay.ts
  • tests/core/game/TrainStation.test.ts
  • src/core/game/Game.ts

Comment thread map-generator/assets/maps/worldoil/OIL_EDITING.md Outdated
Comment thread tests/NationStructureBehavior.test.ts Outdated
@socket-security
Copy link
Copy Markdown

socket-security bot commented Apr 18, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedpypi/​pillow@​12.2.08010010010080

View full report

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/core/game/Game.ts (2)

329-329: TrainMission union — simple and typed, love it.

Typed union beats a class hierarchy here. One small suggestion: consider exporting a const tuple alongside (e.g. export const TRAIN_MISSIONS = ["trade", "freight"] as const;) so runtime validation/iteration stays in sync with the type without duplicating literals. Optional.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/game/Game.ts` at line 329, The exported TrainMission type is fine
but lacks a canonical runtime list for validation/iteration; add and export a
const tuple (e.g. a TRAIN_MISSIONS constant) that contains the same string
literals and use a const assertion so its element types match TrainMission, then
update any runtime checks/iteration to reference TRAIN_MISSIONS instead of
duplicating the literals; ensure TrainMission remains the union type and keep
usages (validation, iteration) in sync by using that constant.

28-28: Tiny nit: single-value union is a bit lonely.

BonusIcon = "oil" works, but a union of one feels like a club with one member. If you expect more icons soon, leave it; otherwise consider just using "oil" inline. Totally optional.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/game/Game.ts` at line 28, The exported type BonusIcon currently is a
single-member union ("oil"), which is unnecessary; either remove the BonusIcon
type and replace its usages with the string literal "oil" directly, or expand it
now to an explicit enum/union of expected icons (e.g., export type BonusIcon =
"oil" | "water" | ...) if you plan to add icons soon; update all references to
BonusIcon (the type name) accordingly so the code compiles with the chosen
approach.
map-generator/requirements.txt (1)

1-1: Pin Pillow to a recent safe version

Adding Pillow without a version pin creates two problems: builds become non-reproducible (different installs may pull different versions), and you risk getting a version with known vulnerabilities. The Pillow package has had many security fixes across versions. Specify a minimum safe version such as Pillow>=12.2.0 (the latest) or verify a safe version floor using the OSV query below.

Suggested change
-Pillow
+Pillow>=12.2.0

Use this script to check the latest safe versions and recent security advisories:

#!/bin/bash
set -euo pipefail

echo "Latest Pillow release on PyPI:"
curl -s https://pypi.org/pypi/Pillow/json | jq -r '.info.version'

echo
echo "Recent OSV advisories for Pillow:"
curl -s "https://api.osv.dev/v1/query" \
  -H "Content-Type: application/json" \
  -d '{"package":{"name":"Pillow","ecosystem":"PyPI"}}' \
| jq -r '.vulns[]? | "\(.id) | introduced: \(.affected[0].ranges[0].events[]?.introduced // "-") | fixed: \(.affected[0].ranges[0].events[]?.fixed // "-")"'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@map-generator/requirements.txt` at line 1, requirements.txt currently lists
Pillow without a version pin which can lead to unreproducible builds and pull
vulnerable releases; update the entry for Pillow to pin a recent safe minimum
(for example change "Pillow" to "Pillow>=12.2.0" or another vetted safe version)
so installs are deterministic and avoid known vulnerabilities.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/core/game/Game.ts`:
- Line 706: The addGold signature now accepts icon?: BonusIcon but
PlayerImpl.addGold (the implementation that constructs BonusEvent) never
forwards it; update the code that builds the BonusEvent in PlayerImpl (and any
other place that emits BonusEvent) to include the icon field passed into
addGold, and update the BonusEvent shape in GameUpdates.ts (and its exported
type) to include icon?: BonusIcon so the payload carries the icon value through
to the client renderer.

---

Nitpick comments:
In `@map-generator/requirements.txt`:
- Line 1: requirements.txt currently lists Pillow without a version pin which
can lead to unreproducible builds and pull vulnerable releases; update the entry
for Pillow to pin a recent safe minimum (for example change "Pillow" to
"Pillow>=12.2.0" or another vetted safe version) so installs are deterministic
and avoid known vulnerabilities.

In `@src/core/game/Game.ts`:
- Line 329: The exported TrainMission type is fine but lacks a canonical runtime
list for validation/iteration; add and export a const tuple (e.g. a
TRAIN_MISSIONS constant) that contains the same string literals and use a const
assertion so its element types match TrainMission, then update any runtime
checks/iteration to reference TRAIN_MISSIONS instead of duplicating the
literals; ensure TrainMission remains the union type and keep usages
(validation, iteration) in sync by using that constant.
- Line 28: The exported type BonusIcon currently is a single-member union
("oil"), which is unnecessary; either remove the BonusIcon type and replace its
usages with the string literal "oil" directly, or expand it now to an explicit
enum/union of expected icons (e.g., export type BonusIcon = "oil" | "water" |
...) if you plan to add icons soon; update all references to BonusIcon (the type
name) accordingly so the code compiles with the chosen approach.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eab676a8-cef4-4068-9591-02292e8414f0

📥 Commits

Reviewing files that changed from the base of the PR and between def2454 and 46ccdb0.

📒 Files selected for processing (3)
  • map-generator/requirements.txt
  • src/core/game/Game.ts
  • tests/NationStructureBehavior.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/NationStructureBehavior.test.ts

Comment thread src/core/game/Game.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Development

Development

Successfully merging this pull request may close these issues.

3 participants