@magicborn/dialogue-forge 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. package/README.md +233 -0
  2. package/bin/dialogue-forge.js +78 -0
  3. package/demo/app/layout.tsx +36 -0
  4. package/demo/app/page.tsx +440 -0
  5. package/demo/components/ThemeSwitcher.tsx +611 -0
  6. package/demo/next.config.mjs +7 -0
  7. package/demo/package.json +29 -0
  8. package/demo/postcss.config.mjs +7 -0
  9. package/demo/public/logo.svg +1 -0
  10. package/demo/styles/globals.css +19 -0
  11. package/demo/tailwind.config.ts +90 -0
  12. package/demo/tsconfig.json +42 -0
  13. package/dist/components/ChoiceEdgeV2.d.ts +3 -0
  14. package/dist/components/ChoiceEdgeV2.js +103 -0
  15. package/dist/components/CodeBlock.d.ts +8 -0
  16. package/dist/components/CodeBlock.js +24 -0
  17. package/dist/components/ConditionAutocomplete.d.ts +14 -0
  18. package/dist/components/ConditionAutocomplete.js +284 -0
  19. package/dist/components/ConditionalNodeV2.d.ts +16 -0
  20. package/dist/components/ConditionalNodeV2.js +147 -0
  21. package/dist/components/DialogueEditorV2.d.ts +22 -0
  22. package/dist/components/DialogueEditorV2.js +1170 -0
  23. package/dist/components/EdgeIcon.d.ts +8 -0
  24. package/dist/components/EdgeIcon.js +13 -0
  25. package/dist/components/ExampleLoader.d.ts +11 -0
  26. package/dist/components/ExampleLoader.js +52 -0
  27. package/dist/components/ExampleLoaderButton.d.ts +15 -0
  28. package/dist/components/ExampleLoaderButton.js +102 -0
  29. package/dist/components/FlagManager.d.ts +11 -0
  30. package/dist/components/FlagManager.js +282 -0
  31. package/dist/components/FlagSelector.d.ts +11 -0
  32. package/dist/components/FlagSelector.js +235 -0
  33. package/dist/components/GuidePanel.d.ts +7 -0
  34. package/dist/components/GuidePanel.js +1176 -0
  35. package/dist/components/Minimap.d.ts +16 -0
  36. package/dist/components/Minimap.js +93 -0
  37. package/dist/components/NPCEdgeV2.d.ts +3 -0
  38. package/dist/components/NPCEdgeV2.js +104 -0
  39. package/dist/components/NPCNodeV2.d.ts +26 -0
  40. package/dist/components/NPCNodeV2.js +86 -0
  41. package/dist/components/NodeEditor.d.ts +18 -0
  42. package/dist/components/NodeEditor.js +1025 -0
  43. package/dist/components/PlayView.d.ts +12 -0
  44. package/dist/components/PlayView.js +307 -0
  45. package/dist/components/PlayerNodeV2.d.ts +16 -0
  46. package/dist/components/PlayerNodeV2.js +139 -0
  47. package/dist/components/ReactFlowPOC.d.ts +61 -0
  48. package/dist/components/ReactFlowPOC.js +312 -0
  49. package/dist/components/ScenePlayer.d.ts +18 -0
  50. package/dist/components/ScenePlayer.js +196 -0
  51. package/dist/components/YarnView.d.ts +9 -0
  52. package/dist/components/YarnView.js +45 -0
  53. package/dist/components/ZoomControls.d.ts +11 -0
  54. package/dist/components/ZoomControls.js +34 -0
  55. package/dist/esm/components/ChoiceEdgeV2.d.ts +3 -0
  56. package/dist/esm/components/ChoiceEdgeV2.js +67 -0
  57. package/dist/esm/components/CodeBlock.d.ts +8 -0
  58. package/dist/esm/components/CodeBlock.js +18 -0
  59. package/dist/esm/components/ConditionAutocomplete.d.ts +14 -0
  60. package/dist/esm/components/ConditionAutocomplete.js +248 -0
  61. package/dist/esm/components/ConditionalNodeV2.d.ts +16 -0
  62. package/dist/esm/components/ConditionalNodeV2.js +111 -0
  63. package/dist/esm/components/DialogueEditorV2.d.ts +22 -0
  64. package/dist/esm/components/DialogueEditorV2.js +1134 -0
  65. package/dist/esm/components/EdgeIcon.d.ts +8 -0
  66. package/dist/esm/components/EdgeIcon.js +7 -0
  67. package/dist/esm/components/ExampleLoader.d.ts +11 -0
  68. package/dist/esm/components/ExampleLoader.js +46 -0
  69. package/dist/esm/components/ExampleLoaderButton.d.ts +15 -0
  70. package/dist/esm/components/ExampleLoaderButton.js +66 -0
  71. package/dist/esm/components/FlagManager.d.ts +11 -0
  72. package/dist/esm/components/FlagManager.js +246 -0
  73. package/dist/esm/components/FlagSelector.d.ts +11 -0
  74. package/dist/esm/components/FlagSelector.js +199 -0
  75. package/dist/esm/components/GuidePanel.d.ts +7 -0
  76. package/dist/esm/components/GuidePanel.js +1140 -0
  77. package/dist/esm/components/Minimap.d.ts +16 -0
  78. package/dist/esm/components/Minimap.js +57 -0
  79. package/dist/esm/components/NPCEdgeV2.d.ts +3 -0
  80. package/dist/esm/components/NPCEdgeV2.js +68 -0
  81. package/dist/esm/components/NPCNodeV2.d.ts +26 -0
  82. package/dist/esm/components/NPCNodeV2.js +80 -0
  83. package/dist/esm/components/NodeEditor.d.ts +18 -0
  84. package/dist/esm/components/NodeEditor.js +989 -0
  85. package/dist/esm/components/PlayView.d.ts +12 -0
  86. package/dist/esm/components/PlayView.js +271 -0
  87. package/dist/esm/components/PlayerNodeV2.d.ts +16 -0
  88. package/dist/esm/components/PlayerNodeV2.js +103 -0
  89. package/dist/esm/components/ReactFlowPOC.d.ts +61 -0
  90. package/dist/esm/components/ReactFlowPOC.js +275 -0
  91. package/dist/esm/components/ScenePlayer.d.ts +18 -0
  92. package/dist/esm/components/ScenePlayer.js +160 -0
  93. package/dist/esm/components/YarnView.d.ts +9 -0
  94. package/dist/esm/components/YarnView.js +39 -0
  95. package/dist/esm/components/ZoomControls.d.ts +11 -0
  96. package/dist/esm/components/ZoomControls.js +28 -0
  97. package/dist/esm/examples/example-loader.d.ts +29 -0
  98. package/dist/esm/examples/example-loader.js +103 -0
  99. package/dist/esm/examples/examples-registry.d.ts +38 -0
  100. package/dist/esm/examples/examples-registry.js +153 -0
  101. package/dist/esm/examples/index.d.ts +26 -0
  102. package/dist/esm/examples/index.js +50 -0
  103. package/dist/esm/examples/legacy-examples.d.ts +9 -0
  104. package/dist/esm/examples/legacy-examples.js +814 -0
  105. package/dist/esm/examples/yarn-examples.d.ts +35 -0
  106. package/dist/esm/examples/yarn-examples.js +181 -0
  107. package/dist/esm/index.d.ts +21 -0
  108. package/dist/esm/index.js +26 -0
  109. package/dist/esm/lib/flag-manager.d.ts +21 -0
  110. package/dist/esm/lib/flag-manager.js +93 -0
  111. package/dist/esm/lib/yarn-converter/__tests__/round-trip.test.d.ts +1 -0
  112. package/dist/esm/lib/yarn-converter/__tests__/round-trip.test.js +169 -0
  113. package/dist/esm/lib/yarn-converter.d.ts +17 -0
  114. package/dist/esm/lib/yarn-converter.js +521 -0
  115. package/dist/esm/lib/yarn-runner/__tests__/condition-evaluator.test.d.ts +1 -0
  116. package/dist/esm/lib/yarn-runner/__tests__/condition-evaluator.test.js +171 -0
  117. package/dist/esm/lib/yarn-runner/__tests__/node-processor.test.d.ts +1 -0
  118. package/dist/esm/lib/yarn-runner/__tests__/node-processor.test.js +237 -0
  119. package/dist/esm/lib/yarn-runner/__tests__/variable-manager.test.d.ts +1 -0
  120. package/dist/esm/lib/yarn-runner/__tests__/variable-manager.test.js +106 -0
  121. package/dist/esm/lib/yarn-runner/condition-evaluator.d.ts +12 -0
  122. package/dist/esm/lib/yarn-runner/condition-evaluator.js +56 -0
  123. package/dist/esm/lib/yarn-runner/index.d.ts +12 -0
  124. package/dist/esm/lib/yarn-runner/index.js +11 -0
  125. package/dist/esm/lib/yarn-runner/node-processor.d.ts +18 -0
  126. package/dist/esm/lib/yarn-runner/node-processor.js +129 -0
  127. package/dist/esm/lib/yarn-runner/variable-manager.d.ts +51 -0
  128. package/dist/esm/lib/yarn-runner/variable-manager.js +120 -0
  129. package/dist/esm/lib/yarn-runner/variable-operations.d.ts +16 -0
  130. package/dist/esm/lib/yarn-runner/variable-operations.js +88 -0
  131. package/dist/esm/types/conditionals.d.ts +29 -0
  132. package/dist/esm/types/conditionals.js +1 -0
  133. package/dist/esm/types/constants.d.ts +59 -0
  134. package/dist/esm/types/constants.js +55 -0
  135. package/dist/esm/types/flags.d.ts +49 -0
  136. package/dist/esm/types/flags.js +49 -0
  137. package/dist/esm/types/game-state.d.ts +62 -0
  138. package/dist/esm/types/game-state.js +6 -0
  139. package/dist/esm/types/index.d.ts +77 -0
  140. package/dist/esm/types/index.js +1 -0
  141. package/dist/esm/utils/constants.d.ts +5 -0
  142. package/dist/esm/utils/constants.js +5 -0
  143. package/dist/esm/utils/feature-flags.d.ts +11 -0
  144. package/dist/esm/utils/feature-flags.js +11 -0
  145. package/dist/esm/utils/game-state-flattener.d.ts +41 -0
  146. package/dist/esm/utils/game-state-flattener.js +135 -0
  147. package/dist/esm/utils/layout/collision.d.ts +27 -0
  148. package/dist/esm/utils/layout/collision.js +74 -0
  149. package/dist/esm/utils/layout/index.d.ts +82 -0
  150. package/dist/esm/utils/layout/index.js +98 -0
  151. package/dist/esm/utils/layout/registry.d.ts +91 -0
  152. package/dist/esm/utils/layout/registry.js +148 -0
  153. package/dist/esm/utils/layout/strategies/dagre.d.ts +19 -0
  154. package/dist/esm/utils/layout/strategies/dagre.js +182 -0
  155. package/dist/esm/utils/layout/strategies/force.d.ts +21 -0
  156. package/dist/esm/utils/layout/strategies/force.js +178 -0
  157. package/dist/esm/utils/layout/strategies/grid.d.ts +17 -0
  158. package/dist/esm/utils/layout/strategies/grid.js +91 -0
  159. package/dist/esm/utils/layout/strategies/index.d.ts +8 -0
  160. package/dist/esm/utils/layout/strategies/index.js +8 -0
  161. package/dist/esm/utils/layout/types.d.ts +100 -0
  162. package/dist/esm/utils/layout/types.js +7 -0
  163. package/dist/esm/utils/layout.d.ts +9 -0
  164. package/dist/esm/utils/layout.js +17 -0
  165. package/dist/esm/utils/node-helpers.d.ts +7 -0
  166. package/dist/esm/utils/node-helpers.js +94 -0
  167. package/dist/esm/utils/reactflow-converter.d.ts +42 -0
  168. package/dist/esm/utils/reactflow-converter.js +217 -0
  169. package/dist/examples/example-loader.d.ts +29 -0
  170. package/dist/examples/example-loader.js +109 -0
  171. package/dist/examples/examples-registry.d.ts +38 -0
  172. package/dist/examples/examples-registry.js +160 -0
  173. package/dist/examples/index.d.ts +26 -0
  174. package/dist/examples/index.js +63 -0
  175. package/dist/examples/legacy-examples.d.ts +9 -0
  176. package/dist/examples/legacy-examples.js +817 -0
  177. package/dist/examples/yarn-examples.d.ts +35 -0
  178. package/dist/examples/yarn-examples.js +189 -0
  179. package/dist/index.d.ts +21 -0
  180. package/dist/index.js +66 -0
  181. package/dist/lib/flag-manager.d.ts +21 -0
  182. package/dist/lib/flag-manager.js +99 -0
  183. package/dist/lib/yarn-converter/__tests__/round-trip.test.d.ts +1 -0
  184. package/dist/lib/yarn-converter/__tests__/round-trip.test.js +171 -0
  185. package/dist/lib/yarn-converter.d.ts +17 -0
  186. package/dist/lib/yarn-converter.js +525 -0
  187. package/dist/lib/yarn-runner/__tests__/condition-evaluator.test.d.ts +1 -0
  188. package/dist/lib/yarn-runner/__tests__/condition-evaluator.test.js +173 -0
  189. package/dist/lib/yarn-runner/__tests__/node-processor.test.d.ts +1 -0
  190. package/dist/lib/yarn-runner/__tests__/node-processor.test.js +239 -0
  191. package/dist/lib/yarn-runner/__tests__/variable-manager.test.d.ts +1 -0
  192. package/dist/lib/yarn-runner/__tests__/variable-manager.test.js +108 -0
  193. package/dist/lib/yarn-runner/condition-evaluator.d.ts +12 -0
  194. package/dist/lib/yarn-runner/condition-evaluator.js +60 -0
  195. package/dist/lib/yarn-runner/index.d.ts +12 -0
  196. package/dist/lib/yarn-runner/index.js +21 -0
  197. package/dist/lib/yarn-runner/node-processor.d.ts +18 -0
  198. package/dist/lib/yarn-runner/node-processor.js +133 -0
  199. package/dist/lib/yarn-runner/variable-manager.d.ts +51 -0
  200. package/dist/lib/yarn-runner/variable-manager.js +124 -0
  201. package/dist/lib/yarn-runner/variable-operations.d.ts +16 -0
  202. package/dist/lib/yarn-runner/variable-operations.js +92 -0
  203. package/dist/types/conditionals.d.ts +29 -0
  204. package/dist/types/conditionals.js +2 -0
  205. package/dist/types/constants.d.ts +59 -0
  206. package/dist/types/constants.js +58 -0
  207. package/dist/types/flags.d.ts +49 -0
  208. package/dist/types/flags.js +52 -0
  209. package/dist/types/game-state.d.ts +62 -0
  210. package/dist/types/game-state.js +7 -0
  211. package/dist/types/index.d.ts +77 -0
  212. package/dist/types/index.js +2 -0
  213. package/dist/utils/constants.d.ts +5 -0
  214. package/dist/utils/constants.js +8 -0
  215. package/dist/utils/feature-flags.d.ts +11 -0
  216. package/dist/utils/feature-flags.js +14 -0
  217. package/dist/utils/game-state-flattener.d.ts +41 -0
  218. package/dist/utils/game-state-flattener.js +140 -0
  219. package/dist/utils/layout/collision.d.ts +27 -0
  220. package/dist/utils/layout/collision.js +77 -0
  221. package/dist/utils/layout/index.d.ts +82 -0
  222. package/dist/utils/layout/index.js +109 -0
  223. package/dist/utils/layout/registry.d.ts +91 -0
  224. package/dist/utils/layout/registry.js +151 -0
  225. package/dist/utils/layout/strategies/dagre.d.ts +19 -0
  226. package/dist/utils/layout/strategies/dagre.js +189 -0
  227. package/dist/utils/layout/strategies/force.d.ts +21 -0
  228. package/dist/utils/layout/strategies/force.js +182 -0
  229. package/dist/utils/layout/strategies/grid.d.ts +17 -0
  230. package/dist/utils/layout/strategies/grid.js +95 -0
  231. package/dist/utils/layout/strategies/index.d.ts +8 -0
  232. package/dist/utils/layout/strategies/index.js +14 -0
  233. package/dist/utils/layout/types.d.ts +100 -0
  234. package/dist/utils/layout/types.js +8 -0
  235. package/dist/utils/layout.d.ts +9 -0
  236. package/dist/utils/layout.js +25 -0
  237. package/dist/utils/node-helpers.d.ts +7 -0
  238. package/dist/utils/node-helpers.js +101 -0
  239. package/dist/utils/reactflow-converter.d.ts +42 -0
  240. package/dist/utils/reactflow-converter.js +223 -0
  241. package/package.json +70 -0
@@ -0,0 +1,129 @@
1
+ import { evaluateConditions } from './condition-evaluator';
2
+ /**
3
+ * Processes a dialogue node and returns the result
4
+ */
5
+ export function processNode(node, variableManager) {
6
+ // Player nodes - return choices
7
+ if (node.type === 'player') {
8
+ const availableChoices = node.choices?.filter(choice => {
9
+ if (!choice.conditions)
10
+ return true;
11
+ return evaluateConditions(choice.conditions, variableManager.getAllVariables(), variableManager.getAllMemoryFlags());
12
+ }) || [];
13
+ return {
14
+ content: '',
15
+ speaker: undefined,
16
+ nextNodeId: undefined,
17
+ isEnd: false,
18
+ isPlayerChoice: true,
19
+ choices: availableChoices
20
+ };
21
+ }
22
+ // Conditional nodes - evaluate blocks
23
+ if (node.type === 'conditional' && node.conditionalBlocks) {
24
+ const matchedBlock = findMatchingConditionalBlock(node.conditionalBlocks, variableManager);
25
+ if (matchedBlock) {
26
+ // Interpolate variables in content
27
+ const interpolatedContent = interpolateVariables(matchedBlock.content, variableManager);
28
+ return {
29
+ content: interpolatedContent,
30
+ speaker: matchedBlock.speaker,
31
+ nextNodeId: matchedBlock.nextNodeId || node.nextNodeId,
32
+ isEnd: !matchedBlock.nextNodeId && !node.nextNodeId,
33
+ isPlayerChoice: false,
34
+ choices: undefined
35
+ };
36
+ }
37
+ // No block matched - end dialogue
38
+ return {
39
+ content: '',
40
+ speaker: undefined,
41
+ nextNodeId: undefined,
42
+ isEnd: true,
43
+ isPlayerChoice: false,
44
+ choices: undefined
45
+ };
46
+ }
47
+ // NPC nodes - handle conditional blocks if present
48
+ if (node.type === 'npc') {
49
+ let content = node.content;
50
+ let speaker = node.speaker;
51
+ let nextNodeId = node.nextNodeId;
52
+ // Check for conditional blocks
53
+ if (node.conditionalBlocks && node.conditionalBlocks.length > 0) {
54
+ const matchedBlock = findMatchingConditionalBlock(node.conditionalBlocks, variableManager);
55
+ if (matchedBlock) {
56
+ content = matchedBlock.content;
57
+ speaker = matchedBlock.speaker || node.speaker;
58
+ // Conditional blocks can override nextNodeId
59
+ if (matchedBlock.nextNodeId) {
60
+ nextNodeId = matchedBlock.nextNodeId;
61
+ }
62
+ }
63
+ }
64
+ // Interpolate variables in content (e.g., "Hello {$name}")
65
+ content = interpolateVariables(content, variableManager);
66
+ return {
67
+ content,
68
+ speaker,
69
+ nextNodeId,
70
+ isEnd: !nextNodeId,
71
+ isPlayerChoice: false,
72
+ choices: undefined
73
+ };
74
+ }
75
+ // Default: end dialogue
76
+ return {
77
+ content: '',
78
+ speaker: undefined,
79
+ nextNodeId: undefined,
80
+ isEnd: true,
81
+ isPlayerChoice: false,
82
+ choices: undefined
83
+ };
84
+ }
85
+ /**
86
+ * Finds the first matching conditional block (if/elseif/else logic)
87
+ */
88
+ function findMatchingConditionalBlock(blocks, variableManager) {
89
+ let matchedBlock = null;
90
+ for (const block of blocks) {
91
+ if (block.type === 'else') {
92
+ // Only match else if no previous block matched
93
+ if (!matchedBlock) {
94
+ matchedBlock = block;
95
+ }
96
+ }
97
+ else if (block.condition && block.condition.length > 0) {
98
+ // Check if all conditions in this block are true
99
+ const allMatch = evaluateConditions(block.condition, variableManager.getAllVariables(), variableManager.getAllMemoryFlags());
100
+ if (allMatch) {
101
+ matchedBlock = block;
102
+ break; // Found a match, stop checking (if/elseif matched)
103
+ }
104
+ }
105
+ }
106
+ return matchedBlock;
107
+ }
108
+ /**
109
+ * Interpolates variables in text (e.g., "Hello {$name}" becomes "Hello John")
110
+ */
111
+ function interpolateVariables(text, variableManager) {
112
+ // Match {$variable} patterns
113
+ return text.replace(/\{\$(\w+)\}/g, (match, varName) => {
114
+ const value = variableManager.get(varName);
115
+ if (value === undefined) {
116
+ return match; // Keep original if variable not found
117
+ }
118
+ return String(value);
119
+ });
120
+ }
121
+ /**
122
+ * Validates that a nextNodeId exists and is valid
123
+ */
124
+ export function isValidNextNode(nextNodeId, availableNodes) {
125
+ if (!nextNodeId || !nextNodeId.trim()) {
126
+ return false;
127
+ }
128
+ return !!availableNodes[nextNodeId];
129
+ }
@@ -0,0 +1,51 @@
1
+ import { VariableState } from './condition-evaluator';
2
+ /**
3
+ * Manages variable state for Yarn Spinner execution
4
+ * Handles both game flags (persistent) and dialogue flags (temporary)
5
+ */
6
+ export declare class VariableManager {
7
+ private variables;
8
+ private memoryFlags;
9
+ constructor(initialVariables?: VariableState, initialMemoryFlags?: Set<string>);
10
+ /**
11
+ * Get a variable value
12
+ */
13
+ get(name: string): boolean | number | string | undefined;
14
+ /**
15
+ * Set a variable value
16
+ */
17
+ set(name: string, value: boolean | number | string): void;
18
+ /**
19
+ * Apply an operation to a variable (e.g., +=, -=, *=, /=)
20
+ * If the variable doesn't exist, it's initialized to 0 for numeric operations
21
+ */
22
+ applyOperation(name: string, operator: '+' | '-' | '*' | '/', value: number): void;
23
+ /**
24
+ * Add a memory flag (dialogue flag - temporary)
25
+ */
26
+ addMemoryFlag(name: string): void;
27
+ /**
28
+ * Remove a memory flag
29
+ */
30
+ removeMemoryFlag(name: string): void;
31
+ /**
32
+ * Check if a memory flag exists
33
+ */
34
+ hasMemoryFlag(name: string): boolean;
35
+ /**
36
+ * Get all variables (persistent)
37
+ */
38
+ getAllVariables(): VariableState;
39
+ /**
40
+ * Get all memory flags
41
+ */
42
+ getAllMemoryFlags(): Set<string>;
43
+ /**
44
+ * Clear all memory flags (for dialogue reset)
45
+ */
46
+ clearMemoryFlags(): void;
47
+ /**
48
+ * Reset to initial state
49
+ */
50
+ reset(initialVariables?: VariableState, initialMemoryFlags?: Set<string>): void;
51
+ }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Manages variable state for Yarn Spinner execution
3
+ * Handles both game flags (persistent) and dialogue flags (temporary)
4
+ */
5
+ export class VariableManager {
6
+ constructor(initialVariables, initialMemoryFlags) {
7
+ this.variables = {};
8
+ this.memoryFlags = new Set();
9
+ if (initialVariables) {
10
+ this.variables = { ...initialVariables };
11
+ }
12
+ if (initialMemoryFlags) {
13
+ this.memoryFlags = new Set(initialMemoryFlags);
14
+ }
15
+ }
16
+ /**
17
+ * Get a variable value
18
+ */
19
+ get(name) {
20
+ // Check persistent variables first
21
+ if (this.variables[name] !== undefined) {
22
+ return this.variables[name];
23
+ }
24
+ // Check memory flags (dialogue flags)
25
+ if (this.memoryFlags.has(name)) {
26
+ return true;
27
+ }
28
+ return undefined;
29
+ }
30
+ /**
31
+ * Set a variable value
32
+ */
33
+ set(name, value) {
34
+ this.variables[name] = value;
35
+ }
36
+ /**
37
+ * Apply an operation to a variable (e.g., +=, -=, *=, /=)
38
+ * If the variable doesn't exist, it's initialized to 0 for numeric operations
39
+ */
40
+ applyOperation(name, operator, value) {
41
+ const current = this.get(name);
42
+ let currentNum;
43
+ if (current === undefined) {
44
+ currentNum = 0;
45
+ }
46
+ else if (typeof current === 'number') {
47
+ currentNum = current;
48
+ }
49
+ else if (typeof current === 'string') {
50
+ // Try to parse string as number
51
+ const parsed = parseFloat(current);
52
+ currentNum = isNaN(parsed) ? 0 : parsed;
53
+ }
54
+ else {
55
+ // Boolean: treat true as 1, false as 0
56
+ currentNum = current ? 1 : 0;
57
+ }
58
+ let result;
59
+ switch (operator) {
60
+ case '+':
61
+ result = currentNum + value;
62
+ break;
63
+ case '-':
64
+ result = currentNum - value;
65
+ break;
66
+ case '*':
67
+ result = currentNum * value;
68
+ break;
69
+ case '/':
70
+ result = value !== 0 ? currentNum / value : currentNum;
71
+ break;
72
+ default:
73
+ result = currentNum;
74
+ }
75
+ this.variables[name] = result;
76
+ }
77
+ /**
78
+ * Add a memory flag (dialogue flag - temporary)
79
+ */
80
+ addMemoryFlag(name) {
81
+ this.memoryFlags.add(name);
82
+ }
83
+ /**
84
+ * Remove a memory flag
85
+ */
86
+ removeMemoryFlag(name) {
87
+ this.memoryFlags.delete(name);
88
+ }
89
+ /**
90
+ * Check if a memory flag exists
91
+ */
92
+ hasMemoryFlag(name) {
93
+ return this.memoryFlags.has(name);
94
+ }
95
+ /**
96
+ * Get all variables (persistent)
97
+ */
98
+ getAllVariables() {
99
+ return { ...this.variables };
100
+ }
101
+ /**
102
+ * Get all memory flags
103
+ */
104
+ getAllMemoryFlags() {
105
+ return new Set(this.memoryFlags);
106
+ }
107
+ /**
108
+ * Clear all memory flags (for dialogue reset)
109
+ */
110
+ clearMemoryFlags() {
111
+ this.memoryFlags.clear();
112
+ }
113
+ /**
114
+ * Reset to initial state
115
+ */
116
+ reset(initialVariables, initialMemoryFlags) {
117
+ this.variables = initialVariables ? { ...initialVariables } : {};
118
+ this.memoryFlags = initialMemoryFlags ? new Set(initialMemoryFlags) : new Set();
119
+ }
120
+ }
@@ -0,0 +1,16 @@
1
+ import { VariableManager } from './variable-manager';
2
+ /**
3
+ * Parses and executes a Yarn variable operation command
4
+ * Supports:
5
+ * - <<set $var = value>> (assignment)
6
+ * - <<set $var += value>> (addition)
7
+ * - <<set $var -= value>> (subtraction)
8
+ * - <<set $var *= value>> (multiplication)
9
+ * - <<set $var /= value>> (division)
10
+ */
11
+ export declare function executeVariableOperation(command: string, variableManager: VariableManager): void;
12
+ /**
13
+ * Extracts and executes all variable operations from a node's content
14
+ * This processes any <<set>> commands embedded in the dialogue text
15
+ */
16
+ export declare function processVariableOperationsInContent(content: string, variableManager: VariableManager): string;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Parses and executes a Yarn variable operation command
3
+ * Supports:
4
+ * - <<set $var = value>> (assignment)
5
+ * - <<set $var += value>> (addition)
6
+ * - <<set $var -= value>> (subtraction)
7
+ * - <<set $var *= value>> (multiplication)
8
+ * - <<set $var /= value>> (division)
9
+ */
10
+ export function executeVariableOperation(command, variableManager) {
11
+ // Match: <<set $var = value>> or <<set $var += value>> etc.
12
+ const setMatch = command.match(/<<set\s+\$(\w+)\s*([+\-*/=]+)\s*(.+?)>>/);
13
+ if (!setMatch) {
14
+ return; // Invalid command, skip
15
+ }
16
+ const varName = setMatch[1];
17
+ const operator = setMatch[2].trim();
18
+ const valueStr = setMatch[3].trim();
19
+ // Parse the value
20
+ let value;
21
+ // Try to parse as number first
22
+ const numValue = parseFloat(valueStr);
23
+ if (!isNaN(numValue) && valueStr === String(numValue)) {
24
+ value = numValue;
25
+ }
26
+ else if (valueStr === 'true') {
27
+ value = true;
28
+ }
29
+ else if (valueStr === 'false') {
30
+ value = false;
31
+ }
32
+ else {
33
+ // Remove quotes if present
34
+ value = valueStr.replace(/^["']|["']$/g, '');
35
+ }
36
+ // Handle operations
37
+ if (operator === '=') {
38
+ // Simple assignment
39
+ variableManager.set(varName, value);
40
+ }
41
+ else if (operator === '+=') {
42
+ // Addition
43
+ if (typeof value === 'number') {
44
+ variableManager.applyOperation(varName, '+', value);
45
+ }
46
+ else {
47
+ // String concatenation
48
+ const current = variableManager.get(varName);
49
+ const currentStr = current !== undefined ? String(current) : '';
50
+ variableManager.set(varName, currentStr + String(value));
51
+ }
52
+ }
53
+ else if (operator === '-=') {
54
+ // Subtraction (numeric only)
55
+ if (typeof value === 'number') {
56
+ variableManager.applyOperation(varName, '-', value);
57
+ }
58
+ }
59
+ else if (operator === '*=') {
60
+ // Multiplication (numeric only)
61
+ if (typeof value === 'number') {
62
+ variableManager.applyOperation(varName, '*', value);
63
+ }
64
+ }
65
+ else if (operator === '/=') {
66
+ // Division (numeric only)
67
+ if (typeof value === 'number') {
68
+ variableManager.applyOperation(varName, '/', value);
69
+ }
70
+ }
71
+ }
72
+ /**
73
+ * Extracts and executes all variable operations from a node's content
74
+ * This processes any <<set>> commands embedded in the dialogue text
75
+ */
76
+ export function processVariableOperationsInContent(content, variableManager) {
77
+ // Find all <<set>> commands
78
+ const setCommandRegex = /<<set\s+\$(\w+)\s*([+\-*/=]+)\s*(.+?)>>/g;
79
+ let processedContent = content;
80
+ let match;
81
+ while ((match = setCommandRegex.exec(content)) !== null) {
82
+ // Execute the command
83
+ executeVariableOperation(match[0], variableManager);
84
+ // Remove the command from content (it's executed, not displayed)
85
+ processedContent = processedContent.replace(match[0], '');
86
+ }
87
+ return processedContent.trim();
88
+ }
@@ -0,0 +1,29 @@
1
+ import { ConditionOperator } from './constants';
2
+ /**
3
+ * Conditional block for Yarn Spinner if/elseif/else/endif
4
+ */
5
+ export interface ConditionalBlock {
6
+ type: 'if' | 'elseif' | 'else';
7
+ condition?: {
8
+ flag: string;
9
+ operator: ConditionOperator | 'equals' | 'not_equals' | 'greater_than' | 'less_than' | 'greater_equal' | 'less_equal';
10
+ value?: boolean | number | string;
11
+ };
12
+ content: string;
13
+ nextNodeId?: string;
14
+ }
15
+ /**
16
+ * Extended DialogueNode with conditional support
17
+ */
18
+ export interface ConditionalDialogueNode {
19
+ id: string;
20
+ type: 'npc' | 'player' | 'conditional';
21
+ speaker?: string;
22
+ content: string;
23
+ choices?: any[];
24
+ nextNodeId?: string;
25
+ setFlags?: string[];
26
+ conditionals?: ConditionalBlock[];
27
+ x: number;
28
+ y: number;
29
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Type-safe constants for Dialogue Forge
3
+ * Use these instead of string literals for better type safety and IDE support
4
+ */
5
+ /**
6
+ * Node types in a dialogue tree
7
+ */
8
+ export declare const NODE_TYPE: {
9
+ readonly NPC: "npc";
10
+ readonly PLAYER: "player";
11
+ readonly CONDITIONAL: "conditional";
12
+ };
13
+ export type NodeType = typeof NODE_TYPE[keyof typeof NODE_TYPE];
14
+ /**
15
+ * Flag types for game state management
16
+ */
17
+ export declare const FLAG_TYPE: {
18
+ readonly DIALOGUE: "dialogue";
19
+ readonly QUEST: "quest";
20
+ readonly ACHIEVEMENT: "achievement";
21
+ readonly ITEM: "item";
22
+ readonly STAT: "stat";
23
+ readonly TITLE: "title";
24
+ readonly GLOBAL: "global";
25
+ };
26
+ /**
27
+ * Condition operators for choice visibility
28
+ */
29
+ export declare const CONDITION_OPERATOR: {
30
+ readonly IS_SET: "is_set";
31
+ readonly IS_NOT_SET: "is_not_set";
32
+ readonly EQUALS: "equals";
33
+ readonly NOT_EQUALS: "not_equals";
34
+ readonly GREATER_THAN: "greater_than";
35
+ readonly LESS_THAN: "less_than";
36
+ readonly GREATER_EQUAL: "greater_equal";
37
+ readonly LESS_EQUAL: "less_equal";
38
+ };
39
+ export type ConditionOperator = typeof CONDITION_OPERATOR[keyof typeof CONDITION_OPERATOR];
40
+ /**
41
+ * Flag value types
42
+ */
43
+ export declare const FLAG_VALUE_TYPE: {
44
+ readonly BOOLEAN: "boolean";
45
+ readonly NUMBER: "number";
46
+ readonly STRING: "string";
47
+ };
48
+ export type FlagValueType = typeof FLAG_VALUE_TYPE[keyof typeof FLAG_VALUE_TYPE];
49
+ /**
50
+ * Quest state values (common states for quest flags)
51
+ */
52
+ export declare const QUEST_STATE: {
53
+ readonly NOT_STARTED: "not_started";
54
+ readonly STARTED: "started";
55
+ readonly IN_PROGRESS: "in_progress";
56
+ readonly COMPLETED: "completed";
57
+ readonly FAILED: "failed";
58
+ };
59
+ export type QuestState = typeof QUEST_STATE[keyof typeof QUEST_STATE];
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Type-safe constants for Dialogue Forge
3
+ * Use these instead of string literals for better type safety and IDE support
4
+ */
5
+ /**
6
+ * Node types in a dialogue tree
7
+ */
8
+ export const NODE_TYPE = {
9
+ NPC: 'npc',
10
+ PLAYER: 'player',
11
+ CONDITIONAL: 'conditional',
12
+ };
13
+ /**
14
+ * Flag types for game state management
15
+ */
16
+ export const FLAG_TYPE = {
17
+ DIALOGUE: 'dialogue',
18
+ QUEST: 'quest',
19
+ ACHIEVEMENT: 'achievement',
20
+ ITEM: 'item',
21
+ STAT: 'stat',
22
+ TITLE: 'title',
23
+ GLOBAL: 'global',
24
+ };
25
+ /**
26
+ * Condition operators for choice visibility
27
+ */
28
+ export const CONDITION_OPERATOR = {
29
+ IS_SET: 'is_set',
30
+ IS_NOT_SET: 'is_not_set',
31
+ EQUALS: 'equals',
32
+ NOT_EQUALS: 'not_equals',
33
+ GREATER_THAN: 'greater_than',
34
+ LESS_THAN: 'less_than',
35
+ GREATER_EQUAL: 'greater_equal',
36
+ LESS_EQUAL: 'less_equal',
37
+ };
38
+ /**
39
+ * Flag value types
40
+ */
41
+ export const FLAG_VALUE_TYPE = {
42
+ BOOLEAN: 'boolean',
43
+ NUMBER: 'number',
44
+ STRING: 'string',
45
+ };
46
+ /**
47
+ * Quest state values (common states for quest flags)
48
+ */
49
+ export const QUEST_STATE = {
50
+ NOT_STARTED: 'not_started',
51
+ STARTED: 'started',
52
+ IN_PROGRESS: 'in_progress',
53
+ COMPLETED: 'completed',
54
+ FAILED: 'failed',
55
+ };
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Flag System for Dialogue Forge
3
+ *
4
+ * Flags represent game state that can be checked and modified by dialogues.
5
+ * Different flag types serve different purposes in the game.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { FLAG_TYPE, FlagSchema } from '@magicborn/dialogue-forge';
10
+ *
11
+ * const mySchema: FlagSchema = {
12
+ * flags: [
13
+ * {
14
+ * id: 'quest_main',
15
+ * name: 'Main Quest',
16
+ * type: FLAG_TYPE.QUEST,
17
+ * category: 'quests'
18
+ * }
19
+ * ]
20
+ * };
21
+ * ```
22
+ */
23
+ import { FLAG_TYPE, FlagValueType } from './constants';
24
+ export type FlagType = typeof FLAG_TYPE[keyof typeof FLAG_TYPE];
25
+ export interface FlagDefinition {
26
+ id: string;
27
+ name: string;
28
+ description?: string;
29
+ type: FlagType;
30
+ category?: string;
31
+ defaultValue?: boolean | number | string;
32
+ valueType?: FlagValueType;
33
+ }
34
+ export interface FlagSchema {
35
+ flags: FlagDefinition[];
36
+ categories?: string[];
37
+ }
38
+ /**
39
+ * Flag Reference - used in dialogue nodes
40
+ */
41
+ export interface FlagReference {
42
+ flagId: string;
43
+ operator?: 'is_set' | 'is_not_set' | 'equals' | 'greater_than' | 'less_than';
44
+ value?: boolean | number | string;
45
+ }
46
+ /**
47
+ * Example flag schema for a game
48
+ */
49
+ export declare const exampleFlagSchema: FlagSchema;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Flag System for Dialogue Forge
3
+ *
4
+ * Flags represent game state that can be checked and modified by dialogues.
5
+ * Different flag types serve different purposes in the game.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { FLAG_TYPE, FlagSchema } from '@magicborn/dialogue-forge';
10
+ *
11
+ * const mySchema: FlagSchema = {
12
+ * flags: [
13
+ * {
14
+ * id: 'quest_main',
15
+ * name: 'Main Quest',
16
+ * type: FLAG_TYPE.QUEST,
17
+ * category: 'quests'
18
+ * }
19
+ * ]
20
+ * };
21
+ * ```
22
+ */
23
+ import { FLAG_TYPE, FLAG_VALUE_TYPE } from './constants';
24
+ /**
25
+ * Example flag schema for a game
26
+ */
27
+ export const exampleFlagSchema = {
28
+ categories: ['quests', 'achievements', 'items', 'stats', 'titles'],
29
+ flags: [
30
+ // Quest flags
31
+ { id: 'quest_dragon_slayer', name: 'Dragon Slayer Quest', type: FLAG_TYPE.QUEST, category: 'quests', valueType: FLAG_VALUE_TYPE.STRING },
32
+ { id: 'quest_dragon_slayer_complete', name: 'Dragon Slayer Complete', type: FLAG_TYPE.QUEST, category: 'quests' },
33
+ // Achievement flags
34
+ { id: 'achievement_first_quest', name: 'First Quest', type: FLAG_TYPE.ACHIEVEMENT, category: 'achievements' },
35
+ { id: 'achievement_dragon_slayer', name: 'Dragon Slayer', type: FLAG_TYPE.ACHIEVEMENT, category: 'achievements' },
36
+ // Item flags
37
+ { id: 'item_ancient_key', name: 'Ancient Key', type: FLAG_TYPE.ITEM, category: 'items' },
38
+ { id: 'item_gold', name: 'Gold', type: FLAG_TYPE.STAT, category: 'stats', valueType: FLAG_VALUE_TYPE.NUMBER, defaultValue: 0 },
39
+ // Stat flags
40
+ { id: 'stat_reputation', name: 'Reputation', type: FLAG_TYPE.STAT, category: 'stats', valueType: FLAG_VALUE_TYPE.NUMBER, defaultValue: 0 },
41
+ { id: 'stat_charisma', name: 'Charisma', type: FLAG_TYPE.STAT, category: 'stats', valueType: FLAG_VALUE_TYPE.NUMBER, defaultValue: 10 },
42
+ // Title flags
43
+ { id: 'title_hero', name: 'Hero', type: FLAG_TYPE.TITLE, category: 'titles' },
44
+ // Dialogue flags (temporary, dialogue-scoped)
45
+ { id: 'dialogue_met_stranger', name: 'Met Stranger', type: FLAG_TYPE.DIALOGUE, category: 'dialogue' },
46
+ { id: 'dialogue_seeks_knowledge', name: 'Seeks Knowledge', type: FLAG_TYPE.DIALOGUE, category: 'dialogue' },
47
+ { id: 'dialogue_hostile', name: 'Hostile Response', type: FLAG_TYPE.DIALOGUE, category: 'dialogue' },
48
+ ]
49
+ };