143 lines
5.3 KiB
TypeScript
143 lines
5.3 KiB
TypeScript
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<typeof createDispatchRequestSchema>;
|
||
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 }),
|
||
]);
|