@omnitronix/bonnys-fortune-game-engine 1.3.2 → 1.5.0

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.
Files changed (175) hide show
  1. package/README.md +25 -15
  2. package/dist/__tests__/base-game.test.js +255 -0
  3. package/dist/__tests__/base-game.test.js.map +1 -0
  4. package/dist/__tests__/bonnys-fortune-v1.game-engine.test.js +1 -1
  5. package/dist/__tests__/bonus-handlers.test.js +303 -0
  6. package/dist/__tests__/bonus-handlers.test.js.map +1 -0
  7. package/dist/__tests__/bonus-meters.test.js +508 -0
  8. package/dist/__tests__/bonus-meters.test.js.map +1 -0
  9. package/dist/__tests__/collect-feature-handler.test.js +386 -0
  10. package/dist/__tests__/collect-feature-handler.test.js.map +1 -0
  11. package/dist/__tests__/comprehensive.test.js +747 -0
  12. package/dist/__tests__/comprehensive.test.js.map +1 -0
  13. package/dist/__tests__/error-paths.test.js +373 -0
  14. package/dist/__tests__/error-paths.test.js.map +1 -0
  15. package/dist/__tests__/helpers/test-engine-factory.js +268 -0
  16. package/dist/__tests__/helpers/test-engine-factory.js.map +1 -0
  17. package/dist/__tests__/rng-gli19-compliance.test.js +292 -0
  18. package/dist/__tests__/rng-gli19-compliance.test.js.map +1 -0
  19. package/dist/__tests__/rng-security.test.js +383 -0
  20. package/dist/__tests__/rng-security.test.js.map +1 -0
  21. package/dist/__tests__/rtp-simulation.test.js +242 -0
  22. package/dist/__tests__/rtp-simulation.test.js.map +1 -0
  23. package/dist/__tests__/state-transitions.test.js +307 -0
  24. package/dist/__tests__/state-transitions.test.js.map +1 -0
  25. package/dist/__tests__/steering-fortune-handler.test.js +286 -0
  26. package/dist/__tests__/steering-fortune-handler.test.js.map +1 -0
  27. package/dist/__tests__/symbol-distribution.test.js +195 -0
  28. package/dist/__tests__/symbol-distribution.test.js.map +1 -0
  29. package/dist/__tests__/treasure-hunt-handler.test.js +295 -0
  30. package/dist/__tests__/treasure-hunt-handler.test.js.map +1 -0
  31. package/dist/__tests__/win-calculator.test.js +515 -0
  32. package/dist/__tests__/win-calculator.test.js.map +1 -0
  33. package/dist/bonnys-fortune-v1.game-engine.js +14 -25
  34. package/dist/bonnys-fortune-v1.game-engine.js.map +1 -1
  35. package/dist/config/game-logic-config/game-logic-config.js +0 -2
  36. package/dist/config/game-logic-config/game-logic-config.js.map +1 -1
  37. package/dist/domain/types/{cheat-trigger-bonus-command.js → debug-trigger-bonus-command.js} +1 -1
  38. package/dist/domain/types/debug-trigger-bonus-command.js.map +1 -0
  39. package/dist/domain/types/{cheat-trigger-bonus-request.dto.js → debug-trigger-bonus-request.dto.js} +1 -1
  40. package/dist/domain/types/debug-trigger-bonus-request.dto.js.map +1 -0
  41. package/dist/domain/types/{cheat-update-bonus-meter-progress-command.js → debug-update-bonus-meter-progress-command.js} +1 -1
  42. package/dist/domain/types/debug-update-bonus-meter-progress-command.js.map +1 -0
  43. package/dist/domain/types/{cheat-update-bonus-meter-progress-request.dto.js → debug-update-bonus-meter-progress-request.dto.js} +1 -1
  44. package/dist/domain/types/debug-update-bonus-meter-progress-request.dto.js.map +1 -0
  45. package/dist/index.js.map +1 -1
  46. package/dist/logic/bonnys-fortune.game-logic.js +37 -17
  47. package/dist/logic/bonnys-fortune.game-logic.js.map +1 -1
  48. package/dist/logic/handlers/base-game.handler.js +1 -5
  49. package/dist/logic/handlers/base-game.handler.js.map +1 -1
  50. package/dist/rng/DummyRngClient.js +8 -1
  51. package/dist/rng/DummyRngClient.js.map +1 -1
  52. package/dist/rng/rng-client.factory.js.map +1 -1
  53. package/dist/validation/bonnys-fortune/bonnys-fortune-config.dto.js +0 -9
  54. package/dist/validation/bonnys-fortune/bonnys-fortune-config.dto.js.map +1 -1
  55. package/package.json +6 -6
  56. package/dist/__tests__/bonnys-fortune-v1.game-engine.test.d.ts +0 -1
  57. package/dist/bonnys-fortune-v1.game-engine.d.ts +0 -36
  58. package/dist/config/game-logic-config/file-system.game-logic-config-loader.d.ts +0 -4
  59. package/dist/config/game-logic-config/game-logic-config-loader.d.ts +0 -3
  60. package/dist/config/game-logic-config/game-logic-config.d.ts +0 -2
  61. package/dist/config/reel-strips-config/file-system.reel-strips-config-loader.d.ts +0 -4
  62. package/dist/config/reel-strips-config/reel-strip-option.dto.d.ts +0 -4
  63. package/dist/config/reel-strips-config/reel-strips-config-loader.d.ts +0 -3
  64. package/dist/config/reel-strips-config/reel-strips-config.dto.d.ts +0 -5
  65. package/dist/config/reel-strips-config/reel.dto.d.ts +0 -5
  66. package/dist/domain/game-round.types.d.ts +0 -9
  67. package/dist/domain/mappers/reel-strips-config.mapper.d.ts +0 -4
  68. package/dist/domain/reel-strip-option.d.ts +0 -7
  69. package/dist/domain/reel-strips-config.d.ts +0 -9
  70. package/dist/domain/reel.d.ts +0 -8
  71. package/dist/domain/types/cheat-trigger-bonus-command.d.ts +0 -5
  72. package/dist/domain/types/cheat-trigger-bonus-command.js.map +0 -1
  73. package/dist/domain/types/cheat-trigger-bonus-request.dto.d.ts +0 -5
  74. package/dist/domain/types/cheat-trigger-bonus-request.dto.js.map +0 -1
  75. package/dist/domain/types/cheat-update-bonus-meter-progress-command.d.ts +0 -5
  76. package/dist/domain/types/cheat-update-bonus-meter-progress-command.js.map +0 -1
  77. package/dist/domain/types/cheat-update-bonus-meter-progress-request.dto.d.ts +0 -5
  78. package/dist/domain/types/cheat-update-bonus-meter-progress-request.dto.js.map +0 -1
  79. package/dist/domain/types/game-spin-command.d.ts +0 -8
  80. package/dist/domain/types/game-spin-input.dto.d.ts +0 -8
  81. package/dist/domain/types/game-spin-output.dto.d.ts +0 -119
  82. package/dist/domain/types/game-symbols.response.dto.d.ts +0 -10
  83. package/dist/domain/types/reel-strip-option.dto.d.ts +0 -4
  84. package/dist/domain/types/reel-strips-config.dto.d.ts +0 -5
  85. package/dist/domain/types/reel.dto.d.ts +0 -5
  86. package/dist/domain/types/start-bonus-round-command.d.ts +0 -8
  87. package/dist/domain/types/start-bonus-round-input.dto.d.ts +0 -10
  88. package/dist/game-engine.interface.d.ts +0 -41
  89. package/dist/helpers/generate-hash.d.ts +0 -1
  90. package/dist/helpers/number-helper.d.ts +0 -23
  91. package/dist/helpers/optional-boolean-mapper.d.ts +0 -1
  92. package/dist/helpers/uuid-helper.d.ts +0 -3
  93. package/dist/helpers/validation-helper.d.ts +0 -14
  94. package/dist/index.d.ts +0 -2
  95. package/dist/logger/logger.d.ts +0 -22
  96. package/dist/logger/logger.js +0 -140
  97. package/dist/logger/logger.js.map +0 -1
  98. package/dist/logic/bonnys-fortune.game-logic.d.ts +0 -32
  99. package/dist/logic/bonnys-fortune.spin-generator.d.ts +0 -19
  100. package/dist/logic/bonnys-fortune.types.d.ts +0 -170
  101. package/dist/logic/bonnys-fortune.win-calculator.d.ts +0 -10
  102. package/dist/logic/game-logic-config.interface.d.ts +0 -180
  103. package/dist/logic/handlers/base-game.handler.d.ts +0 -15
  104. package/dist/logic/handlers/collect-feature-bonus.handler.d.ts +0 -13
  105. package/dist/logic/handlers/free-spins-bonus.handler.d.ts +0 -11
  106. package/dist/logic/handlers/steering-to-the-fortune-bonus.handler.d.ts +0 -11
  107. package/dist/logic/handlers/treasure-hunt-bonus.handler.d.ts +0 -15
  108. package/dist/rng/DummyRngClient.d.ts +0 -18
  109. package/dist/rng/rng-client.factory.d.ts +0 -7
  110. package/dist/rng/rng-client.interface.d.ts +0 -16
  111. package/dist/rng/rng-service.d.ts +0 -26
  112. package/dist/validation/abstract-game-logic-config.validator.d.ts +0 -4
  113. package/dist/validation/bonnys-fortune/bonnys-fortune-config.dto.d.ts +0 -131
  114. package/dist/validation/bonnys-fortune/bonnys-fortune-config.validator.d.ts +0 -5
  115. package/dist/validation/custom-decorators/IsNestedIntArray.d.ts +0 -2
  116. package/dist/validation/game-logic-config-validation.service.d.ts +0 -8
  117. package/dist/validation/reel-strips-config-validation.service.d.ts +0 -5
  118. package/src/__tests__/bonnys-fortune-v1.game-engine.test.ts +0 -80
  119. package/src/bonnys-fortune-v1.game-engine.ts +0 -314
  120. package/src/config/game-logic-config/file-system.game-logic-config-loader.ts +0 -27
  121. package/src/config/game-logic-config/game-logic-config-loader.ts +0 -3
  122. package/src/config/game-logic-config/game-logic-config.ts +0 -382
  123. package/src/config/reel-strips-config/file-system.reel-strips-config-loader.ts +0 -43
  124. package/src/config/reel-strips-config/reel-strip-option.dto.ts +0 -13
  125. package/src/config/reel-strips-config/reel-strips-config-loader.ts +0 -9
  126. package/src/config/reel-strips-config/reel-strips-config.dto.ts +0 -16
  127. package/src/config/reel-strips-config/reel.dto.ts +0 -16
  128. package/src/config/reel-strips-config/reels-BASE.csv +0 -52
  129. package/src/config/reel-strips-config/reels-BONUS.csv +0 -52
  130. package/src/domain/game-round.types.ts +0 -10
  131. package/src/domain/mappers/reel-strips-config.mapper.ts +0 -16
  132. package/src/domain/reel-strip-option.ts +0 -15
  133. package/src/domain/reel-strips-config.ts +0 -21
  134. package/src/domain/reel.ts +0 -17
  135. package/src/domain/types/cheat-trigger-bonus-command.ts +0 -5
  136. package/src/domain/types/cheat-trigger-bonus-request.dto.ts +0 -5
  137. package/src/domain/types/cheat-update-bonus-meter-progress-command.ts +0 -6
  138. package/src/domain/types/cheat-update-bonus-meter-progress-request.dto.ts +0 -5
  139. package/src/domain/types/game-spin-command.ts +0 -8
  140. package/src/domain/types/game-spin-input.dto.ts +0 -8
  141. package/src/domain/types/game-spin-output.dto.ts +0 -142
  142. package/src/domain/types/game-symbols.response.dto.ts +0 -11
  143. package/src/domain/types/reel-strip-option.dto.ts +0 -13
  144. package/src/domain/types/reel-strips-config.dto.ts +0 -15
  145. package/src/domain/types/reel.dto.ts +0 -15
  146. package/src/domain/types/start-bonus-round-command.ts +0 -8
  147. package/src/domain/types/start-bonus-round-input.dto.ts +0 -10
  148. package/src/game-engine.interface.ts +0 -59
  149. package/src/helpers/generate-hash.ts +0 -5
  150. package/src/helpers/number-helper.ts +0 -41
  151. package/src/helpers/optional-boolean-mapper.ts +0 -5
  152. package/src/helpers/uuid-helper.ts +0 -7
  153. package/src/helpers/validation-helper.ts +0 -27
  154. package/src/index.ts +0 -3
  155. package/src/logger/logger.ts +0 -178
  156. package/src/logic/bonnys-fortune.game-logic.ts +0 -490
  157. package/src/logic/bonnys-fortune.spin-generator.ts +0 -277
  158. package/src/logic/bonnys-fortune.types.ts +0 -223
  159. package/src/logic/bonnys-fortune.win-calculator.ts +0 -210
  160. package/src/logic/game-logic-config.interface.ts +0 -176
  161. package/src/logic/handlers/base-game.handler.ts +0 -221
  162. package/src/logic/handlers/collect-feature-bonus.handler.ts +0 -301
  163. package/src/logic/handlers/free-spins-bonus.handler.ts +0 -119
  164. package/src/logic/handlers/steering-to-the-fortune-bonus.handler.ts +0 -118
  165. package/src/logic/handlers/treasure-hunt-bonus.handler.ts +0 -232
  166. package/src/rng/DummyRngClient.ts +0 -108
  167. package/src/rng/rng-client.factory.ts +0 -27
  168. package/src/rng/rng-client.interface.ts +0 -38
  169. package/src/rng/rng-service.ts +0 -130
  170. package/src/validation/abstract-game-logic-config.validator.ts +0 -20
  171. package/src/validation/bonnys-fortune/bonnys-fortune-config.dto.ts +0 -379
  172. package/src/validation/bonnys-fortune/bonnys-fortune-config.validator.ts +0 -8
  173. package/src/validation/custom-decorators/IsNestedIntArray.ts +0 -29
  174. package/src/validation/game-logic-config-validation.service.ts +0 -28
  175. package/src/validation/reel-strips-config-validation.service.ts +0 -29
@@ -1,490 +0,0 @@
1
- import {
2
- BonnysFortuneBaseGameSpinResult,
3
- BonnysFortunePrivateState,
4
- BonnysFortunePublicState,
5
- BonusTrigger,
6
- CheatTriggerBonusResult,
7
- CheatUpdateBonusMeterProgressResult,
8
- GetSymbolsResult,
9
- MeterState,
10
- MetersState,
11
- SpinResultResponse,
12
- StartBonusRoundResult,
13
- SpinType,
14
- } from './bonnys-fortune.types';
15
-
16
- import { BaseGameHandler } from './handlers/base-game.handler';
17
- import {
18
- BonnysFortuneGameLogicConfigInterface,
19
- BonnysFortuneSessionStateInterface,
20
- } from './game-logic-config.interface';
21
- import { BonnysFortuneSpinGenerator } from './bonnys-fortune.spin-generator';
22
- import { CheatTriggerBonusRequestDto } from '../domain/types/cheat-trigger-bonus-request.dto';
23
- import { CheatUpdateBonusMeterProgressRequestDto } from '../domain/types/cheat-update-bonus-meter-progress-request.dto';
24
- import { CollectFeatureBonusHandler } from './handlers/collect-feature-bonus.handler';
25
- import { FreeSpinsBonusHandler } from './handlers/free-spins-bonus.handler';
26
- import { GameActionCommand } from '../game-engine.interface';
27
- import { GameSpinInputDto } from '../domain/types/game-spin-input.dto';
28
- import { NumberHelper } from '../helpers/number-helper';
29
- import { ReelStripsConfig } from '../domain/reel-strips-config';
30
- import { RngService } from '../rng/rng-service';
31
- import { StartBonusRoundInputDto } from '../domain/types/start-bonus-round-input.dto';
32
- import { SteeringToTheFortuneBonusHandler } from './handlers/steering-to-the-fortune-bonus.handler';
33
- import { TreasureHuntBonusHandler } from './handlers/treasure-hunt-bonus.handler';
34
- import { UuidHelper } from '../helpers/uuid-helper';
35
-
36
- export class BonnysFortuneGameLogic {
37
- constructor(private readonly rngService: RngService) {}
38
-
39
- public async initSessionState(
40
- gameLogicConfig: BonnysFortuneGameLogicConfigInterface,
41
- reelStripsConfig: ReelStripsConfig,
42
- gameConfig: { betAmountThresholds: number[]; defaultBetAmount: number },
43
- commandId: string,
44
- ): Promise<BonnysFortuneSessionStateInterface> {
45
- const bonusMetersByAmount: Record<number, MetersState> = {};
46
-
47
- for (const betAmount of gameConfig.betAmountThresholds) {
48
- bonusMetersByAmount[betAmount] = await this.drawBonusMeters(
49
- gameLogicConfig,
50
- commandId,
51
- betAmount,
52
- );
53
- }
54
-
55
- const initialBetAmount =
56
- gameConfig.defaultBetAmount ?? gameConfig.betAmountThresholds[0];
57
-
58
- return {
59
- publicState: {
60
- currentBetAmount: initialBetAmount,
61
- bonusMeters: bonusMetersByAmount[initialBetAmount],
62
- },
63
- privateState: {
64
- bonusMetersByAmount,
65
- screen: await new BonnysFortuneSpinGenerator(
66
- this.rngService,
67
- ).generateBaseScreen(
68
- gameLogicConfig,
69
- reelStripsConfig,
70
- commandId,
71
- 'init_screen',
72
- ),
73
- nextSpinType: SpinType.BASE_GAME_SPIN,
74
- pendingBonuses: [],
75
- },
76
- };
77
- }
78
-
79
- public async spin(
80
- params: GameSpinInputDto,
81
- publicState: BonnysFortunePublicState,
82
- privateState: BonnysFortunePrivateState,
83
- gameLogicConfig: BonnysFortuneGameLogicConfigInterface,
84
- reelStripsConfig: ReelStripsConfig,
85
- commandId: string,
86
- ): Promise<SpinResultResponse<BonnysFortuneBaseGameSpinResult>> {
87
- return new BaseGameHandler(this.rngService).handleSpin(
88
- params,
89
- publicState,
90
- privateState,
91
- gameLogicConfig,
92
- reelStripsConfig,
93
- commandId,
94
- );
95
- }
96
-
97
- public async startBonusRound(
98
- params: StartBonusRoundInputDto,
99
- publicState: BonnysFortunePublicState,
100
- privateState: BonnysFortunePrivateState,
101
- gameLogicConfig: BonnysFortuneGameLogicConfigInterface,
102
- reelStripsConfig: ReelStripsConfig,
103
- commandId: string,
104
- ): Promise<StartBonusRoundResult> {
105
- if (!privateState.pendingBonuses?.length) {
106
- throw new Error('No pending bonuses to start.');
107
- }
108
-
109
- const [activeBonus] = privateState.pendingBonuses;
110
-
111
- if (
112
- activeBonus.bonusId !== params.bonusId ||
113
- activeBonus.bonusType !== params.bonusType
114
- ) {
115
- throw new Error(`Invalid bonus start request: ${params.bonusType}`);
116
- }
117
-
118
- if (this.shouldRedrawMeter(activeBonus.bonusType, gameLogicConfig)) {
119
- const updatedStates = await this.updateSessionState(
120
- publicState,
121
- privateState,
122
- gameLogicConfig,
123
- {
124
- id: commandId,
125
- type: 'START_BONUS_ROUND',
126
- payload: {
127
- bonusMeters: {
128
- redraw: [activeBonus.bonusType],
129
- },
130
- },
131
- },
132
- );
133
- publicState = updatedStates.publicState;
134
- privateState = updatedStates.privateState;
135
- }
136
-
137
- const updatedPrivateState: BonnysFortunePrivateState = {
138
- ...privateState,
139
- pendingBonuses: privateState.pendingBonuses.filter(
140
- (b) => b.bonusId !== activeBonus.bonusId,
141
- ),
142
- activeBonus,
143
- };
144
-
145
- switch (params.bonusType) {
146
- case 'bonusGame1': {
147
- const bonusHandlerResult = await new TreasureHuntBonusHandler(
148
- this.rngService,
149
- ).generateFullBonusRound(
150
- { ...params, betAmount: activeBonus.betAmount },
151
- publicState,
152
- {
153
- ...updatedPrivateState,
154
- nextSpinType: SpinType.BONUS_GAME_1_SPIN,
155
- },
156
- gameLogicConfig,
157
- commandId,
158
- );
159
-
160
- return {
161
- ...bonusHandlerResult,
162
- activeBonus,
163
- };
164
- }
165
-
166
- case 'bonusGame2': {
167
- const bonusHandlerResult = await new FreeSpinsBonusHandler(
168
- this.rngService,
169
- ).generateFullBonusRound(
170
- { ...params, betAmount: activeBonus.betAmount },
171
- publicState,
172
- {
173
- ...updatedPrivateState,
174
- nextSpinType: SpinType.BONUS_GAME_2_SPIN,
175
- },
176
- gameLogicConfig,
177
- reelStripsConfig,
178
- commandId,
179
- );
180
-
181
- return {
182
- ...bonusHandlerResult,
183
- activeBonus,
184
- };
185
- }
186
- case 'bonusGame3': {
187
- const bonusHandlerResult = await new SteeringToTheFortuneBonusHandler(
188
- this.rngService,
189
- ).generateFullBonusRound(
190
- { ...params, betAmount: activeBonus.betAmount },
191
- publicState,
192
- {
193
- ...updatedPrivateState,
194
- nextSpinType: SpinType.BONUS_GAME_3_SPIN,
195
- },
196
- gameLogicConfig,
197
- commandId,
198
- );
199
-
200
- return {
201
- ...bonusHandlerResult,
202
- activeBonus,
203
- };
204
- }
205
- case 'collectFeature': {
206
- const bonusHandlerResult = await new CollectFeatureBonusHandler(
207
- this.rngService,
208
- ).generateFullBonusRound(
209
- { ...params, betAmount: activeBonus.betAmount },
210
- publicState,
211
- {
212
- ...updatedPrivateState,
213
- nextSpinType: SpinType.COLLECT_FEATURE_SPIN,
214
- },
215
- gameLogicConfig,
216
- commandId,
217
- );
218
-
219
- return {
220
- ...bonusHandlerResult,
221
- activeBonus,
222
- };
223
- }
224
- }
225
- }
226
-
227
- private async drawBonusMeters(
228
- gameLogicConfig: BonnysFortuneGameLogicConfigInterface,
229
- commandId: string,
230
- betAmount: number,
231
- ): Promise<MetersState> {
232
- const bonusMeters: MetersState = {};
233
-
234
- for (const [key, cfg] of Object.entries(
235
- gameLogicConfig.baseGame.bonusGameMeters,
236
- )) {
237
- const { value: threshold } = await this.randomThreshold(
238
- cfg.min,
239
- cfg.max,
240
- commandId,
241
- `bonus_meter_${betAmount}_${key}`,
242
- );
243
- const progress = 0;
244
- const level = this.getMeterLevel(
245
- progress,
246
- threshold,
247
- cfg.percentageLevels,
248
- );
249
-
250
- bonusMeters[key] = {
251
- symbolName: cfg.symbol,
252
- symbolId:
253
- gameLogicConfig.baseGame.symbolMultipliers.find(
254
- (s) => s.name === cfg.symbol,
255
- )?.symbolId ?? 0,
256
- threshold,
257
- progress,
258
- level,
259
- };
260
- }
261
-
262
- return bonusMeters;
263
- }
264
-
265
- public async updateSessionState(
266
- publicState: BonnysFortunePublicState,
267
- privateState: BonnysFortunePrivateState,
268
- gameLogicConfig: BonnysFortuneGameLogicConfigInterface,
269
- command: GameActionCommand<{ bonusMeters: { redraw: string[] } }>,
270
- ): Promise<BonnysFortuneSessionStateInterface> {
271
- switch (command.type) {
272
- case 'START_BONUS_ROUND': {
273
- if (
274
- !this.requiresMeterUpdate(
275
- command.payload?.bonusMeters.redraw ?? [],
276
- gameLogicConfig,
277
- )
278
- ) {
279
- return { publicState, privateState };
280
- }
281
-
282
- const betAmount = publicState.currentBetAmount;
283
- const bonusMetersForBetAmount = privateState.bonusMetersByAmount[betAmount];
284
-
285
- if (!bonusMetersForBetAmount) {
286
- throw new Error(
287
- `Bet amount ${betAmount} is not in allowed thresholds`,
288
- );
289
- }
290
-
291
- for (const key of command.payload?.bonusMeters.redraw ?? []) {
292
- const cfg =
293
- gameLogicConfig.baseGame.bonusGameMeters[
294
- key as keyof typeof gameLogicConfig.baseGame.bonusGameMeters
295
- ];
296
- const { value: threshold } = await this.randomThreshold(
297
- cfg.min,
298
- cfg.max,
299
- command.id,
300
- `bonus_meter_redraw_${key}`,
301
- );
302
- const progress = 0;
303
- const level = this.getMeterLevel(
304
- progress,
305
- threshold,
306
- cfg.percentageLevels,
307
- );
308
-
309
- bonusMetersForBetAmount[key] = {
310
- ...bonusMetersForBetAmount[key],
311
- threshold,
312
- progress,
313
- level,
314
- };
315
- }
316
-
317
- return {
318
- publicState: {
319
- ...publicState,
320
- bonusMeters: bonusMetersForBetAmount,
321
- },
322
- privateState,
323
- };
324
- }
325
-
326
- default: {
327
- return {
328
- publicState,
329
- privateState,
330
- };
331
- }
332
- }
333
- }
334
-
335
- public cheatTriggerBonus(
336
- publicState: BonnysFortunePublicState,
337
- privateState: BonnysFortunePrivateState,
338
- params: CheatTriggerBonusRequestDto,
339
- ): CheatTriggerBonusResult {
340
- const bonusTrigger: BonusTrigger = {
341
- bonusId: UuidHelper.generateUuid(),
342
- bonusType: params.bonusType,
343
- betAmount: params.betAmount,
344
- };
345
-
346
- privateState.pendingBonuses.push(bonusTrigger);
347
-
348
- return {
349
- publicState,
350
- privateState,
351
- outcome: {
352
- triggeredBonus: bonusTrigger,
353
- },
354
- };
355
- }
356
-
357
- public cheatUpdateBonusMeterProgress(
358
- publicState: BonnysFortunePublicState,
359
- privateState: BonnysFortunePrivateState,
360
- params: CheatUpdateBonusMeterProgressRequestDto,
361
- gameLogicConfig: BonnysFortuneGameLogicConfigInterface,
362
- ): CheatUpdateBonusMeterProgressResult {
363
- const betAmount = publicState.currentBetAmount;
364
-
365
- const bonusMetersForBetAmount = privateState.bonusMetersByAmount[betAmount];
366
- if (!bonusMetersForBetAmount) {
367
- throw new Error(
368
- `Bet amount ${betAmount} is not in allowed thresholds`,
369
- );
370
- }
371
-
372
- const currentPrivateMeter = bonusMetersForBetAmount[params.bonusType];
373
-
374
- if (!currentPrivateMeter) {
375
- throw new Error(
376
- `Bonus meter ${params.bonusType} not found for bet amount ${betAmount}`,
377
- );
378
- }
379
-
380
- const meterConfig =
381
- gameLogicConfig.baseGame.bonusGameMeters[
382
- params.bonusType as keyof typeof gameLogicConfig.baseGame.bonusGameMeters
383
- ];
384
- if (!meterConfig) {
385
- throw new Error(`Config for bonus meter ${params.bonusType} not found`);
386
- }
387
-
388
- const newLevel = this.getMeterLevel(
389
- params.progress,
390
- currentPrivateMeter.threshold,
391
- meterConfig.percentageLevels,
392
- );
393
-
394
- const updatedMeter: MeterState = {
395
- ...currentPrivateMeter,
396
- progress: params.progress,
397
- level: newLevel,
398
- };
399
-
400
- privateState.bonusMetersByAmount[betAmount] = {
401
- ...bonusMetersForBetAmount,
402
- [params.bonusType]: updatedMeter,
403
- };
404
-
405
- publicState = {
406
- ...publicState,
407
- bonusMeters: {
408
- ...publicState.bonusMeters,
409
- [params.bonusType]: {
410
- ...publicState.bonusMeters[params.bonusType],
411
- progress: params.progress,
412
- level: newLevel,
413
- },
414
- },
415
- };
416
-
417
- return {
418
- publicState,
419
- privateState,
420
- outcome: {
421
- updatedMeter,
422
- },
423
- };
424
- }
425
-
426
- public getSymbols(
427
- gameLogicConfig: BonnysFortuneGameLogicConfigInterface,
428
- ): GetSymbolsResult {
429
- const symbols = gameLogicConfig.baseGame.symbolMultipliers.map(
430
- (symbol) => ({
431
- symbolId: symbol.symbolId,
432
- name: symbol.name,
433
- multipliers: symbol.multipliers,
434
- isWild: symbol.isWild,
435
- isScatter: symbol.isScatter,
436
- }),
437
- );
438
-
439
- return { symbols };
440
- }
441
-
442
- private shouldRedrawMeter(
443
- bonusType: string,
444
- gameLogicConfig: BonnysFortuneGameLogicConfigInterface,
445
- ): boolean {
446
- if (bonusType === 'collectFeature') {
447
- return false;
448
- }
449
-
450
- return bonusType in gameLogicConfig.baseGame.bonusGameMeters;
451
- }
452
-
453
- private requiresMeterUpdate(
454
- redrawKeys: string[],
455
- gameLogicConfig: BonnysFortuneGameLogicConfigInterface,
456
- ): boolean {
457
- return redrawKeys.some(
458
- (key) => key in gameLogicConfig.baseGame.bonusGameMeters,
459
- );
460
- }
461
-
462
- private getMeterLevel(
463
- progress: number,
464
- threshold: number,
465
- percentageLevels: Record<
466
- string,
467
- { min: number; max: number; value?: number }
468
- >,
469
- ): number {
470
- for (const [, range] of Object.entries(percentageLevels)) {
471
- const minValue = NumberHelper.safeMultiply(range.min, threshold, 4);
472
- const maxValue = NumberHelper.safeMultiply(range.max, threshold, 4);
473
-
474
- if (progress >= minValue && progress < maxValue) {
475
- return range.value ?? 0;
476
- }
477
- }
478
-
479
- return 5;
480
- }
481
-
482
- private async randomThreshold(
483
- min: number,
484
- max: number,
485
- commandId: string,
486
- actionId: string,
487
- ): Promise<{ value: number; seed: number }> {
488
- return this.rngService.getSingleNumber(min, max, commandId, actionId);
489
- }
490
- }