update views

This commit is contained in:
Evan
2025-02-01 12:05:11 -08:00
parent dab427d614
commit f988d555bb
10 changed files with 233 additions and 206 deletions
+20 -15
View File
@@ -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<Tile>
isPlayer(): this is Player
neighbors(): (Player | TerraNullius)[]
numTilesOwned(): number
tiles(): ReadonlySet<Tile>
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<MutableTile>
ownsTile(cell: Cell): boolean
tiles(): ReadonlySet<MutableTile>
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[]
+6 -6
View File
@@ -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
+26 -8
View File
@@ -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<PlayerViewData> {
public _lastTileChange: number = 0
@@ -27,10 +28,10 @@ export class PlayerImpl implements MutablePlayer {
isTraitor_ = false
public _borderTiles: Set<Tile> = new Set();
public _borderTiles: Set<TileImpl> = new Set();
public _units: UnitImpl[] = [];
public _tiles: Map<CellString, Tile> = new Map<CellString, Tile>();
public _tiles: Map<CellString, Tile> = new Map<CellString, TileImpl>();
private _name: string;
private _displayName: string;
@@ -54,6 +55,23 @@ export class PlayerImpl implements MutablePlayer {
this._displayName = processName(this._name)
}
toViewData(): ViewData<PlayerViewData> {
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<Tile> {
return new Set(this._tiles.values());
tiles(): ReadonlySet<MutableTile> {
return new Set(this._tiles.values()) as Set<MutableTile>;
}
borderTiles(): ReadonlySet<Tile> {
borderTiles(): ReadonlySet<MutableTile> {
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 {
+18 -3
View File
@@ -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<TileViewData> {
public _isBorder = false;
private _neighbors: Tile[] = null;
@@ -22,6 +23,17 @@ export class TileImpl implements Tile {
private readonly _terrain: TerrainTileImpl
) { }
toViewData(): ViewData<TileViewData> {
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
+14 -1
View File
@@ -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<UnitViewData> {
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<UnitViewData> {
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
}