Build bridges to connect stations across water (#1961)

Derived from [LeviathanLevi
PR](https://github.com/openfrontio/OpenFrontIO/pull/1847)
Connect stations over water by automatically building bridges

Changes:
- Railroad construction to water is allowed from shore lines
- Railroad construction from water is allowed to shore lines too

This creates bridges a few tiles long.

<img width="1058" height="680" alt="image"
src="https://github.com/user-attachments/assets/493737b9-7aff-4ee2-88ea-7638f6af7c91"
/>

<img width="361" height="317" alt="image"
src="https://github.com/user-attachments/assets/24a71a7a-1ba1-4c88-a89e-876127024148"
/>

fixes #1837

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
regression is found:

IngloriousTom
This commit is contained in:
DevelopingTom
2025-08-29 01:04:28 +02:00
committed by evanpelle
parent 121ac0eede
commit fc9eb2bec0
3 changed files with 149 additions and 18 deletions
+15 -3
View File
@@ -4,6 +4,7 @@ import { AStar, PathFindResultType } from "./AStar";
import { GraphAdapter, SerialAStar } from "./SerialAStar";
export class GameMapAdapter implements GraphAdapter<TileRef> {
private readonly waterPenalty = 3;
constructor(
private gameMap: GameMap,
private waterPath: boolean,
@@ -14,7 +15,12 @@ export class GameMapAdapter implements GraphAdapter<TileRef> {
}
cost(node: TileRef): number {
return this.gameMap.cost(node);
let base = this.gameMap.cost(node);
// Avoid crossing water when possible
if (!this.waterPath && this.gameMap.isWater(node)) {
base += this.waterPenalty;
}
return base;
}
position(node: TileRef): { x: number; y: number } {
@@ -22,8 +28,14 @@ export class GameMapAdapter implements GraphAdapter<TileRef> {
}
isTraversable(from: TileRef, to: TileRef): boolean {
const isWater = this.gameMap.isWater(to);
return this.waterPath ? isWater : !isWater;
const toWater = this.gameMap.isWater(to);
if (this.waterPath) {
return toWater;
}
// Allow water access from/to shore
const fromShore = this.gameMap.isShoreline(from);
const toShore = this.gameMap.isShoreline(to);
return !toWater || fromShore || toShore;
}
}
export class MiniAStar implements AStar<TileRef> {