mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-24 10:45:04 +00:00
fix
This commit is contained in:
@@ -13,7 +13,7 @@ export const TokenPayloadSchema = z.object({
|
||||
.refine(
|
||||
(val) => {
|
||||
const uuid = base64urlToUuid(val);
|
||||
return uuid != null;
|
||||
return !!uuid;
|
||||
},
|
||||
{
|
||||
message: "Invalid base64-encoded UUID",
|
||||
@@ -31,7 +31,7 @@ export const TokenPayloadSchema = z.object({
|
||||
rol: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((val) => val.split(",")),
|
||||
.transform((val) => (val ?? "").split(",")),
|
||||
});
|
||||
export type TokenPayload = z.infer<typeof TokenPayloadSchema>;
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ export async function createGameRunner(
|
||||
(p) =>
|
||||
new PlayerInfo(
|
||||
p.flag,
|
||||
p.clientID == clientID
|
||||
p.clientID === clientID
|
||||
? sanitize(p.username)
|
||||
: fixProfaneUsername(sanitize(p.username)),
|
||||
PlayerType.Human,
|
||||
|
||||
+1
-1
@@ -319,4 +319,4 @@ export const emojiTable: string[][] = [
|
||||
["💰", "⚓", "⛵", "🏡", "🛡️"],
|
||||
];
|
||||
// 2d to 1d array
|
||||
export const flattenedEmojiTable: string[] = [].concat(...emojiTable);
|
||||
export const flattenedEmojiTable: string[] = emojiTable.flat();
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { MutableAlliance, Player, Tick } from "./Game";
|
||||
import { GameImpl } from "./GameImpl";
|
||||
import { PlayerImpl } from "./PlayerImpl";
|
||||
import { Game, MutableAlliance, Player, Tick } from "./Game";
|
||||
|
||||
export class AllianceImpl implements MutableAlliance {
|
||||
constructor(
|
||||
private readonly mg: GameImpl,
|
||||
readonly requestor_: PlayerImpl,
|
||||
readonly recipient_: PlayerImpl,
|
||||
private readonly mg: Game,
|
||||
readonly requestor_: Player,
|
||||
readonly recipient_: Player,
|
||||
readonly createdAtTick_: Tick,
|
||||
) {}
|
||||
|
||||
other(player: Player): PlayerImpl {
|
||||
other(player: Player): Player {
|
||||
if (this.requestor_ === player) {
|
||||
return this.recipient_;
|
||||
}
|
||||
|
||||
@@ -348,10 +348,10 @@ export interface Unit {
|
||||
ticksLeftInCooldown(cooldownDuration: number): Tick;
|
||||
isCooldown(): boolean;
|
||||
setDstPort(dstPort: Unit): void;
|
||||
dstPort(): Unit; // Only for trade ships
|
||||
dstPort(): Unit | null; // Only for trade ships
|
||||
setSafeFromPirates(): void; // Only for trade ships
|
||||
isSafeFromPirates(): boolean; // Only for trade ships
|
||||
detonationDst(): TileRef; // Only for nukes
|
||||
detonationDst(): TileRef | null; // Only for nukes
|
||||
|
||||
setMoveTarget(cell: TileRef | null): void;
|
||||
moveTarget(): TileRef | null;
|
||||
@@ -501,6 +501,7 @@ export interface Player {
|
||||
}
|
||||
|
||||
export interface Game extends GameMap {
|
||||
expireAlliance(alliance: Alliance);
|
||||
// Map & Dimensions
|
||||
isOnMap(cell: Cell): boolean;
|
||||
width(): number;
|
||||
|
||||
@@ -36,7 +36,6 @@ import { StatsImpl } from "./StatsImpl";
|
||||
import { assignTeams } from "./TeamAssignment";
|
||||
import { TerraNulliusImpl } from "./TerraNulliusImpl";
|
||||
import { UnitGrid } from "./UnitGrid";
|
||||
import { UnitImpl } from "./UnitImpl";
|
||||
|
||||
export function createGame(
|
||||
humans: PlayerInfo[],
|
||||
@@ -119,7 +118,7 @@ export class GameImpl implements Game {
|
||||
}
|
||||
|
||||
private addPlayers() {
|
||||
if (this.config().gameConfig().gameMode != GameMode.Team) {
|
||||
if (this.config().gameConfig().gameMode !== GameMode.Team) {
|
||||
this._humans.forEach((p) => this.addPlayer(p));
|
||||
this._nations.forEach((n) => this.addPlayer(n.playerInfo));
|
||||
return;
|
||||
@@ -182,7 +181,7 @@ export class GameImpl implements Game {
|
||||
});
|
||||
}
|
||||
|
||||
units(...types: UnitType[]): UnitImpl[] {
|
||||
units(...types: UnitType[]): Unit[] {
|
||||
return Array.from(this._players.values()).flatMap((p) => p.units(...types));
|
||||
}
|
||||
unitInfo(type: UnitType): UnitInfo {
|
||||
@@ -619,11 +618,11 @@ export class GameImpl implements Game {
|
||||
category: string,
|
||||
variables: Record<string, string> = {},
|
||||
playerID: PlayerID | null,
|
||||
isFrom: boolean | null = null,
|
||||
isFrom: boolean,
|
||||
recipient: string,
|
||||
): void {
|
||||
let id = null;
|
||||
if (playerID != null) {
|
||||
let id: number | null = null;
|
||||
if (playerID !== null) {
|
||||
id = this.player(playerID).smallID();
|
||||
}
|
||||
this.addUpdate({
|
||||
@@ -632,7 +631,7 @@ export class GameImpl implements Game {
|
||||
category: category,
|
||||
variables: variables,
|
||||
playerID: id,
|
||||
isFrom: isFrom,
|
||||
isFrom,
|
||||
recipient: recipient,
|
||||
});
|
||||
}
|
||||
|
||||
+19
-20
@@ -57,7 +57,7 @@ export class UnitView {
|
||||
}
|
||||
|
||||
lastTile(): TileRef {
|
||||
if (this.lastPos.length == 0) {
|
||||
if (this.lastPos.length === 0) {
|
||||
return this.data.pos;
|
||||
}
|
||||
return this.lastPos[0];
|
||||
@@ -89,7 +89,7 @@ export class UnitView {
|
||||
return this.data.isActive;
|
||||
}
|
||||
hasHealth(): boolean {
|
||||
return this.data.health != undefined;
|
||||
return this.data.health !== undefined;
|
||||
}
|
||||
health(): number {
|
||||
return this.data.health ?? 0;
|
||||
@@ -98,7 +98,7 @@ export class UnitView {
|
||||
return this.data.constructionType;
|
||||
}
|
||||
dstPortId(): number | undefined {
|
||||
if (this.type() != UnitType.TradeShip) {
|
||||
if (this.type() !== UnitType.TradeShip) {
|
||||
throw Error("Must be a trade ship");
|
||||
}
|
||||
return this.data.dstPortId;
|
||||
@@ -110,7 +110,7 @@ export class UnitView {
|
||||
return this.data.detonationDst;
|
||||
}
|
||||
warshipTargetId(): number | undefined {
|
||||
if (this.type() != UnitType.Warship) {
|
||||
if (this.type() !== UnitType.Warship) {
|
||||
throw Error("Must be a warship");
|
||||
}
|
||||
return this.data.warshipTargetId;
|
||||
@@ -132,13 +132,11 @@ export class PlayerView {
|
||||
public data: PlayerUpdate,
|
||||
public nameData: NameViewData,
|
||||
) {
|
||||
if (data.clientID == game.myClientID()) {
|
||||
if (data.clientID === game.myClientID()) {
|
||||
this.anonymousName = this.data.name;
|
||||
} else {
|
||||
this.anonymousName = createRandomName(
|
||||
this.data.name,
|
||||
this.data.playerType,
|
||||
);
|
||||
this.anonymousName =
|
||||
createRandomName(this.data.name, this.data.playerType) ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +163,7 @@ export class PlayerView {
|
||||
units(...types: UnitType[]): UnitView[] {
|
||||
return this.game
|
||||
.units(...types)
|
||||
.filter((u) => u.owner().smallID() == this.smallID());
|
||||
.filter((u) => u.owner().smallID() === this.smallID());
|
||||
}
|
||||
|
||||
nameLocation(): NameViewData {
|
||||
@@ -189,7 +187,7 @@ export class PlayerView {
|
||||
: this.data.name;
|
||||
}
|
||||
|
||||
clientID(): ClientID {
|
||||
clientID(): ClientID | null {
|
||||
return this.data.clientID;
|
||||
}
|
||||
id(): PlayerID {
|
||||
@@ -237,11 +235,11 @@ export class PlayerView {
|
||||
}
|
||||
|
||||
isAlliedWith(other: PlayerView): boolean {
|
||||
return this.data.allies.some((n) => other.smallID() == n);
|
||||
return this.data.allies.some((n) => other.smallID() === n);
|
||||
}
|
||||
|
||||
isOnSameTeam(other: PlayerView): boolean {
|
||||
return this.data.team != null && this.data.team == other.data.team;
|
||||
return this.data.team !== undefined && this.data.team === other.data.team;
|
||||
}
|
||||
|
||||
isFriendly(other: PlayerView): boolean {
|
||||
@@ -249,7 +247,7 @@ export class PlayerView {
|
||||
}
|
||||
|
||||
isRequestingAllianceWith(other: PlayerView) {
|
||||
return this.data.outgoingAllianceRequests.some((id) => other.id() == id);
|
||||
return this.data.outgoingAllianceRequests.some((id) => other.id() === id);
|
||||
}
|
||||
|
||||
hasEmbargoAgainst(other: PlayerView): boolean {
|
||||
@@ -400,7 +398,7 @@ export class GameView implements GameMap {
|
||||
}
|
||||
|
||||
myPlayer(): PlayerView | null {
|
||||
if (this._myPlayer == null) {
|
||||
if (this._myPlayer === null) {
|
||||
this._myPlayer = this.playerByClientID(this._myClientID);
|
||||
}
|
||||
return this._myPlayer;
|
||||
@@ -419,7 +417,7 @@ export class GameView implements GameMap {
|
||||
}
|
||||
|
||||
playerBySmallID(id: number): PlayerView | TerraNullius {
|
||||
if (id == 0) {
|
||||
if (id === 0) {
|
||||
return new TerraNulliusImpl();
|
||||
}
|
||||
const playerId = this.smallIDToID.get(id);
|
||||
@@ -431,9 +429,10 @@ export class GameView implements GameMap {
|
||||
|
||||
playerByClientID(id: ClientID): PlayerView | null {
|
||||
const player =
|
||||
Array.from(this._players.values()).filter((p) => p.clientID() == id)[0] ??
|
||||
null;
|
||||
if (player == null) {
|
||||
Array.from(this._players.values()).filter(
|
||||
(p) => p.clientID() === id,
|
||||
)[0] ?? null;
|
||||
if (player === null) {
|
||||
return null;
|
||||
}
|
||||
return player;
|
||||
@@ -459,7 +458,7 @@ export class GameView implements GameMap {
|
||||
return this._config;
|
||||
}
|
||||
units(...types: UnitType[]): UnitView[] {
|
||||
if (types.length == 0) {
|
||||
if (types.length === 0) {
|
||||
return Array.from(this._units.values()).filter((u) => u.isActive());
|
||||
}
|
||||
return Array.from(this._units.values()).filter(
|
||||
|
||||
+54
-59
@@ -41,7 +41,6 @@ import {
|
||||
import { GameImpl } from "./GameImpl";
|
||||
import { andFN, manhattanDistFN, TileRef } from "./GameMap";
|
||||
import { AttackUpdate, GameUpdateType, PlayerUpdate } from "./GameUpdates";
|
||||
import { TerraNulliusImpl } from "./TerraNulliusImpl";
|
||||
import {
|
||||
bestShoreDeploymentSource,
|
||||
canBuildTransportShip,
|
||||
@@ -77,7 +76,7 @@ export class PlayerImpl implements Player {
|
||||
|
||||
public _borderTiles: Set<TileRef> = new Set();
|
||||
|
||||
public _units: UnitImpl[] = [];
|
||||
public _units: Unit[] = [];
|
||||
public _tiles: Set<TileRef> = new Set();
|
||||
|
||||
private _flag: string | undefined;
|
||||
@@ -203,8 +202,8 @@ export class PlayerImpl implements Player {
|
||||
return this.playerInfo.clan;
|
||||
}
|
||||
|
||||
units(...types: UnitType[]): UnitImpl[] {
|
||||
if (types.length == 0) {
|
||||
units(...types: UnitType[]): Unit[] {
|
||||
if (types.length === 0) {
|
||||
return this._units;
|
||||
}
|
||||
const ts = new Set(types);
|
||||
@@ -215,7 +214,7 @@ export class PlayerImpl implements Player {
|
||||
const units = this.units(type);
|
||||
units.push(
|
||||
...this.units(UnitType.Construction).filter(
|
||||
(u) => u.constructionType() == type,
|
||||
(u) => u.constructionType() === type,
|
||||
),
|
||||
);
|
||||
return units;
|
||||
@@ -224,7 +223,7 @@ export class PlayerImpl implements Player {
|
||||
sharesBorderWith(other: Player | TerraNullius): boolean {
|
||||
for (const border of this._borderTiles) {
|
||||
for (const neighbor of this.mg.map().neighbors(border)) {
|
||||
if (this.mg.map().ownerID(neighbor) == other.smallID()) {
|
||||
if (this.mg.map().ownerID(neighbor) === other.smallID()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -249,10 +248,8 @@ export class PlayerImpl implements Player {
|
||||
for (const neighbor of this.mg.map().neighbors(border)) {
|
||||
if (this.mg.map().isLand(neighbor)) {
|
||||
const owner = this.mg.map().ownerID(neighbor);
|
||||
if (owner != this.smallID()) {
|
||||
ns.add(
|
||||
this.mg.playerBySmallID(owner) as PlayerImpl | TerraNulliusImpl,
|
||||
);
|
||||
if (owner !== this.smallID()) {
|
||||
ns.add(this.mg.playerBySmallID(owner) as Player | TerraNullius);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,7 +267,7 @@ export class PlayerImpl implements Player {
|
||||
this.mg.conquer(this, tile);
|
||||
}
|
||||
orderRetreat(id: string) {
|
||||
const attack = this._outgoingAttacks.filter((attack) => attack.id() == id);
|
||||
const attack = this._outgoingAttacks.filter((attack) => attack.id() === id);
|
||||
if (!attack || !attack[0]) {
|
||||
consolex.warn(`Didn't find outgoing attack with id ${id}`);
|
||||
return;
|
||||
@@ -278,7 +275,7 @@ export class PlayerImpl implements Player {
|
||||
attack[0].orderRetreat();
|
||||
}
|
||||
executeRetreat(id: string): void {
|
||||
const attack = this._outgoingAttacks.filter((attack) => attack.id() == id);
|
||||
const attack = this._outgoingAttacks.filter((attack) => attack.id() === id);
|
||||
// Execution is delayed so it's not an error that the attack does not exist.
|
||||
if (!attack || !attack[0]) {
|
||||
return;
|
||||
@@ -286,7 +283,7 @@ export class PlayerImpl implements Player {
|
||||
attack[0].executeRetreat();
|
||||
}
|
||||
relinquish(tile: TileRef) {
|
||||
if (this.mg.owner(tile) != this) {
|
||||
if (this.mg.owner(tile) !== this) {
|
||||
throw new Error(`Cannot relinquish tile not owned by this player`);
|
||||
}
|
||||
this.mg.relinquish(tile);
|
||||
@@ -307,16 +304,16 @@ export class PlayerImpl implements Player {
|
||||
}
|
||||
|
||||
incomingAllianceRequests(): AllianceRequest[] {
|
||||
return this.mg.allianceRequests.filter((ar) => ar.recipient() == this);
|
||||
return this.mg.allianceRequests.filter((ar) => ar.recipient() === this);
|
||||
}
|
||||
|
||||
outgoingAllianceRequests(): AllianceRequest[] {
|
||||
return this.mg.allianceRequests.filter((ar) => ar.requestor() == this);
|
||||
return this.mg.allianceRequests.filter((ar) => ar.requestor() === this);
|
||||
}
|
||||
|
||||
alliances(): MutableAlliance[] {
|
||||
return this.mg.alliances_.filter(
|
||||
(a) => a.requestor() == this || a.recipient() == this,
|
||||
(a) => a.requestor() === this || a.recipient() === this,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -325,25 +322,25 @@ export class PlayerImpl implements Player {
|
||||
}
|
||||
|
||||
isAlliedWith(other: Player): boolean {
|
||||
if (other == this) {
|
||||
if (other === this) {
|
||||
return false;
|
||||
}
|
||||
return this.allianceWith(other) != null;
|
||||
return this.allianceWith(other) !== null;
|
||||
}
|
||||
|
||||
allianceWith(other: Player): MutableAlliance | null {
|
||||
if (other == this) {
|
||||
if (other === this) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
this.alliances().find(
|
||||
(a) => a.recipient() == other || a.requestor() == other,
|
||||
(a) => a.recipient() === other || a.requestor() === other,
|
||||
) ?? null
|
||||
);
|
||||
}
|
||||
|
||||
canSendAllianceRequest(other: Player): boolean {
|
||||
if (other == this) {
|
||||
if (other === this) {
|
||||
return false;
|
||||
}
|
||||
if (this.isFriendly(other)) {
|
||||
@@ -351,20 +348,18 @@ export class PlayerImpl implements Player {
|
||||
}
|
||||
|
||||
const hasPending =
|
||||
this.incomingAllianceRequests().find((ar) => ar.requestor() == other) !=
|
||||
null ||
|
||||
this.outgoingAllianceRequests().find((ar) => ar.recipient() == other) !=
|
||||
null;
|
||||
this.incomingAllianceRequests().some((ar) => ar.requestor() === other) ||
|
||||
this.outgoingAllianceRequests().some((ar) => ar.recipient() === other);
|
||||
|
||||
if (hasPending) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const recent = this.pastOutgoingAllianceRequests
|
||||
.filter((ar) => ar.recipient() == other)
|
||||
.filter((ar) => ar.recipient() === other)
|
||||
.sort((a, b) => b.createdAt() - a.createdAt());
|
||||
|
||||
if (recent.length == 0) {
|
||||
if (recent.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -396,7 +391,7 @@ export class PlayerImpl implements Player {
|
||||
}
|
||||
|
||||
relation(other: Player): Relation {
|
||||
if (other == this) {
|
||||
if (other === this) {
|
||||
throw new Error(`cannot get relation with self: ${this}`);
|
||||
}
|
||||
const relation = this.relations.get(other) ?? 0;
|
||||
@@ -426,7 +421,7 @@ export class PlayerImpl implements Player {
|
||||
}
|
||||
|
||||
updateRelation(other: Player, delta: number): void {
|
||||
if (other == this) {
|
||||
if (other === this) {
|
||||
throw new Error(`cannot update relation with self: ${this}`);
|
||||
}
|
||||
const relation = this.relations.get(other) ?? 0;
|
||||
@@ -447,7 +442,7 @@ export class PlayerImpl implements Player {
|
||||
}
|
||||
|
||||
canTarget(other: Player): boolean {
|
||||
if (this == other) {
|
||||
if (this === other) {
|
||||
return false;
|
||||
}
|
||||
if (this.isFriendly(other)) {
|
||||
@@ -483,13 +478,13 @@ export class PlayerImpl implements Player {
|
||||
}
|
||||
|
||||
sendEmoji(recipient: Player | typeof AllPlayers, emoji: string): void {
|
||||
if (recipient == this) {
|
||||
if (recipient === this) {
|
||||
throw Error(`Cannot send emoji to oneself: ${this}`);
|
||||
}
|
||||
const msg: EmojiMessage = {
|
||||
message: emoji,
|
||||
senderID: this.smallID(),
|
||||
recipientID: recipient == AllPlayers ? recipient : recipient.smallID(),
|
||||
recipientID: recipient === AllPlayers ? recipient : recipient.smallID(),
|
||||
createdAt: this.mg.ticks(),
|
||||
};
|
||||
this.outgoingEmojis_.push(msg);
|
||||
@@ -508,9 +503,9 @@ export class PlayerImpl implements Player {
|
||||
|
||||
canSendEmoji(recipient: Player | typeof AllPlayers): boolean {
|
||||
const recipientID =
|
||||
recipient == AllPlayers ? AllPlayers : recipient.smallID();
|
||||
recipient === AllPlayers ? AllPlayers : recipient.smallID();
|
||||
const prevMsgs = this.outgoingEmojis_.filter(
|
||||
(msg) => msg.recipientID == recipientID,
|
||||
(msg) => msg.recipientID === recipientID,
|
||||
);
|
||||
for (const msg of prevMsgs) {
|
||||
if (
|
||||
@@ -528,7 +523,7 @@ export class PlayerImpl implements Player {
|
||||
return false;
|
||||
}
|
||||
for (const donation of this.sentDonations) {
|
||||
if (donation.recipient == recipient) {
|
||||
if (donation.recipient === recipient) {
|
||||
if (
|
||||
this.mg.ticks() - donation.tick <
|
||||
this.mg.config().donateCooldown()
|
||||
@@ -576,7 +571,7 @@ export class PlayerImpl implements Player {
|
||||
canTrade(other: Player): boolean {
|
||||
const embargo =
|
||||
other.hasEmbargoAgainst(this) || this.hasEmbargoAgainst(other);
|
||||
return !embargo && other.id() != this.id();
|
||||
return !embargo && other.id() !== this.id();
|
||||
}
|
||||
|
||||
addEmbargo(other: PlayerID): void {
|
||||
@@ -590,7 +585,7 @@ export class PlayerImpl implements Player {
|
||||
tradingPartners(): Player[] {
|
||||
return this.mg
|
||||
.players()
|
||||
.filter((other) => other != this && this.canTrade(other));
|
||||
.filter((other) => other !== this && this.canTrade(other));
|
||||
}
|
||||
|
||||
team(): Team | null {
|
||||
@@ -598,16 +593,16 @@ export class PlayerImpl implements Player {
|
||||
}
|
||||
|
||||
isOnSameTeam(other: Player): boolean {
|
||||
if (other == this) {
|
||||
if (other === this) {
|
||||
return false;
|
||||
}
|
||||
if (this.team() == null || other.team() == null) {
|
||||
if (this.team() === null || other.team() === null) {
|
||||
return false;
|
||||
}
|
||||
if (this.team() == ColoredTeams.Bot || other.team() == ColoredTeams.Bot) {
|
||||
if (this.team() === ColoredTeams.Bot || other.team() === ColoredTeams.Bot) {
|
||||
return false;
|
||||
}
|
||||
return this._team == other.team();
|
||||
return this._team === other.team();
|
||||
}
|
||||
|
||||
isFriendly(other: Player): boolean {
|
||||
@@ -678,15 +673,15 @@ export class PlayerImpl implements Player {
|
||||
}
|
||||
|
||||
captureUnit(unit: Unit): void {
|
||||
if (unit.owner() == this) {
|
||||
if (unit.owner() === this) {
|
||||
throw new Error(`Cannot capture unit, ${this} already owns ${unit}`);
|
||||
}
|
||||
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);
|
||||
this._units.push(unit);
|
||||
this.mg.addUpdate(unit.toUpdate());
|
||||
this.mg.displayMessage(
|
||||
`${unit.type()} captured by ${this.displayName()}`,
|
||||
@@ -704,7 +699,7 @@ export class PlayerImpl implements Player {
|
||||
type: T,
|
||||
spawnTile: TileRef,
|
||||
params: UnitParams<T>,
|
||||
): UnitImpl {
|
||||
): Unit {
|
||||
if (this.mg.config().isUnitDisabled(type)) {
|
||||
throw new Error(
|
||||
`Attempted to build disabled unit ${type} at tile ${spawnTile} by player ${this.name()}`,
|
||||
@@ -722,7 +717,7 @@ export class PlayerImpl implements Player {
|
||||
);
|
||||
this._units.push(b);
|
||||
this.removeGold(cost);
|
||||
this.removeTroops("troops" in params ? params.troops : 0);
|
||||
this.removeTroops("troops" in params ? (params.troops ?? 0) : 0);
|
||||
this.mg.addUpdate(b.toUpdate());
|
||||
this.mg.addUnit(b);
|
||||
|
||||
@@ -801,7 +796,7 @@ export class PlayerImpl implements Player {
|
||||
return !silo.isCooldown();
|
||||
})
|
||||
.sort(distSortUnit(this.mg, tile));
|
||||
if (spawns.length == 0) {
|
||||
if (spawns.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return spawns[0].tile();
|
||||
@@ -814,7 +809,7 @@ export class PlayerImpl implements Player {
|
||||
manhattanDistFN(tile, this.mg.config().radiusPortSpawn()),
|
||||
),
|
||||
)
|
||||
.filter((t) => this.mg.owner(t) == this && this.mg.isOceanShore(t))
|
||||
.filter((t) => this.mg.owner(t) === this && this.mg.isOceanShore(t))
|
||||
.sort(
|
||||
(a, b) =>
|
||||
this.mg.manhattanDist(a, tile) - this.mg.manhattanDist(b, tile),
|
||||
@@ -839,7 +834,7 @@ export class PlayerImpl implements Player {
|
||||
this.mg.manhattanDist(a.tile(), tile) -
|
||||
this.mg.manhattanDist(b.tile(), tile),
|
||||
);
|
||||
if (spawns.length == 0) {
|
||||
if (spawns.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return spawns[0].tile();
|
||||
@@ -850,14 +845,14 @@ export class PlayerImpl implements Player {
|
||||
validTiles: TileRef[] | null = null,
|
||||
): TileRef | false {
|
||||
const tiles = validTiles ?? this.validStructureSpawnTiles(tile);
|
||||
if (tiles.length == 0) {
|
||||
if (tiles.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return tiles[0];
|
||||
}
|
||||
|
||||
private validStructureSpawnTiles(tile: TileRef): TileRef[] {
|
||||
if (this.mg.owner(tile) != this) {
|
||||
if (this.mg.owner(tile) !== this) {
|
||||
return [];
|
||||
}
|
||||
const searchRadius = 15;
|
||||
@@ -872,7 +867,7 @@ export class PlayerImpl implements Player {
|
||||
const nearbyTiles = this.mg.bfs(tile, (gm, t) => {
|
||||
return (
|
||||
this.mg.euclideanDistSquared(tile, t) < searchRadiusSquared &&
|
||||
gm.ownerID(t) == this.smallID()
|
||||
gm.ownerID(t) === this.smallID()
|
||||
);
|
||||
});
|
||||
const validSet: Set<TileRef> = new Set(nearbyTiles);
|
||||
@@ -897,9 +892,9 @@ 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) {
|
||||
if (spawns.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return spawns[0].tile();
|
||||
@@ -911,7 +906,7 @@ export class PlayerImpl implements Player {
|
||||
hash(): number {
|
||||
return (
|
||||
simpleHash(this.id()) * (this.population() + this.numTilesOwned()) +
|
||||
this._units.reduce((acc, unit) => acc + unit.hash(), 0)
|
||||
this._units.reduce((acc, unit) => acc + (unit as UnitImpl).hash(), 0)
|
||||
);
|
||||
}
|
||||
toString(): string {
|
||||
@@ -970,7 +965,7 @@ export class PlayerImpl implements Player {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.mg.owner(tile) == this) {
|
||||
if (this.mg.owner(tile) === this) {
|
||||
return false;
|
||||
}
|
||||
if (this.mg.hasOwner(tile)) {
|
||||
@@ -994,7 +989,7 @@ export class PlayerImpl implements Player {
|
||||
),
|
||||
)) {
|
||||
for (const n of this.mg.neighbors(t)) {
|
||||
if (this.mg.owner(n) == this) {
|
||||
if (this.mg.owner(n) === this) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1012,7 +1007,7 @@ export class PlayerImpl implements Player {
|
||||
tradingPorts(port: Unit): Unit[] {
|
||||
const ports = this.mg
|
||||
.players()
|
||||
.filter((p) => p != port.owner() && p.canTrade(port.owner()))
|
||||
.filter((p) => p !== port.owner() && p.canTrade(port.owner()))
|
||||
.flatMap((p) => p.units(UnitType.Port))
|
||||
.sort((p1, p2) => {
|
||||
return (
|
||||
@@ -1033,7 +1028,7 @@ export class PlayerImpl implements Player {
|
||||
// Make ally ports twice more likely by putting them again
|
||||
this.mg
|
||||
.players()
|
||||
.filter((p) => p != port.owner() && p.canTrade(port.owner()))
|
||||
.filter((p) => p !== port.owner() && p.canTrade(port.owner()))
|
||||
.filter((p) => p.isAlliedWith(port.owner()))
|
||||
.flatMap((p) => p.units(UnitType.Port))
|
||||
.forEach((p) => ports.push(p));
|
||||
|
||||
@@ -44,7 +44,7 @@ export async function genTerrainFromBin(data: string): Promise<GameMap> {
|
||||
const width = (data.charCodeAt(1) << 8) | data.charCodeAt(0);
|
||||
const height = (data.charCodeAt(3) << 8) | data.charCodeAt(2);
|
||||
|
||||
if (data.length != width * height + 4) {
|
||||
if (data.length !== width * height + 4) {
|
||||
throw new Error(
|
||||
`Invalid data: buffer size ${data.length} incorrect for ${width}x${height} terrain plus 4 bytes for dimensions.`,
|
||||
);
|
||||
|
||||
@@ -15,12 +15,12 @@ export function canBuildTransportShip(
|
||||
}
|
||||
|
||||
const dst = targetTransportTile(game, tile);
|
||||
if (dst == null) {
|
||||
if (dst === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const other = game.owner(tile);
|
||||
if (other == player) {
|
||||
if (other === player) {
|
||||
return false;
|
||||
}
|
||||
if (other.isPlayer() && player.isFriendly(other)) {
|
||||
@@ -71,7 +71,7 @@ export function canBuildTransportShip(
|
||||
);
|
||||
|
||||
for (const t of sorted) {
|
||||
if (game.owner(t) == player) {
|
||||
if (game.owner(t) === player) {
|
||||
return transportShipSpawn(game, player, t);
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ function transportShipSpawn(
|
||||
return false;
|
||||
}
|
||||
const spawn = closestShoreFromPlayer(game, player, targetTile);
|
||||
if (spawn == null) {
|
||||
if (spawn === null) {
|
||||
return false;
|
||||
}
|
||||
return spawn;
|
||||
@@ -128,7 +128,7 @@ export function closestShoreFromPlayer(
|
||||
const shoreTiles = Array.from(player.borderTiles()).filter((t) =>
|
||||
gm.isShore(t),
|
||||
);
|
||||
if (shoreTiles.length == 0) {
|
||||
if (shoreTiles.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -144,20 +144,18 @@ export function bestShoreDeploymentSource(
|
||||
player: Player,
|
||||
target: TileRef,
|
||||
): TileRef | false {
|
||||
target = targetTransportTile(gm, target);
|
||||
if (target == null) {
|
||||
return false;
|
||||
}
|
||||
const t = targetTransportTile(gm, target);
|
||||
if (t === null) return false;
|
||||
|
||||
const candidates = candidateShoreTiles(gm, player, target);
|
||||
const aStar = new MiniAStar(gm, gm.miniMap(), candidates, target, 500_000, 1);
|
||||
const candidates = candidateShoreTiles(gm, player, t);
|
||||
const aStar = new MiniAStar(gm, gm.miniMap(), candidates, t, 500_000, 1);
|
||||
const result = aStar.compute();
|
||||
if (result != PathFindResultType.Completed) {
|
||||
if (result !== PathFindResultType.Completed) {
|
||||
console.warn(`bestShoreDeploymentSource: path not found: ${result}`);
|
||||
return false;
|
||||
}
|
||||
const path = aStar.reconstructPath();
|
||||
if (path.length == 0) {
|
||||
if (path.length === 0) {
|
||||
return false;
|
||||
}
|
||||
const potential = path[0];
|
||||
@@ -165,8 +163,8 @@ export function bestShoreDeploymentSource(
|
||||
// of the potential tile to find a valid deployment point
|
||||
const neighbors = gm
|
||||
.neighbors(potential)
|
||||
.filter((n) => gm.isShore(n) && gm.owner(n) == player);
|
||||
if (neighbors.length == 0) {
|
||||
.filter((n) => gm.isShore(n) && gm.owner(n) === player);
|
||||
if (neighbors.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return neighbors[0];
|
||||
@@ -183,8 +181,8 @@ export function candidateShoreTiles(
|
||||
maxX = -Infinity,
|
||||
maxY = -Infinity;
|
||||
|
||||
let bestByManhattan: TileRef = null;
|
||||
const extremumTiles: Record<string, TileRef> = {
|
||||
let bestByManhattan: TileRef | null = null;
|
||||
const extremumTiles: Record<string, TileRef | null> = {
|
||||
minX: null,
|
||||
minY: null,
|
||||
maxX: null,
|
||||
@@ -237,7 +235,7 @@ export function candidateShoreTiles(
|
||||
extremumTiles.maxX,
|
||||
extremumTiles.maxY,
|
||||
...sampledTiles,
|
||||
].filter(Boolean);
|
||||
].filter(Boolean) as number[];
|
||||
|
||||
return candidates;
|
||||
}
|
||||
@@ -246,7 +244,7 @@ function closestShoreTN(
|
||||
gm: GameMap,
|
||||
tile: TileRef,
|
||||
searchDist: number,
|
||||
): TileRef {
|
||||
): TileRef | null {
|
||||
const tn = Array.from(
|
||||
gm.bfs(
|
||||
tile,
|
||||
@@ -255,7 +253,7 @@ function closestShoreTN(
|
||||
)
|
||||
.filter((t) => gm.isShore(t))
|
||||
.sort((a, b) => gm.manhattanDist(tile, a) - gm.manhattanDist(tile, b));
|
||||
if (tn.length == 0) {
|
||||
if (tn.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return tn[0];
|
||||
|
||||
@@ -40,7 +40,7 @@ export class ParabolaPathFinder {
|
||||
|
||||
nextTile(speed: number): TileRef | true {
|
||||
if (!this.curve) {
|
||||
return;
|
||||
throw new Error("ParabolaPathFinder not initialized");
|
||||
}
|
||||
const nextPoint = this.curve.increment(speed);
|
||||
if (!nextPoint) {
|
||||
@@ -72,14 +72,14 @@ export class AirPathFinder {
|
||||
|
||||
const ratio = Math.floor(1 + Math.abs(dstY - y) / (Math.abs(dstX - x) + 1));
|
||||
|
||||
if (this.random.chance(ratio) && x != dstX) {
|
||||
if (this.random.chance(ratio) && x !== dstX) {
|
||||
if (x < dstX) nextX++;
|
||||
else if (x > dstX) nextX--;
|
||||
} else {
|
||||
if (y < dstY) nextY++;
|
||||
else if (y > dstY) nextY--;
|
||||
}
|
||||
if (nextX == x && nextY == y) {
|
||||
if (nextX === x && nextY === y) {
|
||||
return true;
|
||||
}
|
||||
return this.mg.ref(nextX, nextY);
|
||||
@@ -111,12 +111,16 @@ export class PathFinder {
|
||||
});
|
||||
}
|
||||
|
||||
nextTile(curr: TileRef, dst: TileRef, dist: number = 1): TileResult {
|
||||
if (curr == null) {
|
||||
nextTile(
|
||||
curr: TileRef | null,
|
||||
dst: TileRef | null,
|
||||
dist: number = 1,
|
||||
): TileResult {
|
||||
if (curr === null) {
|
||||
consolex.error("curr is null");
|
||||
return { type: PathFindResultType.PathNotFound };
|
||||
}
|
||||
if (dst == null) {
|
||||
if (dst === null) {
|
||||
consolex.error("dst is null");
|
||||
return { type: PathFindResultType.PathNotFound };
|
||||
}
|
||||
@@ -160,7 +164,7 @@ export class PathFinder {
|
||||
}
|
||||
|
||||
private shouldRecompute(curr: TileRef, dst: TileRef) {
|
||||
if (this.path == null || this.curr == null || this.dst == null) {
|
||||
if (this.path === null || this.curr === null || this.dst === null) {
|
||||
return true;
|
||||
}
|
||||
const dist = this.game.manhattanDist(curr, dst);
|
||||
|
||||
@@ -123,7 +123,7 @@ export class SerialAStar implements AStar {
|
||||
private expandTileRef(current: TileRef, isForward: boolean) {
|
||||
for (const neighbor of this.gameMap.neighbors(current)) {
|
||||
if (
|
||||
neighbor != (isForward ? this.dst : this.closestSource) &&
|
||||
neighbor !== (isForward ? this.dst : this.closestSource) &&
|
||||
!this.gameMap.isWater(neighbor)
|
||||
)
|
||||
continue;
|
||||
|
||||
@@ -81,7 +81,7 @@ export class DistanceBasedBezierCurve extends CubicBezierCurve {
|
||||
private distanceLUT: Array<{ t: number; distance: number }> = [];
|
||||
private lastFoundIndex: number = 0; // To keep track of the last found index
|
||||
|
||||
increment(distance: number): Point {
|
||||
increment(distance: number): Point | null {
|
||||
this.totalDistance += distance;
|
||||
const targetDistance = Math.min(
|
||||
this.totalDistance,
|
||||
|
||||
Reference in New Issue
Block a user