@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.
- package/README.md +233 -0
- package/bin/dialogue-forge.js +78 -0
- package/demo/app/layout.tsx +36 -0
- package/demo/app/page.tsx +440 -0
- package/demo/components/ThemeSwitcher.tsx +611 -0
- package/demo/next.config.mjs +7 -0
- package/demo/package.json +29 -0
- package/demo/postcss.config.mjs +7 -0
- package/demo/public/logo.svg +1 -0
- package/demo/styles/globals.css +19 -0
- package/demo/tailwind.config.ts +90 -0
- package/demo/tsconfig.json +42 -0
- package/dist/components/ChoiceEdgeV2.d.ts +3 -0
- package/dist/components/ChoiceEdgeV2.js +103 -0
- package/dist/components/CodeBlock.d.ts +8 -0
- package/dist/components/CodeBlock.js +24 -0
- package/dist/components/ConditionAutocomplete.d.ts +14 -0
- package/dist/components/ConditionAutocomplete.js +284 -0
- package/dist/components/ConditionalNodeV2.d.ts +16 -0
- package/dist/components/ConditionalNodeV2.js +147 -0
- package/dist/components/DialogueEditorV2.d.ts +22 -0
- package/dist/components/DialogueEditorV2.js +1170 -0
- package/dist/components/EdgeIcon.d.ts +8 -0
- package/dist/components/EdgeIcon.js +13 -0
- package/dist/components/ExampleLoader.d.ts +11 -0
- package/dist/components/ExampleLoader.js +52 -0
- package/dist/components/ExampleLoaderButton.d.ts +15 -0
- package/dist/components/ExampleLoaderButton.js +102 -0
- package/dist/components/FlagManager.d.ts +11 -0
- package/dist/components/FlagManager.js +282 -0
- package/dist/components/FlagSelector.d.ts +11 -0
- package/dist/components/FlagSelector.js +235 -0
- package/dist/components/GuidePanel.d.ts +7 -0
- package/dist/components/GuidePanel.js +1176 -0
- package/dist/components/Minimap.d.ts +16 -0
- package/dist/components/Minimap.js +93 -0
- package/dist/components/NPCEdgeV2.d.ts +3 -0
- package/dist/components/NPCEdgeV2.js +104 -0
- package/dist/components/NPCNodeV2.d.ts +26 -0
- package/dist/components/NPCNodeV2.js +86 -0
- package/dist/components/NodeEditor.d.ts +18 -0
- package/dist/components/NodeEditor.js +1025 -0
- package/dist/components/PlayView.d.ts +12 -0
- package/dist/components/PlayView.js +307 -0
- package/dist/components/PlayerNodeV2.d.ts +16 -0
- package/dist/components/PlayerNodeV2.js +139 -0
- package/dist/components/ReactFlowPOC.d.ts +61 -0
- package/dist/components/ReactFlowPOC.js +312 -0
- package/dist/components/ScenePlayer.d.ts +18 -0
- package/dist/components/ScenePlayer.js +196 -0
- package/dist/components/YarnView.d.ts +9 -0
- package/dist/components/YarnView.js +45 -0
- package/dist/components/ZoomControls.d.ts +11 -0
- package/dist/components/ZoomControls.js +34 -0
- package/dist/esm/components/ChoiceEdgeV2.d.ts +3 -0
- package/dist/esm/components/ChoiceEdgeV2.js +67 -0
- package/dist/esm/components/CodeBlock.d.ts +8 -0
- package/dist/esm/components/CodeBlock.js +18 -0
- package/dist/esm/components/ConditionAutocomplete.d.ts +14 -0
- package/dist/esm/components/ConditionAutocomplete.js +248 -0
- package/dist/esm/components/ConditionalNodeV2.d.ts +16 -0
- package/dist/esm/components/ConditionalNodeV2.js +111 -0
- package/dist/esm/components/DialogueEditorV2.d.ts +22 -0
- package/dist/esm/components/DialogueEditorV2.js +1134 -0
- package/dist/esm/components/EdgeIcon.d.ts +8 -0
- package/dist/esm/components/EdgeIcon.js +7 -0
- package/dist/esm/components/ExampleLoader.d.ts +11 -0
- package/dist/esm/components/ExampleLoader.js +46 -0
- package/dist/esm/components/ExampleLoaderButton.d.ts +15 -0
- package/dist/esm/components/ExampleLoaderButton.js +66 -0
- package/dist/esm/components/FlagManager.d.ts +11 -0
- package/dist/esm/components/FlagManager.js +246 -0
- package/dist/esm/components/FlagSelector.d.ts +11 -0
- package/dist/esm/components/FlagSelector.js +199 -0
- package/dist/esm/components/GuidePanel.d.ts +7 -0
- package/dist/esm/components/GuidePanel.js +1140 -0
- package/dist/esm/components/Minimap.d.ts +16 -0
- package/dist/esm/components/Minimap.js +57 -0
- package/dist/esm/components/NPCEdgeV2.d.ts +3 -0
- package/dist/esm/components/NPCEdgeV2.js +68 -0
- package/dist/esm/components/NPCNodeV2.d.ts +26 -0
- package/dist/esm/components/NPCNodeV2.js +80 -0
- package/dist/esm/components/NodeEditor.d.ts +18 -0
- package/dist/esm/components/NodeEditor.js +989 -0
- package/dist/esm/components/PlayView.d.ts +12 -0
- package/dist/esm/components/PlayView.js +271 -0
- package/dist/esm/components/PlayerNodeV2.d.ts +16 -0
- package/dist/esm/components/PlayerNodeV2.js +103 -0
- package/dist/esm/components/ReactFlowPOC.d.ts +61 -0
- package/dist/esm/components/ReactFlowPOC.js +275 -0
- package/dist/esm/components/ScenePlayer.d.ts +18 -0
- package/dist/esm/components/ScenePlayer.js +160 -0
- package/dist/esm/components/YarnView.d.ts +9 -0
- package/dist/esm/components/YarnView.js +39 -0
- package/dist/esm/components/ZoomControls.d.ts +11 -0
- package/dist/esm/components/ZoomControls.js +28 -0
- package/dist/esm/examples/example-loader.d.ts +29 -0
- package/dist/esm/examples/example-loader.js +103 -0
- package/dist/esm/examples/examples-registry.d.ts +38 -0
- package/dist/esm/examples/examples-registry.js +153 -0
- package/dist/esm/examples/index.d.ts +26 -0
- package/dist/esm/examples/index.js +50 -0
- package/dist/esm/examples/legacy-examples.d.ts +9 -0
- package/dist/esm/examples/legacy-examples.js +814 -0
- package/dist/esm/examples/yarn-examples.d.ts +35 -0
- package/dist/esm/examples/yarn-examples.js +181 -0
- package/dist/esm/index.d.ts +21 -0
- package/dist/esm/index.js +26 -0
- package/dist/esm/lib/flag-manager.d.ts +21 -0
- package/dist/esm/lib/flag-manager.js +93 -0
- package/dist/esm/lib/yarn-converter/__tests__/round-trip.test.d.ts +1 -0
- package/dist/esm/lib/yarn-converter/__tests__/round-trip.test.js +169 -0
- package/dist/esm/lib/yarn-converter.d.ts +17 -0
- package/dist/esm/lib/yarn-converter.js +521 -0
- package/dist/esm/lib/yarn-runner/__tests__/condition-evaluator.test.d.ts +1 -0
- package/dist/esm/lib/yarn-runner/__tests__/condition-evaluator.test.js +171 -0
- package/dist/esm/lib/yarn-runner/__tests__/node-processor.test.d.ts +1 -0
- package/dist/esm/lib/yarn-runner/__tests__/node-processor.test.js +237 -0
- package/dist/esm/lib/yarn-runner/__tests__/variable-manager.test.d.ts +1 -0
- package/dist/esm/lib/yarn-runner/__tests__/variable-manager.test.js +106 -0
- package/dist/esm/lib/yarn-runner/condition-evaluator.d.ts +12 -0
- package/dist/esm/lib/yarn-runner/condition-evaluator.js +56 -0
- package/dist/esm/lib/yarn-runner/index.d.ts +12 -0
- package/dist/esm/lib/yarn-runner/index.js +11 -0
- package/dist/esm/lib/yarn-runner/node-processor.d.ts +18 -0
- package/dist/esm/lib/yarn-runner/node-processor.js +129 -0
- package/dist/esm/lib/yarn-runner/variable-manager.d.ts +51 -0
- package/dist/esm/lib/yarn-runner/variable-manager.js +120 -0
- package/dist/esm/lib/yarn-runner/variable-operations.d.ts +16 -0
- package/dist/esm/lib/yarn-runner/variable-operations.js +88 -0
- package/dist/esm/types/conditionals.d.ts +29 -0
- package/dist/esm/types/conditionals.js +1 -0
- package/dist/esm/types/constants.d.ts +59 -0
- package/dist/esm/types/constants.js +55 -0
- package/dist/esm/types/flags.d.ts +49 -0
- package/dist/esm/types/flags.js +49 -0
- package/dist/esm/types/game-state.d.ts +62 -0
- package/dist/esm/types/game-state.js +6 -0
- package/dist/esm/types/index.d.ts +77 -0
- package/dist/esm/types/index.js +1 -0
- package/dist/esm/utils/constants.d.ts +5 -0
- package/dist/esm/utils/constants.js +5 -0
- package/dist/esm/utils/feature-flags.d.ts +11 -0
- package/dist/esm/utils/feature-flags.js +11 -0
- package/dist/esm/utils/game-state-flattener.d.ts +41 -0
- package/dist/esm/utils/game-state-flattener.js +135 -0
- package/dist/esm/utils/layout/collision.d.ts +27 -0
- package/dist/esm/utils/layout/collision.js +74 -0
- package/dist/esm/utils/layout/index.d.ts +82 -0
- package/dist/esm/utils/layout/index.js +98 -0
- package/dist/esm/utils/layout/registry.d.ts +91 -0
- package/dist/esm/utils/layout/registry.js +148 -0
- package/dist/esm/utils/layout/strategies/dagre.d.ts +19 -0
- package/dist/esm/utils/layout/strategies/dagre.js +182 -0
- package/dist/esm/utils/layout/strategies/force.d.ts +21 -0
- package/dist/esm/utils/layout/strategies/force.js +178 -0
- package/dist/esm/utils/layout/strategies/grid.d.ts +17 -0
- package/dist/esm/utils/layout/strategies/grid.js +91 -0
- package/dist/esm/utils/layout/strategies/index.d.ts +8 -0
- package/dist/esm/utils/layout/strategies/index.js +8 -0
- package/dist/esm/utils/layout/types.d.ts +100 -0
- package/dist/esm/utils/layout/types.js +7 -0
- package/dist/esm/utils/layout.d.ts +9 -0
- package/dist/esm/utils/layout.js +17 -0
- package/dist/esm/utils/node-helpers.d.ts +7 -0
- package/dist/esm/utils/node-helpers.js +94 -0
- package/dist/esm/utils/reactflow-converter.d.ts +42 -0
- package/dist/esm/utils/reactflow-converter.js +217 -0
- package/dist/examples/example-loader.d.ts +29 -0
- package/dist/examples/example-loader.js +109 -0
- package/dist/examples/examples-registry.d.ts +38 -0
- package/dist/examples/examples-registry.js +160 -0
- package/dist/examples/index.d.ts +26 -0
- package/dist/examples/index.js +63 -0
- package/dist/examples/legacy-examples.d.ts +9 -0
- package/dist/examples/legacy-examples.js +817 -0
- package/dist/examples/yarn-examples.d.ts +35 -0
- package/dist/examples/yarn-examples.js +189 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +66 -0
- package/dist/lib/flag-manager.d.ts +21 -0
- package/dist/lib/flag-manager.js +99 -0
- package/dist/lib/yarn-converter/__tests__/round-trip.test.d.ts +1 -0
- package/dist/lib/yarn-converter/__tests__/round-trip.test.js +171 -0
- package/dist/lib/yarn-converter.d.ts +17 -0
- package/dist/lib/yarn-converter.js +525 -0
- package/dist/lib/yarn-runner/__tests__/condition-evaluator.test.d.ts +1 -0
- package/dist/lib/yarn-runner/__tests__/condition-evaluator.test.js +173 -0
- package/dist/lib/yarn-runner/__tests__/node-processor.test.d.ts +1 -0
- package/dist/lib/yarn-runner/__tests__/node-processor.test.js +239 -0
- package/dist/lib/yarn-runner/__tests__/variable-manager.test.d.ts +1 -0
- package/dist/lib/yarn-runner/__tests__/variable-manager.test.js +108 -0
- package/dist/lib/yarn-runner/condition-evaluator.d.ts +12 -0
- package/dist/lib/yarn-runner/condition-evaluator.js +60 -0
- package/dist/lib/yarn-runner/index.d.ts +12 -0
- package/dist/lib/yarn-runner/index.js +21 -0
- package/dist/lib/yarn-runner/node-processor.d.ts +18 -0
- package/dist/lib/yarn-runner/node-processor.js +133 -0
- package/dist/lib/yarn-runner/variable-manager.d.ts +51 -0
- package/dist/lib/yarn-runner/variable-manager.js +124 -0
- package/dist/lib/yarn-runner/variable-operations.d.ts +16 -0
- package/dist/lib/yarn-runner/variable-operations.js +92 -0
- package/dist/types/conditionals.d.ts +29 -0
- package/dist/types/conditionals.js +2 -0
- package/dist/types/constants.d.ts +59 -0
- package/dist/types/constants.js +58 -0
- package/dist/types/flags.d.ts +49 -0
- package/dist/types/flags.js +52 -0
- package/dist/types/game-state.d.ts +62 -0
- package/dist/types/game-state.js +7 -0
- package/dist/types/index.d.ts +77 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/constants.d.ts +5 -0
- package/dist/utils/constants.js +8 -0
- package/dist/utils/feature-flags.d.ts +11 -0
- package/dist/utils/feature-flags.js +14 -0
- package/dist/utils/game-state-flattener.d.ts +41 -0
- package/dist/utils/game-state-flattener.js +140 -0
- package/dist/utils/layout/collision.d.ts +27 -0
- package/dist/utils/layout/collision.js +77 -0
- package/dist/utils/layout/index.d.ts +82 -0
- package/dist/utils/layout/index.js +109 -0
- package/dist/utils/layout/registry.d.ts +91 -0
- package/dist/utils/layout/registry.js +151 -0
- package/dist/utils/layout/strategies/dagre.d.ts +19 -0
- package/dist/utils/layout/strategies/dagre.js +189 -0
- package/dist/utils/layout/strategies/force.d.ts +21 -0
- package/dist/utils/layout/strategies/force.js +182 -0
- package/dist/utils/layout/strategies/grid.d.ts +17 -0
- package/dist/utils/layout/strategies/grid.js +95 -0
- package/dist/utils/layout/strategies/index.d.ts +8 -0
- package/dist/utils/layout/strategies/index.js +14 -0
- package/dist/utils/layout/types.d.ts +100 -0
- package/dist/utils/layout/types.js +8 -0
- package/dist/utils/layout.d.ts +9 -0
- package/dist/utils/layout.js +25 -0
- package/dist/utils/node-helpers.d.ts +7 -0
- package/dist/utils/node-helpers.js +101 -0
- package/dist/utils/reactflow-converter.d.ts +42 -0
- package/dist/utils/reactflow-converter.js +223 -0
- 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
|
+
};
|