@novely/core 0.4.2 → 0.4.4

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
@@ -17,6 +17,7 @@ type Thenable<T> = T | Promise<T>;
17
17
  type PathItem = [null, number | string] | ['choice' & Record<never, never>, number] | ['condition' & Record<never, never>, string] | ['exit' & Record<never, never>];
18
18
  type Path = PathItem[];
19
19
  type State = Record<string, any>;
20
+ type Data = Record<string, any>;
20
21
  type SaveDate = number;
21
22
  type SaveType = "manual" | "auto";
22
23
  type SaveMeta = [SaveDate, SaveType];
@@ -27,6 +28,7 @@ type StorageMeta = [Lang, TypewriterSpeed];
27
28
  type Migration = (save: unknown) => unknown;
28
29
  type StorageData = {
29
30
  saves: Save[];
31
+ data: Data;
30
32
  meta: StorageMeta;
31
33
  };
32
34
  type Stack = {
@@ -43,13 +45,7 @@ type DeepPartial<T> = unknown extends T ? T : T extends object ? {
43
45
  [P in keyof T]?: T[P] extends Array<infer U> ? Array<DeepPartial<U>> : T[P] extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : DeepPartial<T[P]>;
44
46
  } : T;
45
47
 
46
- type ValidAction = ['choice', [number]] | ['clear', []] | ['condition', [() => boolean, Record<string, ValidAction[]>]] | ['dialog', [string | undefined, Unwrappable, string | undefined]] | ['end', []] | ['showBackground', [string]] | ['playMusic', [string]] | ['stopMusic', [string]] | ['jump', [string]] | ['showCharacter', [string, keyof Character['emotions'], string?, string?]] | ['hideCharacter', [string, string?, string?, number?]] | ['animateCharacter', [string, number, ...string[]]] | ['wait', [FunctionableValue<number>]] | ['function', [() => Thenable<void>]] | ['input', [string, (meta: {
47
- input: HTMLInputElement;
48
- error: (error: string) => void;
49
- event: InputEvent & {
50
- currentTarget: HTMLInputElement;
51
- };
52
- }) => void, ((input: HTMLInputElement) => void)?]] | ['custom', [CustomHandler]] | ['vibrate', [...number[]]] | ['next', []] | ['text', [...string[]]] | ['exit'] | ValidAction[];
48
+ type ValidAction = ['choice', [number]] | ['clear', []] | ['condition', [() => boolean, Record<string, ValidAction[]>]] | ['dialog', [string | undefined, Unwrappable, string | undefined]] | ['end', []] | ['showBackground', [string]] | ['playMusic', [string]] | ['stopMusic', [string]] | ['jump', [string]] | ['showCharacter', [string, keyof Character['emotions'], string?, string?]] | ['hideCharacter', [string, string?, string?, number?]] | ['animateCharacter', [string, number, ...string[]]] | ['wait', [FunctionableValue<number>]] | ['function', [() => Thenable<void>]] | ['input', [string, (meta: ActionInputOnInputMeta) => void, ActionInputSetup?]] | ['custom', [CustomHandler]] | ['vibrate', [...number[]]] | ['next', []] | ['text', [...string[]]] | ['exit'] | ValidAction[];
53
49
  type Story = Record<string, ValidAction[]>;
54
50
  type Unwrappable = string | ((lang: string, obj: Record<string, unknown>) => string) | Record<string, string>;
55
51
  type FunctionableValue<T> = T | (() => T);
@@ -102,6 +98,7 @@ interface ActionInputOnInputMeta {
102
98
  */
103
99
  value: string;
104
100
  }
101
+ type ActionInputSetup = (input: HTMLInputElement, cleanup: (cb: () => void) => void) => void;
105
102
  type ActionProxyProvider<Characters extends Record<string, Character>> = {
106
103
  choice: {
107
104
  (...choices: ([Unwrappable, ValidAction[]] | [Unwrappable, ValidAction[], () => boolean])[]): ValidAction;
@@ -131,7 +128,7 @@ type ActionProxyProvider<Characters extends Record<string, Character>> = {
131
128
  };
132
129
  wait: (time: FunctionableValue<number>) => ValidAction;
133
130
  function: (fn: (restoring: boolean, goingBack: boolean) => Thenable<void>) => ValidAction;
134
- input: (question: Unwrappable, onInput: (meta: ActionInputOnInputMeta) => void, setup?: (input: HTMLInputElement) => void) => ValidAction;
131
+ input: (question: Unwrappable, onInput: (meta: ActionInputOnInputMeta) => void, setup?: ActionInputSetup) => ValidAction;
135
132
  custom: (handler: CustomHandler) => ValidAction;
136
133
  vibrate: (...pattern: number[]) => ValidAction;
137
134
  next: () => ValidAction;
@@ -211,7 +208,7 @@ interface Storage {
211
208
  }
212
209
  declare const localStorageStorage: (options: LocalStorageStorageSettings) => Storage;
213
210
 
214
- interface NovelyInit<Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends ReturnType<SetupT9N<Languages>>, StateScheme extends State> {
211
+ interface NovelyInit<Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends ReturnType<SetupT9N<Languages>>, StateScheme extends State, DataScheme extends Data> {
215
212
  /**
216
213
  * An array of languages supported by the game.
217
214
  */
@@ -244,6 +241,10 @@ interface NovelyInit<Languages extends string, Characters extends Record<string,
244
241
  * Initial state value
245
242
  */
246
243
  state?: StateScheme;
244
+ /**
245
+ * Initial data value
246
+ */
247
+ data?: DataScheme;
247
248
  /**
248
249
  * Enable autosaves or disable
249
250
  * @default true
@@ -254,14 +255,36 @@ interface NovelyInit<Languages extends string, Characters extends Record<string,
254
255
  */
255
256
  migrations?: Migration[];
256
257
  }
257
- declare const novely: <Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends _novely_t9n.T9N<Languages, string>, StateScheme extends State>({ characters, storage, storageDelay, renderer: createRenderer, initialScreen, t9n, languages, state: defaultState, autosaves, migrations }: NovelyInit<Languages, Characters, Inter, StateScheme>) => {
258
+ declare const novely: <Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends _novely_t9n.T9N<Languages, string>, StateScheme extends State, DataScheme extends Data>({ characters, storage, storageDelay, renderer: createRenderer, initialScreen, t9n, languages, state: defaultState, data: defaultData, autosaves, migrations }: NovelyInit<Languages, Characters, Inter, StateScheme, DataScheme>) => {
259
+ /**
260
+ * Function to set story
261
+ */
258
262
  withStory: (s: Story) => void;
263
+ /**
264
+ * Function to get actions
265
+ */
259
266
  action: ActionProxyProvider<Characters>;
267
+ /**
268
+ * State that belongs to games
269
+ */
260
270
  state: {
261
271
  (value: DeepPartial<StateScheme> | ((prev: StateScheme) => StateScheme)): void;
262
272
  (): StateScheme;
263
273
  };
264
- unwrap: (content: Unwrappable) => string;
274
+ /**
275
+ * Unlike `state`, stored at global scope instead and shared between games
276
+ */
277
+ data: {
278
+ (value: DeepPartial<DataScheme> | ((prev: DataScheme) => DataScheme)): void;
279
+ (): DataScheme;
280
+ };
281
+ /**
282
+ * Unwraps translatable content to a string value
283
+ */
284
+ unwrap(content: string | ((lang: string, obj: Record<string, unknown>) => string) | Record<Languages, string>): string;
285
+ /**
286
+ * Function that is used for translation
287
+ */
265
288
  t: Inter["t"];
266
289
  };
267
290
 
@@ -159,6 +159,9 @@ var Novely = (() => {
159
159
  var isFunction = (val) => {
160
160
  return typeof val === "function";
161
161
  };
162
+ var isEmpty = (val) => {
163
+ return typeof val === "object" && !isNull(val) && Object.keys(val).length === 0;
164
+ };
162
165
  var str = (value) => {
163
166
  return String(value);
164
167
  };
@@ -307,22 +310,25 @@ var Novely = (() => {
307
310
  t9n,
308
311
  languages,
309
312
  state: defaultState,
313
+ data: defaultData,
310
314
  autosaves = true,
311
315
  migrations = []
312
316
  }) => {
313
317
  let story;
314
318
  let times = /* @__PURE__ */ new Set();
319
+ defaultData ||= {};
320
+ defaultState ||= {};
315
321
  const intime = (value) => {
316
322
  return times.add(value), value;
317
323
  };
318
324
  const withStory = (s) => {
319
325
  story = Object.fromEntries(Object.entries(s).map(([name, items]) => {
320
326
  const flat = (item) => {
321
- return item.flatMap((data) => {
322
- const type = data[0];
327
+ return item.flatMap((data2) => {
328
+ const type = data2[0];
323
329
  if (Array.isArray(type))
324
- return flat(data);
325
- return [data];
330
+ return flat(data2);
331
+ return [data2];
326
332
  });
327
333
  };
328
334
  return [name, flat(items)];
@@ -369,6 +375,7 @@ var Novely = (() => {
369
375
  };
370
376
  const initialData = {
371
377
  saves: [],
378
+ data: klona(defaultData),
372
379
  meta: [getLanguage(languages), getTypewriterSpeed()]
373
380
  };
374
381
  const $ = store(initialData);
@@ -386,6 +393,9 @@ var Novely = (() => {
386
393
  }
387
394
  stored.meta[0] ||= getLanguage(languages);
388
395
  stored.meta[1] ||= getTypewriterSpeed();
396
+ if (isEmpty(stored.data)) {
397
+ stored.data = defaultData;
398
+ }
389
399
  initialDataLoaded = true;
390
400
  $.update(() => stored);
391
401
  if (initialScreen === "game")
@@ -441,7 +451,7 @@ var Novely = (() => {
441
451
  return;
442
452
  let latest = save2 ? save2 : $.get().saves.at(-1);
443
453
  if (!latest) {
444
- $.update(() => ({ saves: [initial], meta: [getLanguage(languages), getTypewriterSpeed()] }));
454
+ $.update(() => ({ saves: [initial], data: klona(defaultData), meta: [getLanguage(languages), getTypewriterSpeed()] }));
445
455
  latest = klona(initial);
446
456
  }
447
457
  restoring = true, stack.value = latest;
@@ -668,6 +678,7 @@ var Novely = (() => {
668
678
  target.classList.remove(...classNames);
669
679
  }, timeout);
670
680
  clear(() => {
681
+ target.classList.remove(...classNames);
671
682
  clearTimeout(timeoutId);
672
683
  });
673
684
  };
@@ -676,7 +687,7 @@ var Novely = (() => {
676
687
  }), push();
677
688
  },
678
689
  text(text) {
679
- renderer.text(text.map(unwrap).join(" "), forward);
690
+ renderer.text(text.map((content) => unwrap(content)).join(" "), forward);
680
691
  },
681
692
  exit() {
682
693
  const path = stack.value[0];
@@ -726,17 +737,48 @@ var Novely = (() => {
726
737
  const interactivity = (value = false) => {
727
738
  interacted = value;
728
739
  };
729
- const unwrap = (content) => {
730
- const lang = $.get().meta[0];
731
- const data = state();
732
- const str2 = isFunction(content) ? content(lang, data) : typeof content === "object" ? content[lang] : content;
733
- return c(str2, data);
740
+ const unwrap = (content, global = false) => {
741
+ const { data: data2, meta: [lang] } = $.get();
742
+ const obj = global ? data2 : state();
743
+ const str2 = isFunction(content) ? content(lang, obj) : typeof content === "object" ? content[lang] : content;
744
+ return c(str2, obj);
734
745
  };
746
+ function data(value) {
747
+ if (!value)
748
+ return $.get().data;
749
+ const prev = $.get().data;
750
+ const val = isFunction(value) ? value(prev) : (0, import_deepmerge.all)([prev, value]);
751
+ $.update((prev2) => {
752
+ prev2.data = val;
753
+ return prev2;
754
+ });
755
+ }
735
756
  return {
757
+ /**
758
+ * Function to set story
759
+ */
736
760
  withStory,
761
+ /**
762
+ * Function to get actions
763
+ */
737
764
  action,
765
+ /**
766
+ * State that belongs to games
767
+ */
738
768
  state,
739
- unwrap,
769
+ /**
770
+ * Unlike `state`, stored at global scope instead and shared between games
771
+ */
772
+ data,
773
+ /**
774
+ * Unwraps translatable content to a string value
775
+ */
776
+ unwrap(content) {
777
+ return unwrap(content, true);
778
+ },
779
+ /**
780
+ * Function that is used for translation
781
+ */
740
782
  t: t9n.t
741
783
  };
742
784
  };
@@ -746,7 +788,7 @@ var Novely = (() => {
746
788
  return {
747
789
  async get() {
748
790
  const value = localStorage.getItem(options.key);
749
- return value ? JSON.parse(value) : { saves: [], meta: [] };
791
+ return value ? JSON.parse(value) : { saves: [], data: {}, meta: [] };
750
792
  },
751
793
  async set(data) {
752
794
  localStorage.setItem(options.key, JSON.stringify(data));
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../node_modules/.pnpm/deepmerge@4.3.1/node_modules/deepmerge/dist/cjs.js","../src/index.ts","../src/utils.ts","../src/store.ts","../src/novely.ts","../../../node_modules/.pnpm/klona@2.0.6/node_modules/klona/json/index.mjs","../src/constants.ts","../../t9n/src/lib.ts","../../t9n/src/translation.ts","../../t9n/src/translations.ts","../src/storage.ts"],"sourcesContent":["'use strict';\n\nvar isMergeableObject = function isMergeableObject(value) {\n\treturn isNonNullObject(value)\n\t\t&& !isSpecial(value)\n};\n\nfunction isNonNullObject(value) {\n\treturn !!value && typeof value === 'object'\n}\n\nfunction isSpecial(value) {\n\tvar stringValue = Object.prototype.toString.call(value);\n\n\treturn stringValue === '[object RegExp]'\n\t\t|| stringValue === '[object Date]'\n\t\t|| isReactElement(value)\n}\n\n// see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25\nvar canUseSymbol = typeof Symbol === 'function' && Symbol.for;\nvar REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7;\n\nfunction isReactElement(value) {\n\treturn value.$$typeof === REACT_ELEMENT_TYPE\n}\n\nfunction emptyTarget(val) {\n\treturn Array.isArray(val) ? [] : {}\n}\n\nfunction cloneUnlessOtherwiseSpecified(value, options) {\n\treturn (options.clone !== false && options.isMergeableObject(value))\n\t\t? deepmerge(emptyTarget(value), value, options)\n\t\t: value\n}\n\nfunction defaultArrayMerge(target, source, options) {\n\treturn target.concat(source).map(function(element) {\n\t\treturn cloneUnlessOtherwiseSpecified(element, options)\n\t})\n}\n\nfunction getMergeFunction(key, options) {\n\tif (!options.customMerge) {\n\t\treturn deepmerge\n\t}\n\tvar customMerge = options.customMerge(key);\n\treturn typeof customMerge === 'function' ? customMerge : deepmerge\n}\n\nfunction getEnumerableOwnPropertySymbols(target) {\n\treturn Object.getOwnPropertySymbols\n\t\t? Object.getOwnPropertySymbols(target).filter(function(symbol) {\n\t\t\treturn Object.propertyIsEnumerable.call(target, symbol)\n\t\t})\n\t\t: []\n}\n\nfunction getKeys(target) {\n\treturn Object.keys(target).concat(getEnumerableOwnPropertySymbols(target))\n}\n\nfunction propertyIsOnObject(object, property) {\n\ttry {\n\t\treturn property in object\n\t} catch(_) {\n\t\treturn false\n\t}\n}\n\n// Protects from prototype poisoning and unexpected merging up the prototype chain.\nfunction propertyIsUnsafe(target, key) {\n\treturn propertyIsOnObject(target, key) // Properties are safe to merge if they don't exist in the target yet,\n\t\t&& !(Object.hasOwnProperty.call(target, key) // unsafe if they exist up the prototype chain,\n\t\t\t&& Object.propertyIsEnumerable.call(target, key)) // and also unsafe if they're nonenumerable.\n}\n\nfunction mergeObject(target, source, options) {\n\tvar destination = {};\n\tif (options.isMergeableObject(target)) {\n\t\tgetKeys(target).forEach(function(key) {\n\t\t\tdestination[key] = cloneUnlessOtherwiseSpecified(target[key], options);\n\t\t});\n\t}\n\tgetKeys(source).forEach(function(key) {\n\t\tif (propertyIsUnsafe(target, key)) {\n\t\t\treturn\n\t\t}\n\n\t\tif (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) {\n\t\t\tdestination[key] = getMergeFunction(key, options)(target[key], source[key], options);\n\t\t} else {\n\t\t\tdestination[key] = cloneUnlessOtherwiseSpecified(source[key], options);\n\t\t}\n\t});\n\treturn destination\n}\n\nfunction deepmerge(target, source, options) {\n\toptions = options || {};\n\toptions.arrayMerge = options.arrayMerge || defaultArrayMerge;\n\toptions.isMergeableObject = options.isMergeableObject || isMergeableObject;\n\t// cloneUnlessOtherwiseSpecified is added to `options` so that custom arrayMerge()\n\t// implementations can use it. The caller may not replace it.\n\toptions.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified;\n\n\tvar sourceIsArray = Array.isArray(source);\n\tvar targetIsArray = Array.isArray(target);\n\tvar sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;\n\n\tif (!sourceAndTargetTypesMatch) {\n\t\treturn cloneUnlessOtherwiseSpecified(source, options)\n\t} else if (sourceIsArray) {\n\t\treturn options.arrayMerge(target, source, options)\n\t} else {\n\t\treturn mergeObject(target, source, options)\n\t}\n}\n\ndeepmerge.all = function deepmergeAll(array, options) {\n\tif (!Array.isArray(array)) {\n\t\tthrow new Error('first argument should be an array')\n\t}\n\n\treturn array.reduce(function(prev, next) {\n\t\treturn deepmerge(prev, next, options)\n\t}, {})\n};\n\nvar deepmerge_1 = deepmerge;\n\nmodule.exports = deepmerge_1;\n","export type { ValidAction, Story, ActionProxyProvider, DefaultActionProxyProvider, GetActionParameters, Unwrappable, CustomHandler, CustomHandlerGetResult, CustomHandlerGetResultDataFunction, FunctionableValue } from './action'\nexport type { Emotions, Character } from './character'\nexport type { CharacterHandle, AudioHandle, RendererStore, Renderer, RendererInit } from './renderer'\nexport type { Storage } from './storage'\nexport type { Thenable, Path, StorageData, StorageMeta, TypewriterSpeed, Lang, NovelyScreen } from './types'\nexport type { Stored } from './store'\nexport type { BaseTranslationStrings } from '@novely/t9n';\n\nexport { novely } from './novely'\nexport { localStorageStorage } from './storage'","import type { ActionProxyProvider, CustomHandler } from './action'\nimport type { Character } from './character'\nimport type { TypewriterSpeed, Thenable } from './types'\n\ntype MatchActionMap = {\n [Key in keyof ActionProxyProvider<Record<string, Character>>]: (data: Parameters<ActionProxyProvider<Record<string, Character>>[Key]>) => void;\n}\n\ntype MatchActionMapComplete = Omit<MatchActionMap, 'custom'> & {\n custom: (value: [handler: CustomHandler]) => Thenable<void>;\n}\n\nconst matchAction = <M extends MatchActionMapComplete>(values: M) => {\n return (action: keyof MatchActionMap, props: any) => {\n return values[action](props);\n }\n}\n\nconst isNumber = (val: unknown): val is number => {\n return typeof val === 'number';\n}\n\nconst isNull = (val: unknown): val is null => {\n return val === null;\n}\n\nconst isString = (val: unknown): val is string => {\n return typeof val === 'string';\n}\n\nconst isFunction = (val: unknown): val is ((...parameters: any[]) => any) => {\n return typeof val === 'function';\n}\n\nconst isCSSImage = (str: string) => {\n const startsWith = String.prototype.startsWith.bind(str);\n\n return startsWith('http') || startsWith('/') || startsWith('.') || startsWith('data');\n}\n\nconst str = (value: unknown) => {\n return String(value);\n}\n\nconst isUserRequiredAction = (action: keyof MatchActionMapComplete, meta: Parameters<MatchActionMapComplete[keyof MatchActionMapComplete]>) => {\n return action === 'custom' && meta[0] && (meta[0] as unknown as CustomHandler).requireUserAction;\n}\n\nconst getTypewriterSpeed = (): TypewriterSpeed => {\n return 'Medium'\n}\n\nconst getLanguage = (languages: string[], language = navigator.language) => {\n if (languages.includes(language)) {\n return language;\n } else if (languages.includes((language = language.substring(0, 2)))) {\n return language;\n } else if ((language = languages.find((value) => navigator.languages.includes(value))!)) {\n return language\n }\n\n /**\n * We'v checked the `en-GB` format, `en` format, and maybe any second languages, but there were no matches\n */\n return languages[0];\n}\n\n/**\n * @copyright Techlead LLC\n * @see https://learn.javascript.ru/task/throttle\n */\nconst throttle = <Fn extends ((...args: any[]) => any)>(fn: Fn, ms: number) => {\n let throttled = false, savedArgs: any, savedThis: any;\n\n function wrapper(this: any) {\n if (throttled) {\n savedArgs = arguments;\n savedThis = this;\n return;\n }\n\n fn.apply(this, arguments as unknown as any[]);\n\n throttled = true;\n\n setTimeout(function () {\n throttled = false;\n\n if (savedArgs) {\n wrapper.apply(savedThis, savedArgs);\n savedArgs = savedThis = null;\n }\n }, ms);\n }\n\n return wrapper as unknown as (...args: Parameters<Fn>) => void;\n}\n\nconst vibrate = (pattern: VibratePattern) => {\n try {\n if ('vibrate' in navigator) {\n navigator.vibrate(pattern);\n }\n } catch { }\n}\n\nconst findLastIndex = <T>(array: T[], fn: (item: T) => boolean) => {\n for (let i = array.length - 1; i > 0; i--) {\n if (fn(array[i])) {\n return i;\n }\n }\n\n return -1;\n}\n\nexport { matchAction, isNumber, isNull, isString, isCSSImage, str, isUserRequiredAction, getTypewriterSpeed, getLanguage, throttle, isFunction, vibrate, findLastIndex }","type Stored<T> = {\n subscribe: (cb: (value: T) => void) => () => void;\n update: (fn: (prev: T) => T) => void;\n get: () => T;\n}\n\nconst store = <T>(current: T, subscribers = new Set<(value: T) => void>()): Stored<T> => {\n const subscribe = (cb: (value: T) => void) => {\n subscribers.add(cb), cb(current);\n\n return () => {\n subscribers.delete(cb);\n }\n };\n\n const push = (value: T) => {\n subscribers.forEach((cb) => cb(value))\n };\n\n const update = (fn: (prev: T) => T) => {\n push((current = fn(current)));\n };\n\n const get = () => {\n return current;\n };\n\n return { subscribe, update, get } as const;\n};\n\nexport { store }\nexport type { Stored }","import type { Character } from './character';\nimport type { ActionProxyProvider, GetActionParameters, Story, ValidAction, Unwrappable, CustomHandler } from './action';\nimport type { Storage } from './storage';\nimport type { Save, State, StorageData, DeepPartial, NovelyScreen, Migration } from './types'\nimport type { Renderer, RendererInit } from './renderer'\nimport type { SetupT9N } from '@novely/t9n'\nimport { matchAction, isNumber, isNull, isString, str, isUserRequiredAction, getTypewriterSpeed, getLanguage, throttle, isFunction, vibrate, findLastIndex } from './utils';\nimport { store } from './store';\nimport { all as deepmerge } from 'deepmerge'\nimport { klona } from 'klona/json';\nimport { SKIPPED_DURING_RESTORE } from './constants';\nimport { replace as replaceT9N } from '@novely/t9n';\n\ninterface NovelyInit<Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends ReturnType<SetupT9N<Languages>>, StateScheme extends State> {\n /**\n * An array of languages supported by the game.\n */\n languages: Languages[];\n /**\n * An object containing the characters in the game.\n */\n characters: Characters;\n /**\n * An object that provides access to the game's storage system.\n */\n storage: Storage;\n /**\n * Delay loading data until Promise is resolved\n */\n storageDelay?: Promise<void>;\n /**\n * A function that returns a Renderer object used to display the game's content\n */\n renderer: (characters: RendererInit) => Renderer;\n /**\n * An optional property that specifies the initial screen to display when the game starts\n */\n initialScreen?: NovelyScreen;\n /**\n * An object containing the translation functions used in the game\n */\n t9n: Inter;\n /**\n * Initial state value\n */\n state?: StateScheme;\n /**\n * Enable autosaves or disable\n * @default true\n */\n autosaves?: boolean;\n /**\n * Migration from old saves to newer\n */\n migrations?: Migration[]\n}\n\nconst novely = <\n Languages extends string,\n Characters extends Record<string, Character<Languages>>,\n Inter extends ReturnType<SetupT9N<Languages>>,\n StateScheme extends State\n>({\n characters,\n storage,\n storageDelay = Promise.resolve(),\n renderer: createRenderer,\n initialScreen = \"mainmenu\",\n t9n,\n languages,\n state: defaultState,\n autosaves = true,\n migrations = []\n}: NovelyInit<Languages, Characters, Inter, StateScheme>) => {\n let story: Story;\n let times = new Set<number>();\n\n /**\n * Saves timestamps created in this session\n */\n const intime = (value: number) => {\n return times.add(value), value;\n }\n\n // @todo: find bug here\n const withStory = (s: Story) => {\n /**\n * Transforms `(ValidAction | ValidAction[])[]` to `ValidAction[]`\n */\n story = Object.fromEntries(Object.entries(s).map(([name, items]) => {\n const flat = (item: (ValidAction | ValidAction[])[]): ValidAction[] => {\n return item.flatMap((data) => {\n const type = data[0];\n\n /**\n * This is not just an action like `['name', ...arguments]`, but an array of actions\n */\n if (Array.isArray(type)) return flat(data as ValidAction[]);\n\n return [data as ValidAction];\n });\n };\n\n return [name, flat(items)];\n }));\n\n /**\n * When `initialScreen` is not a game, we can safely show it\n */\n if (initialScreen !== 'game') renderer.ui.showScreen(initialScreen);\n }\n\n const action = new Proxy({} as ActionProxyProvider<Characters>, {\n get(_, prop) {\n return (...props: Parameters<ActionProxyProvider<Record<string, Character>>[keyof ActionProxyProvider<Record<string, Character>>]>) => {\n return [prop, ...props];\n }\n }\n });\n\n function state(value: DeepPartial<StateScheme> | ((prev: StateScheme) => StateScheme)): void;\n function state(): StateScheme;\n function state(value?: DeepPartial<StateScheme> | ((prev: StateScheme) => StateScheme)): StateScheme | void {\n if (!value) return stack.value[1] as StateScheme | void;\n\n const prev = stack.value[1];\n const val = isFunction(value) ? value(prev as StateScheme) : deepmerge([prev, value]);\n\n stack.value[1] = val as StateScheme;\n }\n\n const getDefaultSave = (state = {}) => {\n return [[[null, 'start'], [null, 0]], state, [intime(Date.now()), 'auto']] as Save;\n }\n\n const createStack = (current: Save, stack = [current]) => {\n return {\n get value() {\n return stack.at(-1)!;\n },\n set value(value: Save) {\n stack[stack.length - 1] = value;\n },\n back() {\n if (stack.length > 1) stack.pop(), goingBack = true;\n },\n push(value: Save) {\n stack.push(value);\n },\n clear() {\n stack = [getDefaultSave(klona(defaultState))];\n }\n }\n }\n\n /**\n * 1) Novely rendered using the `initialData`, you can still start new game or `load` an empty one - this is scary, imagine losing your progress\n * 2) Actual stored data is loaded, language and etc is changed \n */\n const initialData: StorageData = {\n saves: [],\n meta: [getLanguage(languages), getTypewriterSpeed()]\n };\n\n const $ = store(initialData);\n\n let initialDataLoaded = false;\n\n const onStorageDataChange = (value: StorageData) => {\n if (initialDataLoaded) storage.set(value);\n };\n\n const throttledOnStorageDataChange = throttle(onStorageDataChange, 120);\n\n $.subscribe(throttledOnStorageDataChange);\n\n const getStoredData = () => {\n storage.get().then(stored => {\n /**\n * Migration is done only once (when game loads it's data), and then is saves the updated format\n */\n for (const migration of migrations) {\n // @ts-expect-error Types does not match between versions, that's why unknown used here, but error appers that way, but it is expected\n stored = migration(stored);\n }\n\n /**\n * Default `localStorageStorage` cannot determine preferred language, and returns empty array\n */\n stored.meta[0] ||= getLanguage(languages);\n stored.meta[1] ||= getTypewriterSpeed();\n\n /**\n * Now the next store updates will entail saving via storage.set\n */\n initialDataLoaded = true;\n\n $.update(() => stored);\n\n /**\n * When initialScreen is game, then we will load it, but after the data is loaded\n */\n if (initialScreen === 'game') restore();\n });\n }\n\n /**\n * By default this is resolved immediately, but also can be delayed.\n * I.e. storage has not loaded yet\n */\n storageDelay.then(getStoredData)\n\n const initial = getDefaultSave(klona(defaultState));\n const stack = createStack(initial);\n\n const save = (override = false, type: Save[2][1] = override ? 'auto' : 'manual') => {\n if (!initialDataLoaded) return;\n\n /**\n * When autosaves diabled just return\n */\n if (!autosaves && type === 'auto') return;\n\n const current = klona(stack.value);\n\n $.update(prev => {\n /**\n * Find latest save that were created in current session, and check if it is latest in an array\n * \n * We check if save was created in current session and it is latest in array\n * When it is not then replacing it will break logical chain\n * \n * [auto save 1]\n * [manual save 1]\n * [auto save 2] <- should not replace first auto save \n */\n const isLatest = findLastIndex(prev.saves, value => times.has(value[2][0])) === prev.saves.length - 1;\n\n /**\n * Update type and time information\n */\n current[2][0] = intime(Date.now());\n current[2][1] = type;\n\n if (!override || !isLatest) {\n prev.saves.push(current);\n\n return prev;\n }\n\n /**\n * Get latest\n */\n const latest = prev.saves.at(-1);\n\n /**\n * When that save is the same type, replace it\n */\n if (latest && latest[2][1] === type) {\n prev.saves[prev.saves.length - 1] = current;\n } else {\n prev.saves.push(current);\n }\n\n return prev;\n });\n }\n\n const newGame = () => {\n if (!initialDataLoaded) return;\n\n const save = getDefaultSave(klona(defaultState));\n\n /**\n * Initial save is automatic, and should be ignored when autosaves is turned off\n */\n if (autosaves) {\n $.update(prev => {\n return prev.saves.push(save), prev;\n });\n }\n\n restore(save);\n }\n\n /**\n * Set's the save\n */\n const set = (save: Save) => {\n stack.value = save;\n\n return restore(save);\n }\n\n let restoring = false;\n let goingBack = false;\n let interacted = false;\n\n /**\n * Визуально восстанавливает историю\n */\n const restore = async (save?: Save) => {\n if (!initialDataLoaded) return;\n\n let latest = save ? save : $.get().saves.at(-1);\n\n /**\n * Если нет сохранённой игры, то запустим ту, которая уже есть\n */\n if (!latest) {\n $.update(() => ({ saves: [initial], meta: [getLanguage(languages), getTypewriterSpeed()] }));\n\n latest = klona(initial);\n }\n\n restoring = true, stack.value = latest;\n\n /**\n * Показать экран игры\n */\n renderer.ui.showScreen('game');\n\n match('clear', [goingBack]);\n\n /**\n * Текущий элемент в истории\n */\n let current: any = story;\n /**\n * Текущий элемент `[null, int]`\n */\n let index = 0;\n\n /**\n * Число элементов `[null, int]`\n */\n const max = stack.value[0].reduce((acc, [type, val]) => {\n if (isNull(type) && isNumber(val)) return acc + 1;\n\n return acc;\n }, 0);\n\n const queue = [] as [any, any][];\n\n for (const [type, val] of stack.value[0]) {\n if (type === null) {\n if (isString(val)) {\n current = current[val];\n } else if (isNumber(val)) {\n index++;\n\n /**\n * Запустим все экшены которые идут в `[null, int]` от `0` до `int`\n */\n for (let i = 0; i < val; i++) {\n const [action, ...meta] = current[i];\n\n /**\n * Экшены, для закрытия которых пользователь должен с ними взаимодействовать\n * Также в эту группу входят экшены, которые не должны быть вызваны при восстановлении\n */\n if (SKIPPED_DURING_RESTORE.has(action) || isUserRequiredAction(action, meta)) {\n if (index === max && i === val) {\n queue.push([action, meta]);\n } else {\n continue;\n }\n }\n\n queue.push([action, meta]);\n }\n\n current = current[val];\n }\n } else if (type === 'choice') {\n current = current[val as number + 1][1];\n } else if (type === 'condition') {\n current = current[2][val];\n }\n }\n\n const indexedQueue = queue.map((value, index) => value.concat(index) as [Exclude<ValidAction[0], ValidAction>, ValidAction[1], number]);\n\n for await (const [action, meta, i] of indexedQueue) {\n if (action === 'function' || action === 'custom') {\n /**\n * Если `callOnlyLatest` - `true`\n */\n if (action === 'custom' && (meta as GetActionParameters<'Custom'>)[0].callOnlyLatest) {\n /**\n * Вычислим `latest` или нет\n */\n const next = indexedQueue.slice(i + 1);\n const notLatest = next.some(([_action, _meta]) => _meta && meta && str(_meta[0]) === str(meta[0]));\n\n if (notLatest) continue;\n }\n\n /**\n * Action может возвращать Promise. Нужно подожать его `resolve`\n */\n const result = match(action, meta);\n\n /**\n * Дождёмся окончания\n */\n if (result && 'then' in result) await result;\n } else if (action === 'showCharacter') {\n const next = indexedQueue.slice(i + 1);\n const skip = next.some(([_action, _meta]) => {\n /**\n * Проверка на возможный `undefined`\n */\n if (!_meta || !meta) return false;\n\n /**\n * Будет ли персонаж скрыт в будущем\n * Нет смысла при загрузке сохранения загружать и отрисовывать персонажа, который будет скрыт\n */\n const hidden = _action === 'hideCharacter' && _meta[0] === meta[0];\n /**\n * Не нужно запускать рендер персонажа, если после этого будет ещё один рендер этого персонажа\n * Таким образом избегаем ситуации, когда при загрузке вследствие гонки при загрузки изображений отрисовывается не последняя эмоция\n */\n const notLatest = _action === action && _meta[0] === meta[0];\n\n return hidden || notLatest;\n })\n\n if (skip) continue;\n\n match(action, meta);\n } else if (action === 'showBackground') {\n const next = indexedQueue.slice(i + 1);\n /**\n * Такая же оптимизация применяется к фонам.\n * Если фон изменится, то нет смысла устанавливать текущий\n */\n const notLatest = next.some(([_action]) => action === _action);\n\n if (notLatest) continue;\n\n match(action, meta);\n } else {\n match(action, meta);\n }\n }\n\n restoring = goingBack = false, render();\n }\n\n const refer = () => {\n let current: any = story;\n\n for (const [type, val] of stack.value[0]) {\n if (type === null) {\n current = current[val];\n } else if (type === 'choice') {\n current = current[val as number + 1][1];\n } else if (type === 'condition') {\n current = current[2][val];\n }\n }\n\n return current;\n }\n\n const exit = () => {\n const current = stack.value;\n\n stack.clear();\n renderer.ui.showScreen('mainmenu');\n\n /**\n * First two save elements and it's type\n */\n const [[first, second], , [time, type]] = current;\n\n if (type === 'auto' && first && second) {\n /**\n * Если сохранение похоже на начальное, и при этом игрок не взаимодействовал с игрой, и оно было создано в текущей сессии, то удаляем его\n */\n if (first[0] === null && first[1] === 'start' && second[0] === null && !interacted && times.has(time)) {\n $.update((prev) => {\n prev.saves = prev.saves.filter(save => save !== current);\n\n return prev;\n })\n }\n }\n\n /**\n * Reset interactive value\n */\n interactivity(false);\n /**\n * Reset session times\n */\n times.clear();\n }\n\n const back = () => {\n return stack.back(), restore(stack.value);\n }\n\n const renderer = createRenderer({\n characters,\n set,\n restore,\n save,\n newGame,\n exit,\n back,\n stack,\n languages,\n t: t9n.i,\n $\n });\n\n const match = matchAction({\n wait([time]) {\n /**\n * `restoring` может поменяться на `true` перед тем как запуститься `push` из `setTimeout`\n */\n if (!restoring) setTimeout(push, isFunction(time) ? time() : time);\n },\n showBackground([background]) {\n renderer.background(background);\n push()\n },\n playMusic([source]) {\n renderer.music(source, 'music').play();\n push()\n },\n stopMusic([source]) {\n renderer.music(source, 'music').stop();\n push()\n },\n showCharacter([character, emotion, className, style]) {\n const handle = renderer.character(character);\n\n handle.append(className, style, restoring);\n handle.withEmotion(emotion)();\n\n push()\n },\n hideCharacter([character, className, style, duration]) {\n renderer.character(character).remove(className, style, duration)(push, restoring);\n },\n dialog([character, content, emotion]) {\n /**\n * Имя персонажа, с учетом выбранного языка\n */\n const name = (() => {\n const c = character, cs = characters;\n const lang = $.get().meta[0];\n\n return c ? c in cs ? typeof cs[c].name === 'string' ? cs[c].name as string : (cs[c].name as Record<string, string>)[lang] : c : '';\n })();\n\n renderer.dialog(unwrap(content), unwrap(name), character, emotion)(forward);\n },\n function([fn]) {\n const result = fn(restoring, goingBack);\n\n if (!restoring) result ? result.then(push) : push();\n\n return result;\n },\n choice([question, ...choices]) {\n const isWithoutQuestion = Array.isArray(question);\n\n if (isWithoutQuestion) {\n /**\n * Первый элемент может быть как строкой, так и элементов выбора\n */\n choices.unshift(question as unknown as [Unwrappable, ValidAction[], () => boolean]);\n /**\n * Значит, текст не требуется\n */\n question = '';\n }\n\n const unwrapped = choices.map(([content, action, visible]) => {\n return [unwrap(content), action, visible] as [string, ValidAction[], () => boolean];\n });\n\n renderer.choices(unwrap(question), unwrapped)((selected) => {\n enmemory();\n\n /**\n * Если был вопрос, то `index` смещается на единицу назад, поэтому нужно добавить единицу\n */\n stack.value[0].push(['choice', isWithoutQuestion ? selected : selected + 1], [null, 0]), render(), interactivity(true);\n });\n },\n jump([scene]) {\n /**\n * `-1` index is used here because `clear` will run `next` that will increase index to `0`\n */\n stack.value[0] = [[null, scene], [null, -1]];\n\n match('clear', []);\n },\n clear() {\n vibrate(0);\n renderer.clear(goingBack)(push);\n },\n condition([condition]) {\n const value = condition();\n\n if (!restoring) stack.value[0].push(['condition', String(value)], [null, 0]), render();\n },\n end() {\n /**\n * Clear the Scene\n */\n match('clear', []);\n /**\n * Go to the main menu\n */\n renderer.ui.showScreen('mainmenu');\n /**\n * Reset interactive value\n */\n interactivity(false);\n /**\n * Reset session times\n */\n times.clear();\n },\n input([question, onInput, setup]) {\n renderer.input(unwrap(question), onInput, setup)(forward);\n },\n custom([handler]) {\n const result = renderer.custom(handler, goingBack, () => {\n if (!restoring && handler.requireUserAction) enmemory(), interactivity(true);\n if (!restoring) push();\n });\n\n return result;\n },\n vibrate(pattern) {\n vibrate(pattern);\n push()\n },\n next() {\n push();\n },\n animateCharacter([character, timeout, ...classes]) {\n const handler: CustomHandler = (get) => {\n const { clear } = get('@@internal-animate-character', false);\n const char = renderer.store.characters[character];\n\n /**\n * Character is not defined, maybe, `animateCharacter` was called before `showCharacter`\n */\n if (!char) return;\n\n const target = char.canvas;\n\n /**\n * Character is not found\n */\n if (!target) return;\n\n const classNames = classes.filter(className => !target.classList.contains(className));\n\n target.classList.add(...classNames);\n\n const timeoutId = setTimeout(() => {\n target.classList.remove(...classNames);\n }, timeout);\n\n clear(() => {\n /**\n * Clear timeout, because when you will game re-runs some callback might remove classes from character\n */\n clearTimeout(timeoutId);\n });\n }\n\n handler.callOnlyLatest = true;\n\n return renderer.custom(handler, goingBack, () => { }), push();\n },\n text(text) {\n renderer.text(text.map(unwrap).join(' '), forward);\n },\n exit() {\n const path = stack.value[0];\n\n for (let i = path.length - 1; i > 0; i--) {\n if (path[i][0] !== 'choice' && path[i][0] !== 'condition') continue;\n\n stack.value[0] = path.slice(0, i);\n next();\n\n break;\n }\n\n render();\n }\n });\n\n const enmemory = () => {\n if (restoring) return;\n\n const current = klona(stack.value);\n\n current[2][1] = 'auto';\n\n stack.push(current);\n\n save(true, 'auto');\n }\n\n const next = () => {\n const path = stack.value[0];\n /**\n * Последний элемент пути\n */\n const last = path[path.length - 1]!;\n\n /**\n * Если он вида `[null, int]` - увеличивает `int`\n */\n if (isNull(last[0]) && isNumber(last[1])) {\n last[1] = last[1] + 1;\n return;\n }\n\n /**\n * Иначе добавляет новое `[null int]`\n */\n path.push([null, 0]);\n }\n\n const render = () => {\n const referred = refer();\n\n if (!Array.isArray(referred)) return;\n\n const [action, ...props] = referred;\n\n match(action, props);\n }\n\n const push = () => {\n if (!restoring) next(), render();\n }\n\n const forward = () => {\n enmemory();\n push();\n interactivity(true)\n }\n\n const interactivity = (value = false) => {\n interacted = value;\n }\n\n /**\n * Unwraps translatable content to string\n * \n * @example ```\n * unwrap(t('Hello'));\n * unwrap({ en: 'Hello', ru: 'Привет' });\n * ```\n */\n const unwrap = (content: Unwrappable) => {\n const lang = $.get().meta[0];\n const data = state();\n const str = isFunction(content) ? content(lang, data) : typeof content === 'object' ? content[lang] : content;\n\n return replaceT9N(str, data);\n }\n\n return {\n withStory,\n action,\n state,\n unwrap,\n t: t9n.t as Inter['t'],\n }\n}\n\nexport { novely }\n","export function klona(val) {\n\tvar k, out, tmp;\n\n\tif (Array.isArray(val)) {\n\t\tout = Array(k=val.length);\n\t\twhile (k--) out[k] = (tmp=val[k]) && typeof tmp === 'object' ? klona(tmp) : tmp;\n\t\treturn out;\n\t}\n\n\tif (Object.prototype.toString.call(val) === '[object Object]') {\n\t\tout = {}; // null\n\t\tfor (k in val) {\n\t\t\tif (k === '__proto__') {\n\t\t\t\tObject.defineProperty(out, k, {\n\t\t\t\t\tvalue: klona(val[k]),\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tout[k] = (tmp=val[k]) && typeof tmp === 'object' ? klona(tmp) : tmp;\n\t\t\t}\n\t\t}\n\t\treturn out;\n\t}\n\n\treturn val;\n}\n","const SKIPPED_DURING_RESTORE = new Set([\n 'dialog',\n 'choice',\n 'input',\n 'vibrate',\n 'text'\n] as const);\n\nexport { SKIPPED_DURING_RESTORE }","const split = (input: string, delimeters: string[]) => {\n const output: (string | undefined)[] = [];\n\n for (const delimeter of delimeters) {\n if (!input) break;\n\n const [start, end] = input.split(delimeter, 2);\n\n output.push(start); input = end;\n }\n\n output.push(input);\n\n return output;\n}\n\nexport { split }","import type { BaseTranslationStrings } from './translations';\nimport { split } from './lib';\n\ntype PluralType = Intl.LDMLPluralRule;\ntype FunctionalSetupT9N = <LanguageKey extends string, PluralKey extends string, StringKey extends string, Actions extends string>(parameters: { [Lang in LanguageKey]: { pluralization: { [Plural in PluralKey]: Partial<Record<PluralType, string>> }; internal: { [Key in BaseTranslationStrings]: string }; strings: { [Str in StringKey]: string }; actions?: { [Action in Actions]?: (value: string) => string; } } }) => T9N<LanguageKey, StringKey>\ntype SetupT9N<LanguageKey extends string> = <PluralKey extends string, StringKey extends string, Actions extends string>(parameters: { [Lang in LanguageKey]: { pluralization: { [Plural in PluralKey]: Partial<Record<PluralType, string>> }; internal: { [Key in BaseTranslationStrings]: string }; strings: { [Str in StringKey]: string }; actions?: { [Action in Actions]?: (value: string) => string; } } }) => T9N<LanguageKey, StringKey>\n\ntype T9N<LanguageKey extends string, StringKey extends string> = {\n t(key: StringKey | Record<LanguageKey, string>): (lang: LanguageKey | (string & {}), obj: Record<string, unknown>) => string;\n i(key: StringKey, lang: LanguageKey | (string & {})): string;\n}\n\nconst RGX = /{{(.*?)}}/g;\n\nconst replace = (str: string, obj: Record<string, unknown>, pluralization?: Record<string, Record<string, PluralType>>, actions?: Partial<Record<string, (str: string) => string>>, pr?: Intl.PluralRules) => {\n return str.replace(RGX, (x: any, key: string, y: any) => {\n x = 0;\n y = obj;\n\n const [pathstr, plural, action] = split(key.trim(), ['@', '%']);\n\n let path = pathstr!.split('.');\n\n while (y && x < path.length) y = y[path[x++]];\n\n if (plural && pluralization && y && pr) {\n y = pluralization[plural][pr.select(y)];\n }\n\n const actionHandler = actions && action && actions[action];\n\n if (actionHandler) y = actionHandler(y);\n\n return y != null ? y : '';\n });\n}\n\nconst createT9N: FunctionalSetupT9N = (parameters) => {\n let locale: string | undefined;\n let pr: Intl.PluralRules | undefined;\n\n return {\n t(key) {\n return (lang, obj) => {\n /**\n * At first run `locale` and `pr` are not defined.\n * When `locale` changes, `pr` should be updated`\n */\n if (!locale || !pr || lang != locale) {\n pr = new Intl.PluralRules(locale = lang);\n }\n\n // @ts-ignore\n const str: string = typeof key === 'object' ? key[lang] : parameters[lang]['strings'][key];\n\n if (!str) return '';\n\n // @ts-ignore `(string & {})` cannot be used to index type `LanguageKey`.\n return replace(str, obj, parameters[lang]['pluralization'], parameters[lang]['actions'], pr);\n }\n },\n i(key, lang) {\n // @ts-ignore `(string & {})` cannot be used to index type `LanguageKey`.\n return parameters[lang]['internal'][key] as string;\n }\n }\n}\n\nexport { createT9N, replace }\nexport type { SetupT9N, T9N, FunctionalSetupT9N } ","const RU = {\n 'NewGame': 'Новая игра',\n 'HomeScreen': 'Главный экран',\n 'ToTheGame': 'К игре',\n 'Language': 'Язык',\n 'NoSaves': 'Сохранений нет',\n 'LoadSave': 'Загрузить',\n 'Saves': 'Сохранения',\n 'Settings': 'Настройки',\n 'Sumbit': 'Подтвердить',\n 'GoBack': 'Назад',\n 'DoSave': 'Сохранение',\n 'Auto': 'Авто',\n 'Stop': 'Стоп',\n 'Exit': 'Выход',\n 'Automatic': 'Автоматическое',\n 'Manual': 'Ручное',\n 'Remove': 'Удалить',\n 'LoadASaveFrom': 'Загрузить сохранение от',\n 'DeleteASaveFrom': 'Удалить сохранение от',\n 'TextSpeed': 'Скорость Текста',\n 'TextSpeedSlow': 'Медленная',\n 'TextSpeedMedium': 'Средняя',\n 'TextSpeedFast': 'Быстрая',\n 'TextSpeedAuto': 'Автоматическая'\n};\n\ntype BaseTranslationStrings = keyof typeof RU;\n\nconst EN: Record<BaseTranslationStrings, string> = {\n 'NewGame': 'New Game',\n 'HomeScreen': 'Home Screen',\n 'ToTheGame': 'To the Game',\n 'Language': 'Language',\n 'NoSaves': 'No saves',\n 'LoadSave': 'Load',\n 'Saves': 'Saves',\n 'Settings': 'Settings',\n 'Sumbit': 'Submit',\n 'GoBack': 'Go back',\n 'DoSave': 'Save',\n 'Auto': 'Auto',\n 'Stop': 'Stop',\n 'Exit': 'Exit',\n 'Automatic': 'Automatic',\n 'Manual': 'Manual',\n 'Remove': 'Remove',\n 'LoadASaveFrom': 'Load a save from',\n 'DeleteASaveFrom': 'Delete a save from',\n 'TextSpeed': 'Text Speed',\n 'TextSpeedSlow': 'Slow',\n 'TextSpeedMedium': 'Medium',\n 'TextSpeedFast': 'Fast',\n 'TextSpeedAuto': 'Auto'\n};\n\nexport { RU, EN }\nexport type { BaseTranslationStrings }","import type { StorageData } from './types'\n\ninterface LocalStorageStorageSettings {\n key: string\n}\n\ninterface Storage {\n get: () => Promise<StorageData>;\n set: (data: StorageData) => Promise<void>;\n}\n\nconst localStorageStorage = (options: LocalStorageStorageSettings): Storage => {\n return {\n async get() {\n const value = localStorage.getItem(options.key);\n\n return value ? JSON.parse(value) : { saves: [], meta: [] };\n },\n async set(data) {\n localStorage.setItem(options.key, JSON.stringify(data));\n }\n }\n}\n\nexport type { Storage }\nexport { localStorageStorage }"],"mappings":"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","names":["isMergeableObject","deepmerge","split","input","delimeters","output","delimeter","start","end","RGX","replace","str","obj","pluralization","actions","pr","x","key","y","pathstr","plural","action","path","actionHandler","deepmerge","state","stack","save","action","index","next","c","str"]}
1
+ {"version":3,"sources":["../../../node_modules/.pnpm/deepmerge@4.3.1/node_modules/deepmerge/dist/cjs.js","../src/index.ts","../src/utils.ts","../src/store.ts","../src/novely.ts","../../../node_modules/.pnpm/klona@2.0.6/node_modules/klona/json/index.mjs","../src/constants.ts","../../t9n/src/lib.ts","../../t9n/src/translation.ts","../../t9n/src/translations.ts","../src/storage.ts"],"sourcesContent":["'use strict';\n\nvar isMergeableObject = function isMergeableObject(value) {\n\treturn isNonNullObject(value)\n\t\t&& !isSpecial(value)\n};\n\nfunction isNonNullObject(value) {\n\treturn !!value && typeof value === 'object'\n}\n\nfunction isSpecial(value) {\n\tvar stringValue = Object.prototype.toString.call(value);\n\n\treturn stringValue === '[object RegExp]'\n\t\t|| stringValue === '[object Date]'\n\t\t|| isReactElement(value)\n}\n\n// see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25\nvar canUseSymbol = typeof Symbol === 'function' && Symbol.for;\nvar REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7;\n\nfunction isReactElement(value) {\n\treturn value.$$typeof === REACT_ELEMENT_TYPE\n}\n\nfunction emptyTarget(val) {\n\treturn Array.isArray(val) ? [] : {}\n}\n\nfunction cloneUnlessOtherwiseSpecified(value, options) {\n\treturn (options.clone !== false && options.isMergeableObject(value))\n\t\t? deepmerge(emptyTarget(value), value, options)\n\t\t: value\n}\n\nfunction defaultArrayMerge(target, source, options) {\n\treturn target.concat(source).map(function(element) {\n\t\treturn cloneUnlessOtherwiseSpecified(element, options)\n\t})\n}\n\nfunction getMergeFunction(key, options) {\n\tif (!options.customMerge) {\n\t\treturn deepmerge\n\t}\n\tvar customMerge = options.customMerge(key);\n\treturn typeof customMerge === 'function' ? customMerge : deepmerge\n}\n\nfunction getEnumerableOwnPropertySymbols(target) {\n\treturn Object.getOwnPropertySymbols\n\t\t? Object.getOwnPropertySymbols(target).filter(function(symbol) {\n\t\t\treturn Object.propertyIsEnumerable.call(target, symbol)\n\t\t})\n\t\t: []\n}\n\nfunction getKeys(target) {\n\treturn Object.keys(target).concat(getEnumerableOwnPropertySymbols(target))\n}\n\nfunction propertyIsOnObject(object, property) {\n\ttry {\n\t\treturn property in object\n\t} catch(_) {\n\t\treturn false\n\t}\n}\n\n// Protects from prototype poisoning and unexpected merging up the prototype chain.\nfunction propertyIsUnsafe(target, key) {\n\treturn propertyIsOnObject(target, key) // Properties are safe to merge if they don't exist in the target yet,\n\t\t&& !(Object.hasOwnProperty.call(target, key) // unsafe if they exist up the prototype chain,\n\t\t\t&& Object.propertyIsEnumerable.call(target, key)) // and also unsafe if they're nonenumerable.\n}\n\nfunction mergeObject(target, source, options) {\n\tvar destination = {};\n\tif (options.isMergeableObject(target)) {\n\t\tgetKeys(target).forEach(function(key) {\n\t\t\tdestination[key] = cloneUnlessOtherwiseSpecified(target[key], options);\n\t\t});\n\t}\n\tgetKeys(source).forEach(function(key) {\n\t\tif (propertyIsUnsafe(target, key)) {\n\t\t\treturn\n\t\t}\n\n\t\tif (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) {\n\t\t\tdestination[key] = getMergeFunction(key, options)(target[key], source[key], options);\n\t\t} else {\n\t\t\tdestination[key] = cloneUnlessOtherwiseSpecified(source[key], options);\n\t\t}\n\t});\n\treturn destination\n}\n\nfunction deepmerge(target, source, options) {\n\toptions = options || {};\n\toptions.arrayMerge = options.arrayMerge || defaultArrayMerge;\n\toptions.isMergeableObject = options.isMergeableObject || isMergeableObject;\n\t// cloneUnlessOtherwiseSpecified is added to `options` so that custom arrayMerge()\n\t// implementations can use it. The caller may not replace it.\n\toptions.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified;\n\n\tvar sourceIsArray = Array.isArray(source);\n\tvar targetIsArray = Array.isArray(target);\n\tvar sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;\n\n\tif (!sourceAndTargetTypesMatch) {\n\t\treturn cloneUnlessOtherwiseSpecified(source, options)\n\t} else if (sourceIsArray) {\n\t\treturn options.arrayMerge(target, source, options)\n\t} else {\n\t\treturn mergeObject(target, source, options)\n\t}\n}\n\ndeepmerge.all = function deepmergeAll(array, options) {\n\tif (!Array.isArray(array)) {\n\t\tthrow new Error('first argument should be an array')\n\t}\n\n\treturn array.reduce(function(prev, next) {\n\t\treturn deepmerge(prev, next, options)\n\t}, {})\n};\n\nvar deepmerge_1 = deepmerge;\n\nmodule.exports = deepmerge_1;\n","export type { ValidAction, Story, ActionProxyProvider, DefaultActionProxyProvider, GetActionParameters, Unwrappable, CustomHandler, CustomHandlerGetResult, CustomHandlerGetResultDataFunction, FunctionableValue } from './action'\nexport type { Emotions, Character } from './character'\nexport type { CharacterHandle, AudioHandle, RendererStore, Renderer, RendererInit } from './renderer'\nexport type { Storage } from './storage'\nexport type { Thenable, Path, StorageData, StorageMeta, TypewriterSpeed, Lang, NovelyScreen } from './types'\nexport type { Stored } from './store'\nexport type { BaseTranslationStrings } from '@novely/t9n';\n\nexport { novely } from './novely'\nexport { localStorageStorage } from './storage'","import type { ActionProxyProvider, CustomHandler } from './action'\nimport type { Character } from './character'\nimport type { TypewriterSpeed, Thenable } from './types'\n\ntype MatchActionMap = {\n [Key in keyof ActionProxyProvider<Record<string, Character>>]: (data: Parameters<ActionProxyProvider<Record<string, Character>>[Key]>) => void;\n}\n\ntype MatchActionMapComplete = Omit<MatchActionMap, 'custom'> & {\n custom: (value: [handler: CustomHandler]) => Thenable<void>;\n}\n\nconst matchAction = <M extends MatchActionMapComplete>(values: M) => {\n return (action: keyof MatchActionMap, props: any) => {\n return values[action](props);\n }\n}\n\nconst isNumber = (val: unknown): val is number => {\n return typeof val === 'number';\n}\n\nconst isNull = (val: unknown): val is null => {\n return val === null;\n}\n\nconst isString = (val: unknown): val is string => {\n return typeof val === 'string';\n}\n\nconst isFunction = (val: unknown): val is ((...parameters: any[]) => any) => {\n return typeof val === 'function';\n}\n\nconst isEmpty = (val: unknown): val is {} => {\n return typeof val === 'object' && !isNull(val) && Object.keys(val).length === 0;\n}\n\nconst isCSSImage = (str: string) => {\n const startsWith = String.prototype.startsWith.bind(str);\n\n return startsWith('http') || startsWith('/') || startsWith('.') || startsWith('data');\n}\n\nconst str = (value: unknown) => {\n return String(value);\n}\n\nconst isUserRequiredAction = (action: keyof MatchActionMapComplete, meta: Parameters<MatchActionMapComplete[keyof MatchActionMapComplete]>) => {\n return action === 'custom' && meta[0] && (meta[0] as unknown as CustomHandler).requireUserAction;\n}\n\nconst getTypewriterSpeed = (): TypewriterSpeed => {\n return 'Medium'\n}\n\nconst getLanguage = (languages: string[], language = navigator.language) => {\n if (languages.includes(language)) {\n return language;\n } else if (languages.includes((language = language.substring(0, 2)))) {\n return language;\n } else if ((language = languages.find((value) => navigator.languages.includes(value))!)) {\n return language\n }\n\n /**\n * We'v checked the `en-GB` format, `en` format, and maybe any second languages, but there were no matches\n */\n return languages[0];\n}\n\n/**\n * @copyright Techlead LLC\n * @see https://learn.javascript.ru/task/throttle\n */\nconst throttle = <Fn extends ((...args: any[]) => any)>(fn: Fn, ms: number) => {\n let throttled = false, savedArgs: any, savedThis: any;\n\n function wrapper(this: any) {\n if (throttled) {\n savedArgs = arguments;\n savedThis = this;\n return;\n }\n\n fn.apply(this, arguments as unknown as any[]);\n\n throttled = true;\n\n setTimeout(function () {\n throttled = false;\n\n if (savedArgs) {\n wrapper.apply(savedThis, savedArgs);\n savedArgs = savedThis = null;\n }\n }, ms);\n }\n\n return wrapper as unknown as (...args: Parameters<Fn>) => void;\n}\n\nconst vibrate = (pattern: VibratePattern) => {\n try {\n if ('vibrate' in navigator) {\n navigator.vibrate(pattern);\n }\n } catch { }\n}\n\nconst findLastIndex = <T>(array: T[], fn: (item: T) => boolean) => {\n for (let i = array.length - 1; i > 0; i--) {\n if (fn(array[i])) {\n return i;\n }\n }\n\n return -1;\n}\n\nexport { matchAction, isNumber, isNull, isString, isEmpty, isCSSImage, str, isUserRequiredAction, getTypewriterSpeed, getLanguage, throttle, isFunction, vibrate, findLastIndex }","type Stored<T> = {\n subscribe: (cb: (value: T) => void) => () => void;\n update: (fn: (prev: T) => T) => void;\n get: () => T;\n}\n\nconst store = <T>(current: T, subscribers = new Set<(value: T) => void>()): Stored<T> => {\n const subscribe = (cb: (value: T) => void) => {\n subscribers.add(cb), cb(current);\n\n return () => {\n subscribers.delete(cb);\n }\n };\n\n const push = (value: T) => {\n subscribers.forEach((cb) => cb(value))\n };\n\n const update = (fn: (prev: T) => T) => {\n push((current = fn(current)));\n };\n\n const get = () => {\n return current;\n };\n\n return { subscribe, update, get } as const;\n};\n\nexport { store }\nexport type { Stored }","import type { Character } from './character';\nimport type { ActionProxyProvider, GetActionParameters, Story, ValidAction, Unwrappable, CustomHandler } from './action';\nimport type { Storage } from './storage';\nimport type { Save, State, Data, StorageData, DeepPartial, NovelyScreen, Migration } from './types'\nimport type { Renderer, RendererInit } from './renderer'\nimport type { SetupT9N } from '@novely/t9n'\nimport { matchAction, isNumber, isNull, isString, isEmpty, str, isUserRequiredAction, getTypewriterSpeed, getLanguage, throttle, isFunction, vibrate, findLastIndex } from './utils';\nimport { store } from './store';\nimport { all as deepmerge } from 'deepmerge'\nimport { klona } from 'klona/json';\nimport { SKIPPED_DURING_RESTORE } from './constants';\nimport { replace as replaceT9N } from '@novely/t9n';\n\ninterface NovelyInit<Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends ReturnType<SetupT9N<Languages>>, StateScheme extends State, DataScheme extends Data> {\n /**\n * An array of languages supported by the game.\n */\n languages: Languages[];\n /**\n * An object containing the characters in the game.\n */\n characters: Characters;\n /**\n * An object that provides access to the game's storage system.\n */\n storage: Storage;\n /**\n * Delay loading data until Promise is resolved\n */\n storageDelay?: Promise<void>;\n /**\n * A function that returns a Renderer object used to display the game's content\n */\n renderer: (characters: RendererInit) => Renderer;\n /**\n * An optional property that specifies the initial screen to display when the game starts\n */\n initialScreen?: NovelyScreen;\n /**\n * An object containing the translation functions used in the game\n */\n t9n: Inter;\n /**\n * Initial state value\n */\n state?: StateScheme;\n /**\n * Initial data value\n */\n data?: DataScheme;\n /**\n * Enable autosaves or disable\n * @default true\n */\n autosaves?: boolean;\n /**\n * Migration from old saves to newer\n */\n migrations?: Migration[]\n}\n\nconst novely = <\n Languages extends string,\n Characters extends Record<string, Character<Languages>>,\n Inter extends ReturnType<SetupT9N<Languages>>,\n StateScheme extends State,\n DataScheme extends Data\n>({\n characters,\n storage,\n storageDelay = Promise.resolve(),\n renderer: createRenderer,\n initialScreen = \"mainmenu\",\n t9n,\n languages,\n state: defaultState,\n data: defaultData,\n autosaves = true,\n migrations = []\n}: NovelyInit<Languages, Characters, Inter, StateScheme, DataScheme>) => {\n let story: Story;\n let times = new Set<number>();\n\n /**\n * Prevent `undefined`\n */\n defaultData ||= {} as DataScheme;\n defaultState ||= {} as StateScheme;\n\n /**\n * Saves timestamps created in this session\n */\n const intime = (value: number) => {\n return times.add(value), value;\n }\n\n const withStory = (s: Story) => {\n /**\n * Transforms `(ValidAction | ValidAction[])[]` to `ValidAction[]`\n */\n story = Object.fromEntries(Object.entries(s).map(([name, items]) => {\n const flat = (item: (ValidAction | ValidAction[])[]): ValidAction[] => {\n return item.flatMap((data) => {\n const type = data[0];\n\n /**\n * This is not just an action like `['name', ...arguments]`, but an array of actions\n */\n if (Array.isArray(type)) return flat(data as ValidAction[]);\n\n return [data as ValidAction];\n });\n };\n\n return [name, flat(items)];\n }));\n\n /**\n * When `initialScreen` is not a game, we can safely show it\n */\n if (initialScreen !== 'game') renderer.ui.showScreen(initialScreen);\n }\n\n const action = new Proxy({} as ActionProxyProvider<Characters>, {\n get(_, prop) {\n return (...props: Parameters<ActionProxyProvider<Record<string, Character>>[keyof ActionProxyProvider<Record<string, Character>>]>) => {\n return [prop, ...props];\n }\n }\n });\n\n function state(value: DeepPartial<StateScheme> | ((prev: StateScheme) => StateScheme)): void;\n function state(): StateScheme;\n function state(value?: DeepPartial<StateScheme> | ((prev: StateScheme) => StateScheme)): StateScheme | void {\n if (!value) return stack.value[1] as StateScheme | void;\n\n const prev = stack.value[1];\n const val = isFunction(value) ? value(prev as StateScheme) : deepmerge([prev, value]);\n\n stack.value[1] = val as StateScheme;\n }\n\n const getDefaultSave = (state = {}) => {\n return [[[null, 'start'], [null, 0]], state, [intime(Date.now()), 'auto']] as Save;\n }\n\n const createStack = (current: Save, stack = [current]) => {\n return {\n get value() {\n return stack.at(-1)!;\n },\n set value(value: Save) {\n stack[stack.length - 1] = value;\n },\n back() {\n if (stack.length > 1) stack.pop(), goingBack = true;\n },\n push(value: Save) {\n stack.push(value);\n },\n clear() {\n stack = [getDefaultSave(klona(defaultState))];\n }\n }\n }\n\n /**\n * 1) Novely rendered using the `initialData`, you can still start new game or `load` an empty one - this is scary, imagine losing your progress\n * 2) Actual stored data is loaded, language and etc is changed \n */\n const initialData: StorageData = {\n saves: [],\n data: klona(defaultData) as Data,\n meta: [getLanguage(languages), getTypewriterSpeed()],\n };\n\n const $ = store(initialData);\n\n let initialDataLoaded = false;\n\n const onStorageDataChange = (value: StorageData) => {\n if (initialDataLoaded) storage.set(value);\n };\n\n const throttledOnStorageDataChange = throttle(onStorageDataChange, 120);\n\n $.subscribe(throttledOnStorageDataChange);\n\n const getStoredData = () => {\n storage.get().then(stored => {\n /**\n * Migration is done only once (when game loads it's data), and then it saves the updated format\n */\n for (const migration of migrations) {\n // @ts-expect-error Types does not match between versions\n stored = migration(stored);\n }\n\n /**\n * Default `localStorageStorage` cannot determine preferred language, and returns empty array\n */\n stored.meta[0] ||= getLanguage(languages);\n stored.meta[1] ||= getTypewriterSpeed();\n\n /**\n * When data is empty replace it with `defaultData`\n * It also might be empty (default to empty)\n */\n if (isEmpty(stored.data)) {\n stored.data = defaultData as Data;\n }\n\n /**\n * Now the next store updates will entail saving via storage.set\n */\n initialDataLoaded = true;\n\n $.update(() => stored);\n\n /**\n * When initialScreen is game, then we will load it, but after the data is loaded\n */\n if (initialScreen === 'game') restore();\n });\n }\n\n /**\n * By default this is resolved immediately, but also can be delayed.\n * I.e. storage has not loaded yet\n */\n storageDelay.then(getStoredData)\n\n const initial = getDefaultSave(klona(defaultState));\n const stack = createStack(initial);\n\n const save = (override = false, type: Save[2][1] = override ? 'auto' : 'manual') => {\n if (!initialDataLoaded) return;\n\n /**\n * When autosaves diabled just return\n */\n if (!autosaves && type === 'auto') return;\n\n const current = klona(stack.value);\n\n $.update(prev => {\n /**\n * Find latest save that were created in current session, and check if it is latest in an array\n * \n * We check if save was created in current session and it is latest in array\n * When it is not then replacing it will break logical chain\n * \n * [auto save 1]\n * [manual save 1]\n * [auto save 2] <- should not replace first auto save \n */\n const isLatest = findLastIndex(prev.saves, value => times.has(value[2][0])) === prev.saves.length - 1;\n\n /**\n * Update type and time information\n */\n current[2][0] = intime(Date.now());\n current[2][1] = type;\n\n if (!override || !isLatest) {\n prev.saves.push(current);\n\n return prev;\n }\n\n /**\n * Get latest\n */\n const latest = prev.saves.at(-1);\n\n /**\n * When that save is the same type, replace it\n */\n if (latest && latest[2][1] === type) {\n prev.saves[prev.saves.length - 1] = current;\n } else {\n prev.saves.push(current);\n }\n\n return prev;\n });\n }\n\n const newGame = () => {\n if (!initialDataLoaded) return;\n\n const save = getDefaultSave(klona(defaultState));\n\n /**\n * Initial save is automatic, and should be ignored when autosaves is turned off\n */\n if (autosaves) {\n $.update(prev => {\n return prev.saves.push(save), prev;\n });\n }\n\n restore(save);\n }\n\n /**\n * Set's the save\n */\n const set = (save: Save) => {\n stack.value = save;\n\n return restore(save);\n }\n\n let restoring = false;\n let goingBack = false;\n let interacted = false;\n\n /**\n * Restore\n */\n const restore = async (save?: Save) => {\n if (!initialDataLoaded) return;\n\n let latest = save ? save : $.get().saves.at(-1);\n\n /**\n * When there is no game, then make a new game\n */\n if (!latest) {\n $.update(() => ({ saves: [initial], data: klona(defaultData) as Data, meta: [getLanguage(languages), getTypewriterSpeed()] }));\n\n latest = klona(initial);\n }\n\n restoring = true, stack.value = latest;\n\n renderer.ui.showScreen('game');\n match('clear', [goingBack]);\n\n /**\n * Текущий элемент в истории\n */\n let current: any = story;\n /**\n * Текущий элемент `[null, int]`\n */\n let index = 0;\n\n /**\n * Число элементов `[null, int]`\n */\n const max = stack.value[0].reduce((acc, [type, val]) => {\n if (isNull(type) && isNumber(val)) return acc + 1;\n\n return acc;\n }, 0);\n\n const queue = [] as [any, any][];\n\n for (const [type, val] of stack.value[0]) {\n if (type === null) {\n if (isString(val)) {\n current = current[val];\n } else if (isNumber(val)) {\n index++;\n\n /**\n * Запустим все экшены которые идут в `[null, int]` от `0` до `int`\n */\n for (let i = 0; i < val; i++) {\n const [action, ...meta] = current[i];\n\n /**\n * Экшены, для закрытия которых пользователь должен с ними взаимодействовать\n * Также в эту группу входят экшены, которые не должны быть вызваны при восстановлении\n */\n if (SKIPPED_DURING_RESTORE.has(action) || isUserRequiredAction(action, meta)) {\n if (index === max && i === val) {\n queue.push([action, meta]);\n } else {\n continue;\n }\n }\n\n queue.push([action, meta]);\n }\n\n current = current[val];\n }\n } else if (type === 'choice') {\n current = current[val as number + 1][1];\n } else if (type === 'condition') {\n current = current[2][val];\n }\n }\n\n const indexedQueue = queue.map((value, index) => value.concat(index) as [Exclude<ValidAction[0], ValidAction>, ValidAction[1], number]);\n\n for await (const [action, meta, i] of indexedQueue) {\n if (action === 'function' || action === 'custom') {\n /**\n * Если `callOnlyLatest` - `true`\n */\n if (action === 'custom' && (meta as GetActionParameters<'Custom'>)[0].callOnlyLatest) {\n /**\n * Вычислим `latest` или нет\n */\n const next = indexedQueue.slice(i + 1);\n const notLatest = next.some(([_action, _meta]) => _meta && meta && str(_meta[0]) === str(meta[0]));\n\n if (notLatest) continue;\n }\n\n /**\n * Action может возвращать Promise. Нужно подожать его `resolve`\n */\n const result = match(action, meta);\n\n /**\n * Дождёмся окончания\n */\n if (result && 'then' in result) await result;\n } else if (action === 'showCharacter') {\n const next = indexedQueue.slice(i + 1);\n const skip = next.some(([_action, _meta]) => {\n /**\n * Проверка на возможный `undefined`\n */\n if (!_meta || !meta) return false;\n\n /**\n * Будет ли персонаж скрыт в будущем\n * Нет смысла при загрузке сохранения загружать и отрисовывать персонажа, который будет скрыт\n */\n const hidden = _action === 'hideCharacter' && _meta[0] === meta[0];\n /**\n * Не нужно запускать рендер персонажа, если после этого будет ещё один рендер этого персонажа\n * Таким образом избегаем ситуации, когда при загрузке вследствие гонки при загрузки изображений отрисовывается не последняя эмоция\n */\n const notLatest = _action === action && _meta[0] === meta[0];\n\n return hidden || notLatest;\n })\n\n if (skip) continue;\n\n match(action, meta);\n } else if (action === 'showBackground') {\n const next = indexedQueue.slice(i + 1);\n /**\n * Такая же оптимизация применяется к фонам.\n * Если фон изменится, то нет смысла устанавливать текущий\n */\n const notLatest = next.some(([_action]) => action === _action);\n\n if (notLatest) continue;\n\n match(action, meta);\n } else {\n match(action, meta);\n }\n }\n\n restoring = goingBack = false, render();\n }\n\n const refer = () => {\n let current: any = story;\n\n for (const [type, val] of stack.value[0]) {\n if (type === null) {\n current = current[val];\n } else if (type === 'choice') {\n current = current[val as number + 1][1];\n } else if (type === 'condition') {\n current = current[2][val];\n }\n }\n\n return current;\n }\n\n const exit = () => {\n const current = stack.value;\n\n stack.clear();\n renderer.ui.showScreen('mainmenu');\n\n /**\n * First two save elements and it's type\n */\n const [[first, second], , [time, type]] = current;\n\n if (type === 'auto' && first && second) {\n /**\n * Если сохранение похоже на начальное, и при этом игрок не взаимодействовал с игрой, и оно было создано в текущей сессии, то удаляем его\n */\n if (first[0] === null && first[1] === 'start' && second[0] === null && !interacted && times.has(time)) {\n $.update((prev) => {\n prev.saves = prev.saves.filter(save => save !== current);\n\n return prev;\n })\n }\n }\n\n /**\n * Reset interactive value\n */\n interactivity(false);\n /**\n * Reset session times\n */\n times.clear();\n }\n\n const back = () => {\n return stack.back(), restore(stack.value);\n }\n\n const renderer = createRenderer({\n characters,\n set,\n restore,\n save,\n newGame,\n exit,\n back,\n stack,\n languages,\n t: t9n.i,\n $\n });\n\n const match = matchAction({\n wait([time]) {\n /**\n * `restoring` может поменяться на `true` перед тем как запуститься `push` из `setTimeout`\n */\n if (!restoring) setTimeout(push, isFunction(time) ? time() : time);\n },\n showBackground([background]) {\n renderer.background(background);\n push()\n },\n playMusic([source]) {\n renderer.music(source, 'music').play();\n push()\n },\n stopMusic([source]) {\n renderer.music(source, 'music').stop();\n push()\n },\n showCharacter([character, emotion, className, style]) {\n const handle = renderer.character(character);\n\n handle.append(className, style, restoring);\n handle.withEmotion(emotion)();\n\n push()\n },\n hideCharacter([character, className, style, duration]) {\n renderer.character(character).remove(className, style, duration)(push, restoring);\n },\n dialog([character, content, emotion]) {\n /**\n * Имя персонажа, с учетом выбранного языка\n */\n const name = (() => {\n const c = character, cs = characters;\n const lang = $.get().meta[0];\n\n return c ? c in cs ? typeof cs[c].name === 'string' ? cs[c].name as string : (cs[c].name as Record<string, string>)[lang] : c : '';\n })();\n\n renderer.dialog(unwrap(content), unwrap(name), character, emotion)(forward);\n },\n function([fn]) {\n const result = fn(restoring, goingBack);\n\n if (!restoring) result ? result.then(push) : push();\n\n return result;\n },\n choice([question, ...choices]) {\n const isWithoutQuestion = Array.isArray(question);\n\n if (isWithoutQuestion) {\n /**\n * Первый элемент может быть как строкой, так и элементов выбора\n */\n choices.unshift(question as unknown as [Unwrappable, ValidAction[], () => boolean]);\n /**\n * Значит, текст не требуется\n */\n question = '';\n }\n\n const unwrapped = choices.map(([content, action, visible]) => {\n return [unwrap(content), action, visible] as [string, ValidAction[], () => boolean];\n });\n\n renderer.choices(unwrap(question), unwrapped)((selected) => {\n enmemory();\n\n /**\n * Если был вопрос, то `index` смещается на единицу назад, поэтому нужно добавить единицу\n */\n stack.value[0].push(['choice', isWithoutQuestion ? selected : selected + 1], [null, 0]), render(), interactivity(true);\n });\n },\n jump([scene]) {\n /**\n * `-1` index is used here because `clear` will run `next` that will increase index to `0`\n */\n stack.value[0] = [[null, scene], [null, -1]];\n\n match('clear', []);\n },\n clear() {\n vibrate(0);\n renderer.clear(goingBack)(push);\n },\n condition([condition]) {\n const value = condition();\n\n if (!restoring) stack.value[0].push(['condition', String(value)], [null, 0]), render();\n },\n end() {\n /**\n * Clear the Scene\n */\n match('clear', []);\n /**\n * Go to the main menu\n */\n renderer.ui.showScreen('mainmenu');\n /**\n * Reset interactive value\n */\n interactivity(false);\n /**\n * Reset session times\n */\n times.clear();\n },\n input([question, onInput, setup]) {\n renderer.input(unwrap(question), onInput, setup)(forward);\n },\n custom([handler]) {\n const result = renderer.custom(handler, goingBack, () => {\n if (!restoring && handler.requireUserAction) enmemory(), interactivity(true);\n if (!restoring) push();\n });\n\n return result;\n },\n vibrate(pattern) {\n vibrate(pattern);\n push()\n },\n next() {\n push();\n },\n animateCharacter([character, timeout, ...classes]) {\n const handler: CustomHandler = (get) => {\n const { clear } = get('@@internal-animate-character', false);\n const char = renderer.store.characters[character];\n\n /**\n * Character is not defined, maybe, `animateCharacter` was called before `showCharacter`\n */\n if (!char) return;\n\n const target = char.canvas;\n\n /**\n * Character is not found\n */\n if (!target) return;\n\n const classNames = classes.filter(className => !target.classList.contains(className));\n\n target.classList.add(...classNames);\n\n const timeoutId = setTimeout(() => {\n target.classList.remove(...classNames);\n }, timeout);\n\n clear(() => {\n target.classList.remove(...classNames);\n \n /**\n * Clear timeout, because when you will game re-runs some callback might remove classes from character\n */\n clearTimeout(timeoutId);\n });\n }\n\n handler.callOnlyLatest = true;\n\n return renderer.custom(handler, goingBack, () => { }), push();\n },\n text(text) {\n renderer.text(text.map((content) => unwrap(content)).join(' '), forward);\n },\n exit() {\n const path = stack.value[0];\n\n for (let i = path.length - 1; i > 0; i--) {\n if (path[i][0] !== 'choice' && path[i][0] !== 'condition') continue;\n\n stack.value[0] = path.slice(0, i);\n next();\n\n break;\n }\n\n render();\n }\n });\n\n const enmemory = () => {\n if (restoring) return;\n\n const current = klona(stack.value);\n\n current[2][1] = 'auto';\n\n stack.push(current);\n\n save(true, 'auto');\n }\n\n const next = () => {\n const path = stack.value[0];\n /**\n * Последний элемент пути\n */\n const last = path[path.length - 1]!;\n\n /**\n * Если он вида `[null, int]` - увеличивает `int`\n */\n if (isNull(last[0]) && isNumber(last[1])) {\n last[1] = last[1] + 1;\n return;\n }\n\n /**\n * Иначе добавляет новое `[null int]`\n */\n path.push([null, 0]);\n }\n\n const render = () => {\n const referred = refer();\n\n if (!Array.isArray(referred)) return;\n\n const [action, ...props] = referred;\n\n match(action, props);\n }\n\n const push = () => {\n if (!restoring) next(), render();\n }\n\n const forward = () => {\n enmemory();\n push();\n interactivity(true)\n }\n\n const interactivity = (value = false) => {\n interacted = value;\n }\n\n /**\n * Unwraps translatable content to string\n * \n * @example ```\n * unwrap(t('Hello'));\n * unwrap({ en: 'Hello', ru: 'Привет' });\n * unwrap('Hello, {{name}}');\n * ```\n */\n const unwrap = (content: Unwrappable, global = false) => {\n const { data, meta: [lang] } = $.get();\n\n const obj = global ? data : state();\n const str = isFunction(content)\n ? content(lang, obj)\n : typeof content === 'object'\n ? content[lang]\n : content;\n \n return replaceT9N(str, obj);\n }\n\n function data(value: DeepPartial<DataScheme> | ((prev: DataScheme) => DataScheme)): void;\n function data(): DataScheme;\n function data(value?: DeepPartial<DataScheme> | ((prev: DataScheme) => DataScheme)): DataScheme | void {\n if (!value) return $.get().data as DataScheme | void;\n\n const prev = $.get().data;\n const val = isFunction(value) ? value(prev as DataScheme) : deepmerge([prev, value]);\n\n $.update((prev) => {\n prev.data = val;\n\n return prev;\n });\n }\n\n return {\n /**\n * Function to set story\n */\n withStory,\n /**\n * Function to get actions\n */\n action,\n /**\n * State that belongs to games\n */\n state,\n /**\n * Unlike `state`, stored at global scope instead and shared between games\n */\n data,\n /**\n * Unwraps translatable content to a string value\n */\n unwrap(content: Exclude<Unwrappable, Record<string, string>> | Record<Languages, string>) {\n return unwrap(content, true);\n },\n /**\n * Function that is used for translation\n */\n t: t9n.t as Inter['t'],\n }\n}\n\nexport { novely }\n","export function klona(val) {\n\tvar k, out, tmp;\n\n\tif (Array.isArray(val)) {\n\t\tout = Array(k=val.length);\n\t\twhile (k--) out[k] = (tmp=val[k]) && typeof tmp === 'object' ? klona(tmp) : tmp;\n\t\treturn out;\n\t}\n\n\tif (Object.prototype.toString.call(val) === '[object Object]') {\n\t\tout = {}; // null\n\t\tfor (k in val) {\n\t\t\tif (k === '__proto__') {\n\t\t\t\tObject.defineProperty(out, k, {\n\t\t\t\t\tvalue: klona(val[k]),\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tout[k] = (tmp=val[k]) && typeof tmp === 'object' ? klona(tmp) : tmp;\n\t\t\t}\n\t\t}\n\t\treturn out;\n\t}\n\n\treturn val;\n}\n","const SKIPPED_DURING_RESTORE = new Set([\n 'dialog',\n 'choice',\n 'input',\n 'vibrate',\n 'text'\n] as const);\n\nexport { SKIPPED_DURING_RESTORE }","const split = (input: string, delimeters: string[]) => {\n const output: (string | undefined)[] = [];\n\n for (const delimeter of delimeters) {\n if (!input) break;\n\n const [start, end] = input.split(delimeter, 2);\n\n output.push(start); input = end;\n }\n\n output.push(input);\n\n return output;\n}\n\nexport { split }","import type { BaseTranslationStrings } from './translations';\nimport { split } from './lib';\n\ntype PluralType = Intl.LDMLPluralRule;\ntype FunctionalSetupT9N = <LanguageKey extends string, PluralKey extends string, StringKey extends string, Actions extends string>(parameters: { [Lang in LanguageKey]: { pluralization: { [Plural in PluralKey]: Partial<Record<PluralType, string>> }; internal: { [Key in BaseTranslationStrings]: string }; strings: { [Str in StringKey]: string }; actions?: { [Action in Actions]?: (value: string) => string; } } }) => T9N<LanguageKey, StringKey>\ntype SetupT9N<LanguageKey extends string> = <PluralKey extends string, StringKey extends string, Actions extends string>(parameters: { [Lang in LanguageKey]: { pluralization: { [Plural in PluralKey]: Partial<Record<PluralType, string>> }; internal: { [Key in BaseTranslationStrings]: string }; strings: { [Str in StringKey]: string }; actions?: { [Action in Actions]?: (value: string) => string; } } }) => T9N<LanguageKey, StringKey>\n\ntype T9N<LanguageKey extends string, StringKey extends string> = {\n t(key: StringKey | Record<LanguageKey, string>): (lang: LanguageKey | (string & {}), obj: Record<string, unknown>) => string;\n i(key: StringKey, lang: LanguageKey | (string & {})): string;\n}\n\nconst RGX = /{{(.*?)}}/g;\n\nconst replace = (str: string, obj: Record<string, unknown>, pluralization?: Record<string, Record<string, PluralType>>, actions?: Partial<Record<string, (str: string) => string>>, pr?: Intl.PluralRules) => {\n return str.replace(RGX, (x: any, key: string, y: any) => {\n x = 0;\n y = obj;\n\n const [pathstr, plural, action] = split(key.trim(), ['@', '%']);\n\n let path = pathstr!.split('.');\n\n while (y && x < path.length) y = y[path[x++]];\n\n if (plural && pluralization && y && pr) {\n y = pluralization[plural][pr.select(y)];\n }\n\n const actionHandler = actions && action && actions[action];\n\n if (actionHandler) y = actionHandler(y);\n\n return y != null ? y : '';\n });\n}\n\nconst createT9N: FunctionalSetupT9N = (parameters) => {\n let locale: string | undefined;\n let pr: Intl.PluralRules | undefined;\n\n return {\n t(key) {\n return (lang, obj) => {\n /**\n * At first run `locale` and `pr` are not defined.\n * When `locale` changes, `pr` should be updated`\n */\n if (!locale || !pr || lang != locale) {\n pr = new Intl.PluralRules(locale = lang);\n }\n\n // @ts-ignore\n const str: string | string[] = typeof key === 'object' ? key[lang] : parameters[lang]['strings'][key];\n\n if (!str) return '';\n\n // @ts-ignore `(string & {})` cannot be used to index type `LanguageKey`.\n return replace(Array.isArray(str) ? str.join('') : str, obj, parameters[lang]['pluralization'], parameters[lang]['actions'], pr);\n }\n },\n i(key, lang) {\n // @ts-ignore `(string & {})` cannot be used to index type `LanguageKey`.\n return parameters[lang]['internal'][key] as string;\n }\n }\n}\n\nexport { createT9N, replace }\nexport type { SetupT9N, T9N, FunctionalSetupT9N } ","const RU = {\n 'NewGame': 'Новая игра',\n 'HomeScreen': 'Главный экран',\n 'ToTheGame': 'К игре',\n 'Language': 'Язык',\n 'NoSaves': 'Сохранений нет',\n 'LoadSave': 'Загрузить',\n 'Saves': 'Сохранения',\n 'Settings': 'Настройки',\n 'Sumbit': 'Подтвердить',\n 'GoBack': 'Назад',\n 'DoSave': 'Сохранение',\n 'Auto': 'Авто',\n 'Stop': 'Стоп',\n 'Exit': 'Выход',\n 'Automatic': 'Автоматическое',\n 'Manual': 'Ручное',\n 'Remove': 'Удалить',\n 'LoadASaveFrom': 'Загрузить сохранение от',\n 'DeleteASaveFrom': 'Удалить сохранение от',\n 'TextSpeed': 'Скорость Текста',\n 'TextSpeedSlow': 'Медленная',\n 'TextSpeedMedium': 'Средняя',\n 'TextSpeedFast': 'Быстрая',\n 'TextSpeedAuto': 'Автоматическая'\n};\n\ntype BaseTranslationStrings = keyof typeof RU;\n\nconst EN: Record<BaseTranslationStrings, string> = {\n 'NewGame': 'New Game',\n 'HomeScreen': 'Home Screen',\n 'ToTheGame': 'To the Game',\n 'Language': 'Language',\n 'NoSaves': 'No saves',\n 'LoadSave': 'Load',\n 'Saves': 'Saves',\n 'Settings': 'Settings',\n 'Sumbit': 'Submit',\n 'GoBack': 'Go back',\n 'DoSave': 'Save',\n 'Auto': 'Auto',\n 'Stop': 'Stop',\n 'Exit': 'Exit',\n 'Automatic': 'Automatic',\n 'Manual': 'Manual',\n 'Remove': 'Remove',\n 'LoadASaveFrom': 'Load a save from',\n 'DeleteASaveFrom': 'Delete a save from',\n 'TextSpeed': 'Text Speed',\n 'TextSpeedSlow': 'Slow',\n 'TextSpeedMedium': 'Medium',\n 'TextSpeedFast': 'Fast',\n 'TextSpeedAuto': 'Auto'\n};\n\nexport { RU, EN }\nexport type { BaseTranslationStrings }","import type { StorageData } from './types'\n\ninterface LocalStorageStorageSettings {\n key: string\n}\n\ninterface Storage {\n get: () => Promise<StorageData>;\n set: (data: StorageData) => Promise<void>;\n}\n\nconst localStorageStorage = (options: LocalStorageStorageSettings): Storage => {\n return {\n async get() {\n const value = localStorage.getItem(options.key);\n\n return value ? JSON.parse(value) : { saves: [], data: {}, meta: [] };\n },\n async set(data) {\n localStorage.setItem(options.key, JSON.stringify(data));\n }\n }\n}\n\nexport type { Storage }\nexport { localStorageStorage }"],"mappings":"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","names":["isMergeableObject","deepmerge","split","input","delimeters","output","delimeter","start","end","RGX","replace","str","obj","pluralization","actions","pr","x","key","y","pathstr","plural","action","path","actionHandler","data","deepmerge","state","stack","save","action","index","next","c","str","prev"]}
package/dist/index.js CHANGED
@@ -16,6 +16,9 @@ var isString = (val) => {
16
16
  var isFunction = (val) => {
17
17
  return typeof val === "function";
18
18
  };
19
+ var isEmpty = (val) => {
20
+ return typeof val === "object" && !isNull(val) && Object.keys(val).length === 0;
21
+ };
19
22
  var str = (value) => {
20
23
  return String(value);
21
24
  };
@@ -116,22 +119,25 @@ var novely = ({
116
119
  t9n,
117
120
  languages,
118
121
  state: defaultState,
122
+ data: defaultData,
119
123
  autosaves = true,
120
124
  migrations = []
121
125
  }) => {
122
126
  let story;
123
127
  let times = /* @__PURE__ */ new Set();
128
+ defaultData ||= {};
129
+ defaultState ||= {};
124
130
  const intime = (value) => {
125
131
  return times.add(value), value;
126
132
  };
127
133
  const withStory = (s) => {
128
134
  story = Object.fromEntries(Object.entries(s).map(([name, items]) => {
129
135
  const flat = (item) => {
130
- return item.flatMap((data) => {
131
- const type = data[0];
136
+ return item.flatMap((data2) => {
137
+ const type = data2[0];
132
138
  if (Array.isArray(type))
133
- return flat(data);
134
- return [data];
139
+ return flat(data2);
140
+ return [data2];
135
141
  });
136
142
  };
137
143
  return [name, flat(items)];
@@ -178,6 +184,7 @@ var novely = ({
178
184
  };
179
185
  const initialData = {
180
186
  saves: [],
187
+ data: klona(defaultData),
181
188
  meta: [getLanguage(languages), getTypewriterSpeed()]
182
189
  };
183
190
  const $ = store(initialData);
@@ -195,6 +202,9 @@ var novely = ({
195
202
  }
196
203
  stored.meta[0] ||= getLanguage(languages);
197
204
  stored.meta[1] ||= getTypewriterSpeed();
205
+ if (isEmpty(stored.data)) {
206
+ stored.data = defaultData;
207
+ }
198
208
  initialDataLoaded = true;
199
209
  $.update(() => stored);
200
210
  if (initialScreen === "game")
@@ -250,7 +260,7 @@ var novely = ({
250
260
  return;
251
261
  let latest = save2 ? save2 : $.get().saves.at(-1);
252
262
  if (!latest) {
253
- $.update(() => ({ saves: [initial], meta: [getLanguage(languages), getTypewriterSpeed()] }));
263
+ $.update(() => ({ saves: [initial], data: klona(defaultData), meta: [getLanguage(languages), getTypewriterSpeed()] }));
254
264
  latest = klona(initial);
255
265
  }
256
266
  restoring = true, stack.value = latest;
@@ -477,6 +487,7 @@ var novely = ({
477
487
  target.classList.remove(...classNames);
478
488
  }, timeout);
479
489
  clear(() => {
490
+ target.classList.remove(...classNames);
480
491
  clearTimeout(timeoutId);
481
492
  });
482
493
  };
@@ -485,7 +496,7 @@ var novely = ({
485
496
  }), push();
486
497
  },
487
498
  text(text) {
488
- renderer.text(text.map(unwrap).join(" "), forward);
499
+ renderer.text(text.map((content) => unwrap(content)).join(" "), forward);
489
500
  },
490
501
  exit() {
491
502
  const path = stack.value[0];
@@ -535,17 +546,48 @@ var novely = ({
535
546
  const interactivity = (value = false) => {
536
547
  interacted = value;
537
548
  };
538
- const unwrap = (content) => {
539
- const lang = $.get().meta[0];
540
- const data = state();
541
- const str2 = isFunction(content) ? content(lang, data) : typeof content === "object" ? content[lang] : content;
542
- return replaceT9N(str2, data);
549
+ const unwrap = (content, global = false) => {
550
+ const { data: data2, meta: [lang] } = $.get();
551
+ const obj = global ? data2 : state();
552
+ const str2 = isFunction(content) ? content(lang, obj) : typeof content === "object" ? content[lang] : content;
553
+ return replaceT9N(str2, obj);
543
554
  };
555
+ function data(value) {
556
+ if (!value)
557
+ return $.get().data;
558
+ const prev = $.get().data;
559
+ const val = isFunction(value) ? value(prev) : deepmerge([prev, value]);
560
+ $.update((prev2) => {
561
+ prev2.data = val;
562
+ return prev2;
563
+ });
564
+ }
544
565
  return {
566
+ /**
567
+ * Function to set story
568
+ */
545
569
  withStory,
570
+ /**
571
+ * Function to get actions
572
+ */
546
573
  action,
574
+ /**
575
+ * State that belongs to games
576
+ */
547
577
  state,
548
- unwrap,
578
+ /**
579
+ * Unlike `state`, stored at global scope instead and shared between games
580
+ */
581
+ data,
582
+ /**
583
+ * Unwraps translatable content to a string value
584
+ */
585
+ unwrap(content) {
586
+ return unwrap(content, true);
587
+ },
588
+ /**
589
+ * Function that is used for translation
590
+ */
549
591
  t: t9n.t
550
592
  };
551
593
  };
@@ -555,7 +597,7 @@ var localStorageStorage = (options) => {
555
597
  return {
556
598
  async get() {
557
599
  const value = localStorage.getItem(options.key);
558
- return value ? JSON.parse(value) : { saves: [], meta: [] };
600
+ return value ? JSON.parse(value) : { saves: [], data: {}, meta: [] };
559
601
  },
560
602
  async set(data) {
561
603
  localStorage.setItem(options.key, JSON.stringify(data));
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils.ts","../src/store.ts","../src/novely.ts","../src/constants.ts","../src/storage.ts"],"sourcesContent":["import type { ActionProxyProvider, CustomHandler } from './action'\nimport type { Character } from './character'\nimport type { TypewriterSpeed, Thenable } from './types'\n\ntype MatchActionMap = {\n [Key in keyof ActionProxyProvider<Record<string, Character>>]: (data: Parameters<ActionProxyProvider<Record<string, Character>>[Key]>) => void;\n}\n\ntype MatchActionMapComplete = Omit<MatchActionMap, 'custom'> & {\n custom: (value: [handler: CustomHandler]) => Thenable<void>;\n}\n\nconst matchAction = <M extends MatchActionMapComplete>(values: M) => {\n return (action: keyof MatchActionMap, props: any) => {\n return values[action](props);\n }\n}\n\nconst isNumber = (val: unknown): val is number => {\n return typeof val === 'number';\n}\n\nconst isNull = (val: unknown): val is null => {\n return val === null;\n}\n\nconst isString = (val: unknown): val is string => {\n return typeof val === 'string';\n}\n\nconst isFunction = (val: unknown): val is ((...parameters: any[]) => any) => {\n return typeof val === 'function';\n}\n\nconst isCSSImage = (str: string) => {\n const startsWith = String.prototype.startsWith.bind(str);\n\n return startsWith('http') || startsWith('/') || startsWith('.') || startsWith('data');\n}\n\nconst str = (value: unknown) => {\n return String(value);\n}\n\nconst isUserRequiredAction = (action: keyof MatchActionMapComplete, meta: Parameters<MatchActionMapComplete[keyof MatchActionMapComplete]>) => {\n return action === 'custom' && meta[0] && (meta[0] as unknown as CustomHandler).requireUserAction;\n}\n\nconst getTypewriterSpeed = (): TypewriterSpeed => {\n return 'Medium'\n}\n\nconst getLanguage = (languages: string[], language = navigator.language) => {\n if (languages.includes(language)) {\n return language;\n } else if (languages.includes((language = language.substring(0, 2)))) {\n return language;\n } else if ((language = languages.find((value) => navigator.languages.includes(value))!)) {\n return language\n }\n\n /**\n * We'v checked the `en-GB` format, `en` format, and maybe any second languages, but there were no matches\n */\n return languages[0];\n}\n\n/**\n * @copyright Techlead LLC\n * @see https://learn.javascript.ru/task/throttle\n */\nconst throttle = <Fn extends ((...args: any[]) => any)>(fn: Fn, ms: number) => {\n let throttled = false, savedArgs: any, savedThis: any;\n\n function wrapper(this: any) {\n if (throttled) {\n savedArgs = arguments;\n savedThis = this;\n return;\n }\n\n fn.apply(this, arguments as unknown as any[]);\n\n throttled = true;\n\n setTimeout(function () {\n throttled = false;\n\n if (savedArgs) {\n wrapper.apply(savedThis, savedArgs);\n savedArgs = savedThis = null;\n }\n }, ms);\n }\n\n return wrapper as unknown as (...args: Parameters<Fn>) => void;\n}\n\nconst vibrate = (pattern: VibratePattern) => {\n try {\n if ('vibrate' in navigator) {\n navigator.vibrate(pattern);\n }\n } catch { }\n}\n\nconst findLastIndex = <T>(array: T[], fn: (item: T) => boolean) => {\n for (let i = array.length - 1; i > 0; i--) {\n if (fn(array[i])) {\n return i;\n }\n }\n\n return -1;\n}\n\nexport { matchAction, isNumber, isNull, isString, isCSSImage, str, isUserRequiredAction, getTypewriterSpeed, getLanguage, throttle, isFunction, vibrate, findLastIndex }","type Stored<T> = {\n subscribe: (cb: (value: T) => void) => () => void;\n update: (fn: (prev: T) => T) => void;\n get: () => T;\n}\n\nconst store = <T>(current: T, subscribers = new Set<(value: T) => void>()): Stored<T> => {\n const subscribe = (cb: (value: T) => void) => {\n subscribers.add(cb), cb(current);\n\n return () => {\n subscribers.delete(cb);\n }\n };\n\n const push = (value: T) => {\n subscribers.forEach((cb) => cb(value))\n };\n\n const update = (fn: (prev: T) => T) => {\n push((current = fn(current)));\n };\n\n const get = () => {\n return current;\n };\n\n return { subscribe, update, get } as const;\n};\n\nexport { store }\nexport type { Stored }","import type { Character } from './character';\nimport type { ActionProxyProvider, GetActionParameters, Story, ValidAction, Unwrappable, CustomHandler } from './action';\nimport type { Storage } from './storage';\nimport type { Save, State, StorageData, DeepPartial, NovelyScreen, Migration } from './types'\nimport type { Renderer, RendererInit } from './renderer'\nimport type { SetupT9N } from '@novely/t9n'\nimport { matchAction, isNumber, isNull, isString, str, isUserRequiredAction, getTypewriterSpeed, getLanguage, throttle, isFunction, vibrate, findLastIndex } from './utils';\nimport { store } from './store';\nimport { all as deepmerge } from 'deepmerge'\nimport { klona } from 'klona/json';\nimport { SKIPPED_DURING_RESTORE } from './constants';\nimport { replace as replaceT9N } from '@novely/t9n';\n\ninterface NovelyInit<Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends ReturnType<SetupT9N<Languages>>, StateScheme extends State> {\n /**\n * An array of languages supported by the game.\n */\n languages: Languages[];\n /**\n * An object containing the characters in the game.\n */\n characters: Characters;\n /**\n * An object that provides access to the game's storage system.\n */\n storage: Storage;\n /**\n * Delay loading data until Promise is resolved\n */\n storageDelay?: Promise<void>;\n /**\n * A function that returns a Renderer object used to display the game's content\n */\n renderer: (characters: RendererInit) => Renderer;\n /**\n * An optional property that specifies the initial screen to display when the game starts\n */\n initialScreen?: NovelyScreen;\n /**\n * An object containing the translation functions used in the game\n */\n t9n: Inter;\n /**\n * Initial state value\n */\n state?: StateScheme;\n /**\n * Enable autosaves or disable\n * @default true\n */\n autosaves?: boolean;\n /**\n * Migration from old saves to newer\n */\n migrations?: Migration[]\n}\n\nconst novely = <\n Languages extends string,\n Characters extends Record<string, Character<Languages>>,\n Inter extends ReturnType<SetupT9N<Languages>>,\n StateScheme extends State\n>({\n characters,\n storage,\n storageDelay = Promise.resolve(),\n renderer: createRenderer,\n initialScreen = \"mainmenu\",\n t9n,\n languages,\n state: defaultState,\n autosaves = true,\n migrations = []\n}: NovelyInit<Languages, Characters, Inter, StateScheme>) => {\n let story: Story;\n let times = new Set<number>();\n\n /**\n * Saves timestamps created in this session\n */\n const intime = (value: number) => {\n return times.add(value), value;\n }\n\n // @todo: find bug here\n const withStory = (s: Story) => {\n /**\n * Transforms `(ValidAction | ValidAction[])[]` to `ValidAction[]`\n */\n story = Object.fromEntries(Object.entries(s).map(([name, items]) => {\n const flat = (item: (ValidAction | ValidAction[])[]): ValidAction[] => {\n return item.flatMap((data) => {\n const type = data[0];\n\n /**\n * This is not just an action like `['name', ...arguments]`, but an array of actions\n */\n if (Array.isArray(type)) return flat(data as ValidAction[]);\n\n return [data as ValidAction];\n });\n };\n\n return [name, flat(items)];\n }));\n\n /**\n * When `initialScreen` is not a game, we can safely show it\n */\n if (initialScreen !== 'game') renderer.ui.showScreen(initialScreen);\n }\n\n const action = new Proxy({} as ActionProxyProvider<Characters>, {\n get(_, prop) {\n return (...props: Parameters<ActionProxyProvider<Record<string, Character>>[keyof ActionProxyProvider<Record<string, Character>>]>) => {\n return [prop, ...props];\n }\n }\n });\n\n function state(value: DeepPartial<StateScheme> | ((prev: StateScheme) => StateScheme)): void;\n function state(): StateScheme;\n function state(value?: DeepPartial<StateScheme> | ((prev: StateScheme) => StateScheme)): StateScheme | void {\n if (!value) return stack.value[1] as StateScheme | void;\n\n const prev = stack.value[1];\n const val = isFunction(value) ? value(prev as StateScheme) : deepmerge([prev, value]);\n\n stack.value[1] = val as StateScheme;\n }\n\n const getDefaultSave = (state = {}) => {\n return [[[null, 'start'], [null, 0]], state, [intime(Date.now()), 'auto']] as Save;\n }\n\n const createStack = (current: Save, stack = [current]) => {\n return {\n get value() {\n return stack.at(-1)!;\n },\n set value(value: Save) {\n stack[stack.length - 1] = value;\n },\n back() {\n if (stack.length > 1) stack.pop(), goingBack = true;\n },\n push(value: Save) {\n stack.push(value);\n },\n clear() {\n stack = [getDefaultSave(klona(defaultState))];\n }\n }\n }\n\n /**\n * 1) Novely rendered using the `initialData`, you can still start new game or `load` an empty one - this is scary, imagine losing your progress\n * 2) Actual stored data is loaded, language and etc is changed \n */\n const initialData: StorageData = {\n saves: [],\n meta: [getLanguage(languages), getTypewriterSpeed()]\n };\n\n const $ = store(initialData);\n\n let initialDataLoaded = false;\n\n const onStorageDataChange = (value: StorageData) => {\n if (initialDataLoaded) storage.set(value);\n };\n\n const throttledOnStorageDataChange = throttle(onStorageDataChange, 120);\n\n $.subscribe(throttledOnStorageDataChange);\n\n const getStoredData = () => {\n storage.get().then(stored => {\n /**\n * Migration is done only once (when game loads it's data), and then is saves the updated format\n */\n for (const migration of migrations) {\n // @ts-expect-error Types does not match between versions, that's why unknown used here, but error appers that way, but it is expected\n stored = migration(stored);\n }\n\n /**\n * Default `localStorageStorage` cannot determine preferred language, and returns empty array\n */\n stored.meta[0] ||= getLanguage(languages);\n stored.meta[1] ||= getTypewriterSpeed();\n\n /**\n * Now the next store updates will entail saving via storage.set\n */\n initialDataLoaded = true;\n\n $.update(() => stored);\n\n /**\n * When initialScreen is game, then we will load it, but after the data is loaded\n */\n if (initialScreen === 'game') restore();\n });\n }\n\n /**\n * By default this is resolved immediately, but also can be delayed.\n * I.e. storage has not loaded yet\n */\n storageDelay.then(getStoredData)\n\n const initial = getDefaultSave(klona(defaultState));\n const stack = createStack(initial);\n\n const save = (override = false, type: Save[2][1] = override ? 'auto' : 'manual') => {\n if (!initialDataLoaded) return;\n\n /**\n * When autosaves diabled just return\n */\n if (!autosaves && type === 'auto') return;\n\n const current = klona(stack.value);\n\n $.update(prev => {\n /**\n * Find latest save that were created in current session, and check if it is latest in an array\n * \n * We check if save was created in current session and it is latest in array\n * When it is not then replacing it will break logical chain\n * \n * [auto save 1]\n * [manual save 1]\n * [auto save 2] <- should not replace first auto save \n */\n const isLatest = findLastIndex(prev.saves, value => times.has(value[2][0])) === prev.saves.length - 1;\n\n /**\n * Update type and time information\n */\n current[2][0] = intime(Date.now());\n current[2][1] = type;\n\n if (!override || !isLatest) {\n prev.saves.push(current);\n\n return prev;\n }\n\n /**\n * Get latest\n */\n const latest = prev.saves.at(-1);\n\n /**\n * When that save is the same type, replace it\n */\n if (latest && latest[2][1] === type) {\n prev.saves[prev.saves.length - 1] = current;\n } else {\n prev.saves.push(current);\n }\n\n return prev;\n });\n }\n\n const newGame = () => {\n if (!initialDataLoaded) return;\n\n const save = getDefaultSave(klona(defaultState));\n\n /**\n * Initial save is automatic, and should be ignored when autosaves is turned off\n */\n if (autosaves) {\n $.update(prev => {\n return prev.saves.push(save), prev;\n });\n }\n\n restore(save);\n }\n\n /**\n * Set's the save\n */\n const set = (save: Save) => {\n stack.value = save;\n\n return restore(save);\n }\n\n let restoring = false;\n let goingBack = false;\n let interacted = false;\n\n /**\n * Визуально восстанавливает историю\n */\n const restore = async (save?: Save) => {\n if (!initialDataLoaded) return;\n\n let latest = save ? save : $.get().saves.at(-1);\n\n /**\n * Если нет сохранённой игры, то запустим ту, которая уже есть\n */\n if (!latest) {\n $.update(() => ({ saves: [initial], meta: [getLanguage(languages), getTypewriterSpeed()] }));\n\n latest = klona(initial);\n }\n\n restoring = true, stack.value = latest;\n\n /**\n * Показать экран игры\n */\n renderer.ui.showScreen('game');\n\n match('clear', [goingBack]);\n\n /**\n * Текущий элемент в истории\n */\n let current: any = story;\n /**\n * Текущий элемент `[null, int]`\n */\n let index = 0;\n\n /**\n * Число элементов `[null, int]`\n */\n const max = stack.value[0].reduce((acc, [type, val]) => {\n if (isNull(type) && isNumber(val)) return acc + 1;\n\n return acc;\n }, 0);\n\n const queue = [] as [any, any][];\n\n for (const [type, val] of stack.value[0]) {\n if (type === null) {\n if (isString(val)) {\n current = current[val];\n } else if (isNumber(val)) {\n index++;\n\n /**\n * Запустим все экшены которые идут в `[null, int]` от `0` до `int`\n */\n for (let i = 0; i < val; i++) {\n const [action, ...meta] = current[i];\n\n /**\n * Экшены, для закрытия которых пользователь должен с ними взаимодействовать\n * Также в эту группу входят экшены, которые не должны быть вызваны при восстановлении\n */\n if (SKIPPED_DURING_RESTORE.has(action) || isUserRequiredAction(action, meta)) {\n if (index === max && i === val) {\n queue.push([action, meta]);\n } else {\n continue;\n }\n }\n\n queue.push([action, meta]);\n }\n\n current = current[val];\n }\n } else if (type === 'choice') {\n current = current[val as number + 1][1];\n } else if (type === 'condition') {\n current = current[2][val];\n }\n }\n\n const indexedQueue = queue.map((value, index) => value.concat(index) as [Exclude<ValidAction[0], ValidAction>, ValidAction[1], number]);\n\n for await (const [action, meta, i] of indexedQueue) {\n if (action === 'function' || action === 'custom') {\n /**\n * Если `callOnlyLatest` - `true`\n */\n if (action === 'custom' && (meta as GetActionParameters<'Custom'>)[0].callOnlyLatest) {\n /**\n * Вычислим `latest` или нет\n */\n const next = indexedQueue.slice(i + 1);\n const notLatest = next.some(([_action, _meta]) => _meta && meta && str(_meta[0]) === str(meta[0]));\n\n if (notLatest) continue;\n }\n\n /**\n * Action может возвращать Promise. Нужно подожать его `resolve`\n */\n const result = match(action, meta);\n\n /**\n * Дождёмся окончания\n */\n if (result && 'then' in result) await result;\n } else if (action === 'showCharacter') {\n const next = indexedQueue.slice(i + 1);\n const skip = next.some(([_action, _meta]) => {\n /**\n * Проверка на возможный `undefined`\n */\n if (!_meta || !meta) return false;\n\n /**\n * Будет ли персонаж скрыт в будущем\n * Нет смысла при загрузке сохранения загружать и отрисовывать персонажа, который будет скрыт\n */\n const hidden = _action === 'hideCharacter' && _meta[0] === meta[0];\n /**\n * Не нужно запускать рендер персонажа, если после этого будет ещё один рендер этого персонажа\n * Таким образом избегаем ситуации, когда при загрузке вследствие гонки при загрузки изображений отрисовывается не последняя эмоция\n */\n const notLatest = _action === action && _meta[0] === meta[0];\n\n return hidden || notLatest;\n })\n\n if (skip) continue;\n\n match(action, meta);\n } else if (action === 'showBackground') {\n const next = indexedQueue.slice(i + 1);\n /**\n * Такая же оптимизация применяется к фонам.\n * Если фон изменится, то нет смысла устанавливать текущий\n */\n const notLatest = next.some(([_action]) => action === _action);\n\n if (notLatest) continue;\n\n match(action, meta);\n } else {\n match(action, meta);\n }\n }\n\n restoring = goingBack = false, render();\n }\n\n const refer = () => {\n let current: any = story;\n\n for (const [type, val] of stack.value[0]) {\n if (type === null) {\n current = current[val];\n } else if (type === 'choice') {\n current = current[val as number + 1][1];\n } else if (type === 'condition') {\n current = current[2][val];\n }\n }\n\n return current;\n }\n\n const exit = () => {\n const current = stack.value;\n\n stack.clear();\n renderer.ui.showScreen('mainmenu');\n\n /**\n * First two save elements and it's type\n */\n const [[first, second], , [time, type]] = current;\n\n if (type === 'auto' && first && second) {\n /**\n * Если сохранение похоже на начальное, и при этом игрок не взаимодействовал с игрой, и оно было создано в текущей сессии, то удаляем его\n */\n if (first[0] === null && first[1] === 'start' && second[0] === null && !interacted && times.has(time)) {\n $.update((prev) => {\n prev.saves = prev.saves.filter(save => save !== current);\n\n return prev;\n })\n }\n }\n\n /**\n * Reset interactive value\n */\n interactivity(false);\n /**\n * Reset session times\n */\n times.clear();\n }\n\n const back = () => {\n return stack.back(), restore(stack.value);\n }\n\n const renderer = createRenderer({\n characters,\n set,\n restore,\n save,\n newGame,\n exit,\n back,\n stack,\n languages,\n t: t9n.i,\n $\n });\n\n const match = matchAction({\n wait([time]) {\n /**\n * `restoring` может поменяться на `true` перед тем как запуститься `push` из `setTimeout`\n */\n if (!restoring) setTimeout(push, isFunction(time) ? time() : time);\n },\n showBackground([background]) {\n renderer.background(background);\n push()\n },\n playMusic([source]) {\n renderer.music(source, 'music').play();\n push()\n },\n stopMusic([source]) {\n renderer.music(source, 'music').stop();\n push()\n },\n showCharacter([character, emotion, className, style]) {\n const handle = renderer.character(character);\n\n handle.append(className, style, restoring);\n handle.withEmotion(emotion)();\n\n push()\n },\n hideCharacter([character, className, style, duration]) {\n renderer.character(character).remove(className, style, duration)(push, restoring);\n },\n dialog([character, content, emotion]) {\n /**\n * Имя персонажа, с учетом выбранного языка\n */\n const name = (() => {\n const c = character, cs = characters;\n const lang = $.get().meta[0];\n\n return c ? c in cs ? typeof cs[c].name === 'string' ? cs[c].name as string : (cs[c].name as Record<string, string>)[lang] : c : '';\n })();\n\n renderer.dialog(unwrap(content), unwrap(name), character, emotion)(forward);\n },\n function([fn]) {\n const result = fn(restoring, goingBack);\n\n if (!restoring) result ? result.then(push) : push();\n\n return result;\n },\n choice([question, ...choices]) {\n const isWithoutQuestion = Array.isArray(question);\n\n if (isWithoutQuestion) {\n /**\n * Первый элемент может быть как строкой, так и элементов выбора\n */\n choices.unshift(question as unknown as [Unwrappable, ValidAction[], () => boolean]);\n /**\n * Значит, текст не требуется\n */\n question = '';\n }\n\n const unwrapped = choices.map(([content, action, visible]) => {\n return [unwrap(content), action, visible] as [string, ValidAction[], () => boolean];\n });\n\n renderer.choices(unwrap(question), unwrapped)((selected) => {\n enmemory();\n\n /**\n * Если был вопрос, то `index` смещается на единицу назад, поэтому нужно добавить единицу\n */\n stack.value[0].push(['choice', isWithoutQuestion ? selected : selected + 1], [null, 0]), render(), interactivity(true);\n });\n },\n jump([scene]) {\n /**\n * `-1` index is used here because `clear` will run `next` that will increase index to `0`\n */\n stack.value[0] = [[null, scene], [null, -1]];\n\n match('clear', []);\n },\n clear() {\n vibrate(0);\n renderer.clear(goingBack)(push);\n },\n condition([condition]) {\n const value = condition();\n\n if (!restoring) stack.value[0].push(['condition', String(value)], [null, 0]), render();\n },\n end() {\n /**\n * Clear the Scene\n */\n match('clear', []);\n /**\n * Go to the main menu\n */\n renderer.ui.showScreen('mainmenu');\n /**\n * Reset interactive value\n */\n interactivity(false);\n /**\n * Reset session times\n */\n times.clear();\n },\n input([question, onInput, setup]) {\n renderer.input(unwrap(question), onInput, setup)(forward);\n },\n custom([handler]) {\n const result = renderer.custom(handler, goingBack, () => {\n if (!restoring && handler.requireUserAction) enmemory(), interactivity(true);\n if (!restoring) push();\n });\n\n return result;\n },\n vibrate(pattern) {\n vibrate(pattern);\n push()\n },\n next() {\n push();\n },\n animateCharacter([character, timeout, ...classes]) {\n const handler: CustomHandler = (get) => {\n const { clear } = get('@@internal-animate-character', false);\n const char = renderer.store.characters[character];\n\n /**\n * Character is not defined, maybe, `animateCharacter` was called before `showCharacter`\n */\n if (!char) return;\n\n const target = char.canvas;\n\n /**\n * Character is not found\n */\n if (!target) return;\n\n const classNames = classes.filter(className => !target.classList.contains(className));\n\n target.classList.add(...classNames);\n\n const timeoutId = setTimeout(() => {\n target.classList.remove(...classNames);\n }, timeout);\n\n clear(() => {\n /**\n * Clear timeout, because when you will game re-runs some callback might remove classes from character\n */\n clearTimeout(timeoutId);\n });\n }\n\n handler.callOnlyLatest = true;\n\n return renderer.custom(handler, goingBack, () => { }), push();\n },\n text(text) {\n renderer.text(text.map(unwrap).join(' '), forward);\n },\n exit() {\n const path = stack.value[0];\n\n for (let i = path.length - 1; i > 0; i--) {\n if (path[i][0] !== 'choice' && path[i][0] !== 'condition') continue;\n\n stack.value[0] = path.slice(0, i);\n next();\n\n break;\n }\n\n render();\n }\n });\n\n const enmemory = () => {\n if (restoring) return;\n\n const current = klona(stack.value);\n\n current[2][1] = 'auto';\n\n stack.push(current);\n\n save(true, 'auto');\n }\n\n const next = () => {\n const path = stack.value[0];\n /**\n * Последний элемент пути\n */\n const last = path[path.length - 1]!;\n\n /**\n * Если он вида `[null, int]` - увеличивает `int`\n */\n if (isNull(last[0]) && isNumber(last[1])) {\n last[1] = last[1] + 1;\n return;\n }\n\n /**\n * Иначе добавляет новое `[null int]`\n */\n path.push([null, 0]);\n }\n\n const render = () => {\n const referred = refer();\n\n if (!Array.isArray(referred)) return;\n\n const [action, ...props] = referred;\n\n match(action, props);\n }\n\n const push = () => {\n if (!restoring) next(), render();\n }\n\n const forward = () => {\n enmemory();\n push();\n interactivity(true)\n }\n\n const interactivity = (value = false) => {\n interacted = value;\n }\n\n /**\n * Unwraps translatable content to string\n * \n * @example ```\n * unwrap(t('Hello'));\n * unwrap({ en: 'Hello', ru: 'Привет' });\n * ```\n */\n const unwrap = (content: Unwrappable) => {\n const lang = $.get().meta[0];\n const data = state();\n const str = isFunction(content) ? content(lang, data) : typeof content === 'object' ? content[lang] : content;\n\n return replaceT9N(str, data);\n }\n\n return {\n withStory,\n action,\n state,\n unwrap,\n t: t9n.t as Inter['t'],\n }\n}\n\nexport { novely }\n","const SKIPPED_DURING_RESTORE = new Set([\n 'dialog',\n 'choice',\n 'input',\n 'vibrate',\n 'text'\n] as const);\n\nexport { SKIPPED_DURING_RESTORE }","import type { StorageData } from './types'\n\ninterface LocalStorageStorageSettings {\n key: string\n}\n\ninterface Storage {\n get: () => Promise<StorageData>;\n set: (data: StorageData) => Promise<void>;\n}\n\nconst localStorageStorage = (options: LocalStorageStorageSettings): Storage => {\n return {\n async get() {\n const value = localStorage.getItem(options.key);\n\n return value ? JSON.parse(value) : { saves: [], meta: [] };\n },\n async set(data) {\n localStorage.setItem(options.key, JSON.stringify(data));\n }\n }\n}\n\nexport type { Storage }\nexport { localStorageStorage }"],"mappings":"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","names":["state","stack","save","action","index","next","str"]}
1
+ {"version":3,"sources":["../src/utils.ts","../src/store.ts","../src/novely.ts","../src/constants.ts","../src/storage.ts"],"sourcesContent":["import type { ActionProxyProvider, CustomHandler } from './action'\nimport type { Character } from './character'\nimport type { TypewriterSpeed, Thenable } from './types'\n\ntype MatchActionMap = {\n [Key in keyof ActionProxyProvider<Record<string, Character>>]: (data: Parameters<ActionProxyProvider<Record<string, Character>>[Key]>) => void;\n}\n\ntype MatchActionMapComplete = Omit<MatchActionMap, 'custom'> & {\n custom: (value: [handler: CustomHandler]) => Thenable<void>;\n}\n\nconst matchAction = <M extends MatchActionMapComplete>(values: M) => {\n return (action: keyof MatchActionMap, props: any) => {\n return values[action](props);\n }\n}\n\nconst isNumber = (val: unknown): val is number => {\n return typeof val === 'number';\n}\n\nconst isNull = (val: unknown): val is null => {\n return val === null;\n}\n\nconst isString = (val: unknown): val is string => {\n return typeof val === 'string';\n}\n\nconst isFunction = (val: unknown): val is ((...parameters: any[]) => any) => {\n return typeof val === 'function';\n}\n\nconst isEmpty = (val: unknown): val is {} => {\n return typeof val === 'object' && !isNull(val) && Object.keys(val).length === 0;\n}\n\nconst isCSSImage = (str: string) => {\n const startsWith = String.prototype.startsWith.bind(str);\n\n return startsWith('http') || startsWith('/') || startsWith('.') || startsWith('data');\n}\n\nconst str = (value: unknown) => {\n return String(value);\n}\n\nconst isUserRequiredAction = (action: keyof MatchActionMapComplete, meta: Parameters<MatchActionMapComplete[keyof MatchActionMapComplete]>) => {\n return action === 'custom' && meta[0] && (meta[0] as unknown as CustomHandler).requireUserAction;\n}\n\nconst getTypewriterSpeed = (): TypewriterSpeed => {\n return 'Medium'\n}\n\nconst getLanguage = (languages: string[], language = navigator.language) => {\n if (languages.includes(language)) {\n return language;\n } else if (languages.includes((language = language.substring(0, 2)))) {\n return language;\n } else if ((language = languages.find((value) => navigator.languages.includes(value))!)) {\n return language\n }\n\n /**\n * We'v checked the `en-GB` format, `en` format, and maybe any second languages, but there were no matches\n */\n return languages[0];\n}\n\n/**\n * @copyright Techlead LLC\n * @see https://learn.javascript.ru/task/throttle\n */\nconst throttle = <Fn extends ((...args: any[]) => any)>(fn: Fn, ms: number) => {\n let throttled = false, savedArgs: any, savedThis: any;\n\n function wrapper(this: any) {\n if (throttled) {\n savedArgs = arguments;\n savedThis = this;\n return;\n }\n\n fn.apply(this, arguments as unknown as any[]);\n\n throttled = true;\n\n setTimeout(function () {\n throttled = false;\n\n if (savedArgs) {\n wrapper.apply(savedThis, savedArgs);\n savedArgs = savedThis = null;\n }\n }, ms);\n }\n\n return wrapper as unknown as (...args: Parameters<Fn>) => void;\n}\n\nconst vibrate = (pattern: VibratePattern) => {\n try {\n if ('vibrate' in navigator) {\n navigator.vibrate(pattern);\n }\n } catch { }\n}\n\nconst findLastIndex = <T>(array: T[], fn: (item: T) => boolean) => {\n for (let i = array.length - 1; i > 0; i--) {\n if (fn(array[i])) {\n return i;\n }\n }\n\n return -1;\n}\n\nexport { matchAction, isNumber, isNull, isString, isEmpty, isCSSImage, str, isUserRequiredAction, getTypewriterSpeed, getLanguage, throttle, isFunction, vibrate, findLastIndex }","type Stored<T> = {\n subscribe: (cb: (value: T) => void) => () => void;\n update: (fn: (prev: T) => T) => void;\n get: () => T;\n}\n\nconst store = <T>(current: T, subscribers = new Set<(value: T) => void>()): Stored<T> => {\n const subscribe = (cb: (value: T) => void) => {\n subscribers.add(cb), cb(current);\n\n return () => {\n subscribers.delete(cb);\n }\n };\n\n const push = (value: T) => {\n subscribers.forEach((cb) => cb(value))\n };\n\n const update = (fn: (prev: T) => T) => {\n push((current = fn(current)));\n };\n\n const get = () => {\n return current;\n };\n\n return { subscribe, update, get } as const;\n};\n\nexport { store }\nexport type { Stored }","import type { Character } from './character';\nimport type { ActionProxyProvider, GetActionParameters, Story, ValidAction, Unwrappable, CustomHandler } from './action';\nimport type { Storage } from './storage';\nimport type { Save, State, Data, StorageData, DeepPartial, NovelyScreen, Migration } from './types'\nimport type { Renderer, RendererInit } from './renderer'\nimport type { SetupT9N } from '@novely/t9n'\nimport { matchAction, isNumber, isNull, isString, isEmpty, str, isUserRequiredAction, getTypewriterSpeed, getLanguage, throttle, isFunction, vibrate, findLastIndex } from './utils';\nimport { store } from './store';\nimport { all as deepmerge } from 'deepmerge'\nimport { klona } from 'klona/json';\nimport { SKIPPED_DURING_RESTORE } from './constants';\nimport { replace as replaceT9N } from '@novely/t9n';\n\ninterface NovelyInit<Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends ReturnType<SetupT9N<Languages>>, StateScheme extends State, DataScheme extends Data> {\n /**\n * An array of languages supported by the game.\n */\n languages: Languages[];\n /**\n * An object containing the characters in the game.\n */\n characters: Characters;\n /**\n * An object that provides access to the game's storage system.\n */\n storage: Storage;\n /**\n * Delay loading data until Promise is resolved\n */\n storageDelay?: Promise<void>;\n /**\n * A function that returns a Renderer object used to display the game's content\n */\n renderer: (characters: RendererInit) => Renderer;\n /**\n * An optional property that specifies the initial screen to display when the game starts\n */\n initialScreen?: NovelyScreen;\n /**\n * An object containing the translation functions used in the game\n */\n t9n: Inter;\n /**\n * Initial state value\n */\n state?: StateScheme;\n /**\n * Initial data value\n */\n data?: DataScheme;\n /**\n * Enable autosaves or disable\n * @default true\n */\n autosaves?: boolean;\n /**\n * Migration from old saves to newer\n */\n migrations?: Migration[]\n}\n\nconst novely = <\n Languages extends string,\n Characters extends Record<string, Character<Languages>>,\n Inter extends ReturnType<SetupT9N<Languages>>,\n StateScheme extends State,\n DataScheme extends Data\n>({\n characters,\n storage,\n storageDelay = Promise.resolve(),\n renderer: createRenderer,\n initialScreen = \"mainmenu\",\n t9n,\n languages,\n state: defaultState,\n data: defaultData,\n autosaves = true,\n migrations = []\n}: NovelyInit<Languages, Characters, Inter, StateScheme, DataScheme>) => {\n let story: Story;\n let times = new Set<number>();\n\n /**\n * Prevent `undefined`\n */\n defaultData ||= {} as DataScheme;\n defaultState ||= {} as StateScheme;\n\n /**\n * Saves timestamps created in this session\n */\n const intime = (value: number) => {\n return times.add(value), value;\n }\n\n const withStory = (s: Story) => {\n /**\n * Transforms `(ValidAction | ValidAction[])[]` to `ValidAction[]`\n */\n story = Object.fromEntries(Object.entries(s).map(([name, items]) => {\n const flat = (item: (ValidAction | ValidAction[])[]): ValidAction[] => {\n return item.flatMap((data) => {\n const type = data[0];\n\n /**\n * This is not just an action like `['name', ...arguments]`, but an array of actions\n */\n if (Array.isArray(type)) return flat(data as ValidAction[]);\n\n return [data as ValidAction];\n });\n };\n\n return [name, flat(items)];\n }));\n\n /**\n * When `initialScreen` is not a game, we can safely show it\n */\n if (initialScreen !== 'game') renderer.ui.showScreen(initialScreen);\n }\n\n const action = new Proxy({} as ActionProxyProvider<Characters>, {\n get(_, prop) {\n return (...props: Parameters<ActionProxyProvider<Record<string, Character>>[keyof ActionProxyProvider<Record<string, Character>>]>) => {\n return [prop, ...props];\n }\n }\n });\n\n function state(value: DeepPartial<StateScheme> | ((prev: StateScheme) => StateScheme)): void;\n function state(): StateScheme;\n function state(value?: DeepPartial<StateScheme> | ((prev: StateScheme) => StateScheme)): StateScheme | void {\n if (!value) return stack.value[1] as StateScheme | void;\n\n const prev = stack.value[1];\n const val = isFunction(value) ? value(prev as StateScheme) : deepmerge([prev, value]);\n\n stack.value[1] = val as StateScheme;\n }\n\n const getDefaultSave = (state = {}) => {\n return [[[null, 'start'], [null, 0]], state, [intime(Date.now()), 'auto']] as Save;\n }\n\n const createStack = (current: Save, stack = [current]) => {\n return {\n get value() {\n return stack.at(-1)!;\n },\n set value(value: Save) {\n stack[stack.length - 1] = value;\n },\n back() {\n if (stack.length > 1) stack.pop(), goingBack = true;\n },\n push(value: Save) {\n stack.push(value);\n },\n clear() {\n stack = [getDefaultSave(klona(defaultState))];\n }\n }\n }\n\n /**\n * 1) Novely rendered using the `initialData`, you can still start new game or `load` an empty one - this is scary, imagine losing your progress\n * 2) Actual stored data is loaded, language and etc is changed \n */\n const initialData: StorageData = {\n saves: [],\n data: klona(defaultData) as Data,\n meta: [getLanguage(languages), getTypewriterSpeed()],\n };\n\n const $ = store(initialData);\n\n let initialDataLoaded = false;\n\n const onStorageDataChange = (value: StorageData) => {\n if (initialDataLoaded) storage.set(value);\n };\n\n const throttledOnStorageDataChange = throttle(onStorageDataChange, 120);\n\n $.subscribe(throttledOnStorageDataChange);\n\n const getStoredData = () => {\n storage.get().then(stored => {\n /**\n * Migration is done only once (when game loads it's data), and then it saves the updated format\n */\n for (const migration of migrations) {\n // @ts-expect-error Types does not match between versions\n stored = migration(stored);\n }\n\n /**\n * Default `localStorageStorage` cannot determine preferred language, and returns empty array\n */\n stored.meta[0] ||= getLanguage(languages);\n stored.meta[1] ||= getTypewriterSpeed();\n\n /**\n * When data is empty replace it with `defaultData`\n * It also might be empty (default to empty)\n */\n if (isEmpty(stored.data)) {\n stored.data = defaultData as Data;\n }\n\n /**\n * Now the next store updates will entail saving via storage.set\n */\n initialDataLoaded = true;\n\n $.update(() => stored);\n\n /**\n * When initialScreen is game, then we will load it, but after the data is loaded\n */\n if (initialScreen === 'game') restore();\n });\n }\n\n /**\n * By default this is resolved immediately, but also can be delayed.\n * I.e. storage has not loaded yet\n */\n storageDelay.then(getStoredData)\n\n const initial = getDefaultSave(klona(defaultState));\n const stack = createStack(initial);\n\n const save = (override = false, type: Save[2][1] = override ? 'auto' : 'manual') => {\n if (!initialDataLoaded) return;\n\n /**\n * When autosaves diabled just return\n */\n if (!autosaves && type === 'auto') return;\n\n const current = klona(stack.value);\n\n $.update(prev => {\n /**\n * Find latest save that were created in current session, and check if it is latest in an array\n * \n * We check if save was created in current session and it is latest in array\n * When it is not then replacing it will break logical chain\n * \n * [auto save 1]\n * [manual save 1]\n * [auto save 2] <- should not replace first auto save \n */\n const isLatest = findLastIndex(prev.saves, value => times.has(value[2][0])) === prev.saves.length - 1;\n\n /**\n * Update type and time information\n */\n current[2][0] = intime(Date.now());\n current[2][1] = type;\n\n if (!override || !isLatest) {\n prev.saves.push(current);\n\n return prev;\n }\n\n /**\n * Get latest\n */\n const latest = prev.saves.at(-1);\n\n /**\n * When that save is the same type, replace it\n */\n if (latest && latest[2][1] === type) {\n prev.saves[prev.saves.length - 1] = current;\n } else {\n prev.saves.push(current);\n }\n\n return prev;\n });\n }\n\n const newGame = () => {\n if (!initialDataLoaded) return;\n\n const save = getDefaultSave(klona(defaultState));\n\n /**\n * Initial save is automatic, and should be ignored when autosaves is turned off\n */\n if (autosaves) {\n $.update(prev => {\n return prev.saves.push(save), prev;\n });\n }\n\n restore(save);\n }\n\n /**\n * Set's the save\n */\n const set = (save: Save) => {\n stack.value = save;\n\n return restore(save);\n }\n\n let restoring = false;\n let goingBack = false;\n let interacted = false;\n\n /**\n * Restore\n */\n const restore = async (save?: Save) => {\n if (!initialDataLoaded) return;\n\n let latest = save ? save : $.get().saves.at(-1);\n\n /**\n * When there is no game, then make a new game\n */\n if (!latest) {\n $.update(() => ({ saves: [initial], data: klona(defaultData) as Data, meta: [getLanguage(languages), getTypewriterSpeed()] }));\n\n latest = klona(initial);\n }\n\n restoring = true, stack.value = latest;\n\n renderer.ui.showScreen('game');\n match('clear', [goingBack]);\n\n /**\n * Текущий элемент в истории\n */\n let current: any = story;\n /**\n * Текущий элемент `[null, int]`\n */\n let index = 0;\n\n /**\n * Число элементов `[null, int]`\n */\n const max = stack.value[0].reduce((acc, [type, val]) => {\n if (isNull(type) && isNumber(val)) return acc + 1;\n\n return acc;\n }, 0);\n\n const queue = [] as [any, any][];\n\n for (const [type, val] of stack.value[0]) {\n if (type === null) {\n if (isString(val)) {\n current = current[val];\n } else if (isNumber(val)) {\n index++;\n\n /**\n * Запустим все экшены которые идут в `[null, int]` от `0` до `int`\n */\n for (let i = 0; i < val; i++) {\n const [action, ...meta] = current[i];\n\n /**\n * Экшены, для закрытия которых пользователь должен с ними взаимодействовать\n * Также в эту группу входят экшены, которые не должны быть вызваны при восстановлении\n */\n if (SKIPPED_DURING_RESTORE.has(action) || isUserRequiredAction(action, meta)) {\n if (index === max && i === val) {\n queue.push([action, meta]);\n } else {\n continue;\n }\n }\n\n queue.push([action, meta]);\n }\n\n current = current[val];\n }\n } else if (type === 'choice') {\n current = current[val as number + 1][1];\n } else if (type === 'condition') {\n current = current[2][val];\n }\n }\n\n const indexedQueue = queue.map((value, index) => value.concat(index) as [Exclude<ValidAction[0], ValidAction>, ValidAction[1], number]);\n\n for await (const [action, meta, i] of indexedQueue) {\n if (action === 'function' || action === 'custom') {\n /**\n * Если `callOnlyLatest` - `true`\n */\n if (action === 'custom' && (meta as GetActionParameters<'Custom'>)[0].callOnlyLatest) {\n /**\n * Вычислим `latest` или нет\n */\n const next = indexedQueue.slice(i + 1);\n const notLatest = next.some(([_action, _meta]) => _meta && meta && str(_meta[0]) === str(meta[0]));\n\n if (notLatest) continue;\n }\n\n /**\n * Action может возвращать Promise. Нужно подожать его `resolve`\n */\n const result = match(action, meta);\n\n /**\n * Дождёмся окончания\n */\n if (result && 'then' in result) await result;\n } else if (action === 'showCharacter') {\n const next = indexedQueue.slice(i + 1);\n const skip = next.some(([_action, _meta]) => {\n /**\n * Проверка на возможный `undefined`\n */\n if (!_meta || !meta) return false;\n\n /**\n * Будет ли персонаж скрыт в будущем\n * Нет смысла при загрузке сохранения загружать и отрисовывать персонажа, который будет скрыт\n */\n const hidden = _action === 'hideCharacter' && _meta[0] === meta[0];\n /**\n * Не нужно запускать рендер персонажа, если после этого будет ещё один рендер этого персонажа\n * Таким образом избегаем ситуации, когда при загрузке вследствие гонки при загрузки изображений отрисовывается не последняя эмоция\n */\n const notLatest = _action === action && _meta[0] === meta[0];\n\n return hidden || notLatest;\n })\n\n if (skip) continue;\n\n match(action, meta);\n } else if (action === 'showBackground') {\n const next = indexedQueue.slice(i + 1);\n /**\n * Такая же оптимизация применяется к фонам.\n * Если фон изменится, то нет смысла устанавливать текущий\n */\n const notLatest = next.some(([_action]) => action === _action);\n\n if (notLatest) continue;\n\n match(action, meta);\n } else {\n match(action, meta);\n }\n }\n\n restoring = goingBack = false, render();\n }\n\n const refer = () => {\n let current: any = story;\n\n for (const [type, val] of stack.value[0]) {\n if (type === null) {\n current = current[val];\n } else if (type === 'choice') {\n current = current[val as number + 1][1];\n } else if (type === 'condition') {\n current = current[2][val];\n }\n }\n\n return current;\n }\n\n const exit = () => {\n const current = stack.value;\n\n stack.clear();\n renderer.ui.showScreen('mainmenu');\n\n /**\n * First two save elements and it's type\n */\n const [[first, second], , [time, type]] = current;\n\n if (type === 'auto' && first && second) {\n /**\n * Если сохранение похоже на начальное, и при этом игрок не взаимодействовал с игрой, и оно было создано в текущей сессии, то удаляем его\n */\n if (first[0] === null && first[1] === 'start' && second[0] === null && !interacted && times.has(time)) {\n $.update((prev) => {\n prev.saves = prev.saves.filter(save => save !== current);\n\n return prev;\n })\n }\n }\n\n /**\n * Reset interactive value\n */\n interactivity(false);\n /**\n * Reset session times\n */\n times.clear();\n }\n\n const back = () => {\n return stack.back(), restore(stack.value);\n }\n\n const renderer = createRenderer({\n characters,\n set,\n restore,\n save,\n newGame,\n exit,\n back,\n stack,\n languages,\n t: t9n.i,\n $\n });\n\n const match = matchAction({\n wait([time]) {\n /**\n * `restoring` может поменяться на `true` перед тем как запуститься `push` из `setTimeout`\n */\n if (!restoring) setTimeout(push, isFunction(time) ? time() : time);\n },\n showBackground([background]) {\n renderer.background(background);\n push()\n },\n playMusic([source]) {\n renderer.music(source, 'music').play();\n push()\n },\n stopMusic([source]) {\n renderer.music(source, 'music').stop();\n push()\n },\n showCharacter([character, emotion, className, style]) {\n const handle = renderer.character(character);\n\n handle.append(className, style, restoring);\n handle.withEmotion(emotion)();\n\n push()\n },\n hideCharacter([character, className, style, duration]) {\n renderer.character(character).remove(className, style, duration)(push, restoring);\n },\n dialog([character, content, emotion]) {\n /**\n * Имя персонажа, с учетом выбранного языка\n */\n const name = (() => {\n const c = character, cs = characters;\n const lang = $.get().meta[0];\n\n return c ? c in cs ? typeof cs[c].name === 'string' ? cs[c].name as string : (cs[c].name as Record<string, string>)[lang] : c : '';\n })();\n\n renderer.dialog(unwrap(content), unwrap(name), character, emotion)(forward);\n },\n function([fn]) {\n const result = fn(restoring, goingBack);\n\n if (!restoring) result ? result.then(push) : push();\n\n return result;\n },\n choice([question, ...choices]) {\n const isWithoutQuestion = Array.isArray(question);\n\n if (isWithoutQuestion) {\n /**\n * Первый элемент может быть как строкой, так и элементов выбора\n */\n choices.unshift(question as unknown as [Unwrappable, ValidAction[], () => boolean]);\n /**\n * Значит, текст не требуется\n */\n question = '';\n }\n\n const unwrapped = choices.map(([content, action, visible]) => {\n return [unwrap(content), action, visible] as [string, ValidAction[], () => boolean];\n });\n\n renderer.choices(unwrap(question), unwrapped)((selected) => {\n enmemory();\n\n /**\n * Если был вопрос, то `index` смещается на единицу назад, поэтому нужно добавить единицу\n */\n stack.value[0].push(['choice', isWithoutQuestion ? selected : selected + 1], [null, 0]), render(), interactivity(true);\n });\n },\n jump([scene]) {\n /**\n * `-1` index is used here because `clear` will run `next` that will increase index to `0`\n */\n stack.value[0] = [[null, scene], [null, -1]];\n\n match('clear', []);\n },\n clear() {\n vibrate(0);\n renderer.clear(goingBack)(push);\n },\n condition([condition]) {\n const value = condition();\n\n if (!restoring) stack.value[0].push(['condition', String(value)], [null, 0]), render();\n },\n end() {\n /**\n * Clear the Scene\n */\n match('clear', []);\n /**\n * Go to the main menu\n */\n renderer.ui.showScreen('mainmenu');\n /**\n * Reset interactive value\n */\n interactivity(false);\n /**\n * Reset session times\n */\n times.clear();\n },\n input([question, onInput, setup]) {\n renderer.input(unwrap(question), onInput, setup)(forward);\n },\n custom([handler]) {\n const result = renderer.custom(handler, goingBack, () => {\n if (!restoring && handler.requireUserAction) enmemory(), interactivity(true);\n if (!restoring) push();\n });\n\n return result;\n },\n vibrate(pattern) {\n vibrate(pattern);\n push()\n },\n next() {\n push();\n },\n animateCharacter([character, timeout, ...classes]) {\n const handler: CustomHandler = (get) => {\n const { clear } = get('@@internal-animate-character', false);\n const char = renderer.store.characters[character];\n\n /**\n * Character is not defined, maybe, `animateCharacter` was called before `showCharacter`\n */\n if (!char) return;\n\n const target = char.canvas;\n\n /**\n * Character is not found\n */\n if (!target) return;\n\n const classNames = classes.filter(className => !target.classList.contains(className));\n\n target.classList.add(...classNames);\n\n const timeoutId = setTimeout(() => {\n target.classList.remove(...classNames);\n }, timeout);\n\n clear(() => {\n target.classList.remove(...classNames);\n \n /**\n * Clear timeout, because when you will game re-runs some callback might remove classes from character\n */\n clearTimeout(timeoutId);\n });\n }\n\n handler.callOnlyLatest = true;\n\n return renderer.custom(handler, goingBack, () => { }), push();\n },\n text(text) {\n renderer.text(text.map((content) => unwrap(content)).join(' '), forward);\n },\n exit() {\n const path = stack.value[0];\n\n for (let i = path.length - 1; i > 0; i--) {\n if (path[i][0] !== 'choice' && path[i][0] !== 'condition') continue;\n\n stack.value[0] = path.slice(0, i);\n next();\n\n break;\n }\n\n render();\n }\n });\n\n const enmemory = () => {\n if (restoring) return;\n\n const current = klona(stack.value);\n\n current[2][1] = 'auto';\n\n stack.push(current);\n\n save(true, 'auto');\n }\n\n const next = () => {\n const path = stack.value[0];\n /**\n * Последний элемент пути\n */\n const last = path[path.length - 1]!;\n\n /**\n * Если он вида `[null, int]` - увеличивает `int`\n */\n if (isNull(last[0]) && isNumber(last[1])) {\n last[1] = last[1] + 1;\n return;\n }\n\n /**\n * Иначе добавляет новое `[null int]`\n */\n path.push([null, 0]);\n }\n\n const render = () => {\n const referred = refer();\n\n if (!Array.isArray(referred)) return;\n\n const [action, ...props] = referred;\n\n match(action, props);\n }\n\n const push = () => {\n if (!restoring) next(), render();\n }\n\n const forward = () => {\n enmemory();\n push();\n interactivity(true)\n }\n\n const interactivity = (value = false) => {\n interacted = value;\n }\n\n /**\n * Unwraps translatable content to string\n * \n * @example ```\n * unwrap(t('Hello'));\n * unwrap({ en: 'Hello', ru: 'Привет' });\n * unwrap('Hello, {{name}}');\n * ```\n */\n const unwrap = (content: Unwrappable, global = false) => {\n const { data, meta: [lang] } = $.get();\n\n const obj = global ? data : state();\n const str = isFunction(content)\n ? content(lang, obj)\n : typeof content === 'object'\n ? content[lang]\n : content;\n \n return replaceT9N(str, obj);\n }\n\n function data(value: DeepPartial<DataScheme> | ((prev: DataScheme) => DataScheme)): void;\n function data(): DataScheme;\n function data(value?: DeepPartial<DataScheme> | ((prev: DataScheme) => DataScheme)): DataScheme | void {\n if (!value) return $.get().data as DataScheme | void;\n\n const prev = $.get().data;\n const val = isFunction(value) ? value(prev as DataScheme) : deepmerge([prev, value]);\n\n $.update((prev) => {\n prev.data = val;\n\n return prev;\n });\n }\n\n return {\n /**\n * Function to set story\n */\n withStory,\n /**\n * Function to get actions\n */\n action,\n /**\n * State that belongs to games\n */\n state,\n /**\n * Unlike `state`, stored at global scope instead and shared between games\n */\n data,\n /**\n * Unwraps translatable content to a string value\n */\n unwrap(content: Exclude<Unwrappable, Record<string, string>> | Record<Languages, string>) {\n return unwrap(content, true);\n },\n /**\n * Function that is used for translation\n */\n t: t9n.t as Inter['t'],\n }\n}\n\nexport { novely }\n","const SKIPPED_DURING_RESTORE = new Set([\n 'dialog',\n 'choice',\n 'input',\n 'vibrate',\n 'text'\n] as const);\n\nexport { SKIPPED_DURING_RESTORE }","import type { StorageData } from './types'\n\ninterface LocalStorageStorageSettings {\n key: string\n}\n\ninterface Storage {\n get: () => Promise<StorageData>;\n set: (data: StorageData) => Promise<void>;\n}\n\nconst localStorageStorage = (options: LocalStorageStorageSettings): Storage => {\n return {\n async get() {\n const value = localStorage.getItem(options.key);\n\n return value ? JSON.parse(value) : { saves: [], data: {}, meta: [] };\n },\n async set(data) {\n localStorage.setItem(options.key, JSON.stringify(data));\n }\n }\n}\n\nexport type { Storage }\nexport { localStorageStorage }"],"mappings":"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","names":["data","state","stack","save","action","index","next","str","prev"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@novely/core",
3
3
  "description": "Novely - powerful visual novel engine for creating interactive stories and games with branching narratives and rich multimedia content.",
4
- "version": "0.4.2",
4
+ "version": "0.4.4",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "publishConfig": {