feat(content): add action story hints and merge GameContent
This commit is contained in:
@@ -124,3 +124,27 @@ describe('unlock conditions', () => {
|
|||||||
expect(content.actionsById.forage.unlock).toBeUndefined();
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import { actionDefs, resourceDefs } from './definitions';
|
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. */
|
const base = buildContent({ resources: resourceDefs, actions: actionDefs });
|
||||||
export const content = 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';
|
export type { ActionDef, Content, ResourceDef } from './schema';
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ export const actionDefSchema = z.object({
|
|||||||
costs: z.array(resourceAmountSchema).default([]),
|
costs: z.array(resourceAmountSchema).default([]),
|
||||||
yields: z.array(resourceAmountSchema).min(1),
|
yields: z.array(resourceAmountSchema).min(1),
|
||||||
unlock: unlockDefSchema.optional(),
|
unlock: unlockDefSchema.optional(),
|
||||||
|
storyHint: z.string().min(1).optional(),
|
||||||
|
storyTooltip: z.string().min(1).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ResourceDef = z.infer<typeof resourceDefSchema>;
|
export type ResourceDef = z.infer<typeof resourceDefSchema>;
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export const storyNodeDefs = [
|
||||||
|
{
|
||||||
|
id: 'boot_intro',
|
||||||
|
prose: 'Placeholder boot.',
|
||||||
|
triggers: [{ type: 'boot', targetNodeId: 'boot_intro' }],
|
||||||
|
},
|
||||||
|
];
|
||||||
Reference in New Issue
Block a user