pixi-rainman-game-engine 0.2.25 → 0.2.27
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/ComponentRegistry/ComponentRegistry.js +1 -2
- package/dist/ComponentRegistry/types.js +1 -1
- package/dist/Rainman/Rainman.js +2 -2
- package/dist/Rainman/appConfig.js +3 -3
- package/dist/Rainman/types.d.ts +2 -0
- package/dist/SettingsUI/components/AutoplaySettings/index.jsx +2 -2
- package/dist/SettingsUI/components/BuyFreeSpins/index.jsx +2 -1
- package/dist/SettingsUI/components/OptionButton/index.jsx +3 -2
- package/dist/SettingsUI/hooks/useBuyFreeSpins/useBuyFreeSpins.js +14 -10
- package/dist/application/SpinLogic/util.js +5 -5
- package/dist/application/setup.js +1 -1
- package/dist/components/AbstractMainContainer/AbstractMainContainer.d.ts +4 -4
- package/dist/components/AbstractMainContainer/AbstractMainContainer.js +16 -4
- package/dist/components/buttons/BaseButton/ButtonState.js +1 -1
- package/dist/components/common/AnimatedNumber.d.ts +6 -4
- package/dist/components/common/AnimatedNumber.js +16 -0
- package/dist/components/symbols/AbstractSymbolsColumn.d.ts +2 -2
- package/dist/connectivity/ConnectionWrapper.d.ts +56 -3
- package/dist/connectivity/ConnectionWrapper.js +83 -18
- package/dist/connectivity/LocalConnectionWrapper.d.ts +1 -0
- package/dist/connectivity/LocalConnectionWrapper.js +10 -0
- package/dist/connectivity/serverConnection.d.ts +14 -6
- package/dist/connectivity/serverData.d.ts +15 -2
- package/dist/connectivity/spinData.js +2 -2
- package/dist/constants/gamePhase.js +1 -1
- package/dist/constants/transformation.js +1 -1
- package/dist/constants/wins.js +1 -1
- package/dist/controllers/AbstractController.d.ts +6 -1
- package/dist/controllers/AbstractController.js +23 -11
- package/dist/controllers/UiController.js +1 -0
- package/dist/loading/AbstractLoadingContainer.js +1 -1
- package/dist/stores/SettingsStore.d.ts +6 -2
- package/dist/stores/SettingsStore.js +10 -0
- package/dist/utils/common/functions.js +1 -1
- package/dist/utils/common/placementHelpers.js +1 -1
- package/dist/utils/common/types.d.ts +2 -1
- package/package.json +1 -1
|
@@ -9,10 +9,9 @@ import { openFullscreen } from "../utils";
|
|
|
9
9
|
export class ComponentRegistry {
|
|
10
10
|
registry = new Map();
|
|
11
11
|
speedAdaptableComponents = new Set();
|
|
12
|
-
incentiveJobsManager;
|
|
12
|
+
incentiveJobsManager = new TimedIncentiveController();
|
|
13
13
|
speedLevelHandler = SpeedLevelHandler.initWithDefaultSpeedLevels();
|
|
14
14
|
constructor(app) {
|
|
15
|
-
this.incentiveJobsManager = new TimedIncentiveController();
|
|
16
15
|
app.renderer.addListener("pointerdown", () => {
|
|
17
16
|
this.setUserActivityTime();
|
|
18
17
|
openFullscreen();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import { AbstractColumnsContainer, AbstractFrame, AbstractInnerFrame, AutoplayButton, Background, BUTTONS, COMPONENTS, FreeSpinButton, InfoButton, MessageBox, MoreButton, NegButton, PlusButton, RefreshButton, SpeedControlButton, VolumeButton
|
|
1
|
+
import { AbstractColumnsContainer, AbstractFrame, AbstractInnerFrame, AutoplayButton, Background, BUTTONS, COMPONENTS, FreeSpinButton, InfoButton, MessageBox, MoreButton, NegButton, PlusButton, RefreshButton, SpeedControlButton, VolumeButton } from "../components";
|
package/dist/Rainman/Rainman.js
CHANGED
|
@@ -28,8 +28,8 @@ export class RainMan {
|
|
|
28
28
|
RainMan.settingsStore = settingStore;
|
|
29
29
|
RainMan.componentRegistry = new ComponentRegistry(app);
|
|
30
30
|
RainMan.globals = {
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
currency: Currencies["USD"],
|
|
32
|
+
shouldShowModals: false
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
}
|
|
@@ -47,10 +47,10 @@ export const defaultAppConfig = {
|
|
|
47
47
|
superBonusWinMinimumTime: 2000,
|
|
48
48
|
superBonusWinPhaseTimeout: 2600,
|
|
49
49
|
speedPopupVisibleTime: 2000,
|
|
50
|
-
minAnimationTime: 1000
|
|
50
|
+
minAnimationTime: 1000
|
|
51
51
|
},
|
|
52
52
|
constants: {
|
|
53
53
|
bigWinMultiplier: 30,
|
|
54
|
-
bigWinTextOffset: 0
|
|
55
|
-
}
|
|
54
|
+
bigWinTextOffset: 0
|
|
55
|
+
}
|
|
56
56
|
};
|
package/dist/Rainman/types.d.ts
CHANGED
|
@@ -68,8 +68,10 @@ export type AppConfig = RequiredAppConfig & DeepPartial<OptionalAppConfig>;
|
|
|
68
68
|
export interface Globals {
|
|
69
69
|
currency: Currency;
|
|
70
70
|
shouldShowModals: boolean;
|
|
71
|
+
getWebSocketConnection?: () => WebSocket;
|
|
71
72
|
actionsAfterClosureWebSocket?: () => void;
|
|
72
73
|
disableSpeedPopup?: (value: boolean) => void;
|
|
73
74
|
handleDisablingButtons?: (value?: boolean) => void;
|
|
74
75
|
throttledSpin?: () => void;
|
|
76
|
+
updateFreeSpinShown?: (value: number) => void;
|
|
75
77
|
}
|
|
@@ -25,7 +25,7 @@ export const AutoplaySettings = observer(() => {
|
|
|
25
25
|
}
|
|
26
26
|
return {
|
|
27
27
|
bottomLimitIndex,
|
|
28
|
-
topLimitIndex
|
|
28
|
+
topLimitIndex
|
|
29
29
|
};
|
|
30
30
|
};
|
|
31
31
|
const updateLimitsBounds = (newLimit) => {
|
|
@@ -49,7 +49,7 @@ export const AutoplaySettings = observer(() => {
|
|
|
49
49
|
useEffect(() => {
|
|
50
50
|
updateLimitsBounds(initialAutoSpinCount);
|
|
51
51
|
}, []);
|
|
52
|
-
const { singleWinExceeds, balancedIncreased, balancedDecreased, howManyAutoSpinsLeft, infinitySpinsEnabled, setSingleWinExceeds, setBalancedIncreased, setBalancedDecreased, setAutoSpinsCount, flipInfinitySpinsFlag, resetAutoplaySettings
|
|
52
|
+
const { singleWinExceeds, balancedIncreased, balancedDecreased, howManyAutoSpinsLeft, infinitySpinsEnabled, setSingleWinExceeds, setBalancedIncreased, setBalancedDecreased, setAutoSpinsCount, flipInfinitySpinsFlag, resetAutoplaySettings } = settingStore;
|
|
53
53
|
return (<div className="autoplay-settings">
|
|
54
54
|
<CloseModalButton layerId={UI_ITEMS.autoplay}/>
|
|
55
55
|
<div className="autoplay-settings__title">
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "./buyFreeSpin.css";
|
|
2
|
+
import i18next from "i18next";
|
|
2
3
|
import React, { useState } from "react";
|
|
3
4
|
import { Currencies } from "ts-money";
|
|
4
5
|
import { UI_ITEMS } from "../../../utils";
|
|
@@ -13,7 +14,7 @@ export const BuyFreeSpinModal = () => {
|
|
|
13
14
|
return (<div className="buyFreeSpins__container">
|
|
14
15
|
<CloseModalButton layerId={UI_ITEMS.freeSpin} afterClose={clearErrorMessage}/>
|
|
15
16
|
<div className="buyFreeSpins__title-container">
|
|
16
|
-
<h1>
|
|
17
|
+
<h1>{i18next.t("buyFreeSpins")}</h1>
|
|
17
18
|
</div>
|
|
18
19
|
<div className="buyFreeSpins__buttons-container">
|
|
19
20
|
{freeSpinOptions.map((option) => (<OptionButton key={option.amount} setMessage={setErrorMessage} option={option} currency={currency}/>))}
|
|
@@ -20,10 +20,11 @@ export const OptionButton = ({ option, currency, setMessage }) => {
|
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
settingStore.setIsFreeSpinBought(true, data);
|
|
23
|
-
settingStore.setRoundNumber(data.getRawData().round_number);
|
|
24
23
|
settingStore.setFreeSpinNumberBought(option.amount);
|
|
25
|
-
RainMan.globals.throttledSpin?.();
|
|
26
24
|
settingStore.handleModalInvocation?.(UI_ITEMS.freeSpin);
|
|
25
|
+
settingStore.handleInvokeFreeSpinPlate?.(option.amount, false);
|
|
26
|
+
RainMan.globals.updateFreeSpinShown?.(option.amount);
|
|
27
|
+
settingStore.setRoundNumber(roundNumber);
|
|
27
28
|
}
|
|
28
29
|
catch (err) {
|
|
29
30
|
setMessage(err.message);
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
import { autorun } from "mobx";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { RainMan } from "../../../Rainman";
|
|
1
4
|
export const useBuyFreeSpinOptions = () => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
];
|
|
5
|
+
const [options, setOptions] = useState([]);
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
const disposer = autorun(() => {
|
|
8
|
+
setOptions(Object.entries(RainMan.settingsStore.freeSpinBuyTable).map(([amount, multiplier]) => ({
|
|
9
|
+
amount: parseInt(amount, 10),
|
|
10
|
+
price: multiplier
|
|
11
|
+
})));
|
|
12
|
+
});
|
|
13
|
+
return () => disposer();
|
|
14
|
+
}, []);
|
|
15
|
+
return options;
|
|
12
16
|
};
|
|
@@ -14,7 +14,7 @@ const getWinFromRawResponse = (rawWin, winIndex) => {
|
|
|
14
14
|
symbolId: rawWin.symbol_id,
|
|
15
15
|
typeId: rawWin.type_id,
|
|
16
16
|
amount: rawWin.amount,
|
|
17
|
-
winIndex
|
|
17
|
+
winIndex
|
|
18
18
|
};
|
|
19
19
|
};
|
|
20
20
|
/**
|
|
@@ -50,7 +50,7 @@ const joinTransformationsIntoDropTransformation = (destroyTransformations, symbo
|
|
|
50
50
|
preparedDropTransformations.push({
|
|
51
51
|
type: transformationTypes.drop,
|
|
52
52
|
coordinates: destroyPlace,
|
|
53
|
-
symbolId: gameConfig.getSymbolId(symbolsToDrop[index])
|
|
53
|
+
symbolId: gameConfig.getSymbolId(symbolsToDrop[index])
|
|
54
54
|
});
|
|
55
55
|
});
|
|
56
56
|
});
|
|
@@ -91,7 +91,7 @@ export const getFreezeTransformationFromRawResponse = (transformations) => {
|
|
|
91
91
|
return transformations.map((freezeTransformation) => {
|
|
92
92
|
return {
|
|
93
93
|
type: transformationTypes.freeze,
|
|
94
|
-
coordinates: freezeTransformation.coordinates
|
|
94
|
+
coordinates: freezeTransformation.coordinates
|
|
95
95
|
};
|
|
96
96
|
});
|
|
97
97
|
};
|
|
@@ -106,7 +106,7 @@ export const concatenateFreezeAndSpinTransformations = (freezeTransformations, o
|
|
|
106
106
|
return {
|
|
107
107
|
type: transformationTypes.spinAndFreeze,
|
|
108
108
|
coordinates: allCoordinatesToFreeze,
|
|
109
|
-
symbolsOnReels: onStopBlindsConfiguration
|
|
109
|
+
symbolsOnReels: onStopBlindsConfiguration
|
|
110
110
|
};
|
|
111
111
|
};
|
|
112
112
|
/**
|
|
@@ -136,6 +136,6 @@ export const collectWinDetailsWithTransformation = (winsDetails, transformations
|
|
|
136
136
|
const wins = winsDetails ? [getWinFromRawResponse(winsDetails, winIndex ?? "")] : [];
|
|
137
137
|
return {
|
|
138
138
|
wins,
|
|
139
|
-
transformations
|
|
139
|
+
transformations
|
|
140
140
|
};
|
|
141
141
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRoot } from "react-dom/client";
|
|
2
2
|
import { RainMan } from "../Rainman";
|
|
3
3
|
import { SettingsUI } from "../SettingsUI";
|
|
4
|
-
import { changeResolution, disableMagnifyingGlassOnIOS, getDeviceOrientation, invokeStatsBoard, loadSoundsOnTabChange, resizeCanvas, setupFullscreenForIOS
|
|
4
|
+
import { changeResolution, disableMagnifyingGlassOnIOS, getDeviceOrientation, invokeStatsBoard, loadSoundsOnTabChange, resizeCanvas, setupFullscreenForIOS } from "../utils";
|
|
5
5
|
/**
|
|
6
6
|
* This function is for setup the whole games
|
|
7
7
|
*
|
|
@@ -2,7 +2,7 @@ import { Container, Graphics, Sprite } from "pixi.js";
|
|
|
2
2
|
import { ButtonsEventManager, WinTypeId } from "../../application";
|
|
3
3
|
import { AbstractController } from "../../controllers";
|
|
4
4
|
import { RainMan } from "../../Rainman";
|
|
5
|
-
import { Nullable } from "../../utils";
|
|
5
|
+
import { Nullable, PromiseResolverType } from "../../utils";
|
|
6
6
|
import { BigWinContainer, MysteryWinContainer, UpdatableSpineContainer } from "../../winComponents";
|
|
7
7
|
import { AbstractFreeSpinContainer } from "../AbstractFreeSpinContainer";
|
|
8
8
|
import { LeftButtons, LeftButtonsLandscape, LeftButtonsMobile, MiddleButtons, RightButtons, RightButtonsLandscape, RightButtonsMobile } from "../buttons";
|
|
@@ -49,9 +49,9 @@ export declare abstract class AbstractMainContainer extends Container {
|
|
|
49
49
|
protected bottomPanel: Nullable<Sprite>;
|
|
50
50
|
protected gambleGameSpineName: Nullable<string>;
|
|
51
51
|
private gambleGame;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
protected resolveMysteryBonusContainer?:
|
|
52
|
+
protected rouletteWinContainer: Nullable<UpdatableSpineContainer>;
|
|
53
|
+
protected mysteryBonusContainer: Nullable<UpdatableSpineContainer>;
|
|
54
|
+
protected resolveMysteryBonusContainer?: PromiseResolverType;
|
|
55
55
|
protected _freeSpinPlate: Nullable<AbstractFreeSpinContainer>;
|
|
56
56
|
protected _freeSpinSummary: Nullable<AbstractFreeSpinContainer>;
|
|
57
57
|
private _bigWinInvokedAt;
|
|
@@ -44,7 +44,7 @@ export class AbstractMainContainer extends Container {
|
|
|
44
44
|
gambleGame = null;
|
|
45
45
|
rouletteWinContainer = null;
|
|
46
46
|
mysteryBonusContainer = null;
|
|
47
|
-
resolveMysteryBonusContainer;
|
|
47
|
+
resolveMysteryBonusContainer = undefined;
|
|
48
48
|
_freeSpinPlate = null;
|
|
49
49
|
_freeSpinSummary = null;
|
|
50
50
|
_bigWinInvokedAt = null;
|
|
@@ -63,6 +63,7 @@ export class AbstractMainContainer extends Container {
|
|
|
63
63
|
SoundManager.setPlayStatus(SoundTracks.music, RainMan.settingsStore.shouldPlayAmbientMusic);
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
+
RainMan.settingsStore.setHandleInvokeFreeSpinPlate(this.invokeFreeSpinPlate.bind(this));
|
|
66
67
|
RainMan.app.renderer.on("resize", () => this.resize());
|
|
67
68
|
}
|
|
68
69
|
/**
|
|
@@ -283,8 +284,9 @@ export class AbstractMainContainer extends Container {
|
|
|
283
284
|
* This function removes the overlay from the main container and sets it to null.
|
|
284
285
|
*/
|
|
285
286
|
hideOverlay() {
|
|
286
|
-
if (this.overlay)
|
|
287
|
+
if (this.overlay) {
|
|
287
288
|
this.removeChild(this.overlay);
|
|
289
|
+
}
|
|
288
290
|
this.overlay = null;
|
|
289
291
|
}
|
|
290
292
|
/**
|
|
@@ -563,8 +565,9 @@ export class AbstractMainContainer extends Container {
|
|
|
563
565
|
* Function for disabling components for mobile portrait orientation.
|
|
564
566
|
*/
|
|
565
567
|
disableForMobile() {
|
|
566
|
-
if (this.logo)
|
|
568
|
+
if (this.logo) {
|
|
567
569
|
this.logo.renderable = false;
|
|
570
|
+
}
|
|
568
571
|
if (this.underFramePanel !== null) {
|
|
569
572
|
this.removeChild(this.underFramePanel);
|
|
570
573
|
this.underFramePanel = null;
|
|
@@ -604,11 +607,15 @@ export class AbstractMainContainer extends Container {
|
|
|
604
607
|
if (this.bonusWinContainer) {
|
|
605
608
|
this.removeChild(this.bonusWinContainer);
|
|
606
609
|
}
|
|
610
|
+
if (this.mysteryBonusContainer) {
|
|
611
|
+
this.removeChild(this.mysteryBonusContainer);
|
|
612
|
+
}
|
|
607
613
|
this.messageBox.resize();
|
|
608
614
|
this.background.resize();
|
|
609
615
|
this.animatedFront?.resize();
|
|
610
|
-
if (this.freeSpinButton)
|
|
616
|
+
if (this.freeSpinButton) {
|
|
611
617
|
this.freeSpinButton.resize();
|
|
618
|
+
}
|
|
612
619
|
this.addChild(this._frame);
|
|
613
620
|
this._frame.resize();
|
|
614
621
|
this.initComponentsForScreenRatio();
|
|
@@ -770,6 +777,11 @@ export class AbstractMainContainer extends Container {
|
|
|
770
777
|
this.addChild(this.mysteryWinContainer);
|
|
771
778
|
this.mysteryWinContainer.resize();
|
|
772
779
|
}
|
|
780
|
+
if (this.mysteryBonusContainer) {
|
|
781
|
+
this.removeChild(this.mysteryBonusContainer);
|
|
782
|
+
this.mysteryBonusContainer.resize();
|
|
783
|
+
this.addChild(this.mysteryBonusContainer);
|
|
784
|
+
}
|
|
773
785
|
if (this.gambleGame) {
|
|
774
786
|
this.gambleGame.resize();
|
|
775
787
|
}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { Container } from "pixi.js";
|
|
2
|
+
import { Spine } from "pixi-spine";
|
|
2
3
|
/**
|
|
3
4
|
* Class representing animated number, based on spine animation.
|
|
4
5
|
* Animation names should be exact the same as a represented symbol.
|
|
5
6
|
*/
|
|
6
7
|
export declare class AnimatedNumber extends Container {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
spineName: string;
|
|
9
|
+
number: number | string;
|
|
10
|
+
digits: Spine[];
|
|
10
11
|
constructor(spineName: string, number: number | string);
|
|
11
12
|
private setDigits;
|
|
12
|
-
|
|
13
|
+
setMoveAnimation(): void;
|
|
14
|
+
removeDigits(): void;
|
|
13
15
|
get value(): number | string;
|
|
14
16
|
set value(value: number | string);
|
|
15
17
|
play(): void;
|
|
@@ -31,6 +31,22 @@ export class AnimatedNumber extends Container {
|
|
|
31
31
|
});
|
|
32
32
|
this.pivot.set(this.width / 2, this.height / 2);
|
|
33
33
|
}
|
|
34
|
+
setMoveAnimation() {
|
|
35
|
+
this.removeDigits();
|
|
36
|
+
Array.from(this.number.toString()).forEach((digit) => {
|
|
37
|
+
const digitSpine = new Spine(getSpineData(this.spineName));
|
|
38
|
+
digitSpine.state.setAnimation(0, digit + "-move", true);
|
|
39
|
+
digitSpine.x = (this.digits.at(-1)?.x || 0) + digitSpine.width * 2;
|
|
40
|
+
if (digit === "." || digit === ",") {
|
|
41
|
+
digitSpine.x += 15;
|
|
42
|
+
digitSpine.y += 25;
|
|
43
|
+
}
|
|
44
|
+
digitSpine.state.timeScale = 1;
|
|
45
|
+
this.addChild(digitSpine);
|
|
46
|
+
this.digits.push(digitSpine);
|
|
47
|
+
});
|
|
48
|
+
this.pivot.set(this.width / 2, this.height / 2);
|
|
49
|
+
}
|
|
34
50
|
removeDigits() {
|
|
35
51
|
this.digits.forEach((digit) => this.removeChild(digit));
|
|
36
52
|
this.digits = [];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Container } from "pixi.js";
|
|
2
2
|
import { SpeedAdapterInterface, SpeedLevel, SymbolId } from "../../application";
|
|
3
3
|
import { DropTransformationDetails, SymbolReel } from "../../connectivity";
|
|
4
|
-
import { Nullable,
|
|
4
|
+
import { Nullable, PromiseResolverType } from "../../utils";
|
|
5
5
|
import { AbstractColumnsContainer, AbstractFrame } from "../frame";
|
|
6
6
|
import { AbstractSymbolBase } from "./AbstractSymbolBase";
|
|
7
7
|
import { AnimationTimeSettings, Phase } from "./types";
|
|
@@ -28,7 +28,7 @@ export declare abstract class AbstractSymbolsColumn extends Container implements
|
|
|
28
28
|
private lastEnding;
|
|
29
29
|
private tween;
|
|
30
30
|
private wiggleTween;
|
|
31
|
-
resolveMysterySpeedUp: Nullable<
|
|
31
|
+
resolveMysterySpeedUp: Nullable<PromiseResolverType<void>>;
|
|
32
32
|
private resolver;
|
|
33
33
|
private shouldMoveToTop;
|
|
34
34
|
private droppingTweens;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { ExtraDataRequest, GambleCardColor, GambleDataInterface, InitDataInterface, ServerMessage, SpinData, SubscribableConnectionWrapper } from "../connectivity";
|
|
2
2
|
/**
|
|
3
3
|
* Class for managing connection to the server via websockets
|
|
4
|
+
* This class handles communication with the server, including fetching initial data, spin data, free spin data, and gamble data.
|
|
5
|
+
* @implements {SubscribableConnectionWrapper}
|
|
4
6
|
*/
|
|
5
7
|
export declare class ConnectionWrapper implements SubscribableConnectionWrapper {
|
|
6
8
|
private webSocketConnection;
|
|
7
|
-
private config
|
|
9
|
+
private config?;
|
|
8
10
|
private fetchInProgress;
|
|
9
11
|
private lastFetchResponse;
|
|
10
12
|
private lastGambleResponse;
|
|
@@ -15,18 +17,43 @@ export declare class ConnectionWrapper implements SubscribableConnectionWrapper
|
|
|
15
17
|
*/
|
|
16
18
|
private handleMessage;
|
|
17
19
|
private _messageHistory;
|
|
18
|
-
private _initData
|
|
20
|
+
private _initData?;
|
|
19
21
|
constructor();
|
|
22
|
+
/**
|
|
23
|
+
* Method for opening a websocket connection
|
|
24
|
+
* @returns {Promise<void>} resolves when the connection is opened
|
|
25
|
+
*/
|
|
20
26
|
private openConnection;
|
|
21
27
|
/**
|
|
22
28
|
* Method for initializing communication with the server
|
|
23
29
|
*/
|
|
24
30
|
initCommunication(): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Method for subscribing to configuration changes
|
|
33
|
+
* @param {() => void} subscriberFn - function to be called when configuration changes
|
|
34
|
+
* @returns {void}
|
|
35
|
+
* @memberof ConnectionWrapper
|
|
36
|
+
*/
|
|
25
37
|
subscribeForConfigChanges(subscriberFn: () => void): void;
|
|
38
|
+
/**
|
|
39
|
+
* Method for fetching initial data from the server
|
|
40
|
+
* @returns {Promise<void>} resolves when the data is fetched
|
|
41
|
+
* @memberof ConnectionWrapper
|
|
42
|
+
*/
|
|
26
43
|
fetchInitData(): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Method for getting initial data from the server
|
|
46
|
+
* @returns {InitDataInterface} initial data from the server
|
|
47
|
+
*/
|
|
27
48
|
initData(): InitDataInterface;
|
|
49
|
+
/**
|
|
50
|
+
* Method for fetching free spin data from the server
|
|
51
|
+
* @param {number} roundNumber round number
|
|
52
|
+
* @param {number} quantity quantity of free spins
|
|
53
|
+
* @param {number} price price of free spins
|
|
54
|
+
* @returns {SpinData} spin data
|
|
55
|
+
*/
|
|
28
56
|
fetchFreeSpinData(roundNumber: number, quantity: number, price: number): Promise<SpinData>;
|
|
29
|
-
private transformFreeSpinData;
|
|
30
57
|
/**
|
|
31
58
|
* Method for fetching spin data from the server
|
|
32
59
|
* @param {number} roundNumber round number
|
|
@@ -35,7 +62,25 @@ export declare class ConnectionWrapper implements SubscribableConnectionWrapper
|
|
|
35
62
|
* @returns {SpinData} spin data
|
|
36
63
|
*/
|
|
37
64
|
fetchSpinData(roundNumber: number, bet: number, extra_data?: ExtraDataRequest): Promise<SpinData>;
|
|
65
|
+
/**
|
|
66
|
+
* Sends end of round data to the server
|
|
67
|
+
* This method is used to notify the server that the round has ended and to update the server state accordingly.
|
|
68
|
+
* @param {number} roundNumber - the round number to send data from
|
|
69
|
+
* @returns {Promise<ServerMessage>} - server message with end of round data
|
|
70
|
+
*/
|
|
71
|
+
sendEndOfRoundData(roundNumber: number): Promise<ServerMessage>;
|
|
72
|
+
/**
|
|
73
|
+
* Method for fetching gamble data from the server
|
|
74
|
+
* @param {number} roundNumber round number
|
|
75
|
+
* @param {number} bet bet amount
|
|
76
|
+
* @param {GambleCardColor} choice gamble card color choice
|
|
77
|
+
* @returns {Promise<GambleDataInterface>} gamble data
|
|
78
|
+
*/
|
|
38
79
|
fetchGambleData(roundNumber: number, bet: number, choice: GambleCardColor): Promise<GambleDataInterface>;
|
|
80
|
+
/**
|
|
81
|
+
* Method for getting a fresh websocket instance
|
|
82
|
+
* @returns {WebSocket} fresh websocket instance
|
|
83
|
+
*/
|
|
39
84
|
private getFreshWsInstance;
|
|
40
85
|
/**
|
|
41
86
|
* Method for fetching data from the server
|
|
@@ -43,6 +88,14 @@ export declare class ConnectionWrapper implements SubscribableConnectionWrapper
|
|
|
43
88
|
* @returns {ServerMessage} server response
|
|
44
89
|
*/
|
|
45
90
|
private fetch;
|
|
91
|
+
/**
|
|
92
|
+
* Method for getting message history
|
|
93
|
+
* @returns {ServerMessage[]} message history
|
|
94
|
+
*/
|
|
46
95
|
getMessageHistory(): ServerMessage[];
|
|
96
|
+
/**
|
|
97
|
+
* Method for getting the last gamble response
|
|
98
|
+
* @returns {GambleDataInterface | null} last gamble response
|
|
99
|
+
*/
|
|
47
100
|
getLastGambleResponse(): typeof this.lastGambleResponse;
|
|
48
101
|
}
|
|
@@ -7,6 +7,8 @@ import { logError, logInfo, logWarn } from "../utils";
|
|
|
7
7
|
const overrideMap = new Map();
|
|
8
8
|
/**
|
|
9
9
|
* Class for managing connection to the server via websockets
|
|
10
|
+
* This class handles communication with the server, including fetching initial data, spin data, free spin data, and gamble data.
|
|
11
|
+
* @implements {SubscribableConnectionWrapper}
|
|
10
12
|
*/
|
|
11
13
|
export class ConnectionWrapper {
|
|
12
14
|
webSocketConnection;
|
|
@@ -40,35 +42,43 @@ export class ConnectionWrapper {
|
|
|
40
42
|
constructor() {
|
|
41
43
|
this.webSocketConnection = this.getFreshWsInstance();
|
|
42
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Method for opening a websocket connection
|
|
47
|
+
* @returns {Promise<void>} resolves when the connection is opened
|
|
48
|
+
*/
|
|
43
49
|
async openConnection() {
|
|
44
|
-
return new Promise((resolve) =>
|
|
45
|
-
this.webSocketConnection.addEventListener("open", resolve);
|
|
46
|
-
});
|
|
50
|
+
return new Promise((resolve) => this.webSocketConnection.addEventListener("open", resolve));
|
|
47
51
|
}
|
|
48
52
|
/**
|
|
49
53
|
* Method for initializing communication with the server
|
|
50
54
|
*/
|
|
51
55
|
async initCommunication() {
|
|
52
|
-
this.webSocketConnection.addEventListener("error", (event) => {
|
|
53
|
-
logError(`Error in webSocket connection: ${event}`);
|
|
54
|
-
});
|
|
56
|
+
this.webSocketConnection.addEventListener("error", (event) => logError(`Error in webSocket connection: ${event}`));
|
|
55
57
|
await this.openConnection();
|
|
56
58
|
this.webSocketConnection.addEventListener("close", async (event) => {
|
|
57
59
|
logWarn(`Reiniting communications after connection was closed. Reason: ${event.reason}`);
|
|
58
60
|
this.webSocketConnection = this.getFreshWsInstance();
|
|
59
61
|
await this.initCommunication();
|
|
60
62
|
await this.fetchInitData();
|
|
61
|
-
this.subscribers.forEach((subscriberFn) =>
|
|
62
|
-
subscriberFn();
|
|
63
|
-
});
|
|
64
|
-
RainMan.globals.actionsAfterClosureWebSocket?.();
|
|
63
|
+
this.subscribers.forEach((subscriberFn) => subscriberFn());
|
|
65
64
|
});
|
|
66
65
|
this.webSocketConnection.addEventListener("message", (event) => this.handleMessage(JSON.parse(event.data)));
|
|
67
66
|
logInfo("connection established, listener set");
|
|
68
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Method for subscribing to configuration changes
|
|
70
|
+
* @param {() => void} subscriberFn - function to be called when configuration changes
|
|
71
|
+
* @returns {void}
|
|
72
|
+
* @memberof ConnectionWrapper
|
|
73
|
+
*/
|
|
69
74
|
subscribeForConfigChanges(subscriberFn) {
|
|
70
75
|
this.subscribers.push(subscriberFn);
|
|
71
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Method for fetching initial data from the server
|
|
79
|
+
* @returns {Promise<void>} resolves when the data is fetched
|
|
80
|
+
* @memberof ConnectionWrapper
|
|
81
|
+
*/
|
|
72
82
|
async fetchInitData() {
|
|
73
83
|
this._initData = (await this.fetch({
|
|
74
84
|
action: "init",
|
|
@@ -85,26 +95,40 @@ export class ConnectionWrapper {
|
|
|
85
95
|
vendor_id: RainMan.config.gameInitVendorId
|
|
86
96
|
}));
|
|
87
97
|
RainMan.globals.currency = Currencies[this._initData.currency];
|
|
98
|
+
RainMan.settingsStore.setFreeSpinsPriceTable(this._initData.free_spins_buy_table);
|
|
88
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Method for getting initial data from the server
|
|
102
|
+
* @returns {InitDataInterface} initial data from the server
|
|
103
|
+
*/
|
|
89
104
|
initData() {
|
|
90
105
|
return this._initData;
|
|
91
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Method for fetching free spin data from the server
|
|
109
|
+
* @param {number} roundNumber round number
|
|
110
|
+
* @param {number} quantity quantity of free spins
|
|
111
|
+
* @param {number} price price of free spins
|
|
112
|
+
* @returns {SpinData} spin data
|
|
113
|
+
*/
|
|
92
114
|
async fetchFreeSpinData(roundNumber, quantity, price) {
|
|
93
115
|
if (typeof this.config?.token === "undefined") {
|
|
94
116
|
throw new Error("Token was not defined");
|
|
95
117
|
}
|
|
96
118
|
const data = (await this.fetch({
|
|
97
|
-
action: "buy
|
|
119
|
+
action: "buy",
|
|
120
|
+
operation: "buy-free-spins",
|
|
121
|
+
buy_price: price,
|
|
98
122
|
round_number: roundNumber,
|
|
99
|
-
free_spins_quantity: quantity,
|
|
100
|
-
free_spins_price: price,
|
|
101
123
|
token: this.config.token,
|
|
102
|
-
reference: RainMan.config.gameInitReference
|
|
124
|
+
reference: RainMan.config.gameInitReference,
|
|
125
|
+
bet: RainMan.settingsStore.bet,
|
|
126
|
+
extra_data: {
|
|
127
|
+
free_spins_quantity: quantity
|
|
128
|
+
}
|
|
103
129
|
}));
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
transformFreeSpinData(data) {
|
|
107
|
-
return { ...data, previous_gambles: [], results: [], win_amount_total: 0, wins: {}, extra_data: {} };
|
|
130
|
+
RainMan.settingsStore.setRoundNumber(data.round_number);
|
|
131
|
+
return new SpinData(this.config, data);
|
|
108
132
|
}
|
|
109
133
|
/**
|
|
110
134
|
* Method for fetching spin data from the server
|
|
@@ -126,8 +150,35 @@ export class ConnectionWrapper {
|
|
|
126
150
|
extra_data
|
|
127
151
|
});
|
|
128
152
|
this._messageHistory.push(data);
|
|
153
|
+
this.sendEndOfRoundData(roundNumber);
|
|
129
154
|
return new SpinData(this.config, data);
|
|
130
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Sends end of round data to the server
|
|
158
|
+
* This method is used to notify the server that the round has ended and to update the server state accordingly.
|
|
159
|
+
* @param {number} roundNumber - the round number to send data from
|
|
160
|
+
* @returns {Promise<ServerMessage>} - server message with end of round data
|
|
161
|
+
*/
|
|
162
|
+
async sendEndOfRoundData(roundNumber) {
|
|
163
|
+
if (typeof this.config?.token === "undefined") {
|
|
164
|
+
throw new Error("Token was not defined");
|
|
165
|
+
}
|
|
166
|
+
const data = await this.fetch({
|
|
167
|
+
action: "end",
|
|
168
|
+
round_number: roundNumber,
|
|
169
|
+
reference: RainMan.config.gameInitReference,
|
|
170
|
+
token: this.config.token
|
|
171
|
+
});
|
|
172
|
+
this._messageHistory.push(data);
|
|
173
|
+
return data;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Method for fetching gamble data from the server
|
|
177
|
+
* @param {number} roundNumber round number
|
|
178
|
+
* @param {number} bet bet amount
|
|
179
|
+
* @param {GambleCardColor} choice gamble card color choice
|
|
180
|
+
* @returns {Promise<GambleDataInterface>} gamble data
|
|
181
|
+
*/
|
|
131
182
|
async fetchGambleData(roundNumber, bet, choice) {
|
|
132
183
|
if (typeof this.config?.token === "undefined") {
|
|
133
184
|
throw new Error("Token was not defined");
|
|
@@ -140,8 +191,14 @@ export class ConnectionWrapper {
|
|
|
140
191
|
bet,
|
|
141
192
|
choice
|
|
142
193
|
}));
|
|
194
|
+
this._messageHistory.push(this.lastGambleResponse);
|
|
195
|
+
this.sendEndOfRoundData(roundNumber);
|
|
143
196
|
return this.lastGambleResponse;
|
|
144
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* Method for getting a fresh websocket instance
|
|
200
|
+
* @returns {WebSocket} fresh websocket instance
|
|
201
|
+
*/
|
|
145
202
|
getFreshWsInstance() {
|
|
146
203
|
return new WebSocket(RainMan.config.websocketUrl);
|
|
147
204
|
}
|
|
@@ -171,9 +228,17 @@ export class ConnectionWrapper {
|
|
|
171
228
|
waitForData();
|
|
172
229
|
});
|
|
173
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* Method for getting message history
|
|
233
|
+
* @returns {ServerMessage[]} message history
|
|
234
|
+
*/
|
|
174
235
|
getMessageHistory() {
|
|
175
236
|
return this._messageHistory;
|
|
176
237
|
}
|
|
238
|
+
/**
|
|
239
|
+
* Method for getting the last gamble response
|
|
240
|
+
* @returns {GambleDataInterface | null} last gamble response
|
|
241
|
+
*/
|
|
177
242
|
getLastGambleResponse() {
|
|
178
243
|
return this.lastGambleResponse;
|
|
179
244
|
}
|
|
@@ -18,6 +18,7 @@ export declare class LocalConnectionWrapper implements SubscribableConnectionWra
|
|
|
18
18
|
initData(): InitDataInterface;
|
|
19
19
|
fetchSpinData(): Promise<SpinData>;
|
|
20
20
|
subscribeForConfigChanges(subscriberFn: () => void): void;
|
|
21
|
+
sendEndOfRoundData(roundNumber: number): Promise<ServerMessage>;
|
|
21
22
|
fetchFreeSpinData(roundNumber: number, quantity: number): Promise<SpinData>;
|
|
22
23
|
getMessageHistory(): ServerMessage[];
|
|
23
24
|
}
|
|
@@ -41,6 +41,16 @@ export class LocalConnectionWrapper {
|
|
|
41
41
|
subscribeForConfigChanges(subscriberFn) {
|
|
42
42
|
this.subscribers.push(subscriberFn);
|
|
43
43
|
}
|
|
44
|
+
sendEndOfRoundData(roundNumber) {
|
|
45
|
+
const data = {
|
|
46
|
+
action: "end",
|
|
47
|
+
balance: 1000,
|
|
48
|
+
round_number: roundNumber,
|
|
49
|
+
status: { code: 200, message: "OK" }
|
|
50
|
+
};
|
|
51
|
+
this.subscribers.forEach((subscriber) => subscriber());
|
|
52
|
+
return Promise.resolve(data);
|
|
53
|
+
}
|
|
44
54
|
fetchFreeSpinData(roundNumber, quantity) {
|
|
45
55
|
const data = {
|
|
46
56
|
action: "buy-free-spins",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GambleCardColor, GambleDataInterface, InitDataInterface, SpinDataInterface } from "./serverData";
|
|
1
|
+
import { EndDataInterface, GambleCardColor, GambleDataInterface, InitDataInterface, SpinDataInterface } from "./serverData";
|
|
2
2
|
import { SpinData } from "./spinData";
|
|
3
3
|
export interface ServerCommunication {
|
|
4
4
|
initCommunication(): Promise<void>;
|
|
@@ -6,6 +6,7 @@ export interface ServerCommunication {
|
|
|
6
6
|
initData(): InitDataInterface;
|
|
7
7
|
fetchSpinData(roundNumber: number, bet: number, extraData?: ExtraDataRequest): Promise<SpinData>;
|
|
8
8
|
fetchFreeSpinData(roundNumber: number, amount: number, price: number): Promise<SpinData>;
|
|
9
|
+
sendEndOfRoundData(roundNumber: number): Promise<ServerMessage>;
|
|
9
10
|
getMessageHistory(): ServerMessage[];
|
|
10
11
|
}
|
|
11
12
|
export interface Subscribable {
|
|
@@ -34,17 +35,24 @@ export type SpinServerRequest = BaseServerRequest & {
|
|
|
34
35
|
extra_data: ExtraDataRequest;
|
|
35
36
|
};
|
|
36
37
|
export type BuyFreeSpinServerRequest = BaseServerRequest & {
|
|
37
|
-
action: "buy
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
action: "buy";
|
|
39
|
+
operation: "buy-free-spins";
|
|
40
|
+
bet: number;
|
|
41
|
+
buy_price: number;
|
|
42
|
+
extra_data: {
|
|
43
|
+
free_spins_quantity: number;
|
|
44
|
+
};
|
|
40
45
|
};
|
|
41
46
|
export type GambleServerRequest = BaseServerRequest & {
|
|
42
47
|
action: "gamble";
|
|
43
48
|
bet: number;
|
|
44
49
|
choice: GambleCardColor;
|
|
45
50
|
};
|
|
51
|
+
export type EndServerRequest = BaseServerRequest & {
|
|
52
|
+
action: "end";
|
|
53
|
+
};
|
|
46
54
|
export interface ExtraDataRequest {
|
|
47
55
|
}
|
|
48
|
-
export type ServerRequest = InitServerRequest | SpinServerRequest | BuyFreeSpinServerRequest | GambleServerRequest;
|
|
49
|
-
export type ServerMessage = InitDataInterface | SpinDataInterface | GambleDataInterface;
|
|
56
|
+
export type ServerRequest = InitServerRequest | SpinServerRequest | BuyFreeSpinServerRequest | GambleServerRequest | EndServerRequest;
|
|
57
|
+
export type ServerMessage = InitDataInterface | SpinDataInterface | GambleDataInterface | EndDataInterface;
|
|
50
58
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PaytableTypes } from "../constants";
|
|
2
|
+
import { Nullable } from "../utils";
|
|
2
3
|
import { Point, RawTransformationDetails } from "./transformation";
|
|
3
4
|
export interface InitDataInterface {
|
|
4
5
|
action: string;
|
|
@@ -14,10 +15,21 @@ export interface InitDataInterface {
|
|
|
14
15
|
wins_names: Array<string>;
|
|
15
16
|
transformations_names: Array<string>;
|
|
16
17
|
transformations_types: Array<number>;
|
|
18
|
+
free_spins_buy_table?: Record<number, number>;
|
|
19
|
+
free_spins_prize_table?: Record<number, number>;
|
|
17
20
|
paytable: PayTableInterface;
|
|
18
21
|
extra_data: InitExtraData;
|
|
19
22
|
jackpot_wins?: JackpotWins;
|
|
20
23
|
}
|
|
24
|
+
export interface EndDataInterface {
|
|
25
|
+
action: "end";
|
|
26
|
+
balance: number;
|
|
27
|
+
round_number: number;
|
|
28
|
+
status: {
|
|
29
|
+
code: number;
|
|
30
|
+
message: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
21
33
|
export type JackpotType = "jackpot-mini" | "jackpot-minor" | "jackpot-major" | "jackpot-grand";
|
|
22
34
|
export type JackpotWins = {
|
|
23
35
|
"jackpot-grand": {
|
|
@@ -76,9 +88,10 @@ export interface SpinDataInterface {
|
|
|
76
88
|
symbols_on_reels: number[][];
|
|
77
89
|
win_amount_total: number;
|
|
78
90
|
wins: Record<string, RawWin>;
|
|
79
|
-
extra_data: ExtraData
|
|
91
|
+
extra_data: Nullable<ExtraData>;
|
|
80
92
|
}
|
|
81
93
|
export interface ExtraData {
|
|
94
|
+
available_free_spins?: number;
|
|
82
95
|
}
|
|
83
96
|
export interface GambleDataInterface {
|
|
84
97
|
action: "gamble";
|
|
@@ -90,7 +103,7 @@ export interface GambleDataInterface {
|
|
|
90
103
|
winning_card: GambleCard;
|
|
91
104
|
}
|
|
92
105
|
export interface FreeSpinDataInterface {
|
|
93
|
-
action: "buy
|
|
106
|
+
action: "buy";
|
|
94
107
|
available_free_spins: number;
|
|
95
108
|
balance: number;
|
|
96
109
|
round_number: number;
|
|
@@ -6,8 +6,8 @@ export class SpinData {
|
|
|
6
6
|
this.rawData = data;
|
|
7
7
|
this.config = config;
|
|
8
8
|
this.balance = data.balance;
|
|
9
|
-
if (data.action !== "spin" && data.action !== "buy
|
|
10
|
-
throw new Error(`Invalid type "${data.action}" provided, "spin" or "buy
|
|
9
|
+
if (data.action !== "spin" && data.action !== "buy") {
|
|
10
|
+
throw new Error(`Invalid type "${data.action}" provided, "spin" or "buy" expected`);
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
getRawData() {
|
package/dist/constants/wins.js
CHANGED
|
@@ -86,12 +86,17 @@ export declare abstract class AbstractController<T> {
|
|
|
86
86
|
* Function for disabling speed button
|
|
87
87
|
* @param {boolean} shouldBeDisabled flag to disable speed button
|
|
88
88
|
*/
|
|
89
|
-
|
|
89
|
+
disableSpeedButton(shouldBeDisabled: boolean): void;
|
|
90
90
|
/**
|
|
91
91
|
* Function for disabling information buttons
|
|
92
92
|
* @param {boolean} shouldBeDisabled flag to disable information buttons
|
|
93
93
|
*/
|
|
94
94
|
disableInformationButtons(shouldBeDisabled: boolean): void;
|
|
95
|
+
/**
|
|
96
|
+
* Function for disabling refresh buttons
|
|
97
|
+
* @param {boolean} shouldBeDisabled flag to disable refresh buttons
|
|
98
|
+
*/
|
|
99
|
+
disableRefreshButton(shouldBeDisabled: boolean): void;
|
|
95
100
|
/**
|
|
96
101
|
* Function for handling disabling buttons
|
|
97
102
|
* @param {boolean} disabled flag to disable buttons
|
|
@@ -177,6 +177,13 @@ export class AbstractController {
|
|
|
177
177
|
];
|
|
178
178
|
buttonsToChange.forEach((button) => button.flipDisabledFlag(shouldBeDisabled));
|
|
179
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Function for disabling refresh buttons
|
|
182
|
+
* @param {boolean} shouldBeDisabled flag to disable refresh buttons
|
|
183
|
+
*/
|
|
184
|
+
disableRefreshButton(shouldBeDisabled) {
|
|
185
|
+
RainMan.componentRegistry.get(BUTTONS.refresh).flipDisabledFlag(shouldBeDisabled);
|
|
186
|
+
}
|
|
180
187
|
/**
|
|
181
188
|
* Function for handling disabling buttons
|
|
182
189
|
* @param {boolean} disabled flag to disable buttons
|
|
@@ -531,8 +538,7 @@ export class AbstractController {
|
|
|
531
538
|
if (RainMan.settingsStore.isFreeSpinsBought) {
|
|
532
539
|
this.uiController.totalNumberOfFreeSpins += this.getBoughtNumberOfFreeSpins();
|
|
533
540
|
RainMan.componentRegistry.getIfExists(FreeSpinButton.registryName)?.setInteractivity(false);
|
|
534
|
-
|
|
535
|
-
this.spin().then(() => RainMan.settingsStore.setIsFreeSpinBought(false));
|
|
541
|
+
RainMan.settingsStore.setIsFreeSpinBought(false);
|
|
536
542
|
return;
|
|
537
543
|
}
|
|
538
544
|
if (RainMan.settingsStore.isAutoplayEnabled && !this.spinning) {
|
|
@@ -560,7 +566,7 @@ export class AbstractController {
|
|
|
560
566
|
* @returns {number} - number of free spins bought
|
|
561
567
|
*/
|
|
562
568
|
getBoughtNumberOfFreeSpins() {
|
|
563
|
-
return RainMan.settingsStore.buyFreeSpinsData?.getRawData().available_free_spins || 0;
|
|
569
|
+
return RainMan.settingsStore.buyFreeSpinsData?.getRawData().extra_data.available_free_spins || 0;
|
|
564
570
|
}
|
|
565
571
|
/**
|
|
566
572
|
* Function for autoplay spin
|
|
@@ -619,8 +625,7 @@ export class AbstractController {
|
|
|
619
625
|
async fetchAndPrepareSpinData() {
|
|
620
626
|
this.changeGamePhase(gamePhases.DATA_FETCH);
|
|
621
627
|
this.handleDisablingButtons(true);
|
|
622
|
-
const data = RainMan.settingsStore.
|
|
623
|
-
(await this.connection.fetchSpinData(this.roundNumber, RainMan.settingsStore.bet, this.getExtraData()));
|
|
628
|
+
const data = await this.connection.fetchSpinData(this.roundNumber, RainMan.settingsStore.bet, this.getExtraData());
|
|
624
629
|
debugSpinData(data);
|
|
625
630
|
const spinLogic = this.spinLogicFactory(data.getRawData(), this.config);
|
|
626
631
|
this._lastWinAmount = this.mysteryWinSymbol ? spinLogic.winTotalAmountWithoutMystery : spinLogic.winTotalAmount;
|
|
@@ -633,6 +638,8 @@ export class AbstractController {
|
|
|
633
638
|
}
|
|
634
639
|
this.changeGamePhase(gamePhases.CONFIGURING_SPIN);
|
|
635
640
|
this.uiController.currentBalance = data.balance;
|
|
641
|
+
this.roundNumber = data.getRawData().round_number;
|
|
642
|
+
RainMan.settingsStore.setRoundNumber(data.getRawData().round_number);
|
|
636
643
|
return {
|
|
637
644
|
data,
|
|
638
645
|
spinLogic
|
|
@@ -704,8 +711,9 @@ export class AbstractController {
|
|
|
704
711
|
case gamePhases.IDLE:
|
|
705
712
|
break;
|
|
706
713
|
case gamePhases.HANDLING_ACTIONS:
|
|
707
|
-
if (!this.canSkipActions())
|
|
714
|
+
if (!this.canSkipActions()) {
|
|
708
715
|
return;
|
|
716
|
+
}
|
|
709
717
|
this.changeGamePhase(gamePhases.STOPPING_HANDLING_ACTIONS);
|
|
710
718
|
if (this.currentlyPlayedAction !== undefined) {
|
|
711
719
|
this.stopPlayingSymbolsStreak();
|
|
@@ -736,10 +744,12 @@ export class AbstractController {
|
|
|
736
744
|
const availableFreeSpins = spinLogic.availableFreeSpins;
|
|
737
745
|
const availableFreeSpinsIncreased = availableFreeSpins > RainMan.settingsStore.howManyFreeSpinsLeft;
|
|
738
746
|
this.hideFreeSpinsMessageBox = availableFreeSpinsIncreased;
|
|
739
|
-
if (!availableFreeSpinsIncreased)
|
|
747
|
+
if (!availableFreeSpinsIncreased) {
|
|
740
748
|
this.uiController.updateShownFreeSpinAmount(availableFreeSpins);
|
|
741
|
-
|
|
749
|
+
}
|
|
750
|
+
else {
|
|
742
751
|
this.uiController.updateShownFreeSpinAmount(RainMan.settingsStore.howManyFreeSpinsLeft - 1);
|
|
752
|
+
}
|
|
743
753
|
if (availableFreeSpins > 0) {
|
|
744
754
|
RainMan.settingsStore.setTotalNumberOfFreeSpins(availableFreeSpins + RainMan.settingsStore.freeSpinNumberBought);
|
|
745
755
|
}
|
|
@@ -764,8 +774,9 @@ export class AbstractController {
|
|
|
764
774
|
this.uiController.limitWinAmount(spinLogic.winTotalAmount);
|
|
765
775
|
}
|
|
766
776
|
this.composeWinActionsQueue(spinLogic);
|
|
767
|
-
if (spinLogic.winTotalAmount === 0 && this.invokeFreeSpinPlateAfterWin)
|
|
777
|
+
if (spinLogic.winTotalAmount === 0 && this.invokeFreeSpinPlateAfterWin) {
|
|
768
778
|
this.uiController.messageBox.hideCurrentWinText();
|
|
779
|
+
}
|
|
769
780
|
RainMan.settingsStore.setIsPlayingAnyAction(true);
|
|
770
781
|
await this.playWinActionQueue();
|
|
771
782
|
await this.countBigWin();
|
|
@@ -788,7 +799,7 @@ export class AbstractController {
|
|
|
788
799
|
RainMan.settingsStore.resetIsLastFreeSpin();
|
|
789
800
|
this.mainContainer.destroyBigWin();
|
|
790
801
|
this.columnsContainer.resetPlayedSounds();
|
|
791
|
-
if (this.invokeFreeSpinPlateAfterWin
|
|
802
|
+
if (this.invokeFreeSpinPlateAfterWin) {
|
|
792
803
|
this.uiController.messageBox.hideCurrentWinText();
|
|
793
804
|
this.mainContainer.messageBox.hideFreeSpinText();
|
|
794
805
|
hideLayerIfPresent();
|
|
@@ -804,8 +815,9 @@ export class AbstractController {
|
|
|
804
815
|
this.uiController.triggerUiElementsUpdate();
|
|
805
816
|
this.uiController.messageBox.showFreeSpinText();
|
|
806
817
|
}
|
|
807
|
-
if (availableFreeSpinsIncreased)
|
|
818
|
+
if (availableFreeSpinsIncreased) {
|
|
808
819
|
this.uiController.updateShownFreeSpinAmount(availableFreeSpins);
|
|
820
|
+
}
|
|
809
821
|
if (this.invokeFreeSpinSummaryPlateAfterWin && !this.skipFreeSpinSummary) {
|
|
810
822
|
hideLayerIfPresent();
|
|
811
823
|
await this.handleFreeSpinSummaryPlateInvocation();
|
|
@@ -17,6 +17,7 @@ export class UiController {
|
|
|
17
17
|
constructor(config) {
|
|
18
18
|
this.config = config;
|
|
19
19
|
this._messageBox = RainMan.componentRegistry.get(MessageBox.registryName);
|
|
20
|
+
RainMan.globals.updateFreeSpinShown = this.updateShownFreeSpinAmount.bind(this);
|
|
20
21
|
}
|
|
21
22
|
get messageBox() {
|
|
22
23
|
return this._messageBox;
|
|
@@ -19,7 +19,7 @@ export class AbstractLoadingContainer extends Container {
|
|
|
19
19
|
this.loaderContainer = new SpriteLoadingContainer("./assets/images/materials/texture.png", {
|
|
20
20
|
fill: ["#FCD784", "#AE6119", "#FEE391"], // gradient
|
|
21
21
|
stroke: "#4a1850",
|
|
22
|
-
dropShadowColor: "#000000"
|
|
22
|
+
dropShadowColor: "#000000"
|
|
23
23
|
});
|
|
24
24
|
RainMan.app.renderer.on("resize", () => this.resize()); // arrow fn to pass this context to resize
|
|
25
25
|
}
|
|
@@ -20,7 +20,7 @@ export declare class SettingsStore {
|
|
|
20
20
|
totalNumberOfFreeSpins: number;
|
|
21
21
|
isFreeSpinsBought: boolean;
|
|
22
22
|
freeSpinNumberBought: number;
|
|
23
|
-
buyFreeSpinsData: SpinData
|
|
23
|
+
buyFreeSpinsData: Nullable<SpinData>;
|
|
24
24
|
isAutoplayEnabled: boolean;
|
|
25
25
|
isLastFreeSpin: boolean;
|
|
26
26
|
infinitySpinsEnabled: boolean;
|
|
@@ -38,6 +38,7 @@ export declare class SettingsStore {
|
|
|
38
38
|
balancedDecreased: number;
|
|
39
39
|
howManyFreeSpinsLeft: number;
|
|
40
40
|
howManyAutoSpinsLeft: number;
|
|
41
|
+
freeSpinBuyTable: Record<number, number>;
|
|
41
42
|
volumeLevel: number;
|
|
42
43
|
popupPaytablePosition?: Point;
|
|
43
44
|
popupPaytableData?: PaytableData[];
|
|
@@ -47,6 +48,7 @@ export declare class SettingsStore {
|
|
|
47
48
|
popupPaytableRepositionCallback?: () => void;
|
|
48
49
|
updateVolumeButtonTexture?: () => void;
|
|
49
50
|
handleModalInvocation?: (layerId: string) => void;
|
|
51
|
+
handleInvokeFreeSpinPlate?: (freeSpinAmount: number, isAdditionalFreeSpin: boolean) => Promise<void>;
|
|
50
52
|
increaseBet?: () => void;
|
|
51
53
|
decreaseBet?: () => void;
|
|
52
54
|
enableButtons?: () => void;
|
|
@@ -61,6 +63,7 @@ export declare class SettingsStore {
|
|
|
61
63
|
changeBetChangeDisabled(flag: boolean): void;
|
|
62
64
|
isIosScrollerInteractive(flag: boolean): void;
|
|
63
65
|
resetCumulativeWinAmount(): void;
|
|
66
|
+
setFreeSpinsPriceTable(freeSpinsPriceTable: Record<number, number>): void;
|
|
64
67
|
/**
|
|
65
68
|
* Sets bet value
|
|
66
69
|
* @param {number} newBet updated bet value
|
|
@@ -113,8 +116,9 @@ export declare class SettingsStore {
|
|
|
113
116
|
resetIsLastFreeSpin(): void;
|
|
114
117
|
setTotalNumberOfFreeSpins(newValue: number): void;
|
|
115
118
|
resetTotalNumberOfFreeSpins(): void;
|
|
116
|
-
setIsFreeSpinBought(newValue: boolean, data?: SpinData
|
|
119
|
+
setIsFreeSpinBought(newValue: boolean, data?: Nullable<SpinData>): void;
|
|
117
120
|
setFreeSpinNumberBought(newValue: number): void;
|
|
121
|
+
setHandleInvokeFreeSpinPlate(callback: (freeSpinAmount: number, isAdditionalFreeSpin: boolean) => Promise<void>): void;
|
|
118
122
|
resetFreeSpinNumberBought(): void;
|
|
119
123
|
setRoundNumber(newValue: number): void;
|
|
120
124
|
setModalsAvailability(flag: boolean): void;
|
|
@@ -41,6 +41,7 @@ export class SettingsStore {
|
|
|
41
41
|
balancedDecreased = 0;
|
|
42
42
|
howManyFreeSpinsLeft = 0;
|
|
43
43
|
howManyAutoSpinsLeft = INITIAL_AUTO_SPIN_COUNT;
|
|
44
|
+
freeSpinBuyTable = {};
|
|
44
45
|
volumeLevel = getFromLocalStorage(LOCAL_STORAGE.volumeLevel, 100);
|
|
45
46
|
popupPaytablePosition;
|
|
46
47
|
popupPaytableData;
|
|
@@ -50,6 +51,7 @@ export class SettingsStore {
|
|
|
50
51
|
popupPaytableRepositionCallback;
|
|
51
52
|
updateVolumeButtonTexture;
|
|
52
53
|
handleModalInvocation;
|
|
54
|
+
handleInvokeFreeSpinPlate;
|
|
53
55
|
increaseBet;
|
|
54
56
|
decreaseBet;
|
|
55
57
|
enableButtons;
|
|
@@ -129,6 +131,9 @@ export class SettingsStore {
|
|
|
129
131
|
resetCumulativeWinAmount() {
|
|
130
132
|
this.cumulativeWinAmount = 0;
|
|
131
133
|
}
|
|
134
|
+
setFreeSpinsPriceTable(freeSpinsPriceTable) {
|
|
135
|
+
this.freeSpinBuyTable = freeSpinsPriceTable;
|
|
136
|
+
}
|
|
132
137
|
/**
|
|
133
138
|
* Sets bet value
|
|
134
139
|
* @param {number} newBet updated bet value
|
|
@@ -333,6 +338,11 @@ export class SettingsStore {
|
|
|
333
338
|
}
|
|
334
339
|
setFreeSpinNumberBought(newValue) {
|
|
335
340
|
this.freeSpinNumberBought = newValue;
|
|
341
|
+
this.howManyFreeSpinsLeft = newValue;
|
|
342
|
+
this.totalNumberOfFreeSpins = newValue;
|
|
343
|
+
}
|
|
344
|
+
setHandleInvokeFreeSpinPlate(callback) {
|
|
345
|
+
this.handleInvokeFreeSpinPlate = callback;
|
|
336
346
|
}
|
|
337
347
|
resetFreeSpinNumberBought() {
|
|
338
348
|
this.freeSpinNumberBought = 0;
|
|
@@ -8,7 +8,7 @@ export const scaleToParent = (width, height, parentWidth, parentHeight) => {
|
|
|
8
8
|
// some dependent size. image, figure etc.
|
|
9
9
|
target: new Size(width, height),
|
|
10
10
|
// policy is optional. default is null
|
|
11
|
-
policy: POLICY.ShowAll
|
|
11
|
+
policy: POLICY.ShowAll // null | ExactFit | NoBorder | FullHeight | FullWidth | ShowAll
|
|
12
12
|
});
|
|
13
13
|
};
|
|
14
14
|
const getMobileScreenRatio = () => {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export type Nullable<T> = T | null;
|
|
2
2
|
export type PlayableAction = () => Promise<void> | Promise<void[]>;
|
|
3
|
-
export type VoidPromiseResolver = (value: void | PromiseLike<void>) => void;
|
|
4
3
|
export type DeviceOrientation = "pc" | "mobile-portrait" | "mobile-landscape";
|
|
5
4
|
export type DeepPartial<T> = T extends object ? {
|
|
6
5
|
[P in keyof T]?: DeepPartial<T[P]>;
|
|
7
6
|
} : T;
|
|
7
|
+
export type VoidFunction = () => void;
|
|
8
|
+
export type PromiseResolverType<T = void> = (value: T | PromiseLike<T>) => void;
|
package/package.json
CHANGED