@slot-engine/core 0.2.1 → 0.2.3

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
@@ -429,8 +429,18 @@ var Board = class {
429
429
  * Used for triggering anticipation effects.
430
430
  */
431
431
  anticipation;
432
+ /**
433
+ * The most recent stop positions for the reels.
434
+ */
432
435
  lastDrawnReelStops;
436
+ /**
437
+ * The reel set used in the most recent draw.
438
+ */
433
439
  lastUsedReels;
440
+ /**
441
+ * Indicates whether each reel is locked or not.
442
+ */
443
+ reelsLocked;
434
444
  constructor() {
435
445
  this.reels = [];
436
446
  this.paddingTop = [];
@@ -438,6 +448,7 @@ var Board = class {
438
448
  this.anticipation = [];
439
449
  this.lastDrawnReelStops = [];
440
450
  this.lastUsedReels = [];
451
+ this.reelsLocked = [];
441
452
  }
442
453
  getSymbol(reelIndex, rowIndex) {
443
454
  return this.reels[reelIndex]?.[rowIndex];
@@ -451,6 +462,14 @@ var Board = class {
451
462
  this.reels[reelIndex].splice(rowIndex, 1);
452
463
  }
453
464
  }
465
+ updateSymbol(reelIndex, rowIndex, properties) {
466
+ const symbol = this.getSymbol(reelIndex, rowIndex);
467
+ if (symbol) {
468
+ for (const [key, value] of Object.entries(properties)) {
469
+ symbol.properties.set(key, value);
470
+ }
471
+ }
472
+ }
454
473
  makeEmptyReels(opts) {
455
474
  const length = opts.reelsAmount ?? opts.ctx.services.game.getCurrentGameMode().reelsAmount;
456
475
  assert3(length, "Cannot make empty reels without context or reelsAmount.");
@@ -585,14 +604,19 @@ var Board = class {
585
604
  return reelSet;
586
605
  }
587
606
  resetReels(opts) {
588
- const length = opts.reelsAmount ?? opts.ctx.services.game.getCurrentGameMode().reelsAmount;
607
+ const { ctx, reelsAmount, reelsLocked } = opts;
608
+ const length = reelsAmount ?? ctx.services.game.getCurrentGameMode().reelsAmount;
589
609
  this.reels = this.makeEmptyReels(opts);
590
610
  this.anticipation = Array.from({ length }, () => false);
611
+ this.reelsLocked = reelsLocked ?? Array.from({ length }, () => false);
591
612
  this.paddingTop = this.makeEmptyReels(opts);
592
613
  this.paddingBottom = this.makeEmptyReels(opts);
593
614
  }
594
615
  drawBoardMixed(opts) {
595
- this.resetReels(opts);
616
+ this.resetReels({
617
+ ...opts,
618
+ ...this.reelsLocked.length && { reelsLocked: this.reelsLocked }
619
+ });
596
620
  const reelsAmount = opts.reelsAmount ?? opts.ctx.services.game.getCurrentGameMode().reelsAmount;
597
621
  const symbolsPerReel = opts.symbolsPerReel ?? opts.ctx.services.game.getCurrentGameMode().symbolsPerReel;
598
622
  const padSymbols = opts.padSymbols ?? opts.ctx.config.padSymbols;
@@ -621,6 +645,18 @@ var Board = class {
621
645
  );
622
646
  }
623
647
  }
648
+ if (this.reelsLocked.some((locked) => locked) && this.lastDrawnReelStops.length == 0) {
649
+ throw new Error(
650
+ "Cannot draw board with locked reels before drawing it at least once."
651
+ );
652
+ }
653
+ if (this.reelsLocked.some((locked) => locked)) {
654
+ for (let ridx = 0; ridx < reelsAmount; ridx++) {
655
+ if (this.reelsLocked[ridx]) {
656
+ finalReelStops[ridx] = this.lastDrawnReelStops[ridx];
657
+ }
658
+ }
659
+ }
624
660
  this.lastDrawnReelStops = finalReelStops.map((pos) => pos);
625
661
  this.lastUsedReels = opts.reels;
626
662
  for (let ridx = 0; ridx < reelsAmount; ridx++) {
@@ -782,6 +818,9 @@ var BoardService = class extends AbstractService {
782
818
  getAnticipation() {
783
819
  return this.board.anticipation;
784
820
  }
821
+ getLockedReels() {
822
+ return this.board.reelsLocked;
823
+ }
785
824
  /**
786
825
  * Gets the symbol at the specified reel and row index.
787
826
  */
@@ -800,6 +839,12 @@ var BoardService = class extends AbstractService {
800
839
  removeSymbol(reelIndex, rowIndex) {
801
840
  this.board.removeSymbol(reelIndex, rowIndex);
802
841
  }
842
+ /**
843
+ * Updates properties of the symbol at the specified reel and row index.
844
+ */
845
+ updateSymbol(reelIndex, rowIndex, properties) {
846
+ this.board.updateSymbol(reelIndex, rowIndex, properties);
847
+ }
803
848
  resetReels() {
804
849
  this.board.resetReels({
805
850
  ctx: this.ctx()
@@ -811,6 +856,12 @@ var BoardService = class extends AbstractService {
811
856
  setAnticipationForReel(reelIndex, value) {
812
857
  this.board.anticipation[reelIndex] = value;
813
858
  }
859
+ /**
860
+ * Sets the locked state for a specific reel.
861
+ */
862
+ setReelLocked(reelIndex, value) {
863
+ this.board.reelsLocked[reelIndex] = value;
864
+ }
814
865
  /**
815
866
  * Counts how many symbols matching the criteria are on a specific reel.
816
867
  */
@@ -4019,27 +4070,36 @@ var ManywaysWinType = class extends WinType {
4019
4070
  * Calculates wins based on the defined paylines and provided board state.\
4020
4071
  * Retrieve the results using `getWins()` after.
4021
4072
  */
4022
- evaluateWins(board) {
4073
+ evaluateWins(board, opts = {}) {
4023
4074
  this.validateConfig();
4075
+ const { jumpGaps = false } = opts;
4024
4076
  const waysWins = [];
4025
4077
  const reels = board;
4026
4078
  const possibleWaysWins = /* @__PURE__ */ new Map();
4027
4079
  const candidateSymbols = /* @__PURE__ */ new Map();
4028
- let searchReelIdx = 0;
4029
- let searchActive = true;
4030
- while (searchActive && searchReelIdx < reels.length) {
4031
- const reel = reels[searchReelIdx];
4032
- let hasWild = false;
4033
- for (const symbol of reel) {
4034
- candidateSymbols.set(symbol.id, symbol);
4035
- if (this.isWild(symbol)) {
4036
- hasWild = true;
4080
+ if (jumpGaps) {
4081
+ for (const reel of reels) {
4082
+ for (const symbol of reel) {
4083
+ candidateSymbols.set(symbol.id, symbol);
4037
4084
  }
4038
4085
  }
4039
- if (!hasWild) {
4040
- searchActive = false;
4086
+ } else {
4087
+ let searchReelIdx = 0;
4088
+ let searchActive = true;
4089
+ while (searchActive && searchReelIdx < reels.length) {
4090
+ const reel = reels[searchReelIdx];
4091
+ let hasWild = false;
4092
+ for (const symbol of reel) {
4093
+ candidateSymbols.set(symbol.id, symbol);
4094
+ if (this.isWild(symbol)) {
4095
+ hasWild = true;
4096
+ }
4097
+ }
4098
+ if (!hasWild) {
4099
+ searchActive = false;
4100
+ }
4101
+ searchReelIdx++;
4041
4102
  }
4042
- searchReelIdx++;
4043
4103
  }
4044
4104
  for (const baseSymbol of candidateSymbols.values()) {
4045
4105
  let symbolList = {};
@@ -4055,7 +4115,7 @@ var ManywaysWinType = class extends WinType {
4055
4115
  symbolList[ridx].push({ reel: ridx, row: sidx, symbol });
4056
4116
  }
4057
4117
  }
4058
- if (!symbolList[ridx]) {
4118
+ if (!symbolList[ridx] && !jumpGaps) {
4059
4119
  isInterrupted = true;
4060
4120
  break;
4061
4121
  }
@@ -4071,7 +4131,7 @@ var ManywaysWinType = class extends WinType {
4071
4131
  for (const [baseSymbolId, symbolList] of possibleWaysWins.entries()) {
4072
4132
  const wayLength = this.getWayLength(symbolList);
4073
4133
  let baseSymbol = Object.values(symbolList).flatMap((l) => l.map((s) => s)).find((s) => !this.isWild(s.symbol))?.symbol;
4074
- if (!baseSymbol) baseSymbol = symbolList[0][0].symbol;
4134
+ if (!baseSymbol) baseSymbol = symbolList[Object.keys(symbolList)[0]][0].symbol;
4075
4135
  const singleWayPayout = this.getSymbolPayout(baseSymbol, wayLength);
4076
4136
  const totalWays = Object.values(symbolList).reduce(
4077
4137
  (ways, syms) => ways * syms.length,
@@ -4105,7 +4165,7 @@ var ManywaysWinType = class extends WinType {
4105
4165
  return this;
4106
4166
  }
4107
4167
  getWayLength(symbolList) {
4108
- return Math.max(...Object.keys(symbolList).map((k) => parseInt(k, 10))) + 1;
4168
+ return Object.keys(symbolList).length;
4109
4169
  }
4110
4170
  };
4111
4171
 
@@ -4543,6 +4603,12 @@ var StandaloneBoard = class {
4543
4603
  getPaddingBottom() {
4544
4604
  return this.board.paddingBottom;
4545
4605
  }
4606
+ getAnticipation() {
4607
+ return this.board.anticipation;
4608
+ }
4609
+ getLockedReels() {
4610
+ return this.board.reelsLocked;
4611
+ }
4546
4612
  /**
4547
4613
  * Gets the symbol at the specified reel and row index.
4548
4614
  */
@@ -4561,6 +4627,12 @@ var StandaloneBoard = class {
4561
4627
  removeSymbol(reelIndex, rowIndex) {
4562
4628
  this.board.removeSymbol(reelIndex, rowIndex);
4563
4629
  }
4630
+ /**
4631
+ * Updates properties of the symbol at the specified reel and row index.
4632
+ */
4633
+ updateSymbol(reelIndex, rowIndex, properties) {
4634
+ this.board.updateSymbol(reelIndex, rowIndex, properties);
4635
+ }
4564
4636
  resetReels() {
4565
4637
  this.board.resetReels({
4566
4638
  ctx: this.ctx
@@ -4572,6 +4644,12 @@ var StandaloneBoard = class {
4572
4644
  setAnticipationForReel(reelIndex, value) {
4573
4645
  this.board.anticipation[reelIndex] = value;
4574
4646
  }
4647
+ /**
4648
+ * Sets the locked state for a specific reel.
4649
+ */
4650
+ setReelLocked(reelIndex, value) {
4651
+ this.board.reelsLocked[reelIndex] = value;
4652
+ }
4575
4653
  /**
4576
4654
  * Counts how many symbols matching the criteria are on a specific reel.
4577
4655
  */