@novely/core 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +9 -10
- package/dist/index.global.js +122 -35
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +122 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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'
|
|
17
|
+
type PathItem = [null, number | string] | ['choice', number] | ['choice:exit'] | ['condition', string] | ['condition:exit'] | ['exit'] | ['block', string] | ['block:exit'];
|
|
18
18
|
type Path = PathItem[];
|
|
19
19
|
type State = Record<string, any>;
|
|
20
20
|
type Data = Record<string, any>;
|
|
@@ -44,8 +44,9 @@ type NovelyScreen = 'mainmenu' | 'game' | 'saves' | 'settings';
|
|
|
44
44
|
type DeepPartial<T> = unknown extends T ? T : T extends object ? {
|
|
45
45
|
[P in keyof T]?: T[P] extends Array<infer U> ? Array<DeepPartial<U>> : T[P] extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : DeepPartial<T[P]>;
|
|
46
46
|
} : T;
|
|
47
|
+
type NonEmptyRecord<T extends Record<PropertyKey, unknown>> = keyof T extends never ? never : T;
|
|
47
48
|
|
|
48
|
-
type ValidAction = ['choice', [number]] | ['clear', [Set<keyof DefaultActionProxyProvider>?, Set<string>?]] | ['condition', [() => boolean, Record<string, ValidAction[]>]] | ['dialog', [string | undefined, Unwrappable, string | undefined]] | ['end', []] | ['showBackground', [string]] | ['playMusic', [string]] | ['stopMusic', [string]] | ['jump', [string]] | ['showCharacter', [string, keyof Character['emotions'], string?, string?]] | ['hideCharacter', [string, string?, string?, number?]] | ['animateCharacter', [string, number, ...string[]]] | ['wait', [FunctionableValue<number>]] | ['function', [() => Thenable<void>]] | ['input', [string, (meta: ActionInputOnInputMeta) => void, ActionInputSetup?]] | ['custom', [CustomHandler]] | ['vibrate', [...number[]]] | ['next', []] | ['text', [...string[]]] | ['exit'] | ['preload', [string]] | ValidAction[];
|
|
49
|
+
type ValidAction = ['choice', [number]] | ['clear', [Set<keyof DefaultActionProxyProvider>?, Set<string>?]] | ['condition', [() => boolean, Record<string, ValidAction[]>]] | ['dialog', [string | undefined, Unwrappable, string | undefined]] | ['end', []] | ['showBackground', [string | NonEmptyRecord<BackgroundImage>]] | ['playMusic', [string]] | ['stopMusic', [string]] | ['jump', [string]] | ['showCharacter', [string, keyof Character['emotions'], string?, string?]] | ['hideCharacter', [string, string?, string?, number?]] | ['animateCharacter', [string, number, ...string[]]] | ['wait', [FunctionableValue<number>]] | ['function', [() => Thenable<void>]] | ['input', [string, (meta: ActionInputOnInputMeta) => void, ActionInputSetup?]] | ['custom', [CustomHandler]] | ['vibrate', [...number[]]] | ['next', []] | ['text', [...string[]]] | ['exit', []] | ['preload', [string]] | ['block', [string]] | ValidAction[];
|
|
49
50
|
type Story = Record<string, ValidAction[]>;
|
|
50
51
|
type Unwrappable = string | ((lang: string, obj: Record<string, unknown>) => string) | Record<string, string | (() => string)>;
|
|
51
52
|
type FunctionableValue<T> = T | (() => T);
|
|
@@ -100,6 +101,7 @@ interface ActionInputOnInputMeta {
|
|
|
100
101
|
value: string;
|
|
101
102
|
}
|
|
102
103
|
type ActionInputSetup = (input: HTMLInputElement, cleanup: (cb: () => void) => void) => void;
|
|
104
|
+
type BackgroundImage = Partial<Record<"portrait" | "landscape" | "all", string>> & Record<(string), string>;
|
|
103
105
|
type ActionProxyProvider<Characters extends Record<string, Character>> = {
|
|
104
106
|
choice: {
|
|
105
107
|
(...choices: ([Unwrappable, ValidAction[]] | [Unwrappable, ValidAction[], () => boolean])[]): ValidAction;
|
|
@@ -114,19 +116,15 @@ type ActionProxyProvider<Characters extends Record<string, Character>> = {
|
|
|
114
116
|
(person: string, content: Unwrappable, emotion?: undefined): ValidAction;
|
|
115
117
|
};
|
|
116
118
|
end: () => ValidAction;
|
|
117
|
-
showBackground: (background: string) => ValidAction;
|
|
119
|
+
showBackground: <T extends string | BackgroundImage>(background: T extends string ? T : T extends Record<PropertyKey, unknown> ? NonEmptyRecord<T> : never) => ValidAction;
|
|
118
120
|
playMusic: (audio: string) => ValidAction;
|
|
119
121
|
stopMusic: (audio: string) => ValidAction;
|
|
120
122
|
jump: (scene: string) => ValidAction;
|
|
121
123
|
showCharacter: {
|
|
122
124
|
<C extends keyof Characters>(character: C, emotion: keyof Characters[C]['emotions'], className?: string, style?: string): ValidAction;
|
|
123
125
|
};
|
|
124
|
-
hideCharacter:
|
|
125
|
-
|
|
126
|
-
};
|
|
127
|
-
animateCharacter: {
|
|
128
|
-
<C extends keyof Characters>(character: C, timeout: number, ...classes: string[]): ValidAction;
|
|
129
|
-
};
|
|
126
|
+
hideCharacter: (character: keyof Characters, className?: string, style?: string, duration?: number) => ValidAction;
|
|
127
|
+
animateCharacter: (character: keyof Characters, timeout: number, ...classes: string[]) => ValidAction;
|
|
130
128
|
wait: (time: FunctionableValue<number>) => ValidAction;
|
|
131
129
|
function: (fn: (restoring: boolean, goingBack: boolean) => Thenable<void>) => ValidAction;
|
|
132
130
|
input: (question: Unwrappable, onInput: (meta: ActionInputOnInputMeta) => void, setup?: ActionInputSetup) => ValidAction;
|
|
@@ -135,6 +133,7 @@ type ActionProxyProvider<Characters extends Record<string, Character>> = {
|
|
|
135
133
|
next: () => ValidAction;
|
|
136
134
|
text: (...text: Unwrappable[]) => ValidAction;
|
|
137
135
|
preload: (source: string) => ValidAction;
|
|
136
|
+
block: (scene: string) => ValidAction;
|
|
138
137
|
};
|
|
139
138
|
type DefaultActionProxyProvider = ActionProxyProvider<Record<string, Character>>;
|
|
140
139
|
type GetActionParameters<T extends Capitalize<keyof DefaultActionProxyProvider>> = Parameters<DefaultActionProxyProvider[Uncapitalize<T>]>;
|
|
@@ -165,7 +164,7 @@ interface RendererStore {
|
|
|
165
164
|
}
|
|
166
165
|
type Renderer = {
|
|
167
166
|
character: (character: string) => CharacterHandle;
|
|
168
|
-
background: (background: string) => void;
|
|
167
|
+
background: (background: string | BackgroundImage) => void;
|
|
169
168
|
dialog: (content: string, name: string, character?: string, emotion?: string) => (resolve: () => void, goingBack: boolean) => void;
|
|
170
169
|
choices: (question: string, choices: ([string, ValidAction[]] | [string, ValidAction[], () => boolean])[]) => (resolve: (selected: number) => void) => void;
|
|
171
170
|
input: (question: string, onInput: Parameters<DefaultActionProxyProvider['input']>[1], setup?: Parameters<DefaultActionProxyProvider['input']>[2]) => (resolve: () => void) => void;
|
package/dist/index.global.js
CHANGED
|
@@ -141,6 +141,13 @@ var Novely = (() => {
|
|
|
141
141
|
novely: () => novely
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
+
// src/constants.ts
|
|
145
|
+
var SKIPPED_DURING_RESTORE = /* @__PURE__ */ new Set(["dialog", "choice", "input", "vibrate", "text"]);
|
|
146
|
+
var BLOCK_EXIT_STATEMENTS = /* @__PURE__ */ new Set(["choice:exit", "condition:exit", "block:exit"]);
|
|
147
|
+
var BLOCK_STATEMENTS = /* @__PURE__ */ new Set(["choice", "condition", "block"]);
|
|
148
|
+
var EMPTY_SET = /* @__PURE__ */ new Set();
|
|
149
|
+
var DEFAULT_TYPEWRITER_SPEED = "Medium";
|
|
150
|
+
|
|
144
151
|
// src/utils.ts
|
|
145
152
|
var matchAction = (values) => {
|
|
146
153
|
return (action, props) => {
|
|
@@ -213,8 +220,8 @@ var Novely = (() => {
|
|
|
213
220
|
}
|
|
214
221
|
};
|
|
215
222
|
var findLastIndex = (array, fn) => {
|
|
216
|
-
for (let i = array.length - 1; i
|
|
217
|
-
if (fn(array[i])) {
|
|
223
|
+
for (let i = array.length - 1; i >= 0; i--) {
|
|
224
|
+
if (fn(array[i], array[i + 1])) {
|
|
218
225
|
return i;
|
|
219
226
|
}
|
|
220
227
|
}
|
|
@@ -242,6 +249,24 @@ var Novely = (() => {
|
|
|
242
249
|
});
|
|
243
250
|
return { resolve, reject, promise };
|
|
244
251
|
};
|
|
252
|
+
var findLastPathItemBeforeItemOfType = (path, name) => {
|
|
253
|
+
const index = findLastIndex(path, ([_name, _value], next) => {
|
|
254
|
+
return isNull(_name) && isNumber(_value) && next != null && next[0] === name;
|
|
255
|
+
});
|
|
256
|
+
return path[index];
|
|
257
|
+
};
|
|
258
|
+
var isBlockStatement = (statement) => {
|
|
259
|
+
return BLOCK_STATEMENTS.has(statement);
|
|
260
|
+
};
|
|
261
|
+
var isBlockExitStatement = (statement) => {
|
|
262
|
+
return BLOCK_EXIT_STATEMENTS.has(statement);
|
|
263
|
+
};
|
|
264
|
+
var isSkippedDurigRestore = (item) => {
|
|
265
|
+
return SKIPPED_DURING_RESTORE.has(item);
|
|
266
|
+
};
|
|
267
|
+
var isAction = (element) => {
|
|
268
|
+
return Array.isArray(element) && isString(element[0]);
|
|
269
|
+
};
|
|
245
270
|
|
|
246
271
|
// src/global.ts
|
|
247
272
|
var PRELOADED_ASSETS = /* @__PURE__ */ new Set();
|
|
@@ -298,11 +323,6 @@ var Novely = (() => {
|
|
|
298
323
|
return val;
|
|
299
324
|
}
|
|
300
325
|
|
|
301
|
-
// src/constants.ts
|
|
302
|
-
var SKIPPED_DURING_RESTORE = /* @__PURE__ */ new Set(["dialog", "choice", "input", "vibrate", "text"]);
|
|
303
|
-
var EMPTY_SET = /* @__PURE__ */ new Set();
|
|
304
|
-
var DEFAULT_TYPEWRITER_SPEED = "Medium";
|
|
305
|
-
|
|
306
326
|
// ../t9n/dist/index.js
|
|
307
327
|
var g = (e, r) => {
|
|
308
328
|
let o = [];
|
|
@@ -534,31 +554,46 @@ var Novely = (() => {
|
|
|
534
554
|
latest = klona(initial);
|
|
535
555
|
}
|
|
536
556
|
restoring = true, stack.value = latest;
|
|
557
|
+
const path = stack.value[0];
|
|
537
558
|
let current = story;
|
|
559
|
+
let precurrent;
|
|
560
|
+
let ignoreNested = false;
|
|
538
561
|
let index = 0;
|
|
539
562
|
const max = stack.value[0].reduce((acc, [type, val]) => {
|
|
540
|
-
if (isNull(type) && isNumber(val))
|
|
563
|
+
if (isNull(type) && isNumber(val)) {
|
|
541
564
|
return acc + 1;
|
|
565
|
+
}
|
|
542
566
|
return acc;
|
|
543
567
|
}, 0);
|
|
544
568
|
const queue = [];
|
|
545
569
|
const keep = /* @__PURE__ */ new Set();
|
|
546
570
|
const characters2 = /* @__PURE__ */ new Set();
|
|
547
|
-
|
|
571
|
+
const blocks = [];
|
|
572
|
+
for (const [type, val] of path) {
|
|
548
573
|
if (type === null) {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
} else if (isNumber(val)) {
|
|
574
|
+
precurrent = current;
|
|
575
|
+
if (isNumber(val)) {
|
|
552
576
|
index++;
|
|
553
|
-
|
|
554
|
-
|
|
577
|
+
let startIndex = 0;
|
|
578
|
+
if (ignoreNested) {
|
|
579
|
+
const prev = findLastPathItemBeforeItemOfType(path.slice(0, index), "block");
|
|
580
|
+
if (prev) {
|
|
581
|
+
startIndex = prev[1];
|
|
582
|
+
ignoreNested = false;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
for (let i = startIndex; i <= val; i++) {
|
|
586
|
+
const item = current[i];
|
|
587
|
+
if (!isAction(item))
|
|
588
|
+
continue;
|
|
589
|
+
const [action2, ...meta] = item;
|
|
555
590
|
const push2 = () => {
|
|
556
591
|
keep.add(action2);
|
|
557
592
|
queue.push([action2, meta]);
|
|
558
593
|
};
|
|
559
594
|
if (action2 === "showCharacter")
|
|
560
595
|
characters2.add(meta[0]);
|
|
561
|
-
if (
|
|
596
|
+
if (isSkippedDurigRestore(action2) || isUserRequiredAction(action2, meta)) {
|
|
562
597
|
if (index === max && i === val) {
|
|
563
598
|
push2();
|
|
564
599
|
} else {
|
|
@@ -567,12 +602,20 @@ var Novely = (() => {
|
|
|
567
602
|
}
|
|
568
603
|
push2();
|
|
569
604
|
}
|
|
570
|
-
current = current[val];
|
|
571
605
|
}
|
|
606
|
+
current = current[val];
|
|
572
607
|
} else if (type === "choice") {
|
|
608
|
+
blocks.push(precurrent = current);
|
|
573
609
|
current = current[val + 1][1];
|
|
574
610
|
} else if (type === "condition") {
|
|
611
|
+
blocks.push(precurrent = current);
|
|
575
612
|
current = current[2][val];
|
|
613
|
+
} else if (type === "block") {
|
|
614
|
+
blocks.push(precurrent);
|
|
615
|
+
current = story[val];
|
|
616
|
+
} else if (type === "block:exit" || type === "choice:exit" || type === "condition:exit") {
|
|
617
|
+
current = blocks.pop();
|
|
618
|
+
ignoreNested = true;
|
|
576
619
|
}
|
|
577
620
|
}
|
|
578
621
|
renderer.ui.showScreen("game");
|
|
@@ -587,7 +630,8 @@ var Novely = (() => {
|
|
|
587
630
|
const c0 = _meta[0];
|
|
588
631
|
const c1 = meta[0];
|
|
589
632
|
const isIdenticalID = c0.id && c1.id && c0.id === c1.id;
|
|
590
|
-
|
|
633
|
+
const isIdenticalByReference = c0 === c1;
|
|
634
|
+
return isIdenticalID || isIdenticalByReference || str(c0) === str(c1);
|
|
591
635
|
});
|
|
592
636
|
if (notLatest)
|
|
593
637
|
continue;
|
|
@@ -618,15 +662,25 @@ var Novely = (() => {
|
|
|
618
662
|
}
|
|
619
663
|
restoring = goingBack = false, render();
|
|
620
664
|
};
|
|
621
|
-
const refer = () => {
|
|
665
|
+
const refer = (path = stack.value[0]) => {
|
|
622
666
|
let current = story;
|
|
623
|
-
|
|
667
|
+
let precurrent = story;
|
|
668
|
+
const blocks = [];
|
|
669
|
+
for (const [type, val] of path) {
|
|
624
670
|
if (type === null) {
|
|
671
|
+
precurrent = current;
|
|
625
672
|
current = current[val];
|
|
626
673
|
} else if (type === "choice") {
|
|
674
|
+
blocks.push(precurrent = current);
|
|
627
675
|
current = current[val + 1][1];
|
|
628
676
|
} else if (type === "condition") {
|
|
677
|
+
blocks.push(precurrent = current);
|
|
629
678
|
current = current[2][val];
|
|
679
|
+
} else if (type === "block") {
|
|
680
|
+
blocks.push(precurrent);
|
|
681
|
+
current = story[val];
|
|
682
|
+
} else if (type === "block:exit" || type === "choice:exit" || type === "condition:exit") {
|
|
683
|
+
current = blocks.pop();
|
|
630
684
|
}
|
|
631
685
|
}
|
|
632
686
|
return current;
|
|
@@ -749,9 +803,13 @@ var Novely = (() => {
|
|
|
749
803
|
renderer.clear(goingBack, keep || EMPTY_SET, characters2 || EMPTY_SET)(push);
|
|
750
804
|
},
|
|
751
805
|
condition([condition]) {
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
806
|
+
if (!restoring) {
|
|
807
|
+
stack.value[0].push(
|
|
808
|
+
["condition", String(condition())],
|
|
809
|
+
[null, 0]
|
|
810
|
+
);
|
|
811
|
+
render();
|
|
812
|
+
}
|
|
755
813
|
},
|
|
756
814
|
end() {
|
|
757
815
|
match("clear", []);
|
|
@@ -803,24 +861,55 @@ var Novely = (() => {
|
|
|
803
861
|
renderer.text(text.map((content) => unwrap(content)).join(" "), forward, goingBack);
|
|
804
862
|
},
|
|
805
863
|
exit() {
|
|
864
|
+
if (restoring)
|
|
865
|
+
return;
|
|
806
866
|
const path = stack.value[0];
|
|
807
|
-
|
|
867
|
+
const last = path.at(-1);
|
|
868
|
+
const ignore = [];
|
|
869
|
+
if (!isAction(refer(path))) {
|
|
870
|
+
if (last && isNull(last[0]) && isNumber(last[1])) {
|
|
871
|
+
last[1]--;
|
|
872
|
+
} else {
|
|
873
|
+
path.pop();
|
|
874
|
+
}
|
|
875
|
+
}
|
|
808
876
|
for (let i = path.length - 1; i > 0; i--) {
|
|
809
|
-
|
|
877
|
+
const [name] = path[i];
|
|
878
|
+
if (isBlockExitStatement(name)) {
|
|
879
|
+
ignore.push(name);
|
|
880
|
+
}
|
|
881
|
+
if (!isBlockStatement(name))
|
|
810
882
|
continue;
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
883
|
+
if (ignore.at(-1)?.startsWith(name)) {
|
|
884
|
+
ignore.pop();
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
path.push([`${name}:exit`]);
|
|
888
|
+
const prev = findLastPathItemBeforeItemOfType(path.slice(0, i + 1), name);
|
|
889
|
+
if (prev)
|
|
890
|
+
path.push([null, prev[1] + 1]);
|
|
891
|
+
if (!isAction(refer(path))) {
|
|
892
|
+
path.pop();
|
|
893
|
+
continue;
|
|
894
|
+
}
|
|
814
895
|
break;
|
|
815
896
|
}
|
|
816
|
-
|
|
817
|
-
render();
|
|
897
|
+
render();
|
|
818
898
|
},
|
|
819
899
|
preload([source]) {
|
|
820
900
|
if (!PRELOADED_ASSETS.has(source) && !goingBack && !restoring) {
|
|
821
901
|
PRELOADED_ASSETS.add(document.createElement("img").src = source);
|
|
822
902
|
}
|
|
823
903
|
push();
|
|
904
|
+
},
|
|
905
|
+
block([scene]) {
|
|
906
|
+
if (!restoring) {
|
|
907
|
+
stack.value[0].push(
|
|
908
|
+
["block", scene],
|
|
909
|
+
[null, 0]
|
|
910
|
+
);
|
|
911
|
+
render();
|
|
912
|
+
}
|
|
824
913
|
}
|
|
825
914
|
});
|
|
826
915
|
const enmemory = () => {
|
|
@@ -834,13 +923,11 @@ var Novely = (() => {
|
|
|
834
923
|
const next = () => {
|
|
835
924
|
const path = stack.value[0];
|
|
836
925
|
const last = path.at(-1);
|
|
837
|
-
if (
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
return;
|
|
926
|
+
if (last && isNull(last[0]) && isNumber(last[1])) {
|
|
927
|
+
last[1]++;
|
|
928
|
+
} else {
|
|
929
|
+
path.push([null, 0]);
|
|
842
930
|
}
|
|
843
|
-
path.push([null, 0]);
|
|
844
931
|
};
|
|
845
932
|
const render = () => {
|
|
846
933
|
const referred = refer();
|