diff --git a/src/lib/attendance/index.ts b/src/lib/attendance/index.ts index 3e8654f..824fa5c 100644 --- a/src/lib/attendance/index.ts +++ b/src/lib/attendance/index.ts @@ -57,9 +57,10 @@ export async function setMissionAttendance( const mission = (await payload .findByID({ collection: "missions", id: missionId, depth: 0, overrideAccess: true }) - .catch(() => null)) as unknown as - | { name?: string; classification: { startDateTime: string } } - | null; + .catch(() => null)) as unknown as { + name?: string; + classification: { startDateTime: string }; + } | null; if (!mission) throw new Error("Mission not found."); if (isMissionPast(mission.classification.startDateTime)) { diff --git a/src/lib/banking/index.ts b/src/lib/banking/index.ts index 30173a2..6b3e4ef 100644 --- a/src/lib/banking/index.ts +++ b/src/lib/banking/index.ts @@ -1,4 +1,3 @@ -import type { Payload } from "payload"; import type { BankAccount, BankTransaction } from "@/payload-types"; export type BankAccountType = "treasury" | "faction" | "personal"; @@ -93,7 +92,10 @@ export async function createAccount( })) as unknown as BankAccount; } -export async function ensurePersonalAccount(payload: PayloadType, userId: number): Promise { +export async function ensurePersonalAccount( + payload: PayloadType, + userId: number, +): Promise { const existing = (await payload.find({ collection: "bank-accounts", where: { @@ -105,12 +107,14 @@ export async function ensurePersonalAccount(payload: PayloadType, userId: number })) as unknown as { docs: BankAccount[] }; if (existing.docs.length > 0) return existing.docs[0]; - const user = (await payload.findByID({ - collection: "users", - id: userId, - depth: 0, - overrideAccess: true, - }).catch(() => null)) as unknown as { username?: string; displayName?: string } | null; + const user = (await payload + .findByID({ + collection: "users", + id: userId, + depth: 0, + overrideAccess: true, + }) + .catch(() => null)) as unknown as { username?: string; displayName?: string } | null; const label = user?.displayName || user?.username || `User ${userId}`; return createAccount(payload, { diff --git a/src/lib/locker/index.ts b/src/lib/locker/index.ts index 97aa771..af8ed83 100644 --- a/src/lib/locker/index.ts +++ b/src/lib/locker/index.ts @@ -1,4 +1,3 @@ -import type { Payload } from "payload"; import type { Asset, LockerStorage } from "@/payload-types"; import type { GridDimensions } from "@/lib/logistics"; diff --git a/src/lib/locker/search.ts b/src/lib/locker/search.ts index 68a589d..880aaaa 100644 --- a/src/lib/locker/search.ts +++ b/src/lib/locker/search.ts @@ -1,10 +1,10 @@ import type { Asset, Loadout } from "@/payload-types"; import { - WARDROBE_SLOT_LAYOUT, getAssetTypeLabel, getLoadoutSlot, type LoadoutSlots, type LockerGridItem, + WARDROBE_SLOT_LAYOUT, } from "@/lib/locker"; export type LockerSearchLocationKind = "locker" | "attached" | "skin" | "loadout"; @@ -77,11 +77,14 @@ export function buildAssetStats(asset: Asset): LockerSearchStat[] { if (mag?.ammoType) stats.push({ label: "Ammo", value: mag.ammoType }); const container = asset["Container Configuration"]; - if (container?.capacityKg != null) stats.push({ label: "Capacity", value: `${container.capacityKg}kg` }); - if (container?.weightKg != null) stats.push({ label: "Weight", value: `${container.weightKg}kg` }); + if (container?.capacityKg != null) + stats.push({ label: "Capacity", value: `${container.capacityKg}kg` }); + if (container?.weightKg != null) + stats.push({ label: "Weight", value: `${container.weightKg}kg` }); const nvg = asset["Nightvision Configuration"]; - if (nvg?.nvgGeneration) stats.push({ label: "Gen", value: NVG_GEN_LABELS[nvg.nvgGeneration] ?? nvg.nvgGeneration }); + if (nvg?.nvgGeneration) + stats.push({ label: "Gen", value: NVG_GEN_LABELS[nvg.nvgGeneration] ?? nvg.nvgGeneration }); if (nvg?.nvgHasThermals) stats.push({ label: "Thermals", value: "Yes" }); const skin = asset["Skin Configuration"]; @@ -93,7 +96,8 @@ export function buildAssetStats(asset: Asset): LockerSearchStat[] { } const market = asset.marketTrading; - if (market?.Rarity) stats.push({ label: "Rarity", value: RARITY_LABELS[market.Rarity] ?? market.Rarity }); + if (market?.Rarity) + stats.push({ label: "Rarity", value: RARITY_LABELS[market.Rarity] ?? market.Rarity }); const dims = asset.storageDimensions; if (dims?.gridWidth != null && dims?.gridHeight != null) { diff --git a/src/lib/market/chatBubbles.ts b/src/lib/market/chatBubbles.ts index 7fabcbb..45e6c19 100644 --- a/src/lib/market/chatBubbles.ts +++ b/src/lib/market/chatBubbles.ts @@ -70,7 +70,10 @@ export function buildChatBubbles( const fallbackRng = negotiation ? seededRng(negotiation.id) : Math.random; if (negotiation?.status === "accepted" && !hasDialogue) { - bubbles.push({ from: "seller", text: npcDialogue("accept", undefined, undefined, fallbackRng) }); + bubbles.push({ + from: "seller", + text: npcDialogue("accept", undefined, undefined, fallbackRng), + }); } else if (negotiation?.status === "closed" && !hasDialogue) { bubbles.push({ from: "seller", diff --git a/src/lib/market/index.ts b/src/lib/market/index.ts index fa83835..c94bd7f 100644 --- a/src/lib/market/index.ts +++ b/src/lib/market/index.ts @@ -1,4 +1,3 @@ -import type { Payload } from "payload"; import type { Asset, LockerStorage, MarketListing, User } from "@/payload-types"; import { ensureLockerStorage, @@ -10,11 +9,7 @@ import { resolveAssetId, toLockerGridItems, } from "@/lib/locker"; -import { - applyTransaction, - ensurePersonalAccount, - getMainCurrencyId, -} from "@/lib/banking"; +import { applyTransaction, ensurePersonalAccount, getMainCurrencyId } from "@/lib/banking"; type PayloadType = Awaited>; @@ -65,14 +60,18 @@ export interface NegotiationRange { } /** Resolve a listing's negotiation range. Non-negotiable listings have min === desired. */ -export function negotiationRange(listing: Pick): NegotiationRange { +export function negotiationRange( + listing: Pick, +): NegotiationRange { const desired = listing.desiredPrice ?? listing.price ?? 0; const min = listing.minPrice ?? desired; return { min, desired }; } /** A listing is negotiable when the seller has set a floor below the asking price. */ -export function isNegotiable(listing: Pick): boolean { +export function isNegotiable( + listing: Pick, +): boolean { const { min, desired } = negotiationRange(listing); return min < desired; } @@ -179,7 +178,13 @@ export async function creditLockerQuantity( while (remaining > 0) { const stackAmount = Math.min(remaining, maxStack === Infinity ? remaining : maxStack); - const spot = findLockerEmptySpot(gridItems, footprint.width, footprint.height, grid.width, grid.height); + const spot = findLockerEmptySpot( + gridItems, + footprint.width, + footprint.height, + grid.width, + grid.height, + ); if (!spot) { throw new Error( `No space in buyer's locker for ${asset.name}. Needs ${footprint.width}×${footprint.height} free cells.`, @@ -266,7 +271,9 @@ export async function buyListing( } const sellerId = - typeof listing.seller === "object" && listing.seller ? listing.seller.id : (listing.seller as number | null); + typeof listing.seller === "object" && listing.seller + ? listing.seller.id + : (listing.seller as number | null); if (sellerId != null && sellerId === buyer.id) { throw new Error("You cannot buy your own listing."); } @@ -343,10 +350,17 @@ export async function expireListing( listing: MarketListing, ): Promise { const sellerId = - typeof listing.seller === "object" && listing.seller ? listing.seller.id : (listing.seller as number | null); + typeof listing.seller === "object" && listing.seller + ? listing.seller.id + : (listing.seller as number | null); if (sellerId != null && !listing.isAutoGenerated) { - await creditLockerQuantity(payload, sellerId, resolveAssetId(listing.asset) as number, listing.quantity); + await creditLockerQuantity( + payload, + sellerId, + resolveAssetId(listing.asset) as number, + listing.quantity, + ); } return (await payload.update({ diff --git a/src/lib/market/negotiations.ts b/src/lib/market/negotiations.ts index cb935a2..b3090c9 100644 --- a/src/lib/market/negotiations.ts +++ b/src/lib/market/negotiations.ts @@ -98,7 +98,8 @@ export function npcResponseToOffer( amount > lastBuyerOffer && amount - lastBuyerOffer < desired * NPC_PATIENCE.stallRatio; - if (amount >= stance) return { action: "accept", amount: Math.min(amount, desired), reason: good(amount) }; + if (amount >= stance) + return { action: "accept", amount: Math.min(amount, desired), reason: good(amount) }; if (amount >= stance - margin) { if (rng() < NPC_ACCEPT.chance) { return { action: "accept", amount: Math.min(amount, desired), reason: good(amount) }; @@ -136,7 +137,11 @@ function advancePatience( previous: number | null, ): number { let delta: number; - if (previous != null && amount > previous && amount - previous < desired * NPC_PATIENCE.stallRatio) { + if ( + previous != null && + amount > previous && + amount - previous < desired * NPC_PATIENCE.stallRatio + ) { delta = NPC_PATIENCE.roundCost + NPC_PATIENCE.stallPenalty; } else if (amount < min) { delta = NPC_PATIENCE.roundCost + NPC_PATIENCE.lowballPenalty; diff --git a/src/lib/market/npcs.ts b/src/lib/market/npcs.ts index b074405..a865f50 100644 --- a/src/lib/market/npcs.ts +++ b/src/lib/market/npcs.ts @@ -168,17 +168,11 @@ export async function createGeneratedNpc( } /** All enabled vendor NPCs that sell the given asset. */ -export async function findVendorNpcs( - payload: PayloadType, - assetId: number, -): Promise { +export async function findVendorNpcs(payload: PayloadType, assetId: number): Promise { const result = await payload.find({ collection: "game-npcs", where: { - and: [ - { "vendor.enabled": { equals: true } }, - { "vendor.sells": { equals: assetId } }, - ], + and: [{ "vendor.enabled": { equals: true } }, { "vendor.sells": { equals: assetId } }], }, limit: 100, depth: 0, @@ -193,10 +187,7 @@ export async function findVendorNpcs( * 2. Otherwise reuse any existing vendor NPC selling the asset. * 3. If none exist, generate a new placeholder NPC for the asset. */ -export async function resolveVendorNpc( - payload: PayloadType, - assetId: number, -): Promise { +export async function resolveVendorNpc(payload: PayloadType, assetId: number): Promise { const vendors = await findVendorNpcs(payload, assetId); if (vendors.length > 0) { const inGame = vendors.filter((npc) => npc.isInGame === true); diff --git a/src/lib/storageRules.ts b/src/lib/storageRules.ts index 8503538..2b73a9a 100644 --- a/src/lib/storageRules.ts +++ b/src/lib/storageRules.ts @@ -10,10 +10,7 @@ export type StorageRulesSource = Pick< "allowedStorage" | "prohibitedStorage" | "restrictToAllowed" >; -export type StorageRuleViolation = - | "prohibited" - | "not_whitelisted" - | "over_cap"; +export type StorageRuleViolation = "prohibited" | "not_whitelisted" | "over_cap"; export interface StorageRuleCheck { allowed: boolean; @@ -35,10 +32,7 @@ function resolveResourceId(value: number | { id: number }): number { /** * Whether this resource is on the structure's prohibited list. */ -export function isResourceProhibited( - rules: StorageRulesSource, - resourceId: number, -): boolean { +export function isResourceProhibited(rules: StorageRulesSource, resourceId: number): boolean { return (rules.prohibitedStorage ?? []).some((rule) => { if (!isResourceRef(rule.item)) return false; return resolveResourceId(rule.item.value) === resourceId; @@ -50,10 +44,7 @@ export function isResourceProhibited( * enabled, only resources listed in `allowedStorage` pass. Otherwise everything * passes (prohibited list still applies separately). */ -export function isResourceWhitelisted( - rules: StorageRulesSource, - resourceId: number, -): boolean { +export function isResourceWhitelisted(rules: StorageRulesSource, resourceId: number): boolean { if (!rules.restrictToAllowed) return true; return (rules.allowedStorage ?? []).some((rule) => { if (!isResourceRef(rule.item)) return false; @@ -106,20 +97,14 @@ export function checkStorageDeposit( /** * Human-readable message describing why a deposit/transfer was rejected. */ -export function storageViolationMessage( - resourceName: string, - check: StorageRuleCheck, -): string { +export function storageViolationMessage(resourceName: string, check: StorageRuleCheck): string { switch (check.violation) { case "prohibited": return `This resource is prohibited from storage at this structure.`; case "not_whitelisted": return `This structure only accepts items on its allowed storage list — "${resourceName}" is not permitted.`; case "over_cap": { - const available = Math.max( - 0, - (check.cap ?? 0) - (check.currentStored ?? 0), - ); + const available = Math.max(0, (check.cap ?? 0) - (check.currentStored ?? 0)); return available <= 0 ? `${resourceName} is at its storage allowance here (${check.cap?.toLocaleString()}). No more can be stored.` : `${resourceName} is limited to ${check.cap?.toLocaleString()} units here — you can add at most ${available.toLocaleString()} more.`; diff --git a/src/utils/access-control/hasRoles.ts b/src/utils/access-control/hasRoles.ts index c9dfd25..a3edce4 100644 --- a/src/utils/access-control/hasRoles.ts +++ b/src/utils/access-control/hasRoles.ts @@ -1,6 +1,6 @@ import { User } from "@/payload-types"; -export default function hasRoles(roles: NonNullable, user: User | null | undefined) { +export default function hasRoles(roles: NonNullable, user: User | null | undefined) { if (!user) return false; return roles.some((role) => user.roles?.some((urole) => urole === role || urole === "developer")); diff --git a/src/utils/event-log/emit.ts b/src/utils/event-log/emit.ts index 46979f2..b1d48ab 100644 --- a/src/utils/event-log/emit.ts +++ b/src/utils/event-log/emit.ts @@ -5,7 +5,29 @@ interface GameEventInput { message: string; actor?: number; structure?: number; - targetCollection?: "users" | "missions" | "maps" | "campaigns" | "factions" | "technologies" | "assets" | "resources" | "structures" | "vehicles" | "game-structures" | "game-vehicles" | "game-npcs" | "shipments" | "bank-accounts" | "bank-transactions" | "ledger-entries" | "locker-storages" | "loadouts" | "market-listings" | "market-negotiations" | "tickets"; + targetCollection?: + | "users" + | "missions" + | "maps" + | "campaigns" + | "factions" + | "technologies" + | "assets" + | "resources" + | "structures" + | "vehicles" + | "game-structures" + | "game-vehicles" + | "game-npcs" + | "shipments" + | "bank-accounts" + | "bank-transactions" + | "ledger-entries" + | "locker-storages" + | "loadouts" + | "market-listings" + | "market-negotiations" + | "tickets"; targetId?: number; data?: Record; }