mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 11:10:42 +00:00
refactored GameImpl into multiple files
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import {Config, getConfig} from "../core/configuration/Config";
|
||||
import {GameID, Lobby, ServerMessage, ServerMessageSchema} from "../core/Schemas";
|
||||
import {loadTerrainMap, TerrainMap} from "../core/TerrainMapLoader";
|
||||
import {loadTerrainMap, TerrainMap} from "../core/game/TerrainMapLoader";
|
||||
import {ClientGame, createClientGame} from "./ClientGame";
|
||||
import backgroundImage from '../../resources/images/TerrainMapFrontPage.png';
|
||||
import favicon from '../../resources/images/Favicon.png';
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import {Executor} from "../core/execution/ExecutionManager";
|
||||
import {Cell, MutableGame, PlayerEvent, PlayerID, MutablePlayer, TileEvent, Player, Game, BoatEvent, Tile, PlayerType} from "../core/Game";
|
||||
import {createGame} from "../core/GameImpl";
|
||||
import {Cell, MutableGame, PlayerEvent, PlayerID, MutablePlayer, TileEvent, Player, Game, BoatEvent, Tile, PlayerType} from "../core/game/Game";
|
||||
import {createGame} from "../core/game/GameImpl";
|
||||
import {EventBus} from "../core/EventBus";
|
||||
import {Config} from "../core/configuration/Config";
|
||||
import {createRenderer, 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";
|
||||
import {TerrainMap} from "../core/game/TerrainMapLoader";
|
||||
import {and, bfs, dist, manhattanDist} from "../core/Util";
|
||||
import {TerrainLayer} from "./graphics/layers/TerrainLayer";
|
||||
import {WinCheckExecution} from "../core/execution/WinCheckExecution";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {EventBus, GameEvent} from "../core/EventBus";
|
||||
import {Cell} from "../core/Game";
|
||||
import {Cell} from "../core/game/Game";
|
||||
|
||||
export class MouseUpEvent implements GameEvent {
|
||||
constructor(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Game} from "../../core/Game";
|
||||
import {Game} from "../../core/game/Game";
|
||||
import {NameLayer} from "./layers/NameLayer";
|
||||
import {TerrainLayer} from "./layers/TerrainLayer";
|
||||
import {TerritoryLayer} from "./layers/TerritoryLayer";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Game, Player, Tile, Cell} from '../../core/Game';
|
||||
import {Game, Player, Tile, Cell} from '../../core/game/Game';
|
||||
import {calculateBoundingBox, within} from '../../core/Util';
|
||||
|
||||
export interface Point {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {EventBus} from "../../core/EventBus"
|
||||
import {Cell, Game} from "../../core/Game";
|
||||
import {Cell, Game} from "../../core/game/Game";
|
||||
import {ZoomEvent, DragEvent} from "../InputHandler";
|
||||
|
||||
export class TransformHandler {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Cell, Game, Player, PlayerType} from "../../../core/Game"
|
||||
import {Cell, Game, Player, PlayerType} from "../../../core/game/Game"
|
||||
import {PseudoRandom} from "../../../core/PseudoRandom"
|
||||
import {calculateBoundingBox} from "../../../core/Util"
|
||||
import {Theme} from "../../../core/configuration/Config"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {inherits} from "util"
|
||||
import {Game} from "../../../core/Game";
|
||||
import {Game} from "../../../core/game/Game";
|
||||
import {throws} from "assert";
|
||||
import {Layer} from "./Layer";
|
||||
import {TransformHandler} from "../TransformHandler";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {PriorityQueue} from "@datastructures-js/priority-queue";
|
||||
import {Boat, BoatEvent, Cell, Game, Player, Tile, TileEvent} from "../../../core/Game";
|
||||
import {Boat, BoatEvent, Cell, Game, Player, Tile, TileEvent} from "../../../core/game/Game";
|
||||
import {PseudoRandom} from "../../../core/PseudoRandom";
|
||||
import {Colord} from "colord";
|
||||
import {bfs, dist} from "../../../core/Util";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {GameEnv, Theme} from "../../../core/configuration/Config";
|
||||
import {EventBus, GameEvent} from "../../../core/EventBus";
|
||||
import {WinEvent} from "../../../core/execution/WinCheckExecution";
|
||||
import {AllianceRequest, Game, Player} from "../../../core/Game";
|
||||
import {AllianceRequest, Game, Player} from "../../../core/game/Game";
|
||||
import {ClientID} from "../../../core/Schemas";
|
||||
import {renderTroops} from "../Utils";
|
||||
import winModalHtml from '../WinModal.html';
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import {z} from 'zod';
|
||||
import {PlayerType} from './Game';
|
||||
import {PlayerType} from './game/Game';
|
||||
|
||||
export type GameID = string
|
||||
export type ClientID = string
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import {v4 as uuidv4} from 'uuid';
|
||||
|
||||
|
||||
import {Cell, Player, Tile} from "./Game";
|
||||
import {Cell, Player, Tile} from "./game/Game";
|
||||
|
||||
export function manhattanDist(c1: Cell, c2: Cell): number {
|
||||
return Math.abs(c1.x - c2.x) + Math.abs(c1.y - c2.y);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Player, PlayerID, PlayerInfo, TerraNullius, Tile} from "../Game";
|
||||
import {Player, PlayerID, PlayerInfo, TerraNullius, Tile} from "../game/Game";
|
||||
import {Colord, colord} from "colord";
|
||||
import {devConfig} from "./DevConfig";
|
||||
import {defaultConfig} from "./DefaultConfig";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Player, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tile} from "../Game";
|
||||
import {Player, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tile} from "../game/Game";
|
||||
import {GameID} from "../Schemas";
|
||||
import {simpleHash, within} from "../Util";
|
||||
import {Config, Theme} from "./Config";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Colord, colord, random} from "colord";
|
||||
import {PlayerID, PlayerInfo, TerrainType, Tile} from "../Game";
|
||||
import {PlayerID, PlayerInfo, TerrainType, Tile} from "../game/Game";
|
||||
import {Theme} from "./Config";
|
||||
import {time} from "console";
|
||||
import {PseudoRandom} from "../PseudoRandom";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {AllianceRequest, Execution, MutableGame, MutablePlayer, Player, PlayerID} from "../Game";
|
||||
import {AllianceRequest, Execution, MutableGame, MutablePlayer, Player, PlayerID} from "../game/Game";
|
||||
|
||||
export class AllianceRequestExecution implements Execution {
|
||||
private active = true
|
||||
@@ -17,7 +17,7 @@ export class AllianceRequestExecution implements Execution {
|
||||
|
||||
tick(ticks: number): void {
|
||||
alert('recied request')
|
||||
|
||||
|
||||
this.active = false
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {PriorityQueue} from "@datastructures-js/priority-queue";
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, PlayerID, TerrainType, TerraNullius, Tile} from "../Game";
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, PlayerID, TerrainType, TerraNullius, Tile} from "../game/Game";
|
||||
import {PseudoRandom} from "../PseudoRandom";
|
||||
import {manhattanDist} from "../Util";
|
||||
import {Terrain} from "../TerrainMapLoader";
|
||||
import {Terrain} from "../game/TerrainMapLoader";
|
||||
|
||||
export class AttackExecution implements Execution {
|
||||
private active: boolean = true;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {PriorityQueue} from "@datastructures-js/priority-queue";
|
||||
import {Boat, Cell, Execution, MutableBoat, MutableGame, MutablePlayer, Player, PlayerID, TerraNullius, Tile, TileEvent} from "../Game";
|
||||
import {Boat, Cell, Execution, MutableBoat, MutableGame, MutablePlayer, Player, PlayerID, TerraNullius, Tile, TileEvent} from "../game/Game";
|
||||
import {manhattanDist, manhattanDistWrapped} from "../Util";
|
||||
import {AttackExecution} from "./AttackExecution";
|
||||
import {Config} from "../configuration/Config";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, PlayerType, TerraNullius} from "../Game"
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, PlayerType, TerraNullius} from "../game/Game"
|
||||
import {PseudoRandom} from "../PseudoRandom"
|
||||
import {simpleHash} from "../Util";
|
||||
import {AttackExecution} from "./AttackExecution";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Cell, Game, PlayerType, Tile, TileEvent} from "../Game";
|
||||
import {Cell, Game, PlayerType, Tile, TileEvent} from "../game/Game";
|
||||
import {PseudoRandom} from "../PseudoRandom";
|
||||
import {SpawnIntent} from "../Schemas";
|
||||
import {bfs, dist as dist, manhattanDist} from "../Util";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Cell, Execution, MutableGame, Game, MutablePlayer, PlayerInfo, TerraNullius, Tile, PlayerType, Alliance} from "../Game";
|
||||
import {Cell, Execution, MutableGame, Game, MutablePlayer, PlayerInfo, TerraNullius, Tile, PlayerType, Alliance} from "../game/Game";
|
||||
import {AttackIntent, BoatAttackIntentSchema, GameID, Intent, Turn} from "../Schemas";
|
||||
import {AttackExecution} from "./AttackExecution";
|
||||
import {SpawnExecution} from "./SpawnExecution";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tile} from "../Game"
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tile} from "../game/Game"
|
||||
import {PseudoRandom} from "../PseudoRandom"
|
||||
import {and, bfs, dist, simpleHash} from "../Util";
|
||||
import {AttackExecution} from "./AttackExecution";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {Config} from "../configuration/Config"
|
||||
import {Execution, MutableGame, MutablePlayer, Player, PlayerID, TerraNullius, Tile} from "../Game"
|
||||
import {Execution, MutableGame, MutablePlayer, Player, PlayerID, TerraNullius, Tile} from "../game/Game"
|
||||
import {bfs, calculateBoundingBox, getMode, inscribed, simpleHash} from "../Util"
|
||||
import {GameImpl} from "../GameImpl"
|
||||
import {GameImpl} from "../game/GameImpl"
|
||||
|
||||
export class PlayerExecution implements Execution {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, PlayerInfo, PlayerType} from "../Game"
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, PlayerInfo, PlayerType} from "../game/Game"
|
||||
import {BotExecution} from "./BotExecution"
|
||||
import {PlayerExecution} from "./PlayerExecution"
|
||||
import {getSpawnCells} from "./Util"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Execution, MutableGame, MutablePlayer, PlayerID} from "../Game"
|
||||
import {Execution, MutableGame, MutablePlayer, PlayerID} from "../game/Game"
|
||||
import {ClientID} from "../Schemas"
|
||||
|
||||
export class UpdateNameExecution implements Execution {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Game, Cell} from "../Game";
|
||||
import {Game, Cell} from "../game/Game";
|
||||
|
||||
|
||||
export function getSpawnCells(gs: Game, cell: Cell): Cell[] {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {EventBus, GameEvent} from "../EventBus"
|
||||
import {Execution, MutableGame, MutablePlayer, Player, PlayerID} from "../Game"
|
||||
import {Execution, MutableGame, MutablePlayer, Player, PlayerID} from "../game/Game"
|
||||
|
||||
export class WinEvent implements GameEvent {
|
||||
constructor(public readonly winner: Player) { }
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import {MutableAllianceRequest, Player} from "./Game";
|
||||
import {GameImpl} from "./GameImpl";
|
||||
|
||||
|
||||
export class AllianceRequestImpl implements MutableAllianceRequest {
|
||||
|
||||
constructor(private requestor_, private recipient_, private game: GameImpl) { }
|
||||
|
||||
requestor(): Player {
|
||||
return this.requestor_;
|
||||
}
|
||||
|
||||
recipient(): Player {
|
||||
return this.recipient_;
|
||||
}
|
||||
|
||||
accept(): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
reject(): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import {MutableBoat, Tile, TerraNullius} from "./Game";
|
||||
import {GameImpl} from "./GameImpl";
|
||||
import {PlayerImpl} from "./PlayerImpl";
|
||||
import {TerraNulliusImpl} from "./TerraNulliusImpl";
|
||||
|
||||
|
||||
export class BoatImpl implements MutableBoat {
|
||||
private _active = true;
|
||||
|
||||
constructor(
|
||||
private g: GameImpl,
|
||||
private _tile: Tile,
|
||||
private _troops: number,
|
||||
private _owner: PlayerImpl,
|
||||
private _target: PlayerImpl | TerraNulliusImpl
|
||||
) { }
|
||||
|
||||
move(tile: Tile): void {
|
||||
const oldTile = this._tile;
|
||||
this._tile = tile;
|
||||
this.g.fireBoatUpdateEvent(this, oldTile);
|
||||
}
|
||||
setTroops(troops: number): void {
|
||||
this._troops = troops;
|
||||
}
|
||||
troops(): number {
|
||||
return this._troops;
|
||||
}
|
||||
tile(): Tile {
|
||||
return this._tile;
|
||||
}
|
||||
owner(): PlayerImpl {
|
||||
return this._owner;
|
||||
}
|
||||
target(): PlayerImpl | TerraNullius {
|
||||
return this._target;
|
||||
}
|
||||
delete(): void {
|
||||
this._owner._boats = this._owner._boats.filter(b => b != this);
|
||||
this._active = false;
|
||||
this.g.fireBoatUpdateEvent(this, this._tile);
|
||||
}
|
||||
isActive(): boolean {
|
||||
return this._active;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import {info} from "console"
|
||||
import {Config} from "./configuration/Config"
|
||||
import {GameEvent} from "./EventBus"
|
||||
import {ClientID, GameID} from "./Schemas"
|
||||
import {Config} from "../configuration/Config"
|
||||
import {GameEvent} from "../EventBus"
|
||||
import {ClientID, GameID} from "../Schemas"
|
||||
|
||||
export type PlayerID = string
|
||||
|
||||
@@ -1,308 +1,18 @@
|
||||
import {info} from "console";
|
||||
import {Config} from "./configuration/Config";
|
||||
import {EventBus} from "./EventBus";
|
||||
import {Cell, Execution, MutableGame, Game, MutablePlayer, PlayerEvent, PlayerID, PlayerInfo, Player, TerraNullius, Tile, TileEvent, Boat, MutableBoat, BoatEvent, TerrainType, PlayerType, MutableAllianceRequest} from "./Game";
|
||||
import {ClientID} from "./Schemas";
|
||||
import {Terrain, TerrainMap} from "./TerrainMapLoader";
|
||||
import {simpleHash} from "./Util";
|
||||
import {Config} from "../configuration/Config";
|
||||
import {EventBus} from "../EventBus";
|
||||
import {Cell, Execution, MutableGame, Game, MutablePlayer, PlayerEvent, PlayerID, PlayerInfo, Player, TerraNullius, Tile, TileEvent, Boat, BoatEvent, PlayerType, MutableAllianceRequest} from "./Game";
|
||||
import {TerrainMap} from "./TerrainMapLoader";
|
||||
import {PlayerImpl} from "./PlayerImpl";
|
||||
import {TerraNulliusImpl} from "./TerraNulliusImpl";
|
||||
import {TileImpl} from "./TileImpl";
|
||||
import {AllianceRequestImpl} from "./AllianceRequestImpl";
|
||||
|
||||
export function createGame(terrainMap: TerrainMap, eventBus: EventBus, config: Config): Game {
|
||||
return new GameImpl(terrainMap, eventBus, config)
|
||||
}
|
||||
|
||||
type CellString = string
|
||||
|
||||
class TileImpl implements Tile {
|
||||
|
||||
public _isBorder = false
|
||||
private _neighbors: Tile[] = null
|
||||
|
||||
constructor(
|
||||
private readonly gs: GameImpl,
|
||||
public _owner: PlayerImpl | TerraNulliusImpl,
|
||||
private readonly _cell: Cell,
|
||||
private readonly _terrain: Terrain
|
||||
) { }
|
||||
|
||||
neighborsWrapped(): Tile[] {
|
||||
const x = this._cell.x;
|
||||
const y = this._cell.y;
|
||||
const ns: Tile[] = [];
|
||||
|
||||
// Check top neighbor
|
||||
if (y > 0) {
|
||||
ns.push(this.gs.map[x][y - 1]);
|
||||
} else {
|
||||
ns.push(this.gs.map[x][this.gs.height() - 1]);
|
||||
}
|
||||
|
||||
// Check bottom neighbor
|
||||
if (y < this.gs.height() - 1) {
|
||||
ns.push(this.gs.map[x][y + 1]);
|
||||
} else {
|
||||
ns.push(this.gs.map[x][0]);
|
||||
}
|
||||
|
||||
// Check left neighbor (wrap around)
|
||||
if (x > 0) {
|
||||
ns.push(this.gs.map[x - 1][y]);
|
||||
} else {
|
||||
ns.push(this.gs.map[this.gs.width() - 1][y]);
|
||||
}
|
||||
|
||||
// Check right neighbor (wrap around)
|
||||
if (x < this.gs.width() - 1) {
|
||||
ns.push(this.gs.map[x + 1][y]);
|
||||
} else {
|
||||
ns.push(this.gs.map[0][y]);
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
borders(other: Player | TerraNullius): boolean {
|
||||
for (const n of this.neighbors()) {
|
||||
if (n.owner() == other) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
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}
|
||||
isInterior(): boolean {return this.hasOwner() && !this.isBorder()}
|
||||
cell(): Cell {return this._cell}
|
||||
|
||||
neighbors(): Tile[] {
|
||||
if (this._neighbors == null) {
|
||||
this._neighbors = this.gs.neighbors(this)
|
||||
}
|
||||
return this._neighbors
|
||||
}
|
||||
}
|
||||
|
||||
export class AllianceRequestImpl implements MutableAllianceRequest {
|
||||
|
||||
constructor(private requestor_, private recipient_, private game: GameImpl) { }
|
||||
|
||||
requestor(): Player {
|
||||
return this.requestor_
|
||||
}
|
||||
|
||||
recipient(): Player {
|
||||
return this.recipient_
|
||||
}
|
||||
|
||||
accept(): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
reject(): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class BoatImpl implements MutableBoat {
|
||||
private _active = true
|
||||
|
||||
constructor(
|
||||
private g: GameImpl,
|
||||
private _tile: Tile,
|
||||
private _troops: number,
|
||||
private _owner: PlayerImpl,
|
||||
private _target: PlayerImpl | TerraNulliusImpl
|
||||
) { }
|
||||
|
||||
move(tile: Tile): void {
|
||||
const oldTile = this._tile
|
||||
this._tile = tile
|
||||
this.g.fireBoatUpdateEvent(this, oldTile)
|
||||
}
|
||||
setTroops(troops: number): void {
|
||||
this._troops = troops
|
||||
}
|
||||
troops(): number {
|
||||
return this._troops
|
||||
}
|
||||
tile(): Tile {
|
||||
return this._tile
|
||||
}
|
||||
owner(): PlayerImpl {
|
||||
return this._owner
|
||||
}
|
||||
target(): PlayerImpl | TerraNullius {
|
||||
return this._target
|
||||
}
|
||||
delete(): void {
|
||||
this._owner._boats = this._owner._boats.filter(b => b != this)
|
||||
this._active = false
|
||||
this.g.fireBoatUpdateEvent(this, this._tile)
|
||||
}
|
||||
isActive(): boolean {
|
||||
return this._active
|
||||
}
|
||||
}
|
||||
|
||||
export class PlayerImpl implements MutablePlayer {
|
||||
public _borderTiles: Set<Tile> = new Set()
|
||||
|
||||
public _boats: BoatImpl[] = []
|
||||
public _tiles: Map<CellString, Tile> = new Map<CellString, Tile>()
|
||||
|
||||
private _name: string
|
||||
|
||||
constructor(private gs: GameImpl, private readonly playerInfo: PlayerInfo, private _troops) {
|
||||
this._name = playerInfo.name
|
||||
}
|
||||
|
||||
name(): string {
|
||||
return this._name
|
||||
}
|
||||
|
||||
clientID(): ClientID {
|
||||
return this.playerInfo.clientID
|
||||
}
|
||||
|
||||
id(): PlayerID {
|
||||
return this.playerInfo.id
|
||||
}
|
||||
|
||||
type(): PlayerType {
|
||||
return this.playerInfo.playerType
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
|
||||
}
|
||||
|
||||
addBoat(troops: number, tile: Tile, target: Player | TerraNullius): BoatImpl {
|
||||
const b = new BoatImpl(this.gs, tile, troops, this, target as PlayerImpl | TerraNulliusImpl)
|
||||
this._boats.push(b)
|
||||
this.gs.fireBoatUpdateEvent(b, b.tile())
|
||||
return b
|
||||
}
|
||||
|
||||
boats(): BoatImpl[] {
|
||||
return this._boats
|
||||
}
|
||||
|
||||
sharesBorderWith(other: Player | TerraNullius): boolean {
|
||||
for (const border of this._borderTiles) {
|
||||
for (const neighbor of border.neighbors()) {
|
||||
if (neighbor.owner() == other) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
numTilesOwned(): number {
|
||||
return this._tiles.size
|
||||
}
|
||||
|
||||
tiles(): ReadonlySet<Tile> {
|
||||
return new Set(this._tiles.values())
|
||||
}
|
||||
|
||||
borderTiles(): ReadonlySet<Tile> {
|
||||
return this._borderTiles
|
||||
}
|
||||
|
||||
neighbors(): (MutablePlayer | TerraNullius)[] {
|
||||
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) {
|
||||
ns.add((neighbor as TileImpl)._owner)
|
||||
}
|
||||
}
|
||||
}
|
||||
return Array.from(ns)
|
||||
}
|
||||
|
||||
addTroops(troops: number): void {
|
||||
this._troops += Math.floor(troops)
|
||||
}
|
||||
removeTroops(troops: number): void {
|
||||
this._troops -= Math.floor(troops)
|
||||
this._troops = Math.max(this._troops, 0)
|
||||
}
|
||||
|
||||
isPlayer(): this is MutablePlayer {return true as const}
|
||||
ownsTile(cell: Cell): boolean {return this._tiles.has(cell.toString())}
|
||||
setTroops(troops: number) {this._troops = Math.floor(troops)}
|
||||
conquer(tile: Tile) {this.gs.conquer(this, tile)}
|
||||
relinquish(tile: Tile) {
|
||||
if (tile.owner() != this) {
|
||||
throw new Error(`Cannot relinquish tile not owned by this player`)
|
||||
}
|
||||
this.gs.relinquish(tile)
|
||||
}
|
||||
info(): PlayerInfo {return this.playerInfo}
|
||||
troops(): number {return this._troops}
|
||||
isAlive(): boolean {return this._tiles.size > 0}
|
||||
gameState(): MutableGame {return this.gs}
|
||||
executions(): Execution[] {
|
||||
return this.gs.executions().filter(exec => exec.owner().id() == this.id())
|
||||
}
|
||||
hash(): number {
|
||||
return simpleHash(this.id()) * (this.troops() + this.numTilesOwned())
|
||||
}
|
||||
toString(): string {
|
||||
return `Player:{name:${this.info().name},clientID:${this.info().clientID},isAlive:${this.isAlive()},troops:${this._troops},numTileOwned:${this.numTilesOwned()}}]`
|
||||
}
|
||||
}
|
||||
|
||||
class TerraNulliusImpl implements TerraNullius {
|
||||
public tiles: Map<Cell, Tile> = new Map<Cell, Tile>()
|
||||
|
||||
|
||||
constructor(private gs: GameImpl) {
|
||||
}
|
||||
|
||||
id(): PlayerID {
|
||||
return 'TerraNulliusID'
|
||||
}
|
||||
ownsTile(cell: Cell): boolean {
|
||||
return this.tiles.has(cell)
|
||||
}
|
||||
isPlayer(): false {return false as const}
|
||||
}
|
||||
|
||||
export type CellString = string
|
||||
|
||||
export class GameImpl implements MutableGame {
|
||||
private _ticks = 0
|
||||
@@ -531,15 +241,6 @@ export class GameImpl implements MutableGame {
|
||||
}
|
||||
|
||||
conquer(owner: PlayerImpl, tile: Tile): void {
|
||||
// if (tile.owner() == owner) {
|
||||
// throw new Error(`Player ${owner} already owns cell ${tile.cell().toString()}`)
|
||||
// }
|
||||
// if (!owner.isPlayer()) {
|
||||
// throw new Error("Must be a player")
|
||||
// }
|
||||
// if (tile.isWater()) {
|
||||
// throw new Error("Cannot conquer water")
|
||||
// }
|
||||
const tileImpl = tile as TileImpl
|
||||
let previousOwner = tileImpl._owner
|
||||
if (previousOwner.isPlayer()) {
|
||||
@@ -0,0 +1,117 @@
|
||||
import {MutablePlayer, Tile, PlayerInfo, PlayerID, PlayerType, Player, TerraNullius, Cell, MutableGame, Execution} from "./Game";
|
||||
import {ClientID} from "../Schemas";
|
||||
import {simpleHash} from "../Util";
|
||||
import {CellString, GameImpl} from "./GameImpl";
|
||||
import {BoatImpl} from "./BoatImpl";
|
||||
import {TileImpl} from "./TileImpl";
|
||||
import {TerraNulliusImpl} from "./TerraNulliusImpl";
|
||||
|
||||
|
||||
export class PlayerImpl implements MutablePlayer {
|
||||
public _borderTiles: Set<Tile> = new Set();
|
||||
|
||||
public _boats: BoatImpl[] = [];
|
||||
public _tiles: Map<CellString, Tile> = new Map<CellString, Tile>();
|
||||
|
||||
private _name: string;
|
||||
|
||||
constructor(private gs: GameImpl, private readonly playerInfo: PlayerInfo, private _troops) {
|
||||
this._name = playerInfo.name;
|
||||
}
|
||||
|
||||
name(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
clientID(): ClientID {
|
||||
return this.playerInfo.clientID;
|
||||
}
|
||||
|
||||
id(): PlayerID {
|
||||
return this.playerInfo.id;
|
||||
}
|
||||
|
||||
type(): PlayerType {
|
||||
return this.playerInfo.playerType;
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
}
|
||||
|
||||
addBoat(troops: number, tile: Tile, target: Player | TerraNullius): BoatImpl {
|
||||
const b = new BoatImpl(this.gs, tile, troops, this, target as PlayerImpl | TerraNulliusImpl);
|
||||
this._boats.push(b);
|
||||
this.gs.fireBoatUpdateEvent(b, b.tile());
|
||||
return b;
|
||||
}
|
||||
|
||||
boats(): BoatImpl[] {
|
||||
return this._boats;
|
||||
}
|
||||
|
||||
sharesBorderWith(other: Player | TerraNullius): boolean {
|
||||
for (const border of this._borderTiles) {
|
||||
for (const neighbor of border.neighbors()) {
|
||||
if (neighbor.owner() == other) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
numTilesOwned(): number {
|
||||
return this._tiles.size;
|
||||
}
|
||||
|
||||
tiles(): ReadonlySet<Tile> {
|
||||
return new Set(this._tiles.values());
|
||||
}
|
||||
|
||||
borderTiles(): ReadonlySet<Tile> {
|
||||
return this._borderTiles;
|
||||
}
|
||||
|
||||
neighbors(): (MutablePlayer | TerraNullius)[] {
|
||||
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) {
|
||||
ns.add((neighbor as TileImpl)._owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Array.from(ns);
|
||||
}
|
||||
|
||||
addTroops(troops: number): void {
|
||||
this._troops += Math.floor(troops);
|
||||
}
|
||||
removeTroops(troops: number): void {
|
||||
this._troops -= Math.floor(troops);
|
||||
this._troops = Math.max(this._troops, 0);
|
||||
}
|
||||
|
||||
isPlayer(): this is MutablePlayer {return true as const;}
|
||||
ownsTile(cell: Cell): boolean {return this._tiles.has(cell.toString());}
|
||||
setTroops(troops: number) {this._troops = Math.floor(troops);}
|
||||
conquer(tile: Tile) {this.gs.conquer(this, tile);}
|
||||
relinquish(tile: Tile) {
|
||||
if (tile.owner() != this) {
|
||||
throw new Error(`Cannot relinquish tile not owned by this player`);
|
||||
}
|
||||
this.gs.relinquish(tile);
|
||||
}
|
||||
info(): PlayerInfo {return this.playerInfo;}
|
||||
troops(): number {return this._troops;}
|
||||
isAlive(): boolean {return this._tiles.size > 0;}
|
||||
gameState(): MutableGame {return this.gs;}
|
||||
executions(): Execution[] {
|
||||
return this.gs.executions().filter(exec => exec.owner().id() == this.id());
|
||||
}
|
||||
hash(): number {
|
||||
return simpleHash(this.id()) * (this.troops() + this.numTilesOwned());
|
||||
}
|
||||
toString(): string {
|
||||
return `Player:{name:${this.info().name},clientID:${this.info().clientID},isAlive:${this.isAlive()},troops:${this._troops},numTileOwned:${this.numTilesOwned()}}]`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import {TerraNullius, Cell, Tile, PlayerID} from "./Game";
|
||||
import {GameImpl} from "./GameImpl";
|
||||
|
||||
|
||||
export class TerraNulliusImpl implements TerraNullius {
|
||||
public tiles: Map<Cell, Tile> = new Map<Cell, Tile>();
|
||||
|
||||
|
||||
constructor(private gs: GameImpl) {
|
||||
}
|
||||
|
||||
id(): PlayerID {
|
||||
return 'TerraNulliusID';
|
||||
}
|
||||
ownsTile(cell: Cell): boolean {
|
||||
return this.tiles.has(cell);
|
||||
}
|
||||
isPlayer(): false {return false as const;}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Cell, TerrainType} from './Game';
|
||||
import binAsString from "!!binary-loader!../../resources/TopoWorldMap.bin";
|
||||
import binAsString from "!!binary-loader!../../../resources/TopoWorldMap.bin";
|
||||
|
||||
export class TerrainMap {
|
||||
constructor(public readonly tiles: Terrain[][], public readonly numLandTiles: number) { }
|
||||
@@ -0,0 +1,109 @@
|
||||
import {Tile, Cell, TerrainType, Player, TerraNullius, MutablePlayer} from "./Game";
|
||||
import {Terrain} from "./TerrainMapLoader";
|
||||
import {GameImpl} from "./GameImpl";
|
||||
import {PlayerImpl} from "./PlayerImpl";
|
||||
import {TerraNulliusImpl} from "./TerraNulliusImpl";
|
||||
|
||||
|
||||
export class TileImpl implements Tile {
|
||||
|
||||
public _isBorder = false;
|
||||
private _neighbors: Tile[] = null;
|
||||
|
||||
constructor(
|
||||
private readonly gs: GameImpl,
|
||||
public _owner: PlayerImpl | TerraNulliusImpl,
|
||||
private readonly _cell: Cell,
|
||||
private readonly _terrain: Terrain
|
||||
) { }
|
||||
|
||||
neighborsWrapped(): Tile[] {
|
||||
const x = this._cell.x;
|
||||
const y = this._cell.y;
|
||||
const ns: Tile[] = [];
|
||||
|
||||
// Check top neighbor
|
||||
if (y > 0) {
|
||||
ns.push(this.gs.map[x][y - 1]);
|
||||
} else {
|
||||
ns.push(this.gs.map[x][this.gs.height() - 1]);
|
||||
}
|
||||
|
||||
// Check bottom neighbor
|
||||
if (y < this.gs.height() - 1) {
|
||||
ns.push(this.gs.map[x][y + 1]);
|
||||
} else {
|
||||
ns.push(this.gs.map[x][0]);
|
||||
}
|
||||
|
||||
// Check left neighbor (wrap around)
|
||||
if (x > 0) {
|
||||
ns.push(this.gs.map[x - 1][y]);
|
||||
} else {
|
||||
ns.push(this.gs.map[this.gs.width() - 1][y]);
|
||||
}
|
||||
|
||||
// Check right neighbor (wrap around)
|
||||
if (x < this.gs.width() - 1) {
|
||||
ns.push(this.gs.map[x + 1][y]);
|
||||
} else {
|
||||
ns.push(this.gs.map[0][y]);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
borders(other: Player | TerraNullius): boolean {
|
||||
for (const n of this.neighbors()) {
|
||||
if (n.owner() == other) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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;}
|
||||
isInterior(): boolean {return this.hasOwner() && !this.isBorder();}
|
||||
cell(): Cell {return this._cell;}
|
||||
|
||||
neighbors(): Tile[] {
|
||||
if (this._neighbors == null) {
|
||||
this._neighbors = this.gs.neighbors(this);
|
||||
}
|
||||
return this._neighbors;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user