@novely/core 0.29.2 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,11 +1,3 @@
1
- type Name<Keys extends string = string> = string | Record<Keys, string>;
2
- type Emotions<Keys extends string = string> = Record<Keys, string | string[]>;
3
- type Character<LanguageKeys extends string = string> = {
4
- name: Name<LanguageKeys>;
5
- color: string;
6
- emotions: Emotions;
7
- };
8
-
9
1
  interface LocalStorageStorageSettings {
10
2
  key: string;
11
3
  }
@@ -237,7 +229,7 @@ type Save<S extends State = State> = [
237
229
  type Lang = string;
238
230
  type TypewriterSpeed = 'Slow' | 'Medium' | 'Fast' | 'Auto';
239
231
  type SoundVolume = number;
240
- type StorageMeta<L extends string = string> = [
232
+ type StorageMeta<L extends Lang = string> = [
241
233
  lang: L,
242
234
  typewriter_speed: TypewriterSpeed,
243
235
  music_volume: SoundVolume,
@@ -245,7 +237,7 @@ type StorageMeta<L extends string = string> = [
245
237
  voice_volume: SoundVolume
246
238
  ];
247
239
  type Migration = (save: unknown) => unknown;
248
- type StorageData<L extends string = string, D extends Data = Data> = {
240
+ type StorageData<L extends Lang = string, D extends Data = Data> = {
249
241
  saves: Save[];
250
242
  data: D;
251
243
  meta: StorageMeta<L>;
@@ -303,6 +295,36 @@ interface NovelyInit<$Language extends Lang, Characters extends Record<string, C
303
295
  * ```
304
296
  */
305
297
  characters: Characters;
298
+ /**
299
+ * Define default emotions for characters
300
+ * @example
301
+ * ```ts
302
+ * const engine = novely({
303
+ * characters: {
304
+ * Yuki: {
305
+ * name: 'Yuki',
306
+ * color: '#f595f6',
307
+ * emotions: {
308
+ * normal: './normal.png'
309
+ * }
310
+ * }
311
+ * },
312
+ * defaultEmotions: {
313
+ * Yuki: 'normal'
314
+ * }
315
+ * });
316
+ *
317
+ * engine.script({
318
+ * start: [
319
+ * // Without emotion!
320
+ * engine.action.showCharacter('Yuki')
321
+ * ]
322
+ * })
323
+ * ```
324
+ */
325
+ defaultEmotions?: {
326
+ [Character in keyof NoInfer<Characters>]?: (keyof NoInfer<Characters>[Character]['emotions'] & string);
327
+ };
306
328
  /**
307
329
  * An object that provides access to the game's storage system.
308
330
  * @default localStorage // at key `novely-game-storage`
@@ -440,6 +462,14 @@ type StateFunction<S extends State> = {
440
462
  (): S;
441
463
  };
442
464
 
465
+ type Name<$Lang extends Lang> = string | Record<$Lang, string>;
466
+ type Emotions<Emotion extends string = string> = Record<Emotion, string | string[]>;
467
+ type Character<$Lang extends Lang = string> = {
468
+ name: Name<$Lang>;
469
+ color: string;
470
+ emotions: Emotions;
471
+ };
472
+
443
473
  type ValidAction = ['choice', number] | ['clear', Set<keyof DefaultActionProxy>?, Set<string>?, {
444
474
  music: Set<string>;
445
475
  sounds: Set<string>;
@@ -579,7 +609,7 @@ type ActionProxy<Characters extends Record<string, Character>, Languages extends
579
609
  stopVoice: () => ValidAction;
580
610
  jump: (scene: string) => ValidAction;
581
611
  showCharacter: {
582
- <C extends keyof Characters>(character: C, emotion: keyof Characters[C]['emotions'], className?: string, style?: string): ValidAction;
612
+ <C extends keyof Characters>(character: C, emotion?: keyof Characters[C]['emotions'], className?: string, style?: string): ValidAction;
583
613
  };
584
614
  hideCharacter: (character: keyof Characters, className?: string, style?: string, duration?: number) => ValidAction;
585
615
  animateCharacter: (character: keyof Characters, timeout: number, ...classes: string[]) => ValidAction;
@@ -598,7 +628,7 @@ type GetActionParameters<T extends Capitalize<keyof DefaultActionProxy>> = Param
598
628
 
599
629
  type ConditionParams<T> = T extends ActionProxy<Record<string, Character>, Lang, infer $State> ? Parameters<ConditionCheckFunction<$State, string | boolean>>[0] : never;
600
630
 
601
- declare const novely: <$Language extends string, Characters extends Record<string, Character<$Language>>, StateScheme extends State, DataScheme extends Data>({ characters, storage, storageDelay, renderer: createRenderer, initialScreen, translation, state: defaultState, data: defaultData, autosaves, migrations, throttleTimeout, getLanguage, overrideLanguage, askBeforeExit, preloadAssets, parallelAssetsDownloadLimit, fetch: request, saveOnUnload, startKey }: NovelyInit<$Language, Characters, StateScheme, DataScheme>) => {
631
+ declare const novely: <$Language extends string, Characters extends Record<string, Character<$Language>>, StateScheme extends State, DataScheme extends Data>({ characters, defaultEmotions, storage, storageDelay, renderer: createRenderer, initialScreen, translation, state: defaultState, data: defaultData, autosaves, migrations, throttleTimeout, getLanguage, overrideLanguage, askBeforeExit, preloadAssets, parallelAssetsDownloadLimit, fetch: request, saveOnUnload, startKey }: NovelyInit<$Language, Characters, StateScheme, DataScheme>) => {
602
632
  /**
603
633
  * Function to set game script
604
634
  *
@@ -699,7 +699,7 @@ var Novely = (() => {
699
699
  return { subscribe, update, set, get };
700
700
  };
701
701
 
702
- // ../deepmerge/dist/index.js
702
+ // ../../node_modules/.pnpm/@novely+deepmerge@0.0.0/node_modules/@novely/deepmerge/dist/index.js
703
703
  var { isArray } = Array;
704
704
  var { hasOwnProperty, propertyIsEnumerable, getOwnPropertySymbols } = Object;
705
705
  var propertyIsOnObject = (object, property) => {
@@ -710,9 +710,7 @@ var Novely = (() => {
710
710
  }
711
711
  };
712
712
  var propertyIsUnsafe = (target, key) => {
713
- return propertyIsOnObject(target, key) && // Properties are safe to merge if they don't exist in the target yet,
714
- !(hasOwnProperty.call(target, key) && // unsafe if they exist up the prototype chain,
715
- propertyIsEnumerable.call(target, key));
713
+ return propertyIsOnObject(target, key) && !(hasOwnProperty.call(target, key) && propertyIsEnumerable.call(target, key));
716
714
  };
717
715
  var getEnumerableOwnPropertySymbols = (target) => {
718
716
  if (!getOwnPropertySymbols)
@@ -887,6 +885,7 @@ var Novely = (() => {
887
885
  var import_p_limit = __toESM(require_p_limit(), 1);
888
886
  var novely = ({
889
887
  characters,
888
+ defaultEmotions = {},
890
889
  storage = localStorageStorage({ key: "novely-game-storage" }),
891
890
  storageDelay = Promise.resolve(),
892
891
  renderer: createRenderer,
@@ -1124,6 +1123,12 @@ var Novely = (() => {
1124
1123
  };
1125
1124
  let interacted = 0;
1126
1125
  const restore = async (save2) => {
1126
+ if (isEmpty(story)) {
1127
+ if (DEV) {
1128
+ throw new Error("Story is empty. You should call an `enine.script` function [https://novely.pages.dev/guide/story.html]");
1129
+ }
1130
+ return;
1131
+ }
1127
1132
  if (!coreData.get().dataLoaded)
1128
1133
  return;
1129
1134
  let latest = save2 || storageData.get().saves.at(-1);
@@ -1244,6 +1249,8 @@ var Novely = (() => {
1244
1249
  return translation[lang].internal[key];
1245
1250
  };
1246
1251
  const preview = async (save2, name) => {
1252
+ if (isEmpty(story))
1253
+ return;
1247
1254
  const [path, data2] = save2;
1248
1255
  const { queue } = getActionsFromPath(story, path, true);
1249
1256
  const ctx = renderer.getContext(name);
@@ -1396,6 +1403,12 @@ var Novely = (() => {
1396
1403
  push();
1397
1404
  },
1398
1405
  showCharacter({ ctx, push }, [character, emotion, className, style]) {
1406
+ emotion ??= defaultEmotions[character];
1407
+ if (DEV && !emotion) {
1408
+ throw new Error(`Attemp to show character "${character}" without emotion provided.`);
1409
+ }
1410
+ if (!emotion)
1411
+ return;
1399
1412
  if (DEV && !characters[character].emotions[emotion]) {
1400
1413
  throw new Error(`Attempt to show character "${character}" with unknown emotion "${emotion}"`);
1401
1414
  }
@@ -1533,11 +1546,7 @@ var Novely = (() => {
1533
1546
  end({ ctx }) {
1534
1547
  if (ctx.meta.preview)
1535
1548
  return;
1536
- ctx.vibrate(0);
1537
- ctx.clear(EMPTY_SET, EMPTY_SET, { music: EMPTY_SET, sounds: EMPTY_SET }, noop);
1538
- renderer.ui.showScreen("mainmenu");
1539
- interactivity(false);
1540
- times.clear();
1549
+ exit(true);
1541
1550
  },
1542
1551
  input({ ctx, data: data2, forward }, [question, onInput, setup]) {
1543
1552
  ctx.input(