mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 11:50:42 +00:00
put methods onto terraintile
This commit is contained in:
@@ -211,7 +211,7 @@ export class ClientGameRunner {
|
||||
}
|
||||
consolex.log(`clicked cell ${cell}`)
|
||||
const tile = this.gs.tile(cell)
|
||||
if (tile.isLand() && !tile.hasOwner() && this.gs.inSpawnPhase()) {
|
||||
if (tile.terrain().isLand() && !tile.hasOwner() && this.gs.inSpawnPhase()) {
|
||||
this.eventBus.emit(new SendSpawnIntentEvent(cell))
|
||||
return
|
||||
}
|
||||
@@ -233,13 +233,13 @@ export class ClientGameRunner {
|
||||
return
|
||||
}
|
||||
|
||||
if (tile.isLand()) {
|
||||
if (tile.terrain().isLand()) {
|
||||
if (tile.hasOwner()) {
|
||||
if (this.myPlayer.sharesBorderWith(tile.owner())) {
|
||||
this.eventBus.emit(new SendAttackIntentEvent(targetID, this.myPlayer.troops() * this.renderer.uiState.attackRatio))
|
||||
}
|
||||
} else {
|
||||
outer_loop: for (const t of bfs(tile, and(t => !t.hasOwner() && t.isLand(), dist(tile, 200)))) {
|
||||
outer_loop: for (const t of bfs(tile, and(t => !t.hasOwner() && t.terrain().isLand(), dist(tile, 200)))) {
|
||||
for (const n of t.neighbors()) {
|
||||
if (n.owner() == this.myPlayer) {
|
||||
this.eventBus.emit(new SendAttackIntentEvent(targetID, this.myPlayer.troops() * this.renderer.uiState.attackRatio))
|
||||
|
||||
@@ -61,7 +61,7 @@ export function createGrid(game: Game, player: Player, boundingBox: { min: Point
|
||||
const cell = new Cell(x * scalingFactor, y * scalingFactor);
|
||||
if (game.isOnMap(cell)) {
|
||||
const tile = game.tile(cell);
|
||||
grid[x - scaledBoundingBox.min.x][y - scaledBoundingBox.min.y] = tile.isLake() || tile.owner() === player; // TODO: okay if lake
|
||||
grid[x - scaledBoundingBox.min.x][y - scaledBoundingBox.min.y] = tile.terrain().isLake() || tile.owner() === player; // TODO: okay if lake
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
if (owner.isPlayer()) {
|
||||
this.player = owner;
|
||||
this.setVisible(true);
|
||||
} else if (!tile.isLand()) {
|
||||
} else if (!tile.terrain().isLand()) {
|
||||
const units = this.game.units(UnitType.Destroyer, UnitType.Battleship, UnitType.TradeShip)
|
||||
.filter(u => euclideanDist(worldCoord, u.tile().cell()) < 50)
|
||||
.sort(distSortUnit(tile));
|
||||
|
||||
@@ -239,7 +239,7 @@ export class RadialMenu implements Layer {
|
||||
const other = tile.owner()
|
||||
|
||||
if (this.game.inSpawnPhase()) {
|
||||
if (tile.isLand() && !tile.hasOwner()) {
|
||||
if (tile.terrain().isLand() && !tile.hasOwner()) {
|
||||
this.enableCenterButton(true)
|
||||
}
|
||||
return
|
||||
@@ -268,13 +268,13 @@ export class RadialMenu implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
if (tile.owner() != myPlayer && tile.isLand() && myPlayer.sharesBorderWith(other)) {
|
||||
if (tile.owner() != myPlayer && tile.terrain().isLand() && myPlayer.sharesBorderWith(other)) {
|
||||
if (other.isPlayer()) {
|
||||
if (!myPlayer.isAlliedWith(other)) {
|
||||
this.enableCenterButton(true)
|
||||
}
|
||||
} else {
|
||||
outer_loop: for (const t of bfs(tile, and(t => !t.hasOwner() && t.isLand(), dist(tile, 200)))) {
|
||||
outer_loop: for (const t of bfs(tile, and(t => !t.hasOwner() && t.terrain().isLand(), dist(tile, 200)))) {
|
||||
for (const n of t.neighbors()) {
|
||||
if (n.owner() == myPlayer) {
|
||||
this.enableCenterButton(true)
|
||||
@@ -321,7 +321,7 @@ export class RadialMenu implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
if (!tile.isLand()) {
|
||||
if (!tile.terrain().isLand()) {
|
||||
return
|
||||
}
|
||||
if (myPlayer.units(UnitType.TransportShip).length >= this.game.config().boatMaxNumber()) {
|
||||
@@ -330,7 +330,7 @@ export class RadialMenu implements Layer {
|
||||
|
||||
let myPlayerBordersOcean = false
|
||||
for (const bt of myPlayer.borderTiles()) {
|
||||
if (bt.isOceanShore()) {
|
||||
if (bt.terrain().isOceanShore()) {
|
||||
myPlayerBordersOcean = true
|
||||
break
|
||||
}
|
||||
@@ -340,7 +340,7 @@ export class RadialMenu implements Layer {
|
||||
otherPlayerBordersOcean = true
|
||||
} else {
|
||||
for (const bt of (other as Player).borderTiles()) {
|
||||
if (bt.isOceanShore()) {
|
||||
if (bt.terrain().isOceanShore()) {
|
||||
otherPlayerBordersOcean = true
|
||||
break
|
||||
}
|
||||
@@ -352,8 +352,8 @@ export class RadialMenu implements Layer {
|
||||
}
|
||||
|
||||
let nearOcean = false
|
||||
for (const t of bfs(tile, and(t => t.owner() == tile.owner() && t.isLand(), dist(tile, 25)))) {
|
||||
if (t.isOceanShore()) {
|
||||
for (const t of bfs(tile, and(t => t.owner() == tile.owner() && t.terrain().isLand(), dist(tile, 25)))) {
|
||||
if (t.terrain().isOceanShore()) {
|
||||
nearOcean = true
|
||||
break
|
||||
}
|
||||
|
||||
+6
-25
@@ -1,32 +1,12 @@
|
||||
import { getConfig } from "./configuration/Config";
|
||||
import { EventBus } from "./EventBus";
|
||||
import { Executor } from "./execution/ExecutionManager";
|
||||
import { Game } from "./game/Game";
|
||||
import { Game, Tile, TileEvent } from "./game/Game";
|
||||
import { createGame } from "./game/GameImpl";
|
||||
import { loadTerrainMap } from "./game/TerrainMapLoader";
|
||||
import { GameUpdateViewData } from "./GameViewData";
|
||||
import { GameConfig, Turn } from "./Schemas";
|
||||
|
||||
export interface GameUpdate {
|
||||
players: PlayerUpdate[]
|
||||
units: UnitUpdate[]
|
||||
|
||||
}
|
||||
|
||||
export interface PlayerUpdate {
|
||||
|
||||
}
|
||||
|
||||
export interface UnitUpdate {
|
||||
|
||||
}
|
||||
|
||||
export interface TileUpdate {
|
||||
x: number
|
||||
y: number
|
||||
isBorder: boolean
|
||||
|
||||
}
|
||||
|
||||
export async function createGameRunner(gameID: string, gameConfig: GameConfig): Promise<GameRunner> {
|
||||
const config = getConfig(gameConfig)
|
||||
const terrainMap = await loadTerrainMap(gameConfig.gameMap);
|
||||
@@ -36,13 +16,14 @@ export async function createGameRunner(gameID: string, gameConfig: GameConfig):
|
||||
}
|
||||
|
||||
export class GameRunner {
|
||||
private updatedTiles: Tile[]
|
||||
|
||||
constructor(private game: Game, private eventBus: EventBus, private execManager: Executor) {
|
||||
|
||||
eventBus.on(TileEvent, (e) => { this.updatedTiles.push(e.tile) })
|
||||
}
|
||||
|
||||
public executeNextTick(turn: Turn): GameUpdate {
|
||||
|
||||
public executeNextTick(turn: Turn): GameUpdateViewData {
|
||||
this.updatedTiles = []
|
||||
this.game.executeNextTick()
|
||||
return null
|
||||
}
|
||||
|
||||
+304
-11
@@ -1,26 +1,319 @@
|
||||
import { Cell, PlayerID } from "./game/Game";
|
||||
import { GameUpdate } from "./GameRunner";
|
||||
|
||||
export class TileView {
|
||||
import { MessageType } from "../client/graphics/layers/EventsDisplay";
|
||||
import { Config } from "./configuration/Config";
|
||||
import { Alliance, AllianceRequest, AllPlayers, Cell, DefenseBonus, EmojiMessage, Execution, ExecutionView, Game, Gold, Nation, Player, PlayerID, PlayerInfo, PlayerType, Relation, TerrainMap, TerrainTile, TerrainType, TerraNullius, Tick, Tile, Unit, UnitInfo, UnitType } from "./game/Game";
|
||||
import { GameUpdateViewData, PlayerViewData, TileViewData, UnitViewData } from "./GameViewData";
|
||||
import { ClientID } from "./Schemas";
|
||||
|
||||
export class TileView implements Tile {
|
||||
constructor(private data: TileViewData, terrain: TerrainTile) { }
|
||||
isLand(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isShore(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isOceanShore(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isWater(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isShorelineWater(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isOcean(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isLake(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
terrain(): TerrainTile {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
magnitude(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
owner(): Player | TerraNullius {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
hasOwner(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isBorder(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
borders(other: Player | TerraNullius): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isInterior(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
cell(): Cell {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
neighbors(): Tile[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
neighborsWrapped(): Tile[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
onShore(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
defenseBonuses(): DefenseBonus[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
defenseBonus(player: Player): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
hasFallout(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
cost(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
type(): TerrainType {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
export class PlayerView {
|
||||
export class UnitView implements Unit {
|
||||
constructor(private data: UnitViewData) { }
|
||||
|
||||
type(): UnitType {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
troops(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
tile(): Tile {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
owner(): Player {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isActive(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
info(): UnitInfo {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
hasHealth(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
health(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
export class GameView {
|
||||
export class PlayerView implements Player {
|
||||
constructor(private data: PlayerViewData) { }
|
||||
info(): PlayerInfo {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
name(): string {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
displayName(): string {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
clientID(): ClientID {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
id(): PlayerID {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
type(): PlayerType {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
units(...types: UnitType[]): Unit[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
ownsTile(cell: Cell): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isAlive(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
borderTiles(): ReadonlySet<Tile> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isPlayer(): this is Player {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
neighbors(): (Player | TerraNullius)[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
numTilesOwned(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
tiles(): ReadonlySet<Tile> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
sharesBorderWith(other: Player | TerraNullius): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
incomingAllianceRequests(): AllianceRequest[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
outgoingAllianceRequests(): AllianceRequest[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
alliances(): Alliance[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
allies(): Player[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isAlliedWith(other: Player): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
allianceWith(other: Player): Alliance | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
recentOrPendingAllianceRequestWith(other: Player): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
relation(other: Player): Relation {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
allRelationsSorted(): { player: Player; relation: Relation; }[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isTraitor(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
canTarget(other: Player): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
targets(): Player[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
transitiveTargets(): Player[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
toString(): string {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
canSendEmoji(recipient: Player | typeof AllPlayers): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
outgoingEmojis(): EmojiMessage[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
canDonate(recipient: Player): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
gold(): Gold {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
population(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
workers(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
targetTroopRatio(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
troops(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
canBuild(type: UnitType, targetTile: Tile): Tile | false {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
lastTileChange(): Tick {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
public update(gu: GameUpdate) {
|
||||
export class GameView implements Game {
|
||||
private lastGameUpdate: GameUpdateViewData
|
||||
private tiles: TileViewData[][] = []
|
||||
|
||||
constructor(private _terrainMap: TerrainMap) { }
|
||||
executions(): ExecutionView[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
executeNextTick(): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
tile(cell: Cell): TileView {
|
||||
return null
|
||||
public update(gu: GameUpdateViewData) {
|
||||
this.lastGameUpdate = gu
|
||||
gu.tileUpdates.forEach(tu => {
|
||||
this.tiles[tu.x][tu.y] = tu
|
||||
})
|
||||
}
|
||||
|
||||
player(id: PlayerID): PlayerView {
|
||||
return null
|
||||
recentlyUpdatedTiles(): TileView[] {
|
||||
return this.lastGameUpdate.tileUpdates.map(tu => new TileView(tu, this._terrainMap.terrain(new Cell(tu.x, tu.y))))
|
||||
}
|
||||
|
||||
player(id: PlayerID): Player {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
playerByClientID(id: ClientID): Player | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
hasPlayer(id: PlayerID): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
players(): Player[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
tile(cell: Cell): Tile {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isOnMap(cell: Cell): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
neighbors(cell: Cell | Tile): Tile[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
width(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
height(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
numLandTiles(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
forEachTile(fn: (tile: Tile) => void): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
terraNullius(): TerraNullius {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
ticks(): Tick {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
inSpawnPhase(): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
addExecution(...exec: Execution[]): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
nations(): Nation[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
config(): Config {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
displayMessage(message: string, type: MessageType, playerID: PlayerID | null): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
units(...types: UnitType[]): Unit[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
unitInfo(type: UnitType): UnitInfo {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
terrainMap(): TerrainMap {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
terrainMiniMap(): TerrainMap {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
export interface ViewSerialiable {
|
||||
toViewData(): ViewData
|
||||
}
|
||||
|
||||
export interface ViewData {
|
||||
|
||||
}
|
||||
|
||||
export interface TileViewData extends ViewData {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
|
||||
export interface UnitViewData extends ViewData {
|
||||
|
||||
}
|
||||
|
||||
export interface PlayerViewData extends ViewData {
|
||||
|
||||
}
|
||||
|
||||
export interface GameUpdateViewData extends ViewData {
|
||||
units: UnitViewData[]
|
||||
players: PlayerViewData[]
|
||||
tileUpdates: TileViewData[]
|
||||
}
|
||||
+2
-2
@@ -86,7 +86,7 @@ export function targetTransportTile(game: Game, tile: Tile): Tile | null {
|
||||
}
|
||||
|
||||
export function closestOceanShoreFromPlayer(player: Player, target: Tile, width: number): Tile | null {
|
||||
const shoreTiles = Array.from(player.borderTiles()).filter(t => t.isOceanShore())
|
||||
const shoreTiles = Array.from(player.borderTiles()).filter(t => t.terrain().isOceanShore())
|
||||
if (shoreTiles.length == 0) {
|
||||
return null
|
||||
}
|
||||
@@ -100,7 +100,7 @@ export function closestOceanShoreFromPlayer(player: Player, target: Tile, width:
|
||||
|
||||
function closestOceanShoreTN(tile: Tile, searchDist: number): Tile {
|
||||
const tn = Array.from(bfs(tile, and(t => !t.hasOwner(), dist(tile, searchDist))))
|
||||
.filter(t => t.isOceanShore())
|
||||
.filter(t => t.terrain().isOceanShore())
|
||||
.sort((a, b) => manhattanDist(tile.cell(), a.cell()) - manhattanDist(tile.cell(), b.cell()))
|
||||
if (tn.length == 0) {
|
||||
return null
|
||||
|
||||
@@ -189,7 +189,7 @@ export class DefaultConfig implements Config {
|
||||
attackLogic(attackTroops: number, attacker: Player, defender: Player | TerraNullius, tileToConquer: Tile): { attackerTroopLoss: number; defenderTroopLoss: number; tilesPerTickUsed: number } {
|
||||
let mag = 0
|
||||
let speed = 0
|
||||
switch (tileToConquer.terrain()) {
|
||||
switch (tileToConquer.terrain().type()) {
|
||||
case TerrainType.Plains:
|
||||
mag = 80
|
||||
speed = 15
|
||||
|
||||
@@ -155,18 +155,18 @@ export const pastelTheme = new class implements Theme {
|
||||
}
|
||||
|
||||
terrainColor(tile: Tile): Colord {
|
||||
let mag = tile.magnitude()
|
||||
if (tile.isShore()) {
|
||||
let mag = tile.terrain().magnitude()
|
||||
if (tile.terrain().isShore()) {
|
||||
return this.shore
|
||||
}
|
||||
switch (tile.terrain()) {
|
||||
switch (tile.terrain().type()) {
|
||||
case TerrainType.Ocean:
|
||||
case TerrainType.Lake:
|
||||
const w = this.water.rgba
|
||||
if (tile.isShorelineWater()) {
|
||||
if (tile.terrain().isShorelineWater()) {
|
||||
return this.shorelineWater
|
||||
}
|
||||
if (tile.magnitude() < 7) {
|
||||
if (tile.terrain().magnitude() < 7) {
|
||||
return colord({
|
||||
r: Math.max(w.r - 7 + mag, 0),
|
||||
g: Math.max(w.g - 7 + mag, 0),
|
||||
|
||||
@@ -173,12 +173,12 @@ export class AttackExecution implements Execution {
|
||||
|
||||
private addNeighbors(tile: Tile) {
|
||||
for (const neighbor of tile.neighbors()) {
|
||||
if (neighbor.isWater() || neighbor.owner() != this.target) {
|
||||
if (neighbor.terrain().isWater() || neighbor.owner() != this.target) {
|
||||
continue
|
||||
}
|
||||
this.border.add(neighbor)
|
||||
let numOwnedByMe = neighbor.neighbors()
|
||||
.filter(t => t.isLand())
|
||||
.filter(t => t.terrain().isLand())
|
||||
.filter(t => t.owner() == this._owner)
|
||||
.length
|
||||
let dist = 0
|
||||
@@ -189,7 +189,7 @@ export class AttackExecution implements Execution {
|
||||
numOwnedByMe = 10
|
||||
}
|
||||
let mag = 0
|
||||
switch (tile.terrain()) {
|
||||
switch (tile.terrain().type()) {
|
||||
case TerrainType.Plains:
|
||||
mag = 1
|
||||
break
|
||||
|
||||
@@ -34,7 +34,7 @@ export class BattleshipExecution implements Execution {
|
||||
|
||||
|
||||
init(mg: MutableGame, ticks: number): void {
|
||||
this.pathfinder = PathFinder.Mini(mg, 5000, t => t.terrainType() == TerrainType.Ocean)
|
||||
this.pathfinder = PathFinder.Mini(mg, 5000, t => t.type() == TerrainType.Ocean)
|
||||
this._owner = mg.player(this.playerID)
|
||||
this.mg = mg
|
||||
this.patrolCenterTile = mg.tile(this.cell)
|
||||
@@ -133,7 +133,7 @@ export class BattleshipExecution implements Execution {
|
||||
continue
|
||||
}
|
||||
const tile = this.mg.tile(cell)
|
||||
if (!tile.isOcean()) {
|
||||
if (!tile.terrain().isOcean()) {
|
||||
continue
|
||||
}
|
||||
return tile
|
||||
|
||||
@@ -56,7 +56,7 @@ export class BotExecution implements Execution {
|
||||
if (this.neighborsTerraNullius) {
|
||||
for (const b of this.bot.borderTiles()) {
|
||||
for (const n of b.neighbors()) {
|
||||
if (n.owner() == this.mg.terraNullius() && n.isLand()) {
|
||||
if (n.owner() == this.mg.terraNullius() && n.terrain().isLand()) {
|
||||
this.sendAttack(this.mg.terraNullius())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ export class BotSpawner {
|
||||
|
||||
spawnBot(botName: string): SpawnIntent | null {
|
||||
const tile = this.randTile()
|
||||
if (!tile.isLand()) {
|
||||
if (!tile.terrain().isLand()) {
|
||||
return null
|
||||
}
|
||||
for (const spawn of this.bots) {
|
||||
|
||||
@@ -30,7 +30,7 @@ export class DefensePostExecution implements Execution {
|
||||
}
|
||||
this.post = this.player.buildUnit(UnitType.DefensePost, 0, spawnTile)
|
||||
bfs(spawnTile, dist(spawnTile, this.mg.config().defensePostRange())).forEach(t => {
|
||||
if (t.isLand()) {
|
||||
if (t.terrain().isLand()) {
|
||||
this.defenseBonuses.push(this.mg.addTileDefenseBonus(t, this.post, this.mg.config().defensePostDefenseBonus()))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -30,7 +30,7 @@ export class DestroyerExecution implements Execution {
|
||||
|
||||
|
||||
init(mg: MutableGame, ticks: number): void {
|
||||
this.pathfinder = PathFinder.Mini(mg, 5000, t => t.terrainType() == TerrainType.Ocean)
|
||||
this.pathfinder = PathFinder.Mini(mg, 5000, t => t.type() == TerrainType.Ocean)
|
||||
this._owner = mg.player(this.playerID)
|
||||
this.mg = mg
|
||||
this.patrolCenterTile = mg.tile(this.cell)
|
||||
@@ -141,7 +141,7 @@ export class DestroyerExecution implements Execution {
|
||||
continue
|
||||
}
|
||||
const tile = this.mg.tile(cell)
|
||||
if (!tile.isOcean()) {
|
||||
if (!tile.terrain().isOcean()) {
|
||||
continue
|
||||
}
|
||||
return tile
|
||||
|
||||
@@ -91,7 +91,7 @@ export class FakeHumanExecution implements Execution {
|
||||
this.handleEnemies()
|
||||
this.handleUnits()
|
||||
|
||||
const enemyborder = Array.from(this.player.borderTiles()).flatMap(t => t.neighbors()).filter(t => t.isLand() && t.owner() != this.player)
|
||||
const enemyborder = Array.from(this.player.borderTiles()).flatMap(t => t.neighbors()).filter(t => t.terrain().isLand() && t.owner() != this.player)
|
||||
|
||||
if (enemyborder.length == 0) {
|
||||
if (this.random.chance(5)) {
|
||||
@@ -243,8 +243,8 @@ export class FakeHumanExecution implements Execution {
|
||||
|
||||
private maybeSendBoatAttack(other: Player) {
|
||||
const closest = closestTwoTiles(
|
||||
Array.from(this.player.borderTiles()).filter(t => t.isOceanShore()),
|
||||
Array.from(other.borderTiles()).filter(t => t.isOceanShore())
|
||||
Array.from(this.player.borderTiles()).filter(t => t.terrain().isOceanShore()),
|
||||
Array.from(other.borderTiles()).filter(t => t.terrain().isOceanShore())
|
||||
)
|
||||
if (closest == null) {
|
||||
return
|
||||
@@ -262,7 +262,7 @@ export class FakeHumanExecution implements Execution {
|
||||
private handleUnits() {
|
||||
const ports = this.player.units(UnitType.Port)
|
||||
if (ports.length == 0 && this.player.gold() > this.cost(UnitType.Port)) {
|
||||
const oceanTiles = Array.from(this.player.borderTiles()).filter(t => t.isOceanShore())
|
||||
const oceanTiles = Array.from(this.player.borderTiles()).filter(t => t.terrain().isOceanShore())
|
||||
if (oceanTiles.length > 0) {
|
||||
const buildTile = this.random.randElement(oceanTiles)
|
||||
this.mg.addExecution(new PortExecution(this.player.id(), buildTile.cell()))
|
||||
@@ -359,7 +359,7 @@ export class FakeHumanExecution implements Execution {
|
||||
continue
|
||||
}
|
||||
const tile = this.mg.tile(cell)
|
||||
if (!tile.isOcean()) {
|
||||
if (!tile.terrain().isOcean()) {
|
||||
continue
|
||||
}
|
||||
return tile
|
||||
@@ -402,7 +402,7 @@ export class FakeHumanExecution implements Execution {
|
||||
}
|
||||
|
||||
if (oceanShore == null) {
|
||||
oceanShore = Array.from(this.player.borderTiles()).filter(t => t.isOceanShore())
|
||||
oceanShore = Array.from(this.player.borderTiles()).filter(t => t.terrain().isOceanShore())
|
||||
}
|
||||
if (oceanShore.length == 0) {
|
||||
return
|
||||
@@ -412,9 +412,9 @@ export class FakeHumanExecution implements Execution {
|
||||
const otherShore = Array.from(
|
||||
bfs(
|
||||
src,
|
||||
and((t) => t.isOcean() || t.isOceanShore(), dist(src, 200))
|
||||
and((t) => t.terrain().isOcean() || t.terrain().isOceanShore(), dist(src, 200))
|
||||
)
|
||||
).filter(t => t.isOceanShore() && t.owner() != this.player)
|
||||
).filter(t => t.terrain().isOceanShore() && t.owner() != this.player)
|
||||
|
||||
if (otherShore.length == 0) {
|
||||
return
|
||||
@@ -453,8 +453,8 @@ export class FakeHumanExecution implements Execution {
|
||||
continue
|
||||
}
|
||||
const tile = this.mg.tile(cell)
|
||||
if (tile.isLand() && !tile.hasOwner()) {
|
||||
if (tile.terrain() == TerrainType.Mountain && this.random.chance(2)) {
|
||||
if (tile.terrain().isLand() && !tile.hasOwner()) {
|
||||
if (tile.terrain().type() == TerrainType.Mountain && this.random.chance(2)) {
|
||||
continue
|
||||
}
|
||||
return tile
|
||||
@@ -474,7 +474,7 @@ export class FakeHumanExecution implements Execution {
|
||||
}
|
||||
|
||||
isSmallIsland(tile: Tile): boolean {
|
||||
return bfs(tile, and((t) => t.isLand(), dist(tile, 10))).size < 50
|
||||
return bfs(tile, and((t) => t.terrain().isLand(), dist(tile, 10))).size < 50
|
||||
}
|
||||
|
||||
owner(): MutablePlayer {
|
||||
|
||||
@@ -92,7 +92,7 @@ export class NukeExecution implements Execution {
|
||||
const prev = attacked.get(mp)
|
||||
attacked.set(mp, prev + 1)
|
||||
}
|
||||
if (tile.isLand()) {
|
||||
if (tile.terrain().isLand()) {
|
||||
this.mg.addFallout(tile)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ export class PlayerExecution implements Execution {
|
||||
private surroundedBySamePlayer(cluster: Set<Tile>): false | Player {
|
||||
const enemies = new Set<Player>()
|
||||
for (const tile of cluster) {
|
||||
if (tile.isOceanShore() || tile.neighbors().find(n => !n.hasOwner())) {
|
||||
if (tile.terrain().isOceanShore() || tile.neighbors().find(n => !n.hasOwner())) {
|
||||
return false
|
||||
}
|
||||
tile.neighbors()
|
||||
@@ -131,7 +131,7 @@ export class PlayerExecution implements Execution {
|
||||
private isSurrounded(cluster: Set<Tile>): boolean {
|
||||
let enemyTiles = new Set<Tile>()
|
||||
for (const tile of cluster) {
|
||||
if (tile.isOceanShore()) {
|
||||
if (tile.terrain().isOceanShore()) {
|
||||
return false
|
||||
}
|
||||
tile.neighbors()
|
||||
|
||||
@@ -41,7 +41,7 @@ export class PortExecution implements Execution {
|
||||
return
|
||||
}
|
||||
const spawns = Array.from(bfs(tile, dist(tile, 20)))
|
||||
.filter(t => t.isOceanShore() && t.owner() == player)
|
||||
.filter(t => t.terrain().isOceanShore() && t.owner() == player)
|
||||
.sort((a, b) => manhattanDist(a.cell(), tile.cell()) - manhattanDist(b.cell(), tile.cell()))
|
||||
|
||||
if (spawns.length == 0) {
|
||||
@@ -89,7 +89,7 @@ export class PortExecution implements Execution {
|
||||
this.mg.terrainMap(),
|
||||
this.mg.terrainMiniMap(),
|
||||
this.port.tile(), port.tile(),
|
||||
sn => sn.terrainType() == TerrainType.Ocean,
|
||||
sn => sn.type() == TerrainType.Ocean,
|
||||
10_000,
|
||||
25
|
||||
)
|
||||
@@ -109,7 +109,7 @@ export class PortExecution implements Execution {
|
||||
const port = this.random.randElement(portConnections)
|
||||
const path = this.portPaths.get(port)
|
||||
if (path != null) {
|
||||
const pf = PathFinder.Mini(this.mg, 10, (sn) => sn.terrainType() == TerrainType.Ocean)
|
||||
const pf = PathFinder.Mini(this.mg, 10, (sn) => sn.type() == TerrainType.Ocean)
|
||||
this.mg.addExecution(new TradeShipExecution(this.player().id(), this.port, port, pf, path))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ export class TransportShipExecution implements Execution {
|
||||
init(mg: MutableGame, ticks: number) {
|
||||
this.lastMove = ticks
|
||||
this.mg = mg
|
||||
this.pathFinder = PathFinder.Mini(mg, 10_000, t => t.terrainType() == TerrainType.Ocean, 2)
|
||||
this.pathFinder = PathFinder.Mini(mg, 10_000, t => t.type() == TerrainType.Ocean, 2)
|
||||
|
||||
this.attacker = mg.player(this.attackerID)
|
||||
|
||||
|
||||
@@ -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).isWater()) {
|
||||
if (gs.tile(c).terrain().isWater()) {
|
||||
continue;
|
||||
}
|
||||
if (gs.tile(c).hasOwner()) {
|
||||
|
||||
+10
-12
@@ -162,7 +162,15 @@ export interface TerrainMap {
|
||||
}
|
||||
|
||||
export interface TerrainTile extends SearchNode {
|
||||
terrainType(): TerrainType
|
||||
isLand(): boolean
|
||||
isShore(): boolean
|
||||
isOceanShore(): boolean
|
||||
isWater(): boolean
|
||||
isShorelineWater(): boolean
|
||||
isOcean(): boolean
|
||||
isLake(): boolean
|
||||
type(): TerrainType
|
||||
magnitude(): number
|
||||
}
|
||||
|
||||
export interface DefenseBonus {
|
||||
@@ -173,15 +181,6 @@ export interface DefenseBonus {
|
||||
}
|
||||
|
||||
export interface Tile extends SearchNode {
|
||||
isLand(): boolean
|
||||
isShore(): boolean
|
||||
isOceanShore(): boolean
|
||||
isWater(): boolean
|
||||
isShorelineWater(): boolean
|
||||
isOcean(): boolean
|
||||
isLake(): boolean
|
||||
terrain(): TerrainType
|
||||
magnitude(): number
|
||||
owner(): Player | TerraNullius
|
||||
hasOwner(): boolean
|
||||
isBorder(): boolean
|
||||
@@ -190,12 +189,11 @@ export interface Tile extends SearchNode {
|
||||
cell(): Cell
|
||||
neighbors(): Tile[]
|
||||
neighborsWrapped(): Tile[]
|
||||
onShore(): boolean
|
||||
|
||||
defenseBonuses(): DefenseBonus[]
|
||||
// defense bonus against this player
|
||||
defenseBonus(player: Player): number
|
||||
hasFallout(): boolean
|
||||
terrain(): TerrainTile
|
||||
}
|
||||
|
||||
export interface Unit {
|
||||
|
||||
@@ -342,7 +342,7 @@ export class GameImpl implements MutableGame {
|
||||
if (!tile.hasOwner()) {
|
||||
throw new Error(`Cannot relinquish tile because it is unowned: cell ${tile.cell().toString()}`)
|
||||
}
|
||||
if (tile.isWater()) {
|
||||
if (tile.terrain().isWater()) {
|
||||
throw new Error("Cannot relinquish water")
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,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.isLand() && neighbor.owner() != this) {
|
||||
if (neighbor.terrain().isLand() && neighbor.owner() != this) {
|
||||
ns.add((neighbor as TileImpl)._owner);
|
||||
}
|
||||
}
|
||||
@@ -450,7 +450,7 @@ export class PlayerImpl implements MutablePlayer {
|
||||
|
||||
portSpawn(tile: Tile): Tile | false {
|
||||
const spawns = Array.from(bfs(tile, dist(tile, 20)))
|
||||
.filter(t => t.owner() == this && t.isOceanShore())
|
||||
.filter(t => t.owner() == this && t.terrain().isOceanShore())
|
||||
.sort((a, b) => manhattanDist(a.cell(), tile.cell()) - manhattanDist(b.cell(), tile.cell()))
|
||||
if (spawns.length == 0) {
|
||||
return false
|
||||
@@ -459,7 +459,7 @@ export class PlayerImpl implements MutablePlayer {
|
||||
}
|
||||
|
||||
warshipSpawn(tile: Tile): Tile | false {
|
||||
if (!tile.isOcean()) {
|
||||
if (!tile.terrain().isOcean()) {
|
||||
return false
|
||||
}
|
||||
const spawns = this.units(UnitType.Port)
|
||||
@@ -479,7 +479,7 @@ export class PlayerImpl implements MutablePlayer {
|
||||
}
|
||||
|
||||
transportShipSpawn(targetTile: Tile): Tile | false {
|
||||
if (!targetTile.isOceanShore()) {
|
||||
if (!targetTile.terrain().isOceanShore()) {
|
||||
return false
|
||||
}
|
||||
const spawn = closestOceanShoreFromPlayer(this, targetTile, this.gs.width())
|
||||
|
||||
@@ -20,19 +20,41 @@ export interface Nation {
|
||||
|
||||
export class TerrainTileImpl implements TerrainTile {
|
||||
public shoreline: boolean = false
|
||||
public magnitude: number = 0
|
||||
public _magnitude: number = 0
|
||||
public ocean = false
|
||||
public land = false
|
||||
private _neighbors: TerrainTile[] | null = null
|
||||
|
||||
constructor(private map: TerrainMap, public type: TerrainType, private _cell: Cell) { }
|
||||
|
||||
terrainType(): TerrainType {
|
||||
return this.type
|
||||
constructor(private map: TerrainMap, public _type: TerrainType, private _cell: Cell) { }
|
||||
type(): TerrainType {
|
||||
return this._type
|
||||
}
|
||||
isLake(): boolean {
|
||||
return !this.isLand() && !this.isOcean();
|
||||
}
|
||||
isOcean(): boolean {
|
||||
return this.ocean;
|
||||
}
|
||||
magnitude(): number {
|
||||
return this._magnitude;
|
||||
}
|
||||
isShore(): boolean {
|
||||
return this.isLand() && this.shoreline;
|
||||
}
|
||||
isOceanShore(): boolean {
|
||||
return this.isShore() && this.neighbors().filter(n => n.isOcean()).length > -1;
|
||||
}
|
||||
isShorelineWater(): boolean {
|
||||
return this.isWater() && this.shoreline;
|
||||
}
|
||||
isLand(): boolean {
|
||||
return this.land;
|
||||
}
|
||||
isWater(): boolean {
|
||||
return !this.land;
|
||||
}
|
||||
|
||||
cost(): number {
|
||||
return this.magnitude < 10 ? 2 : 1
|
||||
return this._magnitude < 10 ? 2 : 1
|
||||
}
|
||||
|
||||
cell(): Cell {
|
||||
@@ -146,7 +168,7 @@ export async function loadTerrainFromFile(fileData: string): Promise<TerrainMapI
|
||||
|
||||
terrain[x][y] = new TerrainTileImpl(m, type, new Cell(x, y));
|
||||
terrain[x][y].shoreline = shoreline;
|
||||
terrain[x][y].magnitude = magnitude;
|
||||
terrain[x][y]._magnitude = magnitude;
|
||||
terrain[x][y].ocean = ocean
|
||||
terrain[x][y].land = land
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ export class TileImpl implements Tile {
|
||||
return this._hasFallout
|
||||
}
|
||||
|
||||
terrainType(): TerrainType {
|
||||
return this._terrain.type
|
||||
type(): TerrainType {
|
||||
return this._terrain._type
|
||||
}
|
||||
|
||||
defenseBonus(player: Player): number {
|
||||
@@ -77,32 +77,8 @@ export class TileImpl implements Tile {
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
isLake(): boolean {
|
||||
return !this.isLand() && !this.isOcean();
|
||||
}
|
||||
isOcean(): boolean {
|
||||
return this._terrain.ocean;
|
||||
}
|
||||
magnitude(): number {
|
||||
return this._terrain.magnitude;
|
||||
}
|
||||
isShore(): boolean {
|
||||
return this.isLand() && this._terrain.shoreline;
|
||||
}
|
||||
isOceanShore(): boolean {
|
||||
return this.isShore() && this.neighbors().filter(n => n.isOcean()).length > 0;
|
||||
}
|
||||
isShorelineWater(): boolean {
|
||||
return this.isWater() && this._terrain.shoreline;
|
||||
}
|
||||
isLand(): boolean {
|
||||
return this._terrain.land;
|
||||
}
|
||||
isWater(): boolean {
|
||||
return !this._terrain.land;
|
||||
}
|
||||
terrain(): TerrainType {
|
||||
return this._terrain.type;
|
||||
terrain(): TerrainTile {
|
||||
return this._terrain
|
||||
}
|
||||
|
||||
borders(other: Player | TerraNullius): boolean {
|
||||
@@ -114,12 +90,6 @@ export class TileImpl implements Tile {
|
||||
return false;
|
||||
}
|
||||
|
||||
onShore(): boolean {
|
||||
return this.neighbors()
|
||||
.filter(t => t.isWater())
|
||||
.length > 0;
|
||||
}
|
||||
|
||||
hasOwner(): boolean { return this._owner != this.gs._terraNullius; }
|
||||
owner(): MutablePlayer | TerraNullius { return this._owner; }
|
||||
isBorder(): boolean { return this._isBorder; }
|
||||
@@ -140,6 +110,6 @@ export class TileImpl implements Tile {
|
||||
}
|
||||
|
||||
cost(): number {
|
||||
return this.magnitude() < 10 ? 2 : 1
|
||||
return this.terrain().magnitude() < 10 ? 2 : 1
|
||||
};
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ export interface SearchNode {
|
||||
cost(): number
|
||||
cell(): Cell
|
||||
neighbors(): SearchNode[]
|
||||
terrainType(): TerrainType
|
||||
type(): TerrainType
|
||||
}
|
||||
export interface Point {
|
||||
x: number;
|
||||
|
||||
@@ -53,7 +53,7 @@ function findPath(terrainMap: TerrainMap, miniTerrainMap: TerrainMap, req: Searc
|
||||
miniTerrainMap,
|
||||
terrainMap.terrain(req.start),
|
||||
terrainMap.terrain(req.end),
|
||||
(sn: SearchNode) => (sn as TerrainTile).terrainType() == TerrainType.Ocean,
|
||||
(sn: SearchNode) => (sn as TerrainTile).type() == TerrainType.Ocean,
|
||||
10_000,
|
||||
req.duration,
|
||||
);
|
||||
|
||||
@@ -117,7 +117,7 @@ export class ParallelAStar implements AStar {
|
||||
this.game.terrainMap(),
|
||||
this.game.terrainMiniMap(),
|
||||
this.src, this.dst,
|
||||
(t: TerrainTile) => t.terrainType() == TerrainType.Ocean,
|
||||
(t: TerrainTile) => t.type() == TerrainType.Ocean,
|
||||
100_000_000,
|
||||
20
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user