diff --git a/src/client/graphics/GameRenderer.ts b/src/client/graphics/GameRenderer.ts index 858493198..2865f9d17 100644 --- a/src/client/graphics/GameRenderer.ts +++ b/src/client/graphics/GameRenderer.ts @@ -77,7 +77,7 @@ export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus: new TerritoryLayer(game, eventBus), new StructureLayer(game, eventBus), new UnitLayer(game, eventBus, clientID), - new NameLayer(game, game.config().theme(), transformHandler, clientID), + new NameLayer(game, eventBus, game.config().theme(), transformHandler, clientID), new UILayer(eventBus, game, clientID, transformHandler), eventsDisplay, new RadialMenu(eventBus, game, transformHandler, clientID, emojiTable as EmojiTable, buildMenu, uiState), diff --git a/src/client/graphics/layers/NameLayer.ts b/src/client/graphics/layers/NameLayer.ts index 4e3cdaf8f..9d60519bd 100644 --- a/src/client/graphics/layers/NameLayer.ts +++ b/src/client/graphics/layers/NameLayer.ts @@ -11,6 +11,8 @@ import allianceIcon from '../../../../resources/images/AllianceIcon.png'; import crownIcon from '../../../../resources/images/CrownIcon.png'; import targetIcon from '../../../../resources/images/TargetIcon.png'; import { ClientID } from "../../../core/Schemas" +import { EventBus } from "../../../core/EventBus" +import { AlternateViewEvent } from "../../InputHandler" class RenderInfo { @@ -42,7 +44,17 @@ export class NameLayer implements Layer { private firstPlace: Player | null = null - constructor(private game: Game, private theme: Theme, private transformHandler: TransformHandler, private clientID: ClientID) { + private alternateView = false + + constructor( + private game: Game, + private eventBus: EventBus, + private theme: Theme, + private transformHandler: TransformHandler, + private clientID: ClientID + ) { + this.eventBus.on(AlternateViewEvent, e => { this.alternateView = e.alternateView }) + this.traitorIconImage = new Image(); this.traitorIconImage.src = traitorIcon; @@ -146,6 +158,11 @@ export class NameLayer implements Layer { } renderPlayerInfo(render: RenderInfo, context: CanvasRenderingContext2D, scale: number, uppperLeft: Cell, bottomRight: Cell) { + if (this.alternateView) { + return + } + + const nameCenterX = Math.floor(render.location.x - this.game.width() / 2) const nameCenterY = Math.floor(render.location.y - this.game.height() / 2) diff --git a/src/client/graphics/layers/TerritoryLayer.ts b/src/client/graphics/layers/TerritoryLayer.ts index 6a397fd7a..1e11e5f7c 100644 --- a/src/client/graphics/layers/TerritoryLayer.ts +++ b/src/client/graphics/layers/TerritoryLayer.ts @@ -8,6 +8,7 @@ import { Layer } from "./Layer"; import { TransformHandler } from "../TransformHandler"; import { EventBus } from "../../../core/EventBus"; import { initRemoteSender } from "../../../core/Consolex"; +import { AlternateViewEvent } from "../../InputHandler"; export class TerritoryLayer implements Layer { private canvas: HTMLCanvasElement @@ -22,10 +23,11 @@ export class TerritoryLayer implements Layer { private highlightCanvas: HTMLCanvasElement private highlightContext: CanvasRenderingContext2D + private alternativeView = false - constructor(private game: Game, eventBus: EventBus) { + + constructor(private game: Game, private eventBus: EventBus) { this.theme = game.config().theme() - eventBus.on(TileEvent, e => this.tileUpdate(e)) } shouldTransform(): boolean { @@ -58,11 +60,14 @@ export class TerritoryLayer implements Layer { } init(game: Game) { - console.log('redrew territory layer') + this.eventBus.on(TileEvent, e => this.tileUpdate(e)) + this.eventBus.on(AlternateViewEvent, e => { this.alternativeView = e.alternateView }) this.redraw() } + redraw() { + console.log('redrew territory layer') this.canvas = document.createElement('canvas'); this.context = this.canvas.getContext("2d") @@ -94,6 +99,9 @@ export class TerritoryLayer implements Layer { renderLayer(context: CanvasRenderingContext2D) { this.renderTerritory() this.context.putImageData(this.imageData, 0, 0); + if (this.alternativeView) { + return + } context.drawImage( this.canvas, @@ -155,7 +163,7 @@ export class TerritoryLayer implements Layer { this.paintCell( tile.cell(), this.theme.territoryColor(owner.info()), - 110 + 150 ) } } diff --git a/src/core/execution/FakeHumanExecution.ts b/src/core/execution/FakeHumanExecution.ts index 2f1131330..7976d2a24 100644 --- a/src/core/execution/FakeHumanExecution.ts +++ b/src/core/execution/FakeHumanExecution.ts @@ -1,6 +1,6 @@ import { Cell, Execution, MutableGame, MutablePlayer, Player, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tile, UnitType } from "../game/Game" import { PseudoRandom } from "../PseudoRandom" -import { and, bfs, dist, euclDist, manhattanDist, simpleHash } from "../Util"; +import { and, bfs, calculateBoundingBox, dist, euclDist, manhattanDist, simpleHash } from "../Util"; import { AttackExecution } from "./AttackExecution"; import { TransportShipExecution } from "./TransportShipExecution"; import { SpawnExecution } from "./SpawnExecution"; @@ -11,6 +11,7 @@ import { DestroyerExecution } from "./DestroyerExecution"; import { BattleshipExecution } from "./BattleshipExecution"; import { GameID } from "../Schemas"; import { consolex } from "../Consolex"; +import { CityExecution } from "./CityExecution"; export class FakeHumanExecution implements Execution { @@ -71,6 +72,11 @@ export class FakeHumanExecution implements Execution { return } + if (!this.player.isAlive()) { + this.active = false + return + } + if (this.player.troops() > 100_000 && this.player.targetTroopRatio() > .7) { this.player.setTargetTroopRatio(.7) } @@ -162,6 +168,7 @@ export class FakeHumanExecution implements Execution { } return } + this.maybeSpawnCity() if (this.maybeSpawnWarship(UnitType.Destroyer)) { return } @@ -170,6 +177,22 @@ export class FakeHumanExecution implements Execution { } } + private maybeSpawnCity() { + const cities = this.player.units(UnitType.City) + if (cities.length > 5) { + return + } + if (this.player.gold() > this.mg.config().unitInfo(UnitType.City).cost(this.player)) { + return + } + const tile = this.randTerritoryTile() + const canBuild = this.player.canBuild(UnitType.City, tile) + if (canBuild == false) { + return + } + this.mg.addExecution(new CityExecution(this.player.id(), tile.cell())) + } + private maybeSpawnWarship(shipType: UnitType.Destroyer | UnitType.Battleship): boolean { if (!this.random.chance(30)) { return false @@ -200,6 +223,23 @@ export class FakeHumanExecution implements Execution { return false } + private randTerritoryTile(): Tile | null { + const boundingBox = calculateBoundingBox(this.player.borderTiles()) + for (let i = 0; i < 100; i++) { + const randX = this.random.nextInt(boundingBox.min.x, boundingBox.max.x) + const randY = this.random.nextInt(boundingBox.min.y, boundingBox.max.y) + if (!this.mg.isOnMap(new Cell(randX, randY))) { + // Sanity check should never happen + continue + } + const randTile = this.mg.tile(new Cell(randX, randY)) + if (randTile.owner() == this.player) { + return randTile + } + } + return null + } + private warshipSpawnTile(portTile: Tile): Tile | null { const radius = this.mg.config().boatMaxDistance() / 2 for (let attempts = 0; attempts < 50; attempts++) {