From b441ab2f97d2ea4e0c7293befcda623dbc4b9545 Mon Sep 17 00:00:00 2001 From: aqw42 Date: Fri, 30 May 2025 14:02:44 +0200 Subject: [PATCH] Disconnected player giveaway for team mode --- src/core/execution/PlayerExecution.ts | 51 +++++++++++++++++++++++++++ src/core/game/Game.ts | 1 + src/core/game/PlayerImpl.ts | 24 +++++++++++++ 3 files changed, 76 insertions(+) diff --git a/src/core/execution/PlayerExecution.ts b/src/core/execution/PlayerExecution.ts index 4bf039072..344837a02 100644 --- a/src/core/execution/PlayerExecution.ts +++ b/src/core/execution/PlayerExecution.ts @@ -4,6 +4,7 @@ import { consolex } from "../Consolex"; import { Execution, Game, + GameMode, MessageType, Player, PlayerID, @@ -75,6 +76,17 @@ export class PlayerExecution implements Execution { return; } + if ( + this.player.isDisconnected() && + this.config.gameConfig().gameMode === GameMode.Team + ) { + const closestAlly = this.getMoreSharedBorderAlly(); + if (closestAlly) { + this.giveaway(closestAlly); + } + return; + } + const popInc = this.config.populationIncreaseRate(this.player); this.player.addWorkers(popInc * (1 - this.player.targetTroopRatio())); this.player.addTroops(popInc * this.player.targetTroopRatio()); @@ -252,6 +264,45 @@ export class PlayerExecution implements Execution { } } + private getMoreSharedBorderAlly(): Player | null { + if (!this.player) { + return null; + } + + const neighbours = this.player!.neighborsBordersSurface().filter((p) => + p[0].isOnSameTeam(this.player!), + ); + + if (!neighbours.length) { + return null; + } + + return neighbours[0][0]; + } + + private giveaway(other: Player) { + if (this.mg === null || this.player === null) { + return; + } + + for (const tile of this.player.tiles()) { + other.conquer(tile); + } + + other.addGold(this.player.gold()); + this.player.removeGold(this.player.gold()); + + other.addTroops(this.player.troops()); + this.player.removeTroops(this.player.troops()); + + other.addWorkers(this.player.workers()); + this.player.removeWorkers(this.player.workers()); + + for (const unit of this.player.units()) { + other.captureUnit(unit); + } + } + private getCapturingPlayer(cluster: Set): Player | null { if (this.mg === null || this.player === null) { throw new Error("Not initialized"); diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index 4a3a88e88..b7c0b607d 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -478,6 +478,7 @@ export interface Player { // Relations & Diplomacy neighbors(): (Player | TerraNullius)[]; sharesBorderWith(other: Player | TerraNullius): boolean; + neighborsBordersSurface(): [Player, number][]; relation(other: Player): Relation; allRelationsSorted(): { player: Player; relation: Relation }[]; updateRelation(other: Player, delta: number): void; diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index d06565a86..80724feba 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -260,6 +260,30 @@ export class PlayerImpl implements Player { return Array.from(ns); } + neighborsBordersSurface(): [Player, number][] { + const map = new Map(); + + const borderTiles = this.borderTiles(); + for (const borderTile of borderTiles) { + const neighbors = this.mg.neighbors(borderTile); + for (const neighborTile of neighbors) { + if (!this.mg.hasOwner(neighborTile)) { + continue; + } + const neighborOwner = this.mg.owner(neighborTile); + if (neighborOwner.smallID() === this.smallID()) { + continue; + } + if (neighborOwner.isPlayer()) { + const currentCount = map.get(neighborOwner) || 0; + map.set(neighborOwner, currentCount + 1); + } + } + } + + return Array.from(map).sort((a, b) => a[1] - b[1]); + } + isPlayer(): this is Player { return true as const; }