import type { AppliedEvent, TripEvent } from "@deadhead/sim"; import { z } from "zod"; // Local, not from ./entities: entities imports this file. const idSchema = z.string().min(1); const timeSchema = z.number().int().nonnegative(); const credits = z.number().int(); /** One option's pre-rolled outcome (decision 0.5.143). */ const eventOutcomeSchema = z.object({ delayMs: z.number().int(), hullLoss: z.number().nonnegative(), payLoss: credits.nonnegative(), fee: credits.nonnegative(), bonus: credits.nonnegative(), xpBonusPct: z.number().nonnegative(), extraFuelFu: z.number().nonnegative(), }); /** A trip's event as rolled at dispatch (decisions 0.5.143–0.5.145). */ export const savedTripEventSchema = z.object({ eventId: idSchema, kind: z.enum(["automatic", "radio"]), good: z.boolean(), fireAt: timeSchema, windowEndsAt: timeSchema, options: z.array(z.object({ id: idSchema, available: z.boolean(), outcome: eventOutcomeSchema })), defaultOptionId: idSchema, }); /** What the event changed once its option applied. */ export const appliedEventSchema = z.object({ eventId: idSchema, optionId: idSchema, answered: z.boolean(), arrivalAt: timeSchema, hullLoss: z.number().nonnegative(), payLoss: credits.nonnegative(), fee: credits.nonnegative(), bonus: credits.nonnegative(), priorityLost: credits.nonnegative(), xpBonusPct: z.number().nonnegative(), extraFuelFu: z.number().nonnegative(), }); /** * A radio call waiting for the player (decision 0.5.144): fired, not yet * answered, window still open. The options' outcomes stay hidden: the player * chooses on what each option might do (content), not on what it will. */ export const radioCallSchema = z.object({ dispatchId: idSchema, shipId: idSchema.nullable(), pilotId: idSchema, eventId: idSchema, fireAt: timeSchema, windowEndsAt: timeSchema, options: z.array(z.object({ id: idSchema, available: z.boolean() })), defaultOptionId: idSchema, /** Flown by an Independent pilot's own choice (CR-021). */ independent: z.boolean(), }); export type RadioCall = z.infer; // The saved shapes are the sim's own: a change on either side fails the build. type Same = [A] extends [B] ? ([B] extends [A] ? true : false) : false; const _sameEvent: Same, TripEvent> = true; const _sameApplied: Same, AppliedEvent> = true; void [_sameEvent, _sameApplied];