import { z } from "zod"; import { baySchema, companySchema, contractSchema, dispatchSchema, idSchema, pilotSchema, playerStateSchema, shipSchema, timeSchema, } from "./entities"; /** Request with no body or parameters. */ export const emptyRequestSchema = z.object({}).strict(); export const createGuestResponseSchema = z.object({ playerId: idSchema, state: playerStateSchema, }); export const contractBoardRequestSchema = z.object({ locationId: idSchema }); export const contractBoardResponseSchema = z.object({ contracts: z.array(contractSchema), /** When this board period ends and every contract on it expires. */ periodEndsAt: timeSchema, }); export const createDispatchRequestSchema = z.discriminatedUnion("kind", [ z.object({ kind: z.literal("contract"), contractId: idSchema, shipId: idSchema, pilotId: idSchema, }), /** The avatar flies the loaner; no ship or pilot to choose. */ z.object({ kind: z.literal("tutorial"), contractId: idSchema }), z.object({ kind: z.literal("reposition"), shipId: idSchema, pilotId: idSchema, destinationId: idSchema, }), ]); export type CreateDispatchRequest = z.infer; export const dispatchResponseSchema = z.object({ dispatch: dispatchSchema }); /** Decision 0.5.35: the ship is delivered to one of the player's bays. */ export const buyShipRequestSchema = z.object({ modelId: idSchema, bayId: idSchema }); export const shipResponseSchema = z.object({ ship: shipSchema }); /** CR-009: start the next level of an upgrade on a ship at an HQ. */ export const startUpgradeRequestSchema = z.object({ shipId: idSchema, upgradeId: idSchema }); /** CR-015: buy fuel where the ship is; no amount fills the tank. */ export const refuelRequestSchema = z.object({ shipId: idSchema, amountFu: z.number().positive().optional(), }); /** CR-015: Auto top-up on landing, or Manual. */ export const refuelPolicyRequestSchema = z.object({ shipId: idSchema, policy: z.enum(["auto", "manual"]), }); /** CR-015: emergency fuel for a ship that can't get anywhere (decision 0.5.99). */ export const emergencyFuelRequestSchema = z.object({ shipId: idSchema }); export const leaseBayRequestSchema = z.object({ locationId: idSchema }); export const bayResponseSchema = z.object({ bay: baySchema }); /** Decision 0.5.22: hire at one of the player's bays. */ export const hirePilotRequestSchema = z.object({ locationId: idSchema }); export const assignPilotRequestSchema = z.object({ pilotId: idSchema, shipId: idSchema }); export const unassignPilotRequestSchema = z.object({ pilotId: idSchema }); /** CR-004: rest an idle pilot now, at any duty level. */ export const restPilotRequestSchema = z.object({ pilotId: idSchema }); export const spendSkillPointRequestSchema = z.object({ pilotId: idSchema, skillId: idSchema }); export const pilotResponseSchema = z.object({ pilot: pilotSchema }); export const acknowledgeSummariesRequestSchema = z .object({ dispatchIds: z.array(idSchema), /** Ships whose finished upgrade the player has now seen (CR-009). */ shipIds: z.array(idSchema).optional(), }) .refine((r) => r.dispatchIds.length + (r.shipIds?.length ?? 0) > 0, { message: "Acknowledge at least one summary or ship", }); export const acknowledgeSummariesResponseSchema = z.object({ acknowledged: z.number().int().nonnegative(), }); /** Pay the loan down by up to `amount` credits (decision 0.5.32). */ export const repayLoanRequestSchema = z.object({ amount: z.number().int().positive() }); export const claimGoalRequestSchema = z.object({ goalId: idSchema }); export const companyResponseSchema = z.object({ company: companySchema }); /** * A company name (decision 0.5.75): trimmed, 3–32 characters of letters, * digits, spaces and basic punctuation. */ export const companyNameSchema = z .string() .trim() .min(3, "At least 3 characters") .max(32, "At most 32 characters") .regex(/^[A-Za-z0-9 .,'&!?-]+$/, "Letters, digits, spaces and . , ' & ! ? - only"); export const renameCompanyRequestSchema = z.object({ name: companyNameSchema }); /** Export save (decision 0.5.92): the whole save as one text code. */ export const exportSaveResponseSchema = z.object({ code: z.string().min(1) }); /** Import save: a pasted or opened export code (generous: big companies make long codes). */ export const importSaveRequestSchema = z.object({ code: z.string().trim().min(1).max(10_000_000) }); /** Developer tools, non-production only (CR-011). */ export const devAdvanceClockRequestSchema = z.object({ advanceMs: z .number() .int() .positive() .max(30 * 24 * 3_600_000), }); export const devAdvanceClockResponseSchema = z.object({ offsetMs: z.number().int(), realTime: timeSchema, }); export const devAddCreditsRequestSchema = z.object({ amount: z.number().int().positive().max(10_000_000), }); /** A pilot to the next level's XP, or out of duty and rest. */ export const devPilotRequestSchema = z.object({ pilotId: idSchema, action: z.enum(["level-up", "clear-rest"]), }); /** A ship's upgrades maxed or removed, its shop work finished, or moved while idle. */ export const devShipRequestSchema = z.discriminatedUnion("action", [ z.object({ shipId: idSchema, action: z.enum(["max-upgrades", "reset-upgrades", "finish-shop"]), }), z.object({ shipId: idSchema, action: z.literal("move"), locationId: idSchema }), ]);