import type { GraphNodeId, Project, SceneGraphEdge, SceneGraphNode, SceneId } from '../types'; import { reconcileSceneListOrder } from './sceneListOrder'; import { buildStoryRootMap, getNodeStoryRoot, getSideStoryComponentNodeIds, isSideStoryRoot, } from './sceneGraphLineage'; export type ActiveStorylineSceneEntry = { sceneId: SceneId; graphNodeId: GraphNodeId; }; /** Узлы графа, принадлежащие активной сюжетной линии текущего положения. */ export function getActiveStorylineGraphNodeIds( nodes: SceneGraphNode[], edges: SceneGraphEdge[], currentGraphNodeId: GraphNodeId, ): Set { const root = getNodeStoryRoot(nodes, edges, currentGraphNodeId); if (root === 'main') { const rootMap = buildStoryRootMap(nodes, edges); const ids = new Set(); for (const [id, r] of rootMap) { if (r === 'main') ids.add(id); } return ids; } if (isSideStoryRoot(root)) { return getSideStoryComponentNodeIds(nodes, edges, root); } return new Set(); } function pickGraphNodeForScene( sceneId: SceneId, storylineNodeIds: Set, nodes: SceneGraphNode[], currentGraphNodeId: GraphNodeId | null, ): GraphNodeId | null { const matching = nodes.filter((n) => storylineNodeIds.has(n.id) && n.sceneId === sceneId); if (matching.length === 0) return null; if (currentGraphNodeId && matching.some((n) => n.id === currentGraphNodeId)) { return currentGraphNodeId; } return matching[0]?.id ?? null; } /** * Сцены активной линии в порядке бокового списка редактора; каждая sceneId — один раз. */ export function listActiveStorylineScenes(project: Project): ActiveStorylineSceneEntry[] { const currentGraphNodeId = project.currentGraphNodeId; if (!currentGraphNodeId) return []; const storylineNodeIds = getActiveStorylineGraphNodeIds( project.sceneGraphNodes, project.sceneGraphEdges, currentGraphNodeId, ); if (storylineNodeIds.size === 0) return []; const order = reconcileSceneListOrder(project.scenes, project.sceneListOrder); const out: ActiveStorylineSceneEntry[] = []; for (const sceneId of order) { const graphNodeId = pickGraphNodeForScene( sceneId, storylineNodeIds, project.sceneGraphNodes, currentGraphNodeId, ); if (graphNodeId) out.push({ sceneId, graphNodeId }); } return out; }