import { z } from "zod"; import { contentReferenceSchema, diceKindSchema, ruleEffectSchema, } from "./rules"; export const tableEntrySchema = z.object({ key: z.string().min(1), min: z.number().int().optional(), max: z.number().int().optional(), exact: z.number().int().optional(), d66: z.number().int().optional(), label: z.string().min(1), text: z.string().optional(), effects: z.array(ruleEffectSchema).optional(), references: z.array(contentReferenceSchema).optional(), }); export const tableDefinitionSchema = z.object({ id: z.string().min(1), code: z.string().min(1), name: z.string().min(1), category: z.enum(["generic", "random-list", "loot", "level", "optional", "town", "room"]), level: z.number().int().positive().optional(), page: z.number().int().positive(), diceKind: diceKindSchema, usesModifiedRangesRule: z.boolean().optional(), entries: z.array(tableEntrySchema), notes: z.array(z.string()).optional(), mvp: z.boolean(), }); export const weaponDefinitionSchema = z.object({ id: z.string().min(1), name: z.string().min(1), category: z.enum(["melee", "ranged"]), handedness: z.enum(["one-handed", "two-handed"]), baseDamage: z.number().int(), allowedManoeuvreIds: z.array(z.string()), tags: z.array(z.string()), startingOption: z.boolean(), }); export const manoeuvreDefinitionSchema = z.object({ id: z.string().min(1), name: z.string().min(1), weaponCategories: z.array(z.enum(["melee", "ranged"])), shiftCost: z.number().int().optional(), disciplineModifier: z.number().int().optional(), precisionModifier: z.number().int().optional(), damageModifier: z.number().int().optional(), exactStrikeBonus: z.boolean().optional(), interruptRule: z.string().optional(), effectText: z.string().optional(), mvp: z.boolean(), }); export const armourDefinitionSchema = z.object({ id: z.string().min(1), name: z.string().min(1), armourValue: z.number().int(), penalties: z .object({ shift: z.number().int().optional(), discipline: z.number().int().optional(), precision: z.number().int().optional(), }) .optional(), deflectionRule: z.string().optional(), startingOption: z.boolean(), valueGp: z.number().int().optional(), mvp: z.boolean(), }); export const itemDefinitionSchema = z.object({ id: z.string().min(1), name: z.string().min(1), itemType: z.enum([ "gear", "treasure", "quest", "herb", "rune", "misc", "ration", "light-source", ]), stackable: z.boolean(), consumable: z.boolean(), valueGp: z.number().int().optional(), weight: z.number().optional(), rulesText: z.string().optional(), effects: z.array(ruleEffectSchema).optional(), mvp: z.boolean(), }); export const potionDefinitionSchema = z.object({ id: z.string().min(1), name: z.string().min(1), tableSource: z.string().min(1), useTiming: z.enum(["combat", "exploration", "town", "any"]), effects: z.array(ruleEffectSchema), valueGp: z.number().int().optional(), mvp: z.boolean(), }); export const scrollDefinitionSchema = z.object({ id: z.string().min(1), name: z.string().min(1), tableSource: z.string().min(1), castCheck: z .object({ diceKind: z.enum(["d6", "2d6"]), successMin: z.number().int().optional(), successMax: z.number().int().optional(), }) .optional(), onSuccess: z.array(ruleEffectSchema), onFailureTableCode: z.string().optional(), valueGp: z.number().int().optional(), startingOption: z.boolean(), mvp: z.boolean(), }); export const creatureDefinitionSchema = z.object({ id: z.string().min(1), name: z.string().min(1), level: z.number().int().positive(), category: z.string().min(1), hp: z.number().int().positive(), attackProfile: z.object({ discipline: z.number().int(), precision: z.number().int(), damage: z.number().int(), numberAppearing: z.string().optional(), }), defenceProfile: z .object({ armour: z.number().int().optional(), specialRules: z.array(z.string()).optional(), }) .optional(), xpReward: z.number().int().optional(), lootTableCodes: z.array(z.string()).optional(), interruptRules: z.array(z.string()).optional(), traits: z.array(z.string()).optional(), sourcePage: z.number().int().positive(), mvp: z.boolean(), }); export const exitTemplateSchema = z.object({ direction: z.enum(["north", "east", "south", "west"]).optional(), exitType: z.enum(["open", "door", "locked", "secret", "shaft", "stairs"]), destinationLevel: z.number().int().optional(), }); export const roomTemplateSchema = z.object({ id: z.string().min(1), level: z.number().int().positive(), sourcePage: z.number().int().positive().optional(), roomClass: z.enum(["normal", "small", "large", "special", "start", "stairs"]), tableCode: z.string().min(1), tableEntryKey: z.string().min(1), title: z.string().min(1), text: z.string().optional(), encounterText: z.string().optional(), exitHint: z.string().optional(), unique: z.boolean().optional(), dimensions: z .object({ width: z.number().int().positive(), height: z.number().int().positive(), }) .optional(), exits: z.array(exitTemplateSchema).optional(), encounterRefs: z.array(contentReferenceSchema).optional(), objectRefs: z.array(contentReferenceSchema).optional(), tags: z.array(z.string()), mvp: z.boolean(), }); export const townServiceDefinitionSchema = z.object({ id: z.string().min(1), name: z.string().min(1), serviceType: z.enum(["market", "temple", "tavern", "healer", "smith", "quest"]), tableCodes: z.array(z.string()).optional(), costRules: z.array(z.string()).optional(), effects: z.array(ruleEffectSchema).optional(), mvp: z.boolean(), }); export const contentPackSchema = z.object({ version: z.string().min(1), sourceBooks: z.array(z.string()), tables: z.array(tableDefinitionSchema), weapons: z.array(weaponDefinitionSchema), manoeuvres: z.array(manoeuvreDefinitionSchema), armour: z.array(armourDefinitionSchema), items: z.array(itemDefinitionSchema), potions: z.array(potionDefinitionSchema), scrolls: z.array(scrollDefinitionSchema), creatures: z.array(creatureDefinitionSchema), roomTemplates: z.array(roomTemplateSchema), townServices: z.array(townServiceDefinitionSchema), });