@novely/core 0.0.0-alpha.17 → 0.0.0-alpha.3

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
@@ -1,4 +1,3 @@
1
- import * as _novely_t9n from '@novely/t9n';
2
1
  import { BaseTranslationStrings, SetupT9N } from '@novely/t9n';
3
2
  export { BaseTranslationStrings } from '@novely/t9n';
4
3
 
@@ -40,19 +39,17 @@ type Stack = {
40
39
  clear(): void;
41
40
  };
42
41
 
43
- type ValidAction = ['choice', [number]] | ['clear', []] | ['condition', [() => boolean, Record<string, ValidAction[]>]] | ['dialog', [string | undefined, DialogContent, 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', [number]] | ['function', [() => Thenable<void>]] | ['input', [string, (meta: {
44
- input: HTMLInputElement;
45
- error: (error: string) => void;
46
- event: InputEvent & {
47
- currentTarget: HTMLInputElement;
48
- };
49
- }) => void, ((input: HTMLInputElement) => void)?]] | ['custom', [CustomHandler]] | ['vibrate', [...number[]]] | ['next', []] | ['text', [...string[]]] | ValidAction[];
42
+ type ValidAction = [keyof DefaultActionProxyProvider, Parameters<DefaultActionProxyProvider[keyof DefaultActionProxyProvider]>];
50
43
  type Story = Record<string, ValidAction[]>;
51
44
  type DialogContent = string | ((lang: string, obj: Record<string, unknown>) => string);
52
45
  type ChoiceContent = string | ((lang: string, obj: Record<string, unknown>) => string);
53
- type TextContent = string | ((lang: string, obj: Record<string, unknown>) => string);
54
46
  type CustomHandlerGetResultDataFunction = {
55
- (data?: Record<string, unknown>): Record<string, unknown>;
47
+ (): Record<string, unknown>;
48
+ (data: Record<string, unknown>): void;
49
+ };
50
+ type CustomHandlerGetResultSkipClearOnGoingBackFunction = {
51
+ (): boolean;
52
+ (value: boolean): void;
56
53
  };
57
54
  type CustomHandlerGetResult = {
58
55
  delete: () => void;
@@ -63,21 +60,20 @@ type CustomHandlerGetResult = {
63
60
  /**
64
61
  * Элемент слоя
65
62
  */
66
- element: HTMLDivElement | null;
63
+ element: HTMLDivElement;
67
64
  /**
68
- * Корневой элемент Novely
65
+ * Будет ли запускаться очистка при проходе назад
69
66
  */
70
- root: HTMLElement;
67
+ skipClearOnGoingBack: CustomHandlerGetResultSkipClearOnGoingBackFunction;
71
68
  /**
72
69
  * Устанавливает обработчик очистки
73
70
  */
74
71
  clear: (fn: () => void) => void;
75
72
  };
76
- type CustomHandlerFunction = (get: (id: string, insert?: boolean) => CustomHandlerGetResult, goingBack: boolean, resolve: () => void) => Thenable<void>;
73
+ type CustomHandlerFunction = (get: (id: string) => CustomHandlerGetResult, goingBack: boolean, resolve: () => void) => Thenable<void>;
77
74
  type CustomHandler = CustomHandlerFunction & {
78
75
  callOnlyLatest?: boolean;
79
76
  requireUserAction?: boolean;
80
- skipClearOnGoingBack?: boolean;
81
77
  };
82
78
  type ActionProxyProvider<Characters extends Record<string, Character>> = {
83
79
  choice: (...choices: ([ChoiceContent, ValidAction[]] | [ChoiceContent, ValidAction[], () => boolean])[]) => ValidAction;
@@ -99,9 +95,6 @@ type ActionProxyProvider<Characters extends Record<string, Character>> = {
99
95
  hideCharacter: {
100
96
  <C extends keyof Characters>(character: C, className?: string, style?: string, duration?: number): ValidAction;
101
97
  };
102
- animateCharacter: {
103
- <C extends keyof Characters>(character: C, timeout: number, ...classes: string[]): ValidAction;
104
- };
105
98
  wait: (time: number) => ValidAction;
106
99
  function: (fn: () => Thenable<void>) => ValidAction;
107
100
  input: (question: string, onInput: (meta: {
@@ -114,11 +107,19 @@ type ActionProxyProvider<Characters extends Record<string, Character>> = {
114
107
  custom: (handler: CustomHandler) => ValidAction;
115
108
  vibrate: (...pattern: number[]) => ValidAction;
116
109
  next: () => ValidAction;
117
- text: (...text: TextContent[]) => ValidAction;
118
110
  };
119
111
  type DefaultActionProxyProvider = ActionProxyProvider<Record<string, Character>>;
120
112
  type GetActionParameters<T extends Capitalize<keyof DefaultActionProxyProvider>> = Parameters<DefaultActionProxyProvider[Uncapitalize<T>]>;
121
113
 
114
+ interface LocalStorageStorageSettings {
115
+ key: string;
116
+ }
117
+ interface Storage {
118
+ get: () => Promise<StorageData>;
119
+ set: (data: StorageData) => Promise<void>;
120
+ }
121
+ declare const localStorageStorage: (options: LocalStorageStorageSettings) => Storage;
122
+
122
123
  type Stored<T> = {
123
124
  subscribe: (cb: (value: T) => void) => () => void;
124
125
  update: (fn: (prev: T) => T) => void;
@@ -152,7 +153,6 @@ type Renderer = {
152
153
  music: (source: string, method: keyof RendererStore['audio']) => AudioHandle;
153
154
  clear: (goingBack: boolean) => (resolve: () => void) => void;
154
155
  custom: (fn: Parameters<DefaultActionProxyProvider['custom']>[0], goingBack: boolean, push: () => void) => Thenable<void>;
155
- text: (str: string, resolve: () => void) => void;
156
156
  store: RendererStore;
157
157
  ui: {
158
158
  /**
@@ -163,9 +163,10 @@ type Renderer = {
163
163
  };
164
164
  type RendererInit = {
165
165
  characters: Record<string, Character>;
166
+ storage: Storage;
166
167
  set: (save: Save) => Promise<void>;
167
168
  restore: (save?: Save) => Promise<void>;
168
- save: (override?: boolean, type?: Save[2][1]) => void;
169
+ save: (override?: boolean, type?: Save[2][1]) => Promise<void>;
169
170
  newGame: () => void;
170
171
  stack: Stack;
171
172
  languages: string[];
@@ -179,15 +180,6 @@ type RendererInit = {
179
180
  $: Stored<StorageData>;
180
181
  };
181
182
 
182
- interface LocalStorageStorageSettings {
183
- key: string;
184
- }
185
- interface Storage {
186
- get: () => Promise<StorageData>;
187
- set: (data: StorageData) => Promise<void>;
188
- }
189
- declare const localStorageStorage: (options: LocalStorageStorageSettings) => Storage;
190
-
191
183
  interface NovelyInit<Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends ReturnType<SetupT9N<Languages>>> {
192
184
  /**
193
185
  * An array of languages supported by the game.
@@ -213,12 +205,16 @@ interface NovelyInit<Languages extends string, Characters extends Record<string,
213
205
  * An object containing the translation functions used in the game
214
206
  */
215
207
  t9n: Inter;
208
+ /**
209
+ * An optional property that specifies whether to preload assets when the game starts
210
+ */
211
+ assetsPreload?: boolean;
216
212
  /**
217
213
  * An optional property that specifies whether the game should use a single save.
218
214
  */
219
215
  singleSave?: boolean;
220
216
  }
221
- declare const novely: <Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends _novely_t9n.T9N<Languages, string, string>>({ characters, storage, renderer: createRenderer, initialScreen, t9n, languages }: NovelyInit<Languages, Characters, Inter>) => {
217
+ type Novely = <Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends ReturnType<SetupT9N<Languages>>>(init: NovelyInit<Languages, Characters, Inter>) => {
222
218
  withStory: (s: Story) => void;
223
219
  action: ActionProxyProvider<Characters>;
224
220
  render: () => void;
@@ -226,7 +222,8 @@ declare const novely: <Languages extends string, Characters extends Record<strin
226
222
  (value: State | ((prev: State) => State)): void;
227
223
  (): State;
228
224
  };
229
- t: (key: string) => (lang: (string & {}) | Languages, obj: Record<string, unknown>) => string;
225
+ t: Inter['t'];
230
226
  };
227
+ declare const novely: Novely;
231
228
 
232
- export { ActionProxyProvider, AudioHandle, Character, CharacterHandle, CustomHandler, CustomHandlerGetResult, CustomHandlerGetResultDataFunction, DefaultActionProxyProvider, Emotions, GetActionParameters, Path, Renderer, RendererInit, RendererStore, Storage, StorageData, Stored, Story, Thenable, ValidAction, localStorageStorage, novely };
229
+ export { ActionProxyProvider, AudioHandle, Character, CharacterHandle, CustomHandler, CustomHandlerGetResult, CustomHandlerGetResultDataFunction, CustomHandlerGetResultSkipClearOnGoingBackFunction, DefaultActionProxyProvider, Emotions, GetActionParameters, Path, Renderer, RendererInit, RendererStore, Storage, StorageData, Stored, Story, Thenable, ValidAction, localStorageStorage, novely };
@@ -1,2 +1,2 @@
1
- "use strict";var Novely=(()=>{var de=Object.create;var j=Object.defineProperty;var ye=Object.getOwnPropertyDescriptor;var Se=Object.getOwnPropertyNames;var ve=Object.getPrototypeOf,he=Object.prototype.hasOwnProperty;var Ae=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),be=(e,t)=>{for(var a in t)j(e,a,{get:t[a],enumerable:!0})},J=(e,t,a,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of Se(t))!he.call(e,s)&&s!==a&&j(e,s,{get:()=>t[s],enumerable:!(o=ye(t,s))||o.enumerable});return e};var Ce=(e,t,a)=>(a=e!=null?de(ve(e)):{},J(t||!e||!e.__esModule?j(a,"default",{value:e,enumerable:!0}):a,e)),De=e=>J(j({},"__esModule",{value:!0}),e);var te=Ae((Ke,ee)=>{"use strict";var xe=function(t){return Ee(t)&&!Pe(t)};function Ee(e){return!!e&&typeof e=="object"}function Pe(e){var t=Object.prototype.toString.call(e);return t==="[object RegExp]"||t==="[object Date]"||Me(e)}var Te=typeof Symbol=="function"&&Symbol.for,we=Te?Symbol.for("react.element"):60103;function Me(e){return e.$$typeof===we}function Be(e){return Array.isArray(e)?[]:{}}function O(e,t){return t.clone!==!1&&t.isMergeableObject(e)?T(Be(e),e,t):e}function Oe(e,t,a){return e.concat(t).map(function(o){return O(o,a)})}function Re(e,t){if(!t.customMerge)return T;var a=t.customMerge(e);return typeof a=="function"?a:T}function Le(e){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(e).filter(function(t){return Object.propertyIsEnumerable.call(e,t)}):[]}function X(e){return Object.keys(e).concat(Le(e))}function Z(e,t){try{return t in e}catch{return!1}}function je(e,t){return Z(e,t)&&!(Object.hasOwnProperty.call(e,t)&&Object.propertyIsEnumerable.call(e,t))}function Fe(e,t,a){var o={};return a.isMergeableObject(e)&&X(e).forEach(function(s){o[s]=O(e[s],a)}),X(t).forEach(function(s){je(e,s)||(Z(e,s)&&a.isMergeableObject(t[s])?o[s]=Re(s,a)(e[s],t[s],a):o[s]=O(t[s],a))}),o}function T(e,t,a){a=a||{},a.arrayMerge=a.arrayMerge||Oe,a.isMergeableObject=a.isMergeableObject||xe,a.cloneUnlessOtherwiseSpecified=O;var o=Array.isArray(t),s=Array.isArray(e),l=o===s;return l?o?a.arrayMerge(e,t,a):Fe(e,t,a):O(t,a)}T.all=function(t,a){if(!Array.isArray(t))throw new Error("first argument should be an array");return t.reduce(function(o,s){return T(o,s,a)},{})};var Ne=T;ee.exports=Ne});var Ge={};be(Ge,{localStorageStorage:()=>oe,novely:()=>ne});var $=e=>(t,a)=>e[t](a),F=e=>typeof e=="number",U=e=>e===null,W=e=>typeof e=="string";var V=e=>String(e),z=(e,t)=>e==="custom"&&t[0]&&t[0].requireUserAction,N=()=>[[[null,"start"],[null,0]],{},[Date.now(),"auto"]],I=(e,t=navigator.language)=>e.includes(t)||e.includes(t=t.substring(0,2))||(t=e.find(a=>navigator.languages.includes(a)))?t:e[0],Q=(e,t)=>{let a=!1,o,s;function l(){if(a){o=arguments,s=this;return}e.apply(this,arguments),a=!1}return setTimeout(function(){a=!1,o&&(l.apply(s,o),o=s=null)},t),l};var Y=(e,t=new Set)=>{let a=c=>(t.add(c),c(e),()=>{t.delete(c)}),o=c=>{t.forEach(x=>x(c))};return{subscribe:a,update:c=>{o(e=c(e))},get:()=>e}};var ue=Ce(te(),1);function D(e){var t,a,o;if(Array.isArray(e)){for(a=Array(t=e.length);t--;)a[t]=(o=e[t])&&typeof o=="object"?D(o):o;return a}if(Object.prototype.toString.call(e)==="[object Object]"){a={};for(t in e)t==="__proto__"?Object.defineProperty(a,t,{value:D(e[t]),configurable:!0,enumerable:!0,writable:!0}):a[t]=(o=e[t])&&typeof o=="object"?D(o):o;return a}return e}var re=new Set(["dialog","input","vibrate","text"]);var Ie=/{{(.*?)}}/g,ae=(e,t,a,o)=>e.replace(Ie,(s,l,c)=>{s=0,c=t,l=l.trim();let x=l.split("@"),w;for(x.length>1&&([l,w]=x),l=l.split(".");c&&s<l.length;)c=c[l[s++]];return w&&a&&o&&c&&(c=a[w][o.select(c)]),c??""});var ne=({characters:e,storage:t,renderer:a,initialScreen:o="mainmenu",t9n:s,languages:l})=>{let c,x=r=>{c=Object.fromEntries(Object.entries(r).map(([u,n])=>{let p=y=>y.flatMap(S=>{let C=S[0];return Array.isArray(C)?p(S):[S]});return[u,p(n)]})),o!=="game"&&m.ui.showScreen(o)},w=new Proxy({},{get(r,u){return(...n)=>[u,...n]}});function q(r){if(!r)return i.value[1];let u=i.value[1],n=typeof r=="function"?r(u):(0,ue.all)([u,r]);i.value[1]=n}let se=(r,u=[r])=>({get value(){return u.at(-1)},set value(n){u[u.length-1]=n},back(){u.length>1&&(u.pop(),E=!0)},push(n){u.push(n)},clear(){u=[N()]}}),ie={saves:[],meta:[I(l)]},h=Y(ie),M=!1,ce=Q(r=>{M&&t.set(r)},120);h.subscribe(ce),t.get().then(r=>{r.meta[0]||=I(l),M=!0,h.update(()=>r),o==="game"&&R()});let G=(r=>r.saves.length>0&&r.saves.at(-1))(h.get())||N(),i=se(G),K=(r=!1,u=r?"auto":"manual")=>{M&&h.update(n=>{let p=i.value[2][0],y=n.saves.findIndex(S=>S[2][0]===p)===n.saves.length-1;return i.value[2][0]=Date.now(),i.value[2][1]=u,r&&y?n.saves[n.saves.length-1]=i.value:n.saves.push(i.value),n})},le=()=>{if(!M)return;let r=N();h.update(u=>(u.saves.push(r),R(r),u))},me=r=>(i.value=r,R(r)),v=!1,E=!1,R=async r=>{if(!M)return;let u=r||h.get().saves.at(-1);u||(h.update(()=>({saves:[G],meta:[I(l)]})),u=D(G)),v=!0,i.value=u,m.ui.showScreen("game"),B("clear",[E]);let n=c,p=0,y=i.value[0].reduce((g,[f,A])=>U(f)&&F(A)?g+1:g,0),S=[];for(let[g,f]of i.value[0])if(g===null){if(W(f))n=n[f];else if(F(f)){p++;for(let A=0;A<f;A++){let[b,...L]=n[A];if(re.has(b)||z(b,L))if(p===y&&A===f)S.push([b,L]);else continue;S.push([b,L])}n=n[f]}}else g==="choice"?n=n[f+1][1]:g==="condition"&&(n=n[2][f]);let C=S.map((g,f)=>g.concat(f));for await(let[g,f,A]of C)if(g==="function"||g==="custom"){if(g==="custom"&&f[0].callOnlyLatest&&!!C.slice(A+1).some(([ke,ge])=>V(ge[0])===V(f[0])))continue;let b=B(g,f);b&&"then"in b&&await b}else B(g,f);v=!1,E=!1,P()},fe=()=>{let r=c;for(let[u,n]of i.value[0])u===null?r=r[n]:u==="choice"?r=r[n+1][1]:u==="condition"&&(r=r[2][n]);return r},m=a({characters:e,set:me,restore:R,save:K,newGame:le,stack:i,languages:l,t:s.i,$:h}),B=$({wait([r]){v||setTimeout(d,r)},showBackground([r]){m.background(r),d()},playMusic([r]){m.music(r,"music").play(),d()},stopMusic([r]){m.music(r,"music").stop(),d()},showCharacter([r,u,n,p]){let y=m.character(r);y.append(n,p),y.withEmotion(u)(),d()},hideCharacter([r,u,n,p]){m.character(r).remove(u,n,p)(d)},dialog([r,u,n]){m.dialog(k(u),r,n)(_)},function([r]){let u=r();return v||(u?u.then(d):d()),u},choice(r){let u=r.map(([n,p,y])=>[k(n),p,y]);m.choices(u)(n=>{H(),i.value[0].push(["choice",n],[null,0]),P()})},jump([r]){i.value[0]=[[null,r],[null,0]],m.clear(!1)(()=>{v||P()})},clear(){try{navigator.vibrate(0)}finally{m.clear(E)(d)}},condition([r]){let u=r();v||(i.value[0].push(["condition",u],[null,0]),P())},end(){K(!1,"auto"),B("clear",[]),m.ui.showScreen("mainmenu")},input([r,u,n]){m.input(r,u,n)(_)},custom([r]){return m.custom(r,E,()=>{!v&&r.requireUserAction&&H(),v||d()})},vibrate(r){try{navigator.vibrate(r)}finally{d()}},next(){d()},animateCharacter([r,u,...n]){let p=()=>{let y=m.store.characters[r];if(!y)return;let S=y.canvas;if(!S)return;let C=n.filter(g=>!S.classList.contains(g));S.classList.add(...C),setTimeout(()=>{S.classList.remove(...C)},u)};return p.callOnlyLatest=!0,m.custom(p,E,()=>{}),d()},text(r){m.text(r.map(k).join(" "),_)}}),H=()=>{if(v)return;let r=D(i.value);r[0]=D(i.value[0]),r[2][0]=new Date().valueOf(),r[2][1]="auto",i.push(r)},pe=()=>{let r=i.value[0][i.value[0].length-1];if(U(r[0])&&F(r[1])){r[1]=r[1]+1;return}i.value[0].push([null,0])},_=()=>{H(),d()},P=()=>{let r=fe();if(r){let[u,...n]=r;B(u,n)}},d=()=>{v||(pe(),P())},k=r=>{let u=h.get().meta[0],n=q();return ae(typeof r=="function"?r(u,n):r,n)};return{withStory:x,action:w,render:P,state:q,t:s.t}};var oe=e=>({async get(){let t=localStorage.getItem(e.key);return t?JSON.parse(t):{saves:[],meta:[]}},async set(t){localStorage.setItem(e.key,JSON.stringify(t))}});return De(Ge);})();
1
+ "use strict";var Novely=(()=>{var de=Object.create;var D=Object.defineProperty;var ye=Object.getOwnPropertyDescriptor;var he=Object.getOwnPropertyNames;var ve=Object.getPrototypeOf,Se=Object.prototype.hasOwnProperty;var be=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),Ae=(t,e)=>{for(var n in e)D(t,n,{get:e[n],enumerable:!0})},q=(t,e,n,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of he(e))!Se.call(t,i)&&i!==n&&D(t,i,{get:()=>e[i],enumerable:!(s=ye(e,i))||s.enumerable});return t};var we=(t,e,n)=>(n=t!=null?de(ve(t)):{},q(e||!t||!t.__esModule?D(n,"default",{value:t,enumerable:!0}):n,t)),xe=t=>q(D({},"__esModule",{value:!0}),t);var ee=be((Be,Z)=>{"use strict";var Pe=function(e){return Ce(e)&&!Oe(e)};function Ce(t){return!!t&&typeof t=="object"}function Oe(t){var e=Object.prototype.toString.call(t);return e==="[object RegExp]"||e==="[object Date]"||je(t)}var Me=typeof Symbol=="function"&&Symbol.for,Te=Me?Symbol.for("react.element"):60103;function je(t){return t.$$typeof===Te}function Re(t){return Array.isArray(t)?[]:{}}function T(t,e){return e.clone!==!1&&e.isMergeableObject(t)?x(Re(t),t,e):t}function Ee(t,e,n){return t.concat(e).map(function(s){return T(s,n)})}function De(t,e){if(!e.customMerge)return x;var n=e.customMerge(t);return typeof n=="function"?n:x}function Ie(t){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(t).filter(function(e){return Object.propertyIsEnumerable.call(t,e)}):[]}function z(t){return Object.keys(t).concat(Ie(t))}function X(t,e){try{return e in t}catch{return!1}}function Ne(t,e){return X(t,e)&&!(Object.hasOwnProperty.call(t,e)&&Object.propertyIsEnumerable.call(t,e))}function Le(t,e,n){var s={};return n.isMergeableObject(t)&&z(t).forEach(function(i){s[i]=T(t[i],n)}),z(e).forEach(function(i){Ne(t,i)||(X(t,i)&&n.isMergeableObject(e[i])?s[i]=De(i,n)(t[i],e[i],n):s[i]=T(e[i],n))}),s}function x(t,e,n){n=n||{},n.arrayMerge=n.arrayMerge||Ee,n.isMergeableObject=n.isMergeableObject||Pe,n.cloneUnlessOtherwiseSpecified=T;var s=Array.isArray(e),i=Array.isArray(t),d=s===i;return d?s?n.arrayMerge(t,e,n):Le(t,e,n):T(e,n)}x.all=function(e,n){if(!Array.isArray(e))throw new Error("first argument should be an array");return e.reduce(function(s,i){return x(s,i,n)},{})};var ke=x;Z.exports=ke});var _e={};Ae(_e,{localStorageStorage:()=>ae,novely:()=>ne});var B=t=>(e,n)=>t[e](n),I=t=>typeof t=="number",k=t=>t===null,K=t=>typeof t=="string",$=t=>{let e=String.prototype.startsWith.bind(t);return e("http")||e("/")||e(".")||e("data")},_=t=>String(t),J=(t,e)=>t==="custom"&&e[0]&&e[0].requireUserAction,W=(t,e=navigator.language)=>(e=e.substring(0,2),t.includes(e)||(e=t[0]),e),Q=(t,e)=>{let n=!1,s,i;function d(){if(n){s=arguments,i=this;return}t.apply(this,arguments),n=!1}return setTimeout(function(){n=!1,s&&(d.apply(i,s),s=i=null)},e),d};var Y=(t,e=new Set)=>{let n=h=>(e.add(h),h(t),()=>{e.delete(h)}),s=h=>{e.forEach(P=>P(h))};return{subscribe:n,update:h=>{s(t=h(t))},get:()=>t}};var re=we(ee(),1);function A(t){var e,n,s;if(Array.isArray(t)){for(n=Array(e=t.length);e--;)n[e]=(s=t[e])&&typeof s=="object"?A(s):s;return n}if(Object.prototype.toString.call(t)==="[object Object]"){n={};for(e in t)e==="__proto__"?Object.defineProperty(n,e,{value:A(t[e]),configurable:!0,enumerable:!0,writable:!0}):n[e]=(s=t[e])&&typeof s=="object"?A(s):s;return n}return t}var te=new Set(["dialog","input","vibrate"]),$e=[[[null,"start"],[null,0]],{},[Date.now(),"auto"]],N=(t,e=navigator.language)=>(e=e.substring(0,2),t.includes(e)||(e=t[0]),[[[null,"start"],[null,0]],{},[Date.now(),"auto"]]);var ne=async({characters:t,storage:e,renderer:n,initialScreen:s="mainmenu",t9n:i,languages:d,assetsPreload:h})=>{let P,oe=r=>{P=r,me()},U={background:new Set},se=new Proxy({},{get(r,o){return(...a)=>(o==="showBackground"&&$(a[0])&&U.background.add(a[0]),[o,...a])}});function G(r){if(!r)return c.value[1];let o=c.value[1],a=typeof r=="function"?r(o):(0,re.all)([o,r]);c.value[1]=a}let ie=(r,o=[r])=>({get value(){return o.at(-1)},set value(a){o[o.length-1]=a},back(){o.length>1&&(o.pop(),C=!0)},push(a){o.push(a)},clear(){o=[N(d,v.get().meta[0])]}}),v=Y(await e.get()),ce=Q(r=>e.set(r),120);v.subscribe(ce);let L=(r=>r.saves.length>0&&r.saves.at(-1))(v.get())||N(d,v.get().meta[0]),c=ie(L),H=async(r=!1,o=r?"auto":"manual")=>{let a=await e.get(),g=c.value[2][0],f=a.saves.findIndex(M=>M[2][0]===g)===a.saves.length-1;return c.value[2][0]=Date.now(),c.value[2][1]=o,r&&f?a.saves[a.saves.length-1]=c.value:a.saves.push(c.value),await e.set(a)},ue=()=>{v.update(r=>{let o=N(d,v.get().meta[0]);return r.saves.push(o),j(o),r})},le=r=>(c.value=r,j(r)),y=!1,C=!1,j=async r=>{let o=r||await e.get().then(m=>m.saves.at(-1));o||(await e.set({saves:[L],meta:[W(d)]}),o=A(L)),y=!0,c.value=o,u.ui.showScreen("game"),O("clear",[C]);let a=P,g=0,f=c.value[0].reduce((m,[l,S])=>k(l)&&I(S)?m+1:m,0),M=[];for(let[m,l]of c.value[0])if(m===null){if(K(l))a=a[l];else if(I(l)){g++;for(let S=0;S<l;S++){let[b,...E]=a[S];if(te.has(b)||J(b,E))if(g===f&&S===l)M.push([b,E]);else continue;M.push([b,E])}a=a[l]}}else m==="choice"?a=a[l+1][1]:m==="condition"&&(a=a[2][l]);let V=M.map((m,l)=>m.concat(l));for await(let[m,l,S]of V)if(m==="function"||m==="custom"){if(m==="custom"&&l[0].callOnlyLatest&&!!V.slice(S+1).some(([He,ge])=>_(ge[0])===_(l[0])))continue;let b=O(m,l);b&&"then"in b&&await b}else O(m,l);y=!1,C=!1,w()},fe=()=>{let r=P;for(let[o,a]of c.value[0])o===null?r=r[a]:o==="choice"?r=r[a+1][1]:o==="condition"&&(r=r[2][a]);return r},u=n({characters:t,storage:e,set:le,restore:j,save:H,newGame:ue,stack:c,languages:d,t:i.i,$:v}),me=()=>{if(!h){s==="game"?j():u.ui.showScreen(s);return}let r=[];u.ui.showScreen("loading");for(let[o,{emotions:a}]of Object.entries(t))for(let g of Object.keys(a))r.push(Promise.resolve(u.character(o).withEmotion(g)));for(let o of U.background)r.push(new Promise((a,g)=>{let f=document.createElement("img");f.crossOrigin="*",f.src=o,f.complete&&f.naturalHeight!==0?a(void 0):(f.onload=a,f.onerror=g)}));Promise.all(r).then(()=>{u.ui.showScreen(s)})},O=B({wait([r]){y||setTimeout(p,r)},showBackground([r]){u.background(r),p()},playMusic([r]){u.music(r,"music").play(),p()},stopMusic([r]){u.music(r,"music").stop(),p()},showCharacter([r,o,a,g]){let f=u.character(r);f.append(a,g),f.withEmotion(o)(),p()},hideCharacter([r,o,a,g]){u.character(r).remove(o,a,g)(p)},dialog([r,o,a]){u.dialog(F(o),r,a)(()=>{R(),p()})},function([r]){let o=r();return y||(o?o.then(p):p()),o},choice(r){let o=r.map(([a,g,f])=>[F(a),g,f]);u.choices(o)(a=>{R(),c.value[0].push(["choice",a],[null,0]),w()})},jump([r]){c.value[0]=[[null,r],[null,0]],u.clear(!1)(()=>{y||w()})},clear(){try{navigator.vibrate(0)}finally{u.clear(C)(p)}},condition([r]){let o=r();y||(c.value[0].push(["condition",o],[null,0]),w())},end(){H(!1,"auto").then(()=>{O("clear",[]),u.ui.showScreen("mainmenu")})},input([r,o,a]){u.input(r,o,a)(()=>{R(),p()})},custom([r]){return u.custom(r,C,()=>{!y&&r.requireUserAction&&R(),y||p()})},vibrate(r){navigator.vibrate(r),p()},next(){p()}}),R=()=>{if(y)return;let r=A(c.value);r[0]=A(c.value[0]),r[2][0]=new Date().valueOf(),r[2][1]="auto",c.push(r)},pe=()=>{let r=c.value[0][c.value[0].length-1];if(k(r[0])&&I(r[1])){r[1]=r[1]+1;return}c.value[0].push([null,0])},w=()=>{let r=fe();if(r){let[o,...a]=r;O(o,a)}},p=()=>{y||(pe(),w())},F=r=>typeof r=="function"?r(v.get().meta[0],G()):r;return{withStory:oe,action:se,render:w,state:G,t:i.t}};var ae=t=>({async get(){let e=localStorage.getItem(t.key);return e?JSON.parse(e):{saves:[],meta:[]}},async set(e){localStorage.setItem(t.key,JSON.stringify(e))}});return xe(_e);})();
2
2
  //# sourceMappingURL=index.global.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../node_modules/.pnpm/deepmerge@4.3.0/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/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, CustomHandler, CustomHandlerGetResult, CustomHandlerGetResultDataFunction } 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 } 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 { Save, 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 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 getDefaultSave = () => {\n return [[[null, 'start'], [null, 0]], {}, [Date.now(), 'auto']] as Save;\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() {\n if (throttled) {\n savedArgs = arguments;\n // @ts-ignore\n savedThis = this;\n\n return;\n }\n\n // @ts-ignore\n fn.apply(this, arguments);\n\n throttled = false;\n }\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 return wrapper as unknown as (...args: Parameters<Fn>) => void;\n}\n\nexport { matchAction, isNumber, isNull, isString, isCSSImage, str, isUserRequiredAction, getDefaultSave, getLanguage, throttle }","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, DialogContent, ChoiceContent, CustomHandler } from './action';\nimport type { Storage } from './storage';\nimport type { Save, State, StorageData } from './types'\nimport type { Renderer, RendererInit } from './renderer'\nimport type { SetupT9N } from '@novely/t9n'\nimport { matchAction, isNumber, isNull, isString, str, isUserRequiredAction, getDefaultSave, getLanguage, throttle } 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>>> {\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 * 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?: \"mainmenu\" | \"game\" | \"saves\" | \"settings\";\n /**\n * An object containing the translation functions used in the game\n */\n t9n: Inter;\n /**\n * An optional property that specifies whether the game should use a single save.\n */\n singleSave?: boolean;\n}\n\nconst novely = <Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends ReturnType<SetupT9N<Languages>>>({ characters, storage, renderer: createRenderer, initialScreen = \"mainmenu\", t9n, languages }: NovelyInit<Languages, Characters, Inter>) => {\n let story: Story;\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: State | ((prev: State) => State)): void;\n function state(): State;\n function state(value?: State | ((prev: State) => State)): State | void {\n if (!value) return stack.value[1]\n\n const prev = stack.value[1];\n const val = typeof value === 'function' ? value(prev as State) : deepmerge([prev, value]);\n\n stack.value[1] = val as State;\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()];\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)]\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 storage.get().then(stored => {\n /**\n * Default `localStorageStorage` cannot determine preferred language, and returns empty array\n */\n stored.meta[0] ||= getLanguage(languages);\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 const initial = ((value) => value.saves.length > 0 && value.saves.at(-1))($.get()) || getDefaultSave();\n const stack = createStack(initial);\n\n const save = (override = false, type: Save[2][1] = override ? 'auto' : 'manual') => {\n if (!initialDataLoaded) return;\n\n $.update(prev => {\n const date = stack.value[2][0];\n const isLatest = prev.saves.findIndex(value => value[2][0] === date) === prev.saves.length - 1;\n\n /**\n * Обновим дату и тип\n */\n stack.value[2][0] = Date.now();\n stack.value[2][1] = type;\n\n if (override) {\n /**\n * Перезапишем\n */\n if (isLatest) {\n /**\n * Сохранения хранятся в массиве. Нельзя перезаписать любое последнее\n * \n * Если перезаписывать старое сохранение, то они не будут идти в хронологическом порядке\n */\n prev.saves[prev.saves.length - 1] = stack.value;\n } else {\n prev.saves.push(stack.value);\n }\n } else {\n /**\n * Добавляем текущее сохранение\n */\n prev.saves.push(stack.value);\n }\n\n /**\n * Устанавливаем новое значение\n */\n return prev;\n });\n }\n\n const newGame = () => {\n if (!initialDataLoaded) return;\n\n const save = getDefaultSave();\n\n $.update(prev => {\n prev.saves.push(save), restore(save);\n\n return prev;\n });\n }\n\n /**\n * Устанавливает сохранение\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\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)] }));\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 [ValidAction[0], 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 latest = !next.some(([_action, _meta]) => str(_meta[0]) === str(meta[0]));\n\n if (!latest) 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 {\n match(action as keyof ActionProxyProvider<Record<string, Character<string>>>, meta);\n }\n }\n\n restoring = false, 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 renderer = createRenderer({\n characters,\n set,\n restore,\n save,\n newGame,\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, 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);\n handle.withEmotion(emotion)();\n\n push()\n },\n hideCharacter([character, className, style, duration]) {\n const handle = renderer.character(character);\n\n handle.remove(className, style, duration)(push);\n },\n dialog([person, content, emotion]) {\n renderer.dialog(unwrap(content), person, emotion)(forward);\n },\n function([fn]) {\n const result = fn();\n\n if (!restoring) result ? result.then(push) : push();\n\n return result;\n },\n choice(choices) {\n const unwrapped = choices.map(([content, action, visible]) => {\n return [unwrap(content), action, visible] as [string, ValidAction[], () => boolean];\n });\n\n renderer.choices(unwrapped)((selected) => {\n enmemory();\n\n stack.value[0].push(['choice', selected], [null, 0]), render();\n });\n },\n jump([scene]) {\n stack.value[0] = [[null, scene], [null, 0]];\n\n renderer.clear(false)(() => {\n if (!restoring) render();\n })\n },\n clear() {\n try {\n navigator.vibrate(0)\n } finally {\n renderer.clear(goingBack)(push);\n }\n },\n condition([condition]) {\n const value = condition();\n\n if (!restoring) stack.value[0].push(['condition', value], [null, 0]), render();\n },\n end() {\n /**\n * Save Current Game\n */\n save(false, 'auto');\n /**\n * Clear the Scene\n */\n match('clear', []);\n /**\n * Go to the main menu\n */\n renderer.ui.showScreen('mainmenu');\n },\n input([question, onInput, setup]) {\n renderer.input(question, onInput, setup)(forward);\n },\n custom([handler]) {\n const result = renderer.custom(handler, goingBack, () => {\n if (!restoring && handler.requireUserAction) enmemory();\n if (!restoring) push();\n });\n\n return result;\n },\n vibrate(pattern) {\n try {\n navigator.vibrate(pattern)\n } finally {\n push()\n }\n },\n next() {\n push();\n },\n animateCharacter([character, timeout, ...classes]) {\n const handler: CustomHandler = () => {\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 setTimeout(() => {\n target.classList.remove(...classNames);\n }, timeout);\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 });\n\n const enmemory = () => {\n if (restoring) return;\n\n const current = klona(stack.value);\n\n current[0] = klona(stack.value[0]);\n\n current[2][0] = new Date().valueOf();\n current[2][1] = 'auto';\n\n stack.push(current);\n }\n\n const next = () => {\n /**\n * Последний элемент пути\n */\n const last = stack.value[0][stack.value[0].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 stack.value[0].push([null, 0]);\n }\n\n const forward = () => {\n enmemory();\n push();\n }\n\n const render = () => {\n const referred = refer();\n\n if (referred) {\n const [action, ...props] = referred;\n\n match(action, props);\n }\n }\n\n const push = () => {\n if (!restoring) next(), render();\n }\n\n const unwrap = (content: DialogContent | ChoiceContent) => {\n const lang = $.get().meta[0];\n const data = state();\n\n return replaceT9N(typeof content === 'function' ? content(lang, data) : content, data);\n }\n\n return {\n withStory,\n action,\n render,\n state,\n t: t9n.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 'input',\n 'vibrate',\n 'text'\n] as const);\n\nexport { SKIPPED_DURING_RESTORE }","import type { BaseTranslationStrings } from './translations';\n\ntype PluralType = Intl.LDMLPluralRule;\ntype FunctionalSetupT9N = <LanguageKey extends string, PluralKey extends string, StringKey extends string>(parameters: { [Lang in LanguageKey]: { pluralization: { [Plural in PluralKey]: Partial<Record<PluralType, string>> }; internal: { [Key in BaseTranslationStrings]: string }; strings: { [Str in StringKey]: string } } }) => T9N<LanguageKey, PluralKey, StringKey>\ntype SetupT9N<LanguageKey extends string> = <PluralKey extends string, StringKey extends string>(parameters: { [Lang in LanguageKey]: { pluralization: { [Plural in PluralKey]: Partial<Record<PluralType, string>> }; internal: { [Key in BaseTranslationStrings]: string }; strings: { [Str in StringKey]: string } } }) => T9N<LanguageKey, PluralKey, StringKey>\n\ntype T9N<LanguageKey extends string, _PluralKey extends string, StringKey extends string> = {\n t(key: StringKey): (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>>, pr?: Intl.PluralRules) => {\n return str.replace(RGX, (x: any, key: any, y: any) => {\n x = 0;\n y = obj;\n\n key = (key as string).trim();\n\n let at = (key as string).split('@');\n let plural: string | undefined;\n\n if (at.length > 1) {\n ([key, plural] = at);\n }\n\n key = (key as string).split('.');\n\n while (y && x < key.length) {\n y = y[key[x++]];\n }\n\n if (plural && pluralization && pr && y) {\n y = pluralization[plural][pr!.select(y)];\n }\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 `(string & {})` cannot be used to index type `LanguageKey`.\n return replace(parameters[lang]['strings'][key], obj, parameters[lang]['pluralization']);\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};\n\nconst EN = {\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};\n\nconst JP = {\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};\n\ntype BaseTranslationStrings = keyof typeof RU;\n\nexport { RU, EN, JP }\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":["require_cjs","__commonJSMin","exports","module","isMergeableObject","value","isNonNullObject","isSpecial","stringValue","isReactElement","canUseSymbol","REACT_ELEMENT_TYPE","emptyTarget","val","cloneUnlessOtherwiseSpecified","options","deepmerge","defaultArrayMerge","target","source","element","getMergeFunction","key","customMerge","getEnumerableOwnPropertySymbols","symbol","getKeys","propertyIsOnObject","object","property","propertyIsUnsafe","mergeObject","destination","sourceIsArray","targetIsArray","sourceAndTargetTypesMatch","array","prev","next","deepmerge_1","src_exports","__export","localStorageStorage","novely","matchAction","values","action","props","isNumber","val","isNull","isString","str","value","isUserRequiredAction","action","meta","getDefaultSave","getLanguage","languages","language","throttle","fn","ms","throttled","savedArgs","savedThis","wrapper","store","current","subscribers","subscribe","cb","push","value","fn","import_deepmerge","klona","val","k","out","tmp","SKIPPED_DURING_RESTORE","RGX","replace","str","obj","pluralization","pr","x","key","y","at","plural","novely","characters","storage","createRenderer","initialScreen","t9n","languages","story","withStory","s","name","items","flat","item","data","type","renderer","action","_","prop","props","state","value","stack","prev","val","deepmerge","createStack","current","goingBack","getDefaultSave","initialData","getLanguage","$","store","initialDataLoaded","throttledOnStorageDataChange","throttle","stored","restore","initial","save","override","date","isLatest","newGame","set","restoring","latest","klona","match","index","max","acc","isNull","isNumber","queue","isString","i","meta","SKIPPED_DURING_RESTORE","isUserRequiredAction","indexedQueue","_action","_meta","str","result","render","refer","matchAction","time","push","background","source","character","emotion","className","style","handle","duration","person","content","unwrap","forward","fn","choices","unwrapped","visible","selected","enmemory","scene","condition","question","onInput","setup","handler","pattern","timeout","classes","char","target","classNames","text","next","last","referred","lang","g","localStorageStorage","options","value","data"]}
1
+ {"version":3,"sources":["../../../node_modules/.pnpm/deepmerge@4.3.0/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","../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, CustomHandler, CustomHandlerGetResult, CustomHandlerGetResultDataFunction, CustomHandlerGetResultSkipClearOnGoingBackFunction } 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 } 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 { 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 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\n/**\n * Currently language system supports only 2-character values, like `en` or `ru`\n * todo: support language variations, such `en-GB`, `en-CA`, `en-AU`\n */\nconst getLanguage = (languages: string[], language = navigator.language) => {\n language = language.substring(0, 2);\n\n if (!languages.includes(language)) language = languages[0];\n\n return language;\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() {\n if (throttled) {\n savedArgs = arguments;\n // @ts-ignore\n savedThis = this;\n\n return;\n }\n\n // @ts-ignore\n fn.apply(this, arguments);\n\n throttled = false;\n }\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 return wrapper as unknown as (...args: Parameters<Fn>) => void;\n}\n\nexport { matchAction, isNumber, isNull, isString, isCSSImage, str, isUserRequiredAction, getLanguage, throttle }","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, DialogContent, ChoiceContent } from './action';\nimport type { Storage } from './storage';\nimport type { Save, State, StorageData } from './types'\nimport type { Renderer, RendererInit } from './renderer'\nimport type { SetupT9N } from '@novely/t9n'\nimport { matchAction, isNumber, isNull, isString, isCSSImage, str, isUserRequiredAction, getLanguage, throttle } from './utils';\nimport { store } from './store';\nimport { all as deepmerge } from 'deepmerge'\nimport { klona } from 'klona/json';\nimport { SKIPPED_DURING_RESTORE, getDefaultSave } from './constants';\n\ninterface NovelyInit<Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends ReturnType<SetupT9N<Languages>>> {\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 * 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?: \"mainmenu\" | \"game\" | \"saves\" | \"settings\";\n /**\n * An object containing the translation functions used in the game\n */\n t9n: Inter;\n /**\n * An optional property that specifies whether to preload assets when the game starts\n */\n assetsPreload?: boolean;\n /**\n * An optional property that specifies whether the game should use a single save.\n */\n singleSave?: boolean;\n}\n\ntype Novely = <Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends ReturnType<SetupT9N<Languages>>>(init: NovelyInit<Languages, Characters, Inter>) => {\n withStory: (s: Story) => void;\n action: ActionProxyProvider<Characters>;\n render: () => void;\n state: {\n (value: State | ((prev: State) => State)): void;\n (): State;\n };\n t: Inter['t'];\n}\n\n// @ts-ignore - Fuck ts\nconst novely: Novely = async ({ characters, storage, renderer: createRenderer, initialScreen = \"mainmenu\", t9n, languages, assetsPreload }) => {\n let story: Story;\n\n const withStory = (s: Story) => {\n story = s;\n /**\n * Load assets after the `action` scripts are executed\n */\n preloadAssets();\n }\n\n /**\n * This is used when background is loading\n */\n const preload = {\n background: new Set<string>(),\n }\n\n const action = new Proxy({}, {\n get(_, prop) {\n return (...props: Parameters<ActionProxyProvider<Record<string, Character>>[keyof ActionProxyProvider<Record<string, Character>>]>) => {\n if (prop === 'showBackground') {\n if (isCSSImage(props[0] as string)) preload.background.add(props[0] as string);\n }\n\n return [prop, ...props];\n }\n }\n });\n\n function state(value: State | ((prev: State) => State)): void;\n function state(): State;\n function state(value?: State | ((prev: State) => State)): State | void {\n if (!value) return stack.value[1]\n\n const prev = stack.value[1];\n const val = typeof value === 'function' ? value(prev as State) : deepmerge([prev, value]);\n\n stack.value[1] = val as State;\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(languages, $.get().meta[0])];\n }\n }\n }\n\n const $ = store(await storage.get());\n\n const onStorageDataChange = (value: StorageData) => storage.set(value);\n const throttledOnStorageDataChange = throttle(onStorageDataChange, 120);\n\n $.subscribe(throttledOnStorageDataChange);\n\n const initial = ((value) => value.saves.length > 0 && value.saves.at(-1))($.get()) || getDefaultSave(languages, $.get().meta[0]);\n const stack = createStack(initial);\n\n const save = async (override = false, type: Save[2][1] = override ? 'auto' : 'manual') => {\n /**\n * Получаем предыдущее значение\n */\n const prev = await storage.get();\n\n const date = stack.value[2][0];\n const isLatest = prev.saves.findIndex(value => value[2][0] === date) === prev.saves.length - 1;\n\n /**\n * Обновим дату и тип\n */\n stack.value[2][0] = Date.now();\n stack.value[2][1] = type;\n\n if (override) {\n /**\n * Перезапишем\n */\n if (isLatest) {\n /**\n * Сохранения хранятся в массиве. Нельзя перезаписать любое последнее\n * \n * Если перезаписывать старое сохранение, то они не будут идти в хронологическом порядке\n */\n prev.saves[prev.saves.length - 1] = stack.value;\n } else {\n prev.saves.push(stack.value);\n }\n } else {\n /**\n * Добавляем текущее сохранение\n */\n prev.saves.push(stack.value);\n }\n\n /**\n * Устанавливаем новое значение\n */\n return await storage.set(prev);\n }\n\n const newGame = () => {\n $.update(prev => {\n const save = getDefaultSave(languages, $.get().meta[0]);\n\n prev.saves.push(save), restore(save);\n\n return prev;\n });\n }\n\n /**\n * Устанавливает сохранение\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\n /**\n * Визуально восстанавливает историю\n */\n const restore = async (save?: Save) => {\n let latest = save ? save : await storage.get().then(value => value.saves.at(-1));\n\n /**\n * Если нет сохранённой игры, то запустим ту, которая уже есть\n */\n if (!latest) {\n await storage.set({ saves: [initial], meta: [getLanguage(languages)] });\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 [ValidAction[0], 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 latest = !next.some(([_action, _meta]) => str(_meta[0]) === str(meta[0]));\n\n if (!latest) 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 {\n match(action, meta);\n }\n }\n\n restoring = false, 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 renderer = createRenderer({\n characters,\n storage,\n set,\n restore,\n save,\n newGame,\n stack,\n languages,\n t: t9n.i,\n $\n });\n\n const preloadAssets = () => {\n if (!assetsPreload) {\n initialScreen === 'game' ? restore() : renderer.ui.showScreen(initialScreen);\n\n return;\n }\n\n /**\n * We need to load all the characters and their emotions\n */\n\n let promises: Promise<unknown>[] = [];\n\n renderer.ui.showScreen('loading');\n\n for (const [name, { emotions }] of Object.entries(characters)) {\n for (const emotion of Object.keys(emotions)) {\n promises.push(Promise.resolve(renderer.character(name).withEmotion(emotion)));\n }\n }\n\n for (const bg of preload.background) {\n promises.push(new Promise((res, rej) => {\n /**\n * Create `img` element\n */\n const img = document.createElement('img');\n\n /**\n * Set `src`\n */\n img.crossOrigin = '*';\n img.src = bg;\n\n if (img.complete && img.naturalHeight !== 0) {\n /**\n * Image is already loaded\n */\n res(void 0);\n } else {\n /**\n * Image is uniq, it is safe to use `onload`\n */\n img.onload = res;\n img.onerror = rej;\n }\n }));\n }\n\n Promise.all(promises).then(() => {\n renderer.ui.showScreen(initialScreen);\n });\n }\n\n const match = matchAction({\n wait([time]) {\n /**\n * `restoring` может поменяться на `true` перед тем как запуститься `push` из `setTimeout`\n */\n if (!restoring) setTimeout(push, 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);\n handle.withEmotion(emotion)();\n\n push()\n },\n hideCharacter([character, className, style, duration]) {\n const handle = renderer.character(character);\n\n handle.remove(className, style, duration)(push);\n },\n dialog([person, content, emotion]) {\n renderer.dialog(unwrap(content), person, emotion)(() => {\n enmemory();\n push();\n });\n },\n function([fn]) {\n const result = fn();\n\n if (!restoring) result ? result.then(push) : push();\n\n return result;\n },\n choice(choices) {\n const unwrapped = choices.map(([content, action, visible]) => {\n return [unwrap(content), action, visible] as [string, ValidAction[], () => boolean];\n });\n\n renderer.choices(unwrapped)((selected) => {\n enmemory();\n\n stack.value[0].push(['choice', selected], [null, 0]), render();\n });\n },\n jump([scene]) {\n stack.value[0] = [[null, scene], [null, 0]];\n\n renderer.clear(false)(() => {\n if (!restoring) render();\n })\n },\n clear() {\n try {\n navigator.vibrate(0)\n } finally {\n renderer.clear(goingBack)(push);\n }\n },\n condition([condition]) {\n const value = condition();\n\n if (!restoring) stack.value[0].push(['condition', value], [null, 0]), render();\n },\n end() {\n save(false, 'auto').then(() => {\n match('clear', []);\n\n renderer.ui.showScreen('mainmenu');\n });\n },\n input([question, onInput, setup]) {\n renderer.input(question, onInput, setup)(() => {\n enmemory();\n push();\n });\n },\n custom([handler]) {\n const result = renderer.custom(handler, goingBack, () => {\n if (!restoring && handler.requireUserAction) enmemory();\n if (!restoring) push();\n });\n\n return result;\n },\n vibrate(pattern) {\n navigator.vibrate(pattern), push();\n },\n next() {\n push();\n }\n });\n\n const enmemory = () => {\n if (restoring) return;\n\n const current = klona(stack.value);\n\n current[0] = klona(stack.value[0]);\n\n current[2][0] = new Date().valueOf();\n current[2][1] = 'auto';\n\n stack.push(current);\n }\n\n const next = () => {\n /**\n * Последний элемент пути\n */\n const last = stack.value[0][stack.value[0].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 stack.value[0].push([null, 0]);\n }\n\n const render = () => {\n const referred = refer();\n\n if (referred) {\n const [action, ...props] = referred;\n\n match(action, props);\n }\n }\n\n const push = () => {\n if (!restoring) next(), render();\n }\n\n const unwrap = (content: DialogContent | ChoiceContent) => {\n return typeof content === 'function' ? content($.get().meta[0], state()) : content\n }\n\n return {\n withStory,\n action,\n render,\n state,\n t: t9n.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","import type { Save } from './types'\n\nconst SKIPPED_DURING_RESTORE = new Set([\n 'dialog',\n 'input',\n 'vibrate'\n] as const);\n\nconst DEFAULT_SAVE: Save = [[[null, 'start'], [null, 0]], {}, [Date.now(), 'auto']];\n\n/**\n * Currently language system supports only 2-character values, like `en` or `ru`\n * \n * todo: support language variations, such `en-GB`, `en-CA`, `en-AU`\n */\nconst getDefaultSave = (languages: string[], language = navigator.language) => {\n language = language.substring(0, 2);\n\n if (!languages.includes(language)) language = languages[0];\n\n return [[[null, 'start'], [null, 0]], {}, [Date.now(), 'auto']] as Save;\n}\n\nexport { SKIPPED_DURING_RESTORE, DEFAULT_SAVE, getDefaultSave }","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":["require_cjs","__commonJSMin","exports","module","isMergeableObject","value","isNonNullObject","isSpecial","stringValue","isReactElement","canUseSymbol","REACT_ELEMENT_TYPE","emptyTarget","val","cloneUnlessOtherwiseSpecified","options","deepmerge","defaultArrayMerge","target","source","element","getMergeFunction","key","customMerge","getEnumerableOwnPropertySymbols","symbol","getKeys","propertyIsOnObject","object","property","propertyIsUnsafe","mergeObject","destination","sourceIsArray","targetIsArray","sourceAndTargetTypesMatch","array","prev","next","deepmerge_1","src_exports","__export","localStorageStorage","novely","matchAction","values","action","props","isNumber","val","isNull","isString","isCSSImage","str","startsWith","value","isUserRequiredAction","meta","getLanguage","languages","language","throttle","fn","ms","throttled","savedArgs","savedThis","wrapper","store","current","subscribers","subscribe","cb","push","value","fn","import_deepmerge","klona","val","k","out","tmp","SKIPPED_DURING_RESTORE","DEFAULT_SAVE","getDefaultSave","languages","language","novely","characters","storage","createRenderer","initialScreen","t9n","languages","assetsPreload","story","withStory","s","preloadAssets","preload","action","_","prop","props","isCSSImage","state","value","stack","prev","val","deepmerge","createStack","current","goingBack","getDefaultSave","$","store","throttledOnStorageDataChange","throttle","initial","save","override","type","date","isLatest","newGame","restore","set","restoring","latest","getLanguage","klona","renderer","match","index","max","acc","isNull","isNumber","queue","isString","i","meta","SKIPPED_DURING_RESTORE","isUserRequiredAction","indexedQueue","_action","_meta","str","result","render","refer","promises","name","emotions","emotion","bg","res","rej","img","matchAction","time","push","background","source","character","className","style","handle","duration","person","content","unwrap","enmemory","fn","choices","unwrapped","visible","selected","scene","condition","question","onInput","setup","handler","pattern","next","last","referred","localStorageStorage","options","value","data"]}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var j=a=>(n,f)=>a[n](f),M=a=>typeof a=="number",V=a=>a===null,F=a=>typeof a=="string";var G=a=>String(a),K=(a,n)=>a==="custom"&&n[0]&&n[0].requireUserAction,L=()=>[[[null,"start"],[null,0]],{},[Date.now(),"auto"]],I=(a,n=navigator.language)=>a.includes(n)||a.includes(n=n.substring(0,2))||(n=a.find(f=>navigator.languages.includes(f)))?n:a[0],B=(a,n)=>{let f=!1,g,C;function y(){if(f){g=arguments,C=this;return}a.apply(this,arguments),f=!1}return setTimeout(function(){f=!1,g&&(y.apply(C,g),g=C=null)},n),y};var J=(a,n=new Set)=>{let f=d=>(n.add(d),d(a),()=>{n.delete(d)}),g=d=>{n.forEach(k=>k(d))};return{subscribe:f,update:d=>{g(a=d(a))},get:()=>a}};import{all as at}from"deepmerge";import{klona as U}from"klona/json";var W=new Set(["dialog","input","vibrate","text"]);import{replace as nt}from"@novely/t9n";var ot=({characters:a,storage:n,renderer:f,initialScreen:g="mainmenu",t9n:C,languages:y})=>{let d,k=t=>{d=Object.fromEntries(Object.entries(t).map(([e,r])=>{let c=p=>p.flatMap(m=>{let A=m[0];return Array.isArray(A)?c(m):[m]});return[e,c(r)]})),g!=="game"&&s.ui.showScreen(g)},Q=new Proxy({},{get(t,e){return(...r)=>[e,...r]}});function _(t){if(!t)return o.value[1];let e=o.value[1],r=typeof t=="function"?t(e):at([e,t]);o.value[1]=r}let $=(t,e=[t])=>({get value(){return e.at(-1)},set value(r){e[e.length-1]=r},back(){e.length>1&&(e.pop(),P=!0)},push(r){e.push(r)},clear(){e=[L()]}}),z={saves:[],meta:[I(y)]},v=J(z),w=!1,X=B(t=>{w&&n.set(t)},120);v.subscribe(X),n.get().then(t=>{t.meta[0]||=I(y),w=!0,v.update(()=>t),g==="game"&&D()});let N=(t=>t.saves.length>0&&t.saves.at(-1))(v.get())||L(),o=$(N),q=(t=!1,e=t?"auto":"manual")=>{w&&v.update(r=>{let c=o.value[2][0],p=r.saves.findIndex(m=>m[2][0]===c)===r.saves.length-1;return o.value[2][0]=Date.now(),o.value[2][1]=e,t&&p?r.saves[r.saves.length-1]=o.value:r.saves.push(o.value),r})},Y=()=>{if(!w)return;let t=L();v.update(e=>(e.saves.push(t),D(t),e))},Z=t=>(o.value=t,D(t)),h=!1,P=!1,D=async t=>{if(!w)return;let e=t||v.get().saves.at(-1);e||(v.update(()=>({saves:[N],meta:[I(y)]})),e=U(N)),h=!0,o.value=e,s.ui.showScreen("game"),R("clear",[P]);let r=d,c=0,p=o.value[0].reduce((u,[i,S])=>V(i)&&M(S)?u+1:u,0),m=[];for(let[u,i]of o.value[0])if(u===null){if(F(i))r=r[i];else if(M(i)){c++;for(let S=0;S<i;S++){let[x,...b]=r[S];if(W.has(x)||K(x,b))if(c===p&&S===i)m.push([x,b]);else continue;m.push([x,b])}r=r[i]}}else u==="choice"?r=r[i+1][1]:u==="condition"&&(r=r[2][i]);let A=m.map((u,i)=>u.concat(i));for await(let[u,i,S]of A)if(u==="function"||u==="custom"){if(u==="custom"&&i[0].callOnlyLatest&&!!A.slice(S+1).some(([ut,rt])=>G(rt[0])===G(i[0])))continue;let x=R(u,i);x&&"then"in x&&await x}else R(u,i);h=!1,P=!1,T()},tt=()=>{let t=d;for(let[e,r]of o.value[0])e===null?t=t[r]:e==="choice"?t=t[r+1][1]:e==="condition"&&(t=t[2][r]);return t},s=f({characters:a,set:Z,restore:D,save:q,newGame:Y,stack:o,languages:y,t:C.i,$:v}),R=j({wait([t]){h||setTimeout(l,t)},showBackground([t]){s.background(t),l()},playMusic([t]){s.music(t,"music").play(),l()},stopMusic([t]){s.music(t,"music").stop(),l()},showCharacter([t,e,r,c]){let p=s.character(t);p.append(r,c),p.withEmotion(e)(),l()},hideCharacter([t,e,r,c]){s.character(t).remove(e,r,c)(l)},dialog([t,e,r]){s.dialog(H(e),t,r)(E)},function([t]){let e=t();return h||(e?e.then(l):l()),e},choice(t){let e=t.map(([r,c,p])=>[H(r),c,p]);s.choices(e)(r=>{O(),o.value[0].push(["choice",r],[null,0]),T()})},jump([t]){o.value[0]=[[null,t],[null,0]],s.clear(!1)(()=>{h||T()})},clear(){try{navigator.vibrate(0)}finally{s.clear(P)(l)}},condition([t]){let e=t();h||(o.value[0].push(["condition",e],[null,0]),T())},end(){q(!1,"auto"),R("clear",[]),s.ui.showScreen("mainmenu")},input([t,e,r]){s.input(t,e,r)(E)},custom([t]){return s.custom(t,P,()=>{!h&&t.requireUserAction&&O(),h||l()})},vibrate(t){try{navigator.vibrate(t)}finally{l()}},next(){l()},animateCharacter([t,e,...r]){let c=()=>{let p=s.store.characters[t];if(!p)return;let m=p.canvas;if(!m)return;let A=r.filter(u=>!m.classList.contains(u));m.classList.add(...A),setTimeout(()=>{m.classList.remove(...A)},e)};return c.callOnlyLatest=!0,s.custom(c,P,()=>{}),l()},text(t){s.text(t.map(H).join(" "),E)}}),O=()=>{if(h)return;let t=U(o.value);t[0]=U(o.value[0]),t[2][0]=new Date().valueOf(),t[2][1]="auto",o.push(t)},et=()=>{let t=o.value[0][o.value[0].length-1];if(V(t[0])&&M(t[1])){t[1]=t[1]+1;return}o.value[0].push([null,0])},E=()=>{O(),l()},T=()=>{let t=tt();if(t){let[e,...r]=t;R(e,r)}},l=()=>{h||(et(),T())},H=t=>{let e=v.get().meta[0],r=_();return nt(typeof t=="function"?t(e,r):t,r)};return{withStory:k,action:Q,render:T,state:_,t:C.t}};var st=a=>({async get(){let n=localStorage.getItem(a.key);return n?JSON.parse(n):{saves:[],meta:[]}},async set(n){localStorage.setItem(a.key,JSON.stringify(n))}});export{st as localStorageStorage,ot as novely};
1
+ var F=a=>(n,f)=>a[n](f),k=a=>typeof a=="number",L=a=>a===null,V=a=>typeof a=="string",q=a=>{let n=String.prototype.startsWith.bind(a);return n("http")||n("/")||n(".")||n("data")},N=a=>String(a),B=(a,n)=>a==="custom"&&n[0]&&n[0].requireUserAction,K=(a,n=navigator.language)=>(n=n.substring(0,2),a.includes(n)||(n=a[0]),n),j=(a,n)=>{let f=!1,m,x;function g(){if(f){m=arguments,x=this;return}a.apply(this,arguments),f=!1}return setTimeout(function(){f=!1,m&&(g.apply(x,m),m=x=null)},n),g};var J=(a,n=new Set)=>{let f=v=>(n.add(v),v(a),()=>{n.delete(v)}),m=v=>{n.forEach(w=>w(v))};return{subscribe:f,update:v=>{m(a=v(a))},get:()=>a}};import{all as ae}from"deepmerge";import{klona as E}from"klona/json";var W=new Set(["dialog","input","vibrate"]),me=[[[null,"start"],[null,0]],{},[Date.now(),"auto"]],M=(a,n=navigator.language)=>(n=n.substring(0,2),a.includes(n)||(n=a[0]),[[[null,"start"],[null,0]],{},[Date.now(),"auto"]]);var oe=async({characters:a,storage:n,renderer:f,initialScreen:m="mainmenu",t9n:x,languages:g,assetsPreload:v})=>{let w,Q=e=>{w=e,te()},O={background:new Set},$=new Proxy({},{get(e,r){return(...t)=>(r==="showBackground"&&q(t[0])&&O.background.add(t[0]),[r,...t])}});function G(e){if(!e)return o.value[1];let r=o.value[1],t=typeof e=="function"?e(r):ae([r,e]);o.value[1]=t}let z=(e,r=[e])=>({get value(){return r.at(-1)},set value(t){r[r.length-1]=t},back(){r.length>1&&(r.pop(),P=!0)},push(t){r.push(t)},clear(){r=[M(g,h.get().meta[0])]}}),h=J(await n.get()),X=j(e=>n.set(e),120);h.subscribe(X);let I=(e=>e.saves.length>0&&e.saves.at(-1))(h.get())||M(g,h.get().meta[0]),o=z(I),H=async(e=!1,r=e?"auto":"manual")=>{let t=await n.get(),p=o.value[2][0],c=t.saves.findIndex(b=>b[2][0]===p)===t.saves.length-1;return o.value[2][0]=Date.now(),o.value[2][1]=r,e&&c?t.saves[t.saves.length-1]=o.value:t.saves.push(o.value),await n.set(t)},Y=()=>{h.update(e=>{let r=M(g,h.get().meta[0]);return e.saves.push(r),T(r),e})},Z=e=>(o.value=e,T(e)),d=!1,P=!1,T=async e=>{let r=e||await n.get().then(u=>u.saves.at(-1));r||(await n.set({saves:[I],meta:[K(g)]}),r=E(I)),d=!0,o.value=r,s.ui.showScreen("game"),A("clear",[P]);let t=w,p=0,c=o.value[0].reduce((u,[i,y])=>L(i)&&k(y)?u+1:u,0),b=[];for(let[u,i]of o.value[0])if(u===null){if(V(i))t=t[i];else if(k(i)){p++;for(let y=0;y<i;y++){let[S,...D]=t[y];if(W.has(S)||B(S,D))if(p===c&&y===i)b.push([S,D]);else continue;b.push([S,D])}t=t[i]}}else u==="choice"?t=t[i+1][1]:u==="condition"&&(t=t[2][i]);let _=b.map((u,i)=>u.concat(i));for await(let[u,i,y]of _)if(u==="function"||u==="custom"){if(u==="custom"&&i[0].callOnlyLatest&&!!_.slice(y+1).some(([ue,ne])=>N(ne[0])===N(i[0])))continue;let S=A(u,i);S&&"then"in S&&await S}else A(u,i);d=!1,P=!1,C()},ee=()=>{let e=w;for(let[r,t]of o.value[0])r===null?e=e[t]:r==="choice"?e=e[t+1][1]:r==="condition"&&(e=e[2][t]);return e},s=f({characters:a,storage:n,set:Z,restore:T,save:H,newGame:Y,stack:o,languages:g,t:x.i,$:h}),te=()=>{if(!v){m==="game"?T():s.ui.showScreen(m);return}let e=[];s.ui.showScreen("loading");for(let[r,{emotions:t}]of Object.entries(a))for(let p of Object.keys(t))e.push(Promise.resolve(s.character(r).withEmotion(p)));for(let r of O.background)e.push(new Promise((t,p)=>{let c=document.createElement("img");c.crossOrigin="*",c.src=r,c.complete&&c.naturalHeight!==0?t(void 0):(c.onload=t,c.onerror=p)}));Promise.all(e).then(()=>{s.ui.showScreen(m)})},A=F({wait([e]){d||setTimeout(l,e)},showBackground([e]){s.background(e),l()},playMusic([e]){s.music(e,"music").play(),l()},stopMusic([e]){s.music(e,"music").stop(),l()},showCharacter([e,r,t,p]){let c=s.character(e);c.append(t,p),c.withEmotion(r)(),l()},hideCharacter([e,r,t,p]){s.character(e).remove(r,t,p)(l)},dialog([e,r,t]){s.dialog(U(r),e,t)(()=>{R(),l()})},function([e]){let r=e();return d||(r?r.then(l):l()),r},choice(e){let r=e.map(([t,p,c])=>[U(t),p,c]);s.choices(r)(t=>{R(),o.value[0].push(["choice",t],[null,0]),C()})},jump([e]){o.value[0]=[[null,e],[null,0]],s.clear(!1)(()=>{d||C()})},clear(){try{navigator.vibrate(0)}finally{s.clear(P)(l)}},condition([e]){let r=e();d||(o.value[0].push(["condition",r],[null,0]),C())},end(){H(!1,"auto").then(()=>{A("clear",[]),s.ui.showScreen("mainmenu")})},input([e,r,t]){s.input(e,r,t)(()=>{R(),l()})},custom([e]){return s.custom(e,P,()=>{!d&&e.requireUserAction&&R(),d||l()})},vibrate(e){navigator.vibrate(e),l()},next(){l()}}),R=()=>{if(d)return;let e=E(o.value);e[0]=E(o.value[0]),e[2][0]=new Date().valueOf(),e[2][1]="auto",o.push(e)},re=()=>{let e=o.value[0][o.value[0].length-1];if(L(e[0])&&k(e[1])){e[1]=e[1]+1;return}o.value[0].push([null,0])},C=()=>{let e=ee();if(e){let[r,...t]=e;A(r,t)}},l=()=>{d||(re(),C())},U=e=>typeof e=="function"?e(h.get().meta[0],G()):e;return{withStory:Q,action:$,render:C,state:G,t:x.t}};var se=a=>({async get(){let n=localStorage.getItem(a.key);return n?JSON.parse(n):{saves:[],meta:[]}},async set(n){localStorage.setItem(a.key,JSON.stringify(n))}});export{se as localStorageStorage,oe as novely};
2
2
  //# sourceMappingURL=index.js.map
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 { Save, 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 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 getDefaultSave = () => {\n return [[[null, 'start'], [null, 0]], {}, [Date.now(), 'auto']] as Save;\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() {\n if (throttled) {\n savedArgs = arguments;\n // @ts-ignore\n savedThis = this;\n\n return;\n }\n\n // @ts-ignore\n fn.apply(this, arguments);\n\n throttled = false;\n }\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 return wrapper as unknown as (...args: Parameters<Fn>) => void;\n}\n\nexport { matchAction, isNumber, isNull, isString, isCSSImage, str, isUserRequiredAction, getDefaultSave, getLanguage, throttle }","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, DialogContent, ChoiceContent, CustomHandler } from './action';\nimport type { Storage } from './storage';\nimport type { Save, State, StorageData } from './types'\nimport type { Renderer, RendererInit } from './renderer'\nimport type { SetupT9N } from '@novely/t9n'\nimport { matchAction, isNumber, isNull, isString, str, isUserRequiredAction, getDefaultSave, getLanguage, throttle } 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>>> {\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 * 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?: \"mainmenu\" | \"game\" | \"saves\" | \"settings\";\n /**\n * An object containing the translation functions used in the game\n */\n t9n: Inter;\n /**\n * An optional property that specifies whether the game should use a single save.\n */\n singleSave?: boolean;\n}\n\nconst novely = <Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends ReturnType<SetupT9N<Languages>>>({ characters, storage, renderer: createRenderer, initialScreen = \"mainmenu\", t9n, languages }: NovelyInit<Languages, Characters, Inter>) => {\n let story: Story;\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: State | ((prev: State) => State)): void;\n function state(): State;\n function state(value?: State | ((prev: State) => State)): State | void {\n if (!value) return stack.value[1]\n\n const prev = stack.value[1];\n const val = typeof value === 'function' ? value(prev as State) : deepmerge([prev, value]);\n\n stack.value[1] = val as State;\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()];\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)]\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 storage.get().then(stored => {\n /**\n * Default `localStorageStorage` cannot determine preferred language, and returns empty array\n */\n stored.meta[0] ||= getLanguage(languages);\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 const initial = ((value) => value.saves.length > 0 && value.saves.at(-1))($.get()) || getDefaultSave();\n const stack = createStack(initial);\n\n const save = (override = false, type: Save[2][1] = override ? 'auto' : 'manual') => {\n if (!initialDataLoaded) return;\n\n $.update(prev => {\n const date = stack.value[2][0];\n const isLatest = prev.saves.findIndex(value => value[2][0] === date) === prev.saves.length - 1;\n\n /**\n * Обновим дату и тип\n */\n stack.value[2][0] = Date.now();\n stack.value[2][1] = type;\n\n if (override) {\n /**\n * Перезапишем\n */\n if (isLatest) {\n /**\n * Сохранения хранятся в массиве. Нельзя перезаписать любое последнее\n * \n * Если перезаписывать старое сохранение, то они не будут идти в хронологическом порядке\n */\n prev.saves[prev.saves.length - 1] = stack.value;\n } else {\n prev.saves.push(stack.value);\n }\n } else {\n /**\n * Добавляем текущее сохранение\n */\n prev.saves.push(stack.value);\n }\n\n /**\n * Устанавливаем новое значение\n */\n return prev;\n });\n }\n\n const newGame = () => {\n if (!initialDataLoaded) return;\n\n const save = getDefaultSave();\n\n $.update(prev => {\n prev.saves.push(save), restore(save);\n\n return prev;\n });\n }\n\n /**\n * Устанавливает сохранение\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\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)] }));\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 [ValidAction[0], 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 latest = !next.some(([_action, _meta]) => str(_meta[0]) === str(meta[0]));\n\n if (!latest) 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 {\n match(action as keyof ActionProxyProvider<Record<string, Character<string>>>, meta);\n }\n }\n\n restoring = false, 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 renderer = createRenderer({\n characters,\n set,\n restore,\n save,\n newGame,\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, 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);\n handle.withEmotion(emotion)();\n\n push()\n },\n hideCharacter([character, className, style, duration]) {\n const handle = renderer.character(character);\n\n handle.remove(className, style, duration)(push);\n },\n dialog([person, content, emotion]) {\n renderer.dialog(unwrap(content), person, emotion)(forward);\n },\n function([fn]) {\n const result = fn();\n\n if (!restoring) result ? result.then(push) : push();\n\n return result;\n },\n choice(choices) {\n const unwrapped = choices.map(([content, action, visible]) => {\n return [unwrap(content), action, visible] as [string, ValidAction[], () => boolean];\n });\n\n renderer.choices(unwrapped)((selected) => {\n enmemory();\n\n stack.value[0].push(['choice', selected], [null, 0]), render();\n });\n },\n jump([scene]) {\n stack.value[0] = [[null, scene], [null, 0]];\n\n renderer.clear(false)(() => {\n if (!restoring) render();\n })\n },\n clear() {\n try {\n navigator.vibrate(0)\n } finally {\n renderer.clear(goingBack)(push);\n }\n },\n condition([condition]) {\n const value = condition();\n\n if (!restoring) stack.value[0].push(['condition', value], [null, 0]), render();\n },\n end() {\n /**\n * Save Current Game\n */\n save(false, 'auto');\n /**\n * Clear the Scene\n */\n match('clear', []);\n /**\n * Go to the main menu\n */\n renderer.ui.showScreen('mainmenu');\n },\n input([question, onInput, setup]) {\n renderer.input(question, onInput, setup)(forward);\n },\n custom([handler]) {\n const result = renderer.custom(handler, goingBack, () => {\n if (!restoring && handler.requireUserAction) enmemory();\n if (!restoring) push();\n });\n\n return result;\n },\n vibrate(pattern) {\n try {\n navigator.vibrate(pattern)\n } finally {\n push()\n }\n },\n next() {\n push();\n },\n animateCharacter([character, timeout, ...classes]) {\n const handler: CustomHandler = () => {\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 setTimeout(() => {\n target.classList.remove(...classNames);\n }, timeout);\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 });\n\n const enmemory = () => {\n if (restoring) return;\n\n const current = klona(stack.value);\n\n current[0] = klona(stack.value[0]);\n\n current[2][0] = new Date().valueOf();\n current[2][1] = 'auto';\n\n stack.push(current);\n }\n\n const next = () => {\n /**\n * Последний элемент пути\n */\n const last = stack.value[0][stack.value[0].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 stack.value[0].push([null, 0]);\n }\n\n const forward = () => {\n enmemory();\n push();\n }\n\n const render = () => {\n const referred = refer();\n\n if (referred) {\n const [action, ...props] = referred;\n\n match(action, props);\n }\n }\n\n const push = () => {\n if (!restoring) next(), render();\n }\n\n const unwrap = (content: DialogContent | ChoiceContent) => {\n const lang = $.get().meta[0];\n const data = state();\n\n return replaceT9N(typeof content === 'function' ? content(lang, data) : content, data);\n }\n\n return {\n withStory,\n action,\n render,\n state,\n t: t9n.t,\n }\n}\n\nexport { novely }\n","const SKIPPED_DURING_RESTORE = new Set([\n 'dialog',\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":["matchAction","values","action","props","isNumber","val","isNull","isString","str","value","isUserRequiredAction","action","meta","getDefaultSave","getLanguage","languages","language","throttle","fn","ms","throttled","savedArgs","savedThis","wrapper","store","current","subscribers","subscribe","cb","push","value","fn","deepmerge","klona","SKIPPED_DURING_RESTORE","replaceT9N","novely","characters","storage","createRenderer","initialScreen","t9n","languages","story","withStory","s","name","items","flat","item","data","type","renderer","action","_","prop","props","state","value","stack","prev","val","deepmerge","createStack","current","goingBack","getDefaultSave","initialData","getLanguage","$","store","initialDataLoaded","throttledOnStorageDataChange","throttle","stored","restore","initial","save","override","date","isLatest","newGame","set","restoring","latest","klona","match","index","max","acc","isNull","isNumber","queue","isString","i","meta","SKIPPED_DURING_RESTORE","isUserRequiredAction","indexedQueue","_action","_meta","str","result","render","refer","matchAction","time","push","background","source","character","emotion","className","style","handle","duration","person","content","unwrap","forward","fn","choices","unwrapped","visible","selected","enmemory","scene","condition","question","onInput","setup","handler","pattern","timeout","classes","char","target","classNames","text","next","last","referred","lang","localStorageStorage","options","value","data"]}
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 { 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 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\n/**\n * Currently language system supports only 2-character values, like `en` or `ru`\n * todo: support language variations, such `en-GB`, `en-CA`, `en-AU`\n */\nconst getLanguage = (languages: string[], language = navigator.language) => {\n language = language.substring(0, 2);\n\n if (!languages.includes(language)) language = languages[0];\n\n return language;\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() {\n if (throttled) {\n savedArgs = arguments;\n // @ts-ignore\n savedThis = this;\n\n return;\n }\n\n // @ts-ignore\n fn.apply(this, arguments);\n\n throttled = false;\n }\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 return wrapper as unknown as (...args: Parameters<Fn>) => void;\n}\n\nexport { matchAction, isNumber, isNull, isString, isCSSImage, str, isUserRequiredAction, getLanguage, throttle }","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, DialogContent, ChoiceContent } from './action';\nimport type { Storage } from './storage';\nimport type { Save, State, StorageData } from './types'\nimport type { Renderer, RendererInit } from './renderer'\nimport type { SetupT9N } from '@novely/t9n'\nimport { matchAction, isNumber, isNull, isString, isCSSImage, str, isUserRequiredAction, getLanguage, throttle } from './utils';\nimport { store } from './store';\nimport { all as deepmerge } from 'deepmerge'\nimport { klona } from 'klona/json';\nimport { SKIPPED_DURING_RESTORE, getDefaultSave } from './constants';\n\ninterface NovelyInit<Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends ReturnType<SetupT9N<Languages>>> {\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 * 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?: \"mainmenu\" | \"game\" | \"saves\" | \"settings\";\n /**\n * An object containing the translation functions used in the game\n */\n t9n: Inter;\n /**\n * An optional property that specifies whether to preload assets when the game starts\n */\n assetsPreload?: boolean;\n /**\n * An optional property that specifies whether the game should use a single save.\n */\n singleSave?: boolean;\n}\n\ntype Novely = <Languages extends string, Characters extends Record<string, Character<Languages>>, Inter extends ReturnType<SetupT9N<Languages>>>(init: NovelyInit<Languages, Characters, Inter>) => {\n withStory: (s: Story) => void;\n action: ActionProxyProvider<Characters>;\n render: () => void;\n state: {\n (value: State | ((prev: State) => State)): void;\n (): State;\n };\n t: Inter['t'];\n}\n\n// @ts-ignore - Fuck ts\nconst novely: Novely = async ({ characters, storage, renderer: createRenderer, initialScreen = \"mainmenu\", t9n, languages, assetsPreload }) => {\n let story: Story;\n\n const withStory = (s: Story) => {\n story = s;\n /**\n * Load assets after the `action` scripts are executed\n */\n preloadAssets();\n }\n\n /**\n * This is used when background is loading\n */\n const preload = {\n background: new Set<string>(),\n }\n\n const action = new Proxy({}, {\n get(_, prop) {\n return (...props: Parameters<ActionProxyProvider<Record<string, Character>>[keyof ActionProxyProvider<Record<string, Character>>]>) => {\n if (prop === 'showBackground') {\n if (isCSSImage(props[0] as string)) preload.background.add(props[0] as string);\n }\n\n return [prop, ...props];\n }\n }\n });\n\n function state(value: State | ((prev: State) => State)): void;\n function state(): State;\n function state(value?: State | ((prev: State) => State)): State | void {\n if (!value) return stack.value[1]\n\n const prev = stack.value[1];\n const val = typeof value === 'function' ? value(prev as State) : deepmerge([prev, value]);\n\n stack.value[1] = val as State;\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(languages, $.get().meta[0])];\n }\n }\n }\n\n const $ = store(await storage.get());\n\n const onStorageDataChange = (value: StorageData) => storage.set(value);\n const throttledOnStorageDataChange = throttle(onStorageDataChange, 120);\n\n $.subscribe(throttledOnStorageDataChange);\n\n const initial = ((value) => value.saves.length > 0 && value.saves.at(-1))($.get()) || getDefaultSave(languages, $.get().meta[0]);\n const stack = createStack(initial);\n\n const save = async (override = false, type: Save[2][1] = override ? 'auto' : 'manual') => {\n /**\n * Получаем предыдущее значение\n */\n const prev = await storage.get();\n\n const date = stack.value[2][0];\n const isLatest = prev.saves.findIndex(value => value[2][0] === date) === prev.saves.length - 1;\n\n /**\n * Обновим дату и тип\n */\n stack.value[2][0] = Date.now();\n stack.value[2][1] = type;\n\n if (override) {\n /**\n * Перезапишем\n */\n if (isLatest) {\n /**\n * Сохранения хранятся в массиве. Нельзя перезаписать любое последнее\n * \n * Если перезаписывать старое сохранение, то они не будут идти в хронологическом порядке\n */\n prev.saves[prev.saves.length - 1] = stack.value;\n } else {\n prev.saves.push(stack.value);\n }\n } else {\n /**\n * Добавляем текущее сохранение\n */\n prev.saves.push(stack.value);\n }\n\n /**\n * Устанавливаем новое значение\n */\n return await storage.set(prev);\n }\n\n const newGame = () => {\n $.update(prev => {\n const save = getDefaultSave(languages, $.get().meta[0]);\n\n prev.saves.push(save), restore(save);\n\n return prev;\n });\n }\n\n /**\n * Устанавливает сохранение\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\n /**\n * Визуально восстанавливает историю\n */\n const restore = async (save?: Save) => {\n let latest = save ? save : await storage.get().then(value => value.saves.at(-1));\n\n /**\n * Если нет сохранённой игры, то запустим ту, которая уже есть\n */\n if (!latest) {\n await storage.set({ saves: [initial], meta: [getLanguage(languages)] });\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 [ValidAction[0], 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 latest = !next.some(([_action, _meta]) => str(_meta[0]) === str(meta[0]));\n\n if (!latest) 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 {\n match(action, meta);\n }\n }\n\n restoring = false, 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 renderer = createRenderer({\n characters,\n storage,\n set,\n restore,\n save,\n newGame,\n stack,\n languages,\n t: t9n.i,\n $\n });\n\n const preloadAssets = () => {\n if (!assetsPreload) {\n initialScreen === 'game' ? restore() : renderer.ui.showScreen(initialScreen);\n\n return;\n }\n\n /**\n * We need to load all the characters and their emotions\n */\n\n let promises: Promise<unknown>[] = [];\n\n renderer.ui.showScreen('loading');\n\n for (const [name, { emotions }] of Object.entries(characters)) {\n for (const emotion of Object.keys(emotions)) {\n promises.push(Promise.resolve(renderer.character(name).withEmotion(emotion)));\n }\n }\n\n for (const bg of preload.background) {\n promises.push(new Promise((res, rej) => {\n /**\n * Create `img` element\n */\n const img = document.createElement('img');\n\n /**\n * Set `src`\n */\n img.crossOrigin = '*';\n img.src = bg;\n\n if (img.complete && img.naturalHeight !== 0) {\n /**\n * Image is already loaded\n */\n res(void 0);\n } else {\n /**\n * Image is uniq, it is safe to use `onload`\n */\n img.onload = res;\n img.onerror = rej;\n }\n }));\n }\n\n Promise.all(promises).then(() => {\n renderer.ui.showScreen(initialScreen);\n });\n }\n\n const match = matchAction({\n wait([time]) {\n /**\n * `restoring` может поменяться на `true` перед тем как запуститься `push` из `setTimeout`\n */\n if (!restoring) setTimeout(push, 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);\n handle.withEmotion(emotion)();\n\n push()\n },\n hideCharacter([character, className, style, duration]) {\n const handle = renderer.character(character);\n\n handle.remove(className, style, duration)(push);\n },\n dialog([person, content, emotion]) {\n renderer.dialog(unwrap(content), person, emotion)(() => {\n enmemory();\n push();\n });\n },\n function([fn]) {\n const result = fn();\n\n if (!restoring) result ? result.then(push) : push();\n\n return result;\n },\n choice(choices) {\n const unwrapped = choices.map(([content, action, visible]) => {\n return [unwrap(content), action, visible] as [string, ValidAction[], () => boolean];\n });\n\n renderer.choices(unwrapped)((selected) => {\n enmemory();\n\n stack.value[0].push(['choice', selected], [null, 0]), render();\n });\n },\n jump([scene]) {\n stack.value[0] = [[null, scene], [null, 0]];\n\n renderer.clear(false)(() => {\n if (!restoring) render();\n })\n },\n clear() {\n try {\n navigator.vibrate(0)\n } finally {\n renderer.clear(goingBack)(push);\n }\n },\n condition([condition]) {\n const value = condition();\n\n if (!restoring) stack.value[0].push(['condition', value], [null, 0]), render();\n },\n end() {\n save(false, 'auto').then(() => {\n match('clear', []);\n\n renderer.ui.showScreen('mainmenu');\n });\n },\n input([question, onInput, setup]) {\n renderer.input(question, onInput, setup)(() => {\n enmemory();\n push();\n });\n },\n custom([handler]) {\n const result = renderer.custom(handler, goingBack, () => {\n if (!restoring && handler.requireUserAction) enmemory();\n if (!restoring) push();\n });\n\n return result;\n },\n vibrate(pattern) {\n navigator.vibrate(pattern), push();\n },\n next() {\n push();\n }\n });\n\n const enmemory = () => {\n if (restoring) return;\n\n const current = klona(stack.value);\n\n current[0] = klona(stack.value[0]);\n\n current[2][0] = new Date().valueOf();\n current[2][1] = 'auto';\n\n stack.push(current);\n }\n\n const next = () => {\n /**\n * Последний элемент пути\n */\n const last = stack.value[0][stack.value[0].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 stack.value[0].push([null, 0]);\n }\n\n const render = () => {\n const referred = refer();\n\n if (referred) {\n const [action, ...props] = referred;\n\n match(action, props);\n }\n }\n\n const push = () => {\n if (!restoring) next(), render();\n }\n\n const unwrap = (content: DialogContent | ChoiceContent) => {\n return typeof content === 'function' ? content($.get().meta[0], state()) : content\n }\n\n return {\n withStory,\n action,\n render,\n state,\n t: t9n.t,\n }\n}\n\nexport { novely }\n","import type { Save } from './types'\n\nconst SKIPPED_DURING_RESTORE = new Set([\n 'dialog',\n 'input',\n 'vibrate'\n] as const);\n\nconst DEFAULT_SAVE: Save = [[[null, 'start'], [null, 0]], {}, [Date.now(), 'auto']];\n\n/**\n * Currently language system supports only 2-character values, like `en` or `ru`\n * \n * todo: support language variations, such `en-GB`, `en-CA`, `en-AU`\n */\nconst getDefaultSave = (languages: string[], language = navigator.language) => {\n language = language.substring(0, 2);\n\n if (!languages.includes(language)) language = languages[0];\n\n return [[[null, 'start'], [null, 0]], {}, [Date.now(), 'auto']] as Save;\n}\n\nexport { SKIPPED_DURING_RESTORE, DEFAULT_SAVE, getDefaultSave }","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":["matchAction","values","action","props","isNumber","val","isNull","isString","isCSSImage","str","startsWith","value","isUserRequiredAction","meta","getLanguage","languages","language","throttle","fn","ms","throttled","savedArgs","savedThis","wrapper","store","current","subscribers","subscribe","cb","push","value","fn","deepmerge","klona","SKIPPED_DURING_RESTORE","DEFAULT_SAVE","getDefaultSave","languages","language","novely","characters","storage","createRenderer","initialScreen","t9n","languages","assetsPreload","story","withStory","s","preloadAssets","preload","action","_","prop","props","isCSSImage","state","value","stack","prev","val","deepmerge","createStack","current","goingBack","getDefaultSave","$","store","throttledOnStorageDataChange","throttle","initial","save","override","type","date","isLatest","newGame","restore","set","restoring","latest","getLanguage","klona","renderer","match","index","max","acc","isNull","isNumber","queue","isString","i","meta","SKIPPED_DURING_RESTORE","isUserRequiredAction","indexedQueue","_action","_meta","str","result","render","refer","promises","name","emotions","emotion","bg","res","rej","img","matchAction","time","push","background","source","character","className","style","handle","duration","person","content","unwrap","enmemory","fn","choices","unwrapped","visible","selected","scene","condition","question","onInput","setup","handler","pattern","next","last","referred","localStorageStorage","options","value","data"]}
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.0.0-alpha.17",
4
+ "version": "0.0.0-alpha.3",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "types": "./dist/index.d.ts",