diff --git a/src/core/configuration/Config.ts b/src/core/configuration/Config.ts index d789d52b2..cc8627bb2 100644 --- a/src/core/configuration/Config.ts +++ b/src/core/configuration/Config.ts @@ -111,6 +111,7 @@ export interface Config { boatMaxNumber(): number; allianceDuration(): Tick; allianceRequestCooldown(): Tick; + temporaryEmbargoDuration(): Tick; targetDuration(): Tick; targetCooldown(): Tick; emojiMessageCooldown(): Tick; diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index 841976d0c..538a36156 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -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; diff --git a/src/core/execution/AttackExecution.ts b/src/core/execution/AttackExecution.ts index 8d62debb5..f514cd02b 100644 --- a/src/core/execution/AttackExecution.ts +++ b/src/core/execution/AttackExecution.ts @@ -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); } } diff --git a/src/core/execution/EmbargoExecution.ts b/src/core/execution/EmbargoExecution.ts index 7e159a4ea..a3dfaf7f5 100644 --- a/src/core/execution/EmbargoExecution.ts +++ b/src/core/execution/EmbargoExecution.ts @@ -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; diff --git a/src/core/execution/FakeHumanExecution.ts b/src/core/execution/FakeHumanExecution.ts index 18b84bc3f..a64ba258a 100644 --- a/src/core/execution/FakeHumanExecution.ts +++ b/src/core/execution/FakeHumanExecution.ts @@ -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) diff --git a/src/core/execution/PlayerExecution.ts b/src/core/execution/PlayerExecution.ts index df86b96e6..b93b96223 100644 --- a/src/core/execution/PlayerExecution.ts +++ b/src/core/execution/PlayerExecution.ts @@ -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; diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index bb57ca831..b4ccf7ba7 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -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. diff --git a/src/core/game/GameImpl.ts b/src/core/game/GameImpl.ts index 1b88abad0..797a3396f 100644 --- a/src/core/game/GameImpl.ts +++ b/src/core/game/GameImpl.ts @@ -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(), diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index 0a98ff41a..ed202b9cf 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -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 = new Set(); + private embargoes = new Map(); public _borderTiles: Set = 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()