create territoryBound, have player execution check units for capture

fix bug where PortExecution tries to get random element from empty list and crashes
This commit is contained in:
evanpelle
2024-11-17 19:56:54 -08:00
parent 371a33b406
commit 108fad8096
7 changed files with 50 additions and 25 deletions
+11 -5
View File
@@ -12,26 +12,32 @@ export class DefaultConfig implements Config {
case UnitType.TransportShip:
return {
cost: 0,
territoryBound: false
}
case UnitType.Destroyer:
return {
cost: 100_000
cost: 100_000,
territoryBound: false
}
case UnitType.Port:
return {
cost: 300_000
cost: 300_000,
territoryBound: true
}
case UnitType.Nuke:
return {
cost: 1_000_000
cost: 1_000_000,
territoryBound: false
}
case UnitType.TradeShip:
return {
cost: 0
cost: 0,
territoryBound: false
}
case UnitType.MissileSilo:
return {
cost: 1_000_000
cost: 1_000_000,
territoryBound: true
}
default:
assertNever(type)
@@ -34,10 +34,6 @@ export class MissileSiloExecution implements Execution {
this.active = false
return
}
if (this.silo.tile().owner() != this.silo.owner()) {
this.silo.setOwner(this.silo.tile().owner() as Player)
this.player = this.silo.owner()
}
}
owner(): MutablePlayer {
+15
View File
@@ -46,6 +46,21 @@ export class PlayerExecution implements Execution {
}
}
this.player.units().forEach(u => {
const tileOwner = u.tile().owner()
if (u.info().territoryBound) {
if (tileOwner.isPlayer()) {
if (tileOwner != this.player) {
this.mg.player(tileOwner.id()).captureUnit(u)
}
} else {
u.delete()
}
}
})
if (ticks - this.lastCalc > this.ticksPerClusterCalc) {
this.lastCalc = ticks
const start = performance.now()
+1 -12
View File
@@ -46,17 +46,6 @@ export class PortExecution implements Execution {
this.port = this.player.buildUnit(UnitType.Port, 0, spawns[0])
}
if (!this.port.tile().hasOwner()) {
this.port.delete()
this.active = false
return
}
if (this.port.tile().owner() != this.port.owner()) {
this.port.setOwner(this.port.tile().owner() as Player)
this.player = this.port.owner()
}
const allPorts = this.mg.units(UnitType.Port)
.filter(u => u.owner() != this.player)
if (allPorts.length == 0) {
@@ -82,7 +71,7 @@ export class PortExecution implements Execution {
}
}
if (this.random.chance(50)) {
if (this.portPaths.size > 0 && this.random.chance(50)) {
const port = this.random.randElement(
Array.from(this.portPaths.keys())
.filter(p => this.port.owner().isAlliedWith(p.owner()))
+4 -1
View File
@@ -24,6 +24,8 @@ export enum GameMap {
export interface UnitInfo {
cost: Gold
// Determines if its owner changes when its tile is conquered.
territoryBound: boolean
}
export enum UnitType {
@@ -155,6 +157,7 @@ export interface Unit {
tile(): Tile
owner(): Player
isActive(): boolean
info(): UnitInfo
}
export interface MutableUnit extends Unit {
@@ -162,7 +165,6 @@ export interface MutableUnit extends Unit {
owner(): MutablePlayer
setTroops(troops: number): void
delete(): void
setOwner(newOwner: Player): void
}
export interface TerraNullius {
@@ -247,6 +249,7 @@ export interface MutablePlayer extends Player {
removeTroops(troops: number): number
buildUnit(type: UnitType, troops: number, tile: Tile): MutableUnit
captureUnit(unit: MutableUnit): void
}
export interface Game {
+13 -1
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 } 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 } from "./Game";
import { ClientID } from "../Schemas";
import { assertNever, bfs, closestOceanShoreFromPlayer, dist, distSortUnit, manhattanDist, manhattanDistWrapped, processName, simpleHash, sourceDstOceanShore } from "../Util";
import { CellString, GameImpl } from "./GameImpl";
@@ -81,6 +81,7 @@ export class PlayerImpl implements MutablePlayer {
return this._units.filter(u => ts.has(u.type()));
}
sharesBorderWith(other: Player | TerraNullius): boolean {
for (const border of this._borderTiles) {
for (const neighbor of border.neighbors()) {
@@ -319,6 +320,16 @@ export class PlayerImpl implements MutablePlayer {
return toRemove
}
captureUnit(unit: MutableUnit): void {
if (unit.owner() == this) {
throw new Error(`Cannot capture unit, ${this} already owns ${unit}`)
}
const prev = unit.owner();
(prev as PlayerImpl)._units = (prev as PlayerImpl)._units.filter(u => u != unit);
(unit as UnitImpl)._owner = this
this._units.push(unit as UnitImpl)
}
buildUnit(type: UnitType, troops: number, spawnTile: Tile): UnitImpl {
const b = new UnitImpl(type, this.gs, spawnTile, troops, this);
this._units.push(b);
@@ -328,6 +339,7 @@ export class PlayerImpl implements MutablePlayer {
return b;
}
canBuild(unitType: UnitType, targetTile: Tile): Tile | false {
const cost = this.gs.unitInfo(unitType).cost
if (!this.isAlive() || this.gold() < cost) {
+6 -2
View File
@@ -1,4 +1,4 @@
import { MutableUnit, Tile, TerraNullius, UnitType, Player } from "./Game";
import { MutableUnit, Tile, TerraNullius, UnitType, Player, UnitInfo } from "./Game";
import { GameImpl } from "./GameImpl";
import { PlayerImpl } from "./PlayerImpl";
import { TerraNulliusImpl } from "./TerraNulliusImpl";
@@ -12,7 +12,7 @@ export class UnitImpl implements MutableUnit {
private g: GameImpl,
private _tile: Tile,
private _troops: number,
private _owner: PlayerImpl,
public _owner: PlayerImpl,
) { }
type(): UnitType {
@@ -37,6 +37,10 @@ export class UnitImpl implements MutableUnit {
return this._owner;
}
info(): UnitInfo {
return this.g.unitInfo(this._type)
}
setOwner(newOwner: Player): void {
this._owner = newOwner as PlayerImpl
this.g.fireUnitUpdateEvent(this, this.tile())