@novely/core 0.40.3 → 0.42.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 CHANGED
@@ -101,7 +101,7 @@ type Context = {
101
101
  character: (character: string) => CharacterHandle;
102
102
  background: (background: Record<string, string>) => void;
103
103
  dialog: (content: string, name: string, character: string | undefined, emotion: string | undefined, resolve: () => void) => void;
104
- choices: (question: string, choices: [name: string, active: boolean][], resolve: (selected: number) => void) => void;
104
+ choices: (question: string, choices: [name: string, active: boolean, visible: boolean, image: string][], resolve: (selected: number) => void) => void;
105
105
  input: (question: string, onInput: (meta: ActionInputOnInputMeta<Lang, State>) => void, setup: ActionInputSetup, resolve: () => void) => void;
106
106
  clear: (keep: Set<keyof DefaultActionProxy>, keepCharacters: Set<string>, keepAudio: {
107
107
  music: Set<string>;
@@ -328,6 +328,7 @@ type CharactersData<$Characters extends Record<string, Character<Lang>>> = {
328
328
  };
329
329
  };
330
330
  type AssetsPreloading = 'lazy' | 'blocking' | 'automatic';
331
+ type CloneFN = <T>(value: T) => T;
331
332
  interface NovelyInit<$Language extends Lang, $Characters extends Record<string, Character<NoInfer<$Language>>>, $State extends State, $Data extends Data, $Actions extends Record<string, (...args: any[]) => ValidAction>> {
332
333
  /**
333
334
  * An object containing the characters in the game.
@@ -509,6 +510,10 @@ interface NovelyInit<$Language extends Lang, $Characters extends Record<string,
509
510
  * Fetching function
510
511
  */
511
512
  fetch?: typeof fetch;
513
+ /**
514
+ * Function for clonning operations
515
+ */
516
+ cloneFunction?: CloneFN;
512
517
  /**
513
518
  * When page is going to be unloaded will call `storage.set` method
514
519
  * If 'prod' is passed enable only in production env.
@@ -555,10 +560,10 @@ type Character<$Lang extends Lang = string> = {
555
560
  emotions: Emotions;
556
561
  };
557
562
 
558
- type ValidAction = ['choice', number] | ['clear', Set<keyof DefaultActionProxy>?, Set<string>?, {
563
+ type ValidAction = ['choice', string | undefined, ...[string, unknown[], (() => boolean)?, (() => boolean)?, string?][]] | ['clear', Set<keyof DefaultActionProxy>?, Set<string>?, {
559
564
  music: Set<string>;
560
565
  sounds: Set<string>;
561
- }?] | ['condition', (state: State) => boolean, Record<string, ValidAction[]>] | ['dialog', string | undefined, TextContent<string, State>, string | undefined] | ['say', string, TextContent<string, State>] | ['end'] | ['showBackground', string | NovelyAsset | BackgroundImage] | ['playMusic', string | NovelyAsset] | ['stopMusic', string | NovelyAsset] | ['pauseMusic', string | NovelyAsset] | ['playSound', audio: string | NovelyAsset, loop?: boolean] | ['pauseSound', string | NovelyAsset] | ['stopSound', string | NovelyAsset] | ['voice', string | NovelyAsset | Record<string, string | NovelyAsset>] | ['stopVoice'] | ['jump', string] | ['showCharacter', string, keyof Character['emotions'], string?, string?] | ['hideCharacter', string, string?, string?, number?] | ['animateCharacter', string, number, ...string[]] | ['wait', (number | ((state: State) => number))] | ['function', FunctionAction<string, State>] | ['input', string, (meta: ActionInputOnInputMeta<string, State>) => void, ActionInputSetup?] | ['custom', CustomHandler<string, State>] | ['vibrate', ...number[]] | ['next'] | ['text', ...TextContent<string, State>[]] | ['exit'] | ['preload', string] | ['block', string] | ValidAction[];
566
+ }?] | ['condition', (state: State) => boolean, Record<string, ValidAction[]>] | ['dialog', string | undefined, TextContent<string, State>, string | undefined] | ['end'] | ['showBackground', string | NovelyAsset | BackgroundImage] | ['playMusic', string | NovelyAsset] | ['stopMusic', string | NovelyAsset] | ['pauseMusic', string | NovelyAsset] | ['playSound', audio: string | NovelyAsset, loop?: boolean] | ['pauseSound', string | NovelyAsset] | ['stopSound', string | NovelyAsset] | ['voice', string | NovelyAsset | Record<string, string | NovelyAsset>] | ['stopVoice'] | ['jump', string] | ['showCharacter', string, keyof Character['emotions'], string?, string?] | ['hideCharacter', string, string?, string?, number?] | ['animateCharacter', string, number, ...string[]] | ['wait', (number | ((state: State) => number))] | ['function', FunctionAction<string, State>] | ['input', string, (meta: ActionInputOnInputMeta<string, State>) => void, ActionInputSetup?] | ['custom', CustomHandler<string, State>] | ['vibrate', ...number[]] | ['next'] | ['text', ...TextContent<string, State>[]] | ['exit'] | ['preload', string] | ['block', string] | ValidAction[];
562
567
  type Story = Record<string, ValidAction[]>;
563
568
  type TextContent<L extends string, S extends State> = string | ((state: S) => string) | Record<L, string | ((state: S) => string)>;
564
569
  type FunctionableValue<T> = T | (() => T);
@@ -728,10 +733,24 @@ type ActionInputSetupCleanup = () => void;
728
733
  type ActionInputSetup = (input: HTMLInputElement) => ActionInputSetupCleanup | void;
729
734
  type BackgroundImage = Record<string, string | NovelyAsset>;
730
735
  type VoiceAction<L extends Lang> = (params: string | NovelyAsset | Partial<Record<L, string | NovelyAsset>>) => ValidAction;
736
+ type ActionChoiceExtendedChoice<Languages extends Lang, S extends State> = {
737
+ title: TextContent<Languages, S>;
738
+ children: ValidAction[];
739
+ active?: ChoiceCheckFunction<Languages, S>;
740
+ visible?: ChoiceCheckFunction<Languages, S>;
741
+ image?: string | NovelyAsset;
742
+ };
743
+ type ActionChoiceChoice<Languages extends Lang, S extends State> = [
744
+ title: TextContent<Languages, S>,
745
+ actions: ValidAction[],
746
+ active?: ChoiceCheckFunction<Languages, S>,
747
+ visible?: ChoiceCheckFunction<Languages, S>,
748
+ image?: string | NovelyAsset
749
+ ];
731
750
  type ActionProxy<Characters extends Record<string, Character>, Languages extends Lang, S extends State> = {
732
751
  choice: {
733
- (...choices: [name: TextContent<Languages, S>, actions: ValidAction[], active?: ChoiceCheckFunction<Languages, S>][]): ValidAction;
734
- (question: TextContent<Languages, S>, ...choices: [name: TextContent<Languages, S>, actions: ValidAction[], active?: ChoiceCheckFunction<Languages, S>][]): ValidAction;
752
+ (...choices: ActionChoiceChoice<Languages, S>[]): ValidAction;
753
+ (question: TextContent<Languages, S>, ...choices: ActionChoiceChoice<Languages, S>[]): ValidAction;
735
754
  };
736
755
  clear: (keep?: Set<keyof DefaultActionProxy>, keepCharacters?: Set<string>, keepAudio?: {
737
756
  music: Set<string>;
@@ -744,7 +763,6 @@ type ActionProxy<Characters extends Record<string, Character>, Languages extends
744
763
  (character: undefined, content: TextContent<Languages, S>, emotion?: undefined): ValidAction;
745
764
  (character: string, content: TextContent<Languages, S>, emotion?: undefined): ValidAction;
746
765
  };
747
- say: (character: keyof Characters, content: TextContent<Languages, S>) => ValidAction;
748
766
  end: () => ValidAction;
749
767
  showBackground: {
750
768
  (background: string | NovelyAsset): ValidAction;
@@ -790,13 +808,17 @@ type ActionProxy<Characters extends Record<string, Character>, Languages extends
790
808
  };
791
809
  type DefaultActionProxy = ActionProxy<Record<string, Character>, Lang, State>;
792
810
  type GetActionParameters<T extends Capitalize<keyof DefaultActionProxy>> = Parameters<DefaultActionProxy[Uncapitalize<T>]>;
811
+ type VirtualActions<Characters extends Record<string, Character>, Languages extends Lang, S extends State> = {
812
+ choiceExtended: (question: TextContent<Languages, S>, choices: ActionChoiceExtendedChoice<Languages, State>[]) => ValidAction;
813
+ say: (character: keyof Characters, content: TextContent<Languages, S>) => ValidAction;
814
+ };
793
815
 
794
816
  type ConditionParams<T> = T extends TypeEssentials<any, infer $State, any, any> ? $State : never;
795
817
  type ChoiceParams<T> = T extends TypeEssentials<infer $Lang, infer $State, any, any> ? ChoiceCheckFunctionProps<$Lang, $State> : never;
796
818
  type FunctionParams<T> = T extends TypeEssentials<infer $Lang, infer $State, any, any> ? FunctionActionProps<$Lang, $State> : never;
797
819
  type InputHandler<T> = T extends TypeEssentials<infer $Lang, infer $State, any, any> ? ActionInputOnInputMeta<$Lang, $State> : never;
798
820
 
799
- declare const novely: <$Language extends string, $Characters extends Record<string, Character<$Language>>, $State extends State, $Data extends Data, $Actions extends Record<string, (...args: any[]) => ValidAction>>({ characters, characterAssetSizes, defaultEmotions, storage, storageDelay, renderer: createRenderer, initialScreen, translation, state: defaultState, data: defaultData, autosaves, migrations, throttleTimeout, getLanguage, overrideLanguage, askBeforeExit, preloadAssets, parallelAssetsDownloadLimit, fetch: request, saveOnUnload, startKey }: NovelyInit<$Language, $Characters, $State, $Data, $Actions>) => {
821
+ declare const novely: <$Language extends string, $Characters extends Record<string, Character<$Language>>, $State extends State, $Data extends Data, $Actions extends Record<string, (...args: any[]) => ValidAction>>({ characters, characterAssetSizes, defaultEmotions, storage, storageDelay, renderer: createRenderer, initialScreen, translation, state: defaultState, data: defaultData, autosaves, migrations, throttleTimeout, getLanguage, overrideLanguage, askBeforeExit, preloadAssets, parallelAssetsDownloadLimit, fetch: request, cloneFunction: clone, saveOnUnload, startKey, }: NovelyInit<$Language, $Characters, $State, $Data, $Actions>) => {
800
822
  /**
801
823
  * Function to set game script
802
824
  *
@@ -822,7 +844,7 @@ declare const novely: <$Language extends string, $Characters extends Record<stri
822
844
  * })
823
845
  * ```
824
846
  */
825
- action: $Actions & ActionProxy<$Characters, $Language, $State>;
847
+ action: $Actions & ActionProxy<$Characters, $Language, $State> & VirtualActions<$Characters, $Language, $State>;
826
848
  /**
827
849
  * @deprecated Will be removed BUT replaced with state passed into actions as a parameter
828
850
  */
@@ -32,9 +32,10 @@ var Novely = (() => {
32
32
  });
33
33
 
34
34
  // src/constants.ts
35
- var SKIPPED_DURING_RESTORE = /* @__PURE__ */ new Set(["dialog", "say", "choice", "input", "vibrate", "text"]);
35
+ var SKIPPED_DURING_RESTORE = /* @__PURE__ */ new Set(["dialog", "choice", "input", "vibrate", "text"]);
36
36
  var BLOCK_EXIT_STATEMENTS = /* @__PURE__ */ new Set(["choice:exit", "condition:exit", "block:exit"]);
37
37
  var BLOCK_STATEMENTS = /* @__PURE__ */ new Set(["choice", "condition", "block"]);
38
+ var VIRTUAL_ACTIONS = /* @__PURE__ */ new Set(["say", "choiceExtended"]);
38
39
  var AUDIO_ACTIONS = /* @__PURE__ */ new Set([
39
40
  "playMusic",
40
41
  "stopMusic",
@@ -87,53 +88,6 @@ var Novely = (() => {
87
88
  // ../../node_modules/.pnpm/esm-env@1.0.0/node_modules/esm-env/prod-ssr.js
88
89
  var DEV = false;
89
90
 
90
- // ../../node_modules/.pnpm/klona@2.0.6/node_modules/klona/full/index.mjs
91
- function set(obj, key, val) {
92
- if (typeof val.value === "object") val.value = klona(val.value);
93
- if (!val.enumerable || val.get || val.set || !val.configurable || !val.writable || key === "__proto__") {
94
- Object.defineProperty(obj, key, val);
95
- } else obj[key] = val.value;
96
- }
97
- function klona(x) {
98
- if (typeof x !== "object") return x;
99
- var i = 0, k, list, tmp, str2 = Object.prototype.toString.call(x);
100
- if (str2 === "[object Object]") {
101
- tmp = Object.create(x.__proto__ || null);
102
- } else if (str2 === "[object Array]") {
103
- tmp = Array(x.length);
104
- } else if (str2 === "[object Set]") {
105
- tmp = /* @__PURE__ */ new Set();
106
- x.forEach(function(val) {
107
- tmp.add(klona(val));
108
- });
109
- } else if (str2 === "[object Map]") {
110
- tmp = /* @__PURE__ */ new Map();
111
- x.forEach(function(val, key) {
112
- tmp.set(klona(key), klona(val));
113
- });
114
- } else if (str2 === "[object Date]") {
115
- tmp = /* @__PURE__ */ new Date(+x);
116
- } else if (str2 === "[object RegExp]") {
117
- tmp = new RegExp(x.source, x.flags);
118
- } else if (str2 === "[object DataView]") {
119
- tmp = new x.constructor(klona(x.buffer));
120
- } else if (str2 === "[object ArrayBuffer]") {
121
- tmp = x.slice(0);
122
- } else if (str2.slice(-6) === "Array]") {
123
- tmp = new x.constructor(x);
124
- }
125
- if (tmp) {
126
- for (list = Object.getOwnPropertySymbols(x); i < list.length; i++) {
127
- set(tmp, list[i], Object.getOwnPropertyDescriptor(x, list[i]));
128
- }
129
- for (i = 0, list = Object.getOwnPropertyNames(x); i < list.length; i++) {
130
- if (Object.hasOwnProperty.call(tmp, k = list[i]) && tmp[k] === x[k]) continue;
131
- set(tmp, k, Object.getOwnPropertyDescriptor(x, k));
132
- }
133
- }
134
- return tmp || x;
135
- }
136
-
137
91
  // ../../node_modules/.pnpm/es-toolkit@1.16.0/node_modules/es-toolkit/dist/function/once.mjs
138
92
  function once(func) {
139
93
  let called = false;
@@ -309,13 +263,11 @@ var Novely = (() => {
309
263
  var matchAction = ({ getContext, onBeforeActionCall, push, forward }, values) => {
310
264
  return (action, props, { ctx, data }) => {
311
265
  const context = typeof ctx === "string" ? getContext(ctx) : ctx;
312
- if (action !== "say") {
313
- onBeforeActionCall({
314
- action,
315
- props,
316
- ctx: context
317
- });
318
- }
266
+ onBeforeActionCall({
267
+ action,
268
+ props,
269
+ ctx: context
270
+ });
319
271
  return values[action]({
320
272
  ctx: context,
321
273
  data,
@@ -803,7 +755,7 @@ var Novely = (() => {
803
755
  var isBlockingAction = (action) => {
804
756
  return isUserRequiredAction(action) || isSkippedDuringRestore(action[0]) && action[0] !== "vibrate";
805
757
  };
806
- var collectActionsBeforeBlockingAction = ({ path, refer }) => {
758
+ var collectActionsBeforeBlockingAction = ({ path, refer, clone }) => {
807
759
  const collection = [];
808
760
  let action = refer(path);
809
761
  while (true) {
@@ -826,11 +778,12 @@ var Novely = (() => {
826
778
  for (let i = 0; i < choiceProps.length; i++) {
827
779
  const branchContent = choiceProps[i];
828
780
  if (!Array.isArray(branchContent)) continue;
829
- const virtualPath = klona(path);
781
+ const virtualPath = clone(path);
830
782
  virtualPath.push(["choice", i], [null, 0]);
831
783
  const innerActions = collectActionsBeforeBlockingAction({
832
784
  path: virtualPath,
833
- refer
785
+ refer,
786
+ clone
834
787
  });
835
788
  collection.push(...innerActions);
836
789
  }
@@ -838,11 +791,12 @@ var Novely = (() => {
838
791
  const conditionProps = props;
839
792
  const conditions = Object.keys(conditionProps[1]);
840
793
  for (const condition of conditions) {
841
- const virtualPath = klona(path);
794
+ const virtualPath = clone(path);
842
795
  virtualPath.push(["condition", condition], [null, 0]);
843
796
  const innerActions = collectActionsBeforeBlockingAction({
844
797
  path: virtualPath,
845
- refer
798
+ refer,
799
+ clone
846
800
  });
847
801
  collection.push(...innerActions);
848
802
  }
@@ -968,6 +922,53 @@ var Novely = (() => {
968
922
  return { subscribe, update, set: set2, get };
969
923
  };
970
924
 
925
+ // ../../node_modules/.pnpm/klona@2.0.6/node_modules/klona/full/index.mjs
926
+ function set(obj, key, val) {
927
+ if (typeof val.value === "object") val.value = klona(val.value);
928
+ if (!val.enumerable || val.get || val.set || !val.configurable || !val.writable || key === "__proto__") {
929
+ Object.defineProperty(obj, key, val);
930
+ } else obj[key] = val.value;
931
+ }
932
+ function klona(x) {
933
+ if (typeof x !== "object") return x;
934
+ var i = 0, k, list, tmp, str2 = Object.prototype.toString.call(x);
935
+ if (str2 === "[object Object]") {
936
+ tmp = Object.create(x.__proto__ || null);
937
+ } else if (str2 === "[object Array]") {
938
+ tmp = Array(x.length);
939
+ } else if (str2 === "[object Set]") {
940
+ tmp = /* @__PURE__ */ new Set();
941
+ x.forEach(function(val) {
942
+ tmp.add(klona(val));
943
+ });
944
+ } else if (str2 === "[object Map]") {
945
+ tmp = /* @__PURE__ */ new Map();
946
+ x.forEach(function(val, key) {
947
+ tmp.set(klona(key), klona(val));
948
+ });
949
+ } else if (str2 === "[object Date]") {
950
+ tmp = /* @__PURE__ */ new Date(+x);
951
+ } else if (str2 === "[object RegExp]") {
952
+ tmp = new RegExp(x.source, x.flags);
953
+ } else if (str2 === "[object DataView]") {
954
+ tmp = new x.constructor(klona(x.buffer));
955
+ } else if (str2 === "[object ArrayBuffer]") {
956
+ tmp = x.slice(0);
957
+ } else if (str2.slice(-6) === "Array]") {
958
+ tmp = new x.constructor(x);
959
+ }
960
+ if (tmp) {
961
+ for (list = Object.getOwnPropertySymbols(x); i < list.length; i++) {
962
+ set(tmp, list[i], Object.getOwnPropertyDescriptor(x, list[i]));
963
+ }
964
+ for (i = 0, list = Object.getOwnPropertyNames(x); i < list.length; i++) {
965
+ if (Object.hasOwnProperty.call(tmp, k = list[i]) && tmp[k] === x[k]) continue;
966
+ set(tmp, k, Object.getOwnPropertyDescriptor(x, k));
967
+ }
968
+ }
969
+ return tmp || x;
970
+ }
971
+
971
972
  // src/translation.ts
972
973
  var RGX = /{{(.*?)}}/g;
973
974
  var split = (input, delimeters) => {
@@ -1344,6 +1345,14 @@ var Novely = (() => {
1344
1345
  }
1345
1346
  return;
1346
1347
  }
1348
+ if (action === "choice") {
1349
+ for (let i = 1; i < props.length; i++) {
1350
+ const data = props[i];
1351
+ if (Array.isArray(data)) {
1352
+ handle(handleImageAsset(data[4]));
1353
+ }
1354
+ }
1355
+ }
1347
1356
  };
1348
1357
 
1349
1358
  // src/novely.ts
@@ -1367,6 +1376,7 @@ var Novely = (() => {
1367
1376
  preloadAssets = "lazy",
1368
1377
  parallelAssetsDownloadLimit = 15,
1369
1378
  fetch: request = fetch,
1379
+ cloneFunction: clone = klona,
1370
1380
  saveOnUnload = true,
1371
1381
  startKey = "start"
1372
1382
  }) => {
@@ -1419,6 +1429,28 @@ var Novely = (() => {
1419
1429
  return renderer.actions[action2];
1420
1430
  }
1421
1431
  return (...props) => {
1432
+ if (VIRTUAL_ACTIONS.has(action2)) {
1433
+ if (action2 === "say") {
1434
+ action2 = "dialog";
1435
+ const [character] = props;
1436
+ if (DEV && !characters[character]) {
1437
+ throw new Error(`Attempt to call Say action with unknown character "${character}"`);
1438
+ }
1439
+ } else if (action2 === "choiceExtended") {
1440
+ action2 = "choice";
1441
+ const choices = props[1];
1442
+ const mappedChoices = choices.map((choice) => [
1443
+ choice.title,
1444
+ choice.children,
1445
+ choice.active,
1446
+ choice.visible,
1447
+ choice.image
1448
+ ]);
1449
+ for (let i = 0; i < mappedChoices.length; i++) {
1450
+ props[i + 1] = mappedChoices[i];
1451
+ }
1452
+ }
1453
+ }
1422
1454
  if (preloadAssets === "blocking") {
1423
1455
  huntAssets({
1424
1456
  action: action2,
@@ -1434,7 +1466,7 @@ var Novely = (() => {
1434
1466
  };
1435
1467
  }
1436
1468
  });
1437
- const getDefaultSave = (state = {}) => {
1469
+ const getDefaultSave = (state) => {
1438
1470
  return [
1439
1471
  [
1440
1472
  ["jump", startKey],
@@ -1456,7 +1488,7 @@ var Novely = (() => {
1456
1488
  };
1457
1489
  const initialData = {
1458
1490
  saves: [],
1459
- data: klona(defaultData),
1491
+ data: clone(defaultData),
1460
1492
  meta: [getLanguageWithoutParameters(), DEFAULT_TYPEWRITER_SPEED, 1, 1, 1]
1461
1493
  };
1462
1494
  const storageData = store(initialData);
@@ -1506,7 +1538,7 @@ var Novely = (() => {
1506
1538
  storageData.set(stored);
1507
1539
  };
1508
1540
  storageDelay.then(getStoredData);
1509
- const initial = getDefaultSave(klona(defaultState));
1541
+ const initial = getDefaultSave(clone(defaultState));
1510
1542
  const unsubscribeFromBrowserVisibilityChange = setupBrowserVisibilityChangeListeners({
1511
1543
  onChange: throttledEmergencyOnStorageDataChange
1512
1544
  });
@@ -1514,7 +1546,7 @@ var Novely = (() => {
1514
1546
  if (!coreData.get().dataLoaded) return;
1515
1547
  if (!autosaves && type === "auto") return;
1516
1548
  const stack = useStack(MAIN_CONTEXT_KEY);
1517
- const current = klona(stack.value);
1549
+ const current = clone(stack.value);
1518
1550
  storageData.update((prev) => {
1519
1551
  const replace2 = () => {
1520
1552
  prev.saves[prev.saves.length - 1] = current;
@@ -1544,7 +1576,7 @@ var Novely = (() => {
1544
1576
  };
1545
1577
  const newGame = () => {
1546
1578
  if (!coreData.get().dataLoaded) return;
1547
- const save2 = getDefaultSave(klona(defaultState));
1579
+ const save2 = getDefaultSave(clone(defaultState));
1548
1580
  if (autosaves) {
1549
1581
  storageData.update((prev) => {
1550
1582
  return prev.saves.push(save2), prev;
@@ -1573,7 +1605,7 @@ var Novely = (() => {
1573
1605
  if (!coreData.get().dataLoaded) return;
1574
1606
  let latest = save2 || storageData.get().saves.at(-1);
1575
1607
  if (!latest) {
1576
- latest = klona(initial);
1608
+ latest = clone(initial);
1577
1609
  storageData.update((prev) => {
1578
1610
  prev.saves.push(latest);
1579
1611
  return prev;
@@ -1685,7 +1717,7 @@ var Novely = (() => {
1685
1717
  const processor = createQueueProcessor(queue, {
1686
1718
  skip: EMPTY_SET
1687
1719
  });
1688
- useStack(ctx).push(klona(save2));
1720
+ useStack(ctx).push(clone(save2));
1689
1721
  const assets = [];
1690
1722
  await processor.run(([action2, ...props]) => {
1691
1723
  if (isAudioAction(action2)) return;
@@ -1780,7 +1812,7 @@ var Novely = (() => {
1780
1812
  const enmemory = (ctx) => {
1781
1813
  if (ctx.meta.restoring) return;
1782
1814
  const stack = useStack(ctx);
1783
- const current = klona(stack.value);
1815
+ const current = clone(stack.value);
1784
1816
  current[2][1] = "auto";
1785
1817
  stack.push(current);
1786
1818
  save("auto");
@@ -1808,8 +1840,9 @@ var Novely = (() => {
1808
1840
  if (!isBlockingAction([action2, ...props])) return;
1809
1841
  try {
1810
1842
  const collection = collectActionsBeforeBlockingAction({
1811
- path: nextPath(klona(useStack(ctx).value[0])),
1812
- refer
1843
+ path: nextPath(clone(useStack(ctx).value[0])),
1844
+ refer,
1845
+ clone
1813
1846
  });
1814
1847
  for (const [action3, ...props2] of collection) {
1815
1848
  huntAssets({
@@ -1927,15 +1960,6 @@ var Novely = (() => {
1927
1960
  forward
1928
1961
  );
1929
1962
  },
1930
- say({ ctx, data: data2 }, [character, content]) {
1931
- if (DEV && !characters[character]) {
1932
- throw new Error(`Attempt to call Say action with unknown character "${character}"`);
1933
- }
1934
- match("dialog", [character, content], {
1935
- ctx,
1936
- data: data2
1937
- });
1938
- },
1939
1963
  function({ ctx, push }, [fn]) {
1940
1964
  const { restoring, goingBack, preview: preview2 } = ctx.meta;
1941
1965
  const result = fn({
@@ -1956,15 +1980,20 @@ var Novely = (() => {
1956
1980
  choices.unshift(question);
1957
1981
  question = "";
1958
1982
  }
1959
- const transformedChoices = choices.map(([content, action2, visible]) => {
1960
- const shown = !visible || visible({
1983
+ const transformedChoices = choices.map(([content, action2, active, visible, image]) => {
1984
+ const activeValue = !active || active({
1985
+ lang: getLanguageFromStore(storageData),
1986
+ state: getStateAtCtx(ctx)
1987
+ });
1988
+ const visibleValue = !visible || visible({
1961
1989
  lang: getLanguageFromStore(storageData),
1962
1990
  state: getStateAtCtx(ctx)
1963
1991
  });
1964
- if (DEV && action2.length === 0 && !shown) {
1992
+ const imageValue = image ? handleImageAsset(image) : "";
1993
+ if (DEV && action2.length === 0 && (!activeValue && !visibleValue)) {
1965
1994
  console.warn(`Choice children should not be empty, either add content there or make item not selectable`);
1966
1995
  }
1967
- return [templateReplace(content, data2), shown];
1996
+ return [templateReplace(content, data2), activeValue, visibleValue, imageValue];
1968
1997
  });
1969
1998
  if (DEV && transformedChoices.length === 0) {
1970
1999
  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]`);
@@ -2191,7 +2220,7 @@ var Novely = (() => {
2191
2220
  c: null
2192
2221
  };
2193
2222
  const getCurrentStorageData = () => {
2194
- return coreData.get().dataLoaded ? klona(storageData.get()) : null;
2223
+ return coreData.get().dataLoaded ? clone(storageData.get()) : null;
2195
2224
  };
2196
2225
  const setStorageData = (data2) => {
2197
2226
  if (destroyed) {