diff --git a/src/content/__tests__/schema.test.ts b/src/content/__tests__/schema.test.ts index 1d2ad19..960a724 100644 --- a/src/content/__tests__/schema.test.ts +++ b/src/content/__tests__/schema.test.ts @@ -124,3 +124,27 @@ describe('unlock conditions', () => { expect(content.actionsById.forage.unlock).toBeUndefined(); }); }); + +describe('action narrative fields', () => { + it('accepts optional storyHint and storyTooltip', () => { + const actions = [ + { + id: 'forage', + name: 'Forage', + durationMs: 3000, + yields: [{ resourceId: 'gold', amount: 1 }], + storyHint: 'Gather what the forest offers.', + storyTooltip: 'Your first step into the wild.', + }, + ]; + const content = buildContent({ resources: validResources, actions }); + expect(content.actionsById.forage.storyHint).toBe('Gather what the forest offers.'); + expect(content.actionsById.forage.storyTooltip).toBe('Your first step into the wild.'); + }); + + it('defaults storyHint and storyTooltip to undefined when omitted', () => { + const content = buildContent({ resources: validResources, actions: validActions }); + expect(content.actionsById.forage.storyHint).toBeUndefined(); + expect(content.actionsById.forage.storyTooltip).toBeUndefined(); + }); +}); diff --git a/src/content/index.ts b/src/content/index.ts index 3d77f73..27c6058 100644 --- a/src/content/index.ts +++ b/src/content/index.ts @@ -1,7 +1,12 @@ import { actionDefs, resourceDefs } from './definitions'; -import { buildContent } from './schema'; +import { buildContent, type Content } from './schema'; +import { buildStoryContent, type StoryContent } from './storySchema'; +import { storyNodeDefs } from './story'; -/** The validated, indexed content the engine and view consume. */ -export const content = buildContent({ resources: resourceDefs, actions: actionDefs }); +const base = buildContent({ resources: resourceDefs, actions: actionDefs }); +const story = buildStoryContent(storyNodeDefs, base.actionsById, base.resourcesById); + +export type GameContent = Content & StoryContent; +export const content: GameContent = { ...base, ...story }; export type { ActionDef, Content, ResourceDef } from './schema'; diff --git a/src/content/schema.ts b/src/content/schema.ts index 976bfcf..41771a4 100644 --- a/src/content/schema.ts +++ b/src/content/schema.ts @@ -32,6 +32,8 @@ export const actionDefSchema = z.object({ costs: z.array(resourceAmountSchema).default([]), yields: z.array(resourceAmountSchema).min(1), unlock: unlockDefSchema.optional(), + storyHint: z.string().min(1).optional(), + storyTooltip: z.string().min(1).optional(), }); export type ResourceDef = z.infer; diff --git a/src/content/story.ts b/src/content/story.ts new file mode 100644 index 0000000..e2b6b71 --- /dev/null +++ b/src/content/story.ts @@ -0,0 +1,7 @@ +export const storyNodeDefs = [ + { + id: 'boot_intro', + prose: 'Placeholder boot.', + triggers: [{ type: 'boot', targetNodeId: 'boot_intro' }], + }, +];