docs(mystery): spec for engine prereqs (verbs, disambiguation, ending UI) #1
+1
-1
@@ -150,7 +150,7 @@ export function parseItem(raw: string, sourcePath: string): Item {
|
||||
|
||||
export interface ParsedEnding {
|
||||
id: 'true' | 'wrong' | 'bad'
|
||||
ending: { whenFlags: Record<string, string | boolean | number>; narration: string }
|
||||
ending: { whenFlags: Record<string, string | boolean | number | string[]>; narration: string }
|
||||
}
|
||||
|
||||
export function parseEnding(raw: string, _sourcePath: string): ParsedEnding {
|
||||
|
||||
@@ -79,3 +79,27 @@ describe('encounterFrontmatterSchema', () => {
|
||||
expect(() => encounterFrontmatterSchema.parse(data)).not.toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
describe('itemFrontmatterSchema — bible additions', () => {
|
||||
it('accepts readable + lighter fields', () => {
|
||||
const data = {
|
||||
id: 'matches',
|
||||
names: ['matches', 'matchbook'],
|
||||
short: 'a matchbook',
|
||||
takeable: true,
|
||||
lighter: true,
|
||||
lighterUses: 4,
|
||||
}
|
||||
expect(() => itemFrontmatterSchema.parse(data)).not.toThrow()
|
||||
})
|
||||
|
||||
it('accepts lightable on its own', () => {
|
||||
const data = { id: 'lamp', names: ['lamp'], short: 'a lamp', takeable: true, lightable: true }
|
||||
expect(() => itemFrontmatterSchema.parse(data)).not.toThrow()
|
||||
})
|
||||
|
||||
it('rejects negative lighterUses', () => {
|
||||
const data = { id: 'matches', names: ['matches'], short: 'matches', takeable: true, lighter: true, lighterUses: -1 }
|
||||
expect(() => itemFrontmatterSchema.parse(data)).toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
+5
-1
@@ -1,6 +1,6 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
const stateValueSchema = z.union([z.string(), z.boolean(), z.number()])
|
||||
const stateValueSchema = z.union([z.string(), z.boolean(), z.number(), z.array(z.string())])
|
||||
const stateRecordSchema = z.record(z.string(), stateValueSchema)
|
||||
|
||||
export const roomFrontmatterSchema = z.object({
|
||||
@@ -37,6 +37,10 @@ export const itemFrontmatterSchema = z.object({
|
||||
short: z.string().min(1),
|
||||
takeable: z.boolean(),
|
||||
initialState: stateRecordSchema.default({}),
|
||||
readable: z.boolean().optional(),
|
||||
lightable: z.boolean().optional(),
|
||||
lighter: z.boolean().optional(),
|
||||
lighterUses: z.number().int().nonnegative().optional(),
|
||||
})
|
||||
|
||||
export type ItemFrontmatter = z.infer<typeof itemFrontmatterSchema>
|
||||
|
||||
+20
-4
@@ -37,9 +37,25 @@ export interface Item {
|
||||
/** Long description shown when examined. */
|
||||
long: string
|
||||
/** Initial per-instance state (e.g. `{ lit: false }`). */
|
||||
initialState: Record<string, string | boolean | number>
|
||||
initialState: Record<string, string | boolean | number | string[]>
|
||||
/** True if the player can pick it up. */
|
||||
takeable: boolean
|
||||
/** True if `read X` should narrate the item's `## read` section. */
|
||||
readable?: boolean
|
||||
/** True if `light X` / `extinguish X` apply; toggles state.lit. */
|
||||
lightable?: boolean
|
||||
/** True if this item can light other items. */
|
||||
lighter?: boolean
|
||||
/** Optional remaining-charges counter; absent means unlimited. */
|
||||
lighterUses?: number
|
||||
/** Prose returned by `read X`. Required iff readable is true. */
|
||||
readableText?: string
|
||||
/** Prose narrated when `light X` succeeds. Falls back to "It catches." */
|
||||
litText?: string
|
||||
/** Prose narrated when `extinguish X` succeeds. Falls back to "The flame dies." */
|
||||
extinguishedText?: string
|
||||
/** Prose narrated when this item's lighterUses reaches 0. Falls back to "It is spent." */
|
||||
lighterEmptyText?: string
|
||||
}
|
||||
|
||||
export interface EncounterPhaseDef {
|
||||
@@ -83,8 +99,8 @@ export interface World {
|
||||
encounters: Record<EncounterId, EncounterDef>
|
||||
/** Story flag definitions and the endings they unlock. */
|
||||
endings: {
|
||||
true: { whenFlags: Record<string, string | boolean | number>; narration: string }
|
||||
wrong: { whenFlags: Record<string, string | boolean | number>; narration: string }
|
||||
bad: { whenFlags: Record<string, string | boolean | number>; narration: string }
|
||||
true: { whenFlags: Record<string, string | boolean | number | string[]>; narration: string }
|
||||
wrong: { whenFlags: Record<string, string | boolean | number | string[]>; narration: string }
|
||||
bad: { whenFlags: Record<string, string | boolean | number | string[]>; narration: string }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user