Files
OpenFrontIO/src/core/game/AllianceImpl.ts
T
Mattia Migliorini 90204f6628 Add alliance renewal action to Radial Menu (#3148)
## Description:

The following PR replaces the (disabled) alliance request button with an
alliance extension/renewal button when the alliance with the target
player is expiring.

Agreeing to renewal via radial menu also hides the message in the
EventsDisplay.

<img width="369" height="364" alt="image"
src="https://github.com/user-attachments/assets/d8040f5c-ad7b-47d0-852f-925ecbf273a8"
/>


https://github.com/user-attachments/assets/aa589edf-6505-46bf-88a3-aa4c2df9137f

Icon size adjusted:

<img width="294" height="252" alt="image"
src="https://github.com/user-attachments/assets/7ca63500-b1fb-427b-965c-cf121a5213da"
/>

## 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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-02-19 19:47:57 -06:00

92 lines
2.4 KiB
TypeScript

import { Game, MutableAlliance, Player, Tick } from "./Game";
import { GameUpdateType } from "./GameUpdates";
export class AllianceImpl implements MutableAlliance {
private extensionRequestedRequestor_: boolean = false;
private extensionRequestedRecipient_: boolean = false;
private expiresAt_: Tick;
constructor(
private readonly mg: Game,
readonly requestor_: Player,
readonly recipient_: Player,
private readonly createdAt_: Tick,
private readonly id_: number,
) {
this.expiresAt_ = createdAt_ + mg.config().allianceDuration();
}
other(player: Player): Player {
if (this.requestor_ === player) {
return this.recipient_;
}
return this.requestor_;
}
requestor(): Player {
return this.requestor_;
}
recipient(): Player {
return this.recipient_;
}
createdAt(): Tick {
return this.createdAt_;
}
expire(): void {
this.mg.expireAlliance(this);
}
addExtensionRequest(player: Player): void {
if (this.requestor_ === player) {
this.extensionRequestedRequestor_ = true;
} else if (this.recipient_ === player) {
this.extensionRequestedRecipient_ = true;
}
this.mg.addUpdate({
type: GameUpdateType.AllianceExtension,
playerID: player.smallID(),
allianceID: this.id_,
});
}
bothAgreedToExtend(): boolean {
return (
this.extensionRequestedRequestor_ && this.extensionRequestedRecipient_
);
}
onlyOneAgreedToExtend(): boolean {
// Requestor / Recipient of the original alliance request, not of the extension request
// False if: no expiration or neither requested extension yet (both false), or both agreed to extend (both true)
// True if: one requested extension, other didn't yet or actively ignored (one true, one false)
return (
this.extensionRequestedRequestor_ !== this.extensionRequestedRecipient_
);
}
agreedToExtend(player: Player): boolean {
return (
(this.requestor_ === player && this.extensionRequestedRequestor_) ||
(this.recipient_ === player && this.extensionRequestedRecipient_)
);
}
public id(): number {
return this.id_;
}
extend(): void {
this.extensionRequestedRequestor_ = false;
this.extensionRequestedRecipient_ = false;
this.expiresAt_ = this.mg.ticks() + this.mg.config().allianceDuration();
}
expiresAt(): Tick {
return this.expiresAt_;
}
}