pixi-rainman-game-engine 0.1.49 → 0.1.51

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.
@@ -35,9 +35,9 @@ export const defaultAppConfig = {
35
35
  freeSpinPlateVisibleTime: 2000,
36
36
  freeSpinSummaryVisibleTime: 2000,
37
37
  updatableTextCountingDuration: 500,
38
- scatterDelayerTime: 2000,
39
- scatterSpinningTime: 9200,
40
- mobileSpinTimeout: 300,
38
+ mobileSpinTimeout: 100,
39
+ scatterDelayerTime: 1000,
40
+ scatterSpinningTime: 1200,
41
41
  mysteryWinMinimumTime: 2000,
42
42
  bigWinMinimumTime: 2000,
43
43
  bigWinPhaseTimeout: 2800,
@@ -40,6 +40,15 @@
40
40
  height: 78px;
41
41
  background-repeat: no-repeat no-repeat;
42
42
  background-size: contain;
43
+ cursor: pointer;
44
+ }
45
+
46
+ .speed-settings-popup__option:hover {
47
+ background-image: url("/assets/settings/speedPopup/speed-frame-active.png");
48
+ width: 145px;
49
+ height: 78px;
50
+ background-repeat: no-repeat no-repeat;
51
+ background-size: contain;
43
52
  }
44
53
 
45
54
  .speed-settings-popup_option--active {
@@ -101,6 +110,25 @@
101
110
  }
102
111
  }
103
112
 
113
+ @media screen and (max-width: 450px) and (pointer: coarse) {
114
+ .speed-settings-popup__option {
115
+ width: 120px;
116
+ height: 66px;
117
+ }
118
+
119
+ .speed-settings-popup__option:hover {
120
+ background-image: url("/assets/settings/speedPopup/speed-frame-active.png");
121
+ background-repeat: no-repeat no-repeat;
122
+ background-size: contain;
123
+ }
124
+
125
+ .speed-settings-popup__option:focus {
126
+ background-image: url("/assets/settings/speedPopup/speed-frame-active.png");
127
+ background-repeat: no-repeat no-repeat;
128
+ background-size: contain;
129
+ }
130
+ }
131
+
104
132
  @media only screen and (max-height: 450px) {
105
133
  .speed-settings-modal {
106
134
  width: 80vw;
@@ -14,8 +14,8 @@ const onChange = (newVolumeLevel) => {
14
14
  };
15
15
  const onAfterChange = (newVolumeLevel) => {
16
16
  RainMan.settingsStore.flipSoundsEnabled(newVolumeLevel);
17
- if (RainMan.settingsStore.ambientMusicFlag) {
18
- SoundManager.play("music");
17
+ if (RainMan.settingsStore.isSoundEnabled()) {
18
+ SoundManager.resumeAll();
19
19
  }
20
20
  };
21
21
  export const VolumeSettings = observer(() => {
@@ -1,6 +1,6 @@
1
1
  import i18n from "i18next";
2
2
  import { sample } from "lodash";
3
- import { SoundManager, SoundTracks } from "../../application";
3
+ import { SoundManager } from "../../application";
4
4
  import { AutoplayButton, Background, BUTTONS, COMPONENTS, FreeSpinButton, MessageBox, SpeedControlButton, VolumeButton, } from "../../components";
5
5
  import { RainMan } from "../../Rainman";
6
6
  import { allUiItems, hideLayerIfPresent, UI_ITEMS } from "../../utils";
@@ -193,9 +193,8 @@ export class ButtonsEventManager {
193
193
  RainMan.settingsStore.setUpdateVolumeButtonTexture(() => RainMan.componentRegistry.get(VolumeButton.registryName).changeTextureDependOnVolume());
194
194
  RainMan.componentRegistry.get(VolumeButton.registryName).setOnClick(() => {
195
195
  RainMan.settingsStore.flipSoundsEnabled();
196
- if (RainMan.settingsStore.ambientMusicFlag && RainMan.settingsStore.isSoundEnabled()) {
197
- SoundManager.resume(SoundTracks.music);
198
- }
196
+ if (RainMan.settingsStore.isSoundEnabled())
197
+ SoundManager.resumeAll();
199
198
  RainMan.componentRegistry.get(VolumeButton.registryName).changeTextureDependOnVolume();
200
199
  this.handleModalInvocation(UI_ITEMS.volume);
201
200
  });
@@ -103,7 +103,7 @@ export class SoundManagerInstance {
103
103
  this.musicCatalogue.forEach((sound, soundName) => {
104
104
  if (sound.paused && sound.isPlaying)
105
105
  sound.resume();
106
- if (soundName === SoundTracks.music && sound.paused) {
106
+ if (RainMan.settingsStore.ambientMusicFlag && soundName === SoundTracks.music && sound.paused) {
107
107
  sound.resume();
108
108
  }
109
109
  });
@@ -56,8 +56,8 @@ export class AbstractMainContainer extends Container {
56
56
  this.name = AbstractMainContainer.registryName;
57
57
  this.buttonsEventManager = new ButtonsEventManager();
58
58
  this.messageBox = new MessageBox();
59
- if (RainMan.settingsStore.ambientMusicFlag)
60
- SoundManager.setPlayStatus(SoundTracks.music, true);
59
+ if (RainMan.settingsStore.isSoundEnabled())
60
+ SoundManager.resumeAll();
61
61
  RainMan.app.renderer.on("resize", () => this.resize());
62
62
  }
63
63
  /**
@@ -193,6 +193,7 @@ export class AbstractMainContainer extends Container {
193
193
  this.overlay.drawRect(0, 0, width, height);
194
194
  this.overlay.eventMode = "static";
195
195
  this.overlay.endFill();
196
+ this.overlay.interactive = true;
196
197
  this.addChild(this.overlay);
197
198
  }
198
199
  hideOverlay() {
@@ -83,10 +83,15 @@ export class AbstractColumnsContainer extends Container {
83
83
  break;
84
84
  }
85
85
  const configureSpinAction = configuredBlindSpinsActions.shift();
86
+ indexesOfReelsToExtendSpinningTime.forEach((number) => {
87
+ this.allColumns[number].changeMultiplier();
88
+ });
86
89
  if (configureSpinAction !== undefined) {
87
90
  if (indexesOfReelsToExtendSpinningTime.includes(index)) {
88
91
  this.currentColumn = this.allColumns[index];
92
+ this.currentColumn.adaptToSpeed(RainMan.settingsStore.currentSpeed);
89
93
  frame.invokeMysteryFx(this.currentColumn.x, this.currentColumn.y);
94
+ await this.currentColumn.speedUpForMysterySpin(100, 1500);
90
95
  this.skipScatterDelay = configureSpinAction;
91
96
  setTimeout(() => {
92
97
  this.skipScatterDelay?.();
@@ -134,11 +139,11 @@ export class AbstractColumnsContainer extends Container {
134
139
  return;
135
140
  }
136
141
  if (amount > WIN_MULTIPLIER_VALUES.MEDIUM_WIN_MIN * bet &&
137
- amount < WIN_MULTIPLIER_VALUES.MEDIUM_WIN_MAX * bet) {
142
+ amount <= WIN_MULTIPLIER_VALUES.MEDIUM_WIN_MAX * bet) {
138
143
  SoundManager.play(SoundTracks.mediumWin);
139
144
  return;
140
145
  }
141
- if (amount > WIN_MULTIPLIER_VALUES.HIGH_WIN_MIN * bet && amount < WIN_MULTIPLIER_VALUES.HIGH_WIN_MAX * bet) {
146
+ if (amount > WIN_MULTIPLIER_VALUES.HIGH_WIN_MIN * bet && amount <= WIN_MULTIPLIER_VALUES.HIGH_WIN_MAX * bet) {
142
147
  SoundManager.play(SoundTracks.highWin);
143
148
  return;
144
149
  }
@@ -37,7 +37,7 @@ export declare abstract class AbstractFrame extends ResumableContainer implement
37
37
  adaptToSpeed(speedLevel: SpeedLevel): void;
38
38
  invokeMysteryFx(x: number, y: number): void;
39
39
  protected repositionMysteryFx(_x: number, _y: number): void;
40
- hideMysteryFx(): Promise<void>;
40
+ hideMysteryFx(): void;
41
41
  private resetMysteryFxCoordinates;
42
42
  destroyMysteryFx(): void;
43
43
  protected createWinLineAnimation(_animationName: string): WinLineAnimation | null;
@@ -54,31 +54,25 @@ export class AbstractFrame extends ResumableContainer {
54
54
  this.addChild(this.mysteryFxHighlight);
55
55
  }
56
56
  repositionMysteryFx(_x, _y) { }
57
- async hideMysteryFx() {
58
- return new Promise((resolve) => {
59
- if (!this.mysteryFxConfig)
60
- return resolve();
61
- if (!this.mysteryFxConfig.endAnimationName) {
62
- this.destroyMysteryFx();
63
- return resolve();
64
- }
65
- if (this.mysteryFxHighlight) {
66
- SoundManager.stop(SoundTracks.mysteryFxLoop);
67
- SoundManager.play(SoundTracks.mysteryFxEnd);
68
- this.resetMysteryFxCoordinates();
69
- this.mysteryFxHighlight.state.setAnimation(0, this.mysteryFxConfig.endAnimationName, false);
70
- this.mysteryFxHighlight.state.addListener({
71
- complete: () => resolve(),
72
- });
73
- }
74
- });
57
+ hideMysteryFx() {
58
+ if (!this.mysteryFxConfig)
59
+ return;
60
+ if (!this.mysteryFxConfig.endAnimationName) {
61
+ return;
62
+ }
63
+ if (this.mysteryFxHighlight) {
64
+ SoundManager.play(SoundTracks.mysteryFxEnd);
65
+ this.resetMysteryFxCoordinates();
66
+ this.mysteryFxHighlight.state.setAnimation(0, this.mysteryFxConfig.endAnimationName, false);
67
+ return;
68
+ }
75
69
  }
76
70
  resetMysteryFxCoordinates() {
77
71
  this.mysteryFxCoordinates = { x: 0, y: 0 };
78
72
  }
79
73
  destroyMysteryFx() {
80
74
  if (this.mysteryFxHighlight) {
81
- SoundManager.pause(SoundTracks.mysteryFxLoop);
75
+ SoundManager.stop(SoundTracks.mysteryFxLoop);
82
76
  this.removeChild(this.mysteryFxHighlight);
83
77
  this.mysteryFxHighlight.destroy();
84
78
  this.mysteryFxHighlight = null;
@@ -51,6 +51,8 @@ export declare abstract class AbstractSymbolsColumn extends Container implements
51
51
  get id(): string;
52
52
  protected get componentsTimingSettings(): AnimationTimeSettings;
53
53
  adaptToSpeed(speedLevel: SpeedLevel): void;
54
+ changeMultiplier(): void;
55
+ speedUpForMysterySpin(velocity: number, duration: number): Promise<void>;
54
56
  changeVelocity(velocity: number, duration: number, frame?: AbstractFrame): Promise<void>;
55
57
  protected animateDependentComponents(_distance: number): void;
56
58
  animate(delta: number, lastTime: number): void;
@@ -79,6 +79,24 @@ export class AbstractSymbolsColumn extends Container {
79
79
  this.velocityMultiplier = this.speedLevelMapper[speedLevel];
80
80
  this.symbols.forEach((symbol) => symbol.updateTimeScaleOfSpine(this.velocityMultiplier));
81
81
  }
82
+ changeMultiplier() {
83
+ this.velocityMultiplier = 3.5;
84
+ }
85
+ async speedUpForMysterySpin(velocity, duration) {
86
+ await new Promise((resolve) => {
87
+ this.tween = new TWEEN.Tween({ velocity: velocity })
88
+ .to({ value: 70 }, duration)
89
+ .easing(TWEEN.Easing.Linear.None)
90
+ .onUpdate((value) => {
91
+ this.velocity = value.velocity;
92
+ })
93
+ .onComplete(() => {
94
+ this.tween = null;
95
+ resolve();
96
+ })
97
+ .start();
98
+ });
99
+ }
82
100
  async changeVelocity(velocity, duration, frame) {
83
101
  await new Promise((resolve) => {
84
102
  this.tween = new TWEEN.Tween({ velocity: velocity })
@@ -88,10 +106,19 @@ export class AbstractSymbolsColumn extends Container {
88
106
  .easing(TWEEN.Easing.Linear.None)
89
107
  .to({ velocity }, duration)
90
108
  .start()
109
+ .onComplete(async () => {
110
+ this.tween = null;
111
+ if (frame) {
112
+ frame.hideMysteryFx();
113
+ frame.destroyMysteryFx();
114
+ }
115
+ this.skipHidingMysteryFx = false;
116
+ resolve();
117
+ })
91
118
  .onStop(async () => {
92
119
  this.tween = null;
93
120
  if (frame) {
94
- await frame.hideMysteryFx();
121
+ frame.hideMysteryFx();
95
122
  frame.destroyMysteryFx();
96
123
  }
97
124
  this.skipHidingMysteryFx = false;
@@ -17,8 +17,8 @@ export declare class DroppableSymbolsColumn {
17
17
  get symbolsToBeDestroyed(): DroppableSymbol[];
18
18
  get allSymbolsToBeMovedDown(): DroppableSymbol[];
19
19
  setSymbolsToBeDestroyed(rowIndex: number, replacementSymbol: SymbolId): void;
20
- playAnimations(): Promise<void[]>;
21
- destroyAnimations(isStandalone: boolean): Promise<void[]>;
20
+ playAnimations(): Promise<PromiseSettledResult<void>[]>;
21
+ destroyAnimations(isStandalone: boolean): Promise<PromiseSettledResult<void>[]>;
22
22
  moveDestroyedSymbolsToTop(tileHeight: number): void;
23
23
  swapDestroyedSymbols(): void;
24
24
  /**
@@ -34,7 +34,7 @@ export class DroppableSymbolsColumn {
34
34
  this.sortableSymbols[rowIndex].referencedYInColumn = rowIndex;
35
35
  }
36
36
  async playAnimations() {
37
- return await Promise.all(this.symbolsToBeDestroyed.map((symbol) => symbol.symbol.play()));
37
+ return await Promise.allSettled(this.symbolsToBeDestroyed.map((symbol) => symbol.symbol.play()));
38
38
  }
39
39
  async destroyAnimations(isStandalone) {
40
40
  const destroyedSymbols = [];
@@ -43,7 +43,7 @@ export class DroppableSymbolsColumn {
43
43
  destroyedSymbols.push(symbol.symbol.handlePopSymbol(isStandalone));
44
44
  this._numberToBeDropped++;
45
45
  });
46
- return await Promise.all(destroyedSymbols);
46
+ return await Promise.allSettled(destroyedSymbols);
47
47
  }
48
48
  moveDestroyedSymbolsToTop(tileHeight) {
49
49
  this.symbolsToBeDestroyed.forEach((symbols, index) => {
@@ -8,7 +8,7 @@ export interface AnimationTimeSettings {
8
8
  }
9
9
  export declare enum Speed {
10
10
  FAST = 70,
11
- STOP = 15
11
+ STOP = 65
12
12
  }
13
13
  /**
14
14
  * Enum that describes the phase of columns
@@ -1,7 +1,7 @@
1
1
  export var Speed;
2
2
  (function (Speed) {
3
3
  Speed[Speed["FAST"] = 70] = "FAST";
4
- Speed[Speed["STOP"] = 15] = "STOP";
4
+ Speed[Speed["STOP"] = 65] = "STOP";
5
5
  })(Speed || (Speed = {}));
6
6
  /**
7
7
  * Enum that describes the phase of columns
@@ -184,17 +184,25 @@ export class AbstractController {
184
184
  const refreshButton = RainMan.componentRegistry.get(RefreshButton.registryName);
185
185
  refreshButton.setOnClick(() => this.handleSpinLogic());
186
186
  const clearMobileSpinTimeout = () => {
187
- if (!this.mobileSpinTimeout)
188
- return;
189
- clearInterval(this.mobileSpinTimeout);
190
- this.mobileSpinTimeout = null;
187
+ if (this.mobileSpinTimeout) {
188
+ clearInterval(this.mobileSpinTimeout);
189
+ this.mobileSpinTimeout = null;
190
+ }
191
191
  };
192
192
  refreshButton.on("touchstart", () => {
193
- if (this.mobileSpinTimeout !== null)
194
- return;
195
- this.mobileSpinTimeout = setInterval(() => this.handleSpinLogic(), RainMan.config.durationOfActions.mobileSpinTimeout);
193
+ this.mobileSpinTimeout = setInterval(() => {
194
+ if (this.invokeFreeSpinPlateAfterWin ||
195
+ this.invokeFreeSpinSummaryPlateAfterWin ||
196
+ this.resolveBigWin !== undefined) {
197
+ clearMobileSpinTimeout();
198
+ return;
199
+ }
200
+ this.handleSpinLogic();
201
+ }, RainMan.config.durationOfActions.mobileSpinTimeout);
202
+ });
203
+ refreshButton.on("touchend", () => {
204
+ clearMobileSpinTimeout();
196
205
  });
197
- refreshButton.on("touchend", () => clearMobileSpinTimeout());
198
206
  refreshButton.on("globaltouchmove", (event) => {
199
207
  if (event.target !== refreshButton)
200
208
  clearMobileSpinTimeout();
@@ -777,10 +785,12 @@ export class AbstractController {
777
785
  .get(COMPONENTS.mysteryWin)
778
786
  .randomizeSet(winAmount, RainMan.settingsStore.getMysteryPaytable(this.mysteryWinSymbol, quantity));
779
787
  SoundManager.pause(SoundTracks.mysteryDrawLoop);
788
+ if (RainMan.settingsStore.isFreeSpinsPlayEnabled) {
789
+ this.uiController.limitWinAmount(this.uiController.totalFreeSpinWinAmount + winAmount);
790
+ this.uiController.increaseTotalFreeSpinWinAmount(winAmount);
791
+ }
780
792
  this.updateUiValues(winAmount);
781
793
  this._lastWinAmount += winAmount;
782
- if (RainMan.settingsStore.isFreeSpinsPlayEnabled)
783
- this.uiController.increaseTotalFreeSpinWinAmount(winAmount);
784
794
  await new Promise((resolve) => {
785
795
  this.resolveMysteryWin = resolve;
786
796
  setTimeout(() => {
@@ -834,7 +844,7 @@ export class AbstractController {
834
844
  }
835
845
  }
836
846
  async handleLoopingWinActionQueue() {
837
- if (RainMan.settingsStore.isAutoplayEnabled)
847
+ if (RainMan.settingsStore.isAutoplayEnabled || this.invokeFreeSpinPlateAfterWin)
838
848
  return;
839
849
  this.isLoopingWinActionsQueue = true;
840
850
  await this.loopWinActionsQueue();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixi-rainman-game-engine",
3
- "version": "0.1.49",
3
+ "version": "0.1.51",
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",