feat(state): automation fields on action view model
This commit is contained in:
@@ -239,6 +239,39 @@ describe('action columns projection', () => {
|
|||||||
expect(rest?.loopEnabled).toBe(true);
|
expect(rest?.loopEnabled).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('marks automationUnlocked on actions after manual completion', () => {
|
||||||
|
const state = createGameState(content);
|
||||||
|
state.manualCompletionCounts.gather_supplies = 1;
|
||||||
|
const view = toView(state, content);
|
||||||
|
const gather = view.actionColumns
|
||||||
|
.flatMap((c) => c.groups)
|
||||||
|
.flatMap((g) => g.actions)
|
||||||
|
.find((a) => a.id === 'gather_supplies');
|
||||||
|
|
||||||
|
expect(gather?.automationUnlocked).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('marks actions already in the automation queue', () => {
|
||||||
|
const state = createGameState(content);
|
||||||
|
state.automationQueue = ['gather_supplies'];
|
||||||
|
const view = toView(state, content);
|
||||||
|
const gather = view.actionColumns
|
||||||
|
.flatMap((c) => c.groups)
|
||||||
|
.flatMap((g) => g.actions)
|
||||||
|
.find((a) => a.id === 'gather_supplies');
|
||||||
|
|
||||||
|
expect(gather?.inAutomationQueue).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('projects automation queue ids and display names', () => {
|
||||||
|
const state = createGameState(content);
|
||||||
|
state.automationQueue = ['gather_supplies', 'missing_action'];
|
||||||
|
const view = toView(state, content);
|
||||||
|
|
||||||
|
expect(view.automationQueueIds).toEqual(['gather_supplies', 'missing_action']);
|
||||||
|
expect(view.automationQueueNames).toEqual(['Gather supplies', 'missing_action']);
|
||||||
|
});
|
||||||
|
|
||||||
it('shows story actions only when their choice is available, hiding siblings after a fork is taken', () => {
|
it('shows story actions only when their choice is available, hiding siblings after a fork is taken', () => {
|
||||||
const state = createGameState(content);
|
const state = createGameState(content);
|
||||||
// before reaching the fork, story actions are hidden
|
// before reaching the fork, story actions are hidden
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ export const useGameStore = create<GameStoreState>((set, get) => ({
|
|||||||
actionProgress: 0,
|
actionProgress: 0,
|
||||||
queuedActionIds: [],
|
queuedActionIds: [],
|
||||||
queuedActionNames: [],
|
queuedActionNames: [],
|
||||||
|
automationQueueIds: [],
|
||||||
|
automationQueueNames: [],
|
||||||
actions: [],
|
actions: [],
|
||||||
story: { currentProse: null, atBootIntro: false, choices: [], tree: [] },
|
story: { currentProse: null, atBootIntro: false, choices: [], tree: [] },
|
||||||
actionColumns: [],
|
actionColumns: [],
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { GameContent } from '../content/index';
|
import type { GameContent } from '../content/index';
|
||||||
|
import { isAutomationUnlocked } from '../engine/automation';
|
||||||
import {
|
import {
|
||||||
canAffordAction,
|
canAffordAction,
|
||||||
canUnlockAction,
|
canUnlockAction,
|
||||||
@@ -40,6 +41,8 @@ export interface ActionView {
|
|||||||
yieldsSummary: string | null;
|
yieldsSummary: string | null;
|
||||||
kind: ActionColumnKind;
|
kind: ActionColumnKind;
|
||||||
loopEnabled: boolean;
|
loopEnabled: boolean;
|
||||||
|
automationUnlocked: boolean;
|
||||||
|
inAutomationQueue: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ActionGroupView {
|
export interface ActionGroupView {
|
||||||
@@ -84,6 +87,8 @@ export interface GameView {
|
|||||||
actionProgress: number;
|
actionProgress: number;
|
||||||
queuedActionIds: string[];
|
queuedActionIds: string[];
|
||||||
queuedActionNames: string[];
|
queuedActionNames: string[];
|
||||||
|
automationQueueIds: string[];
|
||||||
|
automationQueueNames: string[];
|
||||||
actions: ActionView[];
|
actions: ActionView[];
|
||||||
story: StoryView;
|
story: StoryView;
|
||||||
actionColumns: ActionColumnView[];
|
actionColumns: ActionColumnView[];
|
||||||
@@ -153,6 +158,8 @@ export function toView(state: GameState, content: GameContent): GameView {
|
|||||||
: 0;
|
: 0;
|
||||||
const queuedActionIds = [...state.actionQueue];
|
const queuedActionIds = [...state.actionQueue];
|
||||||
const queuedActionNames = queuedActionIds.map((id) => content.actionsById[id]?.name ?? id);
|
const queuedActionNames = queuedActionIds.map((id) => content.actionsById[id]?.name ?? id);
|
||||||
|
const automationQueueIds = [...state.automationQueue];
|
||||||
|
const automationQueueNames = automationQueueIds.map((id) => content.actionsById[id]?.name ?? id);
|
||||||
|
|
||||||
// Build a map of ActionView by id for column assembly
|
// Build a map of ActionView by id for column assembly
|
||||||
const actionViewMap = new Map<string, ActionView>();
|
const actionViewMap = new Map<string, ActionView>();
|
||||||
@@ -172,6 +179,8 @@ export function toView(state: GameState, content: GameContent): GameView {
|
|||||||
yieldsSummary: formatResourceList(a.yields, content),
|
yieldsSummary: formatResourceList(a.yields, content),
|
||||||
kind: a.kind,
|
kind: a.kind,
|
||||||
loopEnabled: !!state.enabledLoopActionIds[a.id],
|
loopEnabled: !!state.enabledLoopActionIds[a.id],
|
||||||
|
automationUnlocked: isAutomationUnlocked(state, content, a.id),
|
||||||
|
inAutomationQueue: state.automationQueue.includes(a.id),
|
||||||
};
|
};
|
||||||
actionViewMap.set(a.id, view);
|
actionViewMap.set(a.id, view);
|
||||||
return view;
|
return view;
|
||||||
@@ -243,6 +252,8 @@ export function toView(state: GameState, content: GameContent): GameView {
|
|||||||
actionProgress,
|
actionProgress,
|
||||||
queuedActionIds,
|
queuedActionIds,
|
||||||
queuedActionNames,
|
queuedActionNames,
|
||||||
|
automationQueueIds,
|
||||||
|
automationQueueNames,
|
||||||
actions,
|
actions,
|
||||||
story,
|
story,
|
||||||
actionColumns,
|
actionColumns,
|
||||||
|
|||||||
Reference in New Issue
Block a user