From dc7b87eab2f43be364cce2dfab95bbcc147e12a1 Mon Sep 17 00:00:00 2001 From: ginnoir Date: Thu, 11 Jun 2026 18:48:41 -0500 Subject: [PATCH] feat(engine): tickGame returns completed action ids for story triggers --- src/engine/__tests__/game.test.ts | 19 +++++++++++++++++++ src/engine/game.ts | 24 +++++++++++++----------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/engine/__tests__/game.test.ts b/src/engine/__tests__/game.test.ts index 3d66041..b353fd1 100644 --- a/src/engine/__tests__/game.test.ts +++ b/src/engine/__tests__/game.test.ts @@ -299,6 +299,25 @@ describe('completion advances queue', () => { }); }); +describe('tickGame() completion result', () => { + it('returns the id of each action that completed this tick', () => { + const content = testContent(); + const state = createGameState(content); + enqueueAction(state, content, 'forage'); + const result = tickGame(state, content, 300); + expect(result.completedActionIds).toEqual(['forage']); + expect(state.activeActionId).toBeNull(); + }); + + it('returns an empty array when nothing completes', () => { + const content = testContent(); + const state = createGameState(content); + enqueueAction(state, content, 'forage'); + const result = tickGame(state, content, 100); + expect(result.completedActionIds).toEqual([]); + }); +}); + describe('tickGame()', () => { it('does nothing when no action is active', () => { const content = testContent(); diff --git a/src/engine/game.ts b/src/engine/game.ts index 13ab686..a046ad3 100644 --- a/src/engine/game.ts +++ b/src/engine/game.ts @@ -115,11 +115,8 @@ function startNextFromQueue(state: GameState, content: Content): void { state.actionElapsedMs = 0; } -function completeActiveAction(state: GameState, content: Content): void { - const actionId = state.activeActionId; - if (!actionId) return; - grantYields(state, content, actionId); - startNextFromQueue(state, content); +export interface TickResult { + completedActionIds: string[]; } /** @@ -166,16 +163,21 @@ export function clearQueue(state: GameState): void { * Advance the active action by `tickMs`. On completion, grants yields and * advances the queue — actions do not auto-repeat when the queue is empty. */ -export function tickGame(state: GameState, content: Content, tickMs: number): void { - if (!state.activeActionId) return; +export function tickGame(state: GameState, content: Content, tickMs: number): TickResult { + const completedActionIds: string[] = []; + if (!state.activeActionId) return { completedActionIds }; state.actionElapsedMs += tickMs; while (state.activeActionId) { - const action = content.actionsById[state.activeActionId]; - if (!action) return; - if (state.actionElapsedMs < action.durationMs) return; + const actionId = state.activeActionId; + const action = content.actionsById[actionId]; + if (!action) return { completedActionIds }; + if (state.actionElapsedMs < action.durationMs) return { completedActionIds }; state.actionElapsedMs -= action.durationMs; - completeActiveAction(state, content); + grantYields(state, content, actionId); + completedActionIds.push(actionId); + startNextFromQueue(state, content); } + return { completedActionIds }; }