Skip to content

Comments

v30 nuke wars preparation: Disable boats & Team spawn zones#3263

Open
FloPinguin wants to merge 9 commits intomainfrom
new-modifiers
Open

v30 nuke wars preparation: Disable boats & Team spawn zones#3263
FloPinguin wants to merge 9 commits intomainfrom
new-modifiers

Conversation

@FloPinguin
Copy link
Contributor

Description:

Preparation for nuke wars, for v30.
Next PR will be adding the nuke wars modifier for public games, but Wonders #3224 needs to be merged first to avoid merge conflicts.

1. Disable boats setting

It's possible to disable UnitType.TransportShip now. Because they are not needed in nuke wars and can even be annoying.

image

2. Team spawn zones for random spawn

Maps can have teamGameSpawnAreas in their json file now.
Spawn areas are currently active if

  • a supported map is chosen (Baikal Nuke Wars or Four Islands)
  • a supported team size is chosen (2 teams on Baikal Nuke Wars or 2/4 teams on Four Islands)
  • random spawn is enabled

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

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

FloPinguin

@FloPinguin FloPinguin added this to the v30 milestone Feb 21, 2026
@FloPinguin FloPinguin requested a review from a team as a code owner February 21, 2026 14:53
@FloPinguin FloPinguin changed the title v30 nuke wars preparation: Team spawn zones & disable boats v30 nuke wars preparation: Disable boats & Team spawn zones Feb 21, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 21, 2026

Important

Review skipped

This PR was authored by the user configured for CodeRabbit reviews. By default, CodeRabbit skips reviewing PRs authored by this user. It's recommended to use a dedicated user account to post CodeRabbit review feedback.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Adds team-based rectangular spawn areas: new SpawnArea types and TeamGameSpawnAreas, map/manifest fields, loader scaling for Compact maps, Game plumbing to store/expose team areas, spawn logic constrained to team areas when present, plus a boat unit label and UI option.

Changes

Cohort / File(s) Summary
Map Configuration
map-generator/assets/maps/baikalnukewars/info.json, map-generator/assets/maps/fourislands/info.json, resources/maps/baikalnukewars/manifest.json, resources/maps/fourislands/manifest.json
Added teamGameSpawnAreas top-level field mapping team IDs to arrays of rectangular spawn areas (x, y, width, height). Baikal: areas for team "2". Four Islands: areas for "2" and "4".
Localization & UI
resources/lang/en.json, src/client/components/GameConfigSettings.ts
Added unit_type.boat translation and exposed UnitType.TransportShip (translationKey unit_type.boat) as a selectable unit option in the game settings UI.
Spawn Area Types & Loader
src/core/game/SpawnArea.ts, src/core/game/TerrainMapLoader.ts
New SpawnArea interface and TeamGameSpawnAreas alias. TerrainMapLoader accepts/returns optional teamGameSpawnAreas, scales areas for Compact mapSize, and uses a composite cache key for loaded maps.
Game Core & Init
src/core/game/Game.ts, src/core/game/GameImpl.ts, src/core/GameRunner.ts
Game API gains `teamSpawnArea(team): SpawnArea
Spawn Execution & Nation Spawn
src/core/execution/SpawnExecution.ts, src/core/execution/NationExecution.ts
Spawn logic now prefers/selects random spawn tiles inside a team-defined SpawnArea when available; otherwise falls back to prior behavior. randTile updated to accept an optional SpawnArea.
Unit Configuration
src/core/configuration/DefaultConfig.ts
boatMaxNumber() returns 0 when TransportShip units are disabled; otherwise returns previous default.

Sequence Diagram(s)

sequenceDiagram
    participant Loader as MapLoader (TerrainMapLoader)
    participant Runner as GameRunner
    participant Game as GameImpl
    participant Nation as NationExecution
    participant Spawn as SpawnExecution

    Loader->>Loader: load manifest\nextract teamGameSpawnAreas
    Loader->>Loader: scale areas if mapSize == Compact

    Runner->>Game: createGame(..., teamGameSpawnAreas)
    Game->>Game: store _teamGameSpawnAreas

    Nation->>Game: teamSpawnArea(team)
    Game-->>Nation: return SpawnArea[] or undefined

    alt nation spawn outside team area or needs constrained spawn
        Nation->>Spawn: schedule spawn with team area
        Spawn->>Game: teamSpawnArea(team)
        Game-->>Spawn: return area
        Spawn->>Spawn: pick random tile within area
        Spawn->>Nation: place unit
    else no team area
        Nation->>Nation: use normal spawn logic
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

⛵ Boxes drawn where crews will start,
Maps get bounds and teams take part,
A boat gets named, a UI bit,
Spawns now heed the shaped-out grid,
Small lines of code, a calmer chart.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes both main changes: disabling boats and adding team spawn zones for the v30 nuke wars preparation.
Description check ✅ Passed The description is directly related to the changeset, explaining the nuke wars v30 preparation with clear details about boats setting and team spawn zones.

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


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

Copy link
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

Caution

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

⚠️ Outside diff range comments (1)
src/core/game/TerrainMapLoader.ts (1)

43-44: ⚠️ Potential issue | 🟠 Major

Compact-map spawn-area scaling is silently bypassed for cached map types

loadedMaps is keyed only by GameMapType (line 43–44). If fourislands is first loaded as Normal size, the cache stores the full-size teamGameSpawnAreas ({x:750, y:0, …}). A later Compact-size load hits the early return and returns the same unscaled areas. At runtime, randTile would generate coordinates in the range [0, 1500) on a 750×750 map, producing out-of-bounds tile refs on every team-area spawn attempt.

The same cache-key gap exists for gameMap/miniGameMap selection (pre-existing), but this PR adds new behavior that is immediately incorrect when triggered.

The minimal fix is to include mapSize in the cache key:

🔧 Proposed fix
-const loadedMaps = new Map<GameMapType, TerrainMapData>();
+const loadedMaps = new Map<string, TerrainMapData>();

 export async function loadTerrainMap(
   map: GameMapType,
   mapSize: GameMapSize,
   terrainMapFileLoader: GameMapLoader,
 ): Promise<TerrainMapData> {
-  const cached = loadedMaps.get(map);
+  const cacheKey = `${map}:${mapSize}`;
+  const cached = loadedMaps.get(cacheKey);
   if (cached !== undefined) return cached;
   // ...
-  loadedMaps.set(map, result);
+  loadedMaps.set(cacheKey, result);
   return result;
 }

Also applies to: 70-83

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

In `@src/core/game/TerrainMapLoader.ts` around lines 43 - 44, The cache for
loadedMaps is keyed only by GameMapType, causing Compact vs Normal loads to
share unscaled teamGameSpawnAreas; update TerrainMapLoader to incorporate
mapSize into the cache key (e.g., use a composite key of GameMapType + mapSize)
so that loadedMaps.get(...) and loadedMaps.set(...) distinguish sizes, and apply
the same composite-key change to the other cache usages around the
gameMap/miniGameMap selection (lines ~70–83) so randTile and teamGameSpawnAreas
are generated/stored per (map, mapSize) combination.
🧹 Nitpick comments (2)
src/core/execution/SpawnExecution.ts (1)

81-133: getTeamSpawnArea() is re-evaluated on every loop iteration despite returning a constant value

The spawn area for a given player/team does not change during randomSpawnLand(). Calling getTeamSpawnArea() (and therefore hasPlayer(), player(), team(), teamSpawnArea()) up to MAX_SPAWN_TRIES times adds needless overhead and reduces readability. Computing it once before the loop also keeps randTile() a pure coordinate-generator.

♻️ Proposed refactor
  private randomSpawnLand(): TileRef | undefined {
    let tries = 0;
+   const spawnArea = this.getTeamSpawnArea();

    while (tries < SpawnExecution.MAX_SPAWN_TRIES) {
      tries++;

-     const tile = this.randTile();
+     const tile = this.randTile(spawnArea);
      // ...
    }
    return;
  }

- private randTile(): TileRef {
-   const area = this.getTeamSpawnArea();
-   if (area) {
+ private randTile(area?: SpawnArea): TileRef {
+   if (area) {
      const x = this.random.nextInt(area.x, area.x + area.width);
      const y = this.random.nextInt(area.y, area.y + area.height);
      return this.mg.ref(x, y);
    }
    const x = this.random.nextInt(0, this.mg.width());
    const y = this.random.nextInt(0, this.mg.height());
    return this.mg.ref(x, y);
  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/execution/SpawnExecution.ts` around lines 81 - 133, In
randomSpawnLand(), cache the team spawn area once before the while loop instead
of calling getTeamSpawnArea() repeatedly via randTile(); compute const area =
this.getTeamSpawnArea() (or similar) once and pass that area into randTile (or
make randTile accept an optional area parameter) so randTile becomes a pure
coordinate generator that uses the provided area when present; update
randomSpawnLand() to call randTile(area) each iteration and leave
MAX_SPAWN_TRIES, random, and other logic unchanged.
src/core/game/TerrainMapLoader.ts (1)

4-6: Re-exporting SpawnArea/TeamGameSpawnAreas from TerrainMapLoader creates a duplicate import path

SpawnArea.ts is the canonical source. All changed files in this PR import directly from SpawnArea.ts. The export type { SpawnArea, TeamGameSpawnAreas } here adds a second path (TerrainMapLoader) for the same types with no current consumer. If left in place, future code may import from either location inconsistently. Consider removing the re-export and letting callers depend on SpawnArea.ts directly.

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

In `@src/core/game/TerrainMapLoader.ts` around lines 4 - 6, Remove the re-export
that creates a duplicate import path: delete the line "export type { SpawnArea,
TeamGameSpawnAreas }" from TerrainMapLoader.ts so SpawnArea and
TeamGameSpawnAreas remain exported only from SpawnArea.ts; keep the local import
if TerrainMapLoader still uses those types, and if any files were accidentally
importing the types from TerrainMapLoader, change them to import from
SpawnArea.ts instead.
🤖 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/GameImpl.ts`:
- Around line 800-814: The field playerTeams is declared as Team[] but can be
uninitialized at runtime; update its declaration to be explicitly optional
(Team[] | undefined) or initialize it to an empty array (Team[] = []) so
TypeScript reflects the runtime possibility, then adjust any code that relies on
it (e.g., teamSpawnArea and populateTeams) to handle the new type (use non-null
checks or assign before use) so the existing runtime guard in teamSpawnArea
remains meaningful to the type system.

---

Outside diff comments:
In `@src/core/game/TerrainMapLoader.ts`:
- Around line 43-44: The cache for loadedMaps is keyed only by GameMapType,
causing Compact vs Normal loads to share unscaled teamGameSpawnAreas; update
TerrainMapLoader to incorporate mapSize into the cache key (e.g., use a
composite key of GameMapType + mapSize) so that loadedMaps.get(...) and
loadedMaps.set(...) distinguish sizes, and apply the same composite-key change
to the other cache usages around the gameMap/miniGameMap selection (lines
~70–83) so randTile and teamGameSpawnAreas are generated/stored per (map,
mapSize) combination.

---

Nitpick comments:
In `@src/core/execution/SpawnExecution.ts`:
- Around line 81-133: In randomSpawnLand(), cache the team spawn area once
before the while loop instead of calling getTeamSpawnArea() repeatedly via
randTile(); compute const area = this.getTeamSpawnArea() (or similar) once and
pass that area into randTile (or make randTile accept an optional area
parameter) so randTile becomes a pure coordinate generator that uses the
provided area when present; update randomSpawnLand() to call randTile(area) each
iteration and leave MAX_SPAWN_TRIES, random, and other logic unchanged.

In `@src/core/game/TerrainMapLoader.ts`:
- Around line 4-6: Remove the re-export that creates a duplicate import path:
delete the line "export type { SpawnArea, TeamGameSpawnAreas }" from
TerrainMapLoader.ts so SpawnArea and TeamGameSpawnAreas remain exported only
from SpawnArea.ts; keep the local import if TerrainMapLoader still uses those
types, and if any files were accidentally importing the types from
TerrainMapLoader, change them to import from SpawnArea.ts instead.

@github-project-automation github-project-automation bot moved this from Triage to Development in OpenFront Release Management Feb 21, 2026
Copy link
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.

🧹 Nitpick comments (1)
src/core/game/GameImpl.ts (1)

800-814: Remove dead !this.playerTeams guard.

playerTeams is now initialized to [] (line 98), so !this.playerTeams is always false — an empty array is truthy in JavaScript. The !areas check on line 806 already handles the non-team-mode case (when playerTeams is [], numTeams is 0, and _teamGameSpawnAreas["0"] is undefined).

♻️ Remove dead guard
  teamSpawnArea(team: Team): SpawnArea | undefined {
-   if (!this._teamGameSpawnAreas || !this.playerTeams) {
+   if (!this._teamGameSpawnAreas) {
      return undefined;
    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/game/GameImpl.ts` around lines 800 - 814, In teamSpawnArea, remove
the dead guard that checks !this.playerTeams: since playerTeams is always
initialized to an array, the check is redundant; update the function
(referencing teamSpawnArea, this.playerTeams, and this._teamGameSpawnAreas) to
only early-return when this._teamGameSpawnAreas is falsy, leaving the later
logic (numTeams, areas lookup, teamIndex bounds check) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/core/game/GameImpl.ts`:
- Around line 800-814: In teamSpawnArea, remove the dead guard that checks
!this.playerTeams: since playerTeams is always initialized to an array, the
check is redundant; update the function (referencing teamSpawnArea,
this.playerTeams, and this._teamGameSpawnAreas) to only early-return when
this._teamGameSpawnAreas is falsy, leaving the later logic (numTeams, areas
lookup, teamIndex bounds check) unchanged.

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 21, 2026
coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 21, 2026
…ction

refactor(TerrainMapLoader): clean up imports by removing unused SpawnArea export
Copy link
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.

Caution

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

⚠️ Outside diff range comments (1)
src/core/game/TerrainMapLoader.ts (1)

41-42: ⚠️ Potential issue | 🟡 Minor

Cache is keyed by map only, not by mapSize — stale data risk.

The module-level loadedMaps cache uses GameMapType as the sole key (line 13). However, the cached data includes mapSize-dependent values: nations are scaled when mapSize is Compact (lines 59-65), and teamGameSpawnAreas are scaled conditionally (lines 70-81).

If the same map is loaded with different mapSize values in one process, the second call returns the first call's cached result, including its (un)scaled nations and spawn areas. This is incorrect.

This is a pre-existing issue, but the new spawn-area scaling makes it more visible. Consider fixing the cache key to include mapSize: new Map<[GameMapType, GameMapSize], TerrainMapData>().

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

In `@src/core/game/TerrainMapLoader.ts` around lines 41 - 42, The cache is
currently keyed only by GameMapType (loadedMaps) so calls to loadTerrainMap (or
the loader function that reads `map` and `mapSize`) can return stale data when
the same map is requested with different GameMapSize; change loadedMaps to use a
composite key that includes mapSize (e.g., Map<[GameMapType, GameMapSize],
TerrainMapData> or a serialized string key `${map}:${mapSize}`), update the
lookup where `const cached = loadedMaps.get(map)` to use the composite key, and
update where results are stored into loadedMaps to use the same composite key so
scaled nations and teamGameSpawnAreas are cached per map+size combination
(ensure all references to loadedMaps.get/set use the new key format).
🧹 Nitpick comments (2)
src/core/game/TerrainMapLoader.ts (1)

68-81: Scaling logic is consistent with nation coordinates — good. One small note on Math.floor for width/height.

When you halve width and height with Math.floor, odd values lose a pixel (e.g., width 11 becomes 5, not 5.5). This shrinks the spawn area slightly. For large areas this is fine, but if any area dimension is 1, it becomes 0, which would make randTile call nextInt(x, x) — a degenerate range. Probably never happens in practice, but a Math.max(..., 1) guard would be cheap insurance.

Optional: guard against zero-sized dimensions
       scaled[key] = areas.map((a) => ({
         x: Math.floor(a.x / 2),
         y: Math.floor(a.y / 2),
-        width: Math.floor(a.width / 2),
-        height: Math.floor(a.height / 2),
+        width: Math.max(Math.floor(a.width / 2), 1),
+        height: Math.max(Math.floor(a.height / 2), 1),
       }));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/game/TerrainMapLoader.ts` around lines 68 - 81, The scaling block
for teamGameSpawnAreas can produce zero width/height when halving odd small
dimensions; update the scaling in TerrainMapLoader where teamGameSpawnAreas is
computed (the loop that builds scaled) to clamp width and height to at least 1
(e.g., replace Math.floor(a.width / 2) and Math.floor(a.height / 2) with
Math.max(Math.floor(...), 1)) so spawn areas never become zero-sized; keep x/y
as Math.floor(a.x/2) but ensure width/height use the Math.max guard to avoid
degenerate ranges later when randTile or similar functions consume these areas.
src/core/execution/SpawnExecution.ts (1)

135-145: The hasPlayer guard on line 136 is always true at the call site — harmless but redundant.

When randomSpawnLand() is called from tick() (line 51), the player has already been added at lines 40–44. So hasPlayer can never be false here. This is safe defensive code — not a problem, just noting it in case you want to simplify.

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

In `@src/core/execution/SpawnExecution.ts` around lines 135 - 145, The hasPlayer()
check in getTeamSpawnArea() is redundant at the call site (randomSpawnLand()
invoked from tick() after the player is added), so remove the unnecessary guard
and simplify the method: directly call this.mg.player(this.playerInfo.id),
retrieve team via player.team(), return undefined if team is null, otherwise
return this.mg.teamSpawnArea(team); keep method name getTeamSpawnArea and
callers unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/core/game/TerrainMapLoader.ts`:
- Around line 41-42: The cache is currently keyed only by GameMapType
(loadedMaps) so calls to loadTerrainMap (or the loader function that reads `map`
and `mapSize`) can return stale data when the same map is requested with
different GameMapSize; change loadedMaps to use a composite key that includes
mapSize (e.g., Map<[GameMapType, GameMapSize], TerrainMapData> or a serialized
string key `${map}:${mapSize}`), update the lookup where `const cached =
loadedMaps.get(map)` to use the composite key, and update where results are
stored into loadedMaps to use the same composite key so scaled nations and
teamGameSpawnAreas are cached per map+size combination (ensure all references to
loadedMaps.get/set use the new key format).

---

Nitpick comments:
In `@src/core/execution/SpawnExecution.ts`:
- Around line 135-145: The hasPlayer() check in getTeamSpawnArea() is redundant
at the call site (randomSpawnLand() invoked from tick() after the player is
added), so remove the unnecessary guard and simplify the method: directly call
this.mg.player(this.playerInfo.id), retrieve team via player.team(), return
undefined if team is null, otherwise return this.mg.teamSpawnArea(team); keep
method name getTeamSpawnArea and callers unchanged.

In `@src/core/game/TerrainMapLoader.ts`:
- Around line 68-81: The scaling block for teamGameSpawnAreas can produce zero
width/height when halving odd small dimensions; update the scaling in
TerrainMapLoader where teamGameSpawnAreas is computed (the loop that builds
scaled) to clamp width and height to at least 1 (e.g., replace
Math.floor(a.width / 2) and Math.floor(a.height / 2) with
Math.max(Math.floor(...), 1)) so spawn areas never become zero-sized; keep x/y
as Math.floor(a.x/2) but ensure width/height use the Math.max guard to avoid
degenerate ranges later when randTile or similar functions consume these areas.

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 21, 2026
…ieval

refactor(SpawnExecution): remove unnecessary player check in getTeamSpawnArea
Copy link
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.

🧹 Nitpick comments (2)
src/core/execution/SpawnExecution.ts (1)

124-133: randTile logic is correct; note implicit assumption about nextInt upper-bound exclusivity.

nextInt(area.x, area.x + area.width) produces exactly width distinct x-values only if nextInt is exclusive on the upper bound — which is consistent with the existing nextInt(0, mg.width()) usage for the full-map path. If PseudoRandom.nextInt semantics ever change to inclusive, this would silently sample one column/row outside the area. A brief comment here would make the intent explicit.

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

In `@src/core/execution/SpawnExecution.ts` around lines 124 - 133, Add a short
clarifying comment above the randTile method that documents the assumption that
PseudoRandom.nextInt(a, b) treats b as an exclusive upper bound (so
nextInt(area.x, area.x + area.width) yields exactly area.width distinct values),
and note that if nextInt semantics change to inclusive the sampling could go out
of the intended area; reference the randTile function and PseudoRandom.nextInt
in the comment and, if desired, suggest clamping or using (width-1)/(height-1)
to guard against out-of-range coordinates.
src/core/game/TerrainMapLoader.ts (1)

41-42: Cache key fix is correct; consider a nested Map to eliminate string-collision risk entirely.

The old single-key lookup was buggy — loading the same map in two different sizes could return stale scaled/unscaled data from cache. The composite string key ${map}:${mapSize} fixes that correctly.

Minor: when concatenating strings, the joiner must not appear in either key part. GameMapType values look like "WorldMap" / "BaikalNukeWars" so : is safe in practice, but a nested Map removes the concern completely:

♻️ Nested map alternative
-const loadedMaps = new Map<string, TerrainMapData>();
+const loadedMaps = new Map<GameMapType, Map<GameMapSize, TerrainMapData>>();

Then adjust lookup/insert:

-  const cacheKey = `${map}:${mapSize}`;
-  const cached = loadedMaps.get(cacheKey);
-  if (cached !== undefined) return cached;
+  const cached = loadedMaps.get(map)?.get(mapSize);
+  if (cached !== undefined) return cached;
-  loadedMaps.set(cacheKey, result);
+  if (!loadedMaps.has(map)) loadedMaps.set(map, new Map());
+  loadedMaps.get(map)!.set(mapSize, result);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/game/TerrainMapLoader.ts` around lines 41 - 42, Replace the
composite string key approach in TerrainMapLoader (the cacheKey variable and its
use with loadedMaps) with a nested Map keyed first by map (GameMapType) then by
mapSize to avoid string-collision risks; change loadedMaps to Map<map,
Map<mapSize, LoadedMapType>> (or equivalent), read via inner =
loadedMaps.get(map) then cached = inner?.get(mapSize), and on insert ensure an
inner map is created if missing (loadedMaps.set(map, new Map()) then
inner.set(mapSize, value)); update all lookup/insert sites that currently use
cacheKey to use this two-level map access pattern.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/core/execution/SpawnExecution.ts`:
- Around line 124-133: Add a short clarifying comment above the randTile method
that documents the assumption that PseudoRandom.nextInt(a, b) treats b as an
exclusive upper bound (so nextInt(area.x, area.x + area.width) yields exactly
area.width distinct values), and note that if nextInt semantics change to
inclusive the sampling could go out of the intended area; reference the randTile
function and PseudoRandom.nextInt in the comment and, if desired, suggest
clamping or using (width-1)/(height-1) to guard against out-of-range
coordinates.

In `@src/core/game/TerrainMapLoader.ts`:
- Around line 41-42: Replace the composite string key approach in
TerrainMapLoader (the cacheKey variable and its use with loadedMaps) with a
nested Map keyed first by map (GameMapType) then by mapSize to avoid
string-collision risks; change loadedMaps to Map<map, Map<mapSize,
LoadedMapType>> (or equivalent), read via inner = loadedMaps.get(map) then
cached = inner?.get(mapSize), and on insert ensure an inner map is created if
missing (loadedMaps.set(map, new Map()) then inner.set(mapSize, value)); update
all lookup/insert sites that currently use cacheKey to use this two-level map
access pattern.

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Development

Development

Successfully merging this pull request may close these issues.

1 participant