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