mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-26 07:24:36 +00:00
rename cansendlliance request fix ally self bug
This commit is contained in:
@@ -154,8 +154,7 @@ export class GameRunner {
|
||||
sharedBorder: player.sharesBorderWith(other),
|
||||
canSendEmoji: player.canSendEmoji(other),
|
||||
canTarget: player.canTarget(other),
|
||||
canSendAllianceRequest:
|
||||
!player.recentOrPendingAllianceRequestWith(other),
|
||||
canSendAllianceRequest: player.canSendAllianceRequest(other),
|
||||
canBreakAlliance: player.isAlliedWith(other),
|
||||
canDonate: player.canDonate(other),
|
||||
};
|
||||
|
||||
@@ -48,10 +48,10 @@ export class FakeHumanExecution implements Execution {
|
||||
gameID: GameID,
|
||||
private playerInfo: PlayerInfo,
|
||||
private cell: Cell,
|
||||
private strength: number,
|
||||
private strength: number
|
||||
) {
|
||||
this.random = new PseudoRandom(
|
||||
simpleHash(playerInfo.id) + simpleHash(gameID),
|
||||
simpleHash(playerInfo.id) + simpleHash(gameID)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ export class FakeHumanExecution implements Execution {
|
||||
const enemyborder = Array.from(this.player.borderTiles())
|
||||
.flatMap((t) => this.mg.neighbors(t))
|
||||
.filter(
|
||||
(t) => this.mg.isLand(t) && this.mg.ownerID(t) != this.player.smallID(),
|
||||
(t) => this.mg.isLand(t) && this.mg.ownerID(t) != this.player.smallID()
|
||||
);
|
||||
|
||||
if (enemyborder.length == 0) {
|
||||
@@ -125,7 +125,7 @@ export class FakeHumanExecution implements Execution {
|
||||
}
|
||||
|
||||
const enemiesWithTN = enemyborder.map((t) =>
|
||||
this.mg.playerBySmallID(this.mg.ownerID(t)),
|
||||
this.mg.playerBySmallID(this.mg.ownerID(t))
|
||||
);
|
||||
if (enemiesWithTN.filter((o) => !o.isPlayer()).length > 0) {
|
||||
this.sendAttack(this.mg.terraNullius());
|
||||
@@ -139,10 +139,7 @@ export class FakeHumanExecution implements Execution {
|
||||
|
||||
if (this.random.chance(20)) {
|
||||
const toAlly = this.random.randElement(enemies);
|
||||
if (
|
||||
!this.player.isAlliedWith(toAlly) &&
|
||||
!this.player.recentOrPendingAllianceRequestWith(toAlly)
|
||||
) {
|
||||
if (this.player.canSendAllianceRequest(toAlly)) {
|
||||
this.player.createAllianceRequest(toAlly);
|
||||
return;
|
||||
}
|
||||
@@ -208,7 +205,7 @@ export class FakeHumanExecution implements Execution {
|
||||
this.lastEnemyUpdateTick = this.mg.ticks();
|
||||
if (target.ally.type() == PlayerType.Human) {
|
||||
this.mg.addExecution(
|
||||
new EmojiExecution(this.player.id(), target.ally.id(), "👍"),
|
||||
new EmojiExecution(this.player.id(), target.ally.id(), "👍")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -229,8 +226,8 @@ export class FakeHumanExecution implements Execution {
|
||||
new EmojiExecution(
|
||||
this.player.id(),
|
||||
this.enemy.id(),
|
||||
this.random.randElement(["🤡", "😡"]),
|
||||
),
|
||||
this.random.randElement(["🤡", "😡"])
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -274,7 +271,7 @@ export class FakeHumanExecution implements Execution {
|
||||
}
|
||||
if (this.player.canBuild(UnitType.AtomBomb, tile)) {
|
||||
this.mg.addExecution(
|
||||
new NukeExecution(UnitType.AtomBomb, this.player.id(), tile),
|
||||
new NukeExecution(UnitType.AtomBomb, this.player.id(), tile)
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -285,9 +282,9 @@ export class FakeHumanExecution implements Execution {
|
||||
const closest = closestTwoTiles(
|
||||
this.mg,
|
||||
Array.from(this.player.borderTiles()).filter((t) =>
|
||||
this.mg.isOceanShore(t),
|
||||
this.mg.isOceanShore(t)
|
||||
),
|
||||
Array.from(other.borderTiles()).filter((t) => this.mg.isOceanShore(t)),
|
||||
Array.from(other.borderTiles()).filter((t) => this.mg.isOceanShore(t))
|
||||
);
|
||||
if (closest == null) {
|
||||
return;
|
||||
@@ -301,8 +298,8 @@ export class FakeHumanExecution implements Execution {
|
||||
this.player.id(),
|
||||
other.id(),
|
||||
closest.y,
|
||||
this.player.troops() / 5,
|
||||
),
|
||||
this.player.troops() / 5
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -311,7 +308,7 @@ export class FakeHumanExecution implements Execution {
|
||||
const ports = this.player.units(UnitType.Port);
|
||||
if (ports.length == 0 && this.player.gold() > this.cost(UnitType.Port)) {
|
||||
const oceanTiles = Array.from(this.player.borderTiles()).filter((t) =>
|
||||
this.mg.isOceanShore(t),
|
||||
this.mg.isOceanShore(t)
|
||||
);
|
||||
if (oceanTiles.length > 0) {
|
||||
const buildTile = this.random.randElement(oceanTiles);
|
||||
@@ -322,7 +319,7 @@ export class FakeHumanExecution implements Execution {
|
||||
this.maybeSpawnStructure(
|
||||
UnitType.City,
|
||||
2,
|
||||
(t) => new CityExecution(this.player.id(), t),
|
||||
(t) => new CityExecution(this.player.id(), t)
|
||||
);
|
||||
if (this.maybeSpawnWarship(UnitType.Destroyer)) {
|
||||
return;
|
||||
@@ -333,14 +330,14 @@ export class FakeHumanExecution implements Execution {
|
||||
this.maybeSpawnStructure(
|
||||
UnitType.MissileSilo,
|
||||
1,
|
||||
(t) => new MissileSiloExecution(this.player.id(), t),
|
||||
(t) => new MissileSiloExecution(this.player.id(), t)
|
||||
);
|
||||
}
|
||||
|
||||
private maybeSpawnStructure(
|
||||
type: UnitType,
|
||||
maxNum: number,
|
||||
build: (tile: TileRef) => Execution,
|
||||
build: (tile: TileRef) => Execution
|
||||
) {
|
||||
const units = this.player.units(type);
|
||||
if (units.length >= maxNum) {
|
||||
@@ -363,7 +360,7 @@ export class FakeHumanExecution implements Execution {
|
||||
}
|
||||
|
||||
private maybeSpawnWarship(
|
||||
shipType: UnitType.Destroyer | UnitType.Battleship,
|
||||
shipType: UnitType.Destroyer | UnitType.Battleship
|
||||
): boolean {
|
||||
if (!this.random.chance(50)) {
|
||||
return false;
|
||||
@@ -388,12 +385,12 @@ export class FakeHumanExecution implements Execution {
|
||||
switch (shipType) {
|
||||
case UnitType.Destroyer:
|
||||
this.mg.addExecution(
|
||||
new DestroyerExecution(this.player.id(), targetTile),
|
||||
new DestroyerExecution(this.player.id(), targetTile)
|
||||
);
|
||||
break;
|
||||
case UnitType.Battleship:
|
||||
this.mg.addExecution(
|
||||
new BattleshipExecution(this.player.id(), targetTile),
|
||||
new BattleshipExecution(this.player.id(), targetTile)
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -424,11 +421,11 @@ export class FakeHumanExecution implements Execution {
|
||||
for (let attempts = 0; attempts < 50; attempts++) {
|
||||
const randX = this.random.nextInt(
|
||||
this.mg.x(portTile) - radius,
|
||||
this.mg.x(portTile) + radius,
|
||||
this.mg.x(portTile) + radius
|
||||
);
|
||||
const randY = this.random.nextInt(
|
||||
this.mg.y(portTile) - radius,
|
||||
this.mg.y(portTile) + radius,
|
||||
this.mg.y(portTile) + radius
|
||||
);
|
||||
if (!this.mg.isValidCoord(randX, randY)) {
|
||||
continue;
|
||||
@@ -478,8 +475,8 @@ export class FakeHumanExecution implements Execution {
|
||||
new AllianceRequestReplyExecution(
|
||||
req.requestor().id(),
|
||||
this.player.id(),
|
||||
accept,
|
||||
),
|
||||
accept
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -490,7 +487,7 @@ export class FakeHumanExecution implements Execution {
|
||||
|
||||
if (oceanShore == null) {
|
||||
oceanShore = Array.from(this.player.borderTiles()).filter((t) =>
|
||||
this.mg.isOceanShore(t),
|
||||
this.mg.isOceanShore(t)
|
||||
);
|
||||
}
|
||||
if (oceanShore.length == 0) {
|
||||
@@ -503,9 +500,9 @@ export class FakeHumanExecution implements Execution {
|
||||
src,
|
||||
andFN(
|
||||
(gm, t) => gm.isOcean(t) || gm.isOceanShore(t),
|
||||
manhattanDistFN(src, 200),
|
||||
),
|
||||
),
|
||||
manhattanDistFN(src, 200)
|
||||
)
|
||||
)
|
||||
).filter((t) => this.mg.isOceanShore(t) && this.mg.owner(t) != this.player);
|
||||
|
||||
if (otherShore.length == 0) {
|
||||
@@ -529,8 +526,8 @@ export class FakeHumanExecution implements Execution {
|
||||
this.player.id(),
|
||||
this.mg.hasOwner(dst) ? this.mg.owner(dst).id() : null,
|
||||
dst,
|
||||
this.player.troops() / 5,
|
||||
),
|
||||
this.player.troops() / 5
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -568,8 +565,8 @@ export class FakeHumanExecution implements Execution {
|
||||
this.player.id(),
|
||||
toAttack.isPlayer() ? toAttack.id() : null,
|
||||
null,
|
||||
null,
|
||||
),
|
||||
null
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -577,7 +574,7 @@ export class FakeHumanExecution implements Execution {
|
||||
return (
|
||||
this.mg.bfs(
|
||||
tile,
|
||||
andFN((gm, t) => gm.isLand(t), manhattanDistFN(tile, 10)),
|
||||
andFN((gm, t) => gm.isLand(t), manhattanDistFN(tile, 10))
|
||||
).size < 50
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,10 +13,7 @@ export class AllianceRequestExecution implements Execution {
|
||||
private requestor: Player;
|
||||
private recipient: Player;
|
||||
|
||||
constructor(
|
||||
private requestorID: PlayerID,
|
||||
private recipientID: PlayerID,
|
||||
) {}
|
||||
constructor(private requestorID: PlayerID, private recipientID: PlayerID) {}
|
||||
|
||||
init(mg: Game, ticks: number): void {
|
||||
this.mg = mg;
|
||||
@@ -27,9 +24,7 @@ export class AllianceRequestExecution implements Execution {
|
||||
tick(ticks: number): void {
|
||||
if (this.requestor.isAlliedWith(this.recipient)) {
|
||||
consolex.warn("already allied");
|
||||
} else if (
|
||||
this.requestor.recentOrPendingAllianceRequestWith(this.recipient)
|
||||
) {
|
||||
} else if (!this.requestor.canSendAllianceRequest(this.recipient)) {
|
||||
consolex.warn("recent or pending alliance request");
|
||||
} else {
|
||||
this.requestor.createAllianceRequest(this.recipient);
|
||||
|
||||
@@ -85,7 +85,7 @@ export class Nation {
|
||||
constructor(
|
||||
public readonly name: string,
|
||||
public readonly cell: Cell,
|
||||
public readonly strength: number,
|
||||
public readonly strength: number
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -94,10 +94,7 @@ export class Cell {
|
||||
|
||||
private strRepr: string;
|
||||
|
||||
constructor(
|
||||
public readonly x,
|
||||
public readonly y,
|
||||
) {
|
||||
constructor(public readonly x, public readonly y) {
|
||||
this.strRepr = `Cell[${this.x},${this.y}]`;
|
||||
}
|
||||
|
||||
@@ -162,7 +159,7 @@ export class PlayerInfo {
|
||||
// null if bot.
|
||||
public readonly clientID: ClientID | null,
|
||||
// TODO: make player id the small id
|
||||
public readonly id: PlayerID,
|
||||
public readonly id: PlayerID
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -267,7 +264,7 @@ export interface Player {
|
||||
allies(): Player[];
|
||||
isAlliedWith(other: Player): boolean;
|
||||
allianceWith(other: Player): MutableAlliance | null;
|
||||
recentOrPendingAllianceRequestWith(other: Player): boolean;
|
||||
canSendAllianceRequest(other: Player): boolean;
|
||||
breakAlliance(alliance: Alliance): void;
|
||||
createAllianceRequest(recipient: Player): AllianceRequest;
|
||||
|
||||
@@ -333,7 +330,7 @@ export interface Game extends GameMap {
|
||||
displayMessage(
|
||||
message: string,
|
||||
type: MessageType,
|
||||
playerID: PlayerID | null,
|
||||
playerID: PlayerID | null
|
||||
): void;
|
||||
|
||||
// Nations
|
||||
|
||||
+42
-33
@@ -44,10 +44,7 @@ interface Target {
|
||||
}
|
||||
|
||||
class Donation {
|
||||
constructor(
|
||||
public readonly recipient: Player,
|
||||
public readonly tick: Tick,
|
||||
) {}
|
||||
constructor(public readonly recipient: Player, public readonly tick: Tick) {}
|
||||
}
|
||||
|
||||
export class PlayerImpl implements Player {
|
||||
@@ -82,7 +79,7 @@ export class PlayerImpl implements Player {
|
||||
private mg: GameImpl,
|
||||
private _smallID: number,
|
||||
private readonly playerInfo: PlayerInfo,
|
||||
startPopulation: number,
|
||||
startPopulation: number
|
||||
) {
|
||||
this._name = playerInfo.name;
|
||||
this._targetTroopRatio = 1;
|
||||
@@ -178,7 +175,7 @@ export class PlayerImpl implements Player {
|
||||
const owner = this.mg.map().ownerID(neighbor);
|
||||
if (owner != this.smallID()) {
|
||||
ns.add(
|
||||
this.mg.playerBySmallID(owner) as PlayerImpl | TerraNulliusImpl,
|
||||
this.mg.playerBySmallID(owner) as PlayerImpl | TerraNulliusImpl
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -224,7 +221,7 @@ export class PlayerImpl implements Player {
|
||||
|
||||
alliances(): MutableAlliance[] {
|
||||
return this.mg.alliances_.filter(
|
||||
(a) => a.requestor() == this || a.recipient() == this,
|
||||
(a) => a.requestor() == this || a.recipient() == this
|
||||
);
|
||||
}
|
||||
|
||||
@@ -244,18 +241,26 @@ export class PlayerImpl implements Player {
|
||||
return null;
|
||||
}
|
||||
return this.alliances().find(
|
||||
(a) => a.recipient() == other || a.requestor() == other,
|
||||
(a) => a.recipient() == other || a.requestor() == other
|
||||
);
|
||||
}
|
||||
|
||||
recentOrPendingAllianceRequestWith(other: Player): boolean {
|
||||
canSendAllianceRequest(other: Player): boolean {
|
||||
if (other == this) {
|
||||
return false;
|
||||
}
|
||||
if (this.isAlliedWith(other)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const hasPending =
|
||||
this.incomingAllianceRequests().find((ar) => ar.requestor() == other) !=
|
||||
null ||
|
||||
this.outgoingAllianceRequests().find((ar) => ar.recipient() == other) !=
|
||||
null;
|
||||
|
||||
if (hasPending) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const recent = this.pastOutgoingAllianceRequests
|
||||
@@ -263,12 +268,12 @@ export class PlayerImpl implements Player {
|
||||
.sort((a, b) => b.createdAt() - a.createdAt());
|
||||
|
||||
if (recent.length == 0) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
const delta = this.mg.ticks() - recent[0].createdAt();
|
||||
|
||||
return delta < this.mg.config().allianceRequestCooldown();
|
||||
return delta >= this.mg.config().allianceRequestCooldown();
|
||||
}
|
||||
|
||||
breakAlliance(alliance: Alliance): void {
|
||||
@@ -362,7 +367,7 @@ export class PlayerImpl implements Player {
|
||||
targets(): PlayerImpl[] {
|
||||
return this.targets_
|
||||
.filter(
|
||||
(t) => this.mg.ticks() - t.tick < this.mg.config().targetDuration(),
|
||||
(t) => this.mg.ticks() - t.tick < this.mg.config().targetDuration()
|
||||
)
|
||||
.map((t) => t.target as PlayerImpl);
|
||||
}
|
||||
@@ -394,7 +399,7 @@ export class PlayerImpl implements Player {
|
||||
.filter(
|
||||
(e) =>
|
||||
this.mg.ticks() - e.createdAt <
|
||||
this.mg.config().emojiMessageDuration(),
|
||||
this.mg.config().emojiMessageDuration()
|
||||
)
|
||||
.sort((a, b) => b.createdAt - a.createdAt);
|
||||
}
|
||||
@@ -403,7 +408,7 @@ export class PlayerImpl implements Player {
|
||||
const recipientID =
|
||||
recipient == AllPlayers ? AllPlayers : recipient.smallID();
|
||||
const prevMsgs = this.outgoingEmojis_.filter(
|
||||
(msg) => msg.recipientID == recipientID,
|
||||
(msg) => msg.recipientID == recipientID
|
||||
);
|
||||
for (const msg of prevMsgs) {
|
||||
if (
|
||||
@@ -439,12 +444,12 @@ export class PlayerImpl implements Player {
|
||||
this.mg.displayMessage(
|
||||
`Sent ${renderTroops(troops)} troops to ${recipient.name()}`,
|
||||
MessageType.INFO,
|
||||
this.id(),
|
||||
this.id()
|
||||
);
|
||||
this.mg.displayMessage(
|
||||
`Recieved ${renderTroops(troops)} troops from ${this.name()}`,
|
||||
MessageType.SUCCESS,
|
||||
recipient.id(),
|
||||
recipient.id()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -459,7 +464,7 @@ export class PlayerImpl implements Player {
|
||||
removeGold(toRemove: Gold): void {
|
||||
if (toRemove > this._gold) {
|
||||
throw Error(
|
||||
`Player ${this} does not enough gold (${toRemove} vs ${this._gold}))`,
|
||||
`Player ${this} does not enough gold (${toRemove} vs ${this._gold}))`
|
||||
);
|
||||
}
|
||||
this._gold -= toRemove;
|
||||
@@ -485,7 +490,7 @@ export class PlayerImpl implements Player {
|
||||
setTargetTroopRatio(target: number): void {
|
||||
if (target < 0 || target > 1) {
|
||||
throw new Error(
|
||||
`invalid targetTroopRatio ${target} set on player ${PlayerImpl}`,
|
||||
`invalid targetTroopRatio ${target} set on player ${PlayerImpl}`
|
||||
);
|
||||
}
|
||||
this._targetTroopRatio = target;
|
||||
@@ -517,7 +522,7 @@ export class PlayerImpl implements Player {
|
||||
}
|
||||
const prev = unit.owner();
|
||||
(prev as PlayerImpl)._units = (prev as PlayerImpl)._units.filter(
|
||||
(u) => u != unit,
|
||||
(u) => u != unit
|
||||
);
|
||||
(unit as UnitImpl)._owner = this;
|
||||
this._units.push(unit as UnitImpl);
|
||||
@@ -525,12 +530,12 @@ export class PlayerImpl implements Player {
|
||||
this.mg.displayMessage(
|
||||
`${unit.type()} captured by ${this.displayName()}`,
|
||||
MessageType.ERROR,
|
||||
prev.id(),
|
||||
prev.id()
|
||||
);
|
||||
this.mg.displayMessage(
|
||||
`Captured ${unit.type()} from ${prev.displayName()}`,
|
||||
MessageType.SUCCESS,
|
||||
this.id(),
|
||||
this.id()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -542,7 +547,7 @@ export class PlayerImpl implements Player {
|
||||
spawnTile,
|
||||
troops,
|
||||
this.mg.nextUnitID(),
|
||||
this,
|
||||
this
|
||||
);
|
||||
this._units.push(b);
|
||||
this.removeGold(cost);
|
||||
@@ -597,7 +602,7 @@ export class PlayerImpl implements Player {
|
||||
.filter((t) => this.mg.owner(t) == this && this.mg.isOceanShore(t))
|
||||
.sort(
|
||||
(a, b) =>
|
||||
this.mg.manhattanDist(a, tile) - this.mg.manhattanDist(b, tile),
|
||||
this.mg.manhattanDist(a, tile) - this.mg.manhattanDist(b, tile)
|
||||
);
|
||||
if (spawns.length == 0) {
|
||||
return false;
|
||||
@@ -613,12 +618,12 @@ export class PlayerImpl implements Player {
|
||||
.filter(
|
||||
(u) =>
|
||||
this.mg.manhattanDist(u.tile(), tile) <
|
||||
this.mg.config().boatMaxDistance(),
|
||||
this.mg.config().boatMaxDistance()
|
||||
)
|
||||
.sort(
|
||||
(a, b) =>
|
||||
this.mg.manhattanDist(a.tile(), tile) -
|
||||
this.mg.manhattanDist(b.tile(), tile),
|
||||
this.mg.manhattanDist(b.tile(), tile)
|
||||
);
|
||||
if (spawns.length == 0) {
|
||||
return false;
|
||||
@@ -646,7 +651,7 @@ export class PlayerImpl implements Player {
|
||||
|
||||
tradeShipSpawn(targetTile: TileRef): TileRef | false {
|
||||
const spawns = this.units(UnitType.Port).filter(
|
||||
(u) => u.tile() == targetTile,
|
||||
(u) => u.tile() == targetTile
|
||||
);
|
||||
if (spawns.length == 0) {
|
||||
return false;
|
||||
@@ -664,7 +669,11 @@ export class PlayerImpl implements Player {
|
||||
);
|
||||
}
|
||||
toString(): string {
|
||||
return `Player:{name:${this.info().name},clientID:${this.info().clientID},isAlive:${this.isAlive()},troops:${this._troops},numTileOwned:${this.numTilesOwned()}}]`;
|
||||
return `Player:{name:${this.info().name},clientID:${
|
||||
this.info().clientID
|
||||
},isAlive:${this.isAlive()},troops:${
|
||||
this._troops
|
||||
},numTileOwned:${this.numTilesOwned()}}]`;
|
||||
}
|
||||
|
||||
public playerProfile(): PlayerProfile {
|
||||
@@ -673,7 +682,7 @@ export class PlayerImpl implements Player {
|
||||
this.allRelationsSorted().map(({ player, relation }) => [
|
||||
player.smallID(),
|
||||
relation,
|
||||
]),
|
||||
])
|
||||
),
|
||||
alliances: this.alliances().map((a) => a.other(this).smallID()),
|
||||
};
|
||||
@@ -717,8 +726,8 @@ export class PlayerImpl implements Player {
|
||||
tile,
|
||||
andFN(
|
||||
(gm, t) => gm.ownerID(t) == gm.ownerID(tile) && gm.isLand(t),
|
||||
manhattanDistFN(tile, 25),
|
||||
),
|
||||
manhattanDistFN(tile, 25)
|
||||
)
|
||||
)) {
|
||||
if (this.mg.isOceanShore(t)) {
|
||||
nearOcean = true;
|
||||
@@ -759,8 +768,8 @@ export class PlayerImpl implements Player {
|
||||
tile,
|
||||
andFN(
|
||||
(gm, t) => !gm.hasOwner(t) && gm.isLand(t),
|
||||
manhattanDistFN(tile, 200),
|
||||
),
|
||||
manhattanDistFN(tile, 200)
|
||||
)
|
||||
)) {
|
||||
for (const n of this.mg.neighbors(t)) {
|
||||
if (this.mg.owner(n) == this) {
|
||||
|
||||
Reference in New Issue
Block a user