@novely/core 0.0.0-beta.3 → 0.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@ type Character<LanguageKeys extends string = string> = {
14
14
  };
15
15
 
16
16
  type Thenable<T> = T | Promise<T>;
17
- type PathItem = [null, number | string] | ['choice' & Record<never, never>, number] | ['condition' & Record<never, never>, string];
17
+ type PathItem = [null, number | string] | ['choice' & Record<never, never>, number] | ['condition' & Record<never, never>, string] | ['exit' & Record<never, never>];
18
18
  type Path = PathItem[];
19
19
  type State = Record<string, any>;
20
20
  type SaveDate = number;
@@ -86,6 +86,7 @@ type ActionProxyProvider<Characters extends Record<string, Character>> = {
86
86
  };
87
87
  clear: () => ValidAction;
88
88
  condition: <T extends string>(condition: () => T, variants: Record<T, ValidAction[]>) => ValidAction;
89
+ exit: () => ValidAction;
89
90
  dialog: {
90
91
  <C extends keyof Characters>(person: C, content: DialogContent, emotion?: keyof Characters[C]['emotions']): ValidAction;
91
92
  (person: undefined, content: DialogContent, emotion?: undefined): ValidAction;
@@ -1,2 +1,657 @@
1
- "use strict";var Novely=(()=>{var de=Object.create;var F=Object.defineProperty;var ye=Object.getOwnPropertyDescriptor;var he=Object.getOwnPropertyNames;var ve=Object.getPrototypeOf,Ae=Object.prototype.hasOwnProperty;var be=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),Ce=(e,t)=>{for(var a in t)F(e,a,{get:t[a],enumerable:!0})},W=(e,t,a,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of he(t))!Ae.call(e,s)&&s!==a&&F(e,s,{get:()=>t[s],enumerable:!(o=ye(t,s))||o.enumerable});return e};var De=(e,t,a)=>(a=e!=null?de(ve(e)):{},W(t||!e||!e.__esModule?F(a,"default",{value:e,enumerable:!0}):a,e)),xe=e=>W(F({},"__esModule",{value:!0}),e);var te=be((We,ee)=>{"use strict";var Ee=function(t){return Pe(t)&&!Te(t)};function Pe(e){return!!e&&typeof e=="object"}function Te(e){var t=Object.prototype.toString.call(e);return t==="[object RegExp]"||t==="[object Date]"||Be(e)}var we=typeof Symbol=="function"&&Symbol.for,Me=we?Symbol.for("react.element"):60103;function Be(e){return e.$$typeof===Me}function Oe(e){return Array.isArray(e)?[]:{}}function O(e,t){return t.clone!==!1&&t.isMergeableObject(e)?T(Oe(e),e,t):e}function Re(e,t,a){return e.concat(t).map(function(o){return O(o,a)})}function Le(e,t){if(!t.customMerge)return T;var a=t.customMerge(e);return typeof a=="function"?a:T}function je(e){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(e).filter(function(t){return Object.propertyIsEnumerable.call(e,t)}):[]}function X(e){return Object.keys(e).concat(je(e))}function Z(e,t){try{return t in e}catch{return!1}}function Fe(e,t){return Z(e,t)&&!(Object.hasOwnProperty.call(e,t)&&Object.propertyIsEnumerable.call(e,t))}function Ne(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){Fe(e,s)||(Z(e,s)&&a.isMergeableObject(t[s])?o[s]=Le(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||Re,a.isMergeableObject=a.isMergeableObject||Ee,a.cloneUnlessOtherwiseSpecified=O;var o=Array.isArray(t),s=Array.isArray(e),f=o===s;return f?o?a.arrayMerge(e,t,a):Ne(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 Ie=T;ee.exports=Ie});var He={};Ce(He,{localStorageStorage:()=>oe,novely:()=>ue});var $=e=>(t,a)=>e[t](a),N=e=>typeof e=="number",V=e=>e===null,q=e=>typeof e=="string";var U=e=>String(e),Q=(e,t)=>e==="custom"&&t[0]&&t[0].requireUserAction,I=(e={})=>[[[null,"start"],[null,0]],e,[Date.now(),"auto"]],G=(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],z=(e,t)=>{let a=!1,o,s;function f(){if(a){o=arguments,s=this;return}e.apply(this,arguments),a=!1}return setTimeout(function(){a=!1,o&&(f.apply(s,o),o=s=null)},t),f};var Y=(e,t=new Set)=>{let a=m=>(t.add(m),m(e),()=>{t.delete(m)}),o=m=>{t.forEach(C=>C(m))};return{subscribe:a,update:m=>{o(e=m(e))},get:()=>e}};var ne=De(te(),1);function A(e){var t,a,o;if(Array.isArray(e)){for(a=Array(t=e.length);t--;)a[t]=(o=e[t])&&typeof o=="object"?A(o):o;return a}if(Object.prototype.toString.call(e)==="[object Object]"){a={};for(t in e)t==="__proto__"?Object.defineProperty(a,t,{value:A(e[t]),configurable:!0,enumerable:!0,writable:!0}):a[t]=(o=e[t])&&typeof o=="object"?A(o):o;return a}return e}var re=new Set(["dialog","input","vibrate","text"]);var Ge=/{{(.*?)}}/g,ae=(e,t,a,o)=>e.replace(Ge,(s,f,m)=>{s=0,m=t,f=f.trim();let C=f.split("@"),w;for(C.length>1&&([f,w]=C),f=f.split(".");m&&s<f.length;)m=m[f[s++]];return w&&a&&o&&m&&(m=a[w][o.select(m)]),m??""});var ue=({characters:e,storage:t,renderer:a,initialScreen:o="mainmenu",t9n:s,languages:f,state:m})=>{let C,w=r=>{C=Object.fromEntries(Object.entries(r).map(([n,u])=>{let p=c=>c.flatMap(l=>{let h=l[0];return Array.isArray(h)?p(l):[l]});return[n,p(u)]})),o!=="game"&&g.ui.showScreen(o)},se=new Proxy({},{get(r,n){return(...u)=>[n,...u]}});function K(r){if(!r)return i.value[1];let n=i.value[1],u=typeof r=="function"?r(n):(0,ne.all)([n,r]);i.value[1]=u}let ie=(r,n=[r])=>({get value(){return n.at(-1)},set value(u){n[n.length-1]=u},back(){n.length>1&&(n.pop(),E=!0)},push(u){n.push(u)},clear(){n=[I(A(m))]}}),ce={saves:[],meta:[G(f)]},b=Y(ce),M=!1,le=z(r=>{M&&t.set(r)},120);b.subscribe(le),t.get().then(r=>{r.meta[0]||=G(f),M=!0,b.update(()=>r),o==="game"&&R()});let H=I(A(m)),i=ie(H),J=(r=!1,n=r?"auto":"manual")=>{M&&b.update(u=>{let p=i.value[2][0],c=u.saves.findIndex(l=>l[2][0]===p)===u.saves.length-1;return i.value[2][0]=Date.now(),i.value[2][1]=n,r&&c?u.saves[u.saves.length-1]=i.value:u.saves.push(i.value),u})},me=()=>{if(!M)return;let r=I(A(m));b.update(n=>(n.saves.push(r),R(r),n))},fe=r=>(i.value=r,R(r)),v=!1,E=!1,R=async r=>{if(!M)return;let n=r||b.get().saves.at(-1);n||(b.update(()=>({saves:[H],meta:[G(f)]})),n=A(H)),v=!0,i.value=n,g.ui.showScreen("game"),B("clear",[E]);let u=C,p=0,c=i.value[0].reduce((d,[S,D])=>V(S)&&N(D)?d+1:d,0),l=[];for(let[d,S]of i.value[0])if(d===null){if(q(S))u=u[S];else if(N(S)){p++;for(let D=0;D<S;D++){let[x,...j]=u[D];if(re.has(x)||Q(x,j))if(p===c&&D===S)l.push([x,j]);else continue;l.push([x,j])}u=u[S]}}else d==="choice"?u=u[S+1][1]:d==="condition"&&(u=u[2][S]);let h=l.map((d,S)=>d.concat(S));for await(let[d,S,D]of h)if(d==="function"||d==="custom"){if(d==="custom"&&S[0].callOnlyLatest&&!!h.slice(D+1).some(([Ve,Se])=>U(Se[0])===U(S[0])))continue;let x=B(d,S);x&&"then"in x&&await x}else B(d,S);v=!1,E=!1,P()},pe=()=>{let r=C;for(let[n,u]of i.value[0])n===null?r=r[u]:n==="choice"?r=r[u+1][1]:n==="condition"&&(r=r[2][u]);return r},g=a({characters:e,set:fe,restore:R,save:J,newGame:me,stack:i,languages:f,t:s.i,$:b}),B=$({wait([r]){v||setTimeout(y,r)},showBackground([r]){g.background(r),y()},playMusic([r]){g.music(r,"music").play(),y()},stopMusic([r]){g.music(r,"music").stop(),y()},showCharacter([r,n,u,p]){let c=g.character(r);c.append(u,p),c.withEmotion(n)(),y()},hideCharacter([r,n,u,p]){g.character(r).remove(n,u,p)(y)},dialog([r,n,u]){let p=(()=>{let c=r,l=e,h=b.get().meta[0];return c?c in l?typeof l[c].name=="string"?l[c].name:l[c].name[h]:c:""})();g.dialog(L(n),L(p),r,u)(k)},function([r]){let n=r();return v||(n?n.then(y):y()),n},choice([r,...n]){let u=Array.isArray(r);u&&(n.unshift(r),r="");let p=n.map(([c,l,h])=>[L(c),l,h]);g.choices(r,p)(c=>{_(),i.value[0].push(["choice",u?c:c+1],[null,0]),P()})},jump([r]){i.value[0]=[[null,r],[null,0]],g.clear(!1)(()=>{v||P()})},clear(){try{navigator.vibrate(0)}finally{g.clear(E)(y)}},condition([r]){let n=r();v||(i.value[0].push(["condition",n],[null,0]),P())},end(){J(!1,"auto"),B("clear",[]),g.ui.showScreen("mainmenu")},input([r,n,u]){g.input(r,n,u)(k)},custom([r]){return g.custom(r,E,()=>{!v&&r.requireUserAction&&_(),v||y()})},vibrate(r){try{navigator.vibrate(r)}finally{y()}},next(){y()},animateCharacter([r,n,...u]){let p=()=>{let c=g.store.characters[r];if(!c)return;let l=c.canvas;if(!l)return;let h=u.filter(d=>!l.classList.contains(d));l.classList.add(...h),setTimeout(()=>{l.classList.remove(...h)},n)};return p.callOnlyLatest=!0,g.custom(p,E,()=>{}),y()},text(r){g.text(r.map(L).join(" "),k)}}),_=()=>{if(v)return;let r=A(i.value);r[0]=A(i.value[0]),r[2][0]=new Date().valueOf(),r[2][1]="auto",i.push(r)},ge=()=>{let r=i.value[0][i.value[0].length-1];if(V(r[0])&&N(r[1])){r[1]=r[1]+1;return}i.value[0].push([null,0])},k=()=>{_(),y()},P=()=>{let r=pe();if(r){let[n,...u]=r;B(n,u)}},y=()=>{v||(ge(),P())},L=r=>{let n=b.get().meta[0],u=K();return ae(typeof r=="function"?r(n,u):r,u)};return{withStory:w,action:se,render:P,state:K,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 xe(He);})();
1
+ "use strict";
2
+ var Novely = (() => {
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __commonJS = (cb, mod) => function __require() {
10
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
+
34
+ // ../../node_modules/.pnpm/deepmerge@4.3.0/node_modules/deepmerge/dist/cjs.js
35
+ var require_cjs = __commonJS({
36
+ "../../node_modules/.pnpm/deepmerge@4.3.0/node_modules/deepmerge/dist/cjs.js"(exports, module) {
37
+ "use strict";
38
+ var isMergeableObject = function isMergeableObject2(value) {
39
+ return isNonNullObject(value) && !isSpecial(value);
40
+ };
41
+ function isNonNullObject(value) {
42
+ return !!value && typeof value === "object";
43
+ }
44
+ function isSpecial(value) {
45
+ var stringValue = Object.prototype.toString.call(value);
46
+ return stringValue === "[object RegExp]" || stringValue === "[object Date]" || isReactElement(value);
47
+ }
48
+ var canUseSymbol = typeof Symbol === "function" && Symbol.for;
49
+ var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for("react.element") : 60103;
50
+ function isReactElement(value) {
51
+ return value.$$typeof === REACT_ELEMENT_TYPE;
52
+ }
53
+ function emptyTarget(val) {
54
+ return Array.isArray(val) ? [] : {};
55
+ }
56
+ function cloneUnlessOtherwiseSpecified(value, options) {
57
+ return options.clone !== false && options.isMergeableObject(value) ? deepmerge2(emptyTarget(value), value, options) : value;
58
+ }
59
+ function defaultArrayMerge(target, source, options) {
60
+ return target.concat(source).map(function(element) {
61
+ return cloneUnlessOtherwiseSpecified(element, options);
62
+ });
63
+ }
64
+ function getMergeFunction(key, options) {
65
+ if (!options.customMerge) {
66
+ return deepmerge2;
67
+ }
68
+ var customMerge = options.customMerge(key);
69
+ return typeof customMerge === "function" ? customMerge : deepmerge2;
70
+ }
71
+ function getEnumerableOwnPropertySymbols(target) {
72
+ return Object.getOwnPropertySymbols ? Object.getOwnPropertySymbols(target).filter(function(symbol) {
73
+ return Object.propertyIsEnumerable.call(target, symbol);
74
+ }) : [];
75
+ }
76
+ function getKeys(target) {
77
+ return Object.keys(target).concat(getEnumerableOwnPropertySymbols(target));
78
+ }
79
+ function propertyIsOnObject(object, property) {
80
+ try {
81
+ return property in object;
82
+ } catch (_) {
83
+ return false;
84
+ }
85
+ }
86
+ function propertyIsUnsafe(target, key) {
87
+ return propertyIsOnObject(target, key) && !(Object.hasOwnProperty.call(target, key) && Object.propertyIsEnumerable.call(target, key));
88
+ }
89
+ function mergeObject(target, source, options) {
90
+ var destination = {};
91
+ if (options.isMergeableObject(target)) {
92
+ getKeys(target).forEach(function(key) {
93
+ destination[key] = cloneUnlessOtherwiseSpecified(target[key], options);
94
+ });
95
+ }
96
+ getKeys(source).forEach(function(key) {
97
+ if (propertyIsUnsafe(target, key)) {
98
+ return;
99
+ }
100
+ if (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) {
101
+ destination[key] = getMergeFunction(key, options)(target[key], source[key], options);
102
+ } else {
103
+ destination[key] = cloneUnlessOtherwiseSpecified(source[key], options);
104
+ }
105
+ });
106
+ return destination;
107
+ }
108
+ function deepmerge2(target, source, options) {
109
+ options = options || {};
110
+ options.arrayMerge = options.arrayMerge || defaultArrayMerge;
111
+ options.isMergeableObject = options.isMergeableObject || isMergeableObject;
112
+ options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified;
113
+ var sourceIsArray = Array.isArray(source);
114
+ var targetIsArray = Array.isArray(target);
115
+ var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;
116
+ if (!sourceAndTargetTypesMatch) {
117
+ return cloneUnlessOtherwiseSpecified(source, options);
118
+ } else if (sourceIsArray) {
119
+ return options.arrayMerge(target, source, options);
120
+ } else {
121
+ return mergeObject(target, source, options);
122
+ }
123
+ }
124
+ deepmerge2.all = function deepmergeAll(array, options) {
125
+ if (!Array.isArray(array)) {
126
+ throw new Error("first argument should be an array");
127
+ }
128
+ return array.reduce(function(prev, next) {
129
+ return deepmerge2(prev, next, options);
130
+ }, {});
131
+ };
132
+ var deepmerge_1 = deepmerge2;
133
+ module.exports = deepmerge_1;
134
+ }
135
+ });
136
+
137
+ // src/index.ts
138
+ var src_exports = {};
139
+ __export(src_exports, {
140
+ localStorageStorage: () => localStorageStorage,
141
+ novely: () => novely
142
+ });
143
+
144
+ // src/utils.ts
145
+ var matchAction = (values) => {
146
+ return (action, props) => {
147
+ return values[action](props);
148
+ };
149
+ };
150
+ var isNumber = (val) => {
151
+ return typeof val === "number";
152
+ };
153
+ var isNull = (val) => {
154
+ return val === null;
155
+ };
156
+ var isString = (val) => {
157
+ return typeof val === "string";
158
+ };
159
+ var str = (value) => {
160
+ return String(value);
161
+ };
162
+ var isUserRequiredAction = (action, meta) => {
163
+ return action === "custom" && meta[0] && meta[0].requireUserAction;
164
+ };
165
+ var getDefaultSave = (state = {}) => {
166
+ return [[[null, "start"], [null, 0]], state, [Date.now(), "auto"]];
167
+ };
168
+ var getLanguage = (languages, language = navigator.language) => {
169
+ if (languages.includes(language)) {
170
+ return language;
171
+ } else if (languages.includes(language = language.substring(0, 2))) {
172
+ return language;
173
+ } else if (language = languages.find((value) => navigator.languages.includes(value))) {
174
+ return language;
175
+ }
176
+ return languages[0];
177
+ };
178
+ var throttle = (fn, ms) => {
179
+ let throttled = false, savedArgs, savedThis;
180
+ function wrapper() {
181
+ if (throttled) {
182
+ savedArgs = arguments;
183
+ savedThis = this;
184
+ return;
185
+ }
186
+ fn.apply(this, arguments);
187
+ throttled = false;
188
+ }
189
+ setTimeout(function() {
190
+ throttled = false;
191
+ if (savedArgs) {
192
+ wrapper.apply(savedThis, savedArgs);
193
+ savedArgs = savedThis = null;
194
+ }
195
+ }, ms);
196
+ return wrapper;
197
+ };
198
+
199
+ // src/store.ts
200
+ var store = (current, subscribers = /* @__PURE__ */ new Set()) => {
201
+ const subscribe = (cb) => {
202
+ subscribers.add(cb), cb(current);
203
+ return () => {
204
+ subscribers.delete(cb);
205
+ };
206
+ };
207
+ const push = (value) => {
208
+ subscribers.forEach((cb) => cb(value));
209
+ };
210
+ const update = (fn) => {
211
+ push(current = fn(current));
212
+ };
213
+ const get = () => {
214
+ return current;
215
+ };
216
+ return { subscribe, update, get };
217
+ };
218
+
219
+ // src/novely.ts
220
+ var import_deepmerge = __toESM(require_cjs(), 1);
221
+
222
+ // ../../node_modules/.pnpm/klona@2.0.6/node_modules/klona/json/index.mjs
223
+ function klona(val) {
224
+ var k, out, tmp;
225
+ if (Array.isArray(val)) {
226
+ out = Array(k = val.length);
227
+ while (k--)
228
+ out[k] = (tmp = val[k]) && typeof tmp === "object" ? klona(tmp) : tmp;
229
+ return out;
230
+ }
231
+ if (Object.prototype.toString.call(val) === "[object Object]") {
232
+ out = {};
233
+ for (k in val) {
234
+ if (k === "__proto__") {
235
+ Object.defineProperty(out, k, {
236
+ value: klona(val[k]),
237
+ configurable: true,
238
+ enumerable: true,
239
+ writable: true
240
+ });
241
+ } else {
242
+ out[k] = (tmp = val[k]) && typeof tmp === "object" ? klona(tmp) : tmp;
243
+ }
244
+ }
245
+ return out;
246
+ }
247
+ return val;
248
+ }
249
+
250
+ // src/constants.ts
251
+ var SKIPPED_DURING_RESTORE = /* @__PURE__ */ new Set([
252
+ "dialog",
253
+ "input",
254
+ "vibrate",
255
+ "text"
256
+ ]);
257
+
258
+ // ../t9n/dist/index.js
259
+ var u = /{{(.*?)}}/g;
260
+ var g = (r, i, s, a) => r.replace(u, (e, t, n) => {
261
+ e = 0, n = i, t = t.trim();
262
+ let l = t.split("@"), o;
263
+ for (l.length > 1 && ([t, o] = l), t = t.split("."); n && e < t.length; )
264
+ n = n[t[e++]];
265
+ return o && s && a && n && (n = s[o][a.select(n)]), n ?? "";
266
+ });
267
+
268
+ // src/novely.ts
269
+ var novely = ({ characters, storage, renderer: createRenderer, initialScreen = "mainmenu", t9n, languages, state: defaultState }) => {
270
+ let story;
271
+ const withStory = (s) => {
272
+ story = Object.fromEntries(Object.entries(s).map(([name, items]) => {
273
+ const flat = (item) => {
274
+ return item.flatMap((data) => {
275
+ const type = data[0];
276
+ if (Array.isArray(type))
277
+ return flat(data);
278
+ return [data];
279
+ });
280
+ };
281
+ return [name, flat(items)];
282
+ }));
283
+ if (initialScreen !== "game")
284
+ renderer.ui.showScreen(initialScreen);
285
+ };
286
+ const action = new Proxy({}, {
287
+ get(_, prop) {
288
+ return (...props) => {
289
+ return [prop, ...props];
290
+ };
291
+ }
292
+ });
293
+ function state(value) {
294
+ if (!value)
295
+ return stack.value[1];
296
+ const prev = stack.value[1];
297
+ const val = typeof value === "function" ? value(prev) : (0, import_deepmerge.all)([prev, value]);
298
+ stack.value[1] = val;
299
+ }
300
+ const createStack = (current, stack2 = [current]) => {
301
+ return {
302
+ get value() {
303
+ return stack2.at(-1);
304
+ },
305
+ set value(value) {
306
+ stack2[stack2.length - 1] = value;
307
+ },
308
+ back() {
309
+ if (stack2.length > 1)
310
+ stack2.pop(), goingBack = true;
311
+ },
312
+ push(value) {
313
+ stack2.push(value);
314
+ },
315
+ clear() {
316
+ stack2 = [getDefaultSave(klona(defaultState))];
317
+ }
318
+ };
319
+ };
320
+ const initialData = {
321
+ saves: [],
322
+ meta: [getLanguage(languages)]
323
+ };
324
+ const $ = store(initialData);
325
+ let initialDataLoaded = false;
326
+ const onStorageDataChange = (value) => {
327
+ if (initialDataLoaded)
328
+ storage.set(value);
329
+ };
330
+ const throttledOnStorageDataChange = throttle(onStorageDataChange, 120);
331
+ $.subscribe(throttledOnStorageDataChange);
332
+ storage.get().then((stored) => {
333
+ stored.meta[0] ||= getLanguage(languages);
334
+ initialDataLoaded = true;
335
+ $.update(() => stored);
336
+ if (initialScreen === "game")
337
+ restore();
338
+ });
339
+ const initial = getDefaultSave(klona(defaultState));
340
+ const stack = createStack(initial);
341
+ const save = (override = false, type = override ? "auto" : "manual") => {
342
+ if (!initialDataLoaded)
343
+ return;
344
+ $.update((prev) => {
345
+ const date = stack.value[2][0];
346
+ const isLatest = prev.saves.findIndex((value) => value[2][0] === date) === prev.saves.length - 1;
347
+ stack.value[2][0] = Date.now();
348
+ stack.value[2][1] = type;
349
+ if (override) {
350
+ if (isLatest) {
351
+ prev.saves[prev.saves.length - 1] = stack.value;
352
+ } else {
353
+ prev.saves.push(stack.value);
354
+ }
355
+ } else {
356
+ prev.saves.push(stack.value);
357
+ }
358
+ return prev;
359
+ });
360
+ };
361
+ const newGame = () => {
362
+ if (!initialDataLoaded)
363
+ return;
364
+ const save2 = getDefaultSave(klona(defaultState));
365
+ $.update((prev) => {
366
+ prev.saves.push(save2), restore(save2);
367
+ return prev;
368
+ });
369
+ };
370
+ const set = (save2) => {
371
+ stack.value = save2;
372
+ return restore(save2);
373
+ };
374
+ let restoring = false;
375
+ let goingBack = false;
376
+ const restore = async (save2) => {
377
+ if (!initialDataLoaded)
378
+ return;
379
+ let latest = save2 ? save2 : $.get().saves.at(-1);
380
+ if (!latest) {
381
+ $.update(() => ({ saves: [initial], meta: [getLanguage(languages)] }));
382
+ latest = klona(initial);
383
+ }
384
+ restoring = true, stack.value = latest;
385
+ renderer.ui.showScreen("game");
386
+ match("clear", [goingBack]);
387
+ let current = story;
388
+ let index = 0;
389
+ const max = stack.value[0].reduce((acc, [type, val]) => {
390
+ if (isNull(type) && isNumber(val))
391
+ return acc + 1;
392
+ return acc;
393
+ }, 0);
394
+ const queue = [];
395
+ for (const [type, val] of stack.value[0]) {
396
+ if (type === null) {
397
+ if (isString(val)) {
398
+ current = current[val];
399
+ } else if (isNumber(val)) {
400
+ index++;
401
+ for (let i = 0; i < val; i++) {
402
+ const [action2, ...meta] = current[i];
403
+ if (SKIPPED_DURING_RESTORE.has(action2) || isUserRequiredAction(action2, meta)) {
404
+ if (index === max && i === val) {
405
+ queue.push([action2, meta]);
406
+ } else {
407
+ continue;
408
+ }
409
+ }
410
+ queue.push([action2, meta]);
411
+ }
412
+ current = current[val];
413
+ }
414
+ } else if (type === "choice") {
415
+ current = current[val + 1][1];
416
+ } else if (type === "condition") {
417
+ current = current[2][val];
418
+ }
419
+ }
420
+ const indexedQueue = queue.map((value, index2) => value.concat(index2));
421
+ for await (const [action2, meta, i] of indexedQueue) {
422
+ if (action2 === "function" || action2 === "custom") {
423
+ if (action2 === "custom" && meta[0].callOnlyLatest) {
424
+ const next2 = indexedQueue.slice(i + 1);
425
+ const latest2 = !next2.some(([_action, _meta]) => str(_meta[0]) === str(meta[0]));
426
+ if (!latest2)
427
+ continue;
428
+ }
429
+ const result = match(action2, meta);
430
+ if (result && "then" in result)
431
+ await result;
432
+ } else {
433
+ match(action2, meta);
434
+ }
435
+ }
436
+ restoring = false, goingBack = false, render();
437
+ };
438
+ const refer = () => {
439
+ let current = story;
440
+ for (const [type, val] of stack.value[0]) {
441
+ if (type === null) {
442
+ current = current[val];
443
+ } else if (type === "choice") {
444
+ current = current[val + 1][1];
445
+ } else if (type === "condition") {
446
+ current = current[2][val];
447
+ }
448
+ }
449
+ return current;
450
+ };
451
+ const renderer = createRenderer({
452
+ characters,
453
+ set,
454
+ restore,
455
+ save,
456
+ newGame,
457
+ stack,
458
+ languages,
459
+ t: t9n.i,
460
+ $
461
+ });
462
+ const match = matchAction({
463
+ wait([time]) {
464
+ if (!restoring)
465
+ setTimeout(push, time);
466
+ },
467
+ showBackground([background]) {
468
+ renderer.background(background);
469
+ push();
470
+ },
471
+ playMusic([source]) {
472
+ renderer.music(source, "music").play();
473
+ push();
474
+ },
475
+ stopMusic([source]) {
476
+ renderer.music(source, "music").stop();
477
+ push();
478
+ },
479
+ showCharacter([character, emotion, className, style]) {
480
+ const handle = renderer.character(character);
481
+ handle.append(className, style);
482
+ handle.withEmotion(emotion)();
483
+ push();
484
+ },
485
+ hideCharacter([character, className, style, duration]) {
486
+ const handle = renderer.character(character);
487
+ handle.remove(className, style, duration)(push);
488
+ },
489
+ dialog([character, content, emotion]) {
490
+ const name = (() => {
491
+ const c = character, cs = characters;
492
+ const lang = $.get().meta[0];
493
+ return c ? c in cs ? typeof cs[c].name === "string" ? cs[c].name : cs[c].name[lang] : c : "";
494
+ })();
495
+ renderer.dialog(unwrap(content), unwrap(name), character, emotion)(forward);
496
+ },
497
+ function([fn]) {
498
+ const result = fn();
499
+ if (!restoring)
500
+ result ? result.then(push) : push();
501
+ return result;
502
+ },
503
+ choice([question, ...choices]) {
504
+ const isWithoutQuestion = Array.isArray(question);
505
+ if (isWithoutQuestion) {
506
+ choices.unshift(question);
507
+ question = "";
508
+ }
509
+ const unwrapped = choices.map(([content, action2, visible]) => {
510
+ return [unwrap(content), action2, visible];
511
+ });
512
+ renderer.choices(question, unwrapped)((selected) => {
513
+ enmemory();
514
+ stack.value[0].push(["choice", isWithoutQuestion ? selected : selected + 1], [null, 0]), render();
515
+ });
516
+ },
517
+ jump([scene]) {
518
+ stack.value[0] = [[null, scene], [null, 0]];
519
+ renderer.clear(false)(() => {
520
+ if (!restoring)
521
+ render();
522
+ });
523
+ },
524
+ clear() {
525
+ try {
526
+ navigator.vibrate(0);
527
+ } finally {
528
+ renderer.clear(goingBack)(push);
529
+ }
530
+ },
531
+ condition([condition]) {
532
+ const value = condition();
533
+ if (!restoring)
534
+ stack.value[0].push(["condition", value], [null, 0]), render();
535
+ },
536
+ end() {
537
+ save(false, "auto");
538
+ match("clear", []);
539
+ renderer.ui.showScreen("mainmenu");
540
+ },
541
+ input([question, onInput, setup]) {
542
+ renderer.input(question, onInput, setup)(forward);
543
+ },
544
+ custom([handler]) {
545
+ const result = renderer.custom(handler, goingBack, () => {
546
+ if (!restoring && handler.requireUserAction)
547
+ enmemory();
548
+ if (!restoring)
549
+ push();
550
+ });
551
+ return result;
552
+ },
553
+ vibrate(pattern) {
554
+ try {
555
+ navigator.vibrate(pattern);
556
+ } finally {
557
+ push();
558
+ }
559
+ },
560
+ next() {
561
+ push();
562
+ },
563
+ animateCharacter([character, timeout, ...classes]) {
564
+ const handler = () => {
565
+ const char = renderer.store.characters[character];
566
+ if (!char)
567
+ return;
568
+ const target = char.canvas;
569
+ if (!target)
570
+ return;
571
+ const classNames = classes.filter((className) => !target.classList.contains(className));
572
+ target.classList.add(...classNames);
573
+ setTimeout(() => {
574
+ target.classList.remove(...classNames);
575
+ }, timeout);
576
+ };
577
+ handler.callOnlyLatest = true;
578
+ return renderer.custom(handler, goingBack, () => {
579
+ }), push();
580
+ },
581
+ text(text) {
582
+ renderer.text(text.map(unwrap).join(" "), forward);
583
+ },
584
+ exit() {
585
+ const path = stack.value[0];
586
+ for (let i = path.length - 1; i > 0; i--) {
587
+ if (path[i][0] !== "choice" && path[i][0] !== "condition")
588
+ continue;
589
+ stack.value[0] = path.slice(0, i);
590
+ next();
591
+ break;
592
+ }
593
+ render();
594
+ }
595
+ });
596
+ const enmemory = () => {
597
+ if (restoring)
598
+ return;
599
+ const current = klona(stack.value);
600
+ current[0] = klona(stack.value[0]);
601
+ current[2][0] = (/* @__PURE__ */ new Date()).valueOf();
602
+ current[2][1] = "auto";
603
+ stack.push(current);
604
+ };
605
+ const next = () => {
606
+ const path = stack.value[0];
607
+ const last = path[path.length - 1];
608
+ if (isNull(last[0]) && isNumber(last[1])) {
609
+ last[1] = last[1] + 1;
610
+ return;
611
+ }
612
+ path.push([null, 0]);
613
+ };
614
+ const render = () => {
615
+ const referred = refer();
616
+ if (!(referred && Array.isArray(referred)))
617
+ return;
618
+ const [action2, ...props] = referred;
619
+ match(action2, props);
620
+ };
621
+ const push = () => {
622
+ if (!restoring)
623
+ next(), render();
624
+ };
625
+ const forward = () => {
626
+ enmemory();
627
+ push();
628
+ };
629
+ const unwrap = (content) => {
630
+ const lang = $.get().meta[0];
631
+ const data = state();
632
+ return g(typeof content === "function" ? content(lang, data) : content, data);
633
+ };
634
+ return {
635
+ withStory,
636
+ action,
637
+ render,
638
+ state,
639
+ t: t9n.t
640
+ };
641
+ };
642
+
643
+ // src/storage.ts
644
+ var localStorageStorage = (options) => {
645
+ return {
646
+ async get() {
647
+ const value = localStorage.getItem(options.key);
648
+ return value ? JSON.parse(value) : { saves: [], meta: [] };
649
+ },
650
+ async set(data) {
651
+ localStorage.setItem(options.key, JSON.stringify(data));
652
+ }
653
+ };
654
+ };
655
+ return __toCommonJS(src_exports);
656
+ })();
2
657
  //# sourceMappingURL=index.global.js.map