@rohal12/spindle 0.51.4 → 0.52.1
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/dist/pkg/format.js +1 -1
- package/dist/pkg/headless.js +4512 -1702
- package/dist/pkg/macro-registry.json +7 -7
- package/dist/pkg/story-variables.js +1636 -177
- package/package.json +5 -2
- package/src/action-registry.ts +70 -18
- package/src/automation/runner.ts +2 -1
- package/src/class-registry.ts +214 -103
- package/src/components/Passage.tsx +2 -2
- package/src/components/PassageDialog.tsx +2 -5
- package/src/components/StoryInterface.tsx +2 -4
- package/src/components/macros/Button.tsx +5 -31
- package/src/components/macros/Checkbox.tsx +7 -4
- package/src/components/macros/Computed.tsx +28 -14
- package/src/components/macros/For.tsx +29 -3
- package/src/components/macros/If.tsx +8 -0
- package/src/components/macros/Include.tsx +7 -6
- package/src/components/macros/MacroError.tsx +2 -1
- package/src/components/macros/MacroLink.tsx +12 -45
- package/src/components/macros/Meter.tsx +11 -3
- package/src/components/macros/Nobr.tsx +1 -0
- package/src/components/macros/PassageDisplay.tsx +3 -0
- package/src/components/macros/Print.tsx +4 -0
- package/src/components/macros/Radiobutton.tsx +5 -2
- package/src/components/macros/SaveManager.tsx +25 -8
- package/src/components/macros/Set.tsx +5 -4
- package/src/components/macros/Span.tsx +1 -0
- package/src/components/macros/StoryTitle.tsx +1 -0
- package/src/components/macros/Switch.tsx +13 -0
- package/src/components/macros/Unset.tsx +31 -10
- package/src/components/macros/VarDisplay.tsx +21 -4
- package/src/components/macros/Widget.tsx +20 -1
- package/src/components/macros/WidgetInvocation.tsx +17 -75
- package/src/components/macros/arg-utils.ts +107 -1
- package/src/components/macros/detached-body.tsx +68 -0
- package/src/components/macros/option-utils.ts +3 -2
- package/src/define-macro.ts +32 -5
- package/src/execute-mutation.ts +271 -68
- package/src/expression.ts +91 -59
- package/src/hooks/use-action.ts +24 -3
- package/src/hooks/use-interpolate.ts +36 -5
- package/src/index.tsx +12 -2
- package/src/interpolation.ts +394 -96
- package/src/js-lexer.ts +1231 -97
- package/src/markup/ast.ts +7 -2
- package/src/markup/code-attributes.ts +64 -0
- package/src/markup/markdown.ts +188 -9
- package/src/markup/render.tsx +430 -49
- package/src/markup/tokenizer.ts +578 -110
- package/src/prng.ts +41 -8
- package/src/registry.ts +35 -0
- package/src/saves/save-manager.ts +346 -160
- package/src/saves/storage.ts +16 -7
- package/src/saves/types.ts +2 -1
- package/src/settings.ts +12 -9
- package/src/store.ts +640 -186
- package/src/story-api.ts +38 -73
- package/src/story-init.ts +1 -1
- package/src/story-variables.ts +98 -102
- package/src/triggers.ts +10 -12
- package/src/utils/counts.ts +45 -0
- package/src/utils/error-message.ts +12 -0
- package/src/utils/live-locals.ts +10 -3
- package/src/utils/namespace.ts +71 -0
- package/src/utils/object-path.ts +99 -14
- package/src/utils/stable-key.ts +14 -9
- package/src/widgets/widget-registry.ts +9 -0
- package/types/index.d.ts +43 -7
- package/types/tooling.d.ts +1 -0
package/src/prng.ts
CHANGED
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
// Core algorithm
|
|
10
10
|
// ---------------------------------------------------------------------------
|
|
11
11
|
|
|
12
|
+
const MULBERRY_STEP = 0x6d2b79f5;
|
|
13
|
+
|
|
12
14
|
/** Mulberry32: fast, high-quality 32-bit PRNG. */
|
|
13
15
|
function mulberry32(seed: number): () => number {
|
|
14
16
|
let t = seed | 0;
|
|
15
17
|
return () => {
|
|
16
|
-
t = (t +
|
|
18
|
+
t = (t + MULBERRY_STEP) | 0;
|
|
17
19
|
let r = Math.imul(t ^ (t >>> 15), t | 1);
|
|
18
20
|
r ^= r + Math.imul(r ^ (r >>> 7), r | 61);
|
|
19
21
|
return ((r ^ (r >>> 14)) >>> 0) / 0x100000000;
|
|
@@ -38,6 +40,8 @@ let enabled = false;
|
|
|
38
40
|
let currentSeed = '';
|
|
39
41
|
let currentPull = 0;
|
|
40
42
|
let generator: (() => number) | null = null;
|
|
43
|
+
/** Incremented whenever the generator is replaced (init, restore, reset). */
|
|
44
|
+
let generation = 0;
|
|
41
45
|
|
|
42
46
|
// ---------------------------------------------------------------------------
|
|
43
47
|
// Public API
|
|
@@ -69,6 +73,7 @@ export function initPRNG(seed?: string, useEntropy = true): void {
|
|
|
69
73
|
currentPull = 0;
|
|
70
74
|
generator = mulberry32(hashSeed(resolvedSeed));
|
|
71
75
|
enabled = true;
|
|
76
|
+
generation++;
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
/**
|
|
@@ -76,26 +81,54 @@ export function initPRNG(seed?: string, useEntropy = true): void {
|
|
|
76
81
|
* Recreates the generator from the seed and fast-forwards to the saved pull count.
|
|
77
82
|
*/
|
|
78
83
|
export function restorePRNG(seed: string, pull: number): void {
|
|
84
|
+
generation++;
|
|
85
|
+
moveTo(seed, pull);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Recreate the generator at `pull` pulls from `seed`. */
|
|
89
|
+
function moveTo(seed: string, pull: number): void {
|
|
79
90
|
currentSeed = seed;
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
// Fast-forward in constant time: each pull adds MULBERRY_STEP to the
|
|
92
|
+
// 32-bit state, so `pull` pulls add pull × MULBERRY_STEP (mod 2^32). A
|
|
93
|
+
// loop would hang on the large counts an imported save may hold.
|
|
94
|
+
const steps = Math.imul(pull % 0x100000000, MULBERRY_STEP);
|
|
95
|
+
generator = mulberry32((hashSeed(seed) + steps) | 0);
|
|
82
96
|
enabled = true;
|
|
83
|
-
|
|
84
|
-
// Fast-forward
|
|
85
|
-
for (let i = 0; i < pull; i++) {
|
|
86
|
-
generator();
|
|
87
|
-
}
|
|
88
97
|
currentPull = pull;
|
|
89
98
|
}
|
|
90
99
|
|
|
91
100
|
/** Disable the PRNG (used on restart before StoryInit re-enables it). */
|
|
92
101
|
export function resetPRNG(): void {
|
|
102
|
+
generation++;
|
|
93
103
|
enabled = false;
|
|
94
104
|
currentSeed = '';
|
|
95
105
|
currentPull = 0;
|
|
96
106
|
generator = null;
|
|
97
107
|
}
|
|
98
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Run `fn` without its draws advancing the sequence: the draws it makes are
|
|
111
|
+
* taken back afterwards (also when it throws), so the next draws return the
|
|
112
|
+
* same values again. Save and load event handlers run like this, so that
|
|
113
|
+
* saving or loading never shifts the story's random sequence (a load replays
|
|
114
|
+
* the saved passage from its entry state, without the save's handlers). A
|
|
115
|
+
* generator `fn` replaced (a restart or load it started) is kept.
|
|
116
|
+
*/
|
|
117
|
+
export function withoutDraws<T>(fn: () => T): T {
|
|
118
|
+
const start = { generation, seed: currentSeed, pull: currentPull };
|
|
119
|
+
try {
|
|
120
|
+
return fn();
|
|
121
|
+
} finally {
|
|
122
|
+
if (
|
|
123
|
+
enabled &&
|
|
124
|
+
generation === start.generation &&
|
|
125
|
+
currentPull !== start.pull
|
|
126
|
+
) {
|
|
127
|
+
moveTo(start.seed, start.pull);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
99
132
|
/** Returns the current PRNG state for snapshotting, or null if disabled. */
|
|
100
133
|
export function snapshotPRNG(): PRNGSnapshot | null {
|
|
101
134
|
if (!enabled) return null;
|
package/src/registry.ts
CHANGED
|
@@ -22,6 +22,41 @@ export function getMacro(name: string): ComponentType<MacroProps> | undefined {
|
|
|
22
22
|
return registry.get(name.toLowerCase());
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* What a macro's text form gets: see MacroDefinition.text. Evaluation runs
|
|
27
|
+
* in the scope of the attribute (or label) being resolved.
|
|
28
|
+
*/
|
|
29
|
+
export interface MacroTextContext {
|
|
30
|
+
/** Evaluate an expression in the current scope. */
|
|
31
|
+
evaluate: (expr: string) => unknown;
|
|
32
|
+
/**
|
|
33
|
+
* The text of AST nodes (a body or branch) in the current scope, with
|
|
34
|
+
* `locals` (keys without `@`) added on top of the current locals.
|
|
35
|
+
*/
|
|
36
|
+
renderText: (nodes: ASTNode[], locals?: Record<string, unknown>) => string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** A macro's text form: the string it stands for in text-only markup. */
|
|
40
|
+
export type MacroTextRenderer = (
|
|
41
|
+
props: MacroProps,
|
|
42
|
+
ctx: MacroTextContext,
|
|
43
|
+
) => string;
|
|
44
|
+
|
|
45
|
+
const textRegistry = new Map<string, MacroTextRenderer>();
|
|
46
|
+
|
|
47
|
+
/** Register (or, with undefined, remove) the text form of a macro. */
|
|
48
|
+
export function registerMacroText(
|
|
49
|
+
name: string,
|
|
50
|
+
text: MacroTextRenderer | undefined,
|
|
51
|
+
): void {
|
|
52
|
+
if (text) textRegistry.set(name.toLowerCase(), text);
|
|
53
|
+
else textRegistry.delete(name.toLowerCase());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function getMacroText(name: string): MacroTextRenderer | undefined {
|
|
57
|
+
return textRegistry.get(name.toLowerCase());
|
|
58
|
+
}
|
|
59
|
+
|
|
25
60
|
const subMacros = new Set<string>();
|
|
26
61
|
|
|
27
62
|
export function registerSubMacro(name: string): void {
|