From 55206ca41fc2f55f94be8f4988d35df269419bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Joly?= Date: Fri, 6 Jun 2025 20:58:15 +0200 Subject: [PATCH] [Cleanup] Pass Player into execution constructor instead of PlayerID (#1022) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description: Answering issue: #1017 [Cleanup] Pass Player into the execution constructor instead of PlayerID I have tested the changes running and playing a full game. I do not know other way to test the changes, please inform me ❤️ ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: Lele --------- Co-authored-by: lva --- src/core/execution/AttackExecution.ts | 9 +--- src/core/execution/BoatRetreatExecution.ts | 23 ++-------- src/core/execution/CityExecution.ts | 10 +---- src/core/execution/ConstructionExecution.ts | 24 ++++------ src/core/execution/DefensePostExecution.ts | 10 +---- src/core/execution/DonateGoldExecution.ts | 10 +---- src/core/execution/DonateTroopExecution.ts | 10 +---- src/core/execution/EmbargoExecution.ts | 5 --- src/core/execution/EmojiExecution.ts | 9 +--- src/core/execution/ExecutionManager.ts | 30 ++++++------- src/core/execution/FakeHumanExecution.ts | 20 +++------ src/core/execution/MIRVExecution.ts | 16 ++----- src/core/execution/MissileSiloExecution.ts | 16 +------ src/core/execution/NukeExecution.ts | 45 +++++-------------- src/core/execution/PlayerExecution.ts | 35 ++------------- src/core/execution/PortExecution.ts | 40 +++++------------ src/core/execution/QuickChatExecution.ts | 10 +---- src/core/execution/RetreatExecution.ts | 11 +---- src/core/execution/SAMLauncherExecution.ts | 10 +---- .../execution/SetTargetTroopRatioExecution.ts | 15 ++----- src/core/execution/SpawnExecution.ts | 2 +- src/core/execution/TargetPlayerExecution.ts | 11 +---- src/core/execution/TradeShipExecution.ts | 5 +-- src/core/execution/TransportShipExecution.ts | 16 ++----- .../alliance/AllianceRequestExecution.ts | 13 +----- .../alliance/AllianceRequestReplyExecution.ts | 13 +----- .../alliance/BreakAllianceExecution.ts | 11 +---- src/core/execution/utils/BotBehavior.ts | 4 +- tests/Attack.test.ts | 20 ++++++--- tests/MissileSilo.test.ts | 4 +- tests/SAM.test.ts | 18 ++++---- tests/util/utils.ts | 6 +-- 32 files changed, 120 insertions(+), 361 deletions(-) diff --git a/src/core/execution/AttackExecution.ts b/src/core/execution/AttackExecution.ts index 42d361736..6c765a63c 100644 --- a/src/core/execution/AttackExecution.ts +++ b/src/core/execution/AttackExecution.ts @@ -22,7 +22,6 @@ export class AttackExecution implements Execution { private random = new PseudoRandom(123); - private _owner: Player; private target: Player | TerraNullius; private mg: Game; @@ -31,7 +30,7 @@ export class AttackExecution implements Execution { constructor( private startTroops: number | null = null, - private _ownerID: PlayerID, + private _owner: Player, private _targetID: PlayerID | null, private sourceTile: TileRef | null = null, private removeTroops: boolean = true, @@ -51,18 +50,12 @@ export class AttackExecution implements Execution { } this.mg = mg; - if (!mg.hasPlayer(this._ownerID)) { - console.warn(`player ${this._ownerID} not found`); - this.active = false; - return; - } if (this._targetID !== null && !mg.hasPlayer(this._targetID)) { console.warn(`target ${this._targetID} not found`); this.active = false; return; } - this._owner = mg.player(this._ownerID); this.target = this._targetID === this.mg.terraNullius().id() ? mg.terraNullius() diff --git a/src/core/execution/BoatRetreatExecution.ts b/src/core/execution/BoatRetreatExecution.ts index c5c597639..c6afedff1 100644 --- a/src/core/execution/BoatRetreatExecution.ts +++ b/src/core/execution/BoatRetreatExecution.ts @@ -1,29 +1,15 @@ -import { Execution, Game, Player, PlayerID, UnitType } from "../game/Game"; +import { Execution, Game, Player, UnitType } from "../game/Game"; export class BoatRetreatExecution implements Execution { private active = true; - private player: Player | undefined; constructor( - private playerID: PlayerID, + private player: Player, private unitID: number, ) {} - init(mg: Game, ticks: number): void { - if (!mg.hasPlayer(this.playerID)) { - console.warn(`BoatRetreatExecution: Player ${this.playerID} not found`); - this.active = false; - return; - } - this.player = mg.player(this.playerID); - } + init(mg: Game, ticks: number): void {} tick(ticks: number): void { - if (!this.player) { - console.warn(`BoatRetreatExecution: Player ${this.playerID} not found`); - this.active = false; - return; - } - const unit = this.player .units() .find( @@ -42,9 +28,6 @@ export class BoatRetreatExecution implements Execution { } owner(): Player { - if (this.player === undefined) { - throw new Error("Not initialized"); - } return this.player; } diff --git a/src/core/execution/CityExecution.ts b/src/core/execution/CityExecution.ts index d488df6e3..706adfb21 100644 --- a/src/core/execution/CityExecution.ts +++ b/src/core/execution/CityExecution.ts @@ -2,31 +2,23 @@ import { Execution, Game, Player, - PlayerID, Unit, UnitType, } from "../game/Game"; import { TileRef } from "../game/GameMap"; export class CityExecution implements Execution { - private player: Player; private mg: Game; private city: Unit | null = null; private active: boolean = true; constructor( - private ownerId: PlayerID, + private player: Player, private tile: TileRef, ) {} init(mg: Game, ticks: number): void { this.mg = mg; - if (!mg.hasPlayer(this.ownerId)) { - console.warn(`CityExecution: player ${this.ownerId} not found`); - this.active = false; - return; - } - this.player = mg.player(this.ownerId); } tick(ticks: number): void { diff --git a/src/core/execution/ConstructionExecution.ts b/src/core/execution/ConstructionExecution.ts index aa190bad2..10d31ddd2 100644 --- a/src/core/execution/ConstructionExecution.ts +++ b/src/core/execution/ConstructionExecution.ts @@ -3,7 +3,6 @@ import { Game, Gold, Player, - PlayerID, Tick, Unit, UnitType, @@ -19,7 +18,6 @@ import { SAMLauncherExecution } from "./SAMLauncherExecution"; import { WarshipExecution } from "./WarshipExecution"; export class ConstructionExecution implements Execution { - private player: Player; private construction: Unit | null = null; private active: boolean = true; private mg: Game; @@ -29,19 +27,13 @@ export class ConstructionExecution implements Execution { private cost: Gold; constructor( - private ownerId: PlayerID, + private player: Player, private tile: TileRef, private constructionType: UnitType, ) {} init(mg: Game, ticks: number): void { this.mg = mg; - if (!mg.hasPlayer(this.ownerId)) { - console.warn(`ConstructionExecution: owner ${this.ownerId} not found`); - this.active = false; - return; - } - this.player = mg.player(this.ownerId); } tick(ticks: number): void { @@ -97,11 +89,11 @@ export class ConstructionExecution implements Execution { case UnitType.AtomBomb: case UnitType.HydrogenBomb: this.mg.addExecution( - new NukeExecution(this.constructionType, player.id(), this.tile), + new NukeExecution(this.constructionType, player, this.tile), ); break; case UnitType.MIRV: - this.mg.addExecution(new MirvExecution(player.id(), this.tile)); + this.mg.addExecution(new MirvExecution(player, this.tile)); break; case UnitType.Warship: this.mg.addExecution( @@ -109,19 +101,19 @@ export class ConstructionExecution implements Execution { ); break; case UnitType.Port: - this.mg.addExecution(new PortExecution(player.id(), this.tile)); + this.mg.addExecution(new PortExecution(player, this.tile)); break; case UnitType.MissileSilo: - this.mg.addExecution(new MissileSiloExecution(player.id(), this.tile)); + this.mg.addExecution(new MissileSiloExecution(player, this.tile)); break; case UnitType.DefensePost: - this.mg.addExecution(new DefensePostExecution(player.id(), this.tile)); + this.mg.addExecution(new DefensePostExecution(player, this.tile)); break; case UnitType.SAMLauncher: - this.mg.addExecution(new SAMLauncherExecution(player.id(), this.tile)); + this.mg.addExecution(new SAMLauncherExecution(player, this.tile)); break; case UnitType.City: - this.mg.addExecution(new CityExecution(player.id(), this.tile)); + this.mg.addExecution(new CityExecution(player, this.tile)); break; default: throw Error(`unit type ${this.constructionType} not supported`); diff --git a/src/core/execution/DefensePostExecution.ts b/src/core/execution/DefensePostExecution.ts index 2ec384cb8..098b52aac 100644 --- a/src/core/execution/DefensePostExecution.ts +++ b/src/core/execution/DefensePostExecution.ts @@ -2,7 +2,6 @@ import { Execution, Game, Player, - PlayerID, Unit, UnitType, } from "../game/Game"; @@ -10,7 +9,6 @@ import { TileRef } from "../game/GameMap"; import { ShellExecution } from "./ShellExecution"; export class DefensePostExecution implements Execution { - private player: Player; private mg: Game; private post: Unit | null = null; private active: boolean = true; @@ -21,18 +19,12 @@ export class DefensePostExecution implements Execution { private alreadySentShell = new Set(); constructor( - private ownerId: PlayerID, + private player: Player, private tile: TileRef, ) {} init(mg: Game, ticks: number): void { this.mg = mg; - if (!mg.hasPlayer(this.ownerId)) { - console.warn(`DefensePostExectuion: owner ${this.ownerId} not found`); - this.active = false; - return; - } - this.player = mg.player(this.ownerId); } private shoot() { diff --git a/src/core/execution/DonateGoldExecution.ts b/src/core/execution/DonateGoldExecution.ts index 672c5861d..dfdb53622 100644 --- a/src/core/execution/DonateGoldExecution.ts +++ b/src/core/execution/DonateGoldExecution.ts @@ -1,30 +1,24 @@ import { Execution, Game, Gold, Player, PlayerID } from "../game/Game"; export class DonateGoldExecution implements Execution { - private sender: Player; + private recipient: Player; private active = true; constructor( - private senderID: PlayerID, + private sender: Player, private recipientID: PlayerID, private gold: Gold | null, ) {} init(mg: Game, ticks: number): void { - if (!mg.hasPlayer(this.senderID)) { - console.warn(`DonateExecution: sender ${this.senderID} not found`); - this.active = false; - return; - } if (!mg.hasPlayer(this.recipientID)) { console.warn(`DonateExecution recipient ${this.recipientID} not found`); this.active = false; return; } - this.sender = mg.player(this.senderID); this.recipient = mg.player(this.recipientID); if (this.gold === null) { this.gold = this.sender.gold() / 3n; diff --git a/src/core/execution/DonateTroopExecution.ts b/src/core/execution/DonateTroopExecution.ts index dd05689da..ea20a2b9c 100644 --- a/src/core/execution/DonateTroopExecution.ts +++ b/src/core/execution/DonateTroopExecution.ts @@ -1,30 +1,24 @@ import { Execution, Game, Player, PlayerID } from "../game/Game"; export class DonateTroopsExecution implements Execution { - private sender: Player; + private recipient: Player; private active = true; constructor( - private senderID: PlayerID, + private sender: Player, private recipientID: PlayerID, private troops: number | null, ) {} init(mg: Game, ticks: number): void { - if (!mg.hasPlayer(this.senderID)) { - console.warn(`DonateExecution: sender ${this.senderID} not found`); - this.active = false; - return; - } if (!mg.hasPlayer(this.recipientID)) { console.warn(`DonateExecution recipient ${this.recipientID} not found`); this.active = false; return; } - this.sender = mg.player(this.senderID); this.recipient = mg.player(this.recipientID); if (this.troops === null) { this.troops = mg.config().defaultDonationAmount(this.sender); diff --git a/src/core/execution/EmbargoExecution.ts b/src/core/execution/EmbargoExecution.ts index 79e4b8773..67a0664d1 100644 --- a/src/core/execution/EmbargoExecution.ts +++ b/src/core/execution/EmbargoExecution.ts @@ -10,11 +10,6 @@ export class EmbargoExecution implements Execution { ) {} init(mg: Game, _: number): void { - if (!mg.hasPlayer(this.player.id())) { - console.warn(`EmbargoExecution: sender ${this.player.id()} not found`); - this.active = false; - return; - } if (!mg.hasPlayer(this.targetID)) { console.warn(`EmbargoExecution recipient ${this.targetID} not found`); this.active = false; diff --git a/src/core/execution/EmojiExecution.ts b/src/core/execution/EmojiExecution.ts index 068f11d89..94f84e58d 100644 --- a/src/core/execution/EmojiExecution.ts +++ b/src/core/execution/EmojiExecution.ts @@ -9,30 +9,23 @@ import { import { flattenedEmojiTable } from "../Util"; export class EmojiExecution implements Execution { - private requestor: Player; private recipient: Player | typeof AllPlayers; private active = true; constructor( - private senderID: PlayerID, + private requestor: Player, private recipientID: PlayerID | typeof AllPlayers, private emoji: number, ) {} init(mg: Game, ticks: number): void { - if (!mg.hasPlayer(this.senderID)) { - console.warn(`EmojiExecution: sender ${this.senderID} not found`); - this.active = false; - return; - } if (this.recipientID !== AllPlayers && !mg.hasPlayer(this.recipientID)) { console.warn(`EmojiExecution: recipient ${this.recipientID} not found`); this.active = false; return; } - this.requestor = mg.player(this.senderID); this.recipient = this.recipientID === AllPlayers ? AllPlayers diff --git a/src/core/execution/ExecutionManager.ts b/src/core/execution/ExecutionManager.ts index 0cd160cb0..66d2fd0e8 100644 --- a/src/core/execution/ExecutionManager.ts +++ b/src/core/execution/ExecutionManager.ts @@ -47,21 +47,21 @@ export class Executor { console.warn(`player with clientID ${intent.clientID} not found`); return new NoOpExecution(); } - const playerID = player.id(); + // create execution switch (intent.type) { case "attack": { return new AttackExecution( intent.troops, - playerID, + player, intent.targetID, null, ); } case "cancel_attack": - return new RetreatExecution(playerID, intent.attackID); + return new RetreatExecution(player, intent.attackID); case "cancel_boat": - return new BoatRetreatExecution(playerID, intent.unitID); + return new BoatRetreatExecution(player, intent.unitID); case "move_warship": return new MoveWarshipExecution(player, intent.unitId, intent.tile); case "spawn": @@ -75,47 +75,47 @@ export class Executor { src = this.mg.ref(intent.srcX, intent.srcY); } return new TransportShipExecution( - playerID, + player, intent.targetID, this.mg.ref(intent.dstX, intent.dstY), intent.troops, src, ); case "allianceRequest": - return new AllianceRequestExecution(playerID, intent.recipient); + return new AllianceRequestExecution(player, intent.recipient); case "allianceRequestReply": return new AllianceRequestReplyExecution( intent.requestor, - playerID, + player, intent.accept, ); case "breakAlliance": - return new BreakAllianceExecution(playerID, intent.recipient); + return new BreakAllianceExecution(player, intent.recipient); case "targetPlayer": - return new TargetPlayerExecution(playerID, intent.target); + return new TargetPlayerExecution(player, intent.target); case "emoji": - return new EmojiExecution(playerID, intent.recipient, intent.emoji); + return new EmojiExecution(player, intent.recipient, intent.emoji); case "donate_troops": return new DonateTroopsExecution( - playerID, + player, intent.recipient, intent.troops, ); case "donate_gold": - return new DonateGoldExecution(playerID, intent.recipient, intent.gold); + return new DonateGoldExecution(player, intent.recipient, intent.gold); case "troop_ratio": - return new SetTargetTroopRatioExecution(playerID, intent.ratio); + return new SetTargetTroopRatioExecution(player, intent.ratio); case "embargo": return new EmbargoExecution(player, intent.targetID, intent.action); case "build_unit": return new ConstructionExecution( - playerID, + player, this.mg.ref(intent.x, intent.y), intent.unit, ); case "quick_chat": return new QuickChatExecution( - playerID, + player, intent.recipient, intent.quickChatKey, intent.variables ?? {}, diff --git a/src/core/execution/FakeHumanExecution.ts b/src/core/execution/FakeHumanExecution.ts index 7f4d5c024..8c03a4d49 100644 --- a/src/core/execution/FakeHumanExecution.ts +++ b/src/core/execution/FakeHumanExecution.ts @@ -282,7 +282,7 @@ export class FakeHumanExecution implements Execution { this.lastEmojiSent.set(enemy, this.mg.ticks()); this.mg.addExecution( new EmojiExecution( - this.player.id(), + this.player, enemy.id(), this.random.randElement(this.heckleEmoji), ), @@ -354,7 +354,7 @@ export class FakeHumanExecution implements Execution { const tick = this.mg.ticks(); this.lastNukeSent.push([tick, tile]); this.mg.addExecution( - new NukeExecution(UnitType.AtomBomb, this.player.id(), tile), + new NukeExecution(UnitType.AtomBomb, this.player, tile), ); } @@ -421,7 +421,7 @@ export class FakeHumanExecution implements Execution { } this.mg.addExecution( new TransportShipExecution( - this.player.id(), + this.player, other.id(), closest.y, this.player.troops() / 5, @@ -441,7 +441,7 @@ export class FakeHumanExecution implements Execution { if (oceanTiles.length > 0) { const buildTile = this.random.randElement(oceanTiles); this.mg.addExecution( - new ConstructionExecution(player.id(), buildTile, UnitType.Port), + new ConstructionExecution(player, buildTile, UnitType.Port), ); } return; @@ -470,9 +470,7 @@ export class FakeHumanExecution implements Execution { if (canBuild === false) { return; } - this.mg.addExecution( - new ConstructionExecution(this.player.id(), tile, type), - ); + this.mg.addExecution(new ConstructionExecution(this.player, tile, type)); } private maybeSpawnWarship(): boolean { @@ -498,11 +496,7 @@ export class FakeHumanExecution implements Execution { return false; } this.mg.addExecution( - new ConstructionExecution( - this.player.id(), - targetTile, - UnitType.Warship, - ), + new ConstructionExecution(this.player, targetTile, UnitType.Warship), ); return true; } @@ -573,7 +567,7 @@ export class FakeHumanExecution implements Execution { this.mg.addExecution( new TransportShipExecution( - this.player.id(), + this.player, this.mg.owner(dst).id(), dst, this.player.troops() / 5, diff --git a/src/core/execution/MIRVExecution.ts b/src/core/execution/MIRVExecution.ts index 9b0e8e511..18411e80d 100644 --- a/src/core/execution/MIRVExecution.ts +++ b/src/core/execution/MIRVExecution.ts @@ -3,7 +3,6 @@ import { Game, MessageType, Player, - PlayerID, TerraNullius, Unit, UnitType, @@ -15,8 +14,6 @@ import { simpleHash } from "../Util"; import { NukeExecution } from "./NukeExecution"; export class MirvExecution implements Execution { - private player: Player; - private active = true; private mg: Game; @@ -37,21 +34,14 @@ export class MirvExecution implements Execution { private speed: number = -1; constructor( - private senderID: PlayerID, + private player: Player, private dst: TileRef, ) {} init(mg: Game, ticks: number): void { - if (!mg.hasPlayer(this.senderID)) { - console.warn(`MIRVExecution: player ${this.senderID} not found`); - this.active = false; - return; - } - - this.random = new PseudoRandom(mg.ticks() + simpleHash(this.senderID)); + this.random = new PseudoRandom(mg.ticks() + simpleHash(this.player.id())); this.mg = mg; this.pathFinder = new ParabolaPathFinder(mg); - this.player = mg.player(this.senderID); this.targetPlayer = this.mg.owner(this.dst); this.speed = this.mg.config().defaultNukeSpeed(); @@ -118,7 +108,7 @@ export class MirvExecution implements Execution { this.mg.addExecution( new NukeExecution( UnitType.MIRVWarhead, - this.senderID, + this.player, dst, this.nuke.tile(), 15 + Math.floor((i / this.warheadCount) * 5), diff --git a/src/core/execution/MissileSiloExecution.ts b/src/core/execution/MissileSiloExecution.ts index b0c404405..cadb4c8dc 100644 --- a/src/core/execution/MissileSiloExecution.ts +++ b/src/core/execution/MissileSiloExecution.ts @@ -2,7 +2,6 @@ import { Execution, Game, Player, - PlayerID, Unit, UnitType, } from "../game/Game"; @@ -10,30 +9,19 @@ import { TileRef } from "../game/GameMap"; export class MissileSiloExecution implements Execution { private active = true; - private mg: Game | null = null; - private player: Player | null = null; + private mg: Game; private silo: Unit | null = null; constructor( - private _owner: PlayerID, + private player: Player, private tile: TileRef, ) {} init(mg: Game, ticks: number): void { - if (!mg.hasPlayer(this._owner)) { - console.warn(`MissileSiloExecution: owner ${this._owner} not found`); - this.active = false; - return; - } - this.mg = mg; - this.player = mg.player(this._owner); } tick(ticks: number): void { - if (this.player === null || this.mg === null) { - throw new Error("Not initialized"); - } if (this.silo === null) { const spawn = this.player.canBuild(UnitType.MissileSilo, this.tile); if (spawn === false) { diff --git a/src/core/execution/NukeExecution.ts b/src/core/execution/NukeExecution.ts index 83955ded0..91ed7d725 100644 --- a/src/core/execution/NukeExecution.ts +++ b/src/core/execution/NukeExecution.ts @@ -3,7 +3,6 @@ import { Game, MessageType, Player, - PlayerID, TerraNullius, Unit, UnitType, @@ -15,8 +14,7 @@ import { NukeType } from "../StatsSchemas"; export class NukeExecution implements Execution { private active = true; - private player: Player | null = null; - private mg: Game | null = null; + private mg: Game; private nuke: Unit | null = null; private tilesToDestroyCache: Set | undefined; @@ -24,8 +22,8 @@ export class NukeExecution implements Execution { private pathFinder: ParabolaPathFinder; constructor( - private type: NukeType, - private senderID: PlayerID, + private nukeType: NukeType, + private player: Player, private dst: TileRef, private src?: TileRef | null, private speed: number = -1, @@ -33,14 +31,7 @@ export class NukeExecution implements Execution { ) {} init(mg: Game, ticks: number): void { - if (!mg.hasPlayer(this.senderID)) { - console.warn(`NukeExecution: sender ${this.senderID} not found`); - this.active = false; - return; - } - this.mg = mg; - this.player = mg.player(this.senderID); this.random = new PseudoRandom(ticks); if (this.speed === -1) { this.speed = this.mg.config().defaultNukeSpeed(); @@ -49,9 +40,6 @@ export class NukeExecution implements Execution { } public target(): Player | TerraNullius { - if (this.mg === null) { - throw new Error("Not initialized"); - } return this.mg.owner(this.dst); } @@ -59,7 +47,7 @@ export class NukeExecution implements Execution { if (this.tilesToDestroyCache !== undefined) { return this.tilesToDestroyCache; } - if (this.mg === null || this.nuke === null) { + if (this.nuke === null) { throw new Error("Not initialized"); } const magnitude = this.mg.config().nukeMagnitudes(this.nuke.type()); @@ -74,7 +62,7 @@ export class NukeExecution implements Execution { } private breakAlliances(toDestroy: Set) { - if (this.mg === null || this.player === null || this.nuke === null) { + if (this.nuke === null) { throw new Error("Not initialized"); } const attacked = new Map(); @@ -101,12 +89,8 @@ export class NukeExecution implements Execution { } tick(ticks: number): void { - if (this.mg === null || this.player === null) { - throw new Error("Not initialized"); - } - if (this.nuke === null) { - const spawn = this.src ?? this.player.canBuild(this.type, this.dst); + const spawn = this.src ?? this.player.canBuild(this.nukeType, this.dst); if (spawn === false) { console.warn(`cannot build Nuke`); this.active = false; @@ -115,16 +99,16 @@ export class NukeExecution implements Execution { this.pathFinder.computeControlPoints( spawn, this.dst, - this.type !== UnitType.MIRVWarhead, + this.nukeType !== UnitType.MIRVWarhead, ); - this.nuke = this.player.buildUnit(this.type, spawn, { + this.nuke = this.player.buildUnit(this.nukeType, spawn, { targetTile: this.dst, }); if (this.mg.hasOwner(this.dst)) { const target = this.mg.owner(this.dst); if (!target.isPlayer()) { // Ignore terra nullius - } else if (this.type === UnitType.AtomBomb) { + } else if (this.nukeType === UnitType.AtomBomb) { this.mg.displayIncomingUnit( this.nuke.id(), `${this.player.name()} - atom bomb inbound`, @@ -132,7 +116,7 @@ export class NukeExecution implements Execution { target.id(), ); this.breakAlliances(this.tilesToDestroy()); - } else if (this.type === UnitType.HydrogenBomb) { + } else if (this.nukeType === UnitType.HydrogenBomb) { this.mg.displayIncomingUnit( this.nuke.id(), `${this.player.name()} - hydrogen bomb inbound`, @@ -143,9 +127,7 @@ export class NukeExecution implements Execution { } // Record stats - this.mg - .stats() - .bombLaunch(this.player, target, this.nuke.type() as NukeType); + this.mg.stats().bombLaunch(this.player, target, this.nukeType); } // after sending a nuke set the missilesilo on cooldown @@ -181,7 +163,7 @@ export class NukeExecution implements Execution { } private detonate() { - if (this.mg === null || this.nuke === null || this.player === null) { + if (this.nuke === null) { throw new Error("Not initialized"); } @@ -248,9 +230,6 @@ export class NukeExecution implements Execution { } owner(): Player { - if (this.player === null) { - throw new Error("Not initialized"); - } return this.player; } diff --git a/src/core/execution/PlayerExecution.ts b/src/core/execution/PlayerExecution.ts index 276be4890..44f69354d 100644 --- a/src/core/execution/PlayerExecution.ts +++ b/src/core/execution/PlayerExecution.ts @@ -5,7 +5,6 @@ import { Game, MessageType, Player, - PlayerID, UnitType, } from "../game/Game"; import { GameImpl } from "../game/GameImpl"; @@ -15,35 +14,25 @@ import { calculateBoundingBox, getMode, inscribed, simpleHash } from "../Util"; export class PlayerExecution implements Execution { private readonly ticksPerClusterCalc = 20; - private player: Player | null = null; - private config: Config | null = null; + private config: Config; private lastCalc = 0; - private mg: Game | null = null; + private mg: Game; private active = true; - constructor(private playerID: PlayerID) {} + constructor(private player: Player) {} activeDuringSpawnPhase(): boolean { return false; } init(mg: Game, ticks: number) { - if (!mg.hasPlayer(this.playerID)) { - console.warn(`PlayerExecution: player ${this.playerID} not found`); - this.active = false; - return; - } this.mg = mg; this.config = mg.config(); - this.player = mg.player(this.playerID); this.lastCalc = ticks + (simpleHash(this.player.name()) % this.ticksPerClusterCalc); } tick(ticks: number) { - if (this.mg === null || this.config === null || this.player === null) { - throw new Error("Not initialized"); - } this.player.decayRelations(); this.player.units().forEach((u) => { const tileOwner = this.mg!.owner(u.tile()); @@ -122,9 +111,6 @@ export class PlayerExecution implements Execution { } private removeClusters() { - if (this.mg === null || this.player === null) { - throw new Error("Not initialized"); - } const clusters = this.calculateClusters(); clusters.sort((a, b) => b.size - a.size); @@ -144,9 +130,6 @@ export class PlayerExecution implements Execution { } private surroundedBySamePlayer(cluster: Set): false | Player { - if (this.mg === null || this.player === null) { - throw new Error("Not initialized"); - } const enemies = new Set(); for (const tile of cluster) { const isOceanShore = this.mg.isOceanShore(tile); @@ -181,9 +164,6 @@ export class PlayerExecution implements Execution { } private isSurrounded(cluster: Set): boolean { - if (this.mg === null || this.player === null) { - throw new Error("Not initialized"); - } const enemyTiles = new Set(); for (const tr of cluster) { if (this.mg.isShore(tr) || this.mg.isOnEdgeOfMap(tr)) { @@ -207,9 +187,6 @@ export class PlayerExecution implements Execution { } private removeCluster(cluster: Set) { - if (this.mg === null || this.player === null) { - throw new Error("Not initialized"); - } if ( Array.from(cluster).some( (t) => this.mg?.ownerID(t) !== this.player?.smallID(), @@ -252,9 +229,6 @@ export class PlayerExecution implements Execution { } private getCapturingPlayer(cluster: Set): Player | null { - if (this.mg === null || this.player === null) { - throw new Error("Not initialized"); - } const neighborsIDs = new Set(); for (const t of cluster) { for (const neighbor of this.mg.neighbors(t)) { @@ -297,9 +271,6 @@ export class PlayerExecution implements Execution { } private calculateClusters(): Set[] { - if (this.mg === null || this.player === null) { - throw new Error("Not initialized"); - } const seen = new Set(); const border = this.player.borderTiles(); const clusters: Set[] = []; diff --git a/src/core/execution/PortExecution.ts b/src/core/execution/PortExecution.ts index d234a8de8..ef8769f71 100644 --- a/src/core/execution/PortExecution.ts +++ b/src/core/execution/PortExecution.ts @@ -1,11 +1,4 @@ -import { - Execution, - Game, - Player, - PlayerID, - Unit, - UnitType, -} from "../game/Game"; +import { Execution, Game, Player, Unit, UnitType } from "../game/Game"; import { TileRef } from "../game/GameMap"; import { PseudoRandom } from "../PseudoRandom"; import { TradeShipExecution } from "./TradeShipExecution"; @@ -18,16 +11,11 @@ export class PortExecution implements Execution { private checkOffset: number | null = null; constructor( - private _owner: PlayerID, + private player: Player, private tile: TileRef, ) {} init(mg: Game, ticks: number): void { - if (!mg.hasPlayer(this._owner)) { - console.warn(`PortExecution: player ${this._owner} not found`); - this.active = false; - return; - } this.mg = mg; this.random = new PseudoRandom(mg.ticks()); this.checkOffset = mg.ticks() % 10; @@ -39,14 +27,15 @@ export class PortExecution implements Execution { } if (this.port === null) { const tile = this.tile; - const player = this.mg.player(this._owner); - const spawn = player.canBuild(UnitType.Port, tile); + const spawn = this.player.canBuild(UnitType.Port, tile); if (spawn === false) { - console.warn(`player ${player} cannot build port at ${this.tile}`); + console.warn( + `player ${this.player.id()} cannot build port at ${this.tile}`, + ); this.active = false; return; } - this.port = player.buildUnit(UnitType.Port, spawn, {}); + this.port = this.player.buildUnit(UnitType.Port, spawn, {}); } if (!this.port.isActive()) { @@ -54,8 +43,8 @@ export class PortExecution implements Execution { return; } - if (this._owner !== this.port.owner().id()) { - this._owner = this.port.owner().id(); + if (this.player.id() !== this.port.owner().id()) { + this.player = this.port.owner(); } // Only check every 10 ticks for performance. @@ -70,7 +59,7 @@ export class PortExecution implements Execution { return; } - const ports = this.player().tradingPorts(this.port); + const ports = this.player.tradingPorts(this.port); if (ports.length === 0) { return; @@ -78,7 +67,7 @@ export class PortExecution implements Execution { const port = this.random.randElement(ports); this.mg.addExecution( - new TradeShipExecution(this.player().id(), this.port, port), + new TradeShipExecution(this.player, this.port, port), ); } @@ -89,11 +78,4 @@ export class PortExecution implements Execution { activeDuringSpawnPhase(): boolean { return false; } - - player(): Player { - if (this.port === null) { - throw new Error("Not initialized"); - } - return this.port.owner(); - } } diff --git a/src/core/execution/QuickChatExecution.ts b/src/core/execution/QuickChatExecution.ts index f9d4230bf..bf743ef46 100644 --- a/src/core/execution/QuickChatExecution.ts +++ b/src/core/execution/QuickChatExecution.ts @@ -1,14 +1,14 @@ import { Execution, Game, Player, PlayerID } from "../game/Game"; export class QuickChatExecution implements Execution { - private sender: Player; + private recipient: Player; private mg: Game; private active = true; constructor( - private senderID: PlayerID, + private sender: Player, private recipientID: PlayerID, private quickChatKey: string, private variables: Record, @@ -16,11 +16,6 @@ export class QuickChatExecution implements Execution { init(mg: Game, ticks: number): void { this.mg = mg; - if (!mg.hasPlayer(this.senderID)) { - console.warn(`QuickChatExecution: sender ${this.senderID} not found`); - this.active = false; - return; - } if (!mg.hasPlayer(this.recipientID)) { console.warn( `QuickChatExecution: recipient ${this.recipientID} not found`, @@ -29,7 +24,6 @@ export class QuickChatExecution implements Execution { return; } - this.sender = mg.player(this.senderID); this.recipient = mg.player(this.recipientID); } diff --git a/src/core/execution/RetreatExecution.ts b/src/core/execution/RetreatExecution.ts index c40929adc..3383aec4c 100644 --- a/src/core/execution/RetreatExecution.ts +++ b/src/core/execution/RetreatExecution.ts @@ -1,26 +1,19 @@ -import { Execution, Game, Player, PlayerID } from "../game/Game"; +import { Execution, Game, Player } from "../game/Game"; const cancelDelay = 20; export class RetreatExecution implements Execution { private active = true; private retreatOrdered = false; - private player: Player; private startTick: number; private mg: Game; constructor( - private playerID: PlayerID, + private player: Player, private attackID: string, ) {} init(mg: Game, ticks: number): void { - if (!mg.hasPlayer(this.playerID)) { - console.warn(`RetreatExecution: player ${this.playerID} not found`); - return; - } this.mg = mg; - - this.player = mg.player(this.playerID); this.startTick = mg.ticks(); } diff --git a/src/core/execution/SAMLauncherExecution.ts b/src/core/execution/SAMLauncherExecution.ts index d27737cc0..9fffdaab3 100644 --- a/src/core/execution/SAMLauncherExecution.ts +++ b/src/core/execution/SAMLauncherExecution.ts @@ -3,7 +3,6 @@ import { Game, MessageType, Player, - PlayerID, Unit, UnitType, } from "../game/Game"; @@ -12,7 +11,6 @@ import { PseudoRandom } from "../PseudoRandom"; import { SAMMissileExecution } from "./SAMMissileExecution"; export class SAMLauncherExecution implements Execution { - private player: Player; private mg: Game; private active: boolean = true; @@ -26,7 +24,7 @@ export class SAMLauncherExecution implements Execution { private pseudoRandom: PseudoRandom | undefined; constructor( - private ownerId: PlayerID, + private player: Player, private tile: TileRef | null, private sam: Unit | null = null, ) { @@ -37,12 +35,6 @@ export class SAMLauncherExecution implements Execution { init(mg: Game, ticks: number): void { this.mg = mg; - if (!mg.hasPlayer(this.ownerId)) { - console.warn(`SAMLauncherExecution: owner ${this.ownerId} not found`); - this.active = false; - return; - } - this.player = mg.player(this.ownerId); } private nukeTargetInRange(nuke: Unit) { diff --git a/src/core/execution/SetTargetTroopRatioExecution.ts b/src/core/execution/SetTargetTroopRatioExecution.ts index 9ad8e1380..d43834003 100644 --- a/src/core/execution/SetTargetTroopRatioExecution.ts +++ b/src/core/execution/SetTargetTroopRatioExecution.ts @@ -1,23 +1,14 @@ -import { Execution, Game, Player, PlayerID } from "../game/Game"; +import { Execution, Game, Player } from "../game/Game"; export class SetTargetTroopRatioExecution implements Execution { - private player: Player; - private active = true; constructor( - private playerID: PlayerID, + private player: Player, private targetTroopsRatio: number, ) {} - init(mg: Game, ticks: number): void { - if (!mg.hasPlayer(this.playerID)) { - console.warn( - `SetTargetTRoopRatioExecution: player ${this.playerID} not found`, - ); - } - this.player = mg.player(this.playerID); - } + init(mg: Game, ticks: number): void {} tick(ticks: number): void { if (this.targetTroopsRatio < 0 || this.targetTroopsRatio > 1) { diff --git a/src/core/execution/SpawnExecution.ts b/src/core/execution/SpawnExecution.ts index add0550a4..d6d45b3d4 100644 --- a/src/core/execution/SpawnExecution.ts +++ b/src/core/execution/SpawnExecution.ts @@ -38,7 +38,7 @@ export class SpawnExecution implements Execution { }); if (!player.hasSpawned()) { - this.mg.addExecution(new PlayerExecution(player.id())); + this.mg.addExecution(new PlayerExecution(player)); if (player.type() === PlayerType.Bot) { this.mg.addExecution(new BotExecution(player)); } diff --git a/src/core/execution/TargetPlayerExecution.ts b/src/core/execution/TargetPlayerExecution.ts index 8b22d2998..e6e454534 100644 --- a/src/core/execution/TargetPlayerExecution.ts +++ b/src/core/execution/TargetPlayerExecution.ts @@ -1,31 +1,22 @@ import { Execution, Game, Player, PlayerID } from "../game/Game"; export class TargetPlayerExecution implements Execution { - private requestor: Player; private target: Player; private active = true; constructor( - private requestorID: PlayerID, + private requestor: Player, private targetID: PlayerID, ) {} init(mg: Game, ticks: number): void { - if (!mg.hasPlayer(this.requestorID)) { - console.warn( - `TargetPlayerExecution: requestor ${this.requestorID} not found`, - ); - this.active = false; - return; - } if (!mg.hasPlayer(this.targetID)) { console.warn(`TargetPlayerExecution: target ${this.targetID} not found`); this.active = false; return; } - this.requestor = mg.player(this.requestorID); this.target = mg.player(this.targetID); } diff --git a/src/core/execution/TradeShipExecution.ts b/src/core/execution/TradeShipExecution.ts index 5e1fb10e9..2ae94dca1 100644 --- a/src/core/execution/TradeShipExecution.ts +++ b/src/core/execution/TradeShipExecution.ts @@ -4,7 +4,6 @@ import { Game, MessageType, Player, - PlayerID, Unit, UnitType, } from "../game/Game"; @@ -16,20 +15,18 @@ import { distSortUnit } from "../Util"; export class TradeShipExecution implements Execution { private active = true; private mg: Game; - private origOwner: Player; private tradeShip: Unit | undefined; private wasCaptured = false; private pathFinder: PathFinder; constructor( - private _owner: PlayerID, + private origOwner: Player, private srcPort: Unit, private _dstPort: Unit, ) {} init(mg: Game, ticks: number): void { this.mg = mg; - this.origOwner = mg.player(this._owner); this.pathFinder = PathFinder.Mini(mg, 2500); } diff --git a/src/core/execution/TransportShipExecution.ts b/src/core/execution/TransportShipExecution.ts index e7607cd05..78cc71c06 100644 --- a/src/core/execution/TransportShipExecution.ts +++ b/src/core/execution/TransportShipExecution.ts @@ -23,7 +23,6 @@ export class TransportShipExecution implements Execution { private active = true; private mg: Game; - private attacker: Player; private target: Player | TerraNullius; // TODO make private @@ -35,7 +34,7 @@ export class TransportShipExecution implements Execution { private pathFinder: PathFinder; constructor( - private attackerID: PlayerID, + private attacker: Player, private targetID: PlayerID | null, private ref: TileRef, private troops: number, @@ -47,13 +46,6 @@ export class TransportShipExecution implements Execution { } init(mg: Game, ticks: number) { - if (!mg.hasPlayer(this.attackerID)) { - console.warn( - `TransportShipExecution: attacker ${this.attackerID} not found`, - ); - this.active = false; - return; - } if (this.targetID !== null && !mg.hasPlayer(this.targetID)) { console.warn(`TransportShipExecution: target ${this.targetID} not found`); this.active = false; @@ -64,8 +56,6 @@ export class TransportShipExecution implements Execution { this.mg = mg; this.pathFinder = PathFinder.Mini(mg, 10_000, 10); - this.attacker = mg.player(this.attackerID); - if ( this.attacker.units(UnitType.TransportShip).length >= mg.config().boatMaxNumber() @@ -73,7 +63,7 @@ export class TransportShipExecution implements Execution { mg.displayMessage( `No boats available, max ${mg.config().boatMaxNumber()}`, MessageType.WARN, - this.attackerID, + this.attacker.id(), ); this.active = false; this.attacker.addTroops(this.troops); @@ -192,7 +182,7 @@ export class TransportShipExecution implements Execution { this.mg.addExecution( new AttackExecution( this.troops, - this.attacker.id(), + this.attacker, this.targetID, this.dst, false, diff --git a/src/core/execution/alliance/AllianceRequestExecution.ts b/src/core/execution/alliance/AllianceRequestExecution.ts index 0475d8f9f..419b8b92c 100644 --- a/src/core/execution/alliance/AllianceRequestExecution.ts +++ b/src/core/execution/alliance/AllianceRequestExecution.ts @@ -2,22 +2,14 @@ import { Execution, Game, Player, PlayerID } from "../../game/Game"; export class AllianceRequestExecution implements Execution { private active = true; - private requestor: Player | null = null; private recipient: Player | null = null; constructor( - private requestorID: PlayerID, + private requestor: Player, private recipientID: PlayerID, ) {} init(mg: Game, ticks: number): void { - if (!mg.hasPlayer(this.requestorID)) { - console.warn( - `AllianceRequestExecution requester ${this.requestorID} not found`, - ); - this.active = false; - return; - } if (!mg.hasPlayer(this.recipientID)) { console.warn( `AllianceRequestExecution recipient ${this.recipientID} not found`, @@ -26,12 +18,11 @@ export class AllianceRequestExecution implements Execution { return; } - this.requestor = mg.player(this.requestorID); this.recipient = mg.player(this.recipientID); } tick(ticks: number): void { - if (this.requestor === null || this.recipient === null) { + if (this.recipient === null) { throw new Error("Not initialized"); } if (this.requestor.isFriendly(this.recipient)) { diff --git a/src/core/execution/alliance/AllianceRequestReplyExecution.ts b/src/core/execution/alliance/AllianceRequestReplyExecution.ts index ed3177517..bd3d90a58 100644 --- a/src/core/execution/alliance/AllianceRequestReplyExecution.ts +++ b/src/core/execution/alliance/AllianceRequestReplyExecution.ts @@ -3,11 +3,10 @@ import { Execution, Game, Player, PlayerID } from "../../game/Game"; export class AllianceRequestReplyExecution implements Execution { private active = true; private requestor: Player | null = null; - private recipient: Player | null = null; constructor( private requestorID: PlayerID, - private recipientID: PlayerID, + private recipient: Player, private accept: boolean, ) {} @@ -19,19 +18,11 @@ export class AllianceRequestReplyExecution implements Execution { this.active = false; return; } - if (!mg.hasPlayer(this.recipientID)) { - console.warn( - `AllianceRequestReplyExecution recipient ${this.recipientID} not found`, - ); - this.active = false; - return; - } this.requestor = mg.player(this.requestorID); - this.recipient = mg.player(this.recipientID); } tick(ticks: number): void { - if (this.requestor === null || this.recipient === null) { + if (this.requestor === null) { throw new Error("Not initialized"); } if (this.requestor.isFriendly(this.recipient)) { diff --git a/src/core/execution/alliance/BreakAllianceExecution.ts b/src/core/execution/alliance/BreakAllianceExecution.ts index a028b0cb0..de614c1cc 100644 --- a/src/core/execution/alliance/BreakAllianceExecution.ts +++ b/src/core/execution/alliance/BreakAllianceExecution.ts @@ -2,23 +2,15 @@ import { Execution, Game, Player, PlayerID } from "../../game/Game"; export class BreakAllianceExecution implements Execution { private active = true; - private requestor: Player | null = null; private recipient: Player | null = null; private mg: Game | null = null; constructor( - private requestorID: PlayerID, + private requestor: Player, private recipientID: PlayerID, ) {} init(mg: Game, ticks: number): void { - if (!mg.hasPlayer(this.requestorID)) { - console.warn( - `BreakAllianceExecution requester ${this.requestorID} not found`, - ); - this.active = false; - return; - } if (!mg.hasPlayer(this.recipientID)) { console.warn( `BreakAllianceExecution: recipient ${this.recipientID} not found`, @@ -26,7 +18,6 @@ export class BreakAllianceExecution implements Execution { this.active = false; return; } - this.requestor = mg.player(this.requestorID); this.recipient = mg.player(this.recipientID); this.mg = mg; } diff --git a/src/core/execution/utils/BotBehavior.ts b/src/core/execution/utils/BotBehavior.ts index 111e0baa6..81262176f 100644 --- a/src/core/execution/utils/BotBehavior.ts +++ b/src/core/execution/utils/BotBehavior.ts @@ -41,7 +41,7 @@ export class BotBehavior { private emoji(player: Player, emoji: number) { if (player.type() !== PlayerType.Human) return; this.game.addExecution( - new EmojiExecution(this.player.id(), player.id(), emoji), + new EmojiExecution(this.player, player.id(), emoji), ); } @@ -194,7 +194,7 @@ export class BotBehavior { this.game.addExecution( new AttackExecution( troops, - this.player.id(), + this.player, target.isPlayer() ? target.id() : null, ), ); diff --git a/tests/Attack.test.ts b/tests/Attack.test.ts index 81f3b49d7..37294e53e 100644 --- a/tests/Attack.test.ts +++ b/tests/Attack.test.ts @@ -21,7 +21,13 @@ let attackerSpawn: TileRef; function sendBoat(target: TileRef, source: TileRef, troops: number) { game.addExecution( - new TransportShipExecution(defender.id(), null, target, troops, source), + new TransportShipExecution( + defender, + null, + target, + troops, + source, + ), ); } @@ -64,7 +70,7 @@ describe("Attack", () => { attacker = game.player(attackerInfo.id); defender = game.player(defenderInfo.id); - game.addExecution(new AttackExecution(100, defender.id(), null)); + game.addExecution(new AttackExecution(100, defender, game.terraNullius().id())); game.executeNextTick(); while (defender.outgoingAttacks().length > 0) { game.executeNextTick(); @@ -76,10 +82,10 @@ describe("Attack", () => { test("Nuke reduce attacking troop counts", async () => { // Not building exactly spawn to it's better protected from attacks (but still // on defender territory) - constructionExecution(game, defender.id(), 1, 1, UnitType.MissileSilo); + constructionExecution(game, defender, 1, 1, UnitType.MissileSilo); expect(defender.units(UnitType.MissileSilo)).toHaveLength(1); - game.addExecution(new AttackExecution(100, attacker.id(), defender.id())); - constructionExecution(game, defender.id(), 0, 15, UnitType.AtomBomb, 3); + game.addExecution(new AttackExecution(100, attacker, defender.id())); + constructionExecution(game, defender, 0, 15, UnitType.AtomBomb, 3); const nuke = defender.units(UnitType.AtomBomb)[0]; expect(nuke.isActive()).toBe(true); @@ -94,12 +100,12 @@ describe("Attack", () => { }); test("Nuke reduce attacking boat troop count", async () => { - constructionExecution(game, defender.id(), 1, 1, UnitType.MissileSilo); + constructionExecution(game, defender, 1, 1, UnitType.MissileSilo); expect(defender.units(UnitType.MissileSilo)).toHaveLength(1); sendBoat(game.ref(15, 8), game.ref(10, 5), 100); - constructionExecution(game, defender.id(), 0, 15, UnitType.AtomBomb, 3); + constructionExecution(game, defender, 0, 15, UnitType.AtomBomb, 3); const nuke = defender.units(UnitType.AtomBomb)[0]; expect(nuke.isActive()).toBe(true); diff --git a/tests/MissileSilo.test.ts b/tests/MissileSilo.test.ts index d5930680b..04d708546 100644 --- a/tests/MissileSilo.test.ts +++ b/tests/MissileSilo.test.ts @@ -20,7 +20,7 @@ function attackerBuildsNuke( initialize = true, ) { game.addExecution( - new NukeExecution(UnitType.AtomBomb, attacker.id(), target, source), + new NukeExecution(UnitType.AtomBomb, attacker, target, source), ); if (initialize) { game.executeNextTick(); @@ -50,7 +50,7 @@ describe("MissileSilo", () => { attacker = game.player("attacker_id"); - constructionExecution(game, attacker.id(), 1, 1, UnitType.MissileSilo); + constructionExecution(game, attacker, 1, 1, UnitType.MissileSilo); }); test("missilesilo should launch nuke", async () => { diff --git a/tests/SAM.test.ts b/tests/SAM.test.ts index fc463f960..d3f209673 100644 --- a/tests/SAM.test.ts +++ b/tests/SAM.test.ts @@ -61,12 +61,12 @@ describe("SAM", () => { defender = game.player("defender_id"); far_defender = game.player("far_defender_id"); - constructionExecution(game, attacker.id(), 7, 7, UnitType.MissileSilo); + constructionExecution(game, attacker, 7, 7, UnitType.MissileSilo); }); test("one sam should take down one nuke", async () => { const sam = defender.buildUnit(UnitType.SAMLauncher, game.ref(1, 1), {}); - game.addExecution(new SAMLauncherExecution(defender.id(), null, sam)); + game.addExecution(new SAMLauncherExecution(defender, null, sam)); attacker.buildUnit(UnitType.AtomBomb, game.ref(1, 1), { targetTile: game.ref(2, 1), }); @@ -78,7 +78,7 @@ describe("SAM", () => { test("sam should only get one nuke at a time", async () => { const sam = defender.buildUnit(UnitType.SAMLauncher, game.ref(1, 1), {}); - game.addExecution(new SAMLauncherExecution(defender.id(), null, sam)); + game.addExecution(new SAMLauncherExecution(defender, null, sam)); attacker.buildUnit(UnitType.AtomBomb, game.ref(2, 1), { targetTile: game.ref(2, 1), }); @@ -94,7 +94,7 @@ describe("SAM", () => { test("sam should cooldown as long as configured", async () => { const sam = defender.buildUnit(UnitType.SAMLauncher, game.ref(1, 1), {}); - game.addExecution(new SAMLauncherExecution(defender.id(), null, sam)); + game.addExecution(new SAMLauncherExecution(defender, null, sam)); expect(sam.isInCooldown()).toBeFalsy(); const nuke = attacker.buildUnit(UnitType.AtomBomb, game.ref(1, 2), { targetTile: game.ref(1, 2), @@ -117,9 +117,9 @@ describe("SAM", () => { const sam1 = defender.buildUnit(UnitType.SAMLauncher, game.ref(1, 1), { cooldownDuration: 10, }); - game.addExecution(new SAMLauncherExecution(defender.id(), null, sam1)); + game.addExecution(new SAMLauncherExecution(defender, null, sam1)); const sam2 = defender.buildUnit(UnitType.SAMLauncher, game.ref(1, 2), {}); - game.addExecution(new SAMLauncherExecution(defender.id(), null, sam2)); + game.addExecution(new SAMLauncherExecution(defender, null, sam2)); const nuke = attacker.buildUnit(UnitType.AtomBomb, game.ref(2, 2), { targetTile: game.ref(2, 2), }); @@ -134,7 +134,7 @@ describe("SAM", () => { const targetDistance = 199; // Close SAM: should not intercept anything const sam1 = defender.buildUnit(UnitType.SAMLauncher, game.ref(1, 1), {}); - game.addExecution(new SAMLauncherExecution(defender.id(), null, sam1)); + game.addExecution(new SAMLauncherExecution(defender, null, sam1)); // Far SAM: Should intercept the nuke. Use the far_defender so the SAM can be built const sam2 = far_defender.buildUnit( @@ -142,11 +142,11 @@ describe("SAM", () => { game.ref(targetDistance, 1), {}, ); - game.addExecution(new SAMLauncherExecution(far_defender.id(), null, sam2)); + game.addExecution(new SAMLauncherExecution(far_defender, null, sam2)); const nukeExecution = new NukeExecution( UnitType.AtomBomb, - attacker.id(), + attacker, game.ref(targetDistance, 1), null, ); diff --git a/tests/util/utils.ts b/tests/util/utils.ts index aa1b7a05d..921e5d102 100644 --- a/tests/util/utils.ts +++ b/tests/util/utils.ts @@ -4,18 +4,18 @@ // If you also need execution use function below. Does not work with things not import { ConstructionExecution } from "../../src/core/execution/ConstructionExecution"; -import { Game, PlayerID, UnitType } from "../../src/core/game/Game"; +import { Game, Player, UnitType } from "../../src/core/game/Game"; // built via UI (e.g.: trade ships) export function constructionExecution( game: Game, - playerID: PlayerID, + _owner: Player, x: number, y: number, unit: UnitType, ticks = 4, ) { - game.addExecution(new ConstructionExecution(playerID, game.ref(x, y), unit)); + game.addExecution(new ConstructionExecution(_owner, game.ref(x, y), unit)); // 4 ticks by default as it usually goes like this // Init of construction execution