Files
OpenFrontIO/src/core/execution/TrainStationExecution.ts
T
Scott Anderson b0ec4c5558 Fix trainwreck bug (#1925)
Fixes #1922, the trainwreck bug.

- [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
2025-09-03 16:31:48 -07:00

102 lines
2.8 KiB
TypeScript

import { Execution, Game, Unit, UnitType } from "../game/Game";
import { TrainStation } from "../game/TrainStation";
import { PseudoRandom } from "../PseudoRandom";
import { TrainExecution } from "./TrainExecution";
export class TrainStationExecution implements Execution {
private mg: Game;
private active: boolean = true;
private random: PseudoRandom;
private station: TrainStation | null = null;
private numCars: number = 5;
private lastSpawnTick: number = 0;
private ticksCooldown: number = 10; // Minimum cooldown between two trains
constructor(
private unit: Unit,
private spawnTrains?: boolean, // If set, the station will spawn trains
) {
this.unit.setTrainStation(true);
}
isActive(): boolean {
return this.active;
}
init(mg: Game, ticks: number): void {
this.mg = mg;
if (this.spawnTrains) {
this.random = new PseudoRandom(mg.ticks());
}
}
tick(ticks: number): void {
if (this.mg === undefined) {
throw new Error("Not initialized");
}
if (!this.isActive() || this.unit === undefined) {
return;
}
if (this.station === null) {
// Can't create new executions on init, so it has to be done in the tick
this.station = new TrainStation(this.mg, this.unit);
this.mg.railNetwork().connectStation(this.station);
}
if (!this.station.isActive()) {
this.active = false;
return;
}
this.spawnTrain(this.station, ticks);
}
private shouldSpawnTrain(): boolean {
const spawnRate = this.mg
.config()
.trainSpawnRate(this.unit.owner().unitCount(UnitType.Factory));
for (let i = 0; i < this.unit!.level(); i++) {
if (this.random.chance(spawnRate)) {
return true;
}
}
return false;
}
private spawnTrain(station: TrainStation, currentTick: number) {
if (this.mg === undefined) throw new Error("Not initialized");
if (!this.spawnTrains) return;
if (this.random === undefined) throw new Error("Not initialized");
if (currentTick < this.lastSpawnTick + this.ticksCooldown) return;
const cluster = station.getCluster();
if (cluster === null) {
return;
}
const availableForTrade = cluster.availableForTrade(this.unit.owner());
if (availableForTrade.size === 0) {
return;
}
if (!this.shouldSpawnTrain()) {
return;
}
// Pick a destination randomly.
// Could be improved to pick a lucrative trip
const destination: TrainStation =
this.random.randFromSet(availableForTrade);
if (destination !== station) {
this.mg.addExecution(
new TrainExecution(
this.mg.railNetwork(),
this.unit.owner(),
station,
destination,
this.numCars,
),
);
this.lastSpawnTick = currentTick;
}
}
activeDuringSpawnPhase(): boolean {
return false;
}
}