Feat : Auto remove embargoes that were automatically created (#707)

## Description:

Adds two fields to an Embargo : 
- `createdAt` : the tick at which it was created
- `willExpire` : whether the embargo will expire on its own

An embargo will remove itself only if the player didn't intentionally
set it. It expires either when an alliance is made, or if enough time
has passed (according to the `embargoDuration` config entry).

I put 5 minutes for `embargoDuration` by default, which seems reasonable
to me.

closes #702 

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [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:

leo21_
This commit is contained in:
Léo Kosman
2025-05-15 19:09:27 +02:00
committed by GitHub
parent 2fe99dc2ce
commit 1b286f5518
9 changed files with 65 additions and 11 deletions
+1
View File
@@ -111,6 +111,7 @@ export interface Config {
boatMaxNumber(): number;
allianceDuration(): Tick;
allianceRequestCooldown(): Tick;
temporaryEmbargoDuration(): Tick;
targetDuration(): Tick;
targetCooldown(): Tick;
emojiMessageCooldown(): Tick;
+4
View File
@@ -448,6 +448,10 @@ export class DefaultConfig implements Config {
allianceDuration(): Tick {
return 600 * 10; // 10 minutes.
}
temporaryEmbargoDuration(): Tick {
return 300 * 10; // 5 minutes.
}
percentageTilesOwnedToWin(): number {
if (this._gameConfig.gameMode == GameMode.Team) {
return 95;
+2 -2
View File
@@ -79,8 +79,8 @@ export class AttackExecution implements Execution {
targetPlayer.type() != PlayerType.Bot &&
this._owner.type() != PlayerType.Bot
) {
// Don't let bots embargo since they can't trade anyways.
targetPlayer.addEmbargo(this._owner.id());
// Don't let bots embargo since they can't trade anyway.
targetPlayer.addEmbargo(this._owner.id(), true);
}
}
+1 -1
View File
@@ -23,7 +23,7 @@ export class EmbargoExecution implements Execution {
}
tick(_: number): void {
if (this.action == "start") this.player.addEmbargo(this.targetID);
if (this.action == "start") this.player.addEmbargo(this.targetID, false);
else this.player.stopEmbargo(this.targetID);
this.active = false;
+1 -1
View File
@@ -96,7 +96,7 @@ export class FakeHumanExecution implements Execution {
this.player.relation(other) <= Relation.Hostile &&
!this.player.hasEmbargoAgainst(other)
) {
this.player.addEmbargo(other.id());
this.player.addEmbargo(other.id(), false);
} else if (
this.player.relation(other) >= Relation.Neutral &&
this.player.hasEmbargoAgainst(other)
+11
View File
@@ -97,6 +97,17 @@ export class PlayerExecution implements Execution {
}
}
const embargoes = this.player.getEmbargoes();
for (const embargo of embargoes) {
if (
embargo.isTemporary &&
this.mg.ticks() - embargo.createdAt >
this.mg.config().temporaryEmbargoDuration()
) {
this.player.stopEmbargo(embargo.target);
}
}
if (ticks - this.lastCalc > this.ticksPerClusterCalc) {
if (this.player.lastTileChange() > this.lastCalc) {
this.lastCalc = ticks;
+9 -1
View File
@@ -378,6 +378,12 @@ export interface TerraNullius {
smallID(): number;
}
export interface Embargo {
createdAt: Tick;
isTemporary: boolean;
target: PlayerID;
}
export interface Player {
// Basic Info
smallID(): number;
@@ -476,8 +482,10 @@ export interface Player {
// Embargo
hasEmbargoAgainst(other: Player): boolean;
tradingPartners(): Player[];
addEmbargo(other: PlayerID): void;
addEmbargo(other: PlayerID, isTemporary: boolean): void;
getEmbargoes(): Embargo[];
stopEmbargo(other: PlayerID): void;
endTemporaryEmbargo(other: PlayerID): void;
canTrade(other: Player): boolean;
// Attacking.
+13 -2
View File
@@ -221,16 +221,27 @@ export class GameImpl implements Game {
acceptAllianceRequest(request: AllianceRequestImpl) {
this.allianceRequests = this.allianceRequests.filter((ar) => ar != request);
const requestor = request.requestor();
const recipient = request.recipient();
const alliance = new AllianceImpl(
this,
request.requestor() as PlayerImpl,
request.recipient() as PlayerImpl,
requestor as PlayerImpl,
recipient as PlayerImpl,
this._ticks,
);
this.alliances_.push(alliance);
(request.requestor() as PlayerImpl).pastOutgoingAllianceRequests.push(
request,
);
// Automatically remove embargoes only if they were automatically created
if (requestor.hasEmbargoAgainst(recipient))
requestor.endTemporaryEmbargo(recipient.id());
if (recipient.hasEmbargoAgainst(requestor))
recipient.endTemporaryEmbargo(requestor.id());
this.addUpdate({
type: GameUpdateType.AllianceRequestReply,
request: request.toUpdate(),
+23 -4
View File
@@ -21,6 +21,7 @@ import {
BuildableUnit,
Cell,
ColoredTeams,
Embargo,
EmojiMessage,
Gold,
MessageType,
@@ -73,7 +74,7 @@ export class PlayerImpl implements Player {
markedTraitorTick = -1;
private embargoes: Set<PlayerID> = new Set();
private embargoes = new Map<PlayerID, Embargo>();
public _borderTiles: Set<TileRef> = new Set();
@@ -142,7 +143,7 @@ export class PlayerImpl implements Player {
troops: this.troops(),
targetTroopRatio: this.targetTroopRatio(),
allies: this.alliances().map((a) => a.other(this).smallID()),
embargoes: this.embargoes,
embargoes: new Set([...this.embargoes.keys()].map((p) => p.toString())),
isTraitor: this.isTraitor(),
targets: this.targets().map((p) => p.smallID()),
outgoingEmojis: this.outgoingEmojis(),
@@ -582,14 +583,32 @@ export class PlayerImpl implements Player {
return !embargo && other.id() != this.id();
}
addEmbargo(other: PlayerID): void {
this.embargoes.add(other);
addEmbargo(other: PlayerID, isTemporary: boolean): void {
if (this.embargoes.has(other) && !this.embargoes.get(other).isTemporary)
return;
this.embargoes.set(other, {
createdAt: this.mg.ticks(),
isTemporary: isTemporary,
target: other,
});
}
getEmbargoes(): Embargo[] {
return [...this.embargoes.values()];
}
stopEmbargo(other: PlayerID): void {
this.embargoes.delete(other);
}
endTemporaryEmbargo(other: PlayerID): void {
if (this.embargoes.has(other) && !this.embargoes.get(other).isTemporary)
return;
this.stopEmbargo(other);
}
tradingPartners(): Player[] {
return this.mg
.players()