Files
OpenFrontIO/src/core/execution/RailroadExecution.ts
T
Scott Anderson b56e380107 Enable the sort-keys eslint rule (#1746)
## Description:

Enable the `sort-keys` eslint rule.

Fixes #1629

## Please complete the following:

- [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
- [ ] I have read and accepted the CLA agreement (only required once).
2025-08-07 19:13:42 -04:00

173 lines
5.0 KiB
TypeScript

import { Execution, Game } from "../game/Game";
import { TileRef } from "../game/GameMap";
import { GameUpdateType, RailTile, RailType } from "../game/GameUpdates";
import { Railroad } from "../game/Railroad";
export class RailroadExecution implements Execution {
private mg: Game;
private active: boolean = true;
private headIndex: number = 0;
private tailIndex: number = 0;
private increment: number = 3;
private railTiles: RailTile[] = [];
constructor(private railRoad: Railroad) {
this.tailIndex = railRoad.tiles.length;
}
isActive(): boolean {
return this.active;
}
/* eslint-disable sort-keys */
init(mg: Game, ticks: number): void {
this.mg = mg;
const tiles = this.railRoad.tiles;
// Inverse direction computation for the first tile
this.railTiles.push({
tile: tiles[0],
railType:
tiles.length > 0
? this.computeExtremityDirection(tiles[0], tiles[1])
: RailType.VERTICAL,
});
for (let i = 1; i < tiles.length - 1; i++) {
const direction = this.computeDirection(
tiles[i - 1],
tiles[i],
tiles[i + 1],
);
this.railTiles.push({ tile: tiles[i], railType: direction });
}
this.railTiles.push({
tile: tiles[tiles.length - 1],
railType:
tiles.length > 0
? this.computeExtremityDirection(
tiles[tiles.length - 1],
tiles[tiles.length - 2],
)
: RailType.VERTICAL,
});
}
/* eslint-enable sort-keys */
private computeExtremityDirection(tile: TileRef, next: TileRef): RailType {
const x = this.mg.x(tile);
const y = this.mg.y(tile);
const nextX = this.mg.x(next);
const nextY = this.mg.y(next);
const dx = nextX - x;
const dy = nextY - y;
if (dx === 0 && dy === 0) return RailType.VERTICAL; // No movement
if (dx === 0) {
return RailType.VERTICAL;
} else if (dy === 0) {
return RailType.HORIZONTAL;
}
return RailType.VERTICAL;
}
private computeDirection(
prev: TileRef,
current: TileRef,
next: TileRef,
): RailType {
if (this.mg === null) {
throw new Error("Not initialized");
}
const x1 = this.mg.x(prev);
const y1 = this.mg.y(prev);
const x2 = this.mg.x(current);
const y2 = this.mg.y(current);
const x3 = this.mg.x(next);
const y3 = this.mg.y(next);
const dx1 = x2 - x1;
const dy1 = y2 - y1;
const dx2 = x3 - x2;
const dy2 = y3 - y2;
// Straight line
if (dx1 === dx2 && dy1 === dy2) {
if (dx1 !== 0) return RailType.HORIZONTAL;
if (dy1 !== 0) return RailType.VERTICAL;
}
// Turn (corner) cases
if ((dx1 === 0 && dx2 !== 0) || (dx1 !== 0 && dx2 === 0)) {
// Now figure out which type of corner
if (dx1 === 0 && dx2 === 1 && dy1 === -1) return RailType.BOTTOM_RIGHT;
if (dx1 === 0 && dx2 === -1 && dy1 === -1) return RailType.BOTTOM_LEFT;
if (dx1 === 0 && dx2 === 1 && dy1 === 1) return RailType.TOP_RIGHT;
if (dx1 === 0 && dx2 === -1 && dy1 === 1) return RailType.TOP_LEFT;
if (dx1 === 1 && dx2 === 0 && dy2 === -1) return RailType.TOP_LEFT;
if (dx1 === -1 && dx2 === 0 && dy2 === -1) return RailType.TOP_RIGHT;
if (dx1 === 1 && dx2 === 0 && dy2 === 1) return RailType.BOTTOM_LEFT;
if (dx1 === -1 && dx2 === 0 && dy2 === 1) return RailType.BOTTOM_RIGHT;
}
console.warn(`Invalid rail segment: ${dx1}:${dy1}, ${dx2}:${dy2}`);
return RailType.VERTICAL;
}
tick(ticks: number): void {
if (this.mg === null) {
throw new Error("Not initialized");
}
if (!this.activeSourceOrDestination()) {
this.active = false;
return;
}
if (this.headIndex > this.tailIndex) {
// Construction complete
this.constructionComplete();
return;
}
let updatedRailTiles: RailTile[];
// Check if remaining tiles can be done all at once
if (this.tailIndex - this.headIndex <= 2 * this.increment) {
updatedRailTiles = this.railTiles.slice(this.headIndex, this.tailIndex);
this.constructionComplete();
} else {
updatedRailTiles = this.railTiles.slice(
this.headIndex,
this.headIndex + this.increment,
);
updatedRailTiles = updatedRailTiles.concat(
this.railTiles.slice(this.tailIndex - this.increment, this.tailIndex),
);
this.headIndex += this.increment;
this.tailIndex -= this.increment;
}
if (updatedRailTiles) {
this.mg.addUpdate({
isActive: true,
railTiles: updatedRailTiles,
type: GameUpdateType.RailroadEvent,
});
}
}
activeDuringSpawnPhase(): boolean {
return false;
}
private activeSourceOrDestination(): boolean {
return this.railRoad.from.isActive() && this.railRoad.to.isActive();
}
private constructionComplete() {
this.redrawBuildings();
this.active = false;
}
private redrawBuildings() {
this.railRoad.from.unit.isActive() && this.railRoad.from.unit.touch();
this.railRoad.to.unit.isActive() && this.railRoad.to.unit.touch();
}
}