mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-22 07:07:05 +00:00
[Cleanup] Pass Player into execution constructor instead of PlayerID (#1022)
## 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 <lva@rovsing.dk>
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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`);
|
||||
|
||||
@@ -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<Unit>();
|
||||
|
||||
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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ?? {},
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<TileRef> | 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<TileRef>) {
|
||||
if (this.mg === null || this.player === null || this.nuke === null) {
|
||||
if (this.nuke === null) {
|
||||
throw new Error("Not initialized");
|
||||
}
|
||||
const attacked = new Map<Player, number>();
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<TileRef>): false | Player {
|
||||
if (this.mg === null || this.player === null) {
|
||||
throw new Error("Not initialized");
|
||||
}
|
||||
const enemies = new Set<number>();
|
||||
for (const tile of cluster) {
|
||||
const isOceanShore = this.mg.isOceanShore(tile);
|
||||
@@ -181,9 +164,6 @@ export class PlayerExecution implements Execution {
|
||||
}
|
||||
|
||||
private isSurrounded(cluster: Set<TileRef>): boolean {
|
||||
if (this.mg === null || this.player === null) {
|
||||
throw new Error("Not initialized");
|
||||
}
|
||||
const enemyTiles = new Set<TileRef>();
|
||||
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<TileRef>) {
|
||||
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<TileRef>): Player | null {
|
||||
if (this.mg === null || this.player === null) {
|
||||
throw new Error("Not initialized");
|
||||
}
|
||||
const neighborsIDs = new Set<number>();
|
||||
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<TileRef>[] {
|
||||
if (this.mg === null || this.player === null) {
|
||||
throw new Error("Not initialized");
|
||||
}
|
||||
const seen = new Set<TileRef>();
|
||||
const border = this.player.borderTiles();
|
||||
const clusters: Set<TileRef>[] = [];
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<string, string>,
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
);
|
||||
|
||||
+13
-7
@@ -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);
|
||||
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
+9
-9
@@ -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,
|
||||
);
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user