Files
Battle-for-Tismo/tests/improvements_test.js
T

157 lines
6.2 KiB
JavaScript

import { TestCase } from "./framework/test_case.js";
import { smallState, cityOf } from "./framework/helpers.js";
import { key } from "../shared/hex.js";
import { TRANSPORT_BY_ID } from "../shared/data/improvements.js";
const BIG_BUDGET = 10_000_000_000;
// A land tile owned by civ 0 that carries no transport improvement yet.
function bareOwnedLand(state, civ = 0) {
return state.landCells.find((coords) => {
const k = key(coords.x, coords.y);
return state.civAt(coords) === civ && !state.roads.has(k) && !state.railways.has(k);
});
}
export class ImprovementsTest extends TestCase {
test_building_a_road_costs_money_and_lays_the_tile() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const coords = bareOwnedLand(state);
this.assertNotNull(coords, "the map has a bare owned land tile");
const k = key(coords.x, coords.y);
const before = state.getBudget(0);
this.assertTrue(state.requestBuildImprovement(0, coords, "road"));
this.assertTrue(state.roads.has(k), "the road is on the tile");
this.assertFalse(state.railways.has(k), "it is not a railway");
this.assertApprox(before - state.getBudget(0), TRANSPORT_BY_ID.road.buildCost);
}
test_a_railway_replaces_a_road_and_moves_twice_as_fast() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const coords = bareOwnedLand(state);
this.assertNotNull(coords);
const k = key(coords.x, coords.y);
const unit = state._spawnUnit(coords, 0, state.protoUnits[0]);
state.roads.add(k);
const roadHours = state._tileTravelHours(unit, coords);
this.assertTrue(state.requestBuildImprovement(0, coords, "railway"));
this.assertTrue(state.railways.has(k), "the railway is on the tile");
this.assertFalse(state.roads.has(k), "the road was replaced");
const railHours = state._tileTravelHours(unit, coords);
this.assertApprox(railHours * 2, roadHours, 1e-9, "a railway is 50% faster than a road");
}
test_a_railway_moves_four_times_as_fast_as_open_grass() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const coords = state.landCells.find(
(c) => state.tiles[key(c.x, c.y)].terrainType === "Land" && state.civAt(c) === 0
);
this.assertNotNull(coords, "the map has owned grass");
const unit = state._spawnUnit(coords, 0, state.protoUnits[0]);
state.roads.delete(key(coords.x, coords.y));
state.railways.delete(key(coords.x, coords.y));
const open = state._tileTravelHours(unit, coords);
this.assertTrue(state.requestBuildImprovement(0, coords, "railway"));
const rail = state._tileTravelHours(unit, coords);
this.assertApprox(rail * 4, open, 1e-9, "a railway is four times grass speed");
}
test_only_a_controlled_land_tile_may_be_improved() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const sea = Object.keys(state.tiles)
.map((k) => state.tiles[k])
.find((tile) => tile.terrainClass === "Sea");
this.assertNotNull(sea, "the map has a sea tile");
// The exact coords of the sea tile.
const seaEntry = Object.entries(state.tiles).find(([, tile]) => tile === sea);
const [sx, sy] = seaEntry[0].split(",").map(Number);
this.assertFalse(state.requestBuildImprovement(0, { x: sx, y: sy }, "road"), "no road at sea");
// A tile owned by another civilisation is off limits.
const foreign = state.landCells.find((c) => state.civAt(c) === 1);
if (foreign) {
this.assertFalse(
state.requestBuildImprovement(0, foreign, "road"),
"cannot build on a foreign tile"
);
}
// An unknown improvement id is refused.
const owned = bareOwnedLand(state);
this.assertFalse(state.requestBuildImprovement(0, owned, "monorail"));
}
test_the_same_improvement_cannot_be_built_twice() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const coords = bareOwnedLand(state);
this.assertTrue(state.requestBuildImprovement(0, coords, "road"));
const after = state.getBudget(0);
this.assertFalse(state.requestBuildImprovement(0, coords, "road"), "already a road");
this.assertApprox(state.getBudget(0), after, 1e-9, "nothing was charged");
}
test_poor_nations_cannot_build() {
const state = smallState();
state.budgets.set(0, 0);
const coords = bareOwnedLand(state);
this.assertFalse(state.requestBuildImprovement(0, coords, "road"));
this.assertFalse(state.roads.has(key(coords.x, coords.y)));
}
test_maintenance_counts_roads_and_railways_the_nation_holds() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const coords = bareOwnedLand(state);
const k = key(coords.x, coords.y);
const before = state.getTransportUpkeep(0);
this.assertTrue(state.requestBuildImprovement(0, coords, "road"));
this.assertApprox(
state.getTransportUpkeep(0) - before,
TRANSPORT_BY_ID.road.maintenance,
1e-9,
"a road adds its hourly maintenance"
);
this.assertTrue(state.requestBuildImprovement(0, coords, "railway"));
this.assertApprox(
state.getTransportUpkeep(0) - before,
TRANSPORT_BY_ID.railway.maintenance,
1e-9,
"the railway replaces the road's maintenance"
);
}
test_the_snapshot_ships_railways() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const coords = bareOwnedLand(state);
this.assertTrue(state.requestBuildImprovement(0, coords, "railway"));
const snapshot = state.snapshot(0);
this.assertTrue(
snapshot.railways.some(([x, y]) => x === coords.x && y === coords.y),
"the built railway is in the snapshot"
);
this.assertEqual(
snapshot.versions.improvements,
state._improvementVersion,
"the improvement version is shipped"
);
}
test_a_city_starts_with_a_road_the_player_could_upgrade() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const city = cityOf(state, 0);
const coords = { x: city.coords.x, y: city.coords.y };
const k = key(coords.x, coords.y);
this.assertTrue(state.roads.has(k), "a city carries a road");
this.assertTrue(state.requestBuildImprovement(0, coords, "railway"));
this.assertTrue(state.railways.has(k), "the city road becomes a railway");
this.assertFalse(state.roads.has(k));
}
}