@novely/core 0.19.5 → 0.20.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/dist/index.d.ts +68 -47
- package/dist/index.global.js +430 -247
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +430 -247
- package/dist/index.js.map +1 -1
- package/package.json +62 -62
package/dist/index.global.js
CHANGED
|
@@ -164,13 +164,29 @@ var Novely = (() => {
|
|
|
164
164
|
var SKIPPED_DURING_RESTORE = /* @__PURE__ */ new Set(["dialog", "choice", "input", "vibrate", "text"]);
|
|
165
165
|
var BLOCK_EXIT_STATEMENTS = /* @__PURE__ */ new Set(["choice:exit", "condition:exit", "block:exit"]);
|
|
166
166
|
var BLOCK_STATEMENTS = /* @__PURE__ */ new Set(["choice", "condition", "block"]);
|
|
167
|
+
var AUDIO_ACTIONS = /* @__PURE__ */ new Set([
|
|
168
|
+
"playMusic",
|
|
169
|
+
"stopMusic",
|
|
170
|
+
"playSound",
|
|
171
|
+
"stopSound",
|
|
172
|
+
"voice",
|
|
173
|
+
"stopVoice"
|
|
174
|
+
]);
|
|
167
175
|
var EMPTY_SET = /* @__PURE__ */ new Set();
|
|
168
176
|
var DEFAULT_TYPEWRITER_SPEED = "Medium";
|
|
177
|
+
var MAIN_CONTEXT_KEY = "$MAIN";
|
|
178
|
+
|
|
179
|
+
// src/shared.ts
|
|
180
|
+
var STACK_MAP = /* @__PURE__ */ new Map();
|
|
169
181
|
|
|
170
182
|
// src/utils.ts
|
|
171
|
-
var matchAction = (values) => {
|
|
172
|
-
return (action, props) => {
|
|
173
|
-
|
|
183
|
+
var matchAction = (getContext, values) => {
|
|
184
|
+
return (action, props, { ctx, data }) => {
|
|
185
|
+
const context = typeof ctx === "string" ? getContext(ctx) : ctx;
|
|
186
|
+
return values[action]({
|
|
187
|
+
ctx: context,
|
|
188
|
+
data
|
|
189
|
+
}, props);
|
|
174
190
|
};
|
|
175
191
|
};
|
|
176
192
|
var isNumber = (val) => {
|
|
@@ -314,6 +330,189 @@ var Novely = (() => {
|
|
|
314
330
|
};
|
|
315
331
|
return MAP[action];
|
|
316
332
|
};
|
|
333
|
+
var getActionsFromPath = (story, path, raw = false) => {
|
|
334
|
+
let current = story;
|
|
335
|
+
let precurrent;
|
|
336
|
+
let ignoreNested = false;
|
|
337
|
+
let index = 0;
|
|
338
|
+
const max = path.reduce((acc, [type, val]) => {
|
|
339
|
+
if (isNull(type) && isNumber(val)) {
|
|
340
|
+
return acc + 1;
|
|
341
|
+
}
|
|
342
|
+
return acc;
|
|
343
|
+
}, 0);
|
|
344
|
+
const queue = [];
|
|
345
|
+
const blocks = [];
|
|
346
|
+
for (const [type, val] of path) {
|
|
347
|
+
if (type === "jump") {
|
|
348
|
+
precurrent = story;
|
|
349
|
+
current = current[val];
|
|
350
|
+
} else if (type === null) {
|
|
351
|
+
precurrent = current;
|
|
352
|
+
if (isNumber(val)) {
|
|
353
|
+
index++;
|
|
354
|
+
let startIndex = 0;
|
|
355
|
+
if (ignoreNested) {
|
|
356
|
+
const prev = findLastPathItemBeforeItemOfType(path.slice(0, index), "block");
|
|
357
|
+
if (prev) {
|
|
358
|
+
startIndex = prev[1];
|
|
359
|
+
ignoreNested = false;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
for (let i = startIndex; i <= val; i++) {
|
|
363
|
+
const item = current[i];
|
|
364
|
+
if (!isAction(item))
|
|
365
|
+
continue;
|
|
366
|
+
const [action, ...meta] = item;
|
|
367
|
+
const push = () => {
|
|
368
|
+
queue.push([action, meta]);
|
|
369
|
+
};
|
|
370
|
+
if (raw) {
|
|
371
|
+
push();
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
if (isSkippedDuringRestore(action) || isUserRequiredAction(action, meta)) {
|
|
375
|
+
if (index === max && i === val) {
|
|
376
|
+
push();
|
|
377
|
+
}
|
|
378
|
+
continue;
|
|
379
|
+
} else {
|
|
380
|
+
push();
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
current = current[val];
|
|
385
|
+
} else if (type === "choice") {
|
|
386
|
+
blocks.push(precurrent);
|
|
387
|
+
current = current[val + 1][1];
|
|
388
|
+
} else if (type === "condition") {
|
|
389
|
+
blocks.push(precurrent);
|
|
390
|
+
current = current[2][val];
|
|
391
|
+
} else if (type === "block") {
|
|
392
|
+
blocks.push(precurrent);
|
|
393
|
+
current = story[val];
|
|
394
|
+
} else if (type === "block:exit" || type === "choice:exit" || type === "condition:exit") {
|
|
395
|
+
current = blocks.pop();
|
|
396
|
+
ignoreNested = true;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return queue;
|
|
400
|
+
};
|
|
401
|
+
var createQueueProcessor = (queue) => {
|
|
402
|
+
const processedQueue = [];
|
|
403
|
+
const keep = /* @__PURE__ */ new Set();
|
|
404
|
+
const characters = /* @__PURE__ */ new Set();
|
|
405
|
+
const audio = {
|
|
406
|
+
music: /* @__PURE__ */ new Set(),
|
|
407
|
+
sound: /* @__PURE__ */ new Set()
|
|
408
|
+
};
|
|
409
|
+
const next = (i) => queue.slice(i + 1);
|
|
410
|
+
for (const [i, [action, meta]] of queue.entries()) {
|
|
411
|
+
keep.add(action);
|
|
412
|
+
if (action === "function" || action === "custom") {
|
|
413
|
+
if (action === "custom" && meta[0].callOnlyLatest) {
|
|
414
|
+
const notLatest = next(i).some(([, _meta]) => {
|
|
415
|
+
if (!_meta || !meta)
|
|
416
|
+
return false;
|
|
417
|
+
const c0 = _meta[0];
|
|
418
|
+
const c1 = meta[0];
|
|
419
|
+
const isIdenticalID = c0.id && c1.id && c0.id === c1.id;
|
|
420
|
+
const isIdenticalByReference = c0 === c1;
|
|
421
|
+
return isIdenticalID || isIdenticalByReference || str(c0) === str(c1);
|
|
422
|
+
});
|
|
423
|
+
if (notLatest)
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
processedQueue.push([action, meta]);
|
|
427
|
+
} else if (action === "showCharacter" || action === "playSound" || action === "playMusic" || action === "voice") {
|
|
428
|
+
const closing = getOppositeAction(action);
|
|
429
|
+
const skip = next(i).some(([_action, _meta]) => {
|
|
430
|
+
if (!_meta || !meta)
|
|
431
|
+
return false;
|
|
432
|
+
if (_meta[0] !== meta[0])
|
|
433
|
+
return false;
|
|
434
|
+
return _action === closing || _action === action;
|
|
435
|
+
});
|
|
436
|
+
if (skip)
|
|
437
|
+
continue;
|
|
438
|
+
if (action === "showCharacter") {
|
|
439
|
+
characters.add(meta[0]);
|
|
440
|
+
} else if (action === "playMusic") {
|
|
441
|
+
audio.music.add(meta[0]);
|
|
442
|
+
} else if (action === "playSound") {
|
|
443
|
+
audio.sound.add(meta[0]);
|
|
444
|
+
}
|
|
445
|
+
processedQueue.push([action, meta]);
|
|
446
|
+
} else if (action === "showBackground" || action === "animateCharacter" || action === "preload") {
|
|
447
|
+
const skip = next(i).some(([_action], i2, array) => action === _action);
|
|
448
|
+
if (skip)
|
|
449
|
+
continue;
|
|
450
|
+
processedQueue.push([action, meta]);
|
|
451
|
+
} else {
|
|
452
|
+
processedQueue.push([action, meta]);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
const run = async (match) => {
|
|
456
|
+
for await (const [action, meta] of processedQueue) {
|
|
457
|
+
const result = match(action, meta);
|
|
458
|
+
if (isPromise(result)) {
|
|
459
|
+
await result;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
processedQueue.length = 0;
|
|
463
|
+
};
|
|
464
|
+
const getKeep = () => {
|
|
465
|
+
return {
|
|
466
|
+
keep,
|
|
467
|
+
characters,
|
|
468
|
+
audio
|
|
469
|
+
};
|
|
470
|
+
};
|
|
471
|
+
return {
|
|
472
|
+
run,
|
|
473
|
+
getKeep
|
|
474
|
+
};
|
|
475
|
+
};
|
|
476
|
+
var getStack = (ctx) => {
|
|
477
|
+
const { id } = ctx;
|
|
478
|
+
const cached = STACK_MAP.get(id);
|
|
479
|
+
if (cached)
|
|
480
|
+
return cached;
|
|
481
|
+
const stack = [];
|
|
482
|
+
STACK_MAP.set(id, stack);
|
|
483
|
+
return stack;
|
|
484
|
+
};
|
|
485
|
+
var createUseStackFunction = (renderer) => {
|
|
486
|
+
const useStack = (context) => {
|
|
487
|
+
const ctx = typeof context === "string" ? renderer.getContext(context) : context;
|
|
488
|
+
const stack = getStack(ctx);
|
|
489
|
+
return {
|
|
490
|
+
get previous() {
|
|
491
|
+
return stack.previous;
|
|
492
|
+
},
|
|
493
|
+
get value() {
|
|
494
|
+
return stack.at(-1);
|
|
495
|
+
},
|
|
496
|
+
set value(value) {
|
|
497
|
+
stack[stack.length - 1] = value;
|
|
498
|
+
},
|
|
499
|
+
back() {
|
|
500
|
+
if (stack.length > 1) {
|
|
501
|
+
stack.previous = stack.pop();
|
|
502
|
+
ctx.meta.goingBack = true;
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
push(value) {
|
|
506
|
+
stack.push(value);
|
|
507
|
+
},
|
|
508
|
+
clear() {
|
|
509
|
+
stack.length = 0;
|
|
510
|
+
stack.length = 1;
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
};
|
|
514
|
+
return useStack;
|
|
515
|
+
};
|
|
317
516
|
|
|
318
517
|
// src/global.ts
|
|
319
518
|
var PRELOADED_ASSETS = /* @__PURE__ */ new Set();
|
|
@@ -333,10 +532,13 @@ var Novely = (() => {
|
|
|
333
532
|
const update = (fn) => {
|
|
334
533
|
push(current = fn(current));
|
|
335
534
|
};
|
|
535
|
+
const set = (val) => {
|
|
536
|
+
update(() => val);
|
|
537
|
+
};
|
|
336
538
|
const get = () => {
|
|
337
539
|
return current;
|
|
338
540
|
};
|
|
339
|
-
return { subscribe, update, get };
|
|
541
|
+
return { subscribe, update, set, get };
|
|
340
542
|
};
|
|
341
543
|
|
|
342
544
|
// ../deepmerge/dist/index.js
|
|
@@ -588,6 +790,7 @@ var Novely = (() => {
|
|
|
588
790
|
}
|
|
589
791
|
});
|
|
590
792
|
function state(value) {
|
|
793
|
+
const stack = useStack(MAIN_CONTEXT_KEY);
|
|
591
794
|
if (!value)
|
|
592
795
|
return stack.value[1];
|
|
593
796
|
const prev = stack.value[1];
|
|
@@ -604,26 +807,6 @@ var Novely = (() => {
|
|
|
604
807
|
[intime(Date.now()), "auto"]
|
|
605
808
|
];
|
|
606
809
|
};
|
|
607
|
-
const createStack = (current, stack2 = [current]) => {
|
|
608
|
-
return {
|
|
609
|
-
get value() {
|
|
610
|
-
return stack2.at(-1);
|
|
611
|
-
},
|
|
612
|
-
set value(value) {
|
|
613
|
-
stack2[stack2.length - 1] = value;
|
|
614
|
-
},
|
|
615
|
-
back() {
|
|
616
|
-
if (stack2.length > 1)
|
|
617
|
-
stack2.pop(), goingBack = true;
|
|
618
|
-
},
|
|
619
|
-
push(value) {
|
|
620
|
-
stack2.push(value);
|
|
621
|
-
},
|
|
622
|
-
clear() {
|
|
623
|
-
stack2 = [getDefaultSave(klona(defaultState))];
|
|
624
|
-
}
|
|
625
|
-
};
|
|
626
|
-
};
|
|
627
810
|
const getLanguageWithoutParameters = () => {
|
|
628
811
|
return getLanguage2(languages, getLanguage);
|
|
629
812
|
};
|
|
@@ -665,11 +848,10 @@ var Novely = (() => {
|
|
|
665
848
|
}
|
|
666
849
|
$$.update((prev) => (prev.dataLoaded = true, prev));
|
|
667
850
|
dataLoaded.resolve();
|
|
668
|
-
$.
|
|
851
|
+
$.set(stored);
|
|
669
852
|
};
|
|
670
853
|
storageDelay.then(getStoredData);
|
|
671
854
|
const initial = getDefaultSave(klona(defaultState));
|
|
672
|
-
const stack = createStack(initial);
|
|
673
855
|
addEventListener("visibilitychange", () => {
|
|
674
856
|
if (document.visibilityState === "hidden") {
|
|
675
857
|
throttledEmergencyOnStorageDataChange();
|
|
@@ -681,6 +863,7 @@ var Novely = (() => {
|
|
|
681
863
|
return;
|
|
682
864
|
if (!autosaves && type === "auto")
|
|
683
865
|
return;
|
|
866
|
+
const stack = useStack(MAIN_CONTEXT_KEY);
|
|
684
867
|
const current = klona(stack.value);
|
|
685
868
|
$.update((prev) => {
|
|
686
869
|
const isLatest = findLastIndex(prev.saves, (value) => times.has(value[2][0])) === prev.saves.length - 1;
|
|
@@ -710,139 +893,65 @@ var Novely = (() => {
|
|
|
710
893
|
}
|
|
711
894
|
restore(save2);
|
|
712
895
|
};
|
|
713
|
-
const set = (save2) => {
|
|
896
|
+
const set = (save2, ctx) => {
|
|
897
|
+
const stack = useStack(ctx || renderer.getContext(MAIN_CONTEXT_KEY));
|
|
714
898
|
stack.value = save2;
|
|
715
899
|
return restore(save2);
|
|
716
900
|
};
|
|
717
|
-
let restoring = false;
|
|
718
|
-
let goingBack = false;
|
|
719
901
|
let interacted = 0;
|
|
720
902
|
const restore = async (save2) => {
|
|
721
903
|
if (!$$.get().dataLoaded)
|
|
722
904
|
return;
|
|
723
905
|
let latest = save2 || $.get().saves.at(-1);
|
|
724
906
|
if (!latest) {
|
|
725
|
-
$.
|
|
907
|
+
$.set({
|
|
726
908
|
saves: [initial],
|
|
727
909
|
data: klona(defaultData),
|
|
728
910
|
meta: [getLanguageWithoutParameters(), DEFAULT_TYPEWRITER_SPEED, 1, 1, 1]
|
|
729
|
-
})
|
|
911
|
+
});
|
|
730
912
|
latest = klona(initial);
|
|
731
913
|
}
|
|
732
|
-
|
|
733
|
-
const
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
let index = 0;
|
|
738
|
-
const max = stack.value[0].reduce((acc, [type, val]) => {
|
|
739
|
-
if (isNull(type) && isNumber(val)) {
|
|
740
|
-
return acc + 1;
|
|
741
|
-
}
|
|
742
|
-
return acc;
|
|
743
|
-
}, 0);
|
|
744
|
-
const queue = [];
|
|
745
|
-
const keep = /* @__PURE__ */ new Set();
|
|
746
|
-
const characters2 = /* @__PURE__ */ new Set();
|
|
747
|
-
const blocks = [];
|
|
748
|
-
for (const [type, val] of path) {
|
|
749
|
-
if (type === "jump") {
|
|
750
|
-
precurrent = story;
|
|
751
|
-
current = current[val];
|
|
752
|
-
} else if (type === null) {
|
|
753
|
-
precurrent = current;
|
|
754
|
-
if (isNumber(val)) {
|
|
755
|
-
index++;
|
|
756
|
-
let startIndex = 0;
|
|
757
|
-
if (ignoreNested) {
|
|
758
|
-
const prev = findLastPathItemBeforeItemOfType(path.slice(0, index), "block");
|
|
759
|
-
if (prev) {
|
|
760
|
-
startIndex = prev[1];
|
|
761
|
-
ignoreNested = false;
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
for (let i = startIndex; i <= val; i++) {
|
|
765
|
-
const item = current[i];
|
|
766
|
-
if (!isAction(item))
|
|
767
|
-
continue;
|
|
768
|
-
const [action2, ...meta] = item;
|
|
769
|
-
const push2 = () => {
|
|
770
|
-
keep.add(action2);
|
|
771
|
-
queue.push([action2, meta]);
|
|
772
|
-
};
|
|
773
|
-
if (action2 === "showCharacter")
|
|
774
|
-
characters2.add(meta[0]);
|
|
775
|
-
if (isSkippedDuringRestore(action2) || isUserRequiredAction(action2, meta)) {
|
|
776
|
-
if (index === max && i === val) {
|
|
777
|
-
push2();
|
|
778
|
-
} else {
|
|
779
|
-
continue;
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
push2();
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
current = current[val];
|
|
786
|
-
} else if (type === "choice") {
|
|
787
|
-
blocks.push(precurrent);
|
|
788
|
-
current = current[val + 1][1];
|
|
789
|
-
} else if (type === "condition") {
|
|
790
|
-
blocks.push(precurrent);
|
|
791
|
-
current = current[2][val];
|
|
792
|
-
} else if (type === "block") {
|
|
793
|
-
blocks.push(precurrent);
|
|
794
|
-
current = story[val];
|
|
795
|
-
} else if (type === "block:exit" || type === "choice:exit" || type === "condition:exit") {
|
|
796
|
-
current = blocks.pop();
|
|
797
|
-
ignoreNested = true;
|
|
798
|
-
}
|
|
799
|
-
}
|
|
914
|
+
const context = renderer.getContext(MAIN_CONTEXT_KEY);
|
|
915
|
+
const stack = useStack(context);
|
|
916
|
+
context.meta.restoring = true;
|
|
917
|
+
const previous = stack.previous;
|
|
918
|
+
const [path] = stack.value = latest;
|
|
800
919
|
renderer.ui.showScreen("game");
|
|
801
|
-
|
|
802
|
-
const
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
});
|
|
815
|
-
if (notLatest)
|
|
816
|
-
continue;
|
|
817
|
-
}
|
|
818
|
-
const result = match(action2, meta);
|
|
819
|
-
if (isPromise(result)) {
|
|
820
|
-
await result;
|
|
920
|
+
const queue = getActionsFromPath(story, path);
|
|
921
|
+
const processor = createQueueProcessor(queue);
|
|
922
|
+
const { keep, characters: characters2, audio } = processor.getKeep();
|
|
923
|
+
if (previous) {
|
|
924
|
+
const prevQueue = getActionsFromPath(story, previous[0], true);
|
|
925
|
+
const currQueue = getActionsFromPath(story, path, true);
|
|
926
|
+
for (let i = prevQueue.length - 1; i > currQueue.length; i--) {
|
|
927
|
+
const element = prevQueue[i];
|
|
928
|
+
if (isAction(element)) {
|
|
929
|
+
const [action2, props] = element;
|
|
930
|
+
if (action2 === "custom") {
|
|
931
|
+
context.clearCustom(props[0]);
|
|
932
|
+
}
|
|
821
933
|
}
|
|
822
|
-
} else if (action2 === "showCharacter" || action2 === "playSound" || action2 === "playMusic" || action2 === "voice") {
|
|
823
|
-
const closing = getOppositeAction(action2);
|
|
824
|
-
const skip = next2(i).some(([_action, _meta]) => {
|
|
825
|
-
if (!_meta || !meta)
|
|
826
|
-
return false;
|
|
827
|
-
if (_meta[0] !== meta[0])
|
|
828
|
-
return false;
|
|
829
|
-
return _action === closing || _action === action2;
|
|
830
|
-
});
|
|
831
|
-
if (skip)
|
|
832
|
-
continue;
|
|
833
|
-
match(action2, meta);
|
|
834
|
-
} else if (action2 === "showBackground" || action2 === "animateCharacter" || action2 === "preload") {
|
|
835
|
-
const notLatest = next2(i).some(([_action]) => action2 === _action);
|
|
836
|
-
if (notLatest)
|
|
837
|
-
continue;
|
|
838
|
-
match(action2, meta);
|
|
839
|
-
} else {
|
|
840
|
-
match(action2, meta);
|
|
841
934
|
}
|
|
842
935
|
}
|
|
843
|
-
|
|
936
|
+
match("clear", [keep, characters2, audio], {
|
|
937
|
+
ctx: context,
|
|
938
|
+
data: latest[1]
|
|
939
|
+
});
|
|
940
|
+
await processor.run((action2, props) => {
|
|
941
|
+
if (!latest)
|
|
942
|
+
return;
|
|
943
|
+
return match(action2, props, {
|
|
944
|
+
ctx: context,
|
|
945
|
+
data: latest[1]
|
|
946
|
+
});
|
|
947
|
+
});
|
|
948
|
+
context.meta.restoring = context.meta.restoring = false;
|
|
949
|
+
render(context);
|
|
844
950
|
};
|
|
845
|
-
const refer = (path
|
|
951
|
+
const refer = (path) => {
|
|
952
|
+
if (!path) {
|
|
953
|
+
path = useStack(MAIN_CONTEXT_KEY).value[0];
|
|
954
|
+
}
|
|
846
955
|
let current = story;
|
|
847
956
|
let precurrent = story;
|
|
848
957
|
const blocks = [];
|
|
@@ -873,10 +982,12 @@ var Novely = (() => {
|
|
|
873
982
|
renderer.ui.showExitPrompt();
|
|
874
983
|
return;
|
|
875
984
|
}
|
|
985
|
+
const ctx = renderer.getContext(MAIN_CONTEXT_KEY);
|
|
986
|
+
const stack = useStack(ctx);
|
|
876
987
|
const current = stack.value;
|
|
877
988
|
stack.clear();
|
|
878
989
|
renderer.ui.showScreen("mainmenu");
|
|
879
|
-
|
|
990
|
+
ctx.audio.destroy();
|
|
880
991
|
const [time, type] = current[2];
|
|
881
992
|
if (type === "auto" && interacted <= 1 && times.has(time)) {
|
|
882
993
|
$.update((prev) => {
|
|
@@ -887,13 +998,38 @@ var Novely = (() => {
|
|
|
887
998
|
interactivity(false);
|
|
888
999
|
times.clear();
|
|
889
1000
|
};
|
|
890
|
-
const back = () => {
|
|
891
|
-
|
|
1001
|
+
const back = async () => {
|
|
1002
|
+
const stack = useStack(MAIN_CONTEXT_KEY);
|
|
1003
|
+
stack.back();
|
|
1004
|
+
await restore(stack.value);
|
|
892
1005
|
};
|
|
893
1006
|
const t = (key, lang) => {
|
|
894
1007
|
return translation[lang].internal[key];
|
|
895
1008
|
};
|
|
1009
|
+
const preview = async ([path, data2], name) => {
|
|
1010
|
+
const queue = getActionsFromPath(story, path);
|
|
1011
|
+
const ctx = renderer.getContext(name);
|
|
1012
|
+
ctx.meta.restoring = true;
|
|
1013
|
+
ctx.meta.preview = true;
|
|
1014
|
+
const processor = createQueueProcessor(queue);
|
|
1015
|
+
await processor.run((action2, props) => {
|
|
1016
|
+
if (AUDIO_ACTIONS.has(action2))
|
|
1017
|
+
return;
|
|
1018
|
+
if (action2 === "vibrate")
|
|
1019
|
+
return;
|
|
1020
|
+
if (action2 === "end")
|
|
1021
|
+
return;
|
|
1022
|
+
return match(action2, props, {
|
|
1023
|
+
ctx,
|
|
1024
|
+
data: data2
|
|
1025
|
+
});
|
|
1026
|
+
});
|
|
1027
|
+
};
|
|
1028
|
+
const removeContext = (name) => {
|
|
1029
|
+
STACK_MAP.delete(name);
|
|
1030
|
+
};
|
|
896
1031
|
const renderer = createRenderer({
|
|
1032
|
+
mainContextKey: MAIN_CONTEXT_KEY,
|
|
897
1033
|
characters,
|
|
898
1034
|
set,
|
|
899
1035
|
restore,
|
|
@@ -902,62 +1038,67 @@ var Novely = (() => {
|
|
|
902
1038
|
exit,
|
|
903
1039
|
back,
|
|
904
1040
|
t,
|
|
905
|
-
|
|
1041
|
+
preview,
|
|
1042
|
+
removeContext,
|
|
906
1043
|
languages,
|
|
907
1044
|
$,
|
|
908
1045
|
$$
|
|
909
1046
|
});
|
|
1047
|
+
const useStack = createUseStackFunction(renderer);
|
|
1048
|
+
useStack(MAIN_CONTEXT_KEY).push(initial);
|
|
910
1049
|
renderer.ui.start();
|
|
911
|
-
const match = matchAction({
|
|
912
|
-
wait([time]) {
|
|
913
|
-
if (!restoring)
|
|
1050
|
+
const match = matchAction(renderer.getContext, {
|
|
1051
|
+
wait({ ctx }, [time]) {
|
|
1052
|
+
if (!ctx.meta.restoring)
|
|
914
1053
|
setTimeout(push, isFunction(time) ? time() : time);
|
|
915
1054
|
},
|
|
916
|
-
showBackground([background]) {
|
|
917
|
-
|
|
918
|
-
push();
|
|
1055
|
+
showBackground({ ctx }, [background]) {
|
|
1056
|
+
ctx.background(background);
|
|
1057
|
+
push(ctx);
|
|
919
1058
|
},
|
|
920
|
-
playMusic([source]) {
|
|
921
|
-
|
|
922
|
-
push();
|
|
1059
|
+
playMusic({ ctx }, [source]) {
|
|
1060
|
+
ctx.audio.music(source, "music", true).play();
|
|
1061
|
+
push(ctx);
|
|
923
1062
|
},
|
|
924
|
-
stopMusic([source]) {
|
|
925
|
-
|
|
926
|
-
push();
|
|
1063
|
+
stopMusic({ ctx }, [source]) {
|
|
1064
|
+
ctx.audio.music(source, "music").stop();
|
|
1065
|
+
push(ctx);
|
|
927
1066
|
},
|
|
928
|
-
playSound([source, loop]) {
|
|
929
|
-
|
|
930
|
-
push();
|
|
1067
|
+
playSound({ ctx }, [source, loop]) {
|
|
1068
|
+
ctx.audio.music(source, "sound", loop || false).play();
|
|
1069
|
+
push(ctx);
|
|
931
1070
|
},
|
|
932
|
-
stopSound([source]) {
|
|
933
|
-
|
|
934
|
-
push();
|
|
1071
|
+
stopSound({ ctx }, [source]) {
|
|
1072
|
+
ctx.audio.music(source, "sound").stop();
|
|
1073
|
+
push(ctx);
|
|
935
1074
|
},
|
|
936
|
-
voice([source]) {
|
|
937
|
-
|
|
938
|
-
push();
|
|
1075
|
+
voice({ ctx }, [source]) {
|
|
1076
|
+
ctx.audio.voice(source);
|
|
1077
|
+
push(ctx);
|
|
939
1078
|
},
|
|
940
|
-
stopVoice() {
|
|
941
|
-
|
|
942
|
-
push();
|
|
1079
|
+
stopVoice({ ctx }) {
|
|
1080
|
+
ctx.audio.voiceStop();
|
|
1081
|
+
push(ctx);
|
|
943
1082
|
},
|
|
944
|
-
showCharacter([character, emotion, className, style]) {
|
|
1083
|
+
showCharacter({ ctx }, [character, emotion, className, style]) {
|
|
945
1084
|
if (DEV && !characters[character].emotions[emotion]) {
|
|
946
1085
|
throw new Error(`Attempt to show character "${character}" with unknown emotion "${emotion}"`);
|
|
947
1086
|
}
|
|
948
|
-
const handle =
|
|
949
|
-
handle.append(className, style, restoring);
|
|
950
|
-
handle.
|
|
951
|
-
push();
|
|
1087
|
+
const handle = ctx.character(character);
|
|
1088
|
+
handle.append(className, style, ctx.meta.restoring);
|
|
1089
|
+
handle.emotion(emotion, true);
|
|
1090
|
+
push(ctx);
|
|
952
1091
|
},
|
|
953
|
-
hideCharacter([character, className, style, duration]) {
|
|
954
|
-
|
|
1092
|
+
hideCharacter({ ctx }, [character, className, style, duration]) {
|
|
1093
|
+
ctx.character(character).remove(className, style, duration, ctx.meta.restoring).then(() => {
|
|
1094
|
+
push(ctx);
|
|
1095
|
+
});
|
|
955
1096
|
},
|
|
956
|
-
dialog([character, content, emotion]) {
|
|
1097
|
+
dialog({ ctx, data: data2 }, [character, content, emotion]) {
|
|
957
1098
|
const name = (() => {
|
|
958
1099
|
const c = character;
|
|
959
1100
|
const cs = characters;
|
|
960
|
-
const lang = $.get().meta
|
|
1101
|
+
const [lang] = $.get().meta;
|
|
961
1102
|
if (c && c in cs) {
|
|
962
1103
|
const block = cs[c].name;
|
|
963
1104
|
if (typeof block === "string") {
|
|
@@ -969,16 +1110,17 @@ var Novely = (() => {
|
|
|
969
1110
|
}
|
|
970
1111
|
return c || "";
|
|
971
1112
|
})();
|
|
972
|
-
const run =
|
|
973
|
-
run(forward
|
|
1113
|
+
const run = ctx.dialog(unwrap2(content, data2), unwrap2(name, data2), character, emotion);
|
|
1114
|
+
run(() => forward(ctx));
|
|
974
1115
|
},
|
|
975
|
-
function([fn]) {
|
|
976
|
-
const result = fn(restoring, goingBack);
|
|
977
|
-
if (!restoring)
|
|
978
|
-
result ? result.then(push) : push();
|
|
1116
|
+
function({ ctx }, [fn]) {
|
|
1117
|
+
const result = fn(ctx.meta.restoring, ctx.meta.goingBack, ctx.meta.preview);
|
|
1118
|
+
if (!ctx.meta.restoring) {
|
|
1119
|
+
result ? result.then(() => push(ctx)) : push(ctx);
|
|
1120
|
+
}
|
|
979
1121
|
return result;
|
|
980
1122
|
},
|
|
981
|
-
choice([question, ...choices]) {
|
|
1123
|
+
choice({ ctx, data: data2 }, [question, ...choices]) {
|
|
982
1124
|
const isWithoutQuestion = Array.isArray(question);
|
|
983
1125
|
if (isWithoutQuestion) {
|
|
984
1126
|
choices.unshift(question);
|
|
@@ -988,46 +1130,57 @@ var Novely = (() => {
|
|
|
988
1130
|
if (DEV && action2.length === 0 && (!visible || visible())) {
|
|
989
1131
|
console.warn(`Choice children should not be empty, either add content there or make item not selectable`);
|
|
990
1132
|
}
|
|
991
|
-
return [unwrap2(content), action2, visible];
|
|
1133
|
+
return [unwrap2(content, data2), action2, visible];
|
|
992
1134
|
});
|
|
993
1135
|
if (DEV && unwrapped.length === 0) {
|
|
994
1136
|
throw new Error(`Running choice without variants to choose from, look at how to use Choice action properly [https://novely.pages.dev/guide/actions/choice#usage]`);
|
|
995
1137
|
}
|
|
996
|
-
const run =
|
|
1138
|
+
const run = ctx.choices(unwrap2(question, data2), unwrapped);
|
|
997
1139
|
run((selected) => {
|
|
998
|
-
|
|
1140
|
+
if (!ctx.meta.preview) {
|
|
1141
|
+
enmemory(ctx);
|
|
1142
|
+
}
|
|
1143
|
+
const stack = useStack(ctx);
|
|
999
1144
|
const offset = isWithoutQuestion ? 0 : 1;
|
|
1000
1145
|
if (DEV && !unwrapped[selected + offset]) {
|
|
1001
1146
|
throw new Error("Choice children is empty, either add content there or make item not selectable");
|
|
1002
1147
|
}
|
|
1003
1148
|
stack.value[0].push(["choice", selected + offset], [null, 0]);
|
|
1004
|
-
render();
|
|
1149
|
+
render(ctx);
|
|
1005
1150
|
interactivity(true);
|
|
1006
1151
|
});
|
|
1007
1152
|
},
|
|
1008
|
-
jump([scene]) {
|
|
1153
|
+
jump({ ctx, data: data2 }, [scene]) {
|
|
1009
1154
|
if (DEV && !story[scene]) {
|
|
1010
1155
|
throw new Error(`Attempt to jump to unknown scene "${scene}"`);
|
|
1011
1156
|
}
|
|
1012
1157
|
if (DEV && story[scene].length === 0) {
|
|
1013
1158
|
throw new Error(`Attempt to jump to empty scene "${scene}"`);
|
|
1014
1159
|
}
|
|
1160
|
+
const stack = useStack(ctx);
|
|
1015
1161
|
stack.value[0] = [
|
|
1016
1162
|
["jump", scene],
|
|
1017
1163
|
[null, -1]
|
|
1018
1164
|
];
|
|
1019
|
-
match("clear", []
|
|
1165
|
+
match("clear", [], {
|
|
1166
|
+
ctx,
|
|
1167
|
+
data: data2
|
|
1168
|
+
});
|
|
1020
1169
|
},
|
|
1021
|
-
clear([keep, characters2]) {
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1170
|
+
clear({ ctx }, [keep, characters2, audio]) {
|
|
1171
|
+
ctx.vibrate(0);
|
|
1172
|
+
const run = ctx.clear(
|
|
1173
|
+
keep || EMPTY_SET,
|
|
1174
|
+
characters2 || EMPTY_SET,
|
|
1175
|
+
audio || { music: EMPTY_SET, sounds: EMPTY_SET }
|
|
1176
|
+
);
|
|
1177
|
+
run(() => push(ctx));
|
|
1025
1178
|
},
|
|
1026
|
-
condition([condition, variants]) {
|
|
1179
|
+
condition({ ctx }, [condition, variants]) {
|
|
1027
1180
|
if (DEV && Object.values(variants).length === 0) {
|
|
1028
1181
|
throw new Error(`Attempt to use Condition action with empty variants object`);
|
|
1029
1182
|
}
|
|
1030
|
-
if (!restoring) {
|
|
1183
|
+
if (!ctx.meta.restoring) {
|
|
1031
1184
|
const val = String(condition());
|
|
1032
1185
|
if (DEV && !variants[val]) {
|
|
1033
1186
|
throw new Error(`Attempt to go to unknown variant "${val}"`);
|
|
@@ -1035,46 +1188,56 @@ var Novely = (() => {
|
|
|
1035
1188
|
if (DEV && variants[val].length === 0) {
|
|
1036
1189
|
throw new Error(`Attempt to go to empty variant "${val}"`);
|
|
1037
1190
|
}
|
|
1191
|
+
const stack = useStack(MAIN_CONTEXT_KEY);
|
|
1038
1192
|
stack.value[0].push(["condition", val], [null, 0]);
|
|
1039
|
-
render();
|
|
1193
|
+
render(ctx);
|
|
1040
1194
|
}
|
|
1041
1195
|
},
|
|
1042
|
-
end() {
|
|
1043
|
-
|
|
1044
|
-
|
|
1196
|
+
end({ ctx }) {
|
|
1197
|
+
if (ctx.meta.preview)
|
|
1198
|
+
return;
|
|
1199
|
+
ctx.vibrate(0);
|
|
1200
|
+
ctx.clear(EMPTY_SET, EMPTY_SET, { music: EMPTY_SET, sounds: EMPTY_SET })(noop);
|
|
1045
1201
|
renderer.ui.showScreen("mainmenu");
|
|
1046
1202
|
interactivity(false);
|
|
1047
1203
|
times.clear();
|
|
1048
1204
|
},
|
|
1049
|
-
input([question, onInput, setup]) {
|
|
1050
|
-
|
|
1205
|
+
input({ ctx, data: data2 }, [question, onInput, setup]) {
|
|
1206
|
+
ctx.input(unwrap2(question, data2), onInput, setup)(() => {
|
|
1207
|
+
forward(ctx);
|
|
1208
|
+
});
|
|
1051
1209
|
},
|
|
1052
|
-
custom([handler]) {
|
|
1053
|
-
const result =
|
|
1054
|
-
if (
|
|
1055
|
-
|
|
1056
|
-
if (!
|
|
1057
|
-
|
|
1210
|
+
custom({ ctx }, [handler]) {
|
|
1211
|
+
const result = ctx.custom(handler, () => {
|
|
1212
|
+
if (ctx.meta.restoring)
|
|
1213
|
+
return;
|
|
1214
|
+
if (handler.requireUserAction && !ctx.meta.preview) {
|
|
1215
|
+
enmemory(ctx);
|
|
1216
|
+
interactivity(true);
|
|
1217
|
+
}
|
|
1218
|
+
push(ctx);
|
|
1058
1219
|
});
|
|
1059
1220
|
return result;
|
|
1060
1221
|
},
|
|
1061
|
-
vibrate(pattern) {
|
|
1062
|
-
|
|
1063
|
-
push();
|
|
1222
|
+
vibrate({ ctx }, pattern) {
|
|
1223
|
+
ctx.vibrate(pattern);
|
|
1224
|
+
push(ctx);
|
|
1064
1225
|
},
|
|
1065
|
-
next() {
|
|
1066
|
-
push();
|
|
1226
|
+
next({ ctx }) {
|
|
1227
|
+
push(ctx);
|
|
1067
1228
|
},
|
|
1068
|
-
animateCharacter([character, timeout, ...classes]) {
|
|
1229
|
+
animateCharacter({ ctx, data: data2 }, [character, timeout, ...classes]) {
|
|
1069
1230
|
if (DEV && classes.length === 0) {
|
|
1070
1231
|
throw new Error("Attempt to use AnimateCharacter without classes. Classes should be provided [https://novely.pages.dev/guide/actions/animateCharacter.html]");
|
|
1071
1232
|
}
|
|
1072
1233
|
if (DEV && (timeout <= 0 || !Number.isFinite(timeout) || Number.isNaN(timeout))) {
|
|
1073
1234
|
throw new Error("Attempt to use AnimateCharacter with unacceptable timeout. It should be finite and greater than zero");
|
|
1074
1235
|
}
|
|
1236
|
+
if (ctx.meta.preview)
|
|
1237
|
+
return;
|
|
1075
1238
|
const handler = (get) => {
|
|
1076
|
-
const { clear } = get(
|
|
1077
|
-
const char =
|
|
1239
|
+
const { clear } = get(false);
|
|
1240
|
+
const char = ctx.getCharacter(character);
|
|
1078
1241
|
if (!char)
|
|
1079
1242
|
return;
|
|
1080
1243
|
const target = char.canvas;
|
|
@@ -1090,18 +1253,23 @@ var Novely = (() => {
|
|
|
1090
1253
|
clearTimeout(timeoutId);
|
|
1091
1254
|
});
|
|
1092
1255
|
};
|
|
1093
|
-
|
|
1256
|
+
handler.key = "@@internal-animate-character";
|
|
1257
|
+
match("custom", [handler], {
|
|
1258
|
+
ctx,
|
|
1259
|
+
data: data2
|
|
1260
|
+
});
|
|
1094
1261
|
},
|
|
1095
|
-
text(text) {
|
|
1096
|
-
const string = text.map((content) => unwrap2(content)).join(" ");
|
|
1262
|
+
text({ ctx, data: data2 }, text) {
|
|
1263
|
+
const string = text.map((content) => unwrap2(content, data2)).join(" ");
|
|
1097
1264
|
if (DEV && string.length === 0) {
|
|
1098
1265
|
throw new Error(`Action Text was called with empty string or array`);
|
|
1099
1266
|
}
|
|
1100
|
-
|
|
1267
|
+
ctx.text(string, () => forward(ctx));
|
|
1101
1268
|
},
|
|
1102
|
-
exit() {
|
|
1103
|
-
if (restoring)
|
|
1269
|
+
exit({ ctx, data: data2 }) {
|
|
1270
|
+
if (ctx.meta.restoring)
|
|
1104
1271
|
return;
|
|
1272
|
+
const stack = useStack(ctx);
|
|
1105
1273
|
const path = stack.value[0];
|
|
1106
1274
|
const last = path.at(-1);
|
|
1107
1275
|
const ignore = [];
|
|
@@ -1115,7 +1283,10 @@ var Novely = (() => {
|
|
|
1115
1283
|
if (isExitImpossible(path)) {
|
|
1116
1284
|
const referred = refer(path);
|
|
1117
1285
|
if (isAction(referred) && isSkippedDuringRestore(referred[0])) {
|
|
1118
|
-
match("end", []
|
|
1286
|
+
match("end", [], {
|
|
1287
|
+
ctx,
|
|
1288
|
+
data: data2
|
|
1289
|
+
});
|
|
1119
1290
|
}
|
|
1120
1291
|
return;
|
|
1121
1292
|
}
|
|
@@ -1140,36 +1311,39 @@ var Novely = (() => {
|
|
|
1140
1311
|
}
|
|
1141
1312
|
break;
|
|
1142
1313
|
}
|
|
1143
|
-
render();
|
|
1314
|
+
render(ctx);
|
|
1144
1315
|
},
|
|
1145
|
-
preload([source]) {
|
|
1146
|
-
if (!goingBack && !restoring && !PRELOADED_ASSETS.has(source)) {
|
|
1316
|
+
preload({ ctx }, [source]) {
|
|
1317
|
+
if (!ctx.meta.goingBack && !ctx.meta.restoring && !PRELOADED_ASSETS.has(source)) {
|
|
1147
1318
|
PRELOADED_ASSETS.add(renderer.misc.preloadImage(source));
|
|
1148
1319
|
}
|
|
1149
|
-
push();
|
|
1320
|
+
push(ctx);
|
|
1150
1321
|
},
|
|
1151
|
-
block([scene]) {
|
|
1322
|
+
block({ ctx }, [scene]) {
|
|
1152
1323
|
if (DEV && !story[scene]) {
|
|
1153
1324
|
throw new Error(`Attempt to call Block action with unknown scene "${scene}"`);
|
|
1154
1325
|
}
|
|
1155
1326
|
if (DEV && story[scene].length === 0) {
|
|
1156
1327
|
throw new Error(`Attempt to call Block action with empty scene "${scene}"`);
|
|
1157
1328
|
}
|
|
1158
|
-
if (!restoring) {
|
|
1329
|
+
if (!ctx.meta.restoring) {
|
|
1330
|
+
const stack = useStack(ctx);
|
|
1159
1331
|
stack.value[0].push(["block", scene], [null, 0]);
|
|
1160
|
-
render();
|
|
1332
|
+
render(ctx);
|
|
1161
1333
|
}
|
|
1162
1334
|
}
|
|
1163
1335
|
});
|
|
1164
|
-
const enmemory = () => {
|
|
1165
|
-
if (restoring)
|
|
1336
|
+
const enmemory = (ctx) => {
|
|
1337
|
+
if (ctx.meta.restoring)
|
|
1166
1338
|
return;
|
|
1339
|
+
const stack = useStack(ctx);
|
|
1167
1340
|
const current = klona(stack.value);
|
|
1168
1341
|
current[2][1] = "auto";
|
|
1169
1342
|
stack.push(current);
|
|
1170
1343
|
save(true, "auto");
|
|
1171
1344
|
};
|
|
1172
|
-
const next = () => {
|
|
1345
|
+
const next = (ctx) => {
|
|
1346
|
+
const stack = useStack(ctx);
|
|
1173
1347
|
const path = stack.value[0];
|
|
1174
1348
|
const last = path.at(-1);
|
|
1175
1349
|
if (last && (isNull(last[0]) || last[0] === "jump") && isNumber(last[1])) {
|
|
@@ -1178,33 +1352,42 @@ var Novely = (() => {
|
|
|
1178
1352
|
path.push([null, 0]);
|
|
1179
1353
|
}
|
|
1180
1354
|
};
|
|
1181
|
-
const render = () => {
|
|
1182
|
-
const
|
|
1355
|
+
const render = (ctx) => {
|
|
1356
|
+
const stack = useStack(ctx);
|
|
1357
|
+
const referred = refer(stack.value[0]);
|
|
1183
1358
|
if (isAction(referred)) {
|
|
1184
1359
|
const [action2, ...props] = referred;
|
|
1185
|
-
match(action2, props
|
|
1360
|
+
match(action2, props, {
|
|
1361
|
+
ctx,
|
|
1362
|
+
data: stack.value[1]
|
|
1363
|
+
});
|
|
1186
1364
|
} else {
|
|
1187
|
-
match("exit", []
|
|
1365
|
+
match("exit", [], {
|
|
1366
|
+
ctx,
|
|
1367
|
+
data: stack.value[1]
|
|
1368
|
+
});
|
|
1188
1369
|
}
|
|
1189
1370
|
};
|
|
1190
|
-
const push = () => {
|
|
1191
|
-
if (!restoring)
|
|
1192
|
-
next(), render();
|
|
1371
|
+
const push = (ctx) => {
|
|
1372
|
+
if (!ctx.meta.restoring)
|
|
1373
|
+
next(ctx), render(ctx);
|
|
1193
1374
|
};
|
|
1194
|
-
const forward = () => {
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1375
|
+
const forward = (ctx) => {
|
|
1376
|
+
if (!ctx.meta.preview)
|
|
1377
|
+
enmemory(ctx);
|
|
1378
|
+
push(ctx);
|
|
1379
|
+
if (!ctx.meta.preview)
|
|
1380
|
+
interactivity(true);
|
|
1198
1381
|
};
|
|
1199
1382
|
const interactivity = (value = false) => {
|
|
1200
1383
|
interacted = value ? interacted + 1 : 0;
|
|
1201
1384
|
};
|
|
1202
|
-
const unwrap2 = (content,
|
|
1385
|
+
const unwrap2 = (content, values) => {
|
|
1203
1386
|
const {
|
|
1204
1387
|
data: data2,
|
|
1205
1388
|
meta: [lang]
|
|
1206
1389
|
} = $.get();
|
|
1207
|
-
const obj =
|
|
1390
|
+
const obj = values ? values : data2;
|
|
1208
1391
|
const cnt = isFunction(content) ? content() : typeof content === "string" ? content : content[lang];
|
|
1209
1392
|
const str2 = isFunction(cnt) ? cnt() : cnt;
|
|
1210
1393
|
const trans = translation[lang];
|
|
@@ -1244,7 +1427,7 @@ var Novely = (() => {
|
|
|
1244
1427
|
* Unwraps translatable content to a string value
|
|
1245
1428
|
*/
|
|
1246
1429
|
unwrap(content) {
|
|
1247
|
-
return unwrap2(content,
|
|
1430
|
+
return unwrap2(content, $.get().data);
|
|
1248
1431
|
}
|
|
1249
1432
|
};
|
|
1250
1433
|
};
|