@slot-engine/core 0.1.7 → 0.1.9
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.mts +92 -6
- package/dist/index.d.ts +92 -6
- package/dist/index.js +157 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +157 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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]
|
|
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
|
-
|
|
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
|
-
|
|
725
|
-
|
|
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
|
|
@@ -3394,9 +3498,9 @@ var GeneratedReelSet = class extends ReelSet {
|
|
|
3394
3498
|
`Error generating reels for game mode "${this.associatedGameModeName}". It's not defined in the game config.`
|
|
3395
3499
|
);
|
|
3396
3500
|
}
|
|
3501
|
+
const outputDir = path7.join(config.rootDir, config.outputDir);
|
|
3397
3502
|
const filePath = path7.join(
|
|
3398
|
-
|
|
3399
|
-
config.outputDir,
|
|
3503
|
+
outputDir,
|
|
3400
3504
|
`reels_${this.associatedGameModeName}-${this.id}.csv`
|
|
3401
3505
|
);
|
|
3402
3506
|
const exists = fs5.existsSync(filePath);
|
|
@@ -3543,12 +3647,13 @@ var GeneratedReelSet = class extends ReelSet {
|
|
|
3543
3647
|
}
|
|
3544
3648
|
const csvString = csvRows.map((row) => row.join(",")).join("\n");
|
|
3545
3649
|
if (isMainThread5) {
|
|
3650
|
+
createDirIfNotExists(outputDir);
|
|
3546
3651
|
fs5.writeFileSync(filePath, csvString);
|
|
3547
|
-
this.reels = this.parseReelsetCSV(filePath, config);
|
|
3548
3652
|
console.log(
|
|
3549
3653
|
`Generated reelset ${this.id} for game mode ${this.associatedGameModeName}`
|
|
3550
3654
|
);
|
|
3551
3655
|
}
|
|
3656
|
+
this.reels = this.parseReelsetCSV(filePath, config);
|
|
3552
3657
|
return this;
|
|
3553
3658
|
}
|
|
3554
3659
|
};
|
|
@@ -3653,6 +3758,12 @@ var StandaloneBoard = class {
|
|
|
3653
3758
|
setSymbol(reelIndex, rowIndex, symbol) {
|
|
3654
3759
|
this.board.setSymbol(reelIndex, rowIndex, symbol);
|
|
3655
3760
|
}
|
|
3761
|
+
/**
|
|
3762
|
+
* Removes the symbol at the specified reel and row index.
|
|
3763
|
+
*/
|
|
3764
|
+
removeSymbol(reelIndex, rowIndex) {
|
|
3765
|
+
this.board.removeSymbol(reelIndex, rowIndex);
|
|
3766
|
+
}
|
|
3656
3767
|
resetReels() {
|
|
3657
3768
|
this.board.resetReels({
|
|
3658
3769
|
ctx: this.ctx
|
|
@@ -3729,16 +3840,16 @@ var StandaloneBoard = class {
|
|
|
3729
3840
|
* Draws a board using specified reel stops.
|
|
3730
3841
|
*/
|
|
3731
3842
|
drawBoardWithForcedStops(opts) {
|
|
3732
|
-
this.drawBoardMixed(opts.reels, opts.forcedStops, opts.randomOffset);
|
|
3843
|
+
return this.drawBoardMixed(opts.reels, opts.forcedStops, opts.randomOffset);
|
|
3733
3844
|
}
|
|
3734
3845
|
/**
|
|
3735
3846
|
* Draws a board using random reel stops.
|
|
3736
3847
|
*/
|
|
3737
3848
|
drawBoardWithRandomStops(reels) {
|
|
3738
|
-
this.drawBoardMixed(reels);
|
|
3849
|
+
return this.drawBoardMixed(reels);
|
|
3739
3850
|
}
|
|
3740
3851
|
drawBoardMixed(reels, forcedStops, forcedStopsOffset) {
|
|
3741
|
-
this.board.drawBoardMixed({
|
|
3852
|
+
return this.board.drawBoardMixed({
|
|
3742
3853
|
ctx: this.ctx,
|
|
3743
3854
|
reels,
|
|
3744
3855
|
forcedStops,
|
|
@@ -3760,16 +3871,46 @@ var StandaloneBoard = class {
|
|
|
3760
3871
|
padSymbols: this.padSymbols
|
|
3761
3872
|
});
|
|
3762
3873
|
}
|
|
3874
|
+
/**
|
|
3875
|
+
* **Experimental - May be changed or replaced in the future**
|
|
3876
|
+
*
|
|
3877
|
+
* Tumbles the board normally like `tumbleBoard`, but allows specifying a different reel set to get symbols from.\
|
|
3878
|
+
* Also requires specifying the starting stops from where the symbols will be tumbled.\
|
|
3879
|
+
* **This method does not remember the last tumbled position. Use this if you need to do a singular one-off tumble.**
|
|
3880
|
+
*/
|
|
3881
|
+
tumbleBoardAndForget(opts) {
|
|
3882
|
+
return this.board.tumbleBoard({
|
|
3883
|
+
ctx: this.ctx,
|
|
3884
|
+
symbolsToDelete: opts.symbolsToDelete,
|
|
3885
|
+
reelsAmount: this.reelsAmount,
|
|
3886
|
+
symbolsPerReel: this.symbolsPerReel,
|
|
3887
|
+
padSymbols: this.padSymbols,
|
|
3888
|
+
reels: opts.reels,
|
|
3889
|
+
startingStops: opts.forcedStops
|
|
3890
|
+
});
|
|
3891
|
+
}
|
|
3763
3892
|
/**
|
|
3764
3893
|
* Dedupes win symbols for tumble.\
|
|
3765
3894
|
* Returns a list of symbols to remove from the board based on the given win combinations.
|
|
3766
|
-
*
|
|
3895
|
+
*
|
|
3767
3896
|
* Since it may be possible that multiple win combinations include the same symbol (e.g. Wilds),\
|
|
3768
3897
|
* this method ensures that each symbol is only listed once for removal. Otherwise tumbling may break.
|
|
3769
3898
|
*/
|
|
3770
3899
|
dedupeWinSymbolsForTumble(winCombinations) {
|
|
3771
3900
|
return this.board.dedupeWinSymbolsForTumble(winCombinations);
|
|
3772
3901
|
}
|
|
3902
|
+
/**
|
|
3903
|
+
* Sets symbolsPerReel.
|
|
3904
|
+
*/
|
|
3905
|
+
setSymbolsPerReel(symbolsPerReel) {
|
|
3906
|
+
this.symbolsPerReel = symbolsPerReel;
|
|
3907
|
+
}
|
|
3908
|
+
/**
|
|
3909
|
+
* Sets the reelsAmount.
|
|
3910
|
+
*/
|
|
3911
|
+
setReelsAmount(reelsAmount) {
|
|
3912
|
+
this.reelsAmount = reelsAmount;
|
|
3913
|
+
}
|
|
3773
3914
|
};
|
|
3774
3915
|
export {
|
|
3775
3916
|
ClusterWinType,
|