@novely/core 0.45.2 → 0.46.0-next.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.
@@ -57,7 +57,70 @@ var Novely = (() => {
57
57
  return foo !== foo && bar !== bar;
58
58
  }
59
59
 
60
- // ../../node_modules/.pnpm/es-toolkit@1.16.0/node_modules/es-toolkit/dist/function/once.mjs
60
+ // ../../node_modules/.pnpm/es-toolkit@1.23.0/node_modules/es-toolkit/dist/function/debounce.mjs
61
+ function debounce(func, debounceMs, { signal, edges } = {}) {
62
+ let pendingThis = void 0;
63
+ let pendingArgs = null;
64
+ const leading = edges != null && edges.includes("leading");
65
+ const trailing = edges == null || edges.includes("trailing");
66
+ const invoke = () => {
67
+ if (pendingArgs !== null) {
68
+ func.apply(pendingThis, pendingArgs);
69
+ pendingThis = void 0;
70
+ pendingArgs = null;
71
+ }
72
+ };
73
+ const onTimerEnd = () => {
74
+ if (trailing) {
75
+ invoke();
76
+ }
77
+ cancel();
78
+ };
79
+ let timeoutId = null;
80
+ const schedule = () => {
81
+ if (timeoutId != null) {
82
+ clearTimeout(timeoutId);
83
+ }
84
+ timeoutId = setTimeout(() => {
85
+ timeoutId = null;
86
+ onTimerEnd();
87
+ }, debounceMs);
88
+ };
89
+ const cancelTimer = () => {
90
+ if (timeoutId !== null) {
91
+ clearTimeout(timeoutId);
92
+ timeoutId = null;
93
+ }
94
+ };
95
+ const cancel = () => {
96
+ cancelTimer();
97
+ pendingThis = void 0;
98
+ pendingArgs = null;
99
+ };
100
+ const flush = () => {
101
+ cancelTimer();
102
+ invoke();
103
+ };
104
+ const debounced = function(...args) {
105
+ if (signal?.aborted) {
106
+ return;
107
+ }
108
+ pendingThis = this;
109
+ pendingArgs = args;
110
+ const isFirstCall = timeoutId == null;
111
+ schedule();
112
+ if (leading && isFirstCall) {
113
+ invoke();
114
+ }
115
+ };
116
+ debounced.schedule = schedule;
117
+ debounced.cancel = cancel;
118
+ debounced.flush = flush;
119
+ signal?.addEventListener("abort", cancel, { once: true });
120
+ return debounced;
121
+ }
122
+
123
+ // ../../node_modules/.pnpm/es-toolkit@1.23.0/node_modules/es-toolkit/dist/function/once.mjs
61
124
  function once(func) {
62
125
  let called = false;
63
126
  let cache;
@@ -72,20 +135,28 @@ var Novely = (() => {
72
135
  };
73
136
  }
74
137
 
75
- // ../../node_modules/.pnpm/es-toolkit@1.16.0/node_modules/es-toolkit/dist/function/throttle.mjs
76
- function throttle(func, throttleMs) {
77
- let lastCallTime;
78
- const throttledFunction = function(...args) {
79
- const now = Date.now();
80
- if (lastCallTime == null || now - lastCallTime >= throttleMs) {
81
- lastCallTime = now;
82
- func(...args);
138
+ // ../../node_modules/.pnpm/es-toolkit@1.23.0/node_modules/es-toolkit/dist/function/throttle.mjs
139
+ function throttle(func, throttleMs, { signal, edges = ["leading", "trailing"] } = {}) {
140
+ let pendingAt = null;
141
+ const debounced = debounce(func, throttleMs, { signal, edges });
142
+ const throttled = function(...args) {
143
+ if (pendingAt == null) {
144
+ pendingAt = Date.now();
145
+ } else {
146
+ if (Date.now() - pendingAt >= throttleMs) {
147
+ pendingAt = Date.now();
148
+ debounced.cancel();
149
+ debounced(...args);
150
+ }
83
151
  }
152
+ debounced(...args);
84
153
  };
85
- return throttledFunction;
154
+ throttled.cancel = debounced.cancel;
155
+ throttled.flush = debounced.flush;
156
+ return throttled;
86
157
  }
87
158
 
88
- // ../../node_modules/.pnpm/es-toolkit@1.16.0/node_modules/es-toolkit/dist/function/memoize.mjs
159
+ // ../../node_modules/.pnpm/es-toolkit@1.23.0/node_modules/es-toolkit/dist/function/memoize.mjs
89
160
  function memoize(fn, options = {}) {
90
161
  const { cache = /* @__PURE__ */ new Map(), getCacheKey } = options;
91
162
  const memoizedFn = function(arg) {
@@ -101,12 +172,28 @@ var Novely = (() => {
101
172
  return memoizedFn;
102
173
  }
103
174
 
104
- // ../../node_modules/.pnpm/es-toolkit@1.16.0/node_modules/es-toolkit/dist/compat/predicate/isObjectLike.mjs
105
- function isObjectLike(value) {
106
- return typeof value === "object" && value !== null;
175
+ // ../../node_modules/.pnpm/es-toolkit@1.23.0/node_modules/es-toolkit/dist/predicate/isPlainObject.mjs
176
+ function isPlainObject(value) {
177
+ if (typeof value !== "object") {
178
+ return false;
179
+ }
180
+ if (value == null) {
181
+ return false;
182
+ }
183
+ if (Object.getPrototypeOf(value) === null) {
184
+ return true;
185
+ }
186
+ if (value.toString() !== "[object Object]") {
187
+ return false;
188
+ }
189
+ let proto = value;
190
+ while (Object.getPrototypeOf(proto) !== null) {
191
+ proto = Object.getPrototypeOf(proto);
192
+ }
193
+ return Object.getPrototypeOf(value) === proto;
107
194
  }
108
195
 
109
- // ../../node_modules/.pnpm/es-toolkit@1.16.0/node_modules/es-toolkit/dist/object/merge.mjs
196
+ // ../../node_modules/.pnpm/es-toolkit@1.23.0/node_modules/es-toolkit/dist/object/merge.mjs
110
197
  function merge(target, source) {
111
198
  const sourceKeys = Object.keys(source);
112
199
  for (let i = 0; i < sourceKeys.length; i++) {
@@ -114,9 +201,17 @@ var Novely = (() => {
114
201
  const sourceValue = source[key];
115
202
  const targetValue = target[key];
116
203
  if (Array.isArray(sourceValue)) {
117
- target[key] = merge(targetValue ?? [], sourceValue);
118
- } else if (isObjectLike(targetValue) && isObjectLike(sourceValue)) {
119
- target[key] = merge(targetValue ?? {}, sourceValue);
204
+ if (Array.isArray(targetValue)) {
205
+ target[key] = merge(targetValue, sourceValue);
206
+ } else {
207
+ target[key] = merge([], sourceValue);
208
+ }
209
+ } else if (isPlainObject(sourceValue)) {
210
+ if (isPlainObject(targetValue)) {
211
+ target[key] = merge(targetValue, sourceValue);
212
+ } else {
213
+ target[key] = merge({}, sourceValue);
214
+ }
120
215
  } else if (targetValue === void 0 || sourceValue !== void 0) {
121
216
  target[key] = sourceValue;
122
217
  }
@@ -136,30 +231,30 @@ var Novely = (() => {
136
231
  }
137
232
  function klona(x) {
138
233
  if (typeof x !== "object") return x;
139
- var i = 0, k, list, tmp, str2 = Object.prototype.toString.call(x);
140
- if (str2 === "[object Object]") {
234
+ var i = 0, k, list, tmp, str = Object.prototype.toString.call(x);
235
+ if (str === "[object Object]") {
141
236
  tmp = Object.create(x.__proto__ || null);
142
- } else if (str2 === "[object Array]") {
237
+ } else if (str === "[object Array]") {
143
238
  tmp = Array(x.length);
144
- } else if (str2 === "[object Set]") {
239
+ } else if (str === "[object Set]") {
145
240
  tmp = /* @__PURE__ */ new Set();
146
241
  x.forEach(function(val) {
147
242
  tmp.add(klona(val));
148
243
  });
149
- } else if (str2 === "[object Map]") {
244
+ } else if (str === "[object Map]") {
150
245
  tmp = /* @__PURE__ */ new Map();
151
246
  x.forEach(function(val, key) {
152
247
  tmp.set(klona(key), klona(val));
153
248
  });
154
- } else if (str2 === "[object Date]") {
249
+ } else if (str === "[object Date]") {
155
250
  tmp = /* @__PURE__ */ new Date(+x);
156
- } else if (str2 === "[object RegExp]") {
251
+ } else if (str === "[object RegExp]") {
157
252
  tmp = new RegExp(x.source, x.flags);
158
- } else if (str2 === "[object DataView]") {
253
+ } else if (str === "[object DataView]") {
159
254
  tmp = new x.constructor(klona(x.buffer));
160
- } else if (str2 === "[object ArrayBuffer]") {
255
+ } else if (str === "[object ArrayBuffer]") {
161
256
  tmp = x.slice(0);
162
- } else if (str2.slice(-6) === "Array]") {
257
+ } else if (str.slice(-6) === "Array]") {
163
258
  tmp = new x.constructor(x);
164
259
  }
165
260
  if (tmp) {
@@ -305,29 +400,6 @@ var Novely = (() => {
305
400
  }
306
401
  }
307
402
 
308
- // src/audio-codecs.ts
309
- var cut = (str2) => str2.replace(/^no$/, "");
310
- var audio = new Audio();
311
- var canPlay = (type) => !!cut(audio.canPlayType(type));
312
- var canPlayMultiple = (...types) => types.some((type) => canPlay(type));
313
- var supportsMap = {
314
- mp3: canPlayMultiple("audio/mpeg;", "audio/mp3;"),
315
- mpeg: canPlay("audio/mpeg;"),
316
- opus: canPlay('audio/ogg; codecs="opus"'),
317
- ogg: canPlay('audio/ogg; codecs="vorbis"'),
318
- oga: canPlay('audio/ogg; codecs="vorbis"'),
319
- wav: canPlayMultiple('audio/wav; codecs="1"', "audio/wav;"),
320
- aac: canPlay("audio/aac;"),
321
- caf: canPlay("audio/x-caf;"),
322
- m4a: canPlayMultiple("audio/x-m4a;", "audio/m4a;", "audio/aac;"),
323
- m4b: canPlayMultiple("audio/x-m4b;", "audio/m4b;", "audio/aac;"),
324
- mp4: canPlayMultiple("audio/x-mp4;", "audio/mp4;", "audio/aac;"),
325
- weba: canPlay('audio/webm; codecs="vorbis"'),
326
- webm: canPlay('audio/webm; codecs="vorbis"'),
327
- dolby: canPlay('audio/mp4; codecs="ec-3"'),
328
- flac: canPlayMultiple("audio/x-flac;", "audio/flac;")
329
- };
330
-
331
403
  // src/constants.ts
332
404
  var SKIPPED_DURING_RESTORE = /* @__PURE__ */ new Set(["dialog", "choice", "input", "vibrate", "text"]);
333
405
  var BLOCK_EXIT_STATEMENTS = /* @__PURE__ */ new Set(["choice:exit", "condition:exit", "block:exit"]);
@@ -368,50 +440,60 @@ var Novely = (() => {
368
440
  ]);
369
441
  var MAIN_CONTEXT_KEY = "$MAIN";
370
442
 
371
- // src/image-formats.ts
372
- var avif = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
373
- var jxl = "data:image/jxl;base64,/woIAAAMABKIAgC4AF3lEgAAFSqjjBu8nOv58kOHxbSN6wxttW1hSaLIODZJJ3BIEkkaoCUzGM6qJAE=";
374
- var webp = "data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA";
375
- var supportsFormat = (source) => {
376
- const { promise, resolve } = Promise.withResolvers();
377
- const img = Object.assign(document.createElement("img"), {
378
- src: source
379
- });
380
- img.onload = img.onerror = () => {
381
- resolve(img.height === 2);
382
- };
383
- return promise;
443
+ // src/utilities/assertions.ts
444
+ var isNumber = (val) => {
445
+ return typeof val === "number";
384
446
  };
385
- var supportsMap2 = {
386
- avif: false,
387
- jxl: false,
388
- webp: false
447
+ var isNull = (val) => {
448
+ return val === null;
389
449
  };
390
- var formatsMap = {
391
- avif,
392
- jxl,
393
- webp
450
+ var isString = (val) => {
451
+ return typeof val === "string";
394
452
  };
395
- var loadImageFormatsSupport = async () => {
396
- const promises = [];
397
- for (const [format, source] of Object.entries(formatsMap)) {
398
- const promise = supportsFormat(source).then((supported) => {
399
- supportsMap2[format] = supported;
400
- });
401
- promises.push(promise);
402
- }
403
- await Promise.all(promises);
453
+ var isFunction = (val) => {
454
+ return typeof val === "function";
455
+ };
456
+ var isPromise = (val) => {
457
+ return Boolean(val) && (typeof val === "object" || isFunction(val)) && isFunction(val.then);
458
+ };
459
+ var isEmpty = (val) => {
460
+ return typeof val === "object" && !isNull(val) && Object.keys(val).length === 0;
461
+ };
462
+ var isCSSImageURL = (url) => {
463
+ const startsWith = String.prototype.startsWith.bind(url);
464
+ return startsWith("http") || startsWith("/") || startsWith(".") || startsWith("data");
465
+ };
466
+ var isUserRequiredAction = ([action, ...meta]) => {
467
+ return Boolean(action === "custom" && meta[0] && meta[0].requireUserAction);
468
+ };
469
+ var isBlockStatement = (statement) => {
470
+ return BLOCK_STATEMENTS.has(statement);
471
+ };
472
+ var isBlockExitStatement = (statement) => {
473
+ return BLOCK_EXIT_STATEMENTS.has(statement);
474
+ };
475
+ var isSkippedDuringRestore = (item) => {
476
+ return SKIPPED_DURING_RESTORE.has(item);
477
+ };
478
+ var isAudioAction = (action) => {
479
+ return AUDIO_ACTIONS.has(action);
480
+ };
481
+ var isAction = (element) => {
482
+ return Array.isArray(element) && isString(element[0]);
483
+ };
484
+ var isImageAsset = (asset2) => {
485
+ return isString(asset2) && isCSSImageURL(asset2);
486
+ };
487
+ var isBlockingAction = (action) => {
488
+ return isUserRequiredAction(action) || isSkippedDuringRestore(action[0]) && action[0] !== "vibrate";
489
+ };
490
+ var isAsset = (suspect) => {
491
+ return suspect !== null && typeof suspect === "object" && "source" in suspect && "type" in suspect;
404
492
  };
405
- loadImageFormatsSupport();
406
-
407
- // src/shared.ts
408
- var STACK_MAP = /* @__PURE__ */ new Map();
409
- var CUSTOM_ACTION_MAP = /* @__PURE__ */ new Map();
410
- var PRELOADED_ASSETS = /* @__PURE__ */ new Set();
411
- var ASSETS_TO_PRELOAD = /* @__PURE__ */ new Set();
412
493
 
413
- // src/utils.ts
414
- var matchAction = ({ getContext, onBeforeActionCall, push, forward }, values) => {
494
+ // src/utilities/match-action.ts
495
+ var matchAction = (callbacks, values) => {
496
+ const { getContext, onBeforeActionCall, push, forward } = callbacks;
415
497
  return (action, props, { ctx, data }) => {
416
498
  const context = typeof ctx === "string" ? getContext(ctx) : ctx;
417
499
  onBeforeActionCall({
@@ -436,32 +518,8 @@ var Novely = (() => {
436
518
  );
437
519
  };
438
520
  };
439
- var isNumber = (val) => {
440
- return typeof val === "number";
441
- };
442
- var isNull = (val) => {
443
- return val === null;
444
- };
445
- var isString = (val) => {
446
- return typeof val === "string";
447
- };
448
- var isFunction = (val) => {
449
- return typeof val === "function";
450
- };
451
- var isPromise = (val) => {
452
- return Boolean(val) && (typeof val === "object" || isFunction(val)) && isFunction(val.then);
453
- };
454
- var isEmpty = (val) => {
455
- return typeof val === "object" && !isNull(val) && Object.keys(val).length === 0;
456
- };
457
- var isCSSImage = (str2) => {
458
- const startsWith = String.prototype.startsWith.bind(str2);
459
- return startsWith("http") || startsWith("/") || startsWith(".") || startsWith("data");
460
- };
461
- var str = String;
462
- var isUserRequiredAction = ([action, ...meta]) => {
463
- return Boolean(action === "custom" && meta[0] && meta[0].requireUserAction);
464
- };
521
+
522
+ // src/utilities/ungrupped.ts
465
523
  var getLanguage = (languages) => {
466
524
  let { language } = navigator;
467
525
  if (languages.includes(language)) {
@@ -473,65 +531,60 @@ var Novely = (() => {
473
531
  }
474
532
  return languages[0];
475
533
  };
476
- var createControlledPromise = () => {
477
- const object = {
478
- resolve: null,
479
- reject: null,
480
- promise: null,
481
- cancel: null
482
- };
483
- const init = () => {
484
- const promise = new Promise((resolve, reject) => {
485
- object.reject = reject;
486
- object.resolve = (value) => {
487
- resolve({ cancelled: false, value });
488
- };
489
- object.cancel = () => {
490
- resolve({ cancelled: true, value: null });
491
- init();
492
- };
493
- });
494
- object.promise = promise;
495
- };
496
- return init(), object;
534
+ var noop = () => {
497
535
  };
498
- var findLastPathItemBeforeItemOfType = (path, name) => {
499
- const item = path.findLast(([_name, _value], i, array) => {
500
- const next = array[i + 1];
501
- return isNull(_name) && isNumber(_value) && next != null && next[0] === name;
502
- });
503
- return item;
536
+ var mapSet = (set2, fn) => {
537
+ return [...set2].map(fn);
504
538
  };
505
- var isBlockStatement = (statement) => {
506
- return BLOCK_STATEMENTS.has(statement);
539
+ var capitalize = (str) => {
540
+ return str[0].toUpperCase() + str.slice(1);
507
541
  };
508
- var isBlockExitStatement = (statement) => {
509
- return BLOCK_EXIT_STATEMENTS.has(statement);
542
+ var getIntlLanguageDisplayName = memoize((lang) => {
543
+ try {
544
+ const intl = new Intl.DisplayNames([lang], {
545
+ type: "language"
546
+ });
547
+ return intl.of(lang) || lang;
548
+ } catch {
549
+ return lang;
550
+ }
551
+ });
552
+ var unwrapAsset = (asset2) => {
553
+ return isAsset(asset2) ? asset2.source : asset2;
510
554
  };
511
- var isSkippedDuringRestore = (item) => {
512
- return SKIPPED_DURING_RESTORE.has(item);
555
+ var handleAudioAsset = (asset2) => {
556
+ if (DEV && isAsset(asset2) && asset2.type !== "audio") {
557
+ throw new Error("Attempt to use non-audio asset in audio action", { cause: asset2 });
558
+ }
559
+ return unwrapAsset(asset2);
513
560
  };
514
- var isAudioAction = (action) => {
515
- return AUDIO_ACTIONS.has(action);
561
+ var handleImageAsset = (asset2) => {
562
+ if (DEV && isAsset(asset2) && asset2.type !== "image") {
563
+ throw new Error("Attempt to use non-image asset in action that requires image assets", { cause: asset2 });
564
+ }
565
+ return unwrapAsset(asset2);
516
566
  };
517
- var noop = () => {
567
+ var getCharactersData = (characters) => {
568
+ const entries = Object.entries(characters);
569
+ const mapped = entries.map(([key, value]) => [key, { name: value.name, emotions: Object.keys(value.emotions) }]);
570
+ return Object.fromEntries(mapped);
518
571
  };
519
- var isAction = (element) => {
520
- return Array.isArray(element) && isString(element[0]);
572
+ var toArray = (target) => {
573
+ return Array.isArray(target) ? target : [target];
521
574
  };
522
- var flatActions = (item) => {
523
- return item.flatMap((data) => {
524
- const type = data[0];
525
- if (Array.isArray(type)) return flatActions(data);
526
- return [data];
527
- });
575
+ var getLanguageFromStore = (store2) => {
576
+ return store2.get().meta[0];
528
577
  };
529
- var flattenStory = (story) => {
530
- const entries = Object.entries(story).map(([name, items]) => {
531
- return [name, flatActions(items)];
532
- });
533
- return Object.fromEntries(entries);
578
+ var getVolumeFromStore = (store2) => {
579
+ const { meta } = store2.get();
580
+ return {
581
+ music: meta[2],
582
+ sound: meta[3],
583
+ voice: meta[4]
584
+ };
534
585
  };
586
+
587
+ // src/utilities/actions-processing.ts
535
588
  var isExitImpossible = (path) => {
536
589
  const blockStatements = path.filter(([item]) => isBlockStatement(item));
537
590
  const blockExitStatements = path.filter(([item]) => isBlockExitStatement(item));
@@ -543,27 +596,179 @@ var Novely = (() => {
543
596
  }
544
597
  return !blockExitStatements.every(([name], i) => name && name.startsWith(blockStatements[i][0]));
545
598
  };
546
- var getOppositeAction = (action) => {
547
- const MAP = {
548
- showCharacter: "hideCharacter",
549
- playSound: "stopSound",
550
- playMusic: "stopMusic",
551
- voice: "stopVoice"
552
- };
553
- return MAP[action];
554
- };
555
- var getActionsFromPath = (story, path, filter) => {
556
- let current = story;
557
- let precurrent;
558
- let ignoreNestedBefore = null;
559
- let index = 0;
560
- let skipPreserve = void 0;
561
- const skip = /* @__PURE__ */ new Set();
562
- const max = path.reduce((acc, [type, val]) => {
563
- if (isNull(type) && isNumber(val)) {
564
- return acc + 1;
565
- }
566
- return acc;
599
+ var createReferFunction = (story) => {
600
+ const refer = (path) => {
601
+ let current = story;
602
+ let precurrent = story;
603
+ const blocks = [];
604
+ for (const [type, val] of path) {
605
+ if (type === "jump") {
606
+ precurrent = story;
607
+ current = current[val];
608
+ } else if (type === null) {
609
+ precurrent = current;
610
+ current = current[val];
611
+ } else if (type === "choice") {
612
+ blocks.push(precurrent);
613
+ current = current[val + 1][1];
614
+ } else if (type === "condition") {
615
+ blocks.push(precurrent);
616
+ current = current[2][val];
617
+ } else if (type === "block") {
618
+ blocks.push(precurrent);
619
+ current = story[val];
620
+ } else if (type === "block:exit" || type === "choice:exit" || type === "condition:exit") {
621
+ current = blocks.pop();
622
+ }
623
+ }
624
+ return current;
625
+ };
626
+ return refer;
627
+ };
628
+ var exitPath = ({ path, refer, onExitImpossible }) => {
629
+ const last = path.at(-1);
630
+ const ignore = [];
631
+ let wasExitImpossible = false;
632
+ if (!isAction(refer(path))) {
633
+ if (last && isNull(last[0]) && isNumber(last[1])) {
634
+ last[1]--;
635
+ } else {
636
+ path.pop();
637
+ }
638
+ }
639
+ if (isExitImpossible(path)) {
640
+ const referred = refer(path);
641
+ if (isAction(referred) && isSkippedDuringRestore(referred[0])) {
642
+ onExitImpossible?.();
643
+ }
644
+ wasExitImpossible = true;
645
+ return {
646
+ exitImpossible: wasExitImpossible
647
+ };
648
+ }
649
+ for (let i = path.length - 1; i > 0; i--) {
650
+ const [name] = path[i];
651
+ if (isBlockExitStatement(name)) {
652
+ ignore.push(name);
653
+ }
654
+ if (!isBlockStatement(name)) continue;
655
+ if (ignore.at(-1)?.startsWith(name)) {
656
+ ignore.pop();
657
+ continue;
658
+ }
659
+ path.push([`${name}:exit`]);
660
+ const prev = findLastPathItemBeforeItemOfType(path.slice(0, i + 1), name);
661
+ if (prev) path.push([null, prev[1] + 1]);
662
+ if (!isAction(refer(path))) {
663
+ path.pop();
664
+ continue;
665
+ }
666
+ break;
667
+ }
668
+ return {
669
+ exitImpossible: wasExitImpossible
670
+ };
671
+ };
672
+ var nextPath = (path) => {
673
+ const last = path.at(-1);
674
+ if (last && (isNull(last[0]) || last[0] === "jump") && isNumber(last[1])) {
675
+ last[1]++;
676
+ } else {
677
+ path.push([null, 0]);
678
+ }
679
+ return path;
680
+ };
681
+ var collectActionsBeforeBlockingAction = ({ path, refer, clone }) => {
682
+ const collection = [];
683
+ let action = refer(path);
684
+ while (true) {
685
+ if (action == void 0) {
686
+ const { exitImpossible } = exitPath({
687
+ path,
688
+ refer
689
+ });
690
+ if (exitImpossible) {
691
+ break;
692
+ }
693
+ }
694
+ if (!action) {
695
+ break;
696
+ }
697
+ if (isBlockingAction(action)) {
698
+ const [name, ...props] = action;
699
+ if (name === "choice") {
700
+ const choiceProps = props;
701
+ for (let i = 0; i < choiceProps.length; i++) {
702
+ const branchContent = choiceProps[i];
703
+ if (!Array.isArray(branchContent)) continue;
704
+ const virtualPath = clone(path);
705
+ virtualPath.push(["choice", i], [null, 0]);
706
+ const innerActions = collectActionsBeforeBlockingAction({
707
+ path: virtualPath,
708
+ refer,
709
+ clone
710
+ });
711
+ collection.push(...innerActions);
712
+ }
713
+ } else if (name === "condition") {
714
+ const conditionProps = props;
715
+ const conditions = Object.keys(conditionProps[1]);
716
+ for (const condition of conditions) {
717
+ const virtualPath = clone(path);
718
+ virtualPath.push(["condition", condition], [null, 0]);
719
+ const innerActions = collectActionsBeforeBlockingAction({
720
+ path: virtualPath,
721
+ refer,
722
+ clone
723
+ });
724
+ collection.push(...innerActions);
725
+ }
726
+ }
727
+ break;
728
+ }
729
+ collection.push(action);
730
+ if (action[0] === "jump") {
731
+ path = [
732
+ ["jump", action[1]],
733
+ [null, 0]
734
+ ];
735
+ } else if (action[0] == "block") {
736
+ path.push(["block", action[1]], [null, 0]);
737
+ } else {
738
+ nextPath(path);
739
+ }
740
+ action = refer(path);
741
+ }
742
+ return collection;
743
+ };
744
+ var findLastPathItemBeforeItemOfType = (path, name) => {
745
+ const item = path.findLast(([_name, _value], i, array) => {
746
+ const next = array[i + 1];
747
+ return isNull(_name) && isNumber(_value) && next != null && next[0] === name;
748
+ });
749
+ return item;
750
+ };
751
+ var getOppositeAction = (action) => {
752
+ const MAP = {
753
+ showCharacter: "hideCharacter",
754
+ playSound: "stopSound",
755
+ playMusic: "stopMusic",
756
+ voice: "stopVoice"
757
+ };
758
+ return MAP[action];
759
+ };
760
+ var getActionsFromPath = (story, path, filter) => {
761
+ let current = story;
762
+ let precurrent;
763
+ let ignoreNestedBefore = null;
764
+ let index = 0;
765
+ let skipPreserve = void 0;
766
+ const skip = /* @__PURE__ */ new Set();
767
+ const max = path.reduce((acc, [type, val]) => {
768
+ if (isNull(type) && isNumber(val)) {
769
+ return acc + 1;
770
+ }
771
+ return acc;
567
772
  }, 0);
568
773
  const queue = [];
569
774
  const blocks = [];
@@ -648,7 +853,7 @@ var Novely = (() => {
648
853
  const c1 = fn;
649
854
  const isIdenticalID = Boolean(c0.id && c1.id && c0.id === c1.id);
650
855
  const isIdenticalByReference = c0 === c1;
651
- return isIdenticalID || isIdenticalByReference || str(c0) === str(c1);
856
+ return isIdenticalID || isIdenticalByReference || String(c0) === String(c1);
652
857
  });
653
858
  if (notLatest) continue;
654
859
  } else if ("skipOnRestore" in fn && fn.skipOnRestore) {
@@ -715,53 +920,32 @@ var Novely = (() => {
715
920
  }
716
921
  };
717
922
  };
718
- var getStack = memoize(
719
- (_) => {
720
- return [];
721
- },
722
- {
723
- cache: STACK_MAP,
724
- getCacheKey: (ctx) => ctx.id
725
- }
726
- );
727
- var createUseStackFunction = (renderer) => {
728
- const useStack = (context) => {
729
- const ctx = typeof context === "string" ? renderer.getContext(context) : context;
730
- const stack = getStack(ctx);
731
- return {
732
- get previous() {
733
- return stack.previous;
734
- },
735
- get value() {
736
- return stack.at(-1);
737
- },
738
- set value(value) {
739
- stack[stack.length - 1] = value;
740
- },
741
- back() {
742
- if (stack.length > 1) {
743
- stack.previous = stack.pop();
744
- ctx.meta.goingBack = true;
745
- }
746
- },
747
- push(value) {
748
- stack.push(value);
749
- },
750
- clear() {
751
- stack.previous = void 0;
752
- stack.length = 0;
753
- stack.length = 1;
754
- }
755
- };
923
+
924
+ // src/utilities/controlled-promise.ts
925
+ var createControlledPromise = () => {
926
+ const object = {
927
+ resolve: null,
928
+ reject: null,
929
+ promise: null,
930
+ cancel: null
756
931
  };
757
- return useStack;
758
- };
759
- var mapSet = (set2, fn) => {
760
- return [...set2].map(fn);
761
- };
762
- var isImageAsset = (asset2) => {
763
- return isString(asset2) && isCSSImage(asset2);
932
+ const init = () => {
933
+ const promise = new Promise((resolve, reject) => {
934
+ object.reject = reject;
935
+ object.resolve = (value) => {
936
+ resolve({ cancelled: false, value });
937
+ };
938
+ object.cancel = () => {
939
+ resolve({ cancelled: true, value: null });
940
+ init();
941
+ };
942
+ });
943
+ object.promise = promise;
944
+ };
945
+ return init(), object;
764
946
  };
947
+
948
+ // src/utilities/resources.ts
765
949
  var getUrlFileExtension = (address) => {
766
950
  try {
767
951
  const { pathname } = new URL(address, location.href);
@@ -788,7 +972,7 @@ var Novely = (() => {
788
972
  };
789
973
  var getResourseType = memoize(
790
974
  async ({ url, request }) => {
791
- if (!isCSSImage(url)) {
975
+ if (!isCSSImageURL(url)) {
792
976
  return "other";
793
977
  }
794
978
  const extension = getUrlFileExtension(url);
@@ -798,281 +982,82 @@ var Novely = (() => {
798
982
  if (SUPPORTED_IMAGE_FILE_FORMATS.has(extension)) {
799
983
  return "image";
800
984
  }
801
- const contentType = await fetchContentType(url, request);
802
- if (contentType.includes("audio")) {
803
- return "audio";
804
- }
805
- if (contentType.includes("image")) {
806
- return "image";
807
- }
808
- return "other";
809
- },
810
- {
811
- getCacheKey: ({ url }) => url
812
- }
813
- );
814
- var capitalize = (str2) => {
815
- return str2[0].toUpperCase() + str2.slice(1);
816
- };
817
- var getIntlLanguageDisplayName = memoize((lang) => {
818
- try {
819
- const intl = new Intl.DisplayNames([lang], {
820
- type: "language"
821
- });
822
- return intl.of(lang) || lang;
823
- } catch {
824
- return lang;
825
- }
826
- });
827
- var createReferFunction = (story) => {
828
- const refer = (path) => {
829
- let current = story;
830
- let precurrent = story;
831
- const blocks = [];
832
- for (const [type, val] of path) {
833
- if (type === "jump") {
834
- precurrent = story;
835
- current = current[val];
836
- } else if (type === null) {
837
- precurrent = current;
838
- current = current[val];
839
- } else if (type === "choice") {
840
- blocks.push(precurrent);
841
- current = current[val + 1][1];
842
- } else if (type === "condition") {
843
- blocks.push(precurrent);
844
- current = current[2][val];
845
- } else if (type === "block") {
846
- blocks.push(precurrent);
847
- current = story[val];
848
- } else if (type === "block:exit" || type === "choice:exit" || type === "condition:exit") {
849
- current = blocks.pop();
850
- }
851
- }
852
- return current;
853
- };
854
- return refer;
855
- };
856
- var exitPath = ({ path, refer, onExitImpossible }) => {
857
- const last = path.at(-1);
858
- const ignore = [];
859
- let wasExitImpossible = false;
860
- if (!isAction(refer(path))) {
861
- if (last && isNull(last[0]) && isNumber(last[1])) {
862
- last[1]--;
863
- } else {
864
- path.pop();
865
- }
866
- }
867
- if (isExitImpossible(path)) {
868
- const referred = refer(path);
869
- if (isAction(referred) && isSkippedDuringRestore(referred[0])) {
870
- onExitImpossible?.();
871
- }
872
- wasExitImpossible = true;
873
- return {
874
- exitImpossible: wasExitImpossible
875
- };
876
- }
877
- for (let i = path.length - 1; i > 0; i--) {
878
- const [name] = path[i];
879
- if (isBlockExitStatement(name)) {
880
- ignore.push(name);
881
- }
882
- if (!isBlockStatement(name)) continue;
883
- if (ignore.at(-1)?.startsWith(name)) {
884
- ignore.pop();
885
- continue;
886
- }
887
- path.push([`${name}:exit`]);
888
- const prev = findLastPathItemBeforeItemOfType(path.slice(0, i + 1), name);
889
- if (prev) path.push([null, prev[1] + 1]);
890
- if (!isAction(refer(path))) {
891
- path.pop();
892
- continue;
893
- }
894
- break;
895
- }
896
- return {
897
- exitImpossible: wasExitImpossible
898
- };
899
- };
900
- var nextPath = (path) => {
901
- const last = path.at(-1);
902
- if (last && (isNull(last[0]) || last[0] === "jump") && isNumber(last[1])) {
903
- last[1]++;
904
- } else {
905
- path.push([null, 0]);
906
- }
907
- return path;
908
- };
909
- var isBlockingAction = (action) => {
910
- return isUserRequiredAction(action) || isSkippedDuringRestore(action[0]) && action[0] !== "vibrate";
911
- };
912
- var collectActionsBeforeBlockingAction = ({ path, refer, clone }) => {
913
- const collection = [];
914
- let action = refer(path);
915
- while (true) {
916
- if (action == void 0) {
917
- const { exitImpossible } = exitPath({
918
- path,
919
- refer
920
- });
921
- if (exitImpossible) {
922
- break;
923
- }
924
- }
925
- if (!action) {
926
- break;
927
- }
928
- if (isBlockingAction(action)) {
929
- const [name, ...props] = action;
930
- if (name === "choice") {
931
- const choiceProps = props;
932
- for (let i = 0; i < choiceProps.length; i++) {
933
- const branchContent = choiceProps[i];
934
- if (!Array.isArray(branchContent)) continue;
935
- const virtualPath = clone(path);
936
- virtualPath.push(["choice", i], [null, 0]);
937
- const innerActions = collectActionsBeforeBlockingAction({
938
- path: virtualPath,
939
- refer,
940
- clone
941
- });
942
- collection.push(...innerActions);
943
- }
944
- } else if (name === "condition") {
945
- const conditionProps = props;
946
- const conditions = Object.keys(conditionProps[1]);
947
- for (const condition of conditions) {
948
- const virtualPath = clone(path);
949
- virtualPath.push(["condition", condition], [null, 0]);
950
- const innerActions = collectActionsBeforeBlockingAction({
951
- path: virtualPath,
952
- refer,
953
- clone
954
- });
955
- collection.push(...innerActions);
956
- }
957
- }
958
- break;
959
- }
960
- collection.push(action);
961
- if (action[0] === "jump") {
962
- path = [
963
- ["jump", action[1]],
964
- [null, 0]
965
- ];
966
- } else if (action[0] == "block") {
967
- path.push(["block", action[1]], [null, 0]);
968
- } else {
969
- nextPath(path);
970
- }
971
- action = refer(path);
972
- }
973
- return collection;
974
- };
975
- var unwrapAsset = (asset2) => {
976
- return isAsset(asset2) ? asset2.source : asset2;
977
- };
978
- var handleAudioAsset = (asset2) => {
979
- if (DEV && isAsset(asset2) && asset2.type !== "audio") {
980
- throw new Error("Attempt to use non-audio asset in audio action", { cause: asset2 });
981
- }
982
- return unwrapAsset(asset2);
983
- };
984
- var handleImageAsset = (asset2) => {
985
- if (DEV && isAsset(asset2) && asset2.type !== "image") {
986
- throw new Error("Attempt to use non-image asset in action that requires image assets", { cause: asset2 });
987
- }
988
- return unwrapAsset(asset2);
989
- };
990
- var getCharactersData = (characters) => {
991
- const entries = Object.entries(characters);
992
- const mapped = entries.map(([key, value]) => [key, { name: value.name, emotions: Object.keys(value.emotions) }]);
993
- return Object.fromEntries(mapped);
994
- };
995
- var toArray = (target) => {
996
- return Array.isArray(target) ? target : [target];
997
- };
998
- var getLanguageFromStore = (store2) => {
999
- return store2.get().meta[0];
1000
- };
1001
- var getVolumeFromStore = (store2) => {
1002
- const { meta } = store2.get();
1003
- return {
1004
- music: meta[2],
1005
- sound: meta[3],
1006
- voice: meta[4]
1007
- };
1008
- };
1009
-
1010
- // src/asset.ts
1011
- var getType = memoize(
1012
- (extensions) => {
1013
- if (extensions.every((extension) => HOWLER_SUPPORTED_FILE_FORMATS.has(extension))) {
985
+ const contentType = await fetchContentType(url, request);
986
+ if (contentType.includes("audio")) {
1014
987
  return "audio";
1015
988
  }
1016
- if (extensions.every((extension) => SUPPORTED_IMAGE_FILE_FORMATS.has(extension))) {
989
+ if (contentType.includes("image")) {
1017
990
  return "image";
1018
991
  }
1019
- throw extensions;
992
+ return "other";
1020
993
  },
1021
994
  {
1022
- getCacheKey: (extensions) => extensions.join("~")
995
+ getCacheKey: ({ url }) => url
1023
996
  }
1024
997
  );
1025
- var SUPPORT_MAPS = {
1026
- image: supportsMap2,
1027
- audio: supportsMap
1028
- };
1029
- var assetPrivate = memoize(
1030
- (variants) => {
1031
- if (DEV && variants.length === 0) {
1032
- throw new Error(`Attempt to use "asset" function without arguments`);
1033
- }
1034
- const map = {};
1035
- const extensions = [];
1036
- for (const v of variants) {
1037
- const e = getUrlFileExtension(v);
1038
- map[e] = v;
1039
- extensions.push(e);
1040
- }
1041
- const type = getType(extensions);
1042
- const getSource = once(() => {
1043
- const support = SUPPORT_MAPS[type];
1044
- for (const extension of extensions) {
1045
- if (extension in support) {
1046
- if (support[extension]) {
1047
- return map[extension];
1048
- }
1049
- } else {
1050
- return map[extension];
1051
- }
1052
- }
1053
- if (DEV) {
1054
- throw new Error(`No matching asset was found for ${variants.map((v) => `"${v}"`).join(", ")}`);
1055
- }
1056
- return "";
1057
- });
1058
- return {
1059
- get source() {
1060
- return getSource();
1061
- },
1062
- get type() {
1063
- return type;
1064
- }
1065
- };
998
+
999
+ // src/shared.ts
1000
+ var STACK_MAP = /* @__PURE__ */ new Map();
1001
+ var CUSTOM_ACTION_MAP = /* @__PURE__ */ new Map();
1002
+ var PRELOADED_ASSETS = /* @__PURE__ */ new Set();
1003
+ var ASSETS_TO_PRELOAD = /* @__PURE__ */ new Set();
1004
+
1005
+ // src/utilities/stack.ts
1006
+ var getStack = memoize(
1007
+ (_) => {
1008
+ return [];
1066
1009
  },
1067
1010
  {
1068
- getCacheKey: (variants) => variants.join("~")
1011
+ cache: STACK_MAP,
1012
+ getCacheKey: (ctx) => ctx.id
1069
1013
  }
1070
1014
  );
1071
- var asset = (...variants) => {
1072
- return assetPrivate(variants);
1015
+ var createUseStackFunction = (renderer) => {
1016
+ const useStack = (context) => {
1017
+ const ctx = typeof context === "string" ? renderer.getContext(context) : context;
1018
+ const stack = getStack(ctx);
1019
+ return {
1020
+ get previous() {
1021
+ return stack.previous;
1022
+ },
1023
+ get value() {
1024
+ return stack.at(-1);
1025
+ },
1026
+ set value(value) {
1027
+ stack[stack.length - 1] = value;
1028
+ },
1029
+ back() {
1030
+ if (stack.length > 1) {
1031
+ stack.previous = stack.pop();
1032
+ ctx.meta.goingBack = true;
1033
+ }
1034
+ },
1035
+ push(value) {
1036
+ stack.push(value);
1037
+ },
1038
+ clear() {
1039
+ stack.previous = void 0;
1040
+ stack.length = 0;
1041
+ stack.length = 1;
1042
+ }
1043
+ };
1044
+ };
1045
+ return useStack;
1073
1046
  };
1074
- var isAsset = (suspect) => {
1075
- return suspect !== null && typeof suspect === "object" && "source" in suspect && "type" in suspect;
1047
+
1048
+ // src/utilities/story.ts
1049
+ var flatActions = (item) => {
1050
+ return item.flatMap((data) => {
1051
+ const type = data[0];
1052
+ if (Array.isArray(type)) return flatActions(data);
1053
+ return [data];
1054
+ });
1055
+ };
1056
+ var flatStory = (story) => {
1057
+ const entries = Object.entries(story).map(([name, items]) => {
1058
+ return [name, flatActions(items)];
1059
+ });
1060
+ return Object.fromEntries(entries);
1076
1061
  };
1077
1062
 
1078
1063
  // src/browser.ts
@@ -1399,7 +1384,7 @@ var Novely = (() => {
1399
1384
  };
1400
1385
  const scriptBase = async (part) => {
1401
1386
  if (destroyed) return;
1402
- Object.assign(story, flattenStory(part));
1387
+ Object.assign(story, flatStory(part));
1403
1388
  let loadingIsShown = false;
1404
1389
  if (!initialScreenWasShown) {
1405
1390
  renderer.ui.showLoading();
@@ -1478,7 +1463,8 @@ var Novely = (() => {
1478
1463
  [null, 0]
1479
1464
  ],
1480
1465
  state,
1481
- [intime(Date.now()), "auto"]
1466
+ [intime(Date.now()), "auto"],
1467
+ []
1482
1468
  ];
1483
1469
  };
1484
1470
  const getLanguageWithoutParameters = () => {
@@ -1799,6 +1785,61 @@ var Novely = (() => {
1799
1785
  const getCharacterAssets = (character, emotion) => {
1800
1786
  return toArray(characters[character].emotions[emotion]).map(handleImageAsset);
1801
1787
  };
1788
+ const getCharacterName = (character) => {
1789
+ const c = character;
1790
+ const cs = characters;
1791
+ const [lang] = storageData.get().meta;
1792
+ if (c && c in cs) {
1793
+ const block = cs[c].name;
1794
+ if (typeof block === "string") {
1795
+ return block;
1796
+ }
1797
+ if (lang in block) {
1798
+ return block[lang];
1799
+ }
1800
+ }
1801
+ return String(c) || "";
1802
+ };
1803
+ const getDialogOverview = () => {
1804
+ const { value: save2 } = useStack(MAIN_CONTEXT_KEY);
1805
+ const stateSnapshots = save2[3];
1806
+ const { queue } = getActionsFromPath(story, save2[0], false);
1807
+ const [lang] = storageData.get().meta;
1808
+ const dialogItem = [];
1809
+ for (let p = 0, i = 0; i < queue.length; i++) {
1810
+ const action2 = queue[i];
1811
+ if (action2[0] === "dialog") {
1812
+ const [_, name, text] = action2;
1813
+ let voice = void 0;
1814
+ for (let j = i - 1; j > p; j--) {
1815
+ const action3 = queue[j];
1816
+ if (isUserRequiredAction(action3) || isSkippedDuringRestore(action3[0])) break;
1817
+ if (action3[0] === "stopVoice") break;
1818
+ if (action3[0] === "voice") {
1819
+ voice = action3[1];
1820
+ break;
1821
+ }
1822
+ }
1823
+ dialogItem.push({
1824
+ name,
1825
+ text,
1826
+ voice
1827
+ });
1828
+ p = i;
1829
+ }
1830
+ }
1831
+ const entries = dialogItem.map(({ name, text, voice }, i) => {
1832
+ const state = stateSnapshots[i];
1833
+ const audioSource = isString(voice) ? voice : isAsset(voice) ? voice : voice == void 0 ? voice : voice[lang];
1834
+ name = name ? getCharacterName(name) : "";
1835
+ return {
1836
+ name: templateReplace(name, state),
1837
+ text: templateReplace(text, state),
1838
+ voice: audioSource ? handleAudioAsset(audioSource) : ""
1839
+ };
1840
+ });
1841
+ return entries;
1842
+ };
1802
1843
  const renderer = createRenderer({
1803
1844
  mainContextKey: MAIN_CONTEXT_KEY,
1804
1845
  characters: getCharactersData(characters),
@@ -1820,6 +1861,7 @@ var Novely = (() => {
1820
1861
  getLanguageDisplayName,
1821
1862
  getCharacterColor,
1822
1863
  getCharacterAssets,
1864
+ getDialogOverview,
1823
1865
  getResourseType: getResourseTypeForRenderer
1824
1866
  });
1825
1867
  const useStack = createUseStackFunction(renderer);
@@ -1882,9 +1924,9 @@ var Novely = (() => {
1882
1924
  }
1883
1925
  };
1884
1926
  const match = matchAction(matchActionOptions, {
1885
- wait({ ctx, push }, [time]) {
1927
+ wait({ ctx, data: data2, push }, [time]) {
1886
1928
  if (ctx.meta.restoring) return;
1887
- setTimeout(push, isFunction(time) ? time(getStateAtCtx(ctx)) : time);
1929
+ setTimeout(push, isFunction(time) ? time(data2) : time);
1888
1930
  },
1889
1931
  showBackground({ ctx, push }, [background]) {
1890
1932
  if (isString(background) || isAsset(background)) {
@@ -1954,21 +1996,11 @@ var Novely = (() => {
1954
1996
  ctx.character(character).remove(className, style, duration, ctx.meta.restoring).then(push);
1955
1997
  },
1956
1998
  dialog({ ctx, data: data2, forward }, [character, content, emotion]) {
1957
- const name = (() => {
1958
- const c = character;
1959
- const cs = characters;
1960
- const [lang] = storageData.get().meta;
1961
- if (c && c in cs) {
1962
- const block = cs[c].name;
1963
- if (typeof block === "string") {
1964
- return block;
1965
- }
1966
- if (lang in block) {
1967
- return block[lang];
1968
- }
1969
- }
1970
- return c || "";
1971
- })();
1999
+ const name = getCharacterName(character);
2000
+ const stack = useStack(ctx);
2001
+ if (!ctx.meta.restoring && !ctx.meta.goingBack) {
2002
+ stack.value[3].push(clone(data2));
2003
+ }
1972
2004
  ctx.clearBlockingActions("dialog");
1973
2005
  ctx.dialog(templateReplace(content, data2), templateReplace(name, data2), character, emotion, forward);
1974
2006
  },
@@ -1995,19 +2027,19 @@ var Novely = (() => {
1995
2027
  const transformedChoices = choices.map(([content, _children, active, visible, onSelect, image]) => {
1996
2028
  const active$ = store(false);
1997
2029
  const visible$ = store(false);
1998
- const update = () => {
1999
- const lang = getLanguageFromStore(storageData);
2000
- const state = getStateAtCtx(ctx);
2001
- const activeValue = !active || active({
2002
- lang,
2003
- state
2004
- });
2005
- const visibleValue = !visible || visible({
2030
+ const lang = getLanguageFromStore(storageData);
2031
+ const getCheckValue = (fn) => {
2032
+ if (!fn) {
2033
+ return true;
2034
+ }
2035
+ return fn({
2006
2036
  lang,
2007
- state
2037
+ state: getStateAtCtx(ctx)
2008
2038
  });
2009
- active$.set(activeValue);
2010
- visible$.set(visibleValue);
2039
+ };
2040
+ const update = () => {
2041
+ active$.set(getCheckValue(active));
2042
+ visible$.set(getCheckValue(visible));
2011
2043
  };
2012
2044
  update();
2013
2045
  const onSelectGuarded = onSelect || noop;
@@ -2051,6 +2083,7 @@ var Novely = (() => {
2051
2083
  ["jump", scene],
2052
2084
  [null, -1]
2053
2085
  ];
2086
+ stack.value[3] = [];
2054
2087
  match("clear", [], {
2055
2088
  ctx,
2056
2089
  data: data2
@@ -2065,12 +2098,12 @@ var Novely = (() => {
2065
2098
  push
2066
2099
  );
2067
2100
  },
2068
- condition({ ctx }, [condition, variants]) {
2101
+ condition({ ctx, data: data2 }, [condition, variants]) {
2069
2102
  if (DEV && Object.values(variants).length === 0) {
2070
2103
  throw new Error(`Attempt to use Condition action with empty variants object`);
2071
2104
  }
2072
2105
  if (!ctx.meta.restoring) {
2073
- const val = String(condition(getStateAtCtx(ctx)));
2106
+ const val = String(condition(data2));
2074
2107
  if (DEV && !variants[val]) {
2075
2108
  throw new Error(`Attempt to go to unknown variant "${val}"`);
2076
2109
  }
@@ -2189,22 +2222,23 @@ var Novely = (() => {
2189
2222
  });
2190
2223
  const render = (ctx) => {
2191
2224
  const stack = useStack(ctx);
2192
- const referred = refer(stack.value[0]);
2225
+ const [path, state] = stack.value;
2226
+ const referred = refer(path);
2193
2227
  if (isAction(referred)) {
2194
2228
  const [action2, ...props] = referred;
2195
2229
  match(action2, props, {
2196
2230
  ctx,
2197
- data: stack.value[1]
2231
+ data: state
2198
2232
  });
2199
2233
  } else if (Object.values(story).some((branch) => branch === referred)) {
2200
2234
  match("end", [], {
2201
2235
  ctx,
2202
- data: stack.value[1]
2236
+ data: state
2203
2237
  });
2204
2238
  } else {
2205
2239
  match("exit", [], {
2206
2240
  ctx,
2207
- data: stack.value[1]
2241
+ data: state
2208
2242
  });
2209
2243
  }
2210
2244
  };
@@ -2217,10 +2251,10 @@ var Novely = (() => {
2217
2251
  meta: [lang]
2218
2252
  } = storageData.get();
2219
2253
  const obj = values || data2;
2220
- const str2 = flattenAllowedContent(!isFunction(content) && !isString(content) ? content[lang] : content, obj);
2254
+ const str = flattenAllowedContent(!isFunction(content) && !isString(content) ? content[lang] : content, obj);
2221
2255
  const t2 = translation[lang];
2222
2256
  const pluralRules = (t2.plural || t2.actions) && new Intl.PluralRules(t2.tag || lang);
2223
- return replace(str2, obj, t2.plural, t2.actions, pluralRules);
2257
+ return replace(str, obj, t2.plural, t2.actions, pluralRules);
2224
2258
  };
2225
2259
  const data = (value) => {
2226
2260
  const _data = storageData.get().data;
@@ -2417,7 +2451,9 @@ var Novely = (() => {
2417
2451
  CloseMenu: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C \u043C\u0435\u043D\u044E",
2418
2452
  MusicVolume: "\u0413\u0440\u043E\u043C\u043A\u043E\u0441\u0442\u044C \u043C\u0443\u0437\u044B\u043A\u0438",
2419
2453
  SoundVolume: "\u0413\u0440\u043E\u043C\u043A\u043E\u0441\u0442\u044C \u0437\u0432\u0443\u043A\u043E\u0432",
2420
- VoiceVolume: "\u0413\u0440\u043E\u043C\u043A\u043E\u0441\u0442\u044C \u0440\u0435\u0447\u0438"
2454
+ VoiceVolume: "\u0413\u0440\u043E\u043C\u043A\u043E\u0441\u0442\u044C \u0440\u0435\u0447\u0438",
2455
+ Close: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C",
2456
+ DialogOverview: "\u041E\u0431\u0437\u043E\u0440 \u0434\u0438\u0430\u043B\u043E\u0433\u0430"
2421
2457
  };
2422
2458
  var EN = {
2423
2459
  NewGame: "New Game",
@@ -2453,7 +2489,9 @@ var Novely = (() => {
2453
2489
  CloseMenu: "Close menu",
2454
2490
  MusicVolume: "Music volume",
2455
2491
  SoundVolume: "Sound volume",
2456
- VoiceVolume: "Voice volume"
2492
+ VoiceVolume: "Voice volume",
2493
+ Close: "Close",
2494
+ DialogOverview: "Dialog Overview"
2457
2495
  };
2458
2496
  var KK = {
2459
2497
  NewGame: "\u0416\u0430\u04A3\u0430 \u043E\u0439\u044B\u043D",
@@ -2489,7 +2527,9 @@ var Novely = (() => {
2489
2527
  CloseMenu: "\u041C\u04D9\u0437\u0456\u0440\u0434\u0456 \u0436\u0430\u0431\u0443",
2490
2528
  MusicVolume: "\u041C\u0443\u0437\u044B\u043A\u0430\u043D\u044B\u04A3 \u043A\u04E9\u043B\u0435\u043C\u0456",
2491
2529
  SoundVolume: "\u0414\u044B\u0431\u044B\u0441\u0442\u0430\u0440\u0434\u044B\u04A3 \u043A\u04E9\u043B\u0435\u043C\u0456",
2492
- VoiceVolume: "\u0421\u04E9\u0439\u043B\u0435\u0443 \u043A\u04E9\u043B\u0435\u043C\u0456"
2530
+ VoiceVolume: "\u0421\u04E9\u0439\u043B\u0435\u0443 \u043A\u04E9\u043B\u0435\u043C\u0456",
2531
+ Close: "\u0416\u0430\u0431\u0443",
2532
+ DialogOverview: "\u0414\u0438\u0430\u043B\u043E\u0433\u049B\u0430 \u0428\u043E\u043B\u0443"
2493
2533
  };
2494
2534
  var JP = {
2495
2535
  NewGame: "\u300C\u65B0\u3057\u3044\u30B2\u30FC\u30E0\u300D",
@@ -2525,7 +2565,133 @@ var Novely = (() => {
2525
2565
  CloseMenu: "\u30E1\u30CB\u30E5\u30FC\u3092\u9589\u3058\u308B",
2526
2566
  MusicVolume: "\u97F3\u697D\u306E\u30DC\u30EA\u30E5\u30FC\u30E0",
2527
2567
  SoundVolume: "\u97F3\u91CF",
2528
- VoiceVolume: "\u30B9\u30D4\u30FC\u30C1\u306E\u91CF"
2568
+ VoiceVolume: "\u30B9\u30D4\u30FC\u30C1\u306E\u91CF",
2569
+ Close: "\u9589\u3058\u308B",
2570
+ DialogOverview: "\u30C0\u30A4\u30A2\u30ED\u30B0\u306E\u6982\u8981"
2571
+ };
2572
+
2573
+ // src/audio-codecs.ts
2574
+ var cut = (str) => str.replace(/^no$/, "");
2575
+ var audio = new Audio();
2576
+ var canPlay = (type) => !!cut(audio.canPlayType(type));
2577
+ var canPlayMultiple = (...types) => types.some((type) => canPlay(type));
2578
+ var supportsMap = {
2579
+ mp3: canPlayMultiple("audio/mpeg;", "audio/mp3;"),
2580
+ mpeg: canPlay("audio/mpeg;"),
2581
+ opus: canPlay('audio/ogg; codecs="opus"'),
2582
+ ogg: canPlay('audio/ogg; codecs="vorbis"'),
2583
+ oga: canPlay('audio/ogg; codecs="vorbis"'),
2584
+ wav: canPlayMultiple('audio/wav; codecs="1"', "audio/wav;"),
2585
+ aac: canPlay("audio/aac;"),
2586
+ caf: canPlay("audio/x-caf;"),
2587
+ m4a: canPlayMultiple("audio/x-m4a;", "audio/m4a;", "audio/aac;"),
2588
+ m4b: canPlayMultiple("audio/x-m4b;", "audio/m4b;", "audio/aac;"),
2589
+ mp4: canPlayMultiple("audio/x-mp4;", "audio/mp4;", "audio/aac;"),
2590
+ weba: canPlay('audio/webm; codecs="vorbis"'),
2591
+ webm: canPlay('audio/webm; codecs="vorbis"'),
2592
+ dolby: canPlay('audio/mp4; codecs="ec-3"'),
2593
+ flac: canPlayMultiple("audio/x-flac;", "audio/flac;")
2594
+ };
2595
+
2596
+ // src/image-formats.ts
2597
+ var avif = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
2598
+ var jxl = "data:image/jxl;base64,/woIAAAMABKIAgC4AF3lEgAAFSqjjBu8nOv58kOHxbSN6wxttW1hSaLIODZJJ3BIEkkaoCUzGM6qJAE=";
2599
+ var webp = "data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA";
2600
+ var supportsFormat = (source) => {
2601
+ const { promise, resolve } = Promise.withResolvers();
2602
+ const img = Object.assign(document.createElement("img"), {
2603
+ src: source
2604
+ });
2605
+ img.onload = img.onerror = () => {
2606
+ resolve(img.height === 2);
2607
+ };
2608
+ return promise;
2609
+ };
2610
+ var supportsMap2 = {
2611
+ avif: false,
2612
+ jxl: false,
2613
+ webp: false
2614
+ };
2615
+ var formatsMap = {
2616
+ avif,
2617
+ jxl,
2618
+ webp
2619
+ };
2620
+ var loadImageFormatsSupport = async () => {
2621
+ const promises = [];
2622
+ for (const [format, source] of Object.entries(formatsMap)) {
2623
+ const promise = supportsFormat(source).then((supported) => {
2624
+ supportsMap2[format] = supported;
2625
+ });
2626
+ promises.push(promise);
2627
+ }
2628
+ await Promise.all(promises);
2629
+ };
2630
+ loadImageFormatsSupport();
2631
+
2632
+ // src/asset.ts
2633
+ var getType = memoize(
2634
+ (extensions) => {
2635
+ if (extensions.every((extension) => HOWLER_SUPPORTED_FILE_FORMATS.has(extension))) {
2636
+ return "audio";
2637
+ }
2638
+ if (extensions.every((extension) => SUPPORTED_IMAGE_FILE_FORMATS.has(extension))) {
2639
+ return "image";
2640
+ }
2641
+ throw extensions;
2642
+ },
2643
+ {
2644
+ getCacheKey: (extensions) => extensions.join("~")
2645
+ }
2646
+ );
2647
+ var SUPPORT_MAPS = {
2648
+ image: supportsMap2,
2649
+ audio: supportsMap
2650
+ };
2651
+ var assetPrivate = memoize(
2652
+ (variants) => {
2653
+ if (DEV && variants.length === 0) {
2654
+ throw new Error(`Attempt to use "asset" function without arguments`);
2655
+ }
2656
+ const map = {};
2657
+ const extensions = [];
2658
+ for (const v of variants) {
2659
+ const e = getUrlFileExtension(v);
2660
+ map[e] = v;
2661
+ extensions.push(e);
2662
+ }
2663
+ const type = getType(extensions);
2664
+ const getSource = once(() => {
2665
+ const support = SUPPORT_MAPS[type];
2666
+ for (const extension of extensions) {
2667
+ if (extension in support) {
2668
+ if (support[extension]) {
2669
+ return map[extension];
2670
+ }
2671
+ } else {
2672
+ return map[extension];
2673
+ }
2674
+ }
2675
+ if (DEV) {
2676
+ throw new Error(`No matching asset was found for ${variants.map((v) => `"${v}"`).join(", ")}`);
2677
+ }
2678
+ return "";
2679
+ });
2680
+ return {
2681
+ get source() {
2682
+ return getSource();
2683
+ },
2684
+ get type() {
2685
+ return type;
2686
+ }
2687
+ };
2688
+ },
2689
+ {
2690
+ getCacheKey: (variants) => variants.join("~")
2691
+ }
2692
+ );
2693
+ var asset = (...variants) => {
2694
+ return assetPrivate(variants);
2529
2695
  };
2530
2696
  return __toCommonJS(src_exports);
2531
2697
  })();