@energy8platform/game-engine 0.43.3 → 0.43.5

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/host.cjs.js CHANGED
@@ -2853,6 +2853,8 @@ async function createSlotGame(opts) {
2853
2853
  let playErrorOpen = false;
2854
2854
  let stopAutoplay = () => { }; // wired to the autoplay loop once it's created (below)
2855
2855
  let haltAutoplay = () => { }; // ditto — stops the run but KEEPS its counter
2856
+ let holdAutoplay = () => { }; // ditto — pauses the run, owing it a resume
2857
+ let releaseAutoplay = () => { }; // ditto — gives back a run that hold() paused
2856
2858
  const reload = () => {
2857
2859
  try {
2858
2860
  window.location.reload();
@@ -2896,6 +2898,9 @@ async function createSlotGame(opts) {
2896
2898
  const { createConnectionRecovery } = await Promise.resolve().then(function () { return connectionRecovery; });
2897
2899
  const connection = createConnectionRecovery({
2898
2900
  haltAutoplay: () => haltAutoplay(),
2901
+ // A reconnect ends the run for good (Artube): the counter the halt preserved while the link
2902
+ // was down is cleared here, and the disc goes back to a plain SPIN.
2903
+ resetAutoplay: () => stopAutoplay(),
2899
2904
  showReconnecting: () => shell.openModal({
2900
2905
  availableClose: false,
2901
2906
  title: shell.t('Reconnecting…'),
@@ -2937,8 +2942,10 @@ async function createSlotGame(opts) {
2937
2942
  game.scenes.root.eventMode = 'static';
2938
2943
  game.scenes.root.on('pointertap', () => skip.tap(performance.now()));
2939
2944
  // Full auto-pause: on tab blur, freeze the ticker (stops tweens/onUpdate/in-flight onSpin),
2940
- // duck music to silence, hold autoplay, and notify the scene. On focus, reverse it all.
2941
- // `stopAutoplay` is reassigned in the base-mode block below — the closure reads it live.
2945
+ // duck music to silence, hold autoplay, and notify the scene. On focus, reverse it all
2946
+ // autoplay included: a tab switch is not the player pressing STOP.
2947
+ // `holdAutoplay`/`releaseAutoplay` are reassigned in the base-mode block below — the closures
2948
+ // read them live.
2942
2949
  const { createPauseController } = await Promise.resolve().then(function () { return pauseController; });
2943
2950
  createPauseController({
2944
2951
  isHidden: () => typeof document !== 'undefined' && document.hidden,
@@ -2951,12 +2958,19 @@ async function createSlotGame(opts) {
2951
2958
  onHidden: () => {
2952
2959
  game.app.ticker.stop(); // freezes tweens, onUpdate, in-flight onSpin animation
2953
2960
  game.audio.duckMusic(0); // silence music (ducked to 0; restored on resume)
2954
- stopAutoplay(); // hold autoplay — don't start the next auto-round
2961
+ // Hold, don't stop. No auto-round may start while the tab is hidden (the ticker is frozen,
2962
+ // so an animation would never finish, and a play fired here spends the player's money out
2963
+ // of sight) — but the run is owed back: the lab reads "the autoplay sequence stops when the
2964
+ // Stop button is pressed" as ONLY the Stop button, and stopAutoplay() here ended the run and
2965
+ // zeroed its counter on every alt-tab. `hold()` forgets itself if anything else ends the run
2966
+ // meanwhile (a lost connection, a failed round), so those don't come back on the way in.
2967
+ holdAutoplay();
2955
2968
  gameScene()?.onPause?.();
2956
2969
  },
2957
2970
  onVisible: () => {
2958
2971
  game.app.ticker.start();
2959
2972
  game.audio.unduckMusic();
2973
+ releaseAutoplay(); // the run the blur paused picks up where it left off
2960
2974
  gameScene()?.onResume?.();
2961
2975
  },
2962
2976
  });
@@ -3173,6 +3187,8 @@ async function createSlotGame(opts) {
3173
3187
  });
3174
3188
  stopAutoplay = () => autoplay$1.stop();
3175
3189
  haltAutoplay = () => autoplay$1.halt();
3190
+ holdAutoplay = () => autoplay$1.hold();
3191
+ releaseAutoplay = () => autoplay$1.release();
3176
3192
  shell.on('autoplayStart', (o) => autoplay$1.start(o?.remaining ?? 0));
3177
3193
  shell.on('autoplayStop', () => autoplay$1.stop());
3178
3194
  // Resume offer: when the game scene is (or becomes) current on a reload, ask the host whether
@@ -3398,7 +3414,7 @@ const DISCLAIMER_TITLE = 'DISCLAIMER';
3398
3414
  /** The copyright/brand line ("TM and © {year} Engine.") is shown verbatim; the legal body
3399
3415
  * lines localize. Detecting the brand keeps " Engine" out of the translation lookup entirely. */
3400
3416
  function isBrandLine(line) {
3401
- return /stake\s+engine/i.test(line);
3417
+ return /engine/i.test(line);
3402
3418
  }
3403
3419
  /** A disclaimer section from initData's disclaimer lines; null when none supplied. The legal body is
3404
3420
  * run through `t` so it localizes per language, EXCEPT the brand line, which stays verbatim. The
@@ -4226,6 +4242,9 @@ function createConnectionRecovery(deps) {
4226
4242
  if (!linkLost)
4227
4243
  return; // nothing of ours is on screen; nothing of ours to recover
4228
4244
  linkLost = false;
4245
+ // The run does not resume across a reconnect. Like the halt above, this runs even when a
4246
+ // modal owns the screen — the counter must not outlive the drop that ended the run.
4247
+ deps.resetAutoplay();
4229
4248
  if (!blocked())
4230
4249
  deps.dismiss();
4231
4250
  await recover();
@@ -4395,7 +4414,9 @@ function createAutoplayLoop(deps) {
4395
4414
  let active = false;
4396
4415
  let remaining = 0;
4397
4416
  let running = false; // guards against a second concurrent loop
4417
+ let held = false; // a hold() is outstanding — the tab is hidden and the run is owed a resume
4398
4418
  const stop = () => {
4419
+ held = false;
4399
4420
  if (!active && remaining === 0)
4400
4421
  return;
4401
4422
  active = false;
@@ -4403,6 +4424,7 @@ function createAutoplayLoop(deps) {
4403
4424
  deps.onState({ active: false, remaining: 0 });
4404
4425
  };
4405
4426
  const halt = () => {
4427
+ held = false; // whatever is halting the run outranks a pending hold — see hold()'s doc comment
4406
4428
  if (!active)
4407
4429
  return; // nothing running — nothing to preserve
4408
4430
  active = false;
@@ -4439,27 +4461,45 @@ function createAutoplayLoop(deps) {
4439
4461
  running = false;
4440
4462
  }
4441
4463
  }
4464
+ const start = (count) => {
4465
+ if (active || count <= 0)
4466
+ return;
4467
+ held = false; // a run that is starting is no longer one that owes a resume
4468
+ active = true;
4469
+ remaining = count;
4470
+ deps.onState({ active: true, remaining });
4471
+ // `running` bars a SECOND loop, not a new run. After stop(), the round already in flight keeps
4472
+ // animating and the loop stays parked on `await playRound`, so `running` is still true for as
4473
+ // long as that takes — several seconds through a win. Bailing here made the restart a silent
4474
+ // no-op, and silent is what hurt: ShellController.startAutoplay has already lit the disc with
4475
+ // the chosen count, so the player saw autoplay running with a counter that never moved.
4476
+ // The parked loop re-reads `active`/`remaining` on its next turn and simply carries on with
4477
+ // the new budget — no second loop, nothing dropped.
4478
+ if (!running)
4479
+ void loop();
4480
+ };
4442
4481
  return {
4443
- start(count) {
4444
- if (active || count <= 0)
4445
- return;
4446
- active = true;
4447
- remaining = count;
4448
- deps.onState({ active: true, remaining });
4449
- // `running` bars a SECOND loop, not a new run. After stop(), the round already in flight keeps
4450
- // animating and the loop stays parked on `await playRound`, so `running` is still true for as
4451
- // long as that takes — several seconds through a win. Bailing here made the restart a silent
4452
- // no-op, and silent is what hurt: ShellController.startAutoplay has already lit the disc with
4453
- // the chosen count, so the player saw autoplay running with a counter that never moved.
4454
- // The parked loop re-reads `active`/`remaining` on its next turn and simply carries on with
4455
- // the new budget — no second loop, nothing dropped.
4456
- if (!running)
4457
- void loop();
4458
- },
4482
+ start,
4459
4483
  stop,
4460
4484
  halt,
4461
- get active() { return active; },
4462
- get remaining() { return remaining; },
4485
+ hold() {
4486
+ if (!active)
4487
+ return; // nothing running — nothing to hold, and nothing to bring back
4488
+ halt(); // clears `held`; we set it again below, so only a hold() ever leaves it set
4489
+ held = true;
4490
+ },
4491
+ release() {
4492
+ if (!held)
4493
+ return;
4494
+ held = false;
4495
+ start(remaining); // no-op when the remainder is gone (something retired it while hidden)
4496
+ },
4497
+ get active() {
4498
+ return active;
4499
+ },
4500
+ get remaining() {
4501
+ return remaining;
4502
+ },
4463
4503
  };
4464
4504
  }
4465
4505