// Aircraft catalog — in-code constants for now (no DB table yet). One type is // enough for the MVP; add more entries to PLANE_TYPES as they are designed. export interface PlaneType { id: string; name: string; // Fuel capacity, liters. maxFuel: number; // Fuel burn per km of flight at a FULL tank, liters/km (cruise) — the weighted burn // model (v0.16.0) calibrates its rate constant to this value at F = maxFuel. burnPerKm: number; // Operating empty weight in kg (v0.16.0) — feeds the weight-proportional burn model. emptyWeightKg: number; // Cruise speed, km/h — used by the sim tick to advance planes along routes. speedKmh: number; // Market price in € (v0.8.0): buying costs `price`, selling pays out // SELL_FRACTION × price. price: number; // Max payload in kg (v0.27.0, ISS-045 — replaces the v0.12.0 slot count): total // package weight that can be loaded on one plane. ATR 72-600-class figure, tuned // so every cargo type at max count × 1.3 jitter still fits alone (see UNIT_WEIGHT_KG). maxPayloadKg: number; } export const PLANE_TYPES: Record = { atr72: { id: 'atr72', name: 'ATR 72-600', maxFuel: 6300, burnPerKm: 1.75, // full-tank rate: ~893 L/h ≈ 714 kg/h at 510 km/h cruise (Jet-A1 ≈ 0.8 kg/L); the weighted model burns less as fuel drops off emptyWeightKg: 9_300, // ATR 72-600 operating empty weight speedKmh: 510, // €200k — with the starting cash of €20k and typical hop rewards (~€1–3k), // a second ATR takes sustained play to afford, as intended for the MVP sink. price: 200_000, // ponytail: balance-tunable payload (kg) — every cargo type at max count × 1.3 jitter // must stay below this so any single package fits alone; typical loads carry ~3–6 packages. maxPayloadKg: 4_800, }, }; // The plane the player starts with. export const STARTER_MODEL = 'atr72'; // Jet-A1 fuel price in €/liter (v0.8.0): refueling cost = (maxFuel − fuel) × this. export const FUEL_PRICE_PER_L = 0.8; // Fraction of the catalog price paid out when selling a plane (v0.8.0). export const SELL_FRACTION = 0.5; // Snapshot shape of one catalog entry in GET /api/state (v0.10.0): `model` is the // id used by buy/dispatch, `label` the display name — clients compute all market // previews (buy price, sell payout, refuel cost) from these + the economy constants. export interface CatalogEntry { model: string; label: string; price: number; maxFuel: number; burnPerKm: number; // Weighted burn model inputs (v0.16.0) — clients can mirror the closed forms in // lib/sim/movement.ts with these + FUEL_DENSITY_KG_PER_L. emptyWeightKg: number; speedKmh: number; // Max payload in kg (v0.27.0) — total package weight that can be loaded on one plane. maxPayloadKg: number; } // The catalog as a flat array, one entry per plane type — the single source of // truth for both the sim (PLANE_TYPES) and the client snapshot. export function catalogEntries(): CatalogEntry[] { return Object.values(PLANE_TYPES).map((t) => ({ model: t.id, label: t.name, price: t.price, maxFuel: t.maxFuel, burnPerKm: t.burnPerKm, emptyWeightKg: t.emptyWeightKg, speedKmh: t.speedKmh, maxPayloadKg: t.maxPayloadKg, })); }