Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/core/game/GameImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -747,12 +747,12 @@ export class GameImpl implements Game {
}

conquer(owner: PlayerImpl, tile: TileRef): void {
if (!this.isLand(tile)) {
throw Error(`cannot conquer water`);
}
if (this.isImpassable(tile)) {
throw Error(`cannot conquer impassable terrain`);
}
if (!this.isLand(tile)) {
throw Error(`cannot conquer water`);
}
const previousOwner = this.owner(tile) as TerraNullius | PlayerImpl;
if (previousOwner.isPlayer()) {
previousOwner._lastTileChange = this._ticks;
Expand Down
29 changes: 22 additions & 7 deletions src/core/game/GameMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,18 @@ export class GameMapImpl implements GameMap {

// Terrain getters (immutable)
isLand(ref: TileRef): boolean {
return Boolean(this.terrain[ref] & (1 << GameMapImpl.IS_LAND_BIT));
return (
Boolean(this.terrain[ref] & (1 << GameMapImpl.IS_LAND_BIT)) &&
!(
(this.terrain[ref] & GameMapImpl.MAGNITUDE_MASK) ===
GameMapImpl.IMPASSABLE_MAGNITUDE
)
);
}
Comment thread
TKTK123456 marked this conversation as resolved.

isImpassable(ref: TileRef): boolean {
return (
this.isLand(ref) &&
Boolean(this.terrain[ref] & (1 << GameMapImpl.IS_LAND_BIT)) &&
(this.terrain[ref] & GameMapImpl.MAGNITUDE_MASK) ===
GameMapImpl.IMPASSABLE_MAGNITUDE
);
Expand All @@ -236,7 +242,10 @@ export class GameMapImpl implements GameMap {
}

isShoreline(ref: TileRef): boolean {
return Boolean(this.terrain[ref] & (1 << GameMapImpl.SHORELINE_BIT));
return (
Boolean(this.terrain[ref] & (1 << GameMapImpl.SHORELINE_BIT)) &&
!this.isImpassable(ref)
);
}

magnitude(ref: TileRef): number {
Expand Down Expand Up @@ -313,7 +322,14 @@ export class GameMapImpl implements GameMap {
const x = this.x(ref);
const y = this.y(ref);
return (
x === 0 || x === this.width() - 1 || y === 0 || y === this.height() - 1
x === 0 ||
x === this.width() - 1 ||
y === 0 ||
y === this.height() - 1 ||
this.isImpassable(this.ref(x + 1, y)) ||
this.isImpassable(this.ref(x - 1, y)) ||
this.isImpassable(this.ref(x, y + 1)) ||
this.isImpassable(this.ref(x, y - 1))
);
}

Expand Down Expand Up @@ -344,7 +360,7 @@ export class GameMapImpl implements GameMap {

// Helper methods
isWater(ref: TileRef): boolean {
return !this.isLand(ref);
return !this.isLand(ref) && !this.isImpassable(ref);
}

isShore(ref: TileRef): boolean {
Expand All @@ -360,12 +376,11 @@ export class GameMapImpl implements GameMap {
terrainType(ref: TileRef): TerrainType {
if (this.isLand(ref)) {
const magnitude = this.magnitude(ref);
if (magnitude >= GameMapImpl.IMPASSABLE_MAGNITUDE)
return TerrainType.Impassable;
if (magnitude < 10) return TerrainType.Plains;
if (magnitude < 20) return TerrainType.Highland;
return TerrainType.Mountain;
}
if (this.isImpassable(ref)) return TerrainType.Impassable;
return TerrainType.Ocean;
}

Expand Down
20 changes: 5 additions & 15 deletions src/core/pathfinding/algorithms/AStar.Rail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,38 +52,28 @@ class RailAdapter implements AStarAdapter {
let count = 0;
const x = node % this.width;
const fromShoreline = this.gameMap.isShoreline(node);
const isImpassable = this.gameMap.isImpassable(node);

if (node >= this.width) {
const n = node - this.width;
if (this.isTraversable(n, fromShoreline, isImpassable))
buffer[count++] = n;
if (this.isTraversable(n, fromShoreline)) buffer[count++] = n;
}
if (node < this._numNodes - this.width) {
const n = node + this.width;
if (this.isTraversable(n, fromShoreline, isImpassable))
buffer[count++] = n;
if (this.isTraversable(n, fromShoreline)) buffer[count++] = n;
}
if (x !== 0) {
const n = node - 1;
if (this.isTraversable(n, fromShoreline, isImpassable))
buffer[count++] = n;
if (this.isTraversable(n, fromShoreline)) buffer[count++] = n;
}
if (x !== this.width - 1) {
const n = node + 1;
if (this.isTraversable(n, fromShoreline, isImpassable))
buffer[count++] = n;
if (this.isTraversable(n, fromShoreline)) buffer[count++] = n;
}

return count;
}

private isTraversable(
to: number,
fromShoreline: boolean,
isImpassable: boolean,
): boolean {
if (isImpassable) return false;
private isTraversable(to: number, fromShoreline: boolean): boolean {
const toWater = this.gameMap.isWater(to);
if (!toWater) return true;
return fromShoreline || this.gameMap.isShoreline(to);
Expand Down
11 changes: 6 additions & 5 deletions tests/ImpassableTerrain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ describe("Impassable Terrain", () => {
expect(game.terrainType(game.ref(WALL_X, 50))).toBe(TerrainType.Impassable);
});

test("isLand returns true for impassable (solid for pathfinding)", () => {
expect(game.isLand(game.ref(WALL_X, 50))).toBe(true);
test("isLand returns false for impassable (can't pathfind trains through it)", () => {
expect(game.isLand(game.ref(WALL_X, 50))).toBe(false);
});

test("numLandTiles excludes impassable tiles", () => {
Expand Down Expand Up @@ -227,10 +227,10 @@ describe("Impassable Terrain", () => {
game.addExecution(nuke);
executeTicks(game, 30);

// Impassable tiles should still be land and impassable (not flooded).
// Impassable tiles should still not be land and impassable (not flooded).
for (let y = 95; y <= 105; y++) {
const t = game.ref(WALL_X, y);
expect(game.isLand(t)).toBe(true);
expect(game.isLand(t)).toBe(false);
expect(game.isImpassable(t)).toBe(true);
}
});
Expand Down Expand Up @@ -283,7 +283,8 @@ describe("Impassable Terrain", () => {
const t = game.ref(WALL_X, 50);
expect(game.isImpassable(t)).toBe(true);
game.map().setWater(t);
expect(game.isLand(t)).toBe(true);
expect(game.isLand(t)).toBe(false);
expect(game.isWater(t)).toBe(false);
expect(game.isImpassable(t)).toBe(true);
});

Expand Down
Loading