This commit is contained in:
Scott Anderson
2025-05-13 03:29:33 -04:00
parent 363e4b995e
commit 60d5e8679d
13 changed files with 123 additions and 129 deletions
+2 -2
View File
@@ -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>;
+1 -1
View File
@@ -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
View File
@@ -319,4 +319,4 @@ export const emojiTable: string[][] = [
["💰", "⚓", "⛵", "🏡", "🛡️"],
];
// 2d to 1d array
export const flattenedEmojiTable: string[] = [].concat(...emojiTable);
export const flattenedEmojiTable: string[] = emojiTable.flat();
+5 -7
View File
@@ -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_;
}
+3 -2
View File
@@ -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;
+6 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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));
+1 -1
View File
@@ -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.`,
);
+18 -20
View File
@@ -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];
+11 -7
View File
@@ -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);
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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,