pixi-rainman-game-engine 0.3.28 → 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.
- package/dist/Rainman/types.d.ts +1 -0
- package/dist/application/ButtonsEventManager/ButtonsEventManager.js +1 -1
- package/dist/components/AbstractBuyFreeSpins/AbstractBuyFreeSpinsPlate.d.ts +44 -0
- package/dist/components/AbstractBuyFreeSpins/AbstractBuyFreeSpinsPlate.js +184 -0
- package/dist/components/AbstractBuyFreeSpins/AcceptDeclineButton.d.ts +14 -0
- package/dist/components/AbstractBuyFreeSpins/AcceptDeclineButton.js +28 -0
- package/dist/components/AbstractBuyFreeSpins/BuyFreeSpinButton.d.ts +14 -0
- package/dist/components/AbstractBuyFreeSpins/BuyFreeSpinButton.js +22 -0
- package/dist/components/AbstractBuyFreeSpins/index.d.ts +3 -0
- package/dist/components/AbstractBuyFreeSpins/index.js +3 -0
- package/dist/components/AbstractIntroScreen/AbstractIntroScreen.d.ts +7 -1
- package/dist/components/AbstractIntroScreen/AbstractIntroScreen.js +34 -6
- package/dist/components/AbstractIntroScreen/IntroPageData.d.ts +8 -0
- package/dist/components/AbstractMainContainer/AbstractMainContainer.d.ts +5 -0
- package/dist/components/AbstractMainContainer/AbstractMainContainer.js +33 -2
- package/dist/components/GambleGame/GambleGame.js +1 -0
- package/dist/components/dictionary/locales/en.json +3 -0
- package/dist/components/frame/AbstractColumnsContainer.d.ts +25 -0
- package/dist/components/frame/AbstractColumnsContainer.js +67 -9
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/controllers/AbstractController.d.ts +3 -1
- package/dist/controllers/AbstractController.js +50 -17
- package/dist/stores/SettingsStore.d.ts +8 -0
- package/dist/stores/SettingsStore.js +10 -0
- package/package.json +1 -1
package/dist/Rainman/types.d.ts
CHANGED
|
@@ -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[];
|
|
@@ -209,7 +209,7 @@ export class ButtonsEventManager {
|
|
|
209
209
|
initFreeSpinModal() {
|
|
210
210
|
RainMan.componentRegistry
|
|
211
211
|
.getIfExists(FreeSpinButton.registryName)
|
|
212
|
-
?.setOnClick(() =>
|
|
212
|
+
?.setOnClick(() => RainMan.settingsStore.handleBuyFreeSpinPopupActivation?.());
|
|
213
213
|
}
|
|
214
214
|
/**
|
|
215
215
|
* Method for initializing volume button
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Container, Sprite } from "pixi.js";
|
|
2
|
+
import { BuyFreeSpinOption } from "SettingsUI/hooks";
|
|
3
|
+
import { AcceptDeclineButton } from "./AcceptDeclineButton";
|
|
4
|
+
export type BuyFreeSpinConfig = {
|
|
5
|
+
options: BuyFreeSpinOption[];
|
|
6
|
+
};
|
|
7
|
+
export type BuyFreeSpinState = "selection" | "confirmation";
|
|
8
|
+
export declare abstract class AbstractBuyFreeSpinsPlate extends Container {
|
|
9
|
+
private state;
|
|
10
|
+
protected selectedOption?: BuyFreeSpinOption;
|
|
11
|
+
protected readonly config: BuyFreeSpinConfig;
|
|
12
|
+
protected selectionPlate?: Sprite;
|
|
13
|
+
protected closeButton?: AcceptDeclineButton;
|
|
14
|
+
protected confirmationPlate?: Sprite;
|
|
15
|
+
protected acceptButton?: AcceptDeclineButton;
|
|
16
|
+
protected declineButton?: AcceptDeclineButton;
|
|
17
|
+
protected selectionPlateTexture: string;
|
|
18
|
+
protected confirmationPlateTexture: string;
|
|
19
|
+
private readonly onContinueCallback;
|
|
20
|
+
private readonly resizeHandler;
|
|
21
|
+
private handleClose;
|
|
22
|
+
protected constructor(onContinue: () => void, config: BuyFreeSpinConfig);
|
|
23
|
+
init(): void;
|
|
24
|
+
private createElements;
|
|
25
|
+
resize(): void;
|
|
26
|
+
private showSelectionScreen;
|
|
27
|
+
private showConfirmationScreen;
|
|
28
|
+
protected abstract getPlateScale(): {
|
|
29
|
+
vertical: number;
|
|
30
|
+
horizontal: number;
|
|
31
|
+
};
|
|
32
|
+
protected abstract createSelectionContent(): void;
|
|
33
|
+
protected abstract createConfirmationContent(): void;
|
|
34
|
+
protected abstract showSelectionContent(): void;
|
|
35
|
+
protected abstract showConfirmationContent(option: BuyFreeSpinOption): void;
|
|
36
|
+
protected abstract positionSelectionScreen(): void;
|
|
37
|
+
protected abstract positionConfirmationScreen(): void;
|
|
38
|
+
protected onCleanup(): void;
|
|
39
|
+
protected onBuyButtonClick(option: BuyFreeSpinOption): void;
|
|
40
|
+
private onAcceptClick;
|
|
41
|
+
private renderState;
|
|
42
|
+
private onDeclineClick;
|
|
43
|
+
private cleanup;
|
|
44
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { Container, Sprite, Texture } from "pixi.js";
|
|
2
|
+
import { UXLayer } from "../../layers";
|
|
3
|
+
import { RainMan } from "../../Rainman";
|
|
4
|
+
import { scaleToParent } from "../../utils";
|
|
5
|
+
import { AcceptDeclineButton } from "./AcceptDeclineButton";
|
|
6
|
+
export class AbstractBuyFreeSpinsPlate extends Container {
|
|
7
|
+
state = "selection";
|
|
8
|
+
selectedOption;
|
|
9
|
+
config;
|
|
10
|
+
selectionPlate;
|
|
11
|
+
closeButton;
|
|
12
|
+
confirmationPlate;
|
|
13
|
+
acceptButton;
|
|
14
|
+
declineButton;
|
|
15
|
+
selectionPlateTexture = "selection-freespin-frame";
|
|
16
|
+
confirmationPlateTexture = "confirmation-freespin-frame";
|
|
17
|
+
onContinueCallback;
|
|
18
|
+
resizeHandler = () => this.resize();
|
|
19
|
+
handleClose = () => {
|
|
20
|
+
this.cleanup();
|
|
21
|
+
this.onContinueCallback();
|
|
22
|
+
RainMan.settingsStore.disableKeyboardShortcuts = false;
|
|
23
|
+
};
|
|
24
|
+
constructor(onContinue, config) {
|
|
25
|
+
super();
|
|
26
|
+
RainMan.settingsStore.disableKeyboardShortcuts = true;
|
|
27
|
+
this.onContinueCallback = onContinue;
|
|
28
|
+
this.config = config;
|
|
29
|
+
this.parentLayer = UXLayer;
|
|
30
|
+
this.eventMode = "static";
|
|
31
|
+
if (config.options.length === 1) {
|
|
32
|
+
this.state = "confirmation";
|
|
33
|
+
this.selectedOption = config.options[0];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
init() {
|
|
37
|
+
this.createElements();
|
|
38
|
+
this.renderState();
|
|
39
|
+
RainMan.app.renderer.on("resize", this.resizeHandler);
|
|
40
|
+
this.resize();
|
|
41
|
+
}
|
|
42
|
+
createElements() {
|
|
43
|
+
const numOptions = this.config.options.length;
|
|
44
|
+
this.selectionPlate = new Sprite(Texture.from(this.selectionPlateTexture));
|
|
45
|
+
this.selectionPlate.anchor.set(0.5);
|
|
46
|
+
if (numOptions > 1) {
|
|
47
|
+
this.closeButton = new AcceptDeclineButton(false);
|
|
48
|
+
this.closeButton.setOnClick(() => this.handleClose());
|
|
49
|
+
this.closeButton.anchor.set(0.5);
|
|
50
|
+
}
|
|
51
|
+
this.confirmationPlate = new Sprite(Texture.from(this.confirmationPlateTexture));
|
|
52
|
+
this.confirmationPlate.anchor.set(0.5);
|
|
53
|
+
this.acceptButton = new AcceptDeclineButton(true);
|
|
54
|
+
this.acceptButton.setOnClick(() => this.onAcceptClick(this.selectedOption));
|
|
55
|
+
this.acceptButton.anchor.set(0.5);
|
|
56
|
+
this.declineButton = new AcceptDeclineButton(false);
|
|
57
|
+
this.declineButton.setOnClick(() => this.onDeclineClick());
|
|
58
|
+
this.declineButton.anchor.set(0.5);
|
|
59
|
+
this.createSelectionContent();
|
|
60
|
+
this.createConfirmationContent();
|
|
61
|
+
}
|
|
62
|
+
resize() {
|
|
63
|
+
const { width, height } = RainMan.app.screen;
|
|
64
|
+
if (this.state === "selection") {
|
|
65
|
+
if (!this.selectionPlate)
|
|
66
|
+
return;
|
|
67
|
+
const plateScale = this.getPlateScale();
|
|
68
|
+
const texW = this.selectionPlate.texture.width;
|
|
69
|
+
const texH = this.selectionPlate.texture.height;
|
|
70
|
+
const targetW = width * plateScale.horizontal;
|
|
71
|
+
const targetH = height * plateScale.vertical;
|
|
72
|
+
const dims = scaleToParent(texW, texH, targetW, targetH);
|
|
73
|
+
const scaleX = dims.width / texW;
|
|
74
|
+
const scaleY = dims.height / texH;
|
|
75
|
+
const scale = Math.min(scaleX, scaleY);
|
|
76
|
+
this.scale.set(scale);
|
|
77
|
+
this.position.set(width / 2, height / 2);
|
|
78
|
+
this.positionSelectionScreen();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (this.state === "confirmation") {
|
|
82
|
+
if (!this.confirmationPlate)
|
|
83
|
+
return;
|
|
84
|
+
const plateScale = this.getPlateScale();
|
|
85
|
+
const texW = this.confirmationPlate.texture.width;
|
|
86
|
+
const texH = this.confirmationPlate.texture.height;
|
|
87
|
+
const targetW = RainMan.app.screen.width * plateScale.horizontal;
|
|
88
|
+
const targetH = RainMan.app.screen.height * plateScale.vertical;
|
|
89
|
+
const dims = scaleToParent(texW, texH, targetW, targetH);
|
|
90
|
+
const scaleX = dims.width / texW;
|
|
91
|
+
const scaleY = dims.height / texH;
|
|
92
|
+
const scale = Math.min(scaleX, scaleY);
|
|
93
|
+
this.scale.set(scale);
|
|
94
|
+
this.position.set(width / 2, height / 2);
|
|
95
|
+
this.positionConfirmationScreen();
|
|
96
|
+
}
|
|
97
|
+
this.parentLayer = UXLayer;
|
|
98
|
+
}
|
|
99
|
+
showSelectionScreen() {
|
|
100
|
+
if (!this.selectionPlate)
|
|
101
|
+
return;
|
|
102
|
+
this.selectionPlate.visible = true;
|
|
103
|
+
this.selectionPlate.alpha = 1;
|
|
104
|
+
this.addChild(this.selectionPlate);
|
|
105
|
+
this.showSelectionContent();
|
|
106
|
+
if (this.closeButton) {
|
|
107
|
+
this.addChild(this.closeButton);
|
|
108
|
+
}
|
|
109
|
+
this.positionSelectionScreen();
|
|
110
|
+
}
|
|
111
|
+
showConfirmationScreen() {
|
|
112
|
+
if (!this.confirmationPlate)
|
|
113
|
+
return;
|
|
114
|
+
if (!this.selectedOption) {
|
|
115
|
+
this.selectedOption = this.config.options[0];
|
|
116
|
+
}
|
|
117
|
+
this.addChild(this.confirmationPlate);
|
|
118
|
+
this.showConfirmationContent(this.selectedOption);
|
|
119
|
+
if (this.acceptButton) {
|
|
120
|
+
this.addChild(this.acceptButton);
|
|
121
|
+
}
|
|
122
|
+
if (this.declineButton) {
|
|
123
|
+
this.addChild(this.declineButton);
|
|
124
|
+
}
|
|
125
|
+
this.positionConfirmationScreen();
|
|
126
|
+
}
|
|
127
|
+
onCleanup() { }
|
|
128
|
+
onBuyButtonClick(option) {
|
|
129
|
+
this.selectedOption = option;
|
|
130
|
+
this.state = "confirmation";
|
|
131
|
+
this.renderState();
|
|
132
|
+
this.resize();
|
|
133
|
+
}
|
|
134
|
+
async onAcceptClick(option) {
|
|
135
|
+
const roundNumber = RainMan.settingsStore.roundNumber + 1;
|
|
136
|
+
try {
|
|
137
|
+
const data = await window.connectionWrapper.fetchFreeSpinData(roundNumber, option.amount, option.price);
|
|
138
|
+
const code = data.getRawData()?.status?.code;
|
|
139
|
+
if (code === 400 || code === 406) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
RainMan.settingsStore.setIsFreeSpinBought(true, data);
|
|
143
|
+
RainMan.settingsStore.setFreeSpinNumberBought(option.amount);
|
|
144
|
+
RainMan.globals.updateFreeSpinShown?.(option.amount);
|
|
145
|
+
RainMan.settingsStore.setRoundNumber(roundNumber);
|
|
146
|
+
this.cleanup();
|
|
147
|
+
this.onContinueCallback();
|
|
148
|
+
await RainMan.settingsStore.handleInvokeFreeSpinPlate?.(option.amount, false);
|
|
149
|
+
RainMan.settingsStore.disableKeyboardShortcuts = false;
|
|
150
|
+
RainMan.globals.prepareBoughtFreeSpins?.();
|
|
151
|
+
setTimeout(() => {
|
|
152
|
+
RainMan.globals.throttledSpin?.();
|
|
153
|
+
}, 500);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
console.error(err);
|
|
157
|
+
RainMan.settingsStore.setIsFreeSpinBought(false);
|
|
158
|
+
RainMan.settingsStore.disableKeyboardShortcuts = false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
renderState() {
|
|
162
|
+
this.removeChildren();
|
|
163
|
+
if (this.state === "selection") {
|
|
164
|
+
this.showSelectionScreen();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
this.showConfirmationScreen();
|
|
168
|
+
}
|
|
169
|
+
onDeclineClick() {
|
|
170
|
+
if (this.config.options.length === 1) {
|
|
171
|
+
this.handleClose();
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
this.state = "selection";
|
|
175
|
+
this.selectedOption = undefined;
|
|
176
|
+
this.renderState();
|
|
177
|
+
this.resize();
|
|
178
|
+
}
|
|
179
|
+
cleanup() {
|
|
180
|
+
RainMan.app.renderer.off("resize", this.resizeHandler);
|
|
181
|
+
this.onCleanup();
|
|
182
|
+
this.destroy({ children: true });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseButton } from "../buttons/BaseButton";
|
|
2
|
+
/**
|
|
3
|
+
* Button for accepting or declining number of free spins to buy.
|
|
4
|
+
* It needs following textures:
|
|
5
|
+
* - normal - `v-n.png` for accept, `x-n.png` for decline
|
|
6
|
+
* - hover - `v-h.png` for accept, `x-h.png` for decline
|
|
7
|
+
* - clicked - `v-c.png` for accept, `x-c.png` for decline
|
|
8
|
+
* @param {boolean} isAcceptButton desides which texture to use
|
|
9
|
+
* @augments {BaseButton}
|
|
10
|
+
*/
|
|
11
|
+
export declare class AcceptDeclineButton extends BaseButton {
|
|
12
|
+
static registryName: string;
|
|
13
|
+
constructor(isAcceptButton?: boolean);
|
|
14
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { getTexture } from "../../utils";
|
|
2
|
+
import { BaseButton, ButtonStates } from "../buttons/BaseButton";
|
|
3
|
+
/**
|
|
4
|
+
* Button for accepting or declining number of free spins to buy.
|
|
5
|
+
* It needs following textures:
|
|
6
|
+
* - normal - `v-n.png` for accept, `x-n.png` for decline
|
|
7
|
+
* - hover - `v-h.png` for accept, `x-h.png` for decline
|
|
8
|
+
* - clicked - `v-c.png` for accept, `x-c.png` for decline
|
|
9
|
+
* @param {boolean} isAcceptButton desides which texture to use
|
|
10
|
+
* @augments {BaseButton}
|
|
11
|
+
*/
|
|
12
|
+
export class AcceptDeclineButton extends BaseButton {
|
|
13
|
+
static registryName = "acceptDeclineButton";
|
|
14
|
+
constructor(isAcceptButton) {
|
|
15
|
+
const textureMap = isAcceptButton
|
|
16
|
+
? {
|
|
17
|
+
[ButtonStates.NORMAL]: getTexture("v-n.png"),
|
|
18
|
+
[ButtonStates.OVER]: getTexture("v-h.png"),
|
|
19
|
+
[ButtonStates.CLICKED]: getTexture("v-c.png")
|
|
20
|
+
}
|
|
21
|
+
: {
|
|
22
|
+
[ButtonStates.NORMAL]: getTexture("x-n.png"),
|
|
23
|
+
[ButtonStates.OVER]: getTexture("x-h.png"),
|
|
24
|
+
[ButtonStates.CLICKED]: getTexture("x-c.png")
|
|
25
|
+
};
|
|
26
|
+
super(AcceptDeclineButton.registryName, textureMap);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseButton } from "../buttons/BaseButton";
|
|
2
|
+
/**
|
|
3
|
+
* Button for selecting number of freespins to buy
|
|
4
|
+
* It needs following textures:
|
|
5
|
+
* - normal - `buttonTextureName-n.png`
|
|
6
|
+
* - hover - `buttonTextureName-h.png`
|
|
7
|
+
* - clicked - `buttonTextureName-c.png`
|
|
8
|
+
* @param {string} buttonTextureName name of a texture to use
|
|
9
|
+
* @augments {BaseButton}
|
|
10
|
+
*/
|
|
11
|
+
export declare class BuyFreeSpinButton extends BaseButton {
|
|
12
|
+
static registryName: string;
|
|
13
|
+
constructor(buttonTextureName: string);
|
|
14
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { getTexture } from "../../utils";
|
|
2
|
+
import { BaseButton, ButtonStates } from "../buttons/BaseButton";
|
|
3
|
+
/**
|
|
4
|
+
* Button for selecting number of freespins to buy
|
|
5
|
+
* It needs following textures:
|
|
6
|
+
* - normal - `buttonTextureName-n.png`
|
|
7
|
+
* - hover - `buttonTextureName-h.png`
|
|
8
|
+
* - clicked - `buttonTextureName-c.png`
|
|
9
|
+
* @param {string} buttonTextureName name of a texture to use
|
|
10
|
+
* @augments {BaseButton}
|
|
11
|
+
*/
|
|
12
|
+
export class BuyFreeSpinButton extends BaseButton {
|
|
13
|
+
static registryName = "buyFreeSpinButton";
|
|
14
|
+
constructor(buttonTextureName) {
|
|
15
|
+
const textureMap = {
|
|
16
|
+
[ButtonStates.NORMAL]: getTexture(`${buttonTextureName}-n.png`),
|
|
17
|
+
[ButtonStates.OVER]: getTexture(`${buttonTextureName}-h.png`),
|
|
18
|
+
[ButtonStates.CLICKED]: getTexture(`${buttonTextureName}-c.png`)
|
|
19
|
+
};
|
|
20
|
+
super(BuyFreeSpinButton.registryName, textureMap);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
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
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AbstractBuyFreeSpinsPlate } from "components/AbstractBuyFreeSpins/AbstractBuyFreeSpinsPlate";
|
|
1
2
|
import { Container, Graphics, Sprite } from "pixi.js";
|
|
2
3
|
import { ButtonsEventManager, WinTypeId } from "../../application";
|
|
3
4
|
import { AbstractController } from "../../controllers";
|
|
@@ -54,6 +55,7 @@ export declare abstract class AbstractMainContainer extends Container {
|
|
|
54
55
|
protected mysteryBonusContainer: Nullable<UpdatableSpineContainer>;
|
|
55
56
|
protected resolveMysteryBonusContainer?: PromiseResolverType;
|
|
56
57
|
protected _freeSpinPlate: Nullable<AbstractFreeSpinContainer>;
|
|
58
|
+
protected _buyFreeSpinsPlate: Nullable<AbstractBuyFreeSpinsPlate>;
|
|
57
59
|
protected _freeSpinSummary: Nullable<AbstractFreeSpinContainer>;
|
|
58
60
|
private _bigWinInvokedAt;
|
|
59
61
|
private _mysteryWinInvokedAt;
|
|
@@ -173,6 +175,9 @@ export declare abstract class AbstractMainContainer extends Container {
|
|
|
173
175
|
* @returns {Promise<void>}
|
|
174
176
|
*/
|
|
175
177
|
invokeFreeSpinPlate(freeSpinCount: number, isAdditionalFreeSpin?: boolean, isMoneyReward?: boolean): Promise<void>;
|
|
178
|
+
invokeBuyFreeSpinPlate(): void;
|
|
179
|
+
protected closeBuyFreeSpinPlate(): void;
|
|
180
|
+
protected createBuyFreeSpinPlate(): AbstractBuyFreeSpinsPlate | null;
|
|
176
181
|
/**
|
|
177
182
|
* Function for creating free spin summary
|
|
178
183
|
* @protected
|
|
@@ -47,6 +47,7 @@ export class AbstractMainContainer extends Container {
|
|
|
47
47
|
mysteryBonusContainer = null;
|
|
48
48
|
resolveMysteryBonusContainer = undefined;
|
|
49
49
|
_freeSpinPlate = null;
|
|
50
|
+
_buyFreeSpinsPlate = null;
|
|
50
51
|
_freeSpinSummary = null;
|
|
51
52
|
_bigWinInvokedAt = null;
|
|
52
53
|
_mysteryWinInvokedAt = null;
|
|
@@ -60,6 +61,7 @@ export class AbstractMainContainer extends Container {
|
|
|
60
61
|
this.messageBox = new MessageBox();
|
|
61
62
|
SoundManager.setPlayStatus(SoundTracks.music, RainMan.settingsStore.shouldPlayAmbientMusic);
|
|
62
63
|
RainMan.settingsStore.setHandleInvokeFreeSpinPlate(this.invokeFreeSpinPlate.bind(this));
|
|
64
|
+
RainMan.settingsStore.setHandleBuyFreeSpinPopupActivatio(this.invokeBuyFreeSpinPlate.bind(this));
|
|
63
65
|
RainMan.app.renderer.on("resize", () => this.resize());
|
|
64
66
|
}
|
|
65
67
|
/**
|
|
@@ -236,6 +238,30 @@ export class AbstractMainContainer extends Container {
|
|
|
236
238
|
this.hideOverlay();
|
|
237
239
|
refreshButton.flipDisabledFlag(false);
|
|
238
240
|
}
|
|
241
|
+
invokeBuyFreeSpinPlate() {
|
|
242
|
+
const refreshButton = RainMan.componentRegistry.get(RefreshButton.registryName);
|
|
243
|
+
refreshButton.flipDisabledFlag(true);
|
|
244
|
+
this._buyFreeSpinsPlate = this.createBuyFreeSpinPlate();
|
|
245
|
+
if (!this._buyFreeSpinsPlate) {
|
|
246
|
+
refreshButton.flipDisabledFlag(false);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
this._buyFreeSpinsPlate.init();
|
|
250
|
+
this._buyFreeSpinsPlate.resize();
|
|
251
|
+
this.showOverlay();
|
|
252
|
+
this.addChild(this._buyFreeSpinsPlate);
|
|
253
|
+
}
|
|
254
|
+
closeBuyFreeSpinPlate() {
|
|
255
|
+
this.removeChild(this._buyFreeSpinsPlate);
|
|
256
|
+
this._buyFreeSpinsPlate.destroy({ children: true });
|
|
257
|
+
this._buyFreeSpinsPlate = null;
|
|
258
|
+
this.hideOverlay();
|
|
259
|
+
const refreshButton = RainMan.componentRegistry.get(RefreshButton.registryName);
|
|
260
|
+
refreshButton.flipDisabledFlag(false);
|
|
261
|
+
}
|
|
262
|
+
createBuyFreeSpinPlate() {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
239
265
|
/**
|
|
240
266
|
* Function for creating free spin summary
|
|
241
267
|
* @protected
|
|
@@ -523,7 +549,7 @@ export class AbstractMainContainer extends Container {
|
|
|
523
549
|
async invokeGambleGame() {
|
|
524
550
|
if (!this.gambleGameSpineName)
|
|
525
551
|
return;
|
|
526
|
-
|
|
552
|
+
await new Promise((resolve) => {
|
|
527
553
|
this.gambleGame = new GambleGame(this.gambleGameSpineName, resolve, this._controller.lastWinAmount, this._controller.balance);
|
|
528
554
|
RainMan.settingsStore.isGambleGameActive = true;
|
|
529
555
|
this.showOverlay();
|
|
@@ -535,7 +561,7 @@ export class AbstractMainContainer extends Container {
|
|
|
535
561
|
this._controller.updateGambleValues(RainMan.settingsStore.gambleGameWin);
|
|
536
562
|
this.gambleGame = null;
|
|
537
563
|
}
|
|
538
|
-
this._controller
|
|
564
|
+
this._controller?.updateBalance();
|
|
539
565
|
this.hideOverlay();
|
|
540
566
|
}
|
|
541
567
|
/**
|
|
@@ -884,6 +910,11 @@ export class AbstractMainContainer extends Container {
|
|
|
884
910
|
this.addChild(this.freeSpinSummary);
|
|
885
911
|
this.freeSpinSummary.resize();
|
|
886
912
|
}
|
|
913
|
+
if (this._buyFreeSpinsPlate) {
|
|
914
|
+
this.removeChild(this._buyFreeSpinsPlate);
|
|
915
|
+
this.addChild(this._buyFreeSpinsPlate);
|
|
916
|
+
this._buyFreeSpinsPlate.resize();
|
|
917
|
+
}
|
|
887
918
|
RainMan.settingsStore.popupPaytableRepositionCallback?.();
|
|
888
919
|
}
|
|
889
920
|
/**
|
|
@@ -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();
|
|
@@ -60,6 +60,9 @@
|
|
|
60
60
|
"doubleTo": "DOUBLE TO",
|
|
61
61
|
"collect": "COLLECT",
|
|
62
62
|
"totalBet": "Bet",
|
|
63
|
+
"buyFreeSpinTitle": "BUY",
|
|
64
|
+
"freeSpinsAmount": "{{amount}}",
|
|
65
|
+
"freeSpinText": "FREE SPINS",
|
|
63
66
|
"buyFreeSpins": "Buy Free Spins",
|
|
64
67
|
"possibleWin": "POSSIBLE WIN: ",
|
|
65
68
|
"gamePaysText": "GAME PAYS: "
|
|
@@ -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.
|
|
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 ||
|
|
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 (
|
|
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
|
-
|
|
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
|
package/dist/components/index.js
CHANGED
|
@@ -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
|
-
|
|
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");
|
|
@@ -429,12 +431,19 @@ export class AbstractController {
|
|
|
429
431
|
const refreshButton = RainMan.componentRegistry.get(RefreshButton.registryName);
|
|
430
432
|
this.clearMobileSpinTimeout = () => {
|
|
431
433
|
this.buttonHeldSince = 0;
|
|
432
|
-
this.
|
|
434
|
+
const isSpinning = this.gamePhase === gamePhases.SPINNING ||
|
|
435
|
+
this.gamePhase === gamePhases.CONFIGURING_SPIN ||
|
|
436
|
+
this.gamePhase === gamePhases.DATA_FETCH;
|
|
437
|
+
if (!isSpinning) {
|
|
438
|
+
this.columnsContainer.clearQuickReelsStop();
|
|
439
|
+
}
|
|
433
440
|
if (this.mobileSpinTimeout) {
|
|
434
441
|
clearInterval(this.mobileSpinTimeout);
|
|
435
442
|
this.quickStopController.setQuickStopCounterLock(false);
|
|
436
443
|
this.mobileSpinTimeout = null;
|
|
437
|
-
|
|
444
|
+
if (!isSpinning) {
|
|
445
|
+
this.columnsContainer.clearQuickReelsStop();
|
|
446
|
+
}
|
|
438
447
|
}
|
|
439
448
|
if (this.mobileSpinDelay) {
|
|
440
449
|
clearTimeout(this.mobileSpinDelay);
|
|
@@ -720,6 +729,9 @@ export class AbstractController {
|
|
|
720
729
|
this.mainContainer.freeSpinSummary.emit("pointerdown", new PIXI.FederatedPointerEvent("pointerdown"));
|
|
721
730
|
return;
|
|
722
731
|
}
|
|
732
|
+
if (this.gamePhase === gamePhases.HANDLING_ACTIONS) {
|
|
733
|
+
this.shouldPlayNextSpin = true;
|
|
734
|
+
}
|
|
723
735
|
if (this.mainContainer.mysteryWinVisibleFor) {
|
|
724
736
|
RainMan.componentRegistry.get(COMPONENTS.mysteryWin).stopUpdate();
|
|
725
737
|
}
|
|
@@ -779,12 +791,7 @@ export class AbstractController {
|
|
|
779
791
|
this.quickStopController.handleInvokingSpeedPopup();
|
|
780
792
|
return;
|
|
781
793
|
}
|
|
782
|
-
|
|
783
|
-
this.uiController.totalNumberOfFreeSpins += this.getBoughtNumberOfFreeSpins();
|
|
784
|
-
RainMan.componentRegistry.getIfExists(FreeSpinButton.registryName)?.setInteractivity(false);
|
|
785
|
-
RainMan.settingsStore.setIsFreeSpinBought(false);
|
|
786
|
-
return;
|
|
787
|
-
}
|
|
794
|
+
this.prepareBoughtFreeSpins();
|
|
788
795
|
if (RainMan.settingsStore.isAutoplayEnabled && !this.spinning) {
|
|
789
796
|
this.changeGamePhase(gamePhases.IDLE);
|
|
790
797
|
this.spin();
|
|
@@ -799,6 +806,14 @@ export class AbstractController {
|
|
|
799
806
|
}
|
|
800
807
|
this.spinThrottlerTimeout = setTimeout(() => (this.spinThrottlerTimeout = null), 100);
|
|
801
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
|
+
}
|
|
802
817
|
/**
|
|
803
818
|
* This function is responsible for getting the number of free spins bought
|
|
804
819
|
* @private
|
|
@@ -859,6 +874,12 @@ export class AbstractController {
|
|
|
859
874
|
logInfo("Take action can't be performed");
|
|
860
875
|
return;
|
|
861
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);
|
|
862
883
|
const takeData = await window.connectionWrapper.sendTakeAction(RainMan.settingsStore.roundNumber);
|
|
863
884
|
if (takeData.status.code === 200) {
|
|
864
885
|
RainMan.settingsStore.isTakeActionAvailable = false;
|
|
@@ -974,14 +995,10 @@ export class AbstractController {
|
|
|
974
995
|
*/
|
|
975
996
|
gambleGameEnabler(winAmount) {
|
|
976
997
|
if (RainMan.componentRegistry.has(BUTTONS.gamble) && RainMan.settingsStore.isGambleGameAvailable) {
|
|
977
|
-
RainMan.componentRegistry
|
|
978
|
-
.get(BUTTONS.gamble)
|
|
979
|
-
.flipDisabledFlag(RainMan.settingsStore.isFreeSpinsPlayEnabled || winAmount === 0);
|
|
998
|
+
RainMan.componentRegistry.get(BUTTONS.gamble).flipDisabledFlag(winAmount === 0);
|
|
980
999
|
}
|
|
981
1000
|
if (RainMan.componentRegistry.has(BUTTONS.take) && RainMan.settingsStore.isTakeActionAvailable) {
|
|
982
|
-
RainMan.componentRegistry
|
|
983
|
-
.get(BUTTONS.take)
|
|
984
|
-
.flipDisabledFlag(RainMan.settingsStore.isFreeSpinsPlayEnabled || winAmount === 0);
|
|
1001
|
+
RainMan.componentRegistry.get(BUTTONS.take).flipDisabledFlag(winAmount === 0);
|
|
985
1002
|
}
|
|
986
1003
|
}
|
|
987
1004
|
/**
|
|
@@ -1060,7 +1077,7 @@ export class AbstractController {
|
|
|
1060
1077
|
const availableFreeSpins = spinLogic.availableFreeSpins;
|
|
1061
1078
|
const availableFreeSpinsIncreased = availableFreeSpins > RainMan.settingsStore.howManyFreeSpinsLeft;
|
|
1062
1079
|
this.hideFreeSpinsMessageBox = availableFreeSpinsIncreased;
|
|
1063
|
-
if (this._lastWinAmount !== 0) {
|
|
1080
|
+
if (this._lastWinAmount !== 0 && !(availableFreeSpins > 0)) {
|
|
1064
1081
|
RainMan.settingsStore.isTakeActionAvailable = true;
|
|
1065
1082
|
RainMan.settingsStore.isGambleGameAvailable = true;
|
|
1066
1083
|
}
|
|
@@ -1199,6 +1216,24 @@ export class AbstractController {
|
|
|
1199
1216
|
}
|
|
1200
1217
|
RainMan.settingsStore.setIsPlayingAnyAction(false);
|
|
1201
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
|
+
}
|
|
1202
1237
|
}
|
|
1203
1238
|
/**
|
|
1204
1239
|
* Function for invoking free spin plate, invoked in mainContainer
|
|
@@ -1227,7 +1262,6 @@ export class AbstractController {
|
|
|
1227
1262
|
*/
|
|
1228
1263
|
async handleFreeSpinSummaryPlateInvocation() {
|
|
1229
1264
|
await this.buttonsEventManager.disableButtonsForAction(async () => {
|
|
1230
|
-
this.uiController.updateDisplayedBalance(this.uiController.totalFreeSpinWinAmount);
|
|
1231
1265
|
this.uiController.messageBox.hideFreeSpinText();
|
|
1232
1266
|
this.uiController.messageBox.hideCurrentWinText();
|
|
1233
1267
|
await this.mainContainer.invokeFreeSpinSummary(this.uiController.totalNumberOfFreeSpins, this.uiController.totalFreeSpinWinAmount);
|
|
@@ -1235,7 +1269,6 @@ export class AbstractController {
|
|
|
1235
1269
|
this.uiController.resetTotalFreeSpinWinAmount();
|
|
1236
1270
|
this.changeGamePhase(gamePhases.IDLE);
|
|
1237
1271
|
});
|
|
1238
|
-
this.uiController.currentBalance = RainMan.settingsStore.balanceAfterSpin;
|
|
1239
1272
|
RainMan.settingsStore.resetTotalNumberOfFreeSpins();
|
|
1240
1273
|
RainMan.settingsStore.resetFreeSpinNumberBought();
|
|
1241
1274
|
this.changeGamePhase(gamePhases.IDLE);
|
|
@@ -62,6 +62,7 @@ export declare class SettingsStore {
|
|
|
62
62
|
closeOtherModals?: (layerId: string) => void;
|
|
63
63
|
closeCurrentlyOpenModal?: () => void;
|
|
64
64
|
handleInvokeFreeSpinPlate?: (freeSpinAmount: number, isAdditionalFreeSpin: boolean) => Promise<void>;
|
|
65
|
+
handleBuyFreeSpinPopupActivation?: () => void;
|
|
65
66
|
increaseBet?: () => void;
|
|
66
67
|
decreaseBet?: () => void;
|
|
67
68
|
enableButtons?: () => void;
|
|
@@ -387,6 +388,13 @@ export declare class SettingsStore {
|
|
|
387
388
|
* @returns {void}
|
|
388
389
|
*/
|
|
389
390
|
setHandleInvokeFreeSpinPlate(handleInvokeFreeSpinPlate: (freeSpinAmount: number, isAdditionalFreeSpin: boolean) => Promise<void>): void;
|
|
391
|
+
/**
|
|
392
|
+
* Set the callback for invoking the free spin plate
|
|
393
|
+
* @param handleBuyFreeSpinPopupActivation
|
|
394
|
+
* @public
|
|
395
|
+
* @returns {void}
|
|
396
|
+
*/
|
|
397
|
+
setHandleBuyFreeSpinPopupActivatio(handleBuyFreeSpinPopupActivation: () => void): void;
|
|
390
398
|
/**
|
|
391
399
|
* Reset the number of free spins bought
|
|
392
400
|
* @public
|
|
@@ -66,6 +66,7 @@ export class SettingsStore {
|
|
|
66
66
|
closeOtherModals;
|
|
67
67
|
closeCurrentlyOpenModal;
|
|
68
68
|
handleInvokeFreeSpinPlate;
|
|
69
|
+
handleBuyFreeSpinPopupActivation;
|
|
69
70
|
increaseBet;
|
|
70
71
|
decreaseBet;
|
|
71
72
|
enableButtons;
|
|
@@ -641,6 +642,15 @@ export class SettingsStore {
|
|
|
641
642
|
setHandleInvokeFreeSpinPlate(handleInvokeFreeSpinPlate) {
|
|
642
643
|
this.handleInvokeFreeSpinPlate = handleInvokeFreeSpinPlate;
|
|
643
644
|
}
|
|
645
|
+
/**
|
|
646
|
+
* Set the callback for invoking the free spin plate
|
|
647
|
+
* @param handleBuyFreeSpinPopupActivation
|
|
648
|
+
* @public
|
|
649
|
+
* @returns {void}
|
|
650
|
+
*/
|
|
651
|
+
setHandleBuyFreeSpinPopupActivatio(handleBuyFreeSpinPopupActivation) {
|
|
652
|
+
this.handleBuyFreeSpinPopupActivation = handleBuyFreeSpinPopupActivation;
|
|
653
|
+
}
|
|
644
654
|
/**
|
|
645
655
|
* Reset the number of free spins bought
|
|
646
656
|
* @public
|
package/package.json
CHANGED