@omnitronix/happy-panda-game-engine 0.0.1

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 (71) hide show
  1. package/README.md +212 -0
  2. package/dist/__tests__/bonus-sequence.test.js +337 -0
  3. package/dist/__tests__/bonus-sequence.test.js.map +1 -0
  4. package/dist/__tests__/cherry-frequency.test.js +128 -0
  5. package/dist/__tests__/cherry-frequency.test.js.map +1 -0
  6. package/dist/__tests__/counter-manager.test.js +316 -0
  7. package/dist/__tests__/counter-manager.test.js.map +1 -0
  8. package/dist/__tests__/cpp-parity.test.js +368 -0
  9. package/dist/__tests__/cpp-parity.test.js.map +1 -0
  10. package/dist/__tests__/fixtures/cpp-parity-vectors.json +438 -0
  11. package/dist/__tests__/happy-panda-engine.test.js +367 -0
  12. package/dist/__tests__/happy-panda-engine.test.js.map +1 -0
  13. package/dist/__tests__/jackpot-manager.test.js +313 -0
  14. package/dist/__tests__/jackpot-manager.test.js.map +1 -0
  15. package/dist/__tests__/jackpot-trigger-trace.test.js +146 -0
  16. package/dist/__tests__/jackpot-trigger-trace.test.js.map +1 -0
  17. package/dist/__tests__/rtp-1million.test.js +156 -0
  18. package/dist/__tests__/rtp-1million.test.js.map +1 -0
  19. package/dist/__tests__/rtp-analysis.test.js +138 -0
  20. package/dist/__tests__/rtp-analysis.test.js.map +1 -0
  21. package/dist/__tests__/rtp-diagnostic.test.js +126 -0
  22. package/dist/__tests__/rtp-diagnostic.test.js.map +1 -0
  23. package/dist/__tests__/rtp-simulation.test.js +409 -0
  24. package/dist/__tests__/rtp-simulation.test.js.map +1 -0
  25. package/dist/__tests__/special-wins.test.js +179 -0
  26. package/dist/__tests__/special-wins.test.js.map +1 -0
  27. package/dist/__tests__/spin-generator.test.js +250 -0
  28. package/dist/__tests__/spin-generator.test.js.map +1 -0
  29. package/dist/__tests__/spin-handler.test.js +210 -0
  30. package/dist/__tests__/spin-handler.test.js.map +1 -0
  31. package/dist/__tests__/symbol-distribution.test.js +119 -0
  32. package/dist/__tests__/symbol-distribution.test.js.map +1 -0
  33. package/dist/__tests__/weighted-random.test.js +165 -0
  34. package/dist/__tests__/weighted-random.test.js.map +1 -0
  35. package/dist/__tests__/win-evaluator.test.js +254 -0
  36. package/dist/__tests__/win-evaluator.test.js.map +1 -0
  37. package/dist/config/happy-panda.config.js +714 -0
  38. package/dist/config/happy-panda.config.js.map +1 -0
  39. package/dist/config/index.js +21 -0
  40. package/dist/config/index.js.map +1 -0
  41. package/dist/domain/index.js +21 -0
  42. package/dist/domain/index.js.map +1 -0
  43. package/dist/domain/types.js +28 -0
  44. package/dist/domain/types.js.map +1 -0
  45. package/dist/engine/happy-panda-engine.js +197 -0
  46. package/dist/engine/happy-panda-engine.js.map +1 -0
  47. package/dist/engine/index.js +21 -0
  48. package/dist/engine/index.js.map +1 -0
  49. package/dist/index.js +34 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/logic/handlers/index.js +21 -0
  52. package/dist/logic/handlers/index.js.map +1 -0
  53. package/dist/logic/handlers/spin-handler.js +256 -0
  54. package/dist/logic/handlers/spin-handler.js.map +1 -0
  55. package/dist/logic/index.js +22 -0
  56. package/dist/logic/index.js.map +1 -0
  57. package/dist/logic/services/counter-manager.js +265 -0
  58. package/dist/logic/services/counter-manager.js.map +1 -0
  59. package/dist/logic/services/index.js +23 -0
  60. package/dist/logic/services/index.js.map +1 -0
  61. package/dist/logic/services/jackpot-manager.js +142 -0
  62. package/dist/logic/services/jackpot-manager.js.map +1 -0
  63. package/dist/logic/services/win-evaluator.js +470 -0
  64. package/dist/logic/services/win-evaluator.js.map +1 -0
  65. package/dist/rng/index.js +22 -0
  66. package/dist/rng/index.js.map +1 -0
  67. package/dist/rng/spin-generator.js +341 -0
  68. package/dist/rng/spin-generator.js.map +1 -0
  69. package/dist/rng/weighted-random.js +58 -0
  70. package/dist/rng/weighted-random.js.map +1 -0
  71. package/package.json +49 -0
@@ -0,0 +1,714 @@
1
+ "use strict";
2
+ /**
3
+ * Happy Panda Game Engine Configuration
4
+ *
5
+ * Extracted from CherryMaster_A_2.cpp math model.
6
+ * 3x3 slot with 8/16 bidirectional paylines.
7
+ *
8
+ * Game Modes:
9
+ * - gameDirection=0: 8 lines, single direction, min bet = 8
10
+ * - gameDirection=1: 16 lines, both directions, min bet = 16
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.FRUIT_SYMBOLS = exports.BAR_MIX_SYMBOLS = exports.BAR_SYMBOLS = exports.RESPIN_CHERRY_LIMITATION_WEIGHTS = exports.RESPIN_CHERRY_WEIGHTS = exports.RESPIN_CHERRY_SYMBOLS = exports.BAR1_BONUS_3X3_SYMBOL_WEIGHTS = exports.BAR1_BONUS_3X3_WEIGHTS = exports.BAR1_BONUS_LIMITATION_WEIGHTS = exports.BAR1_BONUS_WEIGHTS = exports.BAR1_BONUS_SYMBOLS = exports.BELL_BONUS_3X3_SYMBOL_WEIGHTS = exports.BELL_BONUS_3X3_WEIGHTS = exports.BELL_BONUS_LIMITATION_WEIGHTS = exports.BELL_BONUS_WEIGHTS = exports.BELL_BONUS_SYMBOLS = exports.CHERRY_BONUS_3X3_SYMBOL_WEIGHTS = exports.CHERRY_BONUS_3X3_WEIGHTS = exports.CHERRY_BONUS_LIMITATION_WEIGHTS = exports.CHERRY_BONUS_WEIGHTS = exports.CHERRY_BONUS_SYMBOLS = exports.JACKPOT_BONUS_3X3_SYMBOL_WEIGHTS = exports.JACKPOT_BONUS_3X3_WEIGHTS = exports.JACKPOT_BONUS_LIMITATION_WEIGHTS = exports.JACKPOT_BONUS_WEIGHTS = exports.JACKPOT_BONUS_SYMBOLS = exports.PAID_SPIN_3X3_SYMBOL_WEIGHTS = exports.PAID_SPIN_3X3_WEIGHTS = exports.PAID_SPIN_LIMITATION_WEIGHTS = exports.LIMITATION_TIERS = exports.PAID_SPIN_SYMBOLS = exports.PAID_SPIN_WEIGHTS = exports.RESPIN_CHERRY = exports.BONUS_BAR1 = exports.BONUS_BELL = exports.BONUS_CHERRY = exports.POOL_JACKPOT = exports.BONUS_JACKPOT = exports.SPECIAL_WIN_MULTIPLIERS = exports.SUPER_SEVEN_MULTIPLIER = exports.SEVEN_MIN_COUNT = exports.SEVEN_SCATTER_MULTIPLIERS = exports.WALL_MULTIPLIERS = exports.LINES_PER_DIRECTION = exports.LINE_SHAPES = exports.LINE_MULTIPLIERS = exports.GRID = exports.ScreenWinType = exports.SpinType = exports.Symbol = void 0;
14
+ exports.CHERRY_SYMBOLS = exports.SEVEN_SYMBOLS = exports.COLOR_SYMBOLS = void 0;
15
+ // =============================================================================
16
+ // SYMBOL DEFINITIONS
17
+ // =============================================================================
18
+ var Symbol;
19
+ (function (Symbol) {
20
+ Symbol[Symbol["NONE"] = -1] = "NONE";
21
+ // Base symbols (0-10)
22
+ Symbol[Symbol["SUPER_SEVEN"] = 0] = "SUPER_SEVEN";
23
+ Symbol[Symbol["SEVEN"] = 1] = "SEVEN";
24
+ Symbol[Symbol["BAR3"] = 2] = "BAR3";
25
+ Symbol[Symbol["BAR2"] = 3] = "BAR2";
26
+ Symbol[Symbol["BAR1"] = 4] = "BAR1";
27
+ Symbol[Symbol["MELON"] = 5] = "MELON";
28
+ Symbol[Symbol["BELL"] = 6] = "BELL";
29
+ Symbol[Symbol["PRUNE"] = 7] = "PRUNE";
30
+ Symbol[Symbol["ORANGE"] = 8] = "ORANGE";
31
+ Symbol[Symbol["CHERRY"] = 9] = "CHERRY";
32
+ Symbol[Symbol["SUPER_CHERRY"] = 10] = "SUPER_CHERRY";
33
+ // Special symbols
34
+ Symbol[Symbol["SUPER_BAR"] = 11] = "SUPER_BAR";
35
+ Symbol[Symbol["BAR_ANY"] = 25] = "BAR_ANY";
36
+ // Cherry pieces (Jackpot Bonus only)
37
+ Symbol[Symbol["CHERRY_00"] = 12] = "CHERRY_00";
38
+ Symbol[Symbol["CHERRY_01"] = 13] = "CHERRY_01";
39
+ Symbol[Symbol["CHERRY_02"] = 14] = "CHERRY_02";
40
+ Symbol[Symbol["CHERRY_10"] = 15] = "CHERRY_10";
41
+ Symbol[Symbol["CHERRY_11"] = 16] = "CHERRY_11";
42
+ Symbol[Symbol["CHERRY_12"] = 17] = "CHERRY_12";
43
+ Symbol[Symbol["CHERRY_20"] = 18] = "CHERRY_20";
44
+ Symbol[Symbol["CHERRY_21"] = 19] = "CHERRY_21";
45
+ Symbol[Symbol["CHERRY_22"] = 20] = "CHERRY_22";
46
+ // Colors (bonus indicators)
47
+ Symbol[Symbol["COLOR_YELLOW"] = 21] = "COLOR_YELLOW";
48
+ Symbol[Symbol["COLOR_RED"] = 22] = "COLOR_RED";
49
+ Symbol[Symbol["COLOR_GREEN"] = 23] = "COLOR_GREEN";
50
+ Symbol[Symbol["COLOR_BLUE"] = 24] = "COLOR_BLUE";
51
+ })(Symbol || (exports.Symbol = Symbol = {}));
52
+ var SpinType;
53
+ (function (SpinType) {
54
+ SpinType[SpinType["PAID_SPIN"] = 0] = "PAID_SPIN";
55
+ SpinType[SpinType["BONUS_JACKPOT"] = 1] = "BONUS_JACKPOT";
56
+ SpinType[SpinType["BONUS_CHERRY"] = 2] = "BONUS_CHERRY";
57
+ SpinType[SpinType["BONUS_BELL"] = 3] = "BONUS_BELL";
58
+ SpinType[SpinType["BONUS_BAR1"] = 4] = "BONUS_BAR1";
59
+ SpinType[SpinType["RESPIN_CHERRY"] = 5] = "RESPIN_CHERRY";
60
+ })(SpinType || (exports.SpinType = SpinType = {}));
61
+ var ScreenWinType;
62
+ (function (ScreenWinType) {
63
+ ScreenWinType[ScreenWinType["NOTHING"] = -1] = "NOTHING";
64
+ // Scatter wins (2-9 symbols)
65
+ ScreenWinType[ScreenWinType["SCREEN_SUPER_SEVEN"] = 0] = "SCREEN_SUPER_SEVEN";
66
+ ScreenWinType[ScreenWinType["SCREEN_SEVEN"] = 1] = "SCREEN_SEVEN";
67
+ // Wall wins (3x3 full screen)
68
+ ScreenWinType[ScreenWinType["SCREEN_BAR3"] = 2] = "SCREEN_BAR3";
69
+ ScreenWinType[ScreenWinType["SCREEN_BAR2"] = 3] = "SCREEN_BAR2";
70
+ ScreenWinType[ScreenWinType["SCREEN_BAR1"] = 4] = "SCREEN_BAR1";
71
+ ScreenWinType[ScreenWinType["SCREEN_MELON"] = 5] = "SCREEN_MELON";
72
+ ScreenWinType[ScreenWinType["SCREEN_BELL"] = 6] = "SCREEN_BELL";
73
+ ScreenWinType[ScreenWinType["SCREEN_PRUNE"] = 7] = "SCREEN_PRUNE";
74
+ ScreenWinType[ScreenWinType["SCREEN_ORANGE"] = 8] = "SCREEN_ORANGE";
75
+ ScreenWinType[ScreenWinType["SCREEN_CHERRY"] = 9] = "SCREEN_CHERRY";
76
+ ScreenWinType[ScreenWinType["SCREEN_BAR_ANY"] = 10] = "SCREEN_BAR_ANY";
77
+ ScreenWinType[ScreenWinType["SCREEN_FRUIT_ANY"] = 11] = "SCREEN_FRUIT_ANY";
78
+ ScreenWinType[ScreenWinType["SCREEN_COLOR_ANY"] = 12] = "SCREEN_COLOR_ANY";
79
+ // Special wins
80
+ ScreenWinType[ScreenWinType["SCREEN_CHERRY_PIECES"] = 13] = "SCREEN_CHERRY_PIECES";
81
+ ScreenWinType[ScreenWinType["SCREEN_BELL_SCATTER"] = 14] = "SCREEN_BELL_SCATTER";
82
+ ScreenWinType[ScreenWinType["SCREEN_SUPER_BAR"] = 15] = "SCREEN_SUPER_BAR";
83
+ })(ScreenWinType || (exports.ScreenWinType = ScreenWinType = {}));
84
+ // =============================================================================
85
+ // GRID CONFIGURATION
86
+ // =============================================================================
87
+ exports.GRID = {
88
+ REELS: 3,
89
+ ROWS: 3,
90
+ POSITIONS: 9,
91
+ };
92
+ // =============================================================================
93
+ // LINE CONFIGURATION
94
+ // =============================================================================
95
+ /**
96
+ * Line pay table: [symbol][matchCount] = multiplier
97
+ * matchCount: 0=x1, 1=x2, 2=x3
98
+ * Values are multiplied by line bet
99
+ */
100
+ exports.LINE_MULTIPLIERS = [
101
+ // x1, x2, x3 - exact xlsx values (LinesMulti)
102
+ [0, 0, 150], // Super Seven
103
+ [0, 0, 100], // Seven
104
+ [0, 0, 80], // BAR3
105
+ [0, 0, 50], // BAR2
106
+ [0, 0, 30], // BAR1
107
+ [0, 0, 20], // Melon
108
+ [0, 0, 18], // Bell
109
+ [0, 0, 14], // Prune
110
+ [0, 0, 10], // Orange
111
+ [2, 5, 10], // Cherry (pays for 1, 2, or 3)
112
+ [0, 0, 10], // Any Bar (mixed BAR3/BAR2/BAR1)
113
+ ];
114
+ /**
115
+ * 16 payline definitions: [lineIdx][positionIdx] = [reel, row]
116
+ * Lines 0-7: forward direction
117
+ * Lines 8-15: reverse direction (for 16-line mode)
118
+ */
119
+ exports.LINE_SHAPES = [
120
+ // Forward direction (8 lines)
121
+ [[0, 0], [1, 0], [2, 0]], // Line 0: Top row
122
+ [[0, 1], [1, 1], [2, 1]], // Line 1: Middle row
123
+ [[0, 2], [1, 2], [2, 2]], // Line 2: Bottom row
124
+ [[0, 0], [0, 1], [0, 2]], // Line 3: Left column
125
+ [[1, 0], [1, 1], [1, 2]], // Line 4: Center column
126
+ [[2, 0], [2, 1], [2, 2]], // Line 5: Right column
127
+ [[0, 0], [1, 1], [2, 2]], // Line 6: Diagonal TL-BR
128
+ [[0, 2], [1, 1], [2, 0]], // Line 7: Diagonal BL-TR
129
+ // Reverse direction (8 lines)
130
+ [[2, 0], [1, 0], [0, 0]], // Line 8: Top row reversed
131
+ [[2, 1], [1, 1], [0, 1]], // Line 9: Middle row reversed
132
+ [[2, 2], [1, 2], [0, 2]], // Line 10: Bottom row reversed
133
+ [[0, 2], [0, 1], [0, 0]], // Line 11: Left column reversed
134
+ [[1, 2], [1, 1], [1, 0]], // Line 12: Center column reversed
135
+ [[2, 2], [2, 1], [2, 0]], // Line 13: Right column reversed
136
+ [[2, 2], [1, 1], [0, 0]], // Line 14: Diagonal BR-TL
137
+ [[2, 0], [1, 1], [0, 2]], // Line 15: Diagonal TR-BL
138
+ ];
139
+ exports.LINES_PER_DIRECTION = [8, 16];
140
+ // =============================================================================
141
+ // WALL (3x3) WINS
142
+ // =============================================================================
143
+ /**
144
+ * Wall win multipliers: [wallType] = multiplier x bet_game
145
+ * Order matches ScreenMulti in C++ EXACTLY
146
+ */
147
+ exports.WALL_MULTIPLIERS = [
148
+ 500, // BAR3 - exact xlsx value (ScreenMulti)
149
+ 400, // BAR2
150
+ 300, // BAR1
151
+ 300, // Melon
152
+ 200, // Bell
153
+ 100, // Prune
154
+ 50, // Orange
155
+ 400, // Cherry
156
+ 50, // Any Bar (mixed)
157
+ 15, // All Fruits
158
+ 50, // All Colors
159
+ ];
160
+ // =============================================================================
161
+ // SCATTER (SEVEN) WINS
162
+ // =============================================================================
163
+ /**
164
+ * Seven/Super Seven scatter pay table: [count-2] = multiplier x bet_game
165
+ * Pays for 2-9 matching Seven/Super Seven symbols
166
+ * Matches SevenSuperMulti in C++ EXACTLY
167
+ */
168
+ exports.SEVEN_SCATTER_MULTIPLIERS = [
169
+ 1000, // x9 - exact xlsx value (SevenSuperMulti)
170
+ 400, // x8
171
+ 200, // x7
172
+ 100, // x6
173
+ 50, // x5
174
+ 20, // x4
175
+ 5, // x3
176
+ 2, // x2
177
+ ];
178
+ exports.SEVEN_MIN_COUNT = 2;
179
+ exports.SUPER_SEVEN_MULTIPLIER = 2; // Double win if all Super Sevens
180
+ // =============================================================================
181
+ // SPECIAL WINS (Bonus-specific)
182
+ // =============================================================================
183
+ /**
184
+ * Special win multipliers: [gameDirection][type] = multiplier x line
185
+ * type: 0=cherry pieces, 1=bell scatter, 2=super bar scatter
186
+ * Matches SpecialWins in C++ EXACTLY
187
+ */
188
+ exports.SPECIAL_WIN_MULTIPLIERS = [
189
+ [100, 10, 10], // 8 lines - C++ SpecialWins[0]
190
+ [200, 20, 20], // 16 lines - C++ SpecialWins[1]
191
+ ];
192
+ // =============================================================================
193
+ // JACKPOT CONFIGURATION
194
+ // =============================================================================
195
+ exports.BONUS_JACKPOT = {
196
+ /** Initial jackpot value: multiplier x bet_game */
197
+ INIT: 100,
198
+ /** Maximum jackpot value: multiplier x bet_game */
199
+ MAX: 1000,
200
+ /** Probability weights to increment jackpot on losing spin: [gameDir][yes,no] */
201
+ INCREMENT_WEIGHTS: [
202
+ [3, 10], // 8 lines: 3/13 chance to increase
203
+ [3, 10], // 16 lines: 3/13 chance to increase
204
+ ],
205
+ /** Increment amount: [gameDir] x bet_stake */
206
+ INCREMENT_VALUE: [1, 2],
207
+ /** Counter starts at (always 1 - triggers on 3x cherry line) */
208
+ COUNTER_INIT: 1,
209
+ /** Free spins awarded */
210
+ SPINS: 1,
211
+ /** Additional win on jackpot: multiplier x bet_game */
212
+ ADD_WIN: 5,
213
+ };
214
+ // =============================================================================
215
+ // POOL JACKPOT CONFIGURATION
216
+ // =============================================================================
217
+ exports.POOL_JACKPOT = {
218
+ /** Initial pool value */
219
+ INIT: 0,
220
+ /** Maximum pool value: multiplier x bet_game */
221
+ MAX: 250,
222
+ /** Increment values: [gameDir][superSeven, seven] x bet_line */
223
+ INCREMENT: [
224
+ [10, 5], // 8 lines
225
+ [10, 5], // 16 lines
226
+ ],
227
+ };
228
+ // =============================================================================
229
+ // CHERRY BONUS CONFIGURATION
230
+ // =============================================================================
231
+ exports.BONUS_CHERRY = {
232
+ /** Counter initial values (randomly chosen) */
233
+ COUNTER_INIT: [6, 9],
234
+ /** Weights for choosing initial counter: [gameDir][weight_for_6, weight_for_9] */
235
+ COUNTER_INIT_WEIGHTS: [
236
+ [5, 5], // 8 lines: 50/50
237
+ [5, 5], // 16 lines: 50/50
238
+ ],
239
+ /** Free spins awarded */
240
+ SPINS: 1,
241
+ };
242
+ // =============================================================================
243
+ // BELL BONUS CONFIGURATION
244
+ // =============================================================================
245
+ exports.BONUS_BELL = {
246
+ /** Counter initial values (randomly chosen) */
247
+ COUNTER_INIT: [3, 5],
248
+ /** Weights for choosing initial counter: [gameDir][weight_for_3, weight_for_5] */
249
+ COUNTER_INIT_WEIGHTS: [
250
+ [5, 5], // 8 lines: 50/50
251
+ [5, 5], // 16 lines: 50/50
252
+ ],
253
+ /** Free spins awarded */
254
+ SPINS: 5,
255
+ };
256
+ // =============================================================================
257
+ // BAR1 BONUS CONFIGURATION
258
+ // =============================================================================
259
+ exports.BONUS_BAR1 = {
260
+ /** Counter starts at (always 1) */
261
+ COUNTER_INIT: 1,
262
+ /** Free spins awarded */
263
+ SPINS: 7,
264
+ };
265
+ // =============================================================================
266
+ // CENTER CHERRY RESPIN CONFIGURATION
267
+ // =============================================================================
268
+ exports.RESPIN_CHERRY = {
269
+ /** Spins awarded: [Cherry, Super Cherry] */
270
+ SPINS: [1, 2],
271
+ };
272
+ // =============================================================================
273
+ // PAID SPIN SYMBOL WEIGHTS
274
+ // =============================================================================
275
+ /**
276
+ * Symbol weights for paid spins: [gameDirection][position][symbol]
277
+ * Position order: (0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), (2,2)
278
+ * Symbol order: SEV_S, SEV, BA3, BA2, BA1, ME, BE, PR, OR, CH, CH_S
279
+ */
280
+ exports.PAID_SPIN_WEIGHTS = [
281
+ // gameDirection == 0 (8 lines)
282
+ [
283
+ [1, 3, 3, 6, 10, 26, 2, 16, 36, 4, 0], // (0,0)
284
+ [1, 2, 3, 6, 3, 6, 35, 35, 5, 1, 0], // (0,1)
285
+ [1, 3, 3, 6, 10, 26, 2, 16, 36, 5, 0], // (0,2)
286
+ [1, 2, 3, 6, 3, 6, 35, 35, 5, 1, 4], // (1,0)
287
+ [1, 5, 3, 6, 10, 26, 2, 16, 36, 3, 2], // (1,1) center
288
+ [1, 2, 3, 6, 3, 6, 35, 35, 5, 1, 4], // (1,2)
289
+ [1, 3, 3, 6, 10, 26, 2, 16, 36, 6, 0], // (2,0)
290
+ [1, 2, 3, 6, 3, 6, 35, 35, 5, 1, 0], // (2,1)
291
+ [1, 3, 3, 6, 10, 26, 2, 16, 36, 4, 0], // (2,2)
292
+ ],
293
+ // gameDirection == 1 (16 lines)
294
+ [
295
+ [1, 3, 3, 6, 10, 26, 2, 16, 36, 4, 0], // (0,0)
296
+ [1, 2, 3, 6, 3, 6, 35, 35, 5, 1, 0], // (0,1)
297
+ [1, 3, 3, 6, 10, 26, 2, 16, 36, 4, 0], // (0,2)
298
+ [1, 2, 3, 6, 3, 6, 35, 35, 5, 1, 4], // (1,0)
299
+ [1, 5, 3, 6, 10, 26, 2, 16, 36, 4, 1], // (1,1) center
300
+ [1, 2, 3, 6, 3, 6, 35, 35, 5, 1, 4], // (1,2)
301
+ [1, 3, 3, 6, 10, 26, 2, 16, 36, 5, 0], // (2,0)
302
+ [1, 2, 3, 6, 3, 6, 35, 35, 5, 1, 0], // (2,1)
303
+ [1, 3, 3, 6, 10, 26, 2, 16, 36, 4, 0], // (2,2)
304
+ ],
305
+ ];
306
+ /**
307
+ * Active symbol indices for paid spins
308
+ */
309
+ exports.PAID_SPIN_SYMBOLS = [
310
+ Symbol.SUPER_SEVEN,
311
+ Symbol.SEVEN,
312
+ Symbol.BAR3,
313
+ Symbol.BAR2,
314
+ Symbol.BAR1,
315
+ Symbol.MELON,
316
+ Symbol.BELL,
317
+ Symbol.PRUNE,
318
+ Symbol.ORANGE,
319
+ Symbol.CHERRY,
320
+ Symbol.SUPER_CHERRY,
321
+ ];
322
+ // =============================================================================
323
+ // SYMBOL LIMITATION SYSTEM
324
+ // =============================================================================
325
+ /**
326
+ * Limitation tiers: maximum symbols of same type allowed
327
+ */
328
+ exports.LIMITATION_TIERS = [2, 4, 7, 9];
329
+ /**
330
+ * Limitation weights for paid spins: [gameDirection][symbol][tier]
331
+ * Tier order: max2, max4, max7, max9
332
+ */
333
+ exports.PAID_SPIN_LIMITATION_WEIGHTS = [
334
+ // gameDirection == 0 (8 lines)
335
+ [
336
+ [9, 2, 1, 1], // SEV_S
337
+ [8, 3, 1, 1], // SEV
338
+ [8, 1, 1, 1], // BA3
339
+ [8, 1, 1, 1], // BA2
340
+ [8, 2, 1, 1], // BA1
341
+ [7, 3, 1, 1], // ME
342
+ [5, 3, 1, 1], // BE
343
+ [6, 2, 1, 1], // PR
344
+ [5, 2, 1, 1], // OR
345
+ [5, 1, 1, 1], // CH
346
+ [5, 1, 0, 0], // CH_S (max 4 only)
347
+ ],
348
+ // gameDirection == 1 (16 lines)
349
+ [
350
+ [9, 2, 1, 1], // SEV_S
351
+ [8, 3, 1, 1], // SEV
352
+ [8, 1, 1, 1], // BA3
353
+ [8, 1, 1, 1], // BA2
354
+ [8, 2, 1, 1], // BA1
355
+ [7, 3, 1, 1], // ME
356
+ [5, 3, 1, 1], // BE
357
+ [6, 2, 1, 1], // PR
358
+ [5, 2, 1, 1], // OR
359
+ [5, 1, 1, 1], // CH
360
+ [5, 1, 0, 0], // CH_S (max 4 only)
361
+ ],
362
+ ];
363
+ // =============================================================================
364
+ // 3x3 WIN PROBABILITY
365
+ // =============================================================================
366
+ /**
367
+ * Probability weights for 3x3 wall wins: [gameDirection][yes, no]
368
+ */
369
+ exports.PAID_SPIN_3X3_WEIGHTS = [
370
+ [3, 193], // 8 lines: 3/196 chance
371
+ [3, 198], // 16 lines: 3/201 chance
372
+ ];
373
+ /**
374
+ * Weights for which symbol creates 3x3 win
375
+ * Order: SEV_S, SEV, BA3, BA2, BA1, ME, BE, PR, OR, CH, CH_S
376
+ */
377
+ exports.PAID_SPIN_3X3_SYMBOL_WEIGHTS = [
378
+ 1, 1, 3, 4, 1, 8, 1, 20, 24, 1, 0,
379
+ ];
380
+ // =============================================================================
381
+ // JACKPOT BONUS WEIGHTS
382
+ // =============================================================================
383
+ exports.JACKPOT_BONUS_SYMBOLS = [
384
+ Symbol.SUPER_SEVEN,
385
+ Symbol.SEVEN,
386
+ Symbol.BAR3,
387
+ Symbol.BAR2,
388
+ Symbol.BAR1,
389
+ Symbol.CHERRY_00, // Cherry pieces (all 9 use same weight)
390
+ Symbol.COLOR_YELLOW,
391
+ ];
392
+ exports.JACKPOT_BONUS_WEIGHTS = [
393
+ // gameDirection == 0
394
+ [
395
+ [5, 5, 1, 1, 1, 95, 35], // All 9 positions same
396
+ [5, 5, 1, 1, 1, 95, 35],
397
+ [5, 5, 1, 1, 1, 95, 35],
398
+ [5, 5, 1, 1, 1, 95, 35],
399
+ [5, 5, 1, 1, 1, 95, 35],
400
+ [5, 5, 1, 1, 1, 95, 35],
401
+ [5, 5, 1, 1, 1, 95, 35],
402
+ [5, 5, 1, 1, 1, 95, 35],
403
+ [5, 5, 1, 1, 1, 95, 35],
404
+ ],
405
+ // gameDirection == 1
406
+ [
407
+ [5, 5, 1, 1, 1, 95, 35],
408
+ [5, 5, 1, 1, 1, 95, 35],
409
+ [5, 5, 1, 1, 1, 95, 35],
410
+ [5, 5, 1, 1, 1, 95, 35],
411
+ [5, 5, 1, 1, 1, 95, 35],
412
+ [5, 5, 1, 1, 1, 95, 35],
413
+ [5, 5, 1, 1, 1, 95, 35],
414
+ [5, 5, 1, 1, 1, 95, 35],
415
+ [5, 5, 1, 1, 1, 95, 35],
416
+ ],
417
+ ];
418
+ exports.JACKPOT_BONUS_LIMITATION_WEIGHTS = [
419
+ // gameDirection == 0
420
+ [
421
+ [5, 1, 1, 9], // SEV_S
422
+ [5, 1, 1, 9], // SEV
423
+ [5, 1, 1, 0], // BA3
424
+ [5, 1, 1, 0], // BA2
425
+ [5, 1, 1, 0], // BA1
426
+ [0, 0, 0, 5], // CH_00 (cherry pieces - max 9 only)
427
+ [5, 5, 5, 5], // CO_Y
428
+ ],
429
+ // gameDirection == 1
430
+ [
431
+ [5, 1, 1, 9], // SEV_S
432
+ [5, 1, 1, 9], // SEV
433
+ [5, 1, 1, 0], // BA3
434
+ [5, 1, 1, 0], // BA2
435
+ [5, 1, 1, 0], // BA1
436
+ [0, 0, 0, 5], // CH_00
437
+ [5, 5, 5, 5], // CO_Y
438
+ ],
439
+ ];
440
+ // C++ BonusJackpot3x3 EXACTLY - 25% 3x3 rate
441
+ exports.JACKPOT_BONUS_3X3_WEIGHTS = [
442
+ [3, 9], // 8 lines - C++ BonusJackpot3x3[0] = 25%
443
+ [3, 9], // 16 lines - C++ BonusJackpot3x3[1] = 25%
444
+ ];
445
+ exports.JACKPOT_BONUS_3X3_SYMBOL_WEIGHTS = [0, 0, 0, 0, 0, 8, 6];
446
+ // =============================================================================
447
+ // CHERRY BONUS WEIGHTS
448
+ // =============================================================================
449
+ exports.CHERRY_BONUS_SYMBOLS = [
450
+ Symbol.SUPER_SEVEN,
451
+ Symbol.SEVEN,
452
+ Symbol.BAR3,
453
+ Symbol.BAR2,
454
+ Symbol.BAR1,
455
+ Symbol.CHERRY,
456
+ Symbol.COLOR_RED,
457
+ ];
458
+ exports.CHERRY_BONUS_WEIGHTS = [
459
+ // gameDirection == 0
460
+ [
461
+ [3, 5, 5, 5, 5, 5, 5], // (0,0)
462
+ [3, 5, 5, 5, 5, 5, 5], // (0,1)
463
+ [3, 5, 5, 5, 5, 5, 5], // (0,2)
464
+ [4, 5, 5, 5, 5, 5, 5], // (1,0)
465
+ [3, 5, 5, 5, 5, 5, 5], // (1,1)
466
+ [4, 5, 5, 5, 5, 5, 5], // (1,2)
467
+ [3, 5, 5, 5, 5, 5, 5], // (2,0)
468
+ [3, 5, 5, 5, 5, 5, 5], // (2,1)
469
+ [3, 5, 5, 5, 5, 5, 5], // (2,2)
470
+ ],
471
+ // gameDirection == 1
472
+ [
473
+ [3, 5, 5, 5, 5, 5, 5],
474
+ [3, 5, 5, 5, 5, 5, 5],
475
+ [3, 5, 5, 5, 5, 5, 5],
476
+ [4, 5, 5, 5, 5, 5, 5],
477
+ [3, 5, 5, 5, 5, 5, 5],
478
+ [4, 5, 5, 5, 5, 5, 5],
479
+ [3, 5, 5, 5, 5, 5, 5],
480
+ [3, 5, 5, 5, 5, 5, 5],
481
+ [3, 5, 5, 5, 5, 5, 5],
482
+ ],
483
+ ];
484
+ exports.CHERRY_BONUS_LIMITATION_WEIGHTS = [
485
+ // gameDirection == 0
486
+ [
487
+ [5, 1, 1, 2], // SEV_S
488
+ [5, 1, 1, 2], // SEV
489
+ [5, 2, 1, 1], // BA3
490
+ [5, 2, 1, 1], // BA2
491
+ [5, 2, 1, 1], // BA1
492
+ [5, 2, 1, 1], // CH
493
+ [5, 5, 9, 9], // CO_R
494
+ ],
495
+ // gameDirection == 1
496
+ [
497
+ [5, 1, 1, 2], // SEV_S
498
+ [5, 1, 1, 2], // SEV
499
+ [5, 2, 1, 1], // BA3
500
+ [5, 2, 1, 1], // BA2
501
+ [5, 2, 1, 1], // BA1
502
+ [5, 2, 1, 1], // CH
503
+ [5, 5, 9, 9], // CO_R
504
+ ],
505
+ ];
506
+ // C++ BonusCherry3x3 EXACTLY - 10% 3x3 rate
507
+ exports.CHERRY_BONUS_3X3_WEIGHTS = [
508
+ [1, 9], // 8 lines - C++ BonusCherry3x3[0] = 10%
509
+ [1, 9], // 16 lines - C++ BonusCherry3x3[1] = 10%
510
+ ];
511
+ exports.CHERRY_BONUS_3X3_SYMBOL_WEIGHTS = [0, 0, 0, 0, 0, 7, 6];
512
+ // =============================================================================
513
+ // BELL BONUS WEIGHTS
514
+ // =============================================================================
515
+ exports.BELL_BONUS_SYMBOLS = [
516
+ Symbol.SUPER_SEVEN,
517
+ Symbol.SEVEN,
518
+ Symbol.BAR3,
519
+ Symbol.BAR2,
520
+ Symbol.BAR1,
521
+ Symbol.BELL,
522
+ Symbol.COLOR_GREEN,
523
+ ];
524
+ exports.BELL_BONUS_WEIGHTS = [
525
+ // gameDirection == 0
526
+ [
527
+ [5, 7, 2, 2, 2, 15, 9], // All positions same
528
+ [5, 7, 2, 2, 2, 15, 9],
529
+ [5, 7, 2, 2, 2, 15, 9],
530
+ [5, 7, 2, 2, 2, 15, 9],
531
+ [5, 7, 2, 2, 2, 15, 9],
532
+ [5, 7, 2, 2, 2, 15, 9],
533
+ [5, 7, 2, 2, 2, 15, 9],
534
+ [5, 7, 2, 2, 2, 15, 9],
535
+ [5, 7, 2, 2, 2, 15, 9],
536
+ ],
537
+ // gameDirection == 1
538
+ [
539
+ [5, 7, 2, 2, 2, 15, 9],
540
+ [5, 7, 2, 2, 2, 15, 9],
541
+ [5, 7, 2, 2, 2, 15, 9],
542
+ [5, 7, 2, 2, 2, 15, 9],
543
+ [5, 7, 2, 2, 2, 15, 9],
544
+ [5, 7, 2, 2, 2, 15, 9],
545
+ [5, 7, 2, 2, 2, 15, 9],
546
+ [5, 7, 2, 2, 2, 15, 9],
547
+ [5, 7, 2, 2, 2, 15, 9],
548
+ ],
549
+ ];
550
+ exports.BELL_BONUS_LIMITATION_WEIGHTS = [
551
+ // gameDirection == 0
552
+ [
553
+ [3, 1, 1, 1], // SEV_S
554
+ [3, 1, 1, 1], // SEV
555
+ [2, 1, 1, 1], // BA3
556
+ [2, 1, 1, 1], // BA2
557
+ [2, 1, 1, 1], // BA1
558
+ [0, 0, 5, 5], // BE (min 7 symbols)
559
+ [0, 0, 5, 5], // CO_G
560
+ ],
561
+ // gameDirection == 1
562
+ [
563
+ [3, 1, 1, 1], // SEV_S
564
+ [3, 1, 1, 1], // SEV
565
+ [2, 1, 1, 1], // BA3
566
+ [2, 1, 1, 1], // BA2
567
+ [2, 1, 1, 1], // BA1
568
+ [0, 0, 5, 5], // BE
569
+ [0, 0, 5, 5], // CO_G
570
+ ],
571
+ ];
572
+ // C++ BonusBell3x3 EXACTLY - 18.2% 3x3 rate
573
+ exports.BELL_BONUS_3X3_WEIGHTS = [
574
+ [2, 9], // 8 lines - C++ BonusBell3x3[0] = 18.2%
575
+ [2, 9], // 16 lines - C++ BonusBell3x3[1] = 18.2%
576
+ ];
577
+ exports.BELL_BONUS_3X3_SYMBOL_WEIGHTS = [0, 0, 0, 0, 0, 7, 6];
578
+ // =============================================================================
579
+ // BAR1 BONUS WEIGHTS
580
+ // =============================================================================
581
+ exports.BAR1_BONUS_SYMBOLS = [
582
+ Symbol.SUPER_SEVEN,
583
+ Symbol.SEVEN,
584
+ Symbol.BAR3,
585
+ Symbol.BAR2,
586
+ Symbol.BAR1,
587
+ Symbol.SUPER_BAR,
588
+ Symbol.COLOR_BLUE,
589
+ ];
590
+ exports.BAR1_BONUS_WEIGHTS = [
591
+ // gameDirection == 0
592
+ [
593
+ [2, 3, 2, 2, 3, 12, 15], // (0,0)
594
+ [2, 3, 2, 2, 3, 12, 15], // (0,1)
595
+ [2, 3, 2, 2, 3, 12, 15], // (0,2)
596
+ [2, 4, 2, 3, 4, 15, 19], // (1,0)
597
+ [2, 5, 2, 3, 3, 15, 19], // (1,1)
598
+ [2, 4, 2, 3, 4, 15, 19], // (1,2)
599
+ [2, 3, 2, 2, 3, 12, 15], // (2,0)
600
+ [2, 3, 2, 2, 3, 12, 15], // (2,1)
601
+ [2, 3, 2, 2, 3, 12, 15], // (2,2)
602
+ ],
603
+ // gameDirection == 1
604
+ [
605
+ [2, 3, 2, 2, 3, 12, 15],
606
+ [2, 3, 2, 2, 3, 12, 15],
607
+ [2, 3, 2, 2, 3, 12, 15],
608
+ [2, 4, 2, 3, 4, 15, 19],
609
+ [2, 5, 2, 3, 3, 15, 19],
610
+ [2, 4, 2, 3, 4, 15, 19],
611
+ [2, 3, 2, 2, 3, 12, 15],
612
+ [2, 3, 2, 2, 3, 12, 15],
613
+ [2, 3, 2, 2, 3, 12, 15],
614
+ ],
615
+ ];
616
+ exports.BAR1_BONUS_LIMITATION_WEIGHTS = [
617
+ // gameDirection == 0
618
+ [
619
+ [2, 1, 1, 1], // SEV_S
620
+ [2, 1, 1, 1], // SEV
621
+ [2, 1, 1, 1], // BA3
622
+ [2, 1, 1, 1], // BA2
623
+ [2, 1, 1, 1], // BA1
624
+ [15, 10, 3, 1], // BA_S (heavily weighted to max 2)
625
+ [1, 1, 5, 5], // CO_B
626
+ ],
627
+ // gameDirection == 1
628
+ [
629
+ [2, 1, 1, 1], // SEV_S
630
+ [2, 1, 1, 1], // SEV
631
+ [2, 1, 1, 1], // BA3
632
+ [2, 1, 1, 1], // BA2
633
+ [2, 1, 1, 1], // BA1
634
+ [15, 10, 3, 1], // BA_S
635
+ [1, 1, 5, 5], // CO_B
636
+ ],
637
+ ];
638
+ // C++ BonusBar13x3 EXACTLY - 10% 3x3 rate
639
+ exports.BAR1_BONUS_3X3_WEIGHTS = [
640
+ [1, 9], // 8 lines - C++ BonusBar13x3[0] = 10%
641
+ [1, 9], // 16 lines - C++ BonusBar13x3[1] = 10%
642
+ ];
643
+ exports.BAR1_BONUS_3X3_SYMBOL_WEIGHTS = [0, 0, 0, 0, 0, 3, 6];
644
+ // =============================================================================
645
+ // CENTER CHERRY RESPIN WEIGHTS
646
+ // =============================================================================
647
+ exports.RESPIN_CHERRY_SYMBOLS = exports.PAID_SPIN_SYMBOLS;
648
+ exports.RESPIN_CHERRY_WEIGHTS = [
649
+ // gameDirection == 0
650
+ [
651
+ [1, 3, 3, 6, 10, 25, 6, 25, 25, 19, 0], // (0,0)
652
+ [1, 2, 3, 6, 5, 6, 25, 25, 25, 19, 0], // (0,1)
653
+ [1, 3, 3, 6, 10, 25, 6, 25, 25, 19, 0], // (0,2)
654
+ [1, 2, 3, 6, 3, 6, 25, 25, 25, 9, 9], // (1,0)
655
+ [1, 3, 3, 6, 10, 25, 6, 25, 25, 9, 9], // (1,1) center - cherry stays
656
+ [1, 2, 3, 6, 3, 6, 25, 25, 25, 9, 9], // (1,2)
657
+ [1, 3, 3, 6, 10, 25, 6, 25, 25, 19, 0], // (2,0)
658
+ [1, 2, 3, 6, 3, 6, 25, 25, 25, 19, 0], // (2,1)
659
+ [1, 3, 3, 6, 10, 25, 6, 25, 25, 19, 0], // (2,2)
660
+ ],
661
+ // gameDirection == 1
662
+ [
663
+ [1, 3, 3, 6, 10, 25, 6, 25, 25, 19, 0],
664
+ [1, 2, 3, 6, 5, 6, 25, 25, 25, 19, 0],
665
+ [1, 3, 3, 6, 10, 25, 6, 25, 25, 19, 0],
666
+ [1, 2, 3, 6, 3, 6, 25, 25, 25, 9, 9],
667
+ [1, 3, 3, 6, 10, 25, 6, 25, 25, 9, 9],
668
+ [1, 2, 3, 6, 3, 6, 25, 25, 25, 9, 9],
669
+ [1, 3, 3, 6, 10, 25, 6, 25, 25, 19, 0],
670
+ [1, 2, 3, 6, 3, 6, 25, 25, 25, 19, 0],
671
+ [1, 3, 3, 6, 10, 25, 6, 25, 25, 19, 0],
672
+ ],
673
+ ];
674
+ exports.RESPIN_CHERRY_LIMITATION_WEIGHTS = [
675
+ // gameDirection == 0
676
+ [
677
+ [9, 2, 1, 1], // SEV_S
678
+ [8, 3, 1, 1], // SEV
679
+ [8, 1, 1, 1], // BA3
680
+ [8, 1, 1, 1], // BA2
681
+ [8, 2, 1, 1], // BA1
682
+ [7, 3, 1, 1], // ME
683
+ [5, 3, 1, 1], // BE
684
+ [6, 2, 1, 1], // PR
685
+ [5, 2, 1, 1], // OR
686
+ [5, 1, 1, 1], // CH
687
+ [5, 1, 0, 0], // CH_S
688
+ ],
689
+ // gameDirection == 1
690
+ [
691
+ [9, 2, 1, 1], // SEV_S
692
+ [8, 3, 1, 1], // SEV
693
+ [8, 1, 1, 1], // BA3
694
+ [8, 1, 1, 1], // BA2
695
+ [8, 2, 1, 1], // BA1
696
+ [7, 3, 1, 1], // ME
697
+ [5, 3, 1, 1], // BE
698
+ [6, 2, 1, 1], // PR
699
+ [5, 2, 1, 1], // OR
700
+ [5, 1, 1, 1], // CH
701
+ [5, 1, 0, 0], // CH_S
702
+ ],
703
+ ];
704
+ // =============================================================================
705
+ // SYMBOL GROUPS (for mixed wins)
706
+ // =============================================================================
707
+ exports.BAR_SYMBOLS = [Symbol.BAR3, Symbol.BAR2, Symbol.BAR1];
708
+ /** Bar symbols including Super Bar - for bar mix wins (per C++ math model line 1229) */
709
+ exports.BAR_MIX_SYMBOLS = [Symbol.BAR3, Symbol.BAR2, Symbol.BAR1, Symbol.SUPER_BAR];
710
+ exports.FRUIT_SYMBOLS = [Symbol.MELON, Symbol.PRUNE, Symbol.ORANGE, Symbol.CHERRY, Symbol.SUPER_CHERRY];
711
+ exports.COLOR_SYMBOLS = [Symbol.COLOR_YELLOW, Symbol.COLOR_RED, Symbol.COLOR_GREEN, Symbol.COLOR_BLUE];
712
+ exports.SEVEN_SYMBOLS = [Symbol.SUPER_SEVEN, Symbol.SEVEN];
713
+ exports.CHERRY_SYMBOLS = [Symbol.CHERRY, Symbol.SUPER_CHERRY];
714
+ //# sourceMappingURL=happy-panda.config.js.map