mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 03:00:43 +00:00
port spawns on coast
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Config } from "../core/configuration/Config"
|
||||
import { EventBus, GameEvent } from "../core/EventBus"
|
||||
import { AllianceRequest, AllPlayers, Cell, Item, Player, PlayerID, PlayerType, Tile, UnitType } from "../core/game/Game"
|
||||
import { AllianceRequest, AllPlayers, Cell, BuildItem, Player, PlayerID, PlayerType, Tile, UnitType } from "../core/game/Game"
|
||||
import { ClientID, ClientIntentMessageSchema, ClientJoinMessageSchema, ClientLeaveMessageSchema, BuildUnitIntentSchema, GameID, Intent, ServerMessage, ServerMessageSchema } from "../core/Schemas"
|
||||
import { LocalServer } from "./LocalServer"
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import { ControlPanel } from "./layers/ControlPanel";
|
||||
import { UIState } from "./UIState";
|
||||
import { BuildMenu } from "./layers/radial/BuildMenu";
|
||||
import { UnitLayer } from "./layers/UnitLayer";
|
||||
import { BuildValidator } from "../../core/game/BuildValidator";
|
||||
|
||||
|
||||
export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus: EventBus, clientID: ClientID): GameRenderer {
|
||||
@@ -33,7 +34,7 @@ export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus:
|
||||
}
|
||||
buildMenu.game = game
|
||||
buildMenu.eventBus = eventBus
|
||||
buildMenu.init()
|
||||
buildMenu.buildValidator = new BuildValidator(game)
|
||||
|
||||
const leaderboard = document.querySelector('leader-board') as Leaderboard;
|
||||
if (!emojiTable || !(leaderboard instanceof Leaderboard)) {
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import { LitElement, html, css } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { EventBus } from '../../../../core/EventBus';
|
||||
import { Cell, Game, Item, BuildItems, Player, UnitType } from '../../../../core/game/Game';
|
||||
import { BuildUnitIntentEvent as BuildItemIntentEvent, BuildUnitIntentEvent, SendNukeIntentEvent } from '../../../Transport';
|
||||
import { Cell, Game, BuildItem, BuildItems, Player, UnitType } from '../../../../core/game/Game';
|
||||
import { BuildUnitIntentEvent, SendNukeIntentEvent } from '../../../Transport';
|
||||
import nukeIcon from '../../../../../resources/images/NukeIconWhite.svg';
|
||||
import destroyerIcon from '../../../../../resources/images/DestroyerIconWhite.svg';
|
||||
import goldCoinIcon from '../../../../../resources/images/GoldCoinIcon.svg';
|
||||
import portIcon from '../../../../../resources/images/PortIcon.svg';
|
||||
import { renderNumber } from '../../Utils';
|
||||
import { ContextMenuEvent } from '../../../InputHandler';
|
||||
import { BuildValidator } from '../../../../core/game/BuildValidator';
|
||||
|
||||
interface BuildItem {
|
||||
item: Item
|
||||
interface BuildItemDisplay {
|
||||
item: BuildItem
|
||||
icon: string;
|
||||
}
|
||||
|
||||
const buildTable: BuildItem[][] = [
|
||||
const buildTable: BuildItemDisplay[][] = [
|
||||
[
|
||||
{ item: BuildItems.Nuke, icon: nukeIcon },
|
||||
{ item: BuildItems.Destroyer, icon: destroyerIcon },
|
||||
@@ -27,6 +27,7 @@ const buildTable: BuildItem[][] = [
|
||||
export class BuildMenu extends LitElement {
|
||||
public game: Game;
|
||||
public eventBus: EventBus;
|
||||
public buildValidator: BuildValidator;
|
||||
|
||||
private myPlayer: Player;
|
||||
private clickedCell: Cell;
|
||||
@@ -145,19 +146,14 @@ export class BuildMenu extends LitElement {
|
||||
@state()
|
||||
private _hidden = true;
|
||||
|
||||
private canBuild(item: BuildItem): boolean {
|
||||
if (!this.myPlayer || this.myPlayer.gold() < item.item.cost) {
|
||||
private canBuild(item: BuildItemDisplay): boolean {
|
||||
if(this.myPlayer == null) {
|
||||
return false
|
||||
}
|
||||
switch (item.item) {
|
||||
case BuildItems.Destroyer:
|
||||
return this.myPlayer.units(UnitType.Port).length > 0
|
||||
default:
|
||||
return true
|
||||
}
|
||||
return this.buildValidator.canBuild(this.myPlayer, this.game.tile(this.clickedCell), item.item)
|
||||
}
|
||||
|
||||
public onBuildSelected = (item: BuildItem) => {
|
||||
public onBuildSelected = (item: BuildItemDisplay) => {
|
||||
switch (item.item) {
|
||||
case BuildItems.Nuke:
|
||||
this.eventBus.emit(new SendNukeIntentEvent(this.myPlayer, this.clickedCell, null))
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { AllPlayers, Cell, Execution, MutableGame, MutablePlayer, PlayerID, UnitType } from "../game/Game";
|
||||
import { BuildValidator } from "../game/BuildValidator";
|
||||
import { AllPlayers, BuildItem, BuildItems, Cell, Execution, MutableGame, MutablePlayer, PlayerID, UnitType } from "../game/Game";
|
||||
import { bfs, dist, manhattanDist } from "../Util";
|
||||
|
||||
export class PortExecution implements Execution {
|
||||
|
||||
@@ -18,7 +20,23 @@ export class PortExecution implements Execution {
|
||||
}
|
||||
|
||||
tick(ticks: number): void {
|
||||
this.player.addUnit(UnitType.Port, 0, this.mg.tile(this.cell))
|
||||
const tile = this.mg.tile(this.cell)
|
||||
if (!new BuildValidator(this.mg).canBuild(this.player, tile, BuildItems.Port)) {
|
||||
console.warn(`player ${this.player} cannot build port at ${this.cell}`)
|
||||
this.active = false
|
||||
return
|
||||
}
|
||||
const spawns = Array.from(bfs(tile, dist(tile, 20)))
|
||||
.filter(t => t.isOceanShore() && t.owner() == this.player)
|
||||
.sort((a, b) => manhattanDist(a.cell(), tile.cell()) - manhattanDist(b.cell(), tile.cell()))
|
||||
|
||||
if (spawns.length == 0) {
|
||||
console.warn(`cannot find spawn for port`)
|
||||
this.active = false
|
||||
return
|
||||
}
|
||||
|
||||
this.player.addUnit(UnitType.Port, 0, spawns[0])
|
||||
this.active = false
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { bfs, dist, manhattanDist } from "../Util";
|
||||
import { BuildItem, BuildItems, Game, Player, Tile, UnitType } from "./Game";
|
||||
|
||||
export class BuildValidator {
|
||||
constructor(private game: Game) { }
|
||||
|
||||
canBuild(player: Player, tile: Tile, item: BuildItem): boolean {
|
||||
if (!player.isAlive() || player.gold() < item.cost) {
|
||||
return false
|
||||
}
|
||||
switch (item) {
|
||||
case BuildItems.Nuke:
|
||||
return true
|
||||
case BuildItems.Port:
|
||||
return this.canBuildPort(player, tile)
|
||||
case BuildItems.Destroyer:
|
||||
return this.canBuildDestroyer(player, tile)
|
||||
default:
|
||||
throw Error(`item ${item.type} not supported`)
|
||||
}
|
||||
}
|
||||
|
||||
canBuildPort(player: Player, tile: Tile): boolean {
|
||||
return Array.from(bfs(tile, dist(tile, 20)))
|
||||
.filter(t => t.owner() == player && t.isOceanShore()).length > 0
|
||||
|
||||
}
|
||||
|
||||
canBuildDestroyer(player: Player, tile: Tile): boolean {
|
||||
return player.units(UnitType.Port)
|
||||
.filter(u => manhattanDist(u.tile().cell(), tile.cell()) < this.game.config().boatMaxDistance()).length > 0
|
||||
}
|
||||
}
|
||||
@@ -32,16 +32,17 @@ export enum UnitType {
|
||||
Nuke = "Nuke",
|
||||
}
|
||||
|
||||
export class Item {
|
||||
constructor(public readonly type: UnitType,
|
||||
export class BuildItem {
|
||||
constructor(
|
||||
public readonly type: UnitType,
|
||||
public readonly cost: Gold
|
||||
) { }
|
||||
}
|
||||
|
||||
export const BuildItems = {
|
||||
Nuke: new Item(UnitType.Nuke, 1_000_000),
|
||||
Destroyer: new Item(UnitType.Destroyer, 10),
|
||||
Port: new Item(UnitType.Port, 0)
|
||||
Nuke: new BuildItem(UnitType.Nuke, 1_000_000),
|
||||
Destroyer: new BuildItem(UnitType.Destroyer, 10),
|
||||
Port: new BuildItem(UnitType.Port, 0)
|
||||
} as const;
|
||||
|
||||
export class Nation {
|
||||
|
||||
Reference in New Issue
Block a user