mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 12:10:46 +00:00
Cancel nukes when accepting alliance via radial menu (#3155)
Resolves #3154 ## Description: #2716 introduced nuke cancellation logic on alliance acceptance via `AllianceRequestReplyExecution`. The radial menu action, though, calls `AllianceRequestExecution` instead, which accepts the alliance if a request has already been made by the other player. This PR moves the nuke cancellation logic to `GameImpl`, hooking into the `acceptAllianceRequest` method, therefore accounting for every alliance acceptance, regardless of the specific action that brought to that. ## 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 ## Please put your Discord username so you can be contacted if a bug or regression is found: deshack_82603
This commit is contained in:
committed by
GitHub
parent
d0bb3a016e
commit
f362e47413
+6
-12
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
+6
-9
@@ -34,7 +34,7 @@ export type Intent =
|
||||
| BoatAttackIntent
|
||||
| CancelBoatIntent
|
||||
| AllianceRequestIntent
|
||||
| AllianceRequestReplyIntent
|
||||
| AllianceRejectIntent
|
||||
| AllianceExtensionIntent
|
||||
| BreakAllianceIntent
|
||||
| TargetPlayerIntent
|
||||
@@ -60,9 +60,7 @@ export type BoatAttackIntent = z.infer<typeof BoatAttackIntentSchema>;
|
||||
export type EmbargoAllIntent = z.infer<typeof EmbargoAllIntentSchema>;
|
||||
export type CancelBoatIntent = z.infer<typeof CancelBoatIntentSchema>;
|
||||
export type AllianceRequestIntent = z.infer<typeof AllianceRequestIntentSchema>;
|
||||
export type AllianceRequestReplyIntent = z.infer<
|
||||
typeof AllianceRequestReplyIntentSchema
|
||||
>;
|
||||
export type AllianceRejectIntent = z.infer<typeof AllianceRejectIntentSchema>;
|
||||
export type BreakAllianceIntent = z.infer<typeof BreakAllianceIntentSchema>;
|
||||
export type TargetPlayerIntent = z.infer<typeof TargetPlayerIntentSchema>;
|
||||
export type EmojiIntent = z.infer<typeof EmojiIntentSchema>;
|
||||
@@ -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,
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<Player, number>();
|
||||
|
||||
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 },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Player, number>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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(),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user