diff --git a/src/client/Transport.ts b/src/client/Transport.ts index e046d1068..d86f0fe82 100644 --- a/src/client/Transport.ts +++ b/src/client/Transport.ts @@ -55,13 +55,8 @@ export class SendUpgradeStructureIntentEvent implements GameEvent { ) {} } -export class SendAllianceReplyIntentEvent implements GameEvent { - constructor( - // The original alliance requestor - public readonly requestor: PlayerView, - public readonly recipient: PlayerView, - public readonly accepted: boolean, - ) {} +export class SendAllianceRejectIntentEvent implements GameEvent { + constructor(public readonly requestor: PlayerView) {} } export class SendAllianceExtensionIntentEvent implements GameEvent { @@ -204,8 +199,8 @@ export class Transport { this.eventBus.on(SendAllianceRequestIntentEvent, (e) => this.onSendAllianceRequest(e), ); - this.eventBus.on(SendAllianceReplyIntentEvent, (e) => - this.onAllianceRequestReplyUIEvent(e), + this.eventBus.on(SendAllianceRejectIntentEvent, (e) => + this.onAllianceRejectUIEvent(e), ); this.eventBus.on(SendAllianceExtensionIntentEvent, (e) => this.onSendAllianceExtensionIntent(e), @@ -447,11 +442,10 @@ export class Transport { }); } - private onAllianceRequestReplyUIEvent(event: SendAllianceReplyIntentEvent) { + private onAllianceRejectUIEvent(event: SendAllianceRejectIntentEvent) { this.sendIntent({ - type: "allianceRequestReply", + type: "allianceReject", requestor: event.requestor.id(), - accept: event.accepted, }); } diff --git a/src/client/graphics/layers/EventsDisplay.ts b/src/client/graphics/layers/EventsDisplay.ts index 5fc48143d..2cc0210a7 100644 --- a/src/client/graphics/layers/EventsDisplay.ts +++ b/src/client/graphics/layers/EventsDisplay.ts @@ -24,7 +24,8 @@ import { } from "../../../core/game/GameUpdates"; import { SendAllianceExtensionIntentEvent, - SendAllianceReplyIntentEvent, + SendAllianceRejectIntentEvent, + SendAllianceRequestIntentEvent, } from "../../Transport"; import { Layer } from "./Layer"; @@ -468,16 +469,14 @@ export class EventsDisplay extends LitElement implements Layer { className: "btn", action: () => this.eventBus.emit( - new SendAllianceReplyIntentEvent(requestor, recipient, true), + new SendAllianceRequestIntentEvent(recipient, requestor), ), }, { text: translateText("events_display.reject_alliance"), className: "btn-info", action: () => - this.eventBus.emit( - new SendAllianceReplyIntentEvent(requestor, recipient, false), - ), + this.eventBus.emit(new SendAllianceRejectIntentEvent(requestor)), }, ], highlight: true, diff --git a/src/core/Schemas.ts b/src/core/Schemas.ts index 10b97969f..5647eb744 100644 --- a/src/core/Schemas.ts +++ b/src/core/Schemas.ts @@ -34,7 +34,7 @@ export type Intent = | BoatAttackIntent | CancelBoatIntent | AllianceRequestIntent - | AllianceRequestReplyIntent + | AllianceRejectIntent | AllianceExtensionIntent | BreakAllianceIntent | TargetPlayerIntent @@ -60,9 +60,7 @@ export type BoatAttackIntent = z.infer; export type EmbargoAllIntent = z.infer; export type CancelBoatIntent = z.infer; export type AllianceRequestIntent = z.infer; -export type AllianceRequestReplyIntent = z.infer< - typeof AllianceRequestReplyIntentSchema ->; +export type AllianceRejectIntent = z.infer; export type BreakAllianceIntent = z.infer; export type TargetPlayerIntent = z.infer; export type EmojiIntent = z.infer; @@ -316,10 +314,9 @@ export const AllianceRequestIntentSchema = z.object({ recipient: ID, }); -export const AllianceRequestReplyIntentSchema = z.object({ - type: z.literal("allianceRequestReply"), - requestor: ID, // The one who made the original alliance request - accept: z.boolean(), +export const AllianceRejectIntentSchema = z.object({ + type: z.literal("allianceReject"), + requestor: ID, }); export const BreakAllianceIntentSchema = z.object({ @@ -431,7 +428,7 @@ const IntentSchema = z.discriminatedUnion("type", [ BoatAttackIntentSchema, CancelBoatIntentSchema, AllianceRequestIntentSchema, - AllianceRequestReplyIntentSchema, + AllianceRejectIntentSchema, BreakAllianceIntentSchema, TargetPlayerIntentSchema, EmojiIntentSchema, diff --git a/src/core/execution/ExecutionManager.ts b/src/core/execution/ExecutionManager.ts index af7fb21f6..d50aaadb7 100644 --- a/src/core/execution/ExecutionManager.ts +++ b/src/core/execution/ExecutionManager.ts @@ -3,8 +3,8 @@ import { PseudoRandom } from "../PseudoRandom"; import { ClientID, GameID, StampedIntent, Turn } from "../Schemas"; import { simpleHash } from "../Util"; import { AllianceExtensionExecution } from "./alliance/AllianceExtensionExecution"; +import { AllianceRejectExecution } from "./alliance/AllianceRejectExecution"; import { AllianceRequestExecution } from "./alliance/AllianceRequestExecution"; -import { AllianceRequestReplyExecution } from "./alliance/AllianceRequestReplyExecution"; import { BreakAllianceExecution } from "./alliance/BreakAllianceExecution"; import { AttackExecution } from "./AttackExecution"; import { BoatRetreatExecution } from "./BoatRetreatExecution"; @@ -75,12 +75,8 @@ export class Executor { return new TransportShipExecution(player, intent.dst, intent.troops); case "allianceRequest": return new AllianceRequestExecution(player, intent.recipient); - case "allianceRequestReply": - return new AllianceRequestReplyExecution( - intent.requestor, - player, - intent.accept, - ); + case "allianceReject": + return new AllianceRejectExecution(intent.requestor, player); case "breakAlliance": return new BreakAllianceExecution(player, intent.recipient); case "targetPlayer": diff --git a/src/core/execution/alliance/AllianceRejectExecution.ts b/src/core/execution/alliance/AllianceRejectExecution.ts new file mode 100644 index 000000000..e6ce85557 --- /dev/null +++ b/src/core/execution/alliance/AllianceRejectExecution.ts @@ -0,0 +1,49 @@ +import { Execution, Game, Player, PlayerID } from "../../game/Game"; + +export class AllianceRejectExecution implements Execution { + private active = true; + + constructor( + private requestorID: PlayerID, + private recipient: Player, + ) {} + + init(mg: Game, ticks: number): void { + if (!mg.hasPlayer(this.requestorID)) { + console.warn( + `[AllianceRejectExecution] Requestor ${this.requestorID} not found`, + ); + this.active = false; + return; + } + const requestor = mg.player(this.requestorID); + + if (requestor.isFriendly(this.recipient)) { + console.warn( + `[AllianceRejectExecution] Player ${this.requestorID} cannot reject alliance with ${this.recipient.id}, already allied`, + ); + } else { + const request = requestor + .outgoingAllianceRequests() + .find((ar) => ar.recipient() === this.recipient); + if (request === undefined) { + console.warn( + `[AllianceRejectExecution] Player ${this.requestorID} cannot reject alliance with ${this.recipient.id}, no alliance request found`, + ); + } else { + request.reject(); + } + } + this.active = false; + } + + tick(ticks: number): void {} + + isActive(): boolean { + return this.active; + } + + activeDuringSpawnPhase(): boolean { + return false; + } +} diff --git a/src/core/execution/alliance/AllianceRequestExecution.ts b/src/core/execution/alliance/AllianceRequestExecution.ts index ba36dbcd0..4a109c45e 100644 --- a/src/core/execution/alliance/AllianceRequestExecution.ts +++ b/src/core/execution/alliance/AllianceRequestExecution.ts @@ -2,8 +2,10 @@ import { AllianceRequest, Execution, Game, + MessageType, Player, PlayerID, + UnitType, } from "../../game/Game"; export class AllianceRequestExecution implements Execution { @@ -39,6 +41,19 @@ export class AllianceRequestExecution implements Execution { // then accept it instead of creating a new one. this.active = false; incoming.accept(); + + // Update player relations + this.requestor.updateRelation(recipient, 100); + recipient.updateRelation(this.requestor, 100); + + // Automatically remove embargoes only if they were automatically created + if (this.requestor.hasEmbargoAgainst(recipient)) + this.requestor.endTemporaryEmbargo(recipient); + if (recipient.hasEmbargoAgainst(this.requestor)) + recipient.endTemporaryEmbargo(this.requestor); + + // Cancel incoming nukes between players + this.cancelNukesBetweenAlliedPlayers(recipient); } else { this.req = this.requestor.createAllianceRequest(recipient); } @@ -69,4 +84,51 @@ export class AllianceRequestExecution implements Execution { activeDuringSpawnPhase(): boolean { return false; } + + cancelNukesBetweenAlliedPlayers(recipient: Player): void { + const neutralized = new Map(); + + const players = [this.requestor, recipient]; + + for (const launcher of players) { + for (const unit of launcher.units( + UnitType.AtomBomb, + UnitType.HydrogenBomb, + )) { + if (!unit.isActive() || unit.reachedTarget()) continue; + + const targetTile = unit.targetTile(); + if (!targetTile) continue; + + const targetOwner = this.mg.owner(targetTile); + if (!targetOwner.isPlayer()) continue; + + const other = launcher === this.requestor ? recipient : this.requestor; + if (targetOwner !== other) continue; + + unit.delete(false); + neutralized.set(launcher, (neutralized.get(launcher) ?? 0) + 1); + } + } + + for (const [launcher, count] of neutralized) { + const other = launcher === this.requestor ? recipient : this.requestor; + + this.mg.displayMessage( + "events_display.alliance_nukes_destroyed_outgoing", + MessageType.ALLIANCE_ACCEPTED, + launcher.id(), + undefined, + { name: other.displayName(), count }, + ); + + this.mg.displayMessage( + "events_display.alliance_nukes_destroyed_incoming", + MessageType.ALLIANCE_ACCEPTED, + other.id(), + undefined, + { name: launcher.displayName(), count }, + ); + } + } } diff --git a/src/core/execution/alliance/AllianceRequestReplyExecution.ts b/src/core/execution/alliance/AllianceRequestReplyExecution.ts deleted file mode 100644 index 35ec2ef69..000000000 --- a/src/core/execution/alliance/AllianceRequestReplyExecution.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { - Execution, - Game, - MessageType, - Player, - PlayerID, - UnitType, -} from "../../game/Game"; - -export class AllianceRequestReplyExecution implements Execution { - private active = true; - private requestor: Player | null = null; - - constructor( - private requestorID: PlayerID, - private recipient: Player, - private accept: boolean, - ) {} - - private cancelNukesBetweenAlliedPlayers( - mg: Game, - p1: Player, - p2: Player, - ): void { - const neutralized = new Map(); - - const players = [p1, p2]; - - for (const launcher of players) { - for (const unit of launcher.units( - UnitType.AtomBomb, - UnitType.HydrogenBomb, - )) { - if (!unit.isActive() || unit.reachedTarget()) continue; - - const targetTile = unit.targetTile(); - if (!targetTile) continue; - - const targetOwner = mg.owner(targetTile); - if (!targetOwner.isPlayer()) continue; - - const other = launcher === p1 ? p2 : p1; - if (targetOwner !== other) continue; - - unit.delete(false); - neutralized.set(launcher, (neutralized.get(launcher) ?? 0) + 1); - } - } - - for (const [launcher, count] of neutralized) { - const other = launcher === p1 ? p2 : p1; - - mg.displayMessage( - "events_display.alliance_nukes_destroyed_outgoing", - MessageType.ALLIANCE_ACCEPTED, - launcher.id(), - undefined, - { name: other.displayName(), count }, - ); - - mg.displayMessage( - "events_display.alliance_nukes_destroyed_incoming", - MessageType.ALLIANCE_ACCEPTED, - other.id(), - undefined, - { name: launcher.displayName(), count }, - ); - } - } - - init(mg: Game, ticks: number): void { - if (!mg.hasPlayer(this.requestorID)) { - console.warn( - `AllianceRequestReplyExecution requester ${this.requestorID} not found`, - ); - this.active = false; - return; - } - this.requestor = mg.player(this.requestorID); - - if (this.requestor.isFriendly(this.recipient)) { - console.warn("already allied"); - } else { - const request = this.requestor - .outgoingAllianceRequests() - .find((ar) => ar.recipient() === this.recipient); - if (request === undefined) { - console.warn("no alliance request found"); - } else { - if (this.accept) { - request.accept(); - this.requestor.updateRelation(this.recipient, 100); - this.recipient.updateRelation(this.requestor, 100); - - this.cancelNukesBetweenAlliedPlayers( - mg, - this.requestor, - this.recipient, - ); - } else { - request.reject(); - } - } - } - this.active = false; - } - - tick(ticks: number): void {} - - isActive(): boolean { - return this.active; - } - - activeDuringSpawnPhase(): boolean { - return false; - } -} diff --git a/src/core/game/GameImpl.ts b/src/core/game/GameImpl.ts index 45d77878f..27404b948 100644 --- a/src/core/game/GameImpl.ts +++ b/src/core/game/GameImpl.ts @@ -332,12 +332,6 @@ export class GameImpl implements Game { request, ); - // Automatically remove embargoes only if they were automatically created - if (requestor.hasEmbargoAgainst(recipient)) - requestor.endTemporaryEmbargo(recipient); - if (recipient.hasEmbargoAgainst(requestor)) - recipient.endTemporaryEmbargo(requestor); - this.addUpdate({ type: GameUpdateType.AllianceRequestReply, request: request.toUpdate(), diff --git a/tests/AllianceAcceptNukes.test.ts b/tests/AllianceAcceptNukes.test.ts index d3da89172..c77b153ad 100644 --- a/tests/AllianceAcceptNukes.test.ts +++ b/tests/AllianceAcceptNukes.test.ts @@ -1,4 +1,4 @@ -import { AllianceRequestReplyExecution } from "src/core/execution/alliance/AllianceRequestReplyExecution"; +import { AllianceRequestExecution } from "src/core/execution/alliance/AllianceRequestExecution"; import { GameUpdateType } from "src/core/game/GameUpdates"; import { NukeExecution } from "../src/core/execution/NukeExecution"; import { @@ -69,12 +69,10 @@ describe("Alliance acceptance immediately destroys in-flight nukes", () => { expect(player2.isAlliedWith(player1)).toBe(false); expect(player1.isFriendly(player2)).toBe(false); - player2.createAllianceRequest(player1); - game.addExecution( - new AllianceRequestReplyExecution(player2.id(), player1, true), - ); - - game.executeNextTick(); + game.addExecution(new AllianceRequestExecution(player1, player2.id())); + game.executeNextTick(); // creates request + game.addExecution(new AllianceRequestExecution(player2, player1.id())); + game.executeNextTick(); // counter-request auto-accepts expect(player2.isAlliedWith(player1)).toBe(true); expect(player1.isFriendly(player2)).toBe(true); @@ -100,12 +98,11 @@ describe("Alliance acceptance immediately destroys in-flight nukes", () => { expect(player2.isAlliedWith(player1)).toBe(false); expect(player1.isFriendly(player2)).toBe(false); - player1.createAllianceRequest(player2); - game.addExecution( - new AllianceRequestReplyExecution(player1.id(), player2, true), - ); - - game.executeNextTick(); + // Both requests added in same tick so the nuke tick can't revoke the first + // before the counter-request sees it. + game.addExecution(new AllianceRequestExecution(player1, player2.id())); + game.addExecution(new AllianceRequestExecution(player2, player1.id())); + game.executeNextTick(); // both init: first creates request, second auto-accepts expect(player2.isAlliedWith(player1)).toBe(true); expect(player1.isFriendly(player2)).toBe(true); @@ -137,12 +134,10 @@ describe("Alliance acceptance immediately destroys in-flight nukes", () => { expect(player2.isAlliedWith(player1)).toBe(false); expect(player1.isFriendly(player2)).toBe(false); - player2.createAllianceRequest(player1); - game.addExecution( - new AllianceRequestReplyExecution(player2.id(), player1, true), - ); - - const updates = game.executeNextTick(); + game.addExecution(new AllianceRequestExecution(player1, player2.id())); + game.executeNextTick(); // creates request + game.addExecution(new AllianceRequestExecution(player2, player1.id())); + const updates = game.executeNextTick(); // counter-request auto-accepts expect(player2.isAlliedWith(player1)).toBe(true); expect(player1.isFriendly(player2)).toBe(true); diff --git a/tests/AllianceDonation.test.ts b/tests/AllianceDonation.test.ts index 22cab40df..39da2f77a 100644 --- a/tests/AllianceDonation.test.ts +++ b/tests/AllianceDonation.test.ts @@ -1,5 +1,4 @@ import { AllianceRequestExecution } from "../src/core/execution/alliance/AllianceRequestExecution"; -import { AllianceRequestReplyExecution } from "../src/core/execution/alliance/AllianceRequestReplyExecution"; import { DonateGoldExecution } from "../src/core/execution/DonateGoldExecution"; import { Game, Player, PlayerType } from "../src/core/game/Game"; import { playerInfo, setup } from "./util/Setup"; @@ -44,9 +43,7 @@ describe("Alliance Donation", () => { game.addExecution(new AllianceRequestExecution(player1, player2.id())); game.executeNextTick(); - game.addExecution( - new AllianceRequestReplyExecution(player1.id(), player2, true), - ); + game.addExecution(new AllianceRequestExecution(player2, player1.id())); game.executeNextTick(); expect(player1.isAlliedWith(player2)).toBeTruthy(); @@ -65,9 +62,7 @@ describe("Alliance Donation", () => { game.addExecution(new AllianceRequestExecution(player1, player2.id())); game.executeNextTick(); - game.addExecution( - new AllianceRequestReplyExecution(player1.id(), player2, true), - ); + game.addExecution(new AllianceRequestExecution(player2, player1.id())); game.executeNextTick(); expect(player1.isAlliedWith(player2)).toBeTruthy(); @@ -121,9 +116,7 @@ describe("Alliance Donation", () => { game.executeNextTick(); const goldBefore = player2.gold(); - game.addExecution( - new AllianceRequestReplyExecution(player1.id(), player2, true), - ); + game.addExecution(new AllianceRequestExecution(player2, player1.id())); game.addExecution(new DonateGoldExecution(player1, player2.id(), 100)); game.executeNextTick(); diff --git a/tests/AllianceExtensionExecution.test.ts b/tests/AllianceExtensionExecution.test.ts index 1cbbdd901..1bc1b699c 100644 --- a/tests/AllianceExtensionExecution.test.ts +++ b/tests/AllianceExtensionExecution.test.ts @@ -1,6 +1,5 @@ import { AllianceExtensionExecution } from "../src/core/execution/alliance/AllianceExtensionExecution"; import { AllianceRequestExecution } from "../src/core/execution/alliance/AllianceRequestExecution"; -import { AllianceRequestReplyExecution } from "../src/core/execution/alliance/AllianceRequestReplyExecution"; import { Game, MessageType, Player, PlayerType } from "../src/core/game/Game"; import { playerInfo, setup } from "./util/Setup"; @@ -36,17 +35,14 @@ describe("AllianceExtensionExecution", () => { test("Successfully extends existing alliance between Humans", () => { vi.spyOn(player1, "canSendAllianceRequest").mockReturnValue(true); + vi.spyOn(player2, "canSendAllianceRequest").mockReturnValue(true); vi.spyOn(player2, "isAlive").mockReturnValue(true); vi.spyOn(player1, "isAlive").mockReturnValue(true); game.addExecution(new AllianceRequestExecution(player1, player2.id())); game.executeNextTick(); - game.executeNextTick(); - game.addExecution( - new AllianceRequestReplyExecution(player1.id(), player2, true), - ); - game.executeNextTick(); + game.addExecution(new AllianceRequestExecution(player2, player1.id())); game.executeNextTick(); expect(player1.allianceWith(player2)).toBeTruthy(); @@ -83,17 +79,14 @@ describe("AllianceExtensionExecution", () => { test("Successfully extends existing alliance between Human and non-Human", () => { vi.spyOn(player1, "canSendAllianceRequest").mockReturnValue(true); + vi.spyOn(player3, "canSendAllianceRequest").mockReturnValue(true); vi.spyOn(player3, "isAlive").mockReturnValue(true); vi.spyOn(player1, "isAlive").mockReturnValue(true); game.addExecution(new AllianceRequestExecution(player1, player3.id())); game.executeNextTick(); - game.executeNextTick(); - game.addExecution( - new AllianceRequestReplyExecution(player1.id(), player3, true), - ); - game.executeNextTick(); + game.addExecution(new AllianceRequestExecution(player3, player1.id())); game.executeNextTick(); expect(player1.allianceWith(player3)).toBeTruthy(); @@ -121,18 +114,15 @@ describe("AllianceExtensionExecution", () => { test("Sends message to other player when one player requests renewal", () => { vi.spyOn(player1, "canSendAllianceRequest").mockReturnValue(true); + vi.spyOn(player2, "canSendAllianceRequest").mockReturnValue(true); vi.spyOn(player2, "isAlive").mockReturnValue(true); vi.spyOn(player1, "isAlive").mockReturnValue(true); // Create alliance between player1 and player2 game.addExecution(new AllianceRequestExecution(player1, player2.id())); game.executeNextTick(); - game.executeNextTick(); - game.addExecution( - new AllianceRequestReplyExecution(player1.id(), player2, true), - ); - game.executeNextTick(); + game.addExecution(new AllianceRequestExecution(player2, player1.id())); game.executeNextTick(); expect(player1.allianceWith(player2)).toBeTruthy(); diff --git a/tests/AllianceRequestExecution.test.ts b/tests/AllianceRequestExecution.test.ts index d11649fca..8ced166b7 100644 --- a/tests/AllianceRequestExecution.test.ts +++ b/tests/AllianceRequestExecution.test.ts @@ -1,5 +1,5 @@ +import { AllianceRejectExecution } from "../src/core/execution/alliance/AllianceRejectExecution"; import { AllianceRequestExecution } from "../src/core/execution/alliance/AllianceRequestExecution"; -import { AllianceRequestReplyExecution } from "../src/core/execution/alliance/AllianceRequestReplyExecution"; import { NukeExecution } from "../src/core/execution/NukeExecution"; import { Game, Player, PlayerType, UnitType } from "../src/core/game/Game"; import { playerInfo, setup } from "./util/Setup"; @@ -36,21 +36,7 @@ describe("AllianceRequestExecution", () => { } }); - test("Can create alliance by replying", () => { - game.addExecution(new AllianceRequestExecution(player1, player2.id())); - game.executeNextTick(); - - game.addExecution( - new AllianceRequestReplyExecution(player1.id(), player2, true), - ); - game.executeNextTick(); - game.executeNextTick(); - - expect(player1.isAlliedWith(player2)).toBeTruthy(); - expect(player2.isAlliedWith(player1)).toBeTruthy(); - }); - - test("Can create alliance by sending alliance request back", () => { + test("Can create alliance by counter-request", () => { game.addExecution(new AllianceRequestExecution(player1, player2.id())); game.executeNextTick(); @@ -61,6 +47,18 @@ describe("AllianceRequestExecution", () => { expect(player2.isAlliedWith(player1)).toBeTruthy(); }); + test("Can reject alliance request", () => { + game.addExecution(new AllianceRequestExecution(player1, player2.id())); + game.executeNextTick(); + + game.addExecution(new AllianceRejectExecution(player1.id(), player2)); + game.executeNextTick(); + + expect(player1.isAlliedWith(player2)).toBeFalsy(); + expect(player2.isAlliedWith(player1)).toBeFalsy(); + expect(player1.outgoingAllianceRequests().length).toBe(0); + }); + test("Alliance request expires", () => { game.config().allianceRequestDuration = () => 5; game.addExecution(new AllianceRequestExecution(player1, player2.id())); diff --git a/tests/core/game/GameImpl.test.ts b/tests/core/game/GameImpl.test.ts index 75cf2a235..7b2b5b32c 100644 --- a/tests/core/game/GameImpl.test.ts +++ b/tests/core/game/GameImpl.test.ts @@ -3,7 +3,6 @@ import { AttackExecution } from "../../../src/core/execution/AttackExecution"; import { SpawnExecution } from "../../../src/core/execution/SpawnExecution"; //import { TransportShipExecution } from "../../../src/core/execution/TransportShipExecution"; import { AllianceRequestExecution } from "../../../src/core/execution/alliance/AllianceRequestExecution"; -import { AllianceRequestReplyExecution } from "../../../src/core/execution/alliance/AllianceRequestReplyExecution"; import { Game, Player, @@ -68,16 +67,11 @@ describe("GameImpl", () => { test("Don't become traitor when betraying inactive player", async () => { vi.spyOn(attacker, "canSendAllianceRequest").mockReturnValue(true); + vi.spyOn(defender, "canSendAllianceRequest").mockReturnValue(true); game.addExecution(new AllianceRequestExecution(attacker, defender.id())); - - game.executeNextTick(); game.executeNextTick(); - game.addExecution( - new AllianceRequestReplyExecution(attacker.id(), defender, true), - ); - - game.executeNextTick(); + game.addExecution(new AllianceRequestExecution(defender, attacker.id())); game.executeNextTick(); expect(attacker.allianceWith(defender)).toBeTruthy(); @@ -107,16 +101,11 @@ describe("GameImpl", () => { test("Do become traitor when betraying active player", async () => { vi.spyOn(attacker, "canSendAllianceRequest").mockReturnValue(true); + vi.spyOn(defender, "canSendAllianceRequest").mockReturnValue(true); game.addExecution(new AllianceRequestExecution(attacker, defender.id())); - - game.executeNextTick(); game.executeNextTick(); - game.addExecution( - new AllianceRequestReplyExecution(attacker.id(), defender, true), - ); - - game.executeNextTick(); + game.addExecution(new AllianceRequestExecution(defender, attacker.id())); game.executeNextTick(); expect(attacker.allianceWith(defender)).toBeTruthy();