mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:40:44 +00:00
improved terrain api
This commit is contained in:
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,10 +1,9 @@
|
||||
import {getConfig} from "../core/configuration/Config";
|
||||
import {defaultConfig} from "../core/configuration/DefaultConfig";
|
||||
import {devConfig} from "../core/configuration/DevConfig";
|
||||
import {TerrainMap} from "../core/Game";
|
||||
import {PseudoRandom} from "../core/PseudoRandom";
|
||||
import {GameID, Lobby, ServerMessage, ServerMessageSchema} from "../core/Schemas";
|
||||
import {loadTerrainMap} from "../core/TerrainMapLoader";
|
||||
import {loadTerrainMap, TerrainMap} from "../core/TerrainMapLoader";
|
||||
import {ClientGame, createClientGame} from "./ClientGame";
|
||||
import {v4 as uuidv4} from 'uuid';
|
||||
import backgroundImage from '../../resources/images/empty_map.png';
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import {Executor} from "../core/execution/Executor";
|
||||
import {Cell, MutableGame, PlayerEvent, PlayerID, MutablePlayer, TerrainMap, TileEvent, Player, Game, BoatEvent, TerrainTypes} from "../core/Game";
|
||||
import {Cell, MutableGame, PlayerEvent, PlayerID, MutablePlayer, TileEvent, Player, Game, BoatEvent} from "../core/Game";
|
||||
import {createGame} from "../core/GameImpl";
|
||||
import {EventBus} from "../core/EventBus";
|
||||
import {Config} from "../core/configuration/Config";
|
||||
import {GameRenderer} from "./graphics/GameRenderer";
|
||||
import {InputHandler, MouseUpEvent, ZoomEvent, DragEvent, MouseDownEvent} from "./InputHandler"
|
||||
import {ClientID, ClientIntentMessageSchema, ClientJoinMessageSchema, ClientLeaveMessageSchema, ClientMessageSchema, GameID, Intent, ServerMessage, ServerMessageSchema, ServerSyncMessage, Turn} from "../core/Schemas";
|
||||
import {TerrainMap} from "../core/TerrainMapLoader";
|
||||
|
||||
|
||||
|
||||
@@ -187,7 +188,7 @@ export class ClientGame {
|
||||
|
||||
const owner = tile.owner()
|
||||
const targetID = owner.isPlayer() ? owner.id() : null
|
||||
if (tile.owner() != this.myPlayer && tile.terrain() == TerrainTypes.Land) {
|
||||
if (tile.owner() != this.myPlayer && tile.isLand()) {
|
||||
if (this.myPlayer.sharesBorderWith(tile.owner())) {
|
||||
this.sendAttackIntent(targetID, cell, this.config.player().attackAmount(this.myPlayer, owner))
|
||||
} else if (owner.isPlayer()) {
|
||||
|
||||
@@ -163,7 +163,7 @@ export class GameRenderer {
|
||||
}
|
||||
|
||||
paintTile(tile: Tile) {
|
||||
let terrainColor = this.theme.terrainColor(tile.terrain())
|
||||
let terrainColor = this.theme.terrainColor(tile)
|
||||
this.paintCell(tile.cell(), terrainColor)
|
||||
const owner = tile.owner()
|
||||
if (owner.isPlayer()) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Game, Player, Tile, Cell, TerrainTypes} from '../../core/Game';
|
||||
import {Game, Player, Tile, Cell} from '../../core/Game';
|
||||
import {within} from '../../core/Util';
|
||||
|
||||
export interface Point {
|
||||
|
||||
+2
-22
@@ -37,35 +37,15 @@ export class PlayerInfo {
|
||||
) { }
|
||||
}
|
||||
|
||||
// TODO: make terrain api better.
|
||||
export class Terrain {
|
||||
constructor(
|
||||
public readonly expansionCost: number,
|
||||
public readonly expansionTime: number,
|
||||
) { }
|
||||
}
|
||||
|
||||
export type TerrainType = typeof TerrainTypes[keyof typeof TerrainTypes];
|
||||
|
||||
export const TerrainTypes = {
|
||||
Land: new Terrain(1, 1),
|
||||
Water: new Terrain(0, 0)
|
||||
}
|
||||
|
||||
export interface TerrainMap {
|
||||
terrain(cell: Cell): Terrain
|
||||
width(): number
|
||||
height(): number
|
||||
}
|
||||
|
||||
export interface Tile {
|
||||
isLand(): boolean
|
||||
isWater(): boolean
|
||||
owner(): Player | TerraNullius
|
||||
hasOwner(): boolean
|
||||
isBorder(): boolean
|
||||
borders(other: Player | TerraNullius): boolean
|
||||
isInterior(): boolean
|
||||
cell(): Cell
|
||||
terrain(): Terrain
|
||||
game(): Game
|
||||
neighbors(): Tile[]
|
||||
onShore(): boolean
|
||||
|
||||
+11
-5
@@ -1,5 +1,6 @@
|
||||
import {EventBus} from "./EventBus";
|
||||
import {Cell, Execution, MutableGame, Game, MutablePlayer, PlayerEvent, PlayerID, PlayerInfo, Player, TerrainMap, TerrainType, TerrainTypes, TerraNullius, Tile, TileEvent, Boat, MutableBoat, BoatEvent} from "./Game";
|
||||
import {Cell, Execution, MutableGame, Game, MutablePlayer, PlayerEvent, PlayerID, PlayerInfo, Player, TerraNullius, Tile, TileEvent, Boat, MutableBoat, BoatEvent} from "./Game";
|
||||
import {TerrainMap, TerrainType, TerrainTypes} from "./TerrainMapLoader";
|
||||
|
||||
export function createGame(terrainMap: TerrainMap, eventBus: EventBus): Game {
|
||||
return new GameImpl(terrainMap, eventBus)
|
||||
@@ -18,6 +19,12 @@ class TileImpl implements Tile {
|
||||
private readonly _cell: Cell,
|
||||
private readonly _terrain: TerrainType
|
||||
) { }
|
||||
isLand(): boolean {
|
||||
return this._terrain == TerrainTypes.Land
|
||||
}
|
||||
isWater(): boolean {
|
||||
return this._terrain == TerrainTypes.Water
|
||||
}
|
||||
|
||||
borders(other: Player | TerraNullius): boolean {
|
||||
for (const n of this.neighbors()) {
|
||||
@@ -30,7 +37,7 @@ class TileImpl implements Tile {
|
||||
|
||||
onShore(): boolean {
|
||||
return this.neighbors()
|
||||
.filter(t => t.terrain() == TerrainTypes.Water)
|
||||
.filter(t => t.isWater())
|
||||
.length > 0
|
||||
}
|
||||
|
||||
@@ -39,7 +46,6 @@ class TileImpl implements Tile {
|
||||
isBorder(): boolean {return this._isBorder}
|
||||
isInterior(): boolean {return this.hasOwner() && !this.isBorder()}
|
||||
cell(): Cell {return this._cell}
|
||||
terrain(): TerrainType {return this._terrain}
|
||||
|
||||
neighbors(): Tile[] {
|
||||
if (this._neighbors == null) {
|
||||
@@ -131,7 +137,7 @@ export class PlayerImpl implements MutablePlayer {
|
||||
const ns: Set<(MutablePlayer | TerraNullius)> = new Set()
|
||||
for (const border of this.borderTiles()) {
|
||||
for (const neighbor of border.neighbors()) {
|
||||
if (neighbor.terrain() == TerrainTypes.Land && neighbor.owner() != this) {
|
||||
if (neighbor.isLand() && neighbor.owner() != this) {
|
||||
ns.add((neighbor as TileImpl)._owner)
|
||||
}
|
||||
}
|
||||
@@ -353,7 +359,7 @@ export class GameImpl implements MutableGame {
|
||||
if (!owner.isPlayer()) {
|
||||
throw new Error("Must be a player")
|
||||
}
|
||||
if (tile.terrain() == TerrainTypes.Water) {
|
||||
if (tile.isWater()) {
|
||||
throw new Error("Cannot conquer water")
|
||||
}
|
||||
const tileImpl = tile as TileImpl
|
||||
|
||||
@@ -1,12 +1,33 @@
|
||||
import {Jimp as JimpType, JimpConstructors} from '@jimp/core';
|
||||
import 'jimp';
|
||||
import {TerrainMap, TerrainType, TerrainTypes} from './Game';
|
||||
import {TerrainMapImpl} from './GameImpl';
|
||||
import {TerrainTile} from '../../generated/protos';
|
||||
|
||||
import {Cell} from './Game';
|
||||
|
||||
declare const Jimp: JimpType & JimpConstructors;
|
||||
|
||||
|
||||
// TODO: make terrain api better.
|
||||
export class Terrain {
|
||||
constructor(
|
||||
public readonly expansionCost: number,
|
||||
public readonly expansionTime: number,
|
||||
) { }
|
||||
}
|
||||
|
||||
export type TerrainType = typeof TerrainTypes[keyof typeof TerrainTypes];
|
||||
|
||||
export const TerrainTypes = {
|
||||
Land: new Terrain(1, 1),
|
||||
Water: new Terrain(0, 0)
|
||||
}
|
||||
|
||||
export interface TerrainMap {
|
||||
terrain(cell: Cell): Terrain
|
||||
width(): number
|
||||
height(): number
|
||||
}
|
||||
|
||||
export async function loadTerrainMap(): Promise<TerrainMap> {
|
||||
const imageModule = await import(`../../resources/maps/World.png`);
|
||||
const imageUrl = imageModule.default;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Player, PlayerID, PlayerInfo, TerrainType, TerrainTypes, TerraNullius, Tile} from "../Game";
|
||||
import {Player, PlayerID, PlayerInfo, TerraNullius, Tile} from "../Game";
|
||||
import {Colord, colord} from "colord";
|
||||
import {devConfig} from "./DevConfig";
|
||||
import {defaultConfig} from "./DefaultConfig";
|
||||
@@ -41,7 +41,7 @@ export interface Theme {
|
||||
playerInfoColor(id: PlayerID): Colord;
|
||||
territoryColor(id: PlayerID): Colord;
|
||||
borderColor(id: PlayerID): Colord;
|
||||
terrainColor(tile: TerrainType): Colord;
|
||||
terrainColor(tile: Tile): Colord;
|
||||
backgroundColor(): Colord;
|
||||
font(): string;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Colord, colord} from "colord";
|
||||
import {PlayerID, TerrainType, TerrainTypes} from "../Game";
|
||||
import {PlayerID, Tile} from "../Game";
|
||||
import {Theme} from "./Config";
|
||||
|
||||
export const pastelTheme = new class implements Theme {
|
||||
@@ -75,11 +75,12 @@ export const pastelTheme = new class implements Theme {
|
||||
})
|
||||
}
|
||||
|
||||
terrainColor(tile: TerrainType): Colord {
|
||||
if (tile == TerrainTypes.Land) {
|
||||
terrainColor(tile: Tile): Colord {
|
||||
if (tile.isLand()) {
|
||||
return this.land;
|
||||
} else {
|
||||
return this.water;
|
||||
}
|
||||
return this.water;
|
||||
}
|
||||
|
||||
backgroundColor(): Colord {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import PriorityQueue from "priority-queue-typescript";
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, PlayerID, Player, TerrainTypes, TerraNullius, Tile} from "../Game";
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, PlayerID, TerraNullius, Tile} from "../Game";
|
||||
import {PseudoRandom} from "../PseudoRandom";
|
||||
import {manhattanDist} from "../Util";
|
||||
import {Config, PlayerConfig} from "../configuration/Config";
|
||||
@@ -145,13 +145,13 @@ export class AttackExecution implements Execution {
|
||||
}
|
||||
for (const tile of existingBorder) {
|
||||
for (const neighbor of tile.neighbors()) {
|
||||
if (neighbor.terrain() == TerrainTypes.Water || neighbor.owner() != this.target) {
|
||||
if (neighbor.isWater() || neighbor.owner() != this.target) {
|
||||
continue
|
||||
}
|
||||
newBorder.add(neighbor)
|
||||
this.numTilesWithEnemy += 1
|
||||
let numOwnedByMe = neighbor.neighbors()
|
||||
.filter(t => t.terrain() == TerrainTypes.Land)
|
||||
.filter(t => t.isLand())
|
||||
.filter(t => t.owner() == this._owner)
|
||||
.length
|
||||
let dist = 0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import PriorityQueue from "priority-queue-typescript";
|
||||
import {Boat, Cell, Execution, MutableBoat, MutableGame, MutablePlayer, Player, PlayerID, TerrainTypes, Tile} from "../Game";
|
||||
import {Boat, Cell, Execution, MutableBoat, MutableGame, MutablePlayer, Player, PlayerID, Tile} from "../Game";
|
||||
import {manhattanDist} from "../Util";
|
||||
import {AttackExecution} from "./AttackExecution";
|
||||
import {Config, PlayerConfig} from "../configuration/Config";
|
||||
@@ -165,7 +165,7 @@ export class AStar {
|
||||
}
|
||||
|
||||
for (const neighbor of this.current.neighbors()) {
|
||||
if (neighbor != this.dst && neighbor.terrain() != TerrainTypes.Water) continue; // Skip non-water tiles
|
||||
if (neighbor != this.dst && neighbor.isLand()) continue; // Skip non-water tiles
|
||||
|
||||
const tentativeGScore = this.gScore.get(this.current)! + 1; // Assuming uniform cost
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Config, PlayerConfig} from "../configuration/Config";
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, TerrainTypes, TerraNullius} from "../Game"
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, TerraNullius} from "../Game"
|
||||
import {PseudoRandom} from "../PseudoRandom"
|
||||
import {AttackExecution} from "./AttackExecution";
|
||||
|
||||
@@ -38,7 +38,7 @@ export class BotExecution implements Execution {
|
||||
if (this.neighborsTerra) {
|
||||
for (const b of this.bot.borderTiles()) {
|
||||
for (const n of b.neighbors()) {
|
||||
if (n.owner() == this.gs.terraNullius() && n.terrain() == TerrainTypes.Land) {
|
||||
if (n.owner() == this.gs.terraNullius() && n.isLand()) {
|
||||
this.sendAttack(this.gs.terraNullius())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Cell, Game, TerrainTypes} from "../Game";
|
||||
import {Cell, Game} from "../Game";
|
||||
import {PseudoRandom} from "../PseudoRandom";
|
||||
import {SpawnIntent} from "../Schemas";
|
||||
import {getSpawnCells} from "./Util";
|
||||
@@ -19,7 +19,7 @@ export class BotSpawner {
|
||||
this.numFreeTiles = 0;
|
||||
|
||||
this.gs.forEachTile(tile => {
|
||||
if (tile.terrain() == TerrainTypes.Water) {
|
||||
if (tile.isWater()) {
|
||||
return;
|
||||
}
|
||||
if (tile.hasOwner()) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Game, Cell, TerrainTypes} from "../Game";
|
||||
import {Game, Cell} from "../Game";
|
||||
|
||||
|
||||
export function getSpawnCells(gs: Game, cell: Cell): Cell[] {
|
||||
@@ -12,7 +12,7 @@ export function getSpawnCells(gs: Game, cell: Cell): Cell[] {
|
||||
if (Math.abs(dx) === 2 && Math.abs(dy) === 2) {
|
||||
continue;
|
||||
}
|
||||
if (gs.tile(c).terrain() != TerrainTypes.Land) {
|
||||
if (gs.tile(c).isWater()) {
|
||||
continue;
|
||||
}
|
||||
if (gs.tile(c).hasOwner()) {
|
||||
|
||||
Reference in New Issue
Block a user