pixi-rainman-game-engine 0.2.18 → 0.2.19

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.
@@ -41,6 +41,7 @@ export const defaultAppConfig = {
41
41
  mysteryWinMinimumTime: 2000,
42
42
  bigWinMinimumTime: 2000,
43
43
  bigWinPhaseTimeout: 2800,
44
+ mysteryPhaseTimeout: 2800,
44
45
  bonusWinPhaseTimeout: 2800,
45
46
  bonusWinMinimumTime: 2000,
46
47
  superBonusWinMinimumTime: 2000,
@@ -48,6 +48,7 @@ export type OptionalAppConfig = {
48
48
  mysteryWinMinimumTime: number;
49
49
  bigWinMinimumTime: number;
50
50
  bigWinPhaseTimeout: number;
51
+ mysteryPhaseTimeout: number;
51
52
  bonusWinPhaseTimeout: number;
52
53
  bonusWinMinimumTime: number;
53
54
  superBonusWinPhaseTimeout: number;
@@ -4,4 +4,6 @@ export type CloseModalButtonProps = {
4
4
  layerId: string;
5
5
  afterClose?: () => void;
6
6
  };
7
- export declare const CloseModalButton: ({ layerId, afterClose }: CloseModalButtonProps) => JSX.Element;
7
+ export declare const CloseModalButton: (({ layerId, afterClose }: CloseModalButtonProps) => JSX.Element) & {
8
+ displayName: string;
9
+ };
@@ -1,17 +1,23 @@
1
1
  import "./closeModalButton.css";
2
+ import { observer } from "mobx-react-lite";
2
3
  import React from "react";
3
4
  import { UI_ITEMS } from "../../../utils";
4
5
  import { useStores } from "../../hooks";
5
- export const CloseModalButton = ({ layerId, afterClose }) => {
6
+ export const CloseModalButton = observer(({ layerId, afterClose }) => {
6
7
  const { settingStore } = useStores();
8
+ const { isFreeSpinsPlayEnabled, isFreeSpinsBought, betChangeDisabled } = settingStore;
9
+ const isBetDisabled = isFreeSpinsPlayEnabled || betChangeDisabled || isFreeSpinsBought;
7
10
  const onClose = () => {
8
11
  settingStore.handleModalInvocation?.(layerId);
9
12
  if (layerId === UI_ITEMS.speedSettings) {
10
13
  settingStore.setSpeedPopupVisibility?.("none");
11
14
  }
15
+ if (isBetDisabled) {
16
+ settingStore.enableButtons?.();
17
+ }
12
18
  afterClose?.();
13
19
  };
14
20
  return (<button className="close-modal-button" onClick={onClose}>
15
21
  x
16
22
  </button>);
17
- };
23
+ });
@@ -44,7 +44,12 @@ export class ButtonsEventManager {
44
44
  * @returns {() => void} function for enabling/disabling buttons
45
45
  */
46
46
  setButtonAvailability = (makeDisabled) => () => {
47
- const buttonsToDisable = [SpeedControlButton.registryName, BUTTONS.neg, BUTTONS.plus];
47
+ const isDisabled = RainMan.settingsStore.isFreeSpinsPlayEnabled ||
48
+ RainMan.settingsStore.isFreeSpinsBought ||
49
+ RainMan.settingsStore.betChangeDisabled;
50
+ const buttonsToDisable = isDisabled
51
+ ? [SpeedControlButton.registryName]
52
+ : [SpeedControlButton.registryName, BUTTONS.neg, BUTTONS.plus];
48
53
  buttonsToDisable.forEach((buttonRegistryName) => RainMan.componentRegistry.get(buttonRegistryName).flipDisabledFlag(makeDisabled));
49
54
  RainMan.componentRegistry.get(VolumeButton.registryName).changeTextureDependOnVolume();
50
55
  };
@@ -53,6 +58,7 @@ export class ButtonsEventManager {
53
58
  constructor() {
54
59
  RainMan.settingsStore.handleModalInvocation = this.handleModalInvocation.bind(this);
55
60
  RainMan.settingsStore.setSpeedPopupVisibility = this.setSpeedPopupVisibility.bind(this);
61
+ RainMan.settingsStore.enableButtons = this.enableButtons.bind(this);
56
62
  }
57
63
  /**
58
64
  * Method for initializing events in Settings UI
@@ -3,7 +3,7 @@ import { ButtonsEventManager } from "../../application";
3
3
  import { AbstractController } from "../../controllers";
4
4
  import { RainMan } from "../../Rainman";
5
5
  import { Nullable } from "../../utils";
6
- import { UpdatableSpineContainer } from "../../winComponents";
6
+ import { MysteryWinContainer, UpdatableSpineContainer } from "../../winComponents";
7
7
  import { AbstractFreeSpinContainer } from "../AbstractFreeSpinContainer";
8
8
  import { LeftButtons, LeftButtonsLandscape, LeftButtonsMobile, MiddleButtons, RightButtons, RightButtonsLandscape, RightButtonsMobile } from "../buttons";
9
9
  import { FreeSpinButton, Logo, ResponsiveContainer } from "../common";
@@ -33,7 +33,7 @@ export declare abstract class AbstractMainContainer extends Container {
33
33
  static readonly registryName = "mainContainer";
34
34
  messageBox: MessageBox;
35
35
  protected bigWinContainer: Nullable<UpdatableSpineContainer>;
36
- protected mysteryWinContainer: Nullable<UpdatableSpineContainer>;
36
+ protected mysteryWinContainer: Nullable<UpdatableSpineContainer> | MysteryWinContainer;
37
37
  protected bonusWinContainer: Nullable<UpdatableSpineContainer>;
38
38
  protected superBonusWinContainer: Nullable<UpdatableSpineContainer>;
39
39
  protected overlay: Nullable<Graphics>;
@@ -88,7 +88,7 @@ export declare abstract class AbstractMainContainer extends Container {
88
88
  * Function for creating mystery win container
89
89
  * @returns {Nullable<UpdatableSpineContainer>} The container for the mystery win animation, or null.
90
90
  */
91
- protected createMysteryWinContainer(): Nullable<UpdatableSpineContainer>;
91
+ protected createMysteryWinContainer(): Nullable<UpdatableSpineContainer> | MysteryWinContainer;
92
92
  /**
93
93
  * Function for specifying the container for the free spin summary
94
94
  * This needs to be implemented in each game
@@ -14,7 +14,7 @@ import { UpdatableMode } from "./types";
14
14
  export declare abstract class UpdatableValueComponent extends Container implements SpeedAdapterInterface<number> {
15
15
  private mode;
16
16
  private updateCallback?;
17
- private updatableValue;
17
+ protected updatableValue: number;
18
18
  protected finalValue: number;
19
19
  protected readonly baseTextComponent: Text;
20
20
  protected readonly valueTextComponent: Text;
@@ -922,8 +922,8 @@ export class AbstractController {
922
922
  this.mainContainer.destroyMysteryWin();
923
923
  this.resolveMysteryWin();
924
924
  this.resolveMysteryWin = undefined;
925
- }, RainMan.config.durationOfActions.bigWinPhaseTimeout /
926
- (RainMan.settingsStore.currentSpeed === SPEED_LEVELS.fast ? 3 : 1));
925
+ }, RainMan.config.durationOfActions.mysteryPhaseTimeout /
926
+ (RainMan.settingsStore.currentSpeed === SPEED_LEVELS.fast ? 2 : 1));
927
927
  });
928
928
  }
929
929
  /**
@@ -47,6 +47,7 @@ export declare class SettingsStore {
47
47
  handleModalInvocation?: (layerId: string) => void;
48
48
  increaseBet?: () => void;
49
49
  decreaseBet?: () => void;
50
+ enableButtons?: () => void;
50
51
  private readonly initialAutoplaySettingsState;
51
52
  private modalsAvailable;
52
53
  private paytableMap;
@@ -53,6 +53,7 @@ export class SettingsStore {
53
53
  handleModalInvocation;
54
54
  increaseBet;
55
55
  decreaseBet;
56
+ enableButtons;
56
57
  initialAutoplaySettingsState = {
57
58
  infinitySpinsEnabled: false,
58
59
  onAnyWin: false,
@@ -0,0 +1,32 @@
1
+ import { Container, ITextStyle } from "pixi.js";
2
+ import { Spine } from "pixi-spine";
3
+ import { COMPONENTS } from "../components";
4
+ import { AnimableParticlesEmitter } from "./AnimableParticlesEmitter";
5
+ import { PositioningFrame } from "./PositioningFrame";
6
+ /**
7
+ * Class for Mystery win. Every animation must be named "mystery_big" in spine.
8
+ * @class MysteryWinContainer
9
+ * @augments {Container}
10
+ */
11
+ export declare class MysteryWinContainer extends Container {
12
+ plateSpineSrc: string;
13
+ animationSpineSrc: string;
14
+ plateSpineBgSrc: string;
15
+ protected frame: PositioningFrame;
16
+ spineScale: number;
17
+ private emitters;
18
+ static readonly name = "mysteryWinContainer";
19
+ plateSpine: Spine;
20
+ animationSpine: Spine;
21
+ plateSpineBg: Spine;
22
+ textComponent: Container;
23
+ constructor(componentType: typeof COMPONENTS.mysteryWin | typeof COMPONENTS.bigWin, plateSpineSrc: string, animationSpineSrc: string, plateSpineBgSrc: string, frame: PositioningFrame, text: string, spineScale?: number, emitters?: AnimableParticlesEmitter[], textTexture?: string, textStyle?: ITextStyle, isBgAnimated?: boolean);
24
+ setScale(scale: number): void;
25
+ fadeInTextComponent(duration?: number, delay?: number): void;
26
+ positionTextElement(x?: number, y?: number, scale?: number): void;
27
+ positionAnimationElement(x?: number, y?: number, scale?: number): void;
28
+ adjustToScreen(): void;
29
+ resize(): void;
30
+ destroyAnimations(): Promise<void>;
31
+ private animateBox;
32
+ }
@@ -0,0 +1,134 @@
1
+ import * as TWEEN from "@tweenjs/tween.js";
2
+ import { Container, TextStyle, Ticker } from "pixi.js";
3
+ import { Spine } from "pixi-spine";
4
+ import { COMPONENTS } from "../components";
5
+ import { UXLayer } from "../layers";
6
+ import { RainMan } from "../Rainman";
7
+ import { getSpineData, globalMinRatio } from "../utils";
8
+ import { TexturedText } from "./TexturedText";
9
+ /**
10
+ * Class for Mystery win. Every animation must be named "mystery_big" in spine.
11
+ * @class MysteryWinContainer
12
+ * @augments {Container}
13
+ */
14
+ export class MysteryWinContainer extends Container {
15
+ plateSpineSrc;
16
+ animationSpineSrc;
17
+ plateSpineBgSrc;
18
+ frame;
19
+ spineScale;
20
+ emitters;
21
+ static name = "mysteryWinContainer";
22
+ plateSpine;
23
+ animationSpine;
24
+ plateSpineBg;
25
+ textComponent;
26
+ constructor(componentType, plateSpineSrc, animationSpineSrc, plateSpineBgSrc, frame, text, spineScale = 0.9, emitters = [], textTexture, textStyle, isBgAnimated) {
27
+ super();
28
+ this.plateSpineSrc = plateSpineSrc;
29
+ this.animationSpineSrc = animationSpineSrc;
30
+ this.plateSpineBgSrc = plateSpineBgSrc;
31
+ this.frame = frame;
32
+ this.spineScale = spineScale;
33
+ this.emitters = emitters;
34
+ this.textComponent = new TexturedText(COMPONENTS.mysteryWin, text, new TextStyle({
35
+ fontFamily: RainMan.config.fontFace,
36
+ fill: "#ffffff",
37
+ align: "center",
38
+ fontWeight: "bold",
39
+ ...textStyle,
40
+ }), textTexture);
41
+ this.plateSpine = new Spine(getSpineData(plateSpineSrc));
42
+ this.animationSpine = new Spine(getSpineData(animationSpineSrc));
43
+ this.plateSpineBg = new Spine(getSpineData(plateSpineBgSrc));
44
+ this.sortableChildren = true;
45
+ this.plateSpineBg.zIndex = 1;
46
+ this.animationSpine.zIndex = 2;
47
+ this.textComponent.zIndex = 2;
48
+ this.plateSpine.zIndex = 3;
49
+ this.parentLayer = UXLayer;
50
+ this.plateSpine.state.setAnimation(0, "mystery_big", false);
51
+ this.animationSpine.state.setAnimation(0, "mystery_big", true);
52
+ if (isBgAnimated) {
53
+ this.plateSpineBg.state.setAnimation(0, "mystery_big", false);
54
+ }
55
+ this.addChild(this.frame);
56
+ this.addChild(this.plateSpineBg);
57
+ this.emitters.forEach((emitter) => {
58
+ this.addChild(emitter);
59
+ emitter.zIndex = 0;
60
+ });
61
+ this.addChild(this.animationSpine);
62
+ this.addChild(this.textComponent);
63
+ this.addChild(this.plateSpine);
64
+ this.resize();
65
+ Ticker.shared.add(this.animateBox, this);
66
+ }
67
+ setScale(scale) {
68
+ this.plateSpine.scale.set(scale);
69
+ this.animationSpine.scale.set(scale);
70
+ this.plateSpineBg.scale.set(scale);
71
+ this.textComponent.scale.set(scale);
72
+ }
73
+ fadeInTextComponent(duration = 1000, delay = 0) {
74
+ this.textComponent.alpha = 0;
75
+ new TWEEN.Tween({ alpha: 0 })
76
+ .to({ alpha: 1 }, duration)
77
+ .delay(delay)
78
+ .onUpdate((obj) => {
79
+ this.textComponent.alpha = obj.alpha;
80
+ })
81
+ .start();
82
+ }
83
+ positionTextElement(x, y, scale) {
84
+ if (x) {
85
+ this.textComponent.x = this.textComponent.x - x;
86
+ this.plateSpineBg.x = this.plateSpineBg.x - x;
87
+ this.plateSpine.x = this.plateSpine.x - x;
88
+ }
89
+ if (y) {
90
+ this.textComponent.y = this.textComponent.y - y;
91
+ this.plateSpineBg.y = this.plateSpineBg.y - y;
92
+ this.plateSpine.y = this.plateSpine.y - y;
93
+ }
94
+ if (scale) {
95
+ this.textComponent.scale.set(scale);
96
+ this.plateSpineBg.scale.set(scale);
97
+ this.plateSpine.scale.set(scale);
98
+ }
99
+ }
100
+ positionAnimationElement(x, y, scale) {
101
+ if (x) {
102
+ this.animationSpine.x = x;
103
+ }
104
+ if (y) {
105
+ this.animationSpine.y = y;
106
+ }
107
+ if (scale) {
108
+ this.animationSpine.scale.set(scale);
109
+ }
110
+ }
111
+ adjustToScreen() { }
112
+ resize() {
113
+ this.setScale(this.spineScale * globalMinRatio());
114
+ const { width, height } = RainMan.app.screen;
115
+ this.x = width / 2;
116
+ this.y = height / 2;
117
+ this.plateSpine.y = this.animationSpine.skeleton.data.height / 2;
118
+ this.plateSpineBg.x = this.plateSpine.x;
119
+ this.plateSpineBg.y = this.plateSpine.y;
120
+ this.textComponent.x = this.plateSpineBg.x;
121
+ this.textComponent.y = this.plateSpineBg.y;
122
+ this.frame.resize(width, height);
123
+ this.adjustToScreen();
124
+ }
125
+ async destroyAnimations() {
126
+ this.emitters.forEach((emitter) => emitter.cleanAnimation());
127
+ Ticker.shared.remove(this.animateBox, this);
128
+ RainMan.componentRegistry.removeMany([this, this.textComponent]);
129
+ }
130
+ animateBox() {
131
+ this.emitters.forEach((emitter) => emitter.animate());
132
+ TWEEN.update();
133
+ }
134
+ }
@@ -0,0 +1,8 @@
1
+ import { ITextStyle, Sprite } from "pixi.js";
2
+ import { UpdatableValueComponent } from "../components";
3
+ export declare class TexturedText extends UpdatableValueComponent {
4
+ static registryName: string;
5
+ textureSprite?: Sprite;
6
+ constructor(registryName: string, text: string, textStyle: ITextStyle, textureName?: string);
7
+ randomizeSet(value: number, _possibleValues: number[]): void;
8
+ }
@@ -0,0 +1,26 @@
1
+ import { TilingSprite } from "pixi.js";
2
+ import { UpdatableValueComponent } from "../components";
3
+ import { MoneyText } from "../Money";
4
+ import { RainMan } from "../Rainman";
5
+ import { getTexture } from "../utils";
6
+ export class TexturedText extends UpdatableValueComponent {
7
+ static registryName = "mysteryWinText";
8
+ textureSprite;
9
+ constructor(registryName, text, textStyle, textureName) {
10
+ super(registryName, text, textStyle, textStyle, "money");
11
+ this.valueTextComponent.style = { ...this.valueTextComponent.style, fontSize: 120, padding: 50 };
12
+ this.valueTextComponent.anchor.set(0.5, 0.5);
13
+ if (textureName) {
14
+ this.textureSprite = new TilingSprite(getTexture(textureName), this.valueTextComponent.width, this.valueTextComponent.height);
15
+ this.textureSprite.scale.set(1.1);
16
+ this.textureSprite.mask = this.valueTextComponent;
17
+ this.textureSprite.anchor.set(0.5);
18
+ this.addChildAt(this.textureSprite, 0);
19
+ }
20
+ RainMan.componentRegistry.add(this);
21
+ }
22
+ randomizeSet(value, _possibleValues) {
23
+ this.valueTextComponent.style.fontSize = -10 * new MoneyText(value).toString().length + 190;
24
+ super.update(value, 0);
25
+ }
26
+ }
@@ -1,4 +1,5 @@
1
1
  export * from "./AnimableParticlesEmitter";
2
+ export * from "./MysteryWinContainer";
2
3
  export * from "./PositioningFrame";
3
4
  export * from "./UpdatableSpineContainer";
4
5
  export * from "./winFactory";
@@ -1,4 +1,5 @@
1
1
  export * from "./AnimableParticlesEmitter";
2
+ export * from "./MysteryWinContainer";
2
3
  export * from "./PositioningFrame";
3
4
  export * from "./UpdatableSpineContainer";
4
5
  export * from "./winFactory";
@@ -1,5 +1,7 @@
1
1
  import { ITextStyle } from "pixi.js";
2
+ import { COMPONENTS } from "../components";
2
3
  import { AnimableParticlesEmitter } from "./AnimableParticlesEmitter";
4
+ import { MysteryWinContainer } from "./MysteryWinContainer";
3
5
  import { UpdatableSpineContainer } from "./UpdatableSpineContainer";
4
6
  /**
5
7
  * Factory function for creating BigWin and Mystery win containers
@@ -13,3 +15,30 @@ import { UpdatableSpineContainer } from "./UpdatableSpineContainer";
13
15
  * @returns {UpdatableSpineContainer} - container with scalable spine, text and emitters
14
16
  */
15
17
  export declare const winFactory: (textRegistryName: string, defaultText: string, spineName: string, animationName: string, emitters?: AnimableParticlesEmitter[], textStyleOverrides?: Partial<ITextStyle>, spineScale?: number) => UpdatableSpineContainer;
18
+ type WinFactoryType = typeof COMPONENTS.mysteryWin | typeof COMPONENTS.bigWin;
19
+ type WinFactoryProps = {
20
+ type: WinFactoryType;
21
+ plateSpine: string;
22
+ animationSpine: string;
23
+ plateSpineBg: string;
24
+ text: string;
25
+ textStyle?: ITextStyle;
26
+ textTexture?: string;
27
+ spineScale?: number;
28
+ isBgAnimated?: boolean;
29
+ emitters?: AnimableParticlesEmitter[];
30
+ };
31
+ /**
32
+ * New factory function for creating BigWin and Mystery win containers. It differs from winFactory
33
+ * in that it creates MysteryWinContainer instead of UpdatableSpineContainer
34
+ * @param {typeof COMPONENTS.mysteryWin | typeof COMPONENTS.bigWin} type - type of win
35
+ * @param {string} plateSpine - name of plate spine
36
+ * @param {string} animationSpine - name of animation spine
37
+ * @param {string} plateSpineBg - name of plate spine bg
38
+ * @param {string} text - text
39
+ * @param {string | undefined} textTexture - texture for text
40
+ * @param {number | undefined} spineScale - scale of spine, default is 0.9
41
+ * @returns {MysteryWinContainer}
42
+ */
43
+ export declare const winFactoryV2: ({ type, plateSpine, plateSpineBg, animationSpine, text, textTexture, spineScale, emitters, textStyle, isBgAnimated, }: WinFactoryProps) => MysteryWinContainer;
44
+ export {};
@@ -1,5 +1,6 @@
1
- import { ScalableSpine, StylefulUpdatableText, UPDATABLE_MODES } from "../components";
1
+ import { COMPONENTS, ScalableSpine, StylefulUpdatableText, UPDATABLE_MODES } from "../components";
2
2
  import { RainMan } from "../Rainman";
3
+ import { MysteryWinContainer } from "./MysteryWinContainer";
3
4
  import { PositioningFrame } from "./PositioningFrame";
4
5
  import { UpdatableSpineContainer } from "./UpdatableSpineContainer";
5
6
  /**
@@ -33,3 +34,25 @@ export const winFactory = (textRegistryName, defaultText, spineName, animationNa
33
34
  const bigWinShadow = new PositioningFrame(width, height, 0x000000);
34
35
  return new UpdatableSpineContainer(bigWinText, bigWinSpine, bigWinShadow, emitters, spineScale);
35
36
  };
37
+ /**
38
+ * New factory function for creating BigWin and Mystery win containers. It differs from winFactory
39
+ * in that it creates MysteryWinContainer instead of UpdatableSpineContainer
40
+ * @param {typeof COMPONENTS.mysteryWin | typeof COMPONENTS.bigWin} type - type of win
41
+ * @param {string} plateSpine - name of plate spine
42
+ * @param {string} animationSpine - name of animation spine
43
+ * @param {string} plateSpineBg - name of plate spine bg
44
+ * @param {string} text - text
45
+ * @param {string | undefined} textTexture - texture for text
46
+ * @param {number | undefined} spineScale - scale of spine, default is 0.9
47
+ * @returns {MysteryWinContainer}
48
+ */
49
+ export const winFactoryV2 = ({ type, plateSpine, plateSpineBg, animationSpine, text, textTexture, spineScale, emitters, textStyle, isBgAnimated = false, }) => {
50
+ const { width, height } = RainMan.app.screen;
51
+ const bigWinShadow = new PositioningFrame(width, height, 0x000000);
52
+ if (type === COMPONENTS.bigWin) {
53
+ return new MysteryWinContainer(COMPONENTS.bigWin, plateSpine, animationSpine, plateSpineBg, bigWinShadow, text, spineScale, emitters, textTexture, textStyle, isBgAnimated);
54
+ }
55
+ else {
56
+ return new MysteryWinContainer(COMPONENTS.mysteryWin, plateSpine, animationSpine, plateSpineBg, bigWinShadow, text, spineScale, emitters, textTexture, textStyle, isBgAnimated);
57
+ }
58
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixi-rainman-game-engine",
3
- "version": "0.2.18",
3
+ "version": "0.2.19",
4
4
  "description": "This repository contains all of the mechanics that used in rainman games.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",