pixi-rainman-game-engine 0.3.29 → 0.3.30

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.
@@ -81,6 +81,7 @@ export interface Globals {
81
81
  disableSpeedPopup?: (value: boolean) => void;
82
82
  handleDisablingButtons?: (value?: boolean) => void;
83
83
  throttledSpin?: () => void;
84
+ prepareBoughtFreeSpins?: () => void;
84
85
  updateFreeSpinShown?: (value: number) => void;
85
86
  backendSymbolMap?: Map<number, never>;
86
87
  betTable?: number[];
@@ -145,9 +145,12 @@ export class AbstractBuyFreeSpinsPlate extends Container {
145
145
  RainMan.settingsStore.setRoundNumber(roundNumber);
146
146
  this.cleanup();
147
147
  this.onContinueCallback();
148
- RainMan.settingsStore.handleModalInvocation?.("freeSpin");
149
- RainMan.settingsStore.handleInvokeFreeSpinPlate?.(option.amount, false);
148
+ await RainMan.settingsStore.handleInvokeFreeSpinPlate?.(option.amount, false);
150
149
  RainMan.settingsStore.disableKeyboardShortcuts = false;
150
+ RainMan.globals.prepareBoughtFreeSpins?.();
151
+ setTimeout(() => {
152
+ RainMan.globals.throttledSpin?.();
153
+ }, 500);
151
154
  }
152
155
  catch (err) {
153
156
  console.error(err);
@@ -2,7 +2,7 @@ import { Container, Sprite, Text, TextStyle, Texture } from "pixi.js";
2
2
  import { IntroLogo } from "../common";
3
3
  import { IntroContinueButton } from "./IntroContinueButton";
4
4
  import { IntroDotButton } from "./IntroDotButton";
5
- import { IntroPageData } from "./IntroPageData";
5
+ import { IntroPageData, IntroPageInnerTextBlock } from "./IntroPageData";
6
6
  /**
7
7
  * Abstract intro screen shown between loading and gameplay.
8
8
  * Each game subclasses this and provides assets + page definitions as properties.
@@ -38,6 +38,7 @@ export declare abstract class AbstractIntroScreen extends Container {
38
38
  protected dotShadow?: Sprite;
39
39
  protected frameImage: Sprite;
40
40
  protected pageImage: Sprite;
41
+ protected pageInnerTextBlocks: Text[];
41
42
  protected pageText: Text;
42
43
  private currentPage;
43
44
  private isChecked;
@@ -54,14 +55,19 @@ export declare abstract class AbstractIntroScreen extends Container {
54
55
  protected abstract positionText(): void;
55
56
  protected abstract positionCheckbox(): void;
56
57
  protected abstract positionLogo(): void;
58
+ protected positionPageInnerText(): void;
57
59
  protected abstract getPageImageScale(): {
58
60
  vertical: number;
59
61
  horizontal: number;
60
62
  };
61
63
  protected abstract positionPageImage(): void;
64
+ protected createPageInnerTextBlocks(blocks: IntroPageInnerTextBlock[]): Text[];
62
65
  protected showPage(index: number): void;
63
66
  private updateFade;
64
67
  private cleanup;
68
+ private refreshPageInnerText;
69
+ private setInnerTextAlpha;
70
+ private setPageContentAlpha;
65
71
  /**
66
72
  * Resizes dot shadow width to match all dots and centers it on them.
67
73
  * Call this in positionDots() after positioning the dots.
@@ -32,6 +32,7 @@ export class AbstractIntroScreen extends Container {
32
32
  dotShadow;
33
33
  frameImage;
34
34
  pageImage;
35
+ pageInnerTextBlocks = [];
35
36
  pageText;
36
37
  currentPage = 0;
37
38
  isChecked = false;
@@ -91,8 +92,7 @@ export class AbstractIntroScreen extends Container {
91
92
  this.addChild(bg);
92
93
  this.frameImage.texture = getTexture(isPortrait ? "intro-frame-mobile.png" : "intro-frame.png");
93
94
  this.showPage(this.currentPage);
94
- this.pageImage.alpha = 1;
95
- this.pageText.alpha = 1;
95
+ this.setPageContentAlpha(1);
96
96
  const pageImageScale = this.getPageImageScale();
97
97
  const dimensions = scaleToParent(this.pageImage.texture.width, this.pageImage.texture.height, RainMan.app.screen.width * pageImageScale.horizontal, RainMan.app.screen.height * pageImageScale.vertical);
98
98
  this.pageImage.width = dimensions.width;
@@ -109,6 +109,7 @@ export class AbstractIntroScreen extends Container {
109
109
  this.addChild(this.frameImage);
110
110
  this.addChild(this.frameImage);
111
111
  this.addChild(this.pageImage);
112
+ this.pageInnerTextBlocks.forEach((block) => this.addChild(block));
112
113
  this.addChild(this.pageText);
113
114
  this.addChild(this.continueButton);
114
115
  this.addChild(this.checkboxSprite);
@@ -123,6 +124,7 @@ export class AbstractIntroScreen extends Container {
123
124
  this.positionCheckbox();
124
125
  this.positionContinueButton();
125
126
  this.positionText();
127
+ this.positionPageInnerText();
126
128
  this.positionDotShadow();
127
129
  this.frameImage.x = this.pageImage.x;
128
130
  this.frameImage.y = this.pageImage.y;
@@ -133,6 +135,10 @@ export class AbstractIntroScreen extends Container {
133
135
  this.frameImage.width = this.pageImage.width;
134
136
  this.frameImage.height = this.pageImage.height;
135
137
  }
138
+ positionPageInnerText() { }
139
+ createPageInnerTextBlocks(blocks) {
140
+ return blocks.map((block) => new Text(block.text));
141
+ }
136
142
  showPage(index) {
137
143
  if (index < 0 || index >= this.pages.length)
138
144
  return;
@@ -141,6 +147,8 @@ export class AbstractIntroScreen extends Container {
141
147
  const isPortrait = getDeviceOrientation() === "mobile-portrait";
142
148
  this.pageImage.texture = Texture.from(isPortrait ? page.imageMobile : page.imageDesktop);
143
149
  this.pageText.text = page.text;
150
+ this.refreshPageInnerText(page);
151
+ this.setInnerTextAlpha(this.pageImage.alpha);
144
152
  for (let i = 0; i < this.dots.length; i++) {
145
153
  this.dots[i].setActive(i === index);
146
154
  }
@@ -153,6 +161,28 @@ export class AbstractIntroScreen extends Container {
153
161
  RainMan.app.renderer.off("resize", this.resizeHandler);
154
162
  this.destroy({ children: true });
155
163
  }
164
+ refreshPageInnerText(page) {
165
+ this.pageInnerTextBlocks.forEach((block) => {
166
+ this.removeChild(block);
167
+ block.destroy();
168
+ });
169
+ this.pageInnerTextBlocks = [];
170
+ if (!page.pageInnerText?.length)
171
+ return;
172
+ this.pageInnerTextBlocks = this.createPageInnerTextBlocks(page.pageInnerText);
173
+ this.pageInnerTextBlocks.forEach((block) => this.addChild(block));
174
+ this.positionPageInnerText();
175
+ }
176
+ setInnerTextAlpha(alpha) {
177
+ this.pageInnerTextBlocks.forEach((block) => {
178
+ block.alpha = alpha;
179
+ });
180
+ }
181
+ setPageContentAlpha(alpha) {
182
+ this.pageImage.alpha = alpha;
183
+ this.pageText.alpha = alpha;
184
+ this.setInnerTextAlpha(alpha);
185
+ }
156
186
  /**
157
187
  * Resizes dot shadow width to match all dots and centers it on them.
158
188
  * Call this in positionDots() after positioning the dots.
@@ -195,16 +225,14 @@ export class AbstractIntroScreen extends Container {
195
225
  this.fadeTween = new TWEEN.Tween({ alpha: this.pageImage.alpha })
196
226
  .to({ alpha: 0 }, this.FADE_DURATION)
197
227
  .onUpdate((obj) => {
198
- this.pageImage.alpha = obj.alpha;
199
- this.pageText.alpha = obj.alpha;
228
+ this.setPageContentAlpha(obj.alpha);
200
229
  })
201
230
  .onComplete(() => {
202
231
  this.showPage(index);
203
232
  this.fadeTween = new TWEEN.Tween({ alpha: 0 })
204
233
  .to({ alpha: 1 }, this.FADE_DURATION)
205
234
  .onUpdate((obj) => {
206
- this.pageImage.alpha = obj.alpha;
207
- this.pageText.alpha = obj.alpha;
235
+ this.setPageContentAlpha(obj.alpha);
208
236
  })
209
237
  .onComplete(() => {
210
238
  this.isAnimating = false;
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Data for a single inner text block rendered inside an intro page image.
3
+ */
4
+ export type IntroPageInnerTextBlock = {
5
+ id?: string;
6
+ text: string;
7
+ };
1
8
  /**
2
9
  * Data for a single page in the intro screen.
3
10
  */
@@ -5,4 +12,5 @@ export type IntroPageData = {
5
12
  imageDesktop: string;
6
13
  imageMobile: string;
7
14
  text: string;
15
+ pageInnerText?: IntroPageInnerTextBlock[];
8
16
  };
@@ -549,7 +549,7 @@ export class AbstractMainContainer extends Container {
549
549
  async invokeGambleGame() {
550
550
  if (!this.gambleGameSpineName)
551
551
  return;
552
- const newBalance = await new Promise((resolve) => {
552
+ await new Promise((resolve) => {
553
553
  this.gambleGame = new GambleGame(this.gambleGameSpineName, resolve, this._controller.lastWinAmount, this._controller.balance);
554
554
  RainMan.settingsStore.isGambleGameActive = true;
555
555
  this.showOverlay();
@@ -561,7 +561,7 @@ export class AbstractMainContainer extends Container {
561
561
  this._controller.updateGambleValues(RainMan.settingsStore.gambleGameWin);
562
562
  this.gambleGame = null;
563
563
  }
564
- this._controller.balance = newBalance;
564
+ this._controller?.updateBalance();
565
565
  this.hideOverlay();
566
566
  }
567
567
  /**
@@ -126,6 +126,7 @@ export class GambleGame extends Container {
126
126
  this.card.state.addAnimation(0, "wait", true, 0);
127
127
  const gambleData = await window.connectionWrapper.fetchGambleData(RainMan.settingsStore.roundNumber, this.lastWinAmount, choice);
128
128
  this.balanceValue = gambleData.balance + gambleData.win_amount;
129
+ this.balanceValue = gambleData.balanceAfterSpin;
129
130
  await new Promise((resolve) => {
130
131
  this.card.state.clearTracks();
131
132
  this.card.state.clearListeners();
@@ -18,6 +18,9 @@ export declare abstract class AbstractColumnsContainer extends Container impleme
18
18
  protected allColumns: AbstractSymbolsColumn[];
19
19
  private velocityMultiplier;
20
20
  private skipScatterDelay;
21
+ private mysteryDelayTimeout;
22
+ private mysteryFxGeneration;
23
+ private skipRemainingMysteryFxs;
21
24
  currentColumn: Nullable<AbstractSymbolsColumn>;
22
25
  private playedSounds;
23
26
  quickReelsStop: boolean;
@@ -92,6 +95,28 @@ export declare abstract class AbstractColumnsContainer extends Container impleme
92
95
  * @returns {Promise<void>}
93
96
  */
94
97
  configBlindSpin(finalSymbolReels: SymbolReels, afterSpinResolver: (value: void | PromiseLike<void>) => void, indexesOfReelsToExtendSpinningTime: number[]): Promise<void>;
98
+ /**
99
+ * This cancels the timeout, removes the stored delayed action and invalidates
100
+ * any older timeout callback that might still try to execute later.
101
+ * @private
102
+ * @returns {void}
103
+ */
104
+ private clearPendingMysteryDelay;
105
+ /**
106
+ * Runs the pending mysteryFx immediately and clears its timeout.
107
+ * @private
108
+ * @returns {void}
109
+ */
110
+ private executePendingMysteryFx;
111
+ /**
112
+ * The callback is bound to the current generation so an old timeout from
113
+ * a previous spin cannot execute after a newer mystery delay was scheduled.
114
+ * @private
115
+ * @param {PlayableAction} action delayed reel configuration action
116
+ * @param {number} delay time in milliseconds before the action should run
117
+ * @returns {void}
118
+ */
119
+ private scheduleMysteryDelay;
95
120
  /**
96
121
  * Function for playing all streaks
97
122
  * @public
@@ -20,6 +20,9 @@ export class AbstractColumnsContainer extends Container {
20
20
  allColumns = [];
21
21
  velocityMultiplier = defaultSpeedConfig.symbolsColumnsSpeed;
22
22
  skipScatterDelay = null;
23
+ mysteryDelayTimeout = null;
24
+ mysteryFxGeneration = 0;
25
+ skipRemainingMysteryFxs = false;
23
26
  currentColumn = null;
24
27
  playedSounds = [];
25
28
  quickReelsStop = false;
@@ -93,12 +96,12 @@ export class AbstractColumnsContainer extends Container {
93
96
  */
94
97
  enableQuickReelsStop() {
95
98
  this.quickReelsStop = true;
99
+ this.skipRemainingMysteryFxs = true;
96
100
  RainMan.settingsStore.isQuickSpinsActive = true;
97
101
  RainMan.settingsStore.setIsTemporarySpeed(true);
98
102
  RainMan.componentRegistry.setTemporarySpeedLevel(SPEED_LEVELS.fast);
99
- this.skipScatterDelay?.();
103
+ this.executePendingMysteryFx();
100
104
  this.resolveMysterySpeedUp();
101
- this.skipScatterDelay = null;
102
105
  if (this.currentColumn) {
103
106
  this.currentColumn.skipHidingMysteryFx = true;
104
107
  }
@@ -133,10 +136,15 @@ export class AbstractColumnsContainer extends Container {
133
136
  // spin
134
137
  return new Promise(async (resolve) => {
135
138
  let index = 0;
139
+ this.clearPendingMysteryDelay();
140
+ this.mysteryFxGeneration = 0;
141
+ this.skipRemainingMysteryFxs = false;
136
142
  const configuredBlindSpinsActions = this.prepareConfiguringReelsEnd(finalSymbolReels);
137
143
  const frame = RainMan.componentRegistry.get(AbstractFrame.registryName);
138
144
  while (configuredBlindSpinsActions.length !== 0) {
139
- if (this.quickReelsStop || RainMan.settingsStore.currentSpeed === SPEED_LEVELS.fast) {
145
+ if (this.quickReelsStop ||
146
+ this.skipRemainingMysteryFxs ||
147
+ RainMan.settingsStore.currentSpeed === SPEED_LEVELS.fast) {
140
148
  await Promise.all(configuredBlindSpinsActions.map(async (action) => await action()));
141
149
  configuredBlindSpinsActions.length = 0;
142
150
  SoundManager.play(SoundTracks.allRollStops);
@@ -150,16 +158,16 @@ export class AbstractColumnsContainer extends Container {
150
158
  frame.invokeMysteryFx(this.currentColumn.x, this.currentColumn.y);
151
159
  this.skipScatterDelay = configureSpinAction;
152
160
  await this.currentColumn.speedUpForMysterySpin(100, 1500);
153
- if (!this.quickReelsStop) {
161
+ if (this.quickReelsStop || this.skipRemainingMysteryFxs) {
162
+ await this.currentColumn.changeVelocity(Speed.STOP, 0, frame);
163
+ }
164
+ else {
154
165
  if (!RainMan.settingsStore.isAutoplayEnabled ||
155
166
  (RainMan.settingsStore.isAutoplayEnabled && !this.quickReelsStop)) {
156
- setTimeout(() => {
157
- this.skipScatterDelay?.();
158
- this.skipScatterDelay = null;
159
- }, RainMan.config.durationOfActions.scatterDelayerTime);
167
+ this.scheduleMysteryDelay(configureSpinAction, RainMan.config.durationOfActions.scatterDelayerTime);
160
168
  }
169
+ await this.currentColumn.changeVelocity(Speed.STOP, RainMan.config.durationOfActions.scatterSpinningTime, frame);
161
170
  }
162
- await this.currentColumn.changeVelocity(Speed.STOP, RainMan.config.durationOfActions.scatterSpinningTime, frame);
163
171
  frame.destroyMysteryFx();
164
172
  }
165
173
  if (!indexesOfReelsToExtendSpinningTime.includes(index)) {
@@ -170,10 +178,60 @@ export class AbstractColumnsContainer extends Container {
170
178
  this.currentColumn = null;
171
179
  }
172
180
  await Promise.all(this.allColumns.map((column) => column.getStopPromise()));
181
+ this.clearPendingMysteryDelay();
182
+ this.mysteryFxGeneration = 0;
183
+ this.skipRemainingMysteryFxs = false;
173
184
  afterSpinResolver();
174
185
  resolve();
175
186
  });
176
187
  }
188
+ /**
189
+ * This cancels the timeout, removes the stored delayed action and invalidates
190
+ * any older timeout callback that might still try to execute later.
191
+ * @private
192
+ * @returns {void}
193
+ */
194
+ clearPendingMysteryDelay() {
195
+ this.mysteryFxGeneration += 1;
196
+ if (this.mysteryDelayTimeout !== null) {
197
+ clearTimeout(this.mysteryDelayTimeout);
198
+ this.mysteryDelayTimeout = null;
199
+ }
200
+ this.skipScatterDelay = null;
201
+ }
202
+ /**
203
+ * Runs the pending mysteryFx immediately and clears its timeout.
204
+ * @private
205
+ * @returns {void}
206
+ */
207
+ executePendingMysteryFx() {
208
+ const pendingMysteryDelay = this.skipScatterDelay;
209
+ this.clearPendingMysteryDelay();
210
+ pendingMysteryDelay?.();
211
+ }
212
+ /**
213
+ * The callback is bound to the current generation so an old timeout from
214
+ * a previous spin cannot execute after a newer mystery delay was scheduled.
215
+ * @private
216
+ * @param {PlayableAction} action delayed reel configuration action
217
+ * @param {number} delay time in milliseconds before the action should run
218
+ * @returns {void}
219
+ */
220
+ scheduleMysteryDelay(action, delay) {
221
+ this.clearPendingMysteryDelay();
222
+ // Store new mysteryFx action to be available in executePendingMysteryFx
223
+ this.skipScatterDelay = action;
224
+ const mysteryFxGeneration = this.mysteryFxGeneration;
225
+ this.mysteryDelayTimeout = setTimeout(() => {
226
+ if (mysteryFxGeneration !== this.mysteryFxGeneration) {
227
+ return;
228
+ }
229
+ this.mysteryDelayTimeout = null;
230
+ this.skipScatterDelay = null;
231
+ this.mysteryFxGeneration += 1;
232
+ action();
233
+ }, delay);
234
+ }
177
235
  /**
178
236
  * Function for playing all streaks
179
237
  * @public
@@ -64,6 +64,7 @@ export declare abstract class AbstractController<T> {
64
64
  protected resolveSuperBonusWin?: () => void;
65
65
  clearMobileSpinTimeout: (() => void) | undefined;
66
66
  protected initData: InitDataInterface;
67
+ protected shouldPlayNextSpin: boolean;
67
68
  protected _lastWinAmount: number;
68
69
  protected constructor(buttonsEventManager: ButtonsEventManager, mainContainer: AbstractMainContainer, connection: SubscribableConnectionWrapper);
69
70
  /**
@@ -262,6 +263,7 @@ export declare abstract class AbstractController<T> {
262
263
  * @returns {void}
263
264
  */
264
265
  protected throttledSpin(): void;
266
+ protected prepareBoughtFreeSpins(): void;
265
267
  /**
266
268
  * This function is responsible for getting the number of free spins bought
267
269
  * @private
@@ -366,7 +368,7 @@ export declare abstract class AbstractController<T> {
366
368
  * @param {number} winAmount amount from gamble game
367
369
  * @returns {void}
368
370
  */
369
- protected gambleGameEnabler(winAmount: number): void;
371
+ gambleGameEnabler(winAmount: number): void;
370
372
  /**
371
373
  * Function for spin logic of the game
372
374
  * This function is responsible for:
@@ -64,6 +64,7 @@ export class AbstractController {
64
64
  resolveSuperBonusWin;
65
65
  clearMobileSpinTimeout;
66
66
  initData;
67
+ shouldPlayNextSpin = false;
67
68
  _lastWinAmount = 0;
68
69
  constructor(buttonsEventManager, mainContainer, connection) {
69
70
  this.buttonsEventManager = buttonsEventManager;
@@ -102,6 +103,7 @@ export class AbstractController {
102
103
  RainMan.settingsStore.setRoundNumber(this.roundNumber);
103
104
  RainMan.settingsStore.initPaytableMap(initData);
104
105
  RainMan.globals.throttledSpin = this.throttledSpin.bind(this);
106
+ RainMan.globals.prepareBoughtFreeSpins = this.prepareBoughtFreeSpins.bind(this);
105
107
  RainMan.settingsStore.useTakeAction = this.useTakeAction.bind(this);
106
108
  this.connection.subscribeForConfigChanges(this.reinitializeUserBalanceData.bind(this));
107
109
  this.uiController.updateBet("first");
@@ -727,6 +729,9 @@ export class AbstractController {
727
729
  this.mainContainer.freeSpinSummary.emit("pointerdown", new PIXI.FederatedPointerEvent("pointerdown"));
728
730
  return;
729
731
  }
732
+ if (this.gamePhase === gamePhases.HANDLING_ACTIONS) {
733
+ this.shouldPlayNextSpin = true;
734
+ }
730
735
  if (this.mainContainer.mysteryWinVisibleFor) {
731
736
  RainMan.componentRegistry.get(COMPONENTS.mysteryWin).stopUpdate();
732
737
  }
@@ -786,12 +791,7 @@ export class AbstractController {
786
791
  this.quickStopController.handleInvokingSpeedPopup();
787
792
  return;
788
793
  }
789
- if (RainMan.settingsStore.isFreeSpinsBought) {
790
- this.uiController.totalNumberOfFreeSpins += this.getBoughtNumberOfFreeSpins();
791
- RainMan.componentRegistry.getIfExists(FreeSpinButton.registryName)?.setInteractivity(false);
792
- RainMan.settingsStore.setIsFreeSpinBought(false);
793
- return;
794
- }
794
+ this.prepareBoughtFreeSpins();
795
795
  if (RainMan.settingsStore.isAutoplayEnabled && !this.spinning) {
796
796
  this.changeGamePhase(gamePhases.IDLE);
797
797
  this.spin();
@@ -806,6 +806,14 @@ export class AbstractController {
806
806
  }
807
807
  this.spinThrottlerTimeout = setTimeout(() => (this.spinThrottlerTimeout = null), 100);
808
808
  }
809
+ prepareBoughtFreeSpins() {
810
+ if (!RainMan.settingsStore.isFreeSpinsBought) {
811
+ return;
812
+ }
813
+ this.uiController.totalNumberOfFreeSpins += this.getBoughtNumberOfFreeSpins();
814
+ RainMan.componentRegistry.getIfExists(FreeSpinButton.registryName)?.setInteractivity(false);
815
+ RainMan.settingsStore.setIsFreeSpinBought(false);
816
+ }
809
817
  /**
810
818
  * This function is responsible for getting the number of free spins bought
811
819
  * @private
@@ -866,6 +874,12 @@ export class AbstractController {
866
874
  logInfo("Take action can't be performed");
867
875
  return;
868
876
  }
877
+ if (this.currentlyPlayedAction !== undefined) {
878
+ this.changeGamePhase(gamePhases.STOPPING_HANDLING_ACTIONS);
879
+ this.stopPlayingSymbolsStreak();
880
+ await this.currentlyPlayedAction;
881
+ }
882
+ await Promise.all(this.uiController.promisesToSetBalances);
869
883
  const takeData = await window.connectionWrapper.sendTakeAction(RainMan.settingsStore.roundNumber);
870
884
  if (takeData.status.code === 200) {
871
885
  RainMan.settingsStore.isTakeActionAvailable = false;
@@ -981,14 +995,10 @@ export class AbstractController {
981
995
  */
982
996
  gambleGameEnabler(winAmount) {
983
997
  if (RainMan.componentRegistry.has(BUTTONS.gamble) && RainMan.settingsStore.isGambleGameAvailable) {
984
- RainMan.componentRegistry
985
- .get(BUTTONS.gamble)
986
- .flipDisabledFlag(RainMan.settingsStore.isFreeSpinsPlayEnabled || winAmount === 0);
998
+ RainMan.componentRegistry.get(BUTTONS.gamble).flipDisabledFlag(winAmount === 0);
987
999
  }
988
1000
  if (RainMan.componentRegistry.has(BUTTONS.take) && RainMan.settingsStore.isTakeActionAvailable) {
989
- RainMan.componentRegistry
990
- .get(BUTTONS.take)
991
- .flipDisabledFlag(RainMan.settingsStore.isFreeSpinsPlayEnabled || winAmount === 0);
1001
+ RainMan.componentRegistry.get(BUTTONS.take).flipDisabledFlag(winAmount === 0);
992
1002
  }
993
1003
  }
994
1004
  /**
@@ -1067,7 +1077,7 @@ export class AbstractController {
1067
1077
  const availableFreeSpins = spinLogic.availableFreeSpins;
1068
1078
  const availableFreeSpinsIncreased = availableFreeSpins > RainMan.settingsStore.howManyFreeSpinsLeft;
1069
1079
  this.hideFreeSpinsMessageBox = availableFreeSpinsIncreased;
1070
- if (this._lastWinAmount !== 0) {
1080
+ if (this._lastWinAmount !== 0 && !(availableFreeSpins > 0)) {
1071
1081
  RainMan.settingsStore.isTakeActionAvailable = true;
1072
1082
  RainMan.settingsStore.isGambleGameAvailable = true;
1073
1083
  }
@@ -1206,6 +1216,24 @@ export class AbstractController {
1206
1216
  }
1207
1217
  RainMan.settingsStore.setIsPlayingAnyAction(false);
1208
1218
  this.columnsContainer.setInteractivityForSymbols(true);
1219
+ const shouldStartNextSpin = this.shouldPlayNextSpin &&
1220
+ !RainMan.settingsStore.isAutoplayEnabled &&
1221
+ !RainMan.settingsStore.isFreeSpinsPlayEnabled &&
1222
+ !this.invokeFreeSpinPlateAfterWin &&
1223
+ !this.invokeFreeSpinSummaryPlateAfterWin &&
1224
+ !RainMan.globals.isSuperBonusGameEnabled;
1225
+ this.shouldPlayNextSpin = false;
1226
+ if (shouldStartNextSpin) {
1227
+ setTimeout(() => {
1228
+ if (!this.spinning &&
1229
+ this.gamePhase !== gamePhases.SPINNING &&
1230
+ this.gamePhase !== gamePhases.DATA_FETCH &&
1231
+ this.gamePhase !== gamePhases.CONFIGURING_SPIN &&
1232
+ !RainMan.settingsStore.isPlayingAnyAction) {
1233
+ this.throttledSpin();
1234
+ }
1235
+ }, 0);
1236
+ }
1209
1237
  }
1210
1238
  /**
1211
1239
  * Function for invoking free spin plate, invoked in mainContainer
@@ -1234,7 +1262,6 @@ export class AbstractController {
1234
1262
  */
1235
1263
  async handleFreeSpinSummaryPlateInvocation() {
1236
1264
  await this.buttonsEventManager.disableButtonsForAction(async () => {
1237
- this.uiController.updateDisplayedBalance(this.uiController.totalFreeSpinWinAmount);
1238
1265
  this.uiController.messageBox.hideFreeSpinText();
1239
1266
  this.uiController.messageBox.hideCurrentWinText();
1240
1267
  await this.mainContainer.invokeFreeSpinSummary(this.uiController.totalNumberOfFreeSpins, this.uiController.totalFreeSpinWinAmount);
@@ -1242,7 +1269,6 @@ export class AbstractController {
1242
1269
  this.uiController.resetTotalFreeSpinWinAmount();
1243
1270
  this.changeGamePhase(gamePhases.IDLE);
1244
1271
  });
1245
- this.uiController.currentBalance = RainMan.settingsStore.balanceAfterSpin;
1246
1272
  RainMan.settingsStore.resetTotalNumberOfFreeSpins();
1247
1273
  RainMan.settingsStore.resetFreeSpinNumberBought();
1248
1274
  this.changeGamePhase(gamePhases.IDLE);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixi-rainman-game-engine",
3
- "version": "0.3.29",
3
+ "version": "0.3.30",
4
4
  "description": "This repository contains all of the mechanics that used in rainman games.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",