mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-08-09 13:36:33 +00:00
feat: add warship tests (#291)
This commit is contained in:
@@ -25,6 +25,7 @@ class Terrain {
|
|||||||
|
|
||||||
export async function generateMap(
|
export async function generateMap(
|
||||||
imageBuffer: Buffer,
|
imageBuffer: Buffer,
|
||||||
|
removeSmall = true,
|
||||||
): Promise<{ map: Uint8Array; miniMap: Uint8Array }> {
|
): Promise<{ map: Uint8Array; miniMap: Uint8Array }> {
|
||||||
const stream = Readable.from(imageBuffer);
|
const stream = Readable.from(imageBuffer);
|
||||||
const img = await decodePNGFromStream(stream);
|
const img = await decodePNGFromStream(stream);
|
||||||
@@ -56,8 +57,10 @@ export async function generateMap(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeSmallIslands(terrain);
|
if (removeSmall) {
|
||||||
removeSmallLakes(terrain);
|
removeSmallIslands(terrain);
|
||||||
|
removeSmallLakes(terrain);
|
||||||
|
}
|
||||||
const shorelineWaters = processShore(terrain);
|
const shorelineWaters = processShore(terrain);
|
||||||
processDistToLand(shorelineWaters, terrain);
|
processDistToLand(shorelineWaters, terrain);
|
||||||
processOcean(terrain);
|
processOcean(terrain);
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
import {
|
||||||
|
Game,
|
||||||
|
Player,
|
||||||
|
PlayerInfo,
|
||||||
|
PlayerType,
|
||||||
|
UnitType,
|
||||||
|
} from "../src/core/game/Game";
|
||||||
|
import { SpawnExecution } from "../src/core/execution/SpawnExecution";
|
||||||
|
import { setup } from "./util/Setup";
|
||||||
|
import { constructionExecution } from "./util/utils";
|
||||||
|
|
||||||
|
let game: Game;
|
||||||
|
let player1: Player;
|
||||||
|
let player2: Player;
|
||||||
|
|
||||||
|
describe("Warship", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
game = await setup("half_land_half_ocean", {
|
||||||
|
infiniteGold: true,
|
||||||
|
instantBuild: true,
|
||||||
|
});
|
||||||
|
const player_1_info = new PlayerInfo(
|
||||||
|
"us",
|
||||||
|
"boat dude",
|
||||||
|
PlayerType.Human,
|
||||||
|
null,
|
||||||
|
"player_1_id",
|
||||||
|
);
|
||||||
|
game.addPlayer(player_1_info, 1000);
|
||||||
|
const player_2_info = new PlayerInfo(
|
||||||
|
"us",
|
||||||
|
"boat dude",
|
||||||
|
PlayerType.Human,
|
||||||
|
null,
|
||||||
|
"player_2_id",
|
||||||
|
);
|
||||||
|
game.addPlayer(player_2_info, 1000);
|
||||||
|
|
||||||
|
const spawnTile = game.map().ref(0, 0);
|
||||||
|
game.addExecution(
|
||||||
|
new SpawnExecution(game.player(player_1_info.id).info(), spawnTile),
|
||||||
|
new SpawnExecution(game.player(player_2_info.id).info(), spawnTile),
|
||||||
|
);
|
||||||
|
|
||||||
|
while (game.inSpawnPhase()) {
|
||||||
|
game.executeNextTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
player1 = game.player(player_1_info.id);
|
||||||
|
player2 = game.player(player_2_info.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Warship heals only if player has port", async () => {
|
||||||
|
const maxHealth = game.config().unitInfo(UnitType.Warship).maxHealth;
|
||||||
|
|
||||||
|
const port = player1.buildUnit(UnitType.Port, 0, game.ref(0, 0));
|
||||||
|
const warship = player1.buildUnit(UnitType.Warship, 0, game.ref(7, 7));
|
||||||
|
|
||||||
|
game.executeNextTick();
|
||||||
|
|
||||||
|
expect(warship.health()).toBe(maxHealth);
|
||||||
|
warship.modifyHealth(-10);
|
||||||
|
expect(warship.health()).toBe(maxHealth - 10);
|
||||||
|
game.executeNextTick();
|
||||||
|
expect(warship.health()).toBe(maxHealth - 9);
|
||||||
|
|
||||||
|
port.delete();
|
||||||
|
|
||||||
|
game.executeNextTick();
|
||||||
|
expect(warship.health()).toBe(maxHealth - 9);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Warship captures trade if player has port", async () => {
|
||||||
|
constructionExecution(game, player1.id(), 0, 0, UnitType.Port);
|
||||||
|
constructionExecution(game, player1.id(), 7, 7, UnitType.Warship);
|
||||||
|
// Warship need one more tick (for warship exec to actually build warship)
|
||||||
|
game.executeNextTick();
|
||||||
|
expect(player1.units(UnitType.Warship)).toHaveLength(1);
|
||||||
|
|
||||||
|
// Cannot buildExec with trade ship as it's not buildable (but
|
||||||
|
// we can obviously directly add it to the player)
|
||||||
|
const tradeShip = player2.buildUnit(UnitType.TradeShip, 0, game.ref(6, 6));
|
||||||
|
|
||||||
|
expect(tradeShip.owner().id()).toBe(player2.id());
|
||||||
|
// Let plenty of time for A* to execute
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
game.executeNextTick();
|
||||||
|
}
|
||||||
|
expect(tradeShip.owner().id()).toBe(player1.id());
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Warship do not capture trade if player has no port", async () => {
|
||||||
|
constructionExecution(game, player1.id(), 0, 0, UnitType.Port);
|
||||||
|
constructionExecution(game, player1.id(), 7, 7, UnitType.Warship);
|
||||||
|
expect(player1.units(UnitType.Warship)).toHaveLength(1);
|
||||||
|
|
||||||
|
player1.units(UnitType.Port)[0].delete();
|
||||||
|
// Cannot buildExec with trade ship as it's not buildable (but
|
||||||
|
// we can obviously directly add it to the player)
|
||||||
|
const tradeShip = player2.buildUnit(UnitType.TradeShip, 0, game.ref(6, 6));
|
||||||
|
|
||||||
|
expect(tradeShip.owner().id()).toBe(player2.id());
|
||||||
|
// Let plenty of time for A* to execute
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
game.executeNextTick();
|
||||||
|
}
|
||||||
|
expect(tradeShip.owner().id()).toBe(player2.id());
|
||||||
|
});
|
||||||
|
});
|
||||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 96 B |
+4
-2
@@ -7,12 +7,13 @@ import { TestConfig } from "./TestConfig";
|
|||||||
import { TestServerConfig } from "./TestServerConfig";
|
import { TestServerConfig } from "./TestServerConfig";
|
||||||
import { UserSettings } from "../../src/core/game/UserSettings";
|
import { UserSettings } from "../../src/core/game/UserSettings";
|
||||||
import { Difficulty, GameType } from "../../src/core/game/Game";
|
import { Difficulty, GameType } from "../../src/core/game/Game";
|
||||||
|
import { GameConfig } from "../../src/core/Schemas";
|
||||||
|
|
||||||
export async function setup(mapName: string) {
|
export async function setup(mapName: string, _gameConfig: GameConfig = {}) {
|
||||||
// Load the specified map
|
// Load the specified map
|
||||||
const mapPath = path.join(__dirname, "..", "testdata", `${mapName}.png`);
|
const mapPath = path.join(__dirname, "..", "testdata", `${mapName}.png`);
|
||||||
const imageBuffer = await fs.readFile(mapPath);
|
const imageBuffer = await fs.readFile(mapPath);
|
||||||
const { map, miniMap } = await generateMap(imageBuffer);
|
const { map, miniMap } = await generateMap(imageBuffer, false);
|
||||||
const gameMap = await genTerrainFromBin(String.fromCharCode.apply(null, map));
|
const gameMap = await genTerrainFromBin(String.fromCharCode.apply(null, map));
|
||||||
const miniGameMap = await genTerrainFromBin(
|
const miniGameMap = await genTerrainFromBin(
|
||||||
String.fromCharCode.apply(null, miniMap),
|
String.fromCharCode.apply(null, miniMap),
|
||||||
@@ -30,6 +31,7 @@ export async function setup(mapName: string) {
|
|||||||
infiniteGold: false,
|
infiniteGold: false,
|
||||||
infiniteTroops: false,
|
infiniteTroops: false,
|
||||||
instantBuild: false,
|
instantBuild: false,
|
||||||
|
..._gameConfig,
|
||||||
};
|
};
|
||||||
const config = new TestConfig(serverConfig, gameConfig, new UserSettings());
|
const config = new TestConfig(serverConfig, gameConfig, new UserSettings());
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// Either someone can straight up call player.buildUnit. It's simpler and immediate (no tick required)
|
||||||
|
// Either someone can straight up call player.buildUnit. It's simpler and immediate (no tick required)
|
||||||
|
// However buildUnit do not create executions (e.g.: WarshipExecution)
|
||||||
|
// If you also need execution use function below. Does not work with things not
|
||||||
|
|
||||||
|
import { ConstructionExecution } from "../../src/core/execution/ConstructionExecution";
|
||||||
|
import { Game, PlayerID, UnitType } from "../../src/core/game/Game";
|
||||||
|
|
||||||
|
// built via UI (e.g.: trade ships)
|
||||||
|
export function constructionExecution(
|
||||||
|
game: Game,
|
||||||
|
playerID: PlayerID,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
unit: UnitType,
|
||||||
|
) {
|
||||||
|
game.addExecution(new ConstructionExecution(playerID, game.ref(x, y), unit));
|
||||||
|
// Init
|
||||||
|
game.executeNextTick();
|
||||||
|
// Exec
|
||||||
|
game.executeNextTick();
|
||||||
|
game.executeNextTick();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user