From f988d555bb2e65896f6df69af9b49d378fc23792 Mon Sep 17 00:00:00 2001 From: Evan Date: Thu, 2 Jan 2025 16:55:27 -0800 Subject: [PATCH] update views --- src/client/graphics/layers/TerritoryLayer.ts | 2 +- src/core/GameRunner.ts | 2 +- src/core/GameView.ts | 292 +++++++++---------- src/core/GameViewData.ts | 22 -- src/core/configuration/DefaultConfig.ts | 4 +- src/core/game/Game.ts | 35 ++- src/core/game/GameImpl.ts | 12 +- src/core/game/PlayerImpl.ts | 34 ++- src/core/game/TileImpl.ts | 21 +- src/core/game/UnitImpl.ts | 15 +- 10 files changed, 233 insertions(+), 206 deletions(-) diff --git a/src/client/graphics/layers/TerritoryLayer.ts b/src/client/graphics/layers/TerritoryLayer.ts index 1e11e5f7c..5b915ae5b 100644 --- a/src/client/graphics/layers/TerritoryLayer.ts +++ b/src/client/graphics/layers/TerritoryLayer.ts @@ -146,7 +146,7 @@ export class TerritoryLayer implements Layer { } const owner = tile.owner() as Player if (tile.isBorder()) { - if (tile.defenseBonuses().filter(db => db.unit.owner() == owner).length > 0) { + if (tile.hasDefenseBonus()) { this.paintCell( tile.cell(), this.theme.defendedBorderColor(owner.info()), diff --git a/src/core/GameRunner.ts b/src/core/GameRunner.ts index b336113eb..1217cf772 100644 --- a/src/core/GameRunner.ts +++ b/src/core/GameRunner.ts @@ -4,7 +4,7 @@ import { Executor } from "./execution/ExecutionManager"; import { Game, Tile, TileEvent } from "./game/Game"; import { createGame } from "./game/GameImpl"; import { loadTerrainMap } from "./game/TerrainMapLoader"; -import { GameUpdateViewData } from "./GameViewData"; +import { GameUpdateViewData } from "./GameView"; import { GameConfig, Turn } from "./Schemas"; export async function createGameRunner(gameID: string, gameConfig: GameConfig): Promise { diff --git a/src/core/GameView.ts b/src/core/GameView.ts index 024c1f1ca..9cf4f3fcb 100644 --- a/src/core/GameView.ts +++ b/src/core/GameView.ts @@ -1,80 +1,70 @@ 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 { Alliance, AllianceRequest, AllPlayers, Cell, DefenseBonus, EmojiMessage, Execution, ExecutionView, Game, Gold, MutableTile, Nation, Player, PlayerID, PlayerInfo, PlayerType, Relation, TerrainMap, TerrainTile, TerrainType, TerraNullius, Tick, Tile, Unit, UnitInfo, UnitType } from "./game/Game"; import { ClientID } from "./Schemas"; +export interface ViewSerializable { + toViewData(): ViewData; +} + +export interface ViewData { + // Base view data properties if any +} + +export interface TileViewData extends ViewData { + x: number + y: number + owner: PlayerID, + hasFallout: boolean + hasDefenseBonus: boolean + isBorder: boolean +} + 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."); + constructor(private game: Game, private data: TileViewData, private _terrain: TerrainTile) { } + type(): TerrainType { + return this._terrain.type() } owner(): Player | TerraNullius { - throw new Error("Method not implemented."); + return this.game.player(this.data.owner) } hasOwner(): boolean { - throw new Error("Method not implemented."); + return this.data.owner != null } 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."); + return this.data.isBorder } cell(): Cell { - throw new Error("Method not implemented."); + return new Cell(this.data.x, this.data.y) } + hasFallout(): boolean { + return this.data.hasFallout + } + terrain(): TerrainTile { + return this._terrain + } + 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 { + + + hasDefenseBonus(): boolean { throw new Error("Method not implemented."); } cost(): number { throw new Error("Method not implemented."); } - type(): TerrainType { - throw new Error("Method not implemented."); - } +} + +export interface UnitViewData extends ViewData { + type: UnitType, + troops: number, + x: number, + y: number, + owner: string, + isActive: boolean, + health?: number } export class UnitView implements Unit { @@ -95,136 +85,144 @@ export class UnitView implements Unit { isActive(): boolean { throw new Error("Method not implemented."); } - info(): UnitInfo { - throw new Error("Method not implemented."); - } hasHealth(): boolean { - throw new Error("Method not implemented."); + return this.data.health != undefined } health(): number { - throw new Error("Method not implemented."); + return this.data.health ?? 0 } } +export interface PlayerViewData extends ViewData { + clientID: ClientID, + name: string, + displayName: string, + id: PlayerID, + type: PlayerType, + isAlive: boolean, + tilesOwned: number, + allies: PlayerID[], + gold: number, + population: number, + workers: number, + troops: number, + targetTroopRatio: number +} + export class PlayerView implements Player { - constructor(private data: PlayerViewData) { } - info(): PlayerInfo { - throw new Error("Method not implemented."); - } + constructor(private game: Game, private data: PlayerViewData) { } name(): string { - throw new Error("Method not implemented."); + return this.data.name } displayName(): string { - throw new Error("Method not implemented."); + return this.data.displayName } clientID(): ClientID { - throw new Error("Method not implemented."); + return this.data.clientID } id(): PlayerID { - throw new Error("Method not implemented."); + return this.data.id } 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."); + return this.data.type } isAlive(): boolean { - throw new Error("Method not implemented."); - } - borderTiles(): ReadonlySet { - throw new Error("Method not implemented."); + return this.data.isAlive } isPlayer(): this is Player { - throw new Error("Method not implemented."); - } - neighbors(): (Player | TerraNullius)[] { - throw new Error("Method not implemented."); + return true } numTilesOwned(): number { - throw new Error("Method not implemented."); - } - tiles(): ReadonlySet { - 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."); + return this.data.tilesOwned } 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."); + return this.data.allies.map(a => this.game.player(a)) } gold(): Gold { - throw new Error("Method not implemented."); + return this.data.gold } population(): number { - throw new Error("Method not implemented."); + return this.data.workers } workers(): number { - throw new Error("Method not implemented."); + return this.data.workers } targetTroopRatio(): number { - throw new Error("Method not implemented."); + return this.data.targetTroopRatio } troops(): number { - throw new Error("Method not implemented."); + return + } + + isAlliedWith(other: Player): boolean { + return false + } + allianceWith(other: Player): Alliance | null { + return null + } + borderTiles(): ReadonlySet { + return new Set() + } + units(...types: UnitType[]): Unit[] { + return [] + } + sharesBorderWith(other: Player | TerraNullius): boolean { + return false + } + incomingAllianceRequests(): AllianceRequest[] { + return [] + } + outgoingAllianceRequests(): AllianceRequest[] { + return [] + } + alliances(): Alliance[] { + return [] + } + recentOrPendingAllianceRequestWith(other: Player): boolean { + return false + } + relation(other: Player): Relation { + return Relation.Neutral + } + allRelationsSorted(): { player: Player; relation: Relation; }[] { + return [] + } + transitiveTargets(): Player[] { + return [] + } + isTraitor(): boolean { + return false + } + canTarget(other: Player): boolean { + return false + } + toString(): string { + return '' + } + canSendEmoji(recipient: Player | typeof AllPlayers): boolean { + return false + } + outgoingEmojis(): EmojiMessage[] { + return [] + } + canDonate(recipient: Player): boolean { + return false } canBuild(type: UnitType, targetTile: Tile): Tile | false { - throw new Error("Method not implemented."); + return false } lastTileChange(): Tick { - throw new Error("Method not implemented."); + return 0 } + info(): PlayerInfo { + return null + } +} + +export interface GameUpdateViewData extends ViewData { + units: UnitViewData[] + players: PlayerViewData[] + tileUpdates: TileViewData[] } export class GameView implements Game { @@ -247,7 +245,7 @@ export class GameView implements Game { } recentlyUpdatedTiles(): TileView[] { - return this.lastGameUpdate.tileUpdates.map(tu => new TileView(tu, this._terrainMap.terrain(new Cell(tu.x, tu.y)))) + return this.lastGameUpdate.tileUpdates.map(tu => new TileView(this, tu, this._terrainMap.terrain(new Cell(tu.x, tu.y)))) } player(id: PlayerID): Player { diff --git a/src/core/GameViewData.ts b/src/core/GameViewData.ts index db592fa26..fd40910d9 100644 --- a/src/core/GameViewData.ts +++ b/src/core/GameViewData.ts @@ -1,26 +1,4 @@ -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[] -} \ No newline at end of file diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index 98e3e74bc..ccac63ba8 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -1,4 +1,4 @@ -import { Difficulty, GameType, Gold, Player, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tick, Tile, Unit, UnitInfo, UnitType } from "../game/Game"; +import { Difficulty, GameType, Gold, MutableTile, Player, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tick, Tile, Unit, UnitInfo, UnitType } from "../game/Game"; import { GameConfig } from "../Schemas"; import { assertNever, distSort, manhattanDist, simpleHash, within } from "../Util"; import { Config, ServerConfig, Theme } from "./Config"; @@ -186,7 +186,7 @@ export class DefaultConfig implements Config { } theme(): Theme { return pastelTheme; } - attackLogic(attackTroops: number, attacker: Player, defender: Player | TerraNullius, tileToConquer: Tile): { attackerTroopLoss: number; defenderTroopLoss: number; tilesPerTickUsed: number } { + attackLogic(attackTroops: number, attacker: Player, defender: Player | TerraNullius, tileToConquer: MutableTile): { attackerTroopLoss: number; defenderTroopLoss: number; tilesPerTickUsed: number } { let mag = 0 let speed = 0 switch (tileToConquer.terrain().type()) { diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index 00b341ec3..53b750daf 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -184,16 +184,19 @@ export interface Tile extends SearchNode { owner(): Player | TerraNullius hasOwner(): boolean isBorder(): boolean - borders(other: Player | TerraNullius): boolean - isInterior(): boolean cell(): Cell - neighbors(): Tile[] - neighborsWrapped(): Tile[] - defenseBonuses(): DefenseBonus[] - // defense bonus against this player - defenseBonus(player: Player): number hasFallout(): boolean terrain(): TerrainTile + neighbors(): Tile[] + hasDefenseBonus(): boolean +} + +export interface MutableTile extends Tile { + // defense bonus against this player + defenseBonus(player: Player): number + borders(other: Player | TerraNullius): boolean + neighborsWrapped(): Tile[] + defenseBonuses(): DefenseBonus[] } export interface Unit { @@ -202,7 +205,6 @@ export interface Unit { tile(): Tile owner(): Player isActive(): boolean - info(): UnitInfo hasHealth(): boolean health(): number } @@ -211,6 +213,7 @@ export interface MutableUnit extends Unit { move(tile: Tile): void owner(): MutablePlayer setTroops(troops: number): void + info(): UnitInfo delete(displayerMessage?: boolean): void modifyHealth(delta: number): void } @@ -230,13 +233,10 @@ export interface Player { id(): PlayerID type(): PlayerType units(...types: UnitType[]): Unit[] - ownsTile(cell: Cell): boolean isAlive(): boolean borderTiles(): ReadonlySet isPlayer(): this is Player - neighbors(): (Player | TerraNullius)[] numTilesOwned(): number - tiles(): ReadonlySet sharesBorderWith(other: Player | TerraNullius): boolean incomingAllianceRequests(): AllianceRequest[] outgoingAllianceRequests(): AllianceRequest[] @@ -251,12 +251,9 @@ export interface Player { relation(other: Player): Relation // Sorted from most hated to most liked allRelationsSorted(): { player: Player, relation: Relation }[] + transitiveTargets(): Player[] isTraitor(): boolean canTarget(other: Player): boolean - // Targets for this player - targets(): Player[] - // Targets of player and all allies. - transitiveTargets(): Player[] toString(): string canSendEmoji(recipient: Player | typeof AllPlayers): boolean outgoingEmojis(): EmojiMessage[] @@ -275,6 +272,13 @@ export interface Player { } export interface MutablePlayer extends Player { + // Targets for this player + targets(): Player[] + // Targets of player and all allies. + neighbors(): (Player | TerraNullius)[] + tiles(): ReadonlySet + ownsTile(cell: Cell): boolean + tiles(): ReadonlySet conquer(tile: Tile): void relinquish(tile: Tile): void executions(): Execution[] @@ -338,6 +342,7 @@ export interface Game { } export interface MutableGame extends Game { + tile(cell: Cell): MutableTile player(id: PlayerID): MutablePlayer playerByClientID(id: ClientID): MutablePlayer | null players(): MutablePlayer[] diff --git a/src/core/game/GameImpl.ts b/src/core/game/GameImpl.ts index 8b22c9fad..7d89b4407 100644 --- a/src/core/game/GameImpl.ts +++ b/src/core/game/GameImpl.ts @@ -1,7 +1,7 @@ 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, Unit, UnitEvent as UnitEvent, PlayerType, MutableAllianceRequest, AllianceRequestReplyEvent, AllianceRequestEvent, BrokeAllianceEvent, MutableAlliance, Alliance, AllianceExpiredEvent, Nation, UnitType, UnitInfo, TerrainMap, DefenseBonus } from "./Game"; +import { Cell, Execution, MutableGame, Game, MutablePlayer, PlayerEvent, PlayerID, PlayerInfo, Player, TerraNullius, Tile, TileEvent, Unit, UnitEvent as UnitEvent, PlayerType, MutableAllianceRequest, AllianceRequestReplyEvent, AllianceRequestEvent, BrokeAllianceEvent, MutableAlliance, Alliance, AllianceExpiredEvent, Nation, UnitType, UnitInfo, TerrainMap, DefenseBonus, MutableTile } from "./Game"; import { TerrainMapImpl } from "./TerrainMapLoader"; import { PlayerImpl } from "./PlayerImpl"; import { TerraNulliusImpl } from "./TerraNulliusImpl"; @@ -267,9 +267,9 @@ export class GameImpl implements MutableGame { } - tile(cell: Cell): Tile { + tile(cell: Cell): MutableTile { this.assertIsOnMap(cell) - return this.map[cell.x][cell.y] + return this.map[cell.x][cell.y] as MutableTile } isOnMap(cell: Cell): boolean { @@ -327,7 +327,7 @@ export class GameImpl implements MutableGame { if (previousOwner.isPlayer()) { previousOwner._lastTileChange = this._ticks previousOwner._tiles.delete(tile.cell().toString()) - previousOwner._borderTiles.delete(tile) + previousOwner._borderTiles.delete(tileImpl) tileImpl._isBorder = false } tileImpl._owner = owner @@ -350,7 +350,7 @@ export class GameImpl implements MutableGame { let previousOwner = tileImpl._owner as PlayerImpl previousOwner._lastTileChange = this._ticks previousOwner._tiles.delete(tile.cell().toString()) - previousOwner._borderTiles.delete(tile) + previousOwner._borderTiles.delete(tileImpl) tileImpl._isBorder = false tileImpl._owner = this._terraNullius @@ -382,7 +382,7 @@ export class GameImpl implements MutableGame { if (!tile.hasOwner()) { return false } - for (const neighbor of tile.neighbors()) { + for (const neighbor of (tile as MutableTile).neighbors()) { let bordersEnemy = tile.owner() != neighbor.owner() if (bordersEnemy) { return true diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index 4b053b1d2..68795a7a3 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -1,4 +1,4 @@ -import { MutablePlayer, Tile, PlayerInfo, PlayerID, PlayerType, Player, TerraNullius, Cell, Execution, AllianceRequest, MutableAllianceRequest, MutableAlliance, Alliance, Tick, TargetPlayerEvent, EmojiMessage, EmojiMessageEvent, AllPlayers, Gold, UnitType, Unit, MutableUnit, Relation } from "./Game"; +import { MutablePlayer, Tile, PlayerInfo, PlayerID, PlayerType, Player, TerraNullius, Cell, Execution, AllianceRequest, MutableAllianceRequest, MutableAlliance, Alliance, Tick, TargetPlayerEvent, EmojiMessage, EmojiMessageEvent, AllPlayers, Gold, UnitType, Unit, MutableUnit, Relation, MutableTile } from "./Game"; import { ClientID } from "../Schemas"; import { assertNever, bfs, closestOceanShoreFromPlayer, dist, distSortUnit, manhattanDist, manhattanDistWrapped, processName, simpleHash, sourceDstOceanShore, within } from "../Util"; import { CellString, GameImpl } from "./GameImpl"; @@ -6,6 +6,7 @@ import { UnitImpl } from "./UnitImpl"; import { TileImpl } from "./TileImpl"; import { MessageType } from "../../client/graphics/layers/EventsDisplay"; import { renderTroops } from "../../client/Utils"; +import { PlayerViewData, ViewData, ViewSerializable } from "../GameView"; interface Target { tick: Tick @@ -16,7 +17,7 @@ class Donation { constructor(public readonly recipient: Player, public readonly tick: Tick) { } } -export class PlayerImpl implements MutablePlayer { +export class PlayerImpl implements MutablePlayer, ViewSerializable { public _lastTileChange: number = 0 @@ -27,10 +28,10 @@ export class PlayerImpl implements MutablePlayer { isTraitor_ = false - public _borderTiles: Set = new Set(); + public _borderTiles: Set = new Set(); public _units: UnitImpl[] = []; - public _tiles: Map = new Map(); + public _tiles: Map = new Map(); private _name: string; private _displayName: string; @@ -54,6 +55,23 @@ export class PlayerImpl implements MutablePlayer { this._displayName = processName(this._name) } + toViewData(): ViewData { + return { + clientID: this.clientID(), + name: this.name(), + displayName: this.displayName(), + id: this.id(), + type: this.type(), + isAlive: this.isAlive(), + tilesOwned: this.numTilesOwned(), + allies: this.allies().map(p => p.id()), + gold: this._gold, + population: this.population(), + workers: this.workers(), + troops: this.troops(), + targetTroopRatio: this.targetTroopRatio() + } + } name(): string { return this._name; @@ -98,11 +116,11 @@ export class PlayerImpl implements MutablePlayer { return this._tiles.size; } - tiles(): ReadonlySet { - return new Set(this._tiles.values()); + tiles(): ReadonlySet { + return new Set(this._tiles.values()) as Set; } - borderTiles(): ReadonlySet { + borderTiles(): ReadonlySet { return this._borderTiles; } @@ -279,7 +297,7 @@ export class PlayerImpl implements MutablePlayer { transitiveTargets(): MutablePlayer[] { const ts = this.alliances().map(a => a.other(this)).flatMap(ally => ally.targets()) ts.push(...this.targets()) - return [...new Set(ts)] + return [...new Set(ts)] as MutablePlayer[] } sendEmoji(recipient: Player | typeof AllPlayers, emoji: string): void { diff --git a/src/core/game/TileImpl.ts b/src/core/game/TileImpl.ts index d25c02ee3..e57f92aaa 100644 --- a/src/core/game/TileImpl.ts +++ b/src/core/game/TileImpl.ts @@ -1,12 +1,13 @@ -import { Tile, Cell, TerrainType, Player, TerraNullius, MutablePlayer, TerrainTile, DefenseBonus } from "./Game"; +import { Tile, Cell, TerrainType, Player, TerraNullius, MutablePlayer, TerrainTile, DefenseBonus, MutableTile } from "./Game"; import { SearchNode } from "../pathfinding/AStar"; import { TerrainTileImpl } from "./TerrainMapLoader"; import { GameImpl } from "./GameImpl"; import { PlayerImpl } from "./PlayerImpl"; import { TerraNulliusImpl } from "./TerraNulliusImpl"; +import { TileView, TileViewData, ViewData, ViewSerializable } from "../GameView"; -export class TileImpl implements Tile { +export class TileImpl implements MutableTile, ViewSerializable { public _isBorder = false; private _neighbors: Tile[] = null; @@ -22,6 +23,17 @@ export class TileImpl implements Tile { private readonly _terrain: TerrainTileImpl ) { } + toViewData(): ViewData { + return { + x: this._cell.x, + y: this._cell.y, + owner: this._owner?.id(), + hasFallout: this._hasFallout, + hasDefenseBonus: this.hasDefenseBonus(), + isBorder: this.isBorder() + } + } + hasFallout(): boolean { return this._hasFallout } @@ -30,6 +42,10 @@ export class TileImpl implements Tile { return this._terrain._type } + hasDefenseBonus(): boolean { + return this.defenseBonuses.length > 0 + } + defenseBonus(player: Player): number { if (this.owner() == player) { throw Error(`cannot get defense bonus of tile already owned by player, ${player}`) @@ -93,7 +109,6 @@ export class TileImpl implements Tile { 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; } x(): number { return this._cell.x diff --git a/src/core/game/UnitImpl.ts b/src/core/game/UnitImpl.ts index 04713afbf..23262da56 100644 --- a/src/core/game/UnitImpl.ts +++ b/src/core/game/UnitImpl.ts @@ -1,4 +1,5 @@ import { MessageType } from "../../client/graphics/layers/EventsDisplay"; +import { UnitViewData, ViewData, ViewSerializable } from "../GameView"; import { simpleHash, within } from "../Util"; import { MutableUnit, Tile, TerraNullius, UnitType, Player, UnitInfo } from "./Game"; import { GameImpl } from "./GameImpl"; @@ -6,7 +7,7 @@ import { PlayerImpl } from "./PlayerImpl"; import { TerraNulliusImpl } from "./TerraNulliusImpl"; -export class UnitImpl implements MutableUnit { +export class UnitImpl implements MutableUnit, ViewSerializable { private _active = true; private _health: number @@ -21,6 +22,18 @@ export class UnitImpl implements MutableUnit { this._health = (this.g.unitInfo(_type).maxHealth ?? 2) / 2 } + toViewData(): ViewData { + return { + type: this._type, + troops: this._troops, + x: this.tile().cell().x, + y: this.tile().cell().y, + owner: this.owner().id(), + isActive: this.isActive(), + health: this._health, + } + } + type(): UnitType { return this._type }