@slot-engine/core 0.1.6 → 0.1.8

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.mjs CHANGED
@@ -471,6 +471,11 @@ var Board = class {
471
471
  this.reels[reelIndex] = this.reels[reelIndex] || [];
472
472
  this.reels[reelIndex][rowIndex] = symbol;
473
473
  }
474
+ removeSymbol(reelIndex, rowIndex) {
475
+ if (this.reels[reelIndex]) {
476
+ this.reels[reelIndex].splice(rowIndex, 1);
477
+ }
478
+ }
474
479
  makeEmptyReels(opts) {
475
480
  const length = opts.reelsAmount ?? opts.ctx.services.game.getCurrentGameMode().reelsAmount;
476
481
  assert3(length, "Cannot make empty reels without context or reelsAmount.");
@@ -660,18 +665,35 @@ var Board = class {
660
665
  this.reels[ridx][row] = symbol;
661
666
  }
662
667
  }
668
+ return {
669
+ stopPositions: this.lastDrawnReelStops
670
+ };
663
671
  }
664
672
  tumbleBoard(opts) {
665
673
  assert3(this.lastDrawnReelStops.length > 0, "Cannot tumble board before drawing it.");
666
674
  const reelsAmount = opts.reelsAmount ?? opts.ctx.services.game.getCurrentGameMode().reelsAmount;
667
675
  const symbolsPerReel = opts.symbolsPerReel ?? opts.ctx.services.game.getCurrentGameMode().symbolsPerReel;
668
676
  const padSymbols = opts.padSymbols ?? opts.ctx.config.padSymbols;
677
+ if (opts.startingStops) {
678
+ assert3(
679
+ opts.startingStops.length === reelsAmount,
680
+ "Starting stops length does not match reels amount."
681
+ );
682
+ assert3(opts.reels, "Reels must be provided when using startingStops.");
683
+ }
684
+ if (opts.reels) {
685
+ assert3(opts.startingStops, "Starting stops must be provided when using reels.");
686
+ }
669
687
  if (!opts.ctx && !reelsAmount && !symbolsPerReel) {
670
688
  throw new Error(
671
689
  "If ctx is not provided, reelsAmount and symbolsPerReel must be given."
672
690
  );
673
691
  }
674
- const reels = this.lastUsedReels;
692
+ const reels = opts.reels || this.lastUsedReels;
693
+ assert3(
694
+ reels.length === reelsAmount,
695
+ "Given reels length does not match reels amount."
696
+ );
675
697
  const sortedDeletions = [...opts.symbolsToDelete].sort((a, b) => b.rowIdx - a.rowIdx);
676
698
  sortedDeletions.forEach(({ reelIdx, rowIdx }) => {
677
699
  this.reels[reelIdx].splice(rowIdx, 1);
@@ -681,7 +703,7 @@ var Board = class {
681
703
  const newPaddingTopSymbols = {};
682
704
  for (let ridx = 0; ridx < reelsAmount; ridx++) {
683
705
  while (this.reels[ridx].length < symbolsPerReel[ridx]) {
684
- const padSymbol = this.paddingTop[ridx].pop();
706
+ const padSymbol = this.paddingTop[ridx]?.pop();
685
707
  if (padSymbol) {
686
708
  this.reels[ridx].unshift(padSymbol);
687
709
  if (!newBoardSymbols[ridx]) {
@@ -697,7 +719,16 @@ var Board = class {
697
719
  const symbolsNeeded = symbolsPerReel[ridx] - this.reels[ridx].length;
698
720
  for (let s = 0; s < symbolsNeeded; s++) {
699
721
  const symbolPos = (stopBeforePad - s + reels[ridx].length) % reels[ridx].length;
700
- const newSymbol = reels[ridx][symbolPos];
722
+ let newSymbol = reels[ridx][symbolPos];
723
+ const startStops = opts.startingStops;
724
+ if (startStops) {
725
+ const forcedSym = reels[ridx][startStops?.[ridx]];
726
+ assert3(
727
+ forcedSym,
728
+ `Failed to get forced symbol for tumbling. Tried to get symbol for position ${startStops?.[ridx]} on reel ${ridx}.`
729
+ );
730
+ newSymbol = forcedSym;
731
+ }
701
732
  assert3(newSymbol, "Failed to get new symbol for tumbling.");
702
733
  this.reels[ridx].unshift(newSymbol);
703
734
  newFirstSymbolPositions[ridx] = symbolPos;
@@ -721,9 +752,11 @@ var Board = class {
721
752
  newPaddingTopSymbols[ridx].unshift(padSymbol);
722
753
  }
723
754
  }
724
- this.lastDrawnReelStops = this.lastDrawnReelStops.map((stop, ridx) => {
725
- return newFirstSymbolPositions[ridx] ?? stop;
726
- });
755
+ if (!opts.reels && !opts.startingStops) {
756
+ this.lastDrawnReelStops = this.lastDrawnReelStops.map((stop, ridx) => {
757
+ return newFirstSymbolPositions[ridx] ?? stop;
758
+ });
759
+ }
727
760
  return {
728
761
  newBoardSymbols,
729
762
  newPaddingTopSymbols
@@ -786,6 +819,12 @@ var BoardService = class extends AbstractService {
786
819
  setSymbol(reelIndex, rowIndex, symbol) {
787
820
  this.board.setSymbol(reelIndex, rowIndex, symbol);
788
821
  }
822
+ /**
823
+ * Removes the symbol at the specified reel and row index.
824
+ */
825
+ removeSymbol(reelIndex, rowIndex) {
826
+ this.board.removeSymbol(reelIndex, rowIndex);
827
+ }
789
828
  resetReels() {
790
829
  this.board.resetReels({
791
830
  ctx: this.ctx()
@@ -861,16 +900,16 @@ var BoardService = class extends AbstractService {
861
900
  * Draws a board using specified reel stops.
862
901
  */
863
902
  drawBoardWithForcedStops(opts) {
864
- this.drawBoardMixed(opts.reels, opts.forcedStops, opts.randomOffset);
903
+ return this.drawBoardMixed(opts.reels, opts.forcedStops, opts.randomOffset);
865
904
  }
866
905
  /**
867
906
  * Draws a board using random reel stops.
868
907
  */
869
908
  drawBoardWithRandomStops(reels) {
870
- this.drawBoardMixed(reels);
909
+ return this.drawBoardMixed(reels);
871
910
  }
872
911
  drawBoardMixed(reels, forcedStops, forcedStopsOffset) {
873
- this.board.drawBoardMixed({
912
+ return this.board.drawBoardMixed({
874
913
  ctx: this.ctx(),
875
914
  reels,
876
915
  forcedStops,
@@ -886,6 +925,21 @@ var BoardService = class extends AbstractService {
886
925
  symbolsToDelete
887
926
  });
888
927
  }
928
+ /**
929
+ * **Experimental - May be changed or replaced in the future**
930
+ *
931
+ * Tumbles the board normally like `tumbleBoard`, but allows specifying a different reel set to get symbols from.\
932
+ * Also requires specifying the starting stops from where the symbols will be tumbled.\
933
+ * **This method does not remember the last tumbled position. Use this if you need to do a singular one-off tumble.**
934
+ */
935
+ tumbleBoardAndForget(opts) {
936
+ return this.board.tumbleBoard({
937
+ ctx: this.ctx(),
938
+ symbolsToDelete: opts.symbolsToDelete,
939
+ reels: opts.reels,
940
+ startingStops: opts.forcedStops
941
+ });
942
+ }
889
943
  /**
890
944
  * Dedupes win symbols for tumble.\
891
945
  * Returns a list of symbols to remove from the board based on the given win combinations.
@@ -896,6 +950,26 @@ var BoardService = class extends AbstractService {
896
950
  dedupeWinSymbolsForTumble(winCombinations) {
897
951
  return this.board.dedupeWinSymbolsForTumble(winCombinations);
898
952
  }
953
+ /**
954
+ * Sets the symbolsPerReel for the current game mode.
955
+ *
956
+ * The value will be reset to the original value as set in the game mode config in the next simulation.
957
+ */
958
+ setSymbolsPerReel(symbolsPerReel) {
959
+ this.ctx().config.gameModes[this.ctx().state.currentGameMode]._setSymbolsPerReel(
960
+ symbolsPerReel
961
+ );
962
+ }
963
+ /**
964
+ * Sets the reelsAmount for the current game mode.
965
+ *
966
+ * The value will be reset to the original value as set in the game mode config in the next simulation.
967
+ */
968
+ setReelsAmount(reelsAmount) {
969
+ this.ctx().config.gameModes[this.ctx().state.currentGameMode]._setReelsAmount(
970
+ reelsAmount
971
+ );
972
+ }
899
973
  };
900
974
 
901
975
  // src/service/data.ts
@@ -1800,6 +1874,9 @@ ${error.stack}
1800
1874
  criteria: ctx.state.currentResultSet.criteria
1801
1875
  })
1802
1876
  );
1877
+ Object.values(ctx.config.gameModes).forEach((mode) => {
1878
+ mode._resetTempValues();
1879
+ });
1803
1880
  }
1804
1881
  resetState(ctx) {
1805
1882
  ctx.services.rng.setSeedIfDifferent(ctx.state.currentSimulationId);
@@ -2748,6 +2825,8 @@ var defineGameModes = (gameModes) => gameModes;
2748
2825
  import assert10 from "assert";
2749
2826
  var GameMode = class {
2750
2827
  name;
2828
+ _reelsAmount;
2829
+ _symbolsPerReel;
2751
2830
  reelsAmount;
2752
2831
  symbolsPerReel;
2753
2832
  cost;
@@ -2757,7 +2836,9 @@ var GameMode = class {
2757
2836
  isBonusBuy;
2758
2837
  constructor(opts) {
2759
2838
  this.name = opts.name;
2839
+ this._reelsAmount = opts.reelsAmount;
2760
2840
  this.reelsAmount = opts.reelsAmount;
2841
+ this._symbolsPerReel = opts.symbolsPerReel;
2761
2842
  this.symbolsPerReel = opts.symbolsPerReel;
2762
2843
  this.cost = opts.cost;
2763
2844
  this.rtp = opts.rtp;
@@ -2771,6 +2852,29 @@ var GameMode = class {
2771
2852
  );
2772
2853
  assert10(this.reelSets.length > 0, "GameMode must have at least one ReelSet defined.");
2773
2854
  }
2855
+ /**
2856
+ * Intended for internal use only.
2857
+ */
2858
+ _resetTempValues() {
2859
+ this.reelsAmount = this._reelsAmount;
2860
+ this.symbolsPerReel = this._symbolsPerReel;
2861
+ }
2862
+ /**
2863
+ * Intended for internal use only.
2864
+ */
2865
+ _setSymbolsPerReel(symbolsPerReel) {
2866
+ assert10(
2867
+ symbolsPerReel.length === this._reelsAmount,
2868
+ "symbolsPerReel length must match reelsAmount."
2869
+ );
2870
+ this.symbolsPerReel = symbolsPerReel;
2871
+ }
2872
+ /**
2873
+ * Intended for internal use only.
2874
+ */
2875
+ _setReelsAmount(reelsAmount) {
2876
+ this.reelsAmount = reelsAmount;
2877
+ }
2774
2878
  };
2775
2879
 
2776
2880
  // src/win-types/index.ts
@@ -2872,6 +2976,7 @@ var LinesWinType = class extends WinType {
2872
2976
  let baseSymbol;
2873
2977
  const potentialWinLine = [];
2874
2978
  const potentialWildLine = [];
2979
+ let isInterrupted = false;
2875
2980
  for (const [ridx, reel] of reels.entries()) {
2876
2981
  const sidx = line[ridx];
2877
2982
  const thisSymbol = reel[sidx];
@@ -2898,6 +3003,9 @@ var LinesWinType = class extends WinType {
2898
3003
  }
2899
3004
  if (baseSymbol.compare(thisSymbol) || this.isWild(thisSymbol)) {
2900
3005
  potentialWinLine.push({ reel: ridx, row: sidx, symbol: thisSymbol });
3006
+ } else {
3007
+ isInterrupted = true;
3008
+ break;
2901
3009
  }
2902
3010
  }
2903
3011
  const minSymLine = Math.min(
@@ -3649,6 +3757,12 @@ var StandaloneBoard = class {
3649
3757
  setSymbol(reelIndex, rowIndex, symbol) {
3650
3758
  this.board.setSymbol(reelIndex, rowIndex, symbol);
3651
3759
  }
3760
+ /**
3761
+ * Removes the symbol at the specified reel and row index.
3762
+ */
3763
+ removeSymbol(reelIndex, rowIndex) {
3764
+ this.board.removeSymbol(reelIndex, rowIndex);
3765
+ }
3652
3766
  resetReels() {
3653
3767
  this.board.resetReels({
3654
3768
  ctx: this.ctx
@@ -3725,16 +3839,16 @@ var StandaloneBoard = class {
3725
3839
  * Draws a board using specified reel stops.
3726
3840
  */
3727
3841
  drawBoardWithForcedStops(opts) {
3728
- this.drawBoardMixed(opts.reels, opts.forcedStops, opts.randomOffset);
3842
+ return this.drawBoardMixed(opts.reels, opts.forcedStops, opts.randomOffset);
3729
3843
  }
3730
3844
  /**
3731
3845
  * Draws a board using random reel stops.
3732
3846
  */
3733
3847
  drawBoardWithRandomStops(reels) {
3734
- this.drawBoardMixed(reels);
3848
+ return this.drawBoardMixed(reels);
3735
3849
  }
3736
3850
  drawBoardMixed(reels, forcedStops, forcedStopsOffset) {
3737
- this.board.drawBoardMixed({
3851
+ return this.board.drawBoardMixed({
3738
3852
  ctx: this.ctx,
3739
3853
  reels,
3740
3854
  forcedStops,
@@ -3756,16 +3870,46 @@ var StandaloneBoard = class {
3756
3870
  padSymbols: this.padSymbols
3757
3871
  });
3758
3872
  }
3873
+ /**
3874
+ * **Experimental - May be changed or replaced in the future**
3875
+ *
3876
+ * Tumbles the board normally like `tumbleBoard`, but allows specifying a different reel set to get symbols from.\
3877
+ * Also requires specifying the starting stops from where the symbols will be tumbled.\
3878
+ * **This method does not remember the last tumbled position. Use this if you need to do a singular one-off tumble.**
3879
+ */
3880
+ tumbleBoardAndForget(opts) {
3881
+ return this.board.tumbleBoard({
3882
+ ctx: this.ctx,
3883
+ symbolsToDelete: opts.symbolsToDelete,
3884
+ reelsAmount: this.reelsAmount,
3885
+ symbolsPerReel: this.symbolsPerReel,
3886
+ padSymbols: this.padSymbols,
3887
+ reels: opts.reels,
3888
+ startingStops: opts.forcedStops
3889
+ });
3890
+ }
3759
3891
  /**
3760
3892
  * Dedupes win symbols for tumble.\
3761
3893
  * Returns a list of symbols to remove from the board based on the given win combinations.
3762
- *
3894
+ *
3763
3895
  * Since it may be possible that multiple win combinations include the same symbol (e.g. Wilds),\
3764
3896
  * this method ensures that each symbol is only listed once for removal. Otherwise tumbling may break.
3765
3897
  */
3766
3898
  dedupeWinSymbolsForTumble(winCombinations) {
3767
3899
  return this.board.dedupeWinSymbolsForTumble(winCombinations);
3768
3900
  }
3901
+ /**
3902
+ * Sets symbolsPerReel.
3903
+ */
3904
+ setSymbolsPerReel(symbolsPerReel) {
3905
+ this.symbolsPerReel = symbolsPerReel;
3906
+ }
3907
+ /**
3908
+ * Sets the reelsAmount.
3909
+ */
3910
+ setReelsAmount(reelsAmount) {
3911
+ this.reelsAmount = reelsAmount;
3912
+ }
3769
3913
  };
3770
3914
  export {
3771
3915
  ClusterWinType,