@novely/core 0.47.1 → 0.48.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
@@ -544,6 +544,10 @@ interface NovelyInit<$Language extends Lang, $Characters extends Record<string,
544
544
  * ```
545
545
  */
546
546
  startKey?: 'start' | (string & Record<never, never>);
547
+ /**
548
+ * Typewriter speed set by default
549
+ */
550
+ defaultTypewriterSpeed?: TypewriterSpeed;
547
551
  }
548
552
  type StateFunction<S extends State> = {
549
553
  (value: DeepPartial<S> | ((prev: S) => S)): void;
@@ -672,9 +676,9 @@ type CustomHandlerCalling = {
672
676
  callOnlyLatest?: boolean;
673
677
  /**
674
678
  * Manually check should be skipped or not during restore
675
- * @param getNext Function which will return next actions in queue
679
+ * @param nextActions Next actions in the restoring queue
676
680
  */
677
- skipOnRestore?: (getNext: () => Exclude<ValidAction, ValidAction[]>[]) => boolean;
681
+ skipOnRestore?: (nextActions: Exclude<ValidAction, ValidAction[]>[]) => boolean;
678
682
  };
679
683
  type CustomHandlerInfo = CustomHandlerCalling & {
680
684
  /**
@@ -854,7 +858,7 @@ type ChoiceParams<T> = T extends TypeEssentials<infer $Lang, infer $State, any,
854
858
  type FunctionParams<T> = T extends TypeEssentials<infer $Lang, infer $State, any, any> ? FunctionActionProps<$Lang, $State> : never;
855
859
  type InputHandler<T> = T extends TypeEssentials<infer $Lang, infer $State, any, any> ? ActionInputOnInputMeta<$Lang, $State> : never;
856
860
 
857
- declare const novely: <$Language extends string, $Characters extends Record<string, Character<$Language>>, $State extends State, $Data extends Data, $Actions extends Record<string, (...args: any[]) => ValidAction>>({ characters, characterAssetSizes, defaultEmotions, storage, storageDelay, renderer: createRenderer, initialScreen, translation, state: defaultState, data: defaultData, autosaves, migrations, throttleTimeout, getLanguage, overrideLanguage, askBeforeExit, preloadAssets, parallelAssetsDownloadLimit, fetch: request, cloneFunction: clone, saveOnUnload, startKey, }: NovelyInit<$Language, $Characters, $State, $Data, $Actions>) => {
861
+ declare const novely: <$Language extends string, $Characters extends Record<string, Character<$Language>>, $State extends State, $Data extends Data, $Actions extends Record<string, (...args: any[]) => ValidAction>>({ characters, characterAssetSizes, defaultEmotions, storage, storageDelay, renderer: createRenderer, initialScreen, translation, state: defaultState, data: defaultData, autosaves, migrations, throttleTimeout, getLanguage, overrideLanguage, askBeforeExit, preloadAssets, parallelAssetsDownloadLimit, fetch: request, cloneFunction: clone, saveOnUnload, startKey, defaultTypewriterSpeed, }: NovelyInit<$Language, $Characters, $State, $Data, $Actions>) => {
858
862
  /**
859
863
  * Function to set game script
860
864
  *
@@ -882,7 +886,8 @@ declare const novely: <$Language extends string, $Characters extends Record<stri
882
886
  */
883
887
  action: $Actions & ActionProxy<$Characters, $Language, $State> & VirtualActions<$Characters, $Language, $State>;
884
888
  /**
885
- * @deprecated Will be removed BUT replaced with state passed into actions as a parameter
889
+ * State bound to `$MAIN` game context
890
+ * @deprecated Use `state` function provided from action arguments
886
891
  */
887
892
  state: StateFunction<State>;
888
893
  /**
@@ -965,6 +970,7 @@ declare const novely: <$Language extends string, $Characters extends Record<stri
965
970
  setStorageData: (data: StorageData<$Language, $Data>) => void;
966
971
  };
967
972
 
973
+ type Part = Record<string, (...args: any[]) => ValidAction>;
968
974
  /**
969
975
  * Extens core action with custom actions
970
976
  * @param base Actions object you will extend, `engine.action`
@@ -978,7 +984,7 @@ declare const novely: <$Language extends string, $Characters extends Record<stri
978
984
  * })
979
985
  * ```
980
986
  */
981
- declare const extendAction: <Part0 extends Record<string, (...args: any[]) => ValidAction>, Part1 extends Record<string, (...args: any[]) => ValidAction>>(base: Part0, extension: Part1) => Readonly<Assign<Part0, Part1>>;
987
+ declare const extendAction: <Part0 extends Part, Part1 extends Part>(base: Part0, extension: Part1) => Readonly<Assign<Part0, Part1>>;
982
988
 
983
989
  /**
984
990
  * Memoizes and returns an asset selection object based on provided file variants.
@@ -494,7 +494,7 @@ var Novely = (() => {
494
494
  // src/utilities/match-action.ts
495
495
  var matchAction = (callbacks, values) => {
496
496
  const { getContext, onBeforeActionCall, push, forward } = callbacks;
497
- return (action, props, { ctx, data }) => {
497
+ const match = (action, props, { ctx, data }) => {
498
498
  const context = typeof ctx === "string" ? getContext(ctx) : ctx;
499
499
  onBeforeActionCall({
500
500
  action,
@@ -517,6 +517,10 @@ var Novely = (() => {
517
517
  props
518
518
  );
519
519
  };
520
+ return {
521
+ match,
522
+ nativeActions: Object.keys(values)
523
+ };
520
524
  };
521
525
 
522
526
  // src/utilities/ungrupped.ts
@@ -834,7 +838,7 @@ var Novely = (() => {
834
838
  const characters = /* @__PURE__ */ new Set();
835
839
  const audio2 = {
836
840
  music: /* @__PURE__ */ new Set(),
837
- sound: /* @__PURE__ */ new Set()
841
+ sounds: /* @__PURE__ */ new Set()
838
842
  };
839
843
  const next = (i) => queue.slice(i + 1);
840
844
  for (const [i, item] of queue.entries()) {
@@ -847,39 +851,50 @@ var Novely = (() => {
847
851
  if (action === "custom") {
848
852
  const fn = params[0];
849
853
  if ("callOnlyLatest" in fn && fn.callOnlyLatest) {
850
- const notLatest = next(i).some(([, func]) => {
851
- if (!isFunction(func)) return false;
852
- const c0 = func;
853
- const c1 = fn;
854
- const isIdenticalID = Boolean(c0.id && c1.id && c0.id === c1.id);
855
- const isIdenticalByReference = c0 === c1;
856
- return isIdenticalID || isIdenticalByReference || String(c0) === String(c1);
854
+ const notLatest = next(i).some(([name, func]) => {
855
+ if (name !== "custom") return;
856
+ const isIdenticalId = Boolean(func.id && fn.id && func.id === fn.id);
857
+ const isIdenticalByReference = func === fn;
858
+ const isIdenticalByCode = String(func) === String(fn);
859
+ return isIdenticalId || isIdenticalByReference || isIdenticalByCode;
857
860
  });
858
861
  if (notLatest) continue;
859
862
  } else if ("skipOnRestore" in fn && fn.skipOnRestore) {
860
- if (fn.skipOnRestore(() => next(i))) {
863
+ if (fn.skipOnRestore(next(i))) {
861
864
  continue;
862
865
  }
863
866
  }
864
867
  }
865
868
  processedQueue.push(item);
866
- } else if (action === "showCharacter" || action === "playSound" || action === "playMusic" || action === "voice") {
869
+ } else if (action === "playSound") {
870
+ const closing = getOppositeAction(action);
871
+ const skip = next(i).some((item2) => {
872
+ if (isUserRequiredAction(item2) || isSkippedDuringRestore(item2[0])) {
873
+ return true;
874
+ }
875
+ const [_action, target] = item2;
876
+ if (target !== params[0]) {
877
+ return false;
878
+ }
879
+ return _action === closing || _action === action;
880
+ });
881
+ if (skip) continue;
882
+ audio2.sounds.add(unwrapAsset(params[0]));
883
+ processedQueue.push(item);
884
+ } else if (action === "showCharacter" || action === "playMusic" || action === "voice") {
867
885
  const closing = getOppositeAction(action);
868
886
  const skip = next(i).some(([_action, target]) => {
869
887
  if (target !== params[0] && action !== "voice") {
870
888
  return false;
871
889
  }
872
- const musicGonnaBePaused = action === "playMusic" && _action === "pauseMusic";
873
- const soundGonnaBePaused = action === "playSound" && _action === "pauseSound";
874
- return musicGonnaBePaused || soundGonnaBePaused || _action === closing || _action === action;
890
+ const musicWillBePaused = action === "playMusic" && _action === "pauseMusic";
891
+ return musicWillBePaused || _action === closing || _action === action;
875
892
  });
876
893
  if (skip) continue;
877
894
  if (action === "showCharacter") {
878
895
  characters.add(params[0]);
879
896
  } else if (action === "playMusic") {
880
897
  audio2.music.add(unwrapAsset(params[0]));
881
- } else if (action === "playSound") {
882
- audio2.sound.add(unwrapAsset(params[0]));
883
898
  }
884
899
  processedQueue.push(item);
885
900
  } else if (action === "showBackground" || action === "preload") {
@@ -894,7 +909,8 @@ var Novely = (() => {
894
909
  const next2 = array.slice(j);
895
910
  const characterWillAnimate = next2.some(([__action, __character]) => action === __action);
896
911
  const hasBlockingActions = next2.some((item2) => options.skip.has(item2));
897
- return characterWillAnimate && hasBlockingActions;
912
+ const differentCharacterWillAnimate = !hasBlockingActions && next2.some(([__action, __character]) => __action === action && __character !== params[0]);
913
+ return characterWillAnimate && hasBlockingActions || differentCharacterWillAnimate;
898
914
  });
899
915
  if (skip) continue;
900
916
  processedQueue.push(item);
@@ -1353,6 +1369,69 @@ var Novely = (() => {
1353
1369
  });
1354
1370
  };
1355
1371
 
1372
+ // src/utilities/actions.ts
1373
+ var VIRTUAL_ACTIONS = ["say"];
1374
+ var buildActionObject = ({
1375
+ rendererActions,
1376
+ nativeActions,
1377
+ characters,
1378
+ preloadAssets,
1379
+ storageData
1380
+ }) => {
1381
+ const allActions = [...nativeActions, ...VIRTUAL_ACTIONS];
1382
+ const object = { ...rendererActions };
1383
+ for (let action of allActions) {
1384
+ object[action] = (...props) => {
1385
+ if (action === "say") {
1386
+ action = "dialog";
1387
+ const [character] = props;
1388
+ if (DEV && !characters[character]) {
1389
+ throw new Error(`Attempt to call Say action with unknown character "${character}"`);
1390
+ }
1391
+ } else if (action === "choice") {
1392
+ if (props.slice(1).every((choice) => !Array.isArray(choice))) {
1393
+ for (let i = 1; i < props.length; i++) {
1394
+ const choice = props[i];
1395
+ props[i] = [
1396
+ choice.title,
1397
+ flatActions(choice.children),
1398
+ choice.active,
1399
+ choice.visible,
1400
+ choice.onSelect,
1401
+ choice.image
1402
+ ];
1403
+ }
1404
+ } else {
1405
+ for (let i = 1; i < props.length; i++) {
1406
+ const choice = props[i];
1407
+ if (Array.isArray(choice)) {
1408
+ choice[1] = flatActions(choice[1]);
1409
+ }
1410
+ }
1411
+ }
1412
+ } else if (action === "condition") {
1413
+ const actions = props[1];
1414
+ for (const key in actions) {
1415
+ actions[key] = flatActions(actions[key]);
1416
+ }
1417
+ }
1418
+ if (preloadAssets === "blocking") {
1419
+ huntAssets({
1420
+ action,
1421
+ props,
1422
+ mode: preloadAssets,
1423
+ characters,
1424
+ lang: getLanguageFromStore(storageData),
1425
+ volume: getVolumeFromStore(storageData),
1426
+ handle: enqueueAssetForPreloading
1427
+ });
1428
+ }
1429
+ return [action, ...props];
1430
+ };
1431
+ }
1432
+ return object;
1433
+ };
1434
+
1356
1435
  // src/novely.ts
1357
1436
  var novely = ({
1358
1437
  characters,
@@ -1376,7 +1455,8 @@ var Novely = (() => {
1376
1455
  fetch: request = fetch,
1377
1456
  cloneFunction: clone = klona,
1378
1457
  saveOnUnload = true,
1379
- startKey = "start"
1458
+ startKey = "start",
1459
+ defaultTypewriterSpeed = DEFAULT_TYPEWRITER_SPEED
1380
1460
  }) => {
1381
1461
  const languages = Object.keys(translation);
1382
1462
  const limitScript = pLimit(1);
@@ -1421,61 +1501,6 @@ var Novely = (() => {
1421
1501
  const script = (part) => {
1422
1502
  return limitScript(() => scriptBase(part));
1423
1503
  };
1424
- const action = new Proxy({}, {
1425
- get(_, action2) {
1426
- if (action2 in renderer.actions) {
1427
- return renderer.actions[action2];
1428
- }
1429
- return (...props) => {
1430
- if (action2 === "say") {
1431
- action2 = "dialog";
1432
- const [character] = props;
1433
- if (DEV && !characters[character]) {
1434
- throw new Error(`Attempt to call Say action with unknown character "${character}"`);
1435
- }
1436
- } else if (action2 === "choice") {
1437
- const actions = props.slice(1);
1438
- if (actions.every((choice) => !Array.isArray(choice))) {
1439
- for (let i = 1; i < props.length; i++) {
1440
- const choice = props[i];
1441
- props[i] = [
1442
- choice.title,
1443
- flatActions(choice.children),
1444
- choice.active,
1445
- choice.visible,
1446
- choice.onSelect,
1447
- choice.image
1448
- ];
1449
- }
1450
- } else {
1451
- for (let i = 1; i < props.length; i++) {
1452
- const choice = props[i];
1453
- if (Array.isArray(choice)) {
1454
- choice[1] = flatActions(choice[1]);
1455
- }
1456
- }
1457
- }
1458
- } else if (action2 === "condition") {
1459
- const actions = props[1];
1460
- for (const key in actions) {
1461
- actions[key] = flatActions(actions[key]);
1462
- }
1463
- }
1464
- if (preloadAssets === "blocking") {
1465
- huntAssets({
1466
- action: action2,
1467
- props,
1468
- mode: preloadAssets,
1469
- characters,
1470
- lang: getLanguageFromStore(storageData),
1471
- volume: getVolumeFromStore(storageData),
1472
- handle: enqueueAssetForPreloading
1473
- });
1474
- }
1475
- return [action2, ...props];
1476
- };
1477
- }
1478
- });
1479
1504
  const getDefaultSave = (state) => {
1480
1505
  return [
1481
1506
  [
@@ -1545,7 +1570,7 @@ var Novely = (() => {
1545
1570
  if (overrideLanguage || !stored.meta[0]) {
1546
1571
  stored.meta[0] = getLanguageWithoutParameters();
1547
1572
  }
1548
- stored.meta[1] ||= DEFAULT_TYPEWRITER_SPEED;
1573
+ stored.meta[1] ||= defaultTypewriterSpeed;
1549
1574
  stored.meta[2] ??= 1;
1550
1575
  stored.meta[3] ??= 1;
1551
1576
  stored.meta[4] ??= 1;
@@ -1953,7 +1978,7 @@ var Novely = (() => {
1953
1978
  }
1954
1979
  }
1955
1980
  };
1956
- const match = matchAction(matchActionOptions, {
1981
+ const { match, nativeActions } = matchAction(matchActionOptions, {
1957
1982
  wait({ ctx, data: data2, push }, [time]) {
1958
1983
  if (ctx.meta.restoring) return;
1959
1984
  setTimeout(push, isFunction(time) ? time(data2) : time);
@@ -2251,6 +2276,13 @@ var Novely = (() => {
2251
2276
  }
2252
2277
  }
2253
2278
  });
2279
+ const action = buildActionObject({
2280
+ rendererActions: renderer.actions,
2281
+ nativeActions,
2282
+ characters,
2283
+ preloadAssets,
2284
+ storageData
2285
+ });
2254
2286
  const render = (ctx) => {
2255
2287
  const stack = useStack(ctx);
2256
2288
  const [path, state] = stack.value;
@@ -2345,7 +2377,8 @@ var Novely = (() => {
2345
2377
  */
2346
2378
  action,
2347
2379
  /**
2348
- * @deprecated Will be removed BUT replaced with state passed into actions as a parameter
2380
+ * State bound to `$MAIN` game context
2381
+ * @deprecated Use `state` function provided from action arguments
2349
2382
  */
2350
2383
  state: getStateFunction(MAIN_CONTEXT_KEY),
2351
2384
  /**
@@ -2440,11 +2473,10 @@ var Novely = (() => {
2440
2473
 
2441
2474
  // src/extend-actions.ts
2442
2475
  var extendAction = (base, extension) => {
2443
- return new Proxy({}, {
2444
- get(_, key, receiver) {
2445
- return Reflect.get(key in extension ? extension : base, key, receiver);
2446
- }
2447
- });
2476
+ return {
2477
+ ...extension,
2478
+ ...base
2479
+ };
2448
2480
  };
2449
2481
 
2450
2482
  // src/translations.ts