diff --git a/src/client/graphics/layers/UnitInfoModal.ts b/src/client/graphics/layers/UnitInfoModal.ts index 6a31abdf9..a8d34be30 100644 --- a/src/client/graphics/layers/UnitInfoModal.ts +++ b/src/client/graphics/layers/UnitInfoModal.ts @@ -246,7 +246,10 @@ export class UnitInfoModal extends LitElement implements Layer { class="upgrade-button" title="${translateText("unit_info_modal.create_station")}" style="width: 100px; height: 32px; - display: ${this.unit.hasTrainStation() ? "none" : "block"};" + display: ${this.unit.hasTrainStation() || + !this.game.unitInfo(this.unit.type()).canBuildTrainStation + ? "none" + : "block"};" > ${translateText("unit_info_modal.create_station")} diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index 2e327b14c..6ad3075fd 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -302,7 +302,7 @@ export class DefaultConfig implements Config { return Math.min(50, Math.round(10 * Math.pow(numberOfPorts, 0.6))); } trainSpawnRate(numberOfStations: number): number { - return Math.round(50 * Math.pow(numberOfStations, 0.8)); + return Math.min(1400, Math.round(60 * Math.pow(numberOfStations, 0.8))); } trainGold(): Gold { return BigInt(10_000); @@ -363,6 +363,7 @@ export class DefaultConfig implements Config { territoryBound: true, constructionDuration: this.instantBuild() ? 0 : 2 * 10, upgradable: true, + canBuildTrainStation: true, }; case UnitType.AtomBomb: return { @@ -452,6 +453,7 @@ export class DefaultConfig implements Config { territoryBound: true, constructionDuration: this.instantBuild() ? 0 : 2 * 10, upgradable: true, + canBuildTrainStation: true, }; case UnitType.Factory: return { @@ -466,6 +468,7 @@ export class DefaultConfig implements Config { ), territoryBound: true, constructionDuration: this.instantBuild() ? 0 : 2 * 10, + canBuildTrainStation: true, }; case UnitType.Construction: return { diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index aa19683f3..d2bbade2f 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -132,6 +132,7 @@ export interface UnitInfo { damage?: number; constructionDuration?: number; upgradable?: boolean; + canBuildTrainStation?: boolean; } export enum UnitType { diff --git a/src/core/game/RailNetworkImpl.ts b/src/core/game/RailNetworkImpl.ts index 89cee93c7..5d220e6f5 100644 --- a/src/core/game/RailNetworkImpl.ts +++ b/src/core/game/RailNetworkImpl.ts @@ -88,6 +88,8 @@ export function createRailNetwork(game: Game): RailNetwork { } export class RailNetworkImpl implements RailNetwork { + private maxConnectionDistance: number = 4; + constructor( private game: Game, private stationManager: StationManager, @@ -142,12 +144,20 @@ export class RailNetworkImpl implements RailNetwork { const neighborStation = this.stationManager.findStation(neighbor.unit); if (!neighborStation) continue; - const neighborCluster = neighborStation.getCluster(); - if (!neighborCluster || neighborCluster.has(station)) continue; + const distanceToStation = this.distanceFrom( + neighborStation, + station, + this.maxConnectionDistance, + ); + const neighborCluster = neighborStation.getCluster(); + if (neighborCluster === null) continue; + const connectionAvailable = + distanceToStation > this.maxConnectionDistance || + distanceToStation === -1; if ( - neighbor.distSquared > - this.game.config().trainStationMinRange() ** 2 + connectionAvailable && + neighbor.distSquared > this.game.config().trainStationMinRange() ** 2 ) { if (this.connect(station, neighborStation)) { neighborCluster.addStation(station); @@ -196,6 +206,37 @@ export class RailNetworkImpl implements RailNetwork { return false; } + private distanceFrom( + start: TrainStation, + dest: TrainStation, + maxDistance: number, + ): number { + if (start === dest) return 0; + + const visited = new Set(); + const queue: Array<{ station: TrainStation; distance: number }> = [ + { station: start, distance: 0 }, + ]; + + while (queue.length > 0) { + const { station, distance } = queue.shift()!; + if (visited.has(station)) continue; + visited.add(station); + + if (distance >= maxDistance) continue; + + for (const neighbor of station.neighbors()) { + if (neighbor === dest) return distance + 1; + if (!visited.has(neighbor)) { + queue.push({ station: neighbor, distance: distance + 1 }); + } + } + } + + // If destination not found within maxDistance + return -1; + } + private computeCluster(start: TrainStation): Set { const visited = new Set(); const queue = [start];