slot-server 1.0.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.
- package/README.md +949 -0
- package/dist/index.cjs +2944 -0
- package/dist/index.d.cts +2160 -0
- package/dist/index.d.ts +2160 -0
- package/dist/index.js +2897 -0
- package/package.json +34 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,2160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Symbol mapping: symbol ID → texture key.
|
|
3
|
+
* The client uses this to load the correct images.
|
|
4
|
+
*/
|
|
5
|
+
type SymbolMap = Record<number, string>;
|
|
6
|
+
/**
|
|
7
|
+
* A single payline pattern.
|
|
8
|
+
* Each element is { reel: number; row: number } (0-indexed).
|
|
9
|
+
*/
|
|
10
|
+
type PaylinePattern = {
|
|
11
|
+
reel: number;
|
|
12
|
+
row: number;
|
|
13
|
+
}[];
|
|
14
|
+
/**
|
|
15
|
+
* Paytable data: symbol ID → multiplier by count (e.g., "x3": 50).
|
|
16
|
+
* Keys should be like "x3", "x4", "x5" (or "x2" etc.)
|
|
17
|
+
*/
|
|
18
|
+
type PaytableData = Record<number, Record<string, number>>;
|
|
19
|
+
/**
|
|
20
|
+
* Reel strip: an array of symbol IDs (ordered bottom-to-top or top-to-bottom,
|
|
21
|
+
* but the client will interpret it consistently).
|
|
22
|
+
*/
|
|
23
|
+
type ReelStrip = number[];
|
|
24
|
+
/**
|
|
25
|
+
* Symbol behavior types for special features.
|
|
26
|
+
*/
|
|
27
|
+
type SymbolBehavior = 'normal' | 'wild' | 'scatter' | 'bonus' | 'multiplier' | 'expanding' | 'sticky' | 'shifting' | 'split';
|
|
28
|
+
/**
|
|
29
|
+
* Configuration for a symbol's properties.
|
|
30
|
+
*/
|
|
31
|
+
interface ISymbolConfig {
|
|
32
|
+
id: number;
|
|
33
|
+
textureKey: string;
|
|
34
|
+
behavior: SymbolBehavior;
|
|
35
|
+
/** For wilds: which symbols it can substitute for (undefined = all) */
|
|
36
|
+
substitutesFor?: number[];
|
|
37
|
+
/** For multipliers: multiplier value */
|
|
38
|
+
multiplierValue?: number;
|
|
39
|
+
/** For scatters: minimum count for trigger */
|
|
40
|
+
scatterMinCount?: number;
|
|
41
|
+
/** For scatters/bonus: bonus triggered */
|
|
42
|
+
triggersBonus?: boolean;
|
|
43
|
+
/** For expanding: does it expand */
|
|
44
|
+
expands?: boolean;
|
|
45
|
+
/** For sticky: how many spins it stays */
|
|
46
|
+
stickySpins?: number;
|
|
47
|
+
/** Pay priority (higher = evaluated first) */
|
|
48
|
+
payPriority?: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Ways-to-win configuration (for "243 ways" or similar mechanics).
|
|
52
|
+
*/
|
|
53
|
+
interface IWaysConfig {
|
|
54
|
+
enabled: boolean;
|
|
55
|
+
/** Number of ways (e.g., 243, 1024, 4096) */
|
|
56
|
+
waysCount: number;
|
|
57
|
+
/** Minimum matching symbols from left (default: 3) */
|
|
58
|
+
minMatches: number;
|
|
59
|
+
/** Use adjacent pays (left-to-right only or both directions) */
|
|
60
|
+
direction: 'leftToRight' | 'bothDirections';
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Jackpot tier configuration.
|
|
64
|
+
*/
|
|
65
|
+
interface IJackpotTier {
|
|
66
|
+
id: string;
|
|
67
|
+
name: string;
|
|
68
|
+
seedAmount: number;
|
|
69
|
+
currentAmount: number;
|
|
70
|
+
triggerProbability: number;
|
|
71
|
+
contributionRate: number;
|
|
72
|
+
minBetRequired?: number;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Jackpot configuration.
|
|
76
|
+
*/
|
|
77
|
+
interface IJackpotConfig {
|
|
78
|
+
enabled: boolean;
|
|
79
|
+
tiers: IJackpotTier[];
|
|
80
|
+
/** Type: standalone, local (casino-wide), or wide-area */
|
|
81
|
+
type: 'standalone' | 'local' | 'wideArea';
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Free spins configuration.
|
|
85
|
+
*/
|
|
86
|
+
interface IFreeSpinsConfig {
|
|
87
|
+
/** Scatter symbol ID that triggers free spins */
|
|
88
|
+
scatterSymbolId: number;
|
|
89
|
+
/** Minimum scatters needed */
|
|
90
|
+
minTriggers: number;
|
|
91
|
+
/** Free spins awarded per scatter count */
|
|
92
|
+
spinsByCount: Record<number, number>;
|
|
93
|
+
/** Multiplier applied during free spins */
|
|
94
|
+
multiplier?: number;
|
|
95
|
+
/** Can free spins be retriggered? */
|
|
96
|
+
retriggerable: boolean;
|
|
97
|
+
/** Additional spins on retrigger */
|
|
98
|
+
retriggerSpins: Record<number, number>;
|
|
99
|
+
/** Special expanding symbols during free spins */
|
|
100
|
+
expandingSymbols?: number[];
|
|
101
|
+
/** Sticky wilds during free spins */
|
|
102
|
+
stickyWilds?: boolean;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Gamble feature configuration.
|
|
106
|
+
*/
|
|
107
|
+
interface IGambleConfig {
|
|
108
|
+
enabled: boolean;
|
|
109
|
+
/** Maximum amount that can be gambled */
|
|
110
|
+
maxGambleAmount?: number;
|
|
111
|
+
/** Maximum consecutive gambles */
|
|
112
|
+
maxConsecutiveGambles: number;
|
|
113
|
+
/** Types of gamble games available */
|
|
114
|
+
gameTypes: ('card' | 'ladder' | 'wheel')[];
|
|
115
|
+
/** Auto-collect at win amount */
|
|
116
|
+
autoCollectAt?: number;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Buy bonus feature configuration.
|
|
120
|
+
*/
|
|
121
|
+
interface IBuyBonusConfig {
|
|
122
|
+
enabled: boolean;
|
|
123
|
+
/** Cost multiplier (e.g., 100x bet) */
|
|
124
|
+
costMultiplier: number;
|
|
125
|
+
/** Minimum bet required */
|
|
126
|
+
minBetRequired?: number;
|
|
127
|
+
/** Maximum purchases per session */
|
|
128
|
+
maxPurchasesPerSession?: number;
|
|
129
|
+
/** Cooldown between purchases (ms) */
|
|
130
|
+
cooldownMs?: number;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Tournament mode configuration.
|
|
134
|
+
*/
|
|
135
|
+
interface ITournamentConfig {
|
|
136
|
+
enabled: boolean;
|
|
137
|
+
tournamentId: string;
|
|
138
|
+
startTime: number;
|
|
139
|
+
endTime: number;
|
|
140
|
+
entryFee?: number;
|
|
141
|
+
prizePool: number;
|
|
142
|
+
scoringMethod: 'totalWin' | 'biggestWin' | 'totalSpins';
|
|
143
|
+
leaderboard: ITournamentPlayer[];
|
|
144
|
+
}
|
|
145
|
+
interface ITournamentPlayer {
|
|
146
|
+
playerId: string;
|
|
147
|
+
playerName: string;
|
|
148
|
+
score: number;
|
|
149
|
+
rank: number;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Responsible gaming limits.
|
|
153
|
+
*/
|
|
154
|
+
interface IResponsibleGamingLimits {
|
|
155
|
+
/** Session time limit in minutes */
|
|
156
|
+
sessionTimeLimit?: number;
|
|
157
|
+
/** Loss limit per session */
|
|
158
|
+
lossLimit?: number;
|
|
159
|
+
/** Win goal (notify when reached) */
|
|
160
|
+
winGoal?: number;
|
|
161
|
+
/** Maximum bet allowed */
|
|
162
|
+
maxBetLimit?: number;
|
|
163
|
+
/** Reality check interval in minutes */
|
|
164
|
+
realityCheckInterval?: number;
|
|
165
|
+
/** Self-exclusion end date (ISO timestamp) */
|
|
166
|
+
selfExclusionUntil?: string;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Currency configuration.
|
|
170
|
+
*/
|
|
171
|
+
interface ICurrencyConfig {
|
|
172
|
+
code: string;
|
|
173
|
+
symbol: string;
|
|
174
|
+
decimalSeparator: string;
|
|
175
|
+
thousandSeparator: string;
|
|
176
|
+
minDecimalPlaces: number;
|
|
177
|
+
/** Exchange rate to base currency (for multi-currency) */
|
|
178
|
+
exchangeRate?: number;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Game configuration for the client engine.
|
|
182
|
+
*/
|
|
183
|
+
interface IGameConfigData {
|
|
184
|
+
/** Game identifier (e.g., "lucky7") */
|
|
185
|
+
gameId: string;
|
|
186
|
+
/** Game version */
|
|
187
|
+
version?: string;
|
|
188
|
+
/** Number of reels (default 5) */
|
|
189
|
+
reelCount: number;
|
|
190
|
+
/** Number of visible rows (default 3) */
|
|
191
|
+
rowCount: number;
|
|
192
|
+
/** Symbol configurations */
|
|
193
|
+
symbols?: ISymbolConfig[];
|
|
194
|
+
/** Legacy symbol map (ID → texture key) for backward compatibility */
|
|
195
|
+
symbolMap: SymbolMap;
|
|
196
|
+
/** Paytable data */
|
|
197
|
+
paytableData: PaytableData;
|
|
198
|
+
/** Reel strips (one array per reel) */
|
|
199
|
+
reelStrips: ReelStrip[];
|
|
200
|
+
/** Line patterns (paylines) */
|
|
201
|
+
linePatterns: PaylinePattern[];
|
|
202
|
+
/** Ways-to-win configuration */
|
|
203
|
+
waysConfig?: IWaysConfig;
|
|
204
|
+
/** Jackpot configuration */
|
|
205
|
+
jackpotConfig?: IJackpotConfig;
|
|
206
|
+
/** Free spins configuration */
|
|
207
|
+
freeSpinsConfig?: IFreeSpinsConfig;
|
|
208
|
+
/** Gamble feature configuration */
|
|
209
|
+
gambleConfig?: IGambleConfig;
|
|
210
|
+
/** Buy bonus configuration */
|
|
211
|
+
buyBonusConfig?: IBuyBonusConfig;
|
|
212
|
+
/** Currency settings */
|
|
213
|
+
currency: ICurrencyConfig;
|
|
214
|
+
/** Feature flags (autoplay, fastspin, etc.) */
|
|
215
|
+
features: {
|
|
216
|
+
autoplay: boolean;
|
|
217
|
+
fastSpin: boolean;
|
|
218
|
+
realityCheck: boolean;
|
|
219
|
+
fullscreen: boolean;
|
|
220
|
+
turboSpin?: boolean;
|
|
221
|
+
quickStop?: boolean;
|
|
222
|
+
};
|
|
223
|
+
/** Default bet (in base currency units) */
|
|
224
|
+
defaultBet: number;
|
|
225
|
+
/** Minimum bet */
|
|
226
|
+
minBet: number;
|
|
227
|
+
/** Maximum bet */
|
|
228
|
+
maxBet: number;
|
|
229
|
+
/** Bet step (increment) */
|
|
230
|
+
betStep: number;
|
|
231
|
+
/** Available bet amounts (if using preset bets instead of steps) */
|
|
232
|
+
betPresets?: number[];
|
|
233
|
+
/** Number of selectable paylines (if variable) */
|
|
234
|
+
selectableLines?: number[];
|
|
235
|
+
/** Default number of lines */
|
|
236
|
+
defaultLines: number;
|
|
237
|
+
/** RTP percentage (e.g., 96.5) */
|
|
238
|
+
rtp: number;
|
|
239
|
+
/** Volatility level */
|
|
240
|
+
volatility: 'low' | 'medium' | 'high' | 'veryHigh';
|
|
241
|
+
/** Hit frequency percentage (e.g., 25.5) */
|
|
242
|
+
hitFrequency?: number;
|
|
243
|
+
/** Max win multiplier (e.g., 5000x) */
|
|
244
|
+
maxWinMultiplier?: number;
|
|
245
|
+
/** Responsible gaming limits */
|
|
246
|
+
responsibleGaming?: IResponsibleGamingLimits;
|
|
247
|
+
/** Tournament mode */
|
|
248
|
+
tournament?: ITournamentConfig;
|
|
249
|
+
/** Game rules text (localized keys) */
|
|
250
|
+
rulesText?: Record<string, string>;
|
|
251
|
+
/** Help screens (localized keys) */
|
|
252
|
+
helpScreens?: Array<{
|
|
253
|
+
title: string;
|
|
254
|
+
content: string;
|
|
255
|
+
image?: string;
|
|
256
|
+
}>;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Response structure for an INIT message (sent from server to client).
|
|
260
|
+
*/
|
|
261
|
+
interface IInitResponse {
|
|
262
|
+
/** Player balance */
|
|
263
|
+
balance: number;
|
|
264
|
+
/** Current bet */
|
|
265
|
+
bet: number;
|
|
266
|
+
/** Game configuration (includes all static data) */
|
|
267
|
+
config: IGameConfigData;
|
|
268
|
+
/** Bonus offers (if any) */
|
|
269
|
+
bonusOffers?: any;
|
|
270
|
+
/** Additional game state */
|
|
271
|
+
state?: any;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Request structure for a SPIN message (client → server).
|
|
275
|
+
*/
|
|
276
|
+
interface ISpinRequestData {
|
|
277
|
+
action: 'spin' | 'autospin' | 'fastspin';
|
|
278
|
+
stakePerLine: number;
|
|
279
|
+
selectedLines: number;
|
|
280
|
+
totalStake: number;
|
|
281
|
+
/** Game mode — CHANGED: Formatted to camelCase to match the frontend expectations */
|
|
282
|
+
gameMode: 0 | 1;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Request for buying a bonus feature.
|
|
286
|
+
*/
|
|
287
|
+
interface IBuyBonusRequest {
|
|
288
|
+
action: 'buyBonus';
|
|
289
|
+
totalStake: number;
|
|
290
|
+
gameMode: 0 | 1;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Request for gamble feature.
|
|
294
|
+
*/
|
|
295
|
+
interface IGambleRequest {
|
|
296
|
+
action: 'gamble';
|
|
297
|
+
gambleType: 'card' | 'ladder' | 'wheel';
|
|
298
|
+
currentWin: number;
|
|
299
|
+
choice?: number | string;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Gamble response.
|
|
303
|
+
*/
|
|
304
|
+
interface IGambleResponse {
|
|
305
|
+
result: 'win' | 'lose' | 'push';
|
|
306
|
+
winAmount: number;
|
|
307
|
+
canGambleAgain: boolean;
|
|
308
|
+
consecutiveGambles: number;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Jackpot contribution notification.
|
|
312
|
+
*/
|
|
313
|
+
interface IJackpotContribution {
|
|
314
|
+
tierId: string;
|
|
315
|
+
contributedAmount: number;
|
|
316
|
+
newJackpotAmount: number;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Jackpot win notification.
|
|
320
|
+
*/
|
|
321
|
+
interface IJackpotWin {
|
|
322
|
+
tierId: string;
|
|
323
|
+
tierName: string;
|
|
324
|
+
winAmount: number;
|
|
325
|
+
timestamp: number;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Tournament spin request.
|
|
329
|
+
*/
|
|
330
|
+
interface ITournamentSpinRequest {
|
|
331
|
+
action: 'tournamentSpin';
|
|
332
|
+
tournamentId: string;
|
|
333
|
+
entryFee?: number;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Tournament state response.
|
|
337
|
+
*/
|
|
338
|
+
interface ITournamentState {
|
|
339
|
+
tournamentId: string;
|
|
340
|
+
playerName: string;
|
|
341
|
+
playerRank: number;
|
|
342
|
+
playerScore: number;
|
|
343
|
+
timeRemaining: number;
|
|
344
|
+
leaderboard: ITournamentPlayer[];
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* A single winning line.
|
|
348
|
+
*/
|
|
349
|
+
interface IWinLine {
|
|
350
|
+
lineIndex: number;
|
|
351
|
+
symbolId: number;
|
|
352
|
+
multiplier: number;
|
|
353
|
+
winAmount: number;
|
|
354
|
+
positions: {
|
|
355
|
+
reel: number;
|
|
356
|
+
row: number;
|
|
357
|
+
}[];
|
|
358
|
+
/** For ways-to-win: which way this represents */
|
|
359
|
+
wayIndex?: number;
|
|
360
|
+
/** For expanding symbols: was this an expanded position */
|
|
361
|
+
expanded?: boolean;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Extended win details for complex features.
|
|
365
|
+
*/
|
|
366
|
+
interface IWinDetails {
|
|
367
|
+
/** Base game wins */
|
|
368
|
+
baseWins: IWinLine[];
|
|
369
|
+
/** Scatter pays (anywhere pays) */
|
|
370
|
+
scatterPays: Array<{
|
|
371
|
+
symbolId: number;
|
|
372
|
+
count: number;
|
|
373
|
+
winAmount: number;
|
|
374
|
+
}>;
|
|
375
|
+
/** Wild substitutions made */
|
|
376
|
+
wildSubstitutions: Array<{
|
|
377
|
+
reel: number;
|
|
378
|
+
row: number;
|
|
379
|
+
originalSymbol: number;
|
|
380
|
+
wildSymbol: number;
|
|
381
|
+
}>;
|
|
382
|
+
/** Multipliers applied */
|
|
383
|
+
multipliersApplied: Array<{
|
|
384
|
+
source: string;
|
|
385
|
+
value: number;
|
|
386
|
+
}>;
|
|
387
|
+
/** Cascading/tumbling wins in sequence */
|
|
388
|
+
cascadeSequence?: Array<{
|
|
389
|
+
step: number;
|
|
390
|
+
wins: IWinLine[];
|
|
391
|
+
totalWin: number;
|
|
392
|
+
}>;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Response structure for a SPIN message (server → client).
|
|
396
|
+
*/
|
|
397
|
+
interface ISpinResponseData {
|
|
398
|
+
/** 2D array of symbol IDs [reel][row] (visible positions) */
|
|
399
|
+
result: number[][];
|
|
400
|
+
/** Total win amount */
|
|
401
|
+
totalWin: number;
|
|
402
|
+
/** Stake per line used */
|
|
403
|
+
stakePerLine: number;
|
|
404
|
+
/** Total stake used */
|
|
405
|
+
totalStake: number;
|
|
406
|
+
/** Game mode (0 = main, 1 = bonus) */
|
|
407
|
+
gameMode: 0 | 1;
|
|
408
|
+
/** Free spins remaining (if any) */
|
|
409
|
+
freeSpinsRemaining?: number;
|
|
410
|
+
/** Bonus triggered? */
|
|
411
|
+
bonusTriggered?: boolean;
|
|
412
|
+
/** Bonus data (if triggered) */
|
|
413
|
+
bonusData?: any;
|
|
414
|
+
/** Winning lines (optional) */
|
|
415
|
+
winLines?: IWinLine[];
|
|
416
|
+
/** Detailed win breakdown */
|
|
417
|
+
winDetails?: IWinDetails;
|
|
418
|
+
/** New balance after the spin */
|
|
419
|
+
balanceAfter: number;
|
|
420
|
+
/** Jackpot contributions */
|
|
421
|
+
jackpotContributions?: IJackpotContribution[];
|
|
422
|
+
/** Jackpot won (if any) */
|
|
423
|
+
jackpotWin?: IJackpotWin;
|
|
424
|
+
/** Error message (if any) */
|
|
425
|
+
error?: string;
|
|
426
|
+
/** Spin ID for audit trail */
|
|
427
|
+
spinId?: string;
|
|
428
|
+
/** Server timestamp */
|
|
429
|
+
timestamp?: number;
|
|
430
|
+
/** RNG seed for verification (if using provably fair) */
|
|
431
|
+
rngSeed?: string;
|
|
432
|
+
/** Whether this is a cascading/tumbling spin */
|
|
433
|
+
isCascade?: boolean;
|
|
434
|
+
/** Cascade level (0 = initial spin, 1+ = subsequent cascades) */
|
|
435
|
+
cascadeLevel?: number;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Response for a BONUS message (server → client).
|
|
439
|
+
*/
|
|
440
|
+
interface IBonusResponse {
|
|
441
|
+
/** Bonus ID (if applicable) */
|
|
442
|
+
bonusId?: string;
|
|
443
|
+
/** Action (e.g., "accept", "decline", "pick", "end") */
|
|
444
|
+
action?: string;
|
|
445
|
+
/** Bonus state */
|
|
446
|
+
state?: 'ACTIVE' | 'ENDED' | 'COMPLETE' | 'OFFERED';
|
|
447
|
+
/** Data specific to the bonus type */
|
|
448
|
+
data?: any;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Free spin bonus state.
|
|
452
|
+
*/
|
|
453
|
+
interface IFreeSpinBonus {
|
|
454
|
+
type: 'freespin';
|
|
455
|
+
spinsRemaining: number;
|
|
456
|
+
multiplier: number;
|
|
457
|
+
totalWin: number;
|
|
458
|
+
bet: number;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Pick bonus state.
|
|
462
|
+
*/
|
|
463
|
+
interface IPickBonus {
|
|
464
|
+
type: 'pick';
|
|
465
|
+
items: {
|
|
466
|
+
id: string;
|
|
467
|
+
label: string;
|
|
468
|
+
value: number;
|
|
469
|
+
}[];
|
|
470
|
+
pickedIds: string[];
|
|
471
|
+
totalWin: number;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Extended bonus types for professional features.
|
|
475
|
+
*/
|
|
476
|
+
interface IWheelBonus {
|
|
477
|
+
type: 'wheel';
|
|
478
|
+
segments: Array<{
|
|
479
|
+
id: string;
|
|
480
|
+
value: number;
|
|
481
|
+
probability: number;
|
|
482
|
+
label?: string;
|
|
483
|
+
}>;
|
|
484
|
+
currentRotation?: number;
|
|
485
|
+
resultSegment?: string;
|
|
486
|
+
totalWin: number;
|
|
487
|
+
}
|
|
488
|
+
interface ICascadeBonus {
|
|
489
|
+
type: 'cascade';
|
|
490
|
+
currentLevel: number;
|
|
491
|
+
maxLevels: number;
|
|
492
|
+
multiplierPerLevel: number;
|
|
493
|
+
currentMultiplier: number;
|
|
494
|
+
totalWin: number;
|
|
495
|
+
}
|
|
496
|
+
interface IRespinsBonus {
|
|
497
|
+
type: 'respins';
|
|
498
|
+
spinsRemaining: number;
|
|
499
|
+
lockedPositions: Array<{
|
|
500
|
+
reel: number;
|
|
501
|
+
row: number;
|
|
502
|
+
symbolId: number;
|
|
503
|
+
}>;
|
|
504
|
+
targetSymbol?: number;
|
|
505
|
+
totalWin: number;
|
|
506
|
+
}
|
|
507
|
+
interface IHoldAndSpinBonus {
|
|
508
|
+
type: 'holdAndSpin';
|
|
509
|
+
initialSpins: number;
|
|
510
|
+
spinsRemaining: number;
|
|
511
|
+
grid: (number | null)[][];
|
|
512
|
+
specialSymbols: Array<{
|
|
513
|
+
reel: number;
|
|
514
|
+
row: number;
|
|
515
|
+
type: string;
|
|
516
|
+
value: number;
|
|
517
|
+
}>;
|
|
518
|
+
totalWin: number;
|
|
519
|
+
isComplete: boolean;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Union of all bonus states.
|
|
523
|
+
*/
|
|
524
|
+
type IBonusState = IFreeSpinBonus | IPickBonus | IWheelBonus | ICascadeBonus | IRespinsBonus | IHoldAndSpinBonus;
|
|
525
|
+
/**
|
|
526
|
+
* History entry (for HISTORY response).
|
|
527
|
+
*/
|
|
528
|
+
interface IHistoryEntry {
|
|
529
|
+
time: number;
|
|
530
|
+
bet: number;
|
|
531
|
+
win: number;
|
|
532
|
+
balance: number;
|
|
533
|
+
result: number[][];
|
|
534
|
+
gameMode: 0 | 1;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* History response.
|
|
538
|
+
*/
|
|
539
|
+
interface IHistoryResponse {
|
|
540
|
+
entries: IHistoryEntry[];
|
|
541
|
+
total: number;
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Full player state tracked by the server.
|
|
545
|
+
*/
|
|
546
|
+
interface IPlayerState {
|
|
547
|
+
balance: number;
|
|
548
|
+
bet: number;
|
|
549
|
+
gameMode: 0 | 1;
|
|
550
|
+
freeSpinsRemaining: number;
|
|
551
|
+
bonusActive: boolean;
|
|
552
|
+
bonusState?: IBonusState;
|
|
553
|
+
lastSpinResult?: ISpinResponseData;
|
|
554
|
+
history: IHistoryEntry[];
|
|
555
|
+
/** Responsible gaming session tracking */
|
|
556
|
+
sessionStartTime?: number;
|
|
557
|
+
sessionLoss?: number;
|
|
558
|
+
sessionWin?: number;
|
|
559
|
+
consecutiveGambles?: number;
|
|
560
|
+
/** Tournament state */
|
|
561
|
+
tournamentScore?: number;
|
|
562
|
+
tournamentRank?: number;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Debug mode configuration for testing and development.
|
|
566
|
+
*/
|
|
567
|
+
interface IDebugConfig {
|
|
568
|
+
/** Enable debug mode */
|
|
569
|
+
enabled: boolean;
|
|
570
|
+
/** Log all spin results with detailed breakdown */
|
|
571
|
+
logSpins: boolean;
|
|
572
|
+
/** Log RNG seeds for reproducibility */
|
|
573
|
+
logRngSeeds: boolean;
|
|
574
|
+
/** Force specific outcomes for testing */
|
|
575
|
+
forcedOutcomes?: IForcedOutcome[];
|
|
576
|
+
/** Skip balance checks (for testing) */
|
|
577
|
+
skipBalanceChecks: boolean;
|
|
578
|
+
/** Verbose logging level */
|
|
579
|
+
verboseLevel: 'none' | 'errors' | 'warnings' | 'info' | 'debug';
|
|
580
|
+
/** Output format for logs */
|
|
581
|
+
outputFormat: 'console' | 'json' | 'file';
|
|
582
|
+
/** File path for log output (if file format) */
|
|
583
|
+
logFilePath?: string;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Forced outcome for testing specific scenarios.
|
|
587
|
+
*/
|
|
588
|
+
interface IForcedOutcome {
|
|
589
|
+
/** Condition to trigger forced outcome */
|
|
590
|
+
condition: {
|
|
591
|
+
type: 'spinNumber' | 'randomSeed' | 'betAmount' | 'playerId';
|
|
592
|
+
value: number | string;
|
|
593
|
+
};
|
|
594
|
+
/** Result to force */
|
|
595
|
+
result: {
|
|
596
|
+
symbols?: number[][];
|
|
597
|
+
winAmount?: number;
|
|
598
|
+
bonusTriggered?: boolean;
|
|
599
|
+
jackpotWon?: string;
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Debug log entry.
|
|
604
|
+
*/
|
|
605
|
+
interface IDebugLogEntry {
|
|
606
|
+
timestamp: number;
|
|
607
|
+
level: 'error' | 'warning' | 'info' | 'debug';
|
|
608
|
+
category: string;
|
|
609
|
+
message: string;
|
|
610
|
+
data?: any;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Debug session state.
|
|
614
|
+
*/
|
|
615
|
+
interface IDebugState {
|
|
616
|
+
enabled: boolean;
|
|
617
|
+
spinCount: number;
|
|
618
|
+
lastRngSeed: string;
|
|
619
|
+
forcedOutcomesApplied: number;
|
|
620
|
+
errors: IDebugLogEntry[];
|
|
621
|
+
warnings: IDebugLogEntry[];
|
|
622
|
+
infoLogs: IDebugLogEntry[];
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Spin audit record for regulatory compliance.
|
|
626
|
+
*/
|
|
627
|
+
interface IAuditRecord {
|
|
628
|
+
spinId: string;
|
|
629
|
+
playerId: string;
|
|
630
|
+
gameId: string;
|
|
631
|
+
timestamp: number;
|
|
632
|
+
stake: number;
|
|
633
|
+
win: number;
|
|
634
|
+
balanceBefore: number;
|
|
635
|
+
balanceAfter: number;
|
|
636
|
+
rngSeed: string;
|
|
637
|
+
result: number[][];
|
|
638
|
+
gameMode: 0 | 1;
|
|
639
|
+
bonusTriggered: boolean;
|
|
640
|
+
jackpotContributions: IJackpotContribution[];
|
|
641
|
+
jackpotWins: IJackpotWin[];
|
|
642
|
+
ipAddress?: string;
|
|
643
|
+
sessionId: string;
|
|
644
|
+
/** Extended audit fields */
|
|
645
|
+
deviceInfo?: string;
|
|
646
|
+
location?: string;
|
|
647
|
+
operatorId?: string;
|
|
648
|
+
platform?: 'web' | 'mobile' | 'desktop';
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Player activity summary for reporting.
|
|
652
|
+
*/
|
|
653
|
+
interface IPlayerActivitySummary {
|
|
654
|
+
playerId: string;
|
|
655
|
+
periodStart: number;
|
|
656
|
+
periodEnd: number;
|
|
657
|
+
totalSpins: number;
|
|
658
|
+
totalStaked: number;
|
|
659
|
+
totalWon: number;
|
|
660
|
+
netResult: number;
|
|
661
|
+
biggestWin: number;
|
|
662
|
+
bonusTriggers: number;
|
|
663
|
+
jackpotWins: number;
|
|
664
|
+
sessionCount: number;
|
|
665
|
+
averageSessionDuration: number;
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Generic WebSocket message wrapper.
|
|
669
|
+
*/
|
|
670
|
+
interface IWebSocketMessage<T = any> {
|
|
671
|
+
type: string;
|
|
672
|
+
data: T;
|
|
673
|
+
messageId: string;
|
|
674
|
+
timestamp: number;
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Server acknowledgment message.
|
|
678
|
+
*/
|
|
679
|
+
interface IServerAck {
|
|
680
|
+
messageId: string;
|
|
681
|
+
status: 'success' | 'error';
|
|
682
|
+
errorCode?: string;
|
|
683
|
+
errorMessage?: string;
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Deep partial type for optional updates.
|
|
687
|
+
*/
|
|
688
|
+
type DeepPartial<T> = T extends object ? {
|
|
689
|
+
[P in keyof T]?: DeepPartial<T[P]>;
|
|
690
|
+
} : T;
|
|
691
|
+
/**
|
|
692
|
+
* Nullable type helper.
|
|
693
|
+
*/
|
|
694
|
+
type Nullable<T> = T | null;
|
|
695
|
+
/**
|
|
696
|
+
* Result type for operations that can fail.
|
|
697
|
+
*/
|
|
698
|
+
type Result<T, E = Error> = {
|
|
699
|
+
success: true;
|
|
700
|
+
data: T;
|
|
701
|
+
} | {
|
|
702
|
+
success: false;
|
|
703
|
+
error: E;
|
|
704
|
+
};
|
|
705
|
+
/**
|
|
706
|
+
* Configuration for cascading/tumbling reel mechanics.
|
|
707
|
+
*/
|
|
708
|
+
interface ICascadeConfig {
|
|
709
|
+
/** Enable cascading feature */
|
|
710
|
+
enabled: boolean;
|
|
711
|
+
/** Maximum number of cascades allowed in sequence */
|
|
712
|
+
maxCascades?: number;
|
|
713
|
+
/** Initial multiplier at start of cascade sequence */
|
|
714
|
+
initialMultiplier?: number;
|
|
715
|
+
/** Multiplier increment per cascade */
|
|
716
|
+
multiplierIncrement?: number;
|
|
717
|
+
/** Symbol pool for filling empty positions */
|
|
718
|
+
symbolPool?: ISymbol[];
|
|
719
|
+
/** Stop cascades if no win increase occurs */
|
|
720
|
+
stopOnNoWinIncrease?: boolean;
|
|
721
|
+
/** Trigger special feature on cascade count */
|
|
722
|
+
triggerOnCascadeCount?: number;
|
|
723
|
+
/** Trigger special feature on multiplier threshold */
|
|
724
|
+
triggerOnMultiplier?: number;
|
|
725
|
+
/** Trigger special feature on consecutive wins */
|
|
726
|
+
triggerOnConsecutiveWins?: number;
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Single step in a cascade sequence.
|
|
730
|
+
*/
|
|
731
|
+
interface ICascadeStep {
|
|
732
|
+
/** Cascade number in sequence (1-based) */
|
|
733
|
+
cascadeNumber: number;
|
|
734
|
+
/** Positions where symbols were removed */
|
|
735
|
+
removedPositions: Array<{
|
|
736
|
+
reel: number;
|
|
737
|
+
row: number;
|
|
738
|
+
symbol: ISymbol;
|
|
739
|
+
}>;
|
|
740
|
+
/** Symbols that dropped due to gravity */
|
|
741
|
+
droppedSymbols: Array<{
|
|
742
|
+
symbol: ISymbol;
|
|
743
|
+
fromRow: number;
|
|
744
|
+
toRow: number;
|
|
745
|
+
reel: number;
|
|
746
|
+
}>;
|
|
747
|
+
/** New symbols added at top */
|
|
748
|
+
newSymbols: Array<{
|
|
749
|
+
symbol: ISymbol;
|
|
750
|
+
position: {
|
|
751
|
+
reel: number;
|
|
752
|
+
row: number;
|
|
753
|
+
};
|
|
754
|
+
}>;
|
|
755
|
+
/** Grid state after this cascade */
|
|
756
|
+
resultingGrid: ISymbol[][];
|
|
757
|
+
/** Wins evaluated in this step */
|
|
758
|
+
winsInStep: IWinEvaluation[];
|
|
759
|
+
/** Current multiplier */
|
|
760
|
+
multiplier: number;
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Result of a full cascade sequence.
|
|
764
|
+
*/
|
|
765
|
+
interface ICascadeResult {
|
|
766
|
+
/** Whether cascades occurred */
|
|
767
|
+
success: boolean;
|
|
768
|
+
/** Total number of cascades */
|
|
769
|
+
totalCascades: number;
|
|
770
|
+
/** All steps in the cascade sequence */
|
|
771
|
+
steps: ICascadeStep[];
|
|
772
|
+
/** Final grid state */
|
|
773
|
+
finalGrid: ISymbol[][];
|
|
774
|
+
/** Final multiplier value */
|
|
775
|
+
finalMultiplier: number;
|
|
776
|
+
/** Total wins from all cascade steps */
|
|
777
|
+
totalWinsFromCascades: number;
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Trigger conditions for wild expansion.
|
|
781
|
+
*/
|
|
782
|
+
type WildExpandTrigger = 'any_wild' | 'multiple_wilds' | 'specific_positions' | 'random';
|
|
783
|
+
/**
|
|
784
|
+
* Configuration for expanding wild mechanics.
|
|
785
|
+
*/
|
|
786
|
+
interface IExpandingWildConfig {
|
|
787
|
+
/** Enable expanding wilds */
|
|
788
|
+
enabled: boolean;
|
|
789
|
+
/** Trigger condition for expansion */
|
|
790
|
+
triggerCondition: WildExpandTrigger;
|
|
791
|
+
/** Minimum wilds needed for 'multiple_wilds' trigger */
|
|
792
|
+
minWildsForExpand?: number;
|
|
793
|
+
/** Specific positions required for 'specific_positions' trigger */
|
|
794
|
+
specificPositions?: number[];
|
|
795
|
+
/** Probability for 'random' trigger (0-1) */
|
|
796
|
+
expansionProbability?: number;
|
|
797
|
+
/** Number of rows to expand to (default: entire reel) */
|
|
798
|
+
expandToRows?: number;
|
|
799
|
+
/** Multiplier applied by expanded wild */
|
|
800
|
+
wildMultiplier?: number;
|
|
801
|
+
/** How multipliers stack: 'multiply', 'add', or 'highest' */
|
|
802
|
+
multiplierStacking?: 'multiply' | 'add' | 'highest';
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Result of expanding wild processing.
|
|
806
|
+
*/
|
|
807
|
+
interface IExpandingWildResult {
|
|
808
|
+
/** Whether expansion occurred */
|
|
809
|
+
success: boolean;
|
|
810
|
+
/** Reel indices that expanded */
|
|
811
|
+
expandedReels: number[];
|
|
812
|
+
/** All positions that became wild */
|
|
813
|
+
expandedPositions: Array<{
|
|
814
|
+
reel: number;
|
|
815
|
+
row: number;
|
|
816
|
+
}>;
|
|
817
|
+
/** Modified grid with expanded wilds */
|
|
818
|
+
modifiedGrid: ISymbol[][];
|
|
819
|
+
/** Total positions expanded */
|
|
820
|
+
totalExpanded: number;
|
|
821
|
+
/** Applied multiplier value */
|
|
822
|
+
appliedMultiplier: number;
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* Configuration for sticky wild mechanics.
|
|
826
|
+
*/
|
|
827
|
+
interface IStickyWildConfig {
|
|
828
|
+
/** Enable sticky wilds */
|
|
829
|
+
enabled: boolean;
|
|
830
|
+
/** Number of spins sticky wilds persist */
|
|
831
|
+
persistSpins: number;
|
|
832
|
+
/** Maximum number of sticky wilds allowed */
|
|
833
|
+
maxStickyWilds?: number;
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Result of sticky wild processing.
|
|
837
|
+
*/
|
|
838
|
+
interface IStickyWildResult {
|
|
839
|
+
/** Whether sticky wild state changed */
|
|
840
|
+
success: boolean;
|
|
841
|
+
/** Currently active sticky wilds */
|
|
842
|
+
activeStickyWilds: Array<{
|
|
843
|
+
reel: number;
|
|
844
|
+
row: number;
|
|
845
|
+
remainingSpins: number;
|
|
846
|
+
}>;
|
|
847
|
+
/** Sticky wilds that expired */
|
|
848
|
+
removedStickyWilds: Array<{
|
|
849
|
+
reel: number;
|
|
850
|
+
row: number;
|
|
851
|
+
}>;
|
|
852
|
+
/** Modified grid */
|
|
853
|
+
modifiedGrid: ISymbol[][];
|
|
854
|
+
/** Total active sticky wilds */
|
|
855
|
+
totalActive: number;
|
|
856
|
+
/** Total removed sticky wilds */
|
|
857
|
+
totalRemoved: number;
|
|
858
|
+
/** Whether more sticky wilds can be added */
|
|
859
|
+
canAddMore: boolean;
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Type of scatter trigger.
|
|
863
|
+
*/
|
|
864
|
+
type ScatterTriggerType = 'BONUS_TRIGGER' | 'REEL_COMBINATION_TRIGGER' | 'CLUSTER_TRIGGER' | 'COLLECTION_COMPLETE' | 'COLLECTION_EXPIRY_TRIGGER' | 'PROGRESSIVE_TRIGGER';
|
|
865
|
+
/**
|
|
866
|
+
* Feature types triggered by scatters.
|
|
867
|
+
*/
|
|
868
|
+
type ScatterFeatureType = 'FREE_SPINS' | 'ENHANCED_BONUS' | 'CLUSTER_BONUS' | 'COLLECTION_BONUS' | 'MINI_BONUS';
|
|
869
|
+
/**
|
|
870
|
+
* Individual scatter trigger event.
|
|
871
|
+
*/
|
|
872
|
+
interface IScatterTrigger {
|
|
873
|
+
/** Type of trigger */
|
|
874
|
+
type: ScatterTriggerType;
|
|
875
|
+
/** Whether trigger activated */
|
|
876
|
+
triggered: boolean;
|
|
877
|
+
/** Number of scatters involved */
|
|
878
|
+
scatterCount: number;
|
|
879
|
+
/** Feature type awarded */
|
|
880
|
+
featureType: ScatterFeatureType;
|
|
881
|
+
/** Free spins awarded (if applicable) */
|
|
882
|
+
awardedSpins?: number;
|
|
883
|
+
/** Cluster positions (for cluster triggers) */
|
|
884
|
+
clusterPositions?: Array<{
|
|
885
|
+
reel: number;
|
|
886
|
+
row: number;
|
|
887
|
+
}>;
|
|
888
|
+
/** Collected value (for collection triggers) */
|
|
889
|
+
collectedValue?: number;
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Multiplier zone configuration for scatters.
|
|
893
|
+
*/
|
|
894
|
+
interface IScatterMultiplierZone {
|
|
895
|
+
reelStart: number;
|
|
896
|
+
reelEnd: number;
|
|
897
|
+
rowStart: number;
|
|
898
|
+
rowEnd: number;
|
|
899
|
+
multiplier: number;
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Configuration for advanced scatter mechanics.
|
|
903
|
+
*/
|
|
904
|
+
interface IScatterConfig {
|
|
905
|
+
/** Enable scatter features */
|
|
906
|
+
enabled: boolean;
|
|
907
|
+
/** Minimum scatters for bonus trigger */
|
|
908
|
+
minScattersForTrigger?: number;
|
|
909
|
+
/** Feature type triggered */
|
|
910
|
+
triggeredFeature?: ScatterFeatureType;
|
|
911
|
+
/** Spin award table by scatter count */
|
|
912
|
+
spinAwardTable?: Record<number, number>;
|
|
913
|
+
/** Enable immediate scatter pays */
|
|
914
|
+
enableScatterPays?: boolean;
|
|
915
|
+
/** Pay table for scatter counts */
|
|
916
|
+
scatterPayTable?: Record<number, number>;
|
|
917
|
+
/** Scatter pay multiplier */
|
|
918
|
+
scatterMultiplier?: number;
|
|
919
|
+
/** Require scatters on specific reels */
|
|
920
|
+
requireSpecificReels?: boolean;
|
|
921
|
+
/** Required reel indices */
|
|
922
|
+
requiredReels?: number[];
|
|
923
|
+
/** Enable cluster-based triggers */
|
|
924
|
+
enableClusterTriggers?: boolean;
|
|
925
|
+
/** Minimum cluster size for trigger */
|
|
926
|
+
clusterSizeForTrigger?: number;
|
|
927
|
+
/** Enable progressive scatter accumulation */
|
|
928
|
+
enableProgressiveTrigger?: boolean;
|
|
929
|
+
/** Base threshold for progressive trigger */
|
|
930
|
+
baseProgressiveThreshold?: number;
|
|
931
|
+
/** Bonus spins for progressive trigger */
|
|
932
|
+
progressiveBonusSpins?: number;
|
|
933
|
+
/** Multiplier for progressive bonus */
|
|
934
|
+
progressiveMultiplier?: number;
|
|
935
|
+
/** Reset progressive on trigger */
|
|
936
|
+
progressiveResetOnTrigger?: boolean;
|
|
937
|
+
/** Enable scatter collection system */
|
|
938
|
+
enableCollection?: boolean;
|
|
939
|
+
/** Target scatter count for collection */
|
|
940
|
+
collectionTarget?: number;
|
|
941
|
+
/** Bonus spins on collection complete */
|
|
942
|
+
collectionBonusSpins?: number;
|
|
943
|
+
/** Auto-trigger when collection spins expire */
|
|
944
|
+
autoTriggerOnExpiry?: boolean;
|
|
945
|
+
/** Enable scatter transformation */
|
|
946
|
+
enableTransformation?: boolean;
|
|
947
|
+
/** Transformation type: 'to_wild' or 'to_multiplier' */
|
|
948
|
+
transformationType?: 'to_wild' | 'to_multiplier';
|
|
949
|
+
/** Multiplier for transformed wilds */
|
|
950
|
+
transformedWildMultiplier?: number;
|
|
951
|
+
/** Enable multiplier zones */
|
|
952
|
+
enableMultiplierZones?: boolean;
|
|
953
|
+
/** Multiplier zone definitions */
|
|
954
|
+
multiplierZones?: IScatterMultiplierZone[];
|
|
955
|
+
/** Zone multiplier stacking: 'multiply' or 'add' */
|
|
956
|
+
zoneMultiplierStacking?: 'multiply' | 'add';
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Result of scatter evaluation.
|
|
960
|
+
*/
|
|
961
|
+
interface IScatterResult {
|
|
962
|
+
/** Whether scatters present */
|
|
963
|
+
success: boolean;
|
|
964
|
+
/** Total scatter count */
|
|
965
|
+
scatterCount: number;
|
|
966
|
+
/** Total scatter value */
|
|
967
|
+
scatterValue: number;
|
|
968
|
+
/** Scatter positions on grid */
|
|
969
|
+
positions: Array<{
|
|
970
|
+
reel: number;
|
|
971
|
+
row: number;
|
|
972
|
+
symbol: ISymbol;
|
|
973
|
+
}>;
|
|
974
|
+
/** Triggers activated */
|
|
975
|
+
triggers: IScatterTrigger[];
|
|
976
|
+
/** Immediate scatter payout */
|
|
977
|
+
scatterPays: number;
|
|
978
|
+
/** Scatters collected (for collection system) */
|
|
979
|
+
collectedScatters: number;
|
|
980
|
+
}
|
|
981
|
+
/**
|
|
982
|
+
* Extended symbol interface with additional properties.
|
|
983
|
+
*/
|
|
984
|
+
interface ISymbol {
|
|
985
|
+
id: string | number;
|
|
986
|
+
value?: number;
|
|
987
|
+
isWild: boolean;
|
|
988
|
+
isScatter: boolean;
|
|
989
|
+
/** Weight for random generation */
|
|
990
|
+
weight?: number;
|
|
991
|
+
/** For wilds: multiplier value */
|
|
992
|
+
wildMultiplier?: number;
|
|
993
|
+
/** For expanding wilds: original symbol ID */
|
|
994
|
+
expandedFrom?: string | number;
|
|
995
|
+
/** For sticky wilds: is sticky */
|
|
996
|
+
isSticky?: boolean;
|
|
997
|
+
/** For sticky wilds: remaining spins */
|
|
998
|
+
remainingSpins?: number;
|
|
999
|
+
/** For sticky wilds: unique identifier */
|
|
1000
|
+
stickyId?: string;
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Win evaluation result.
|
|
1004
|
+
*/
|
|
1005
|
+
interface IWinEvaluation {
|
|
1006
|
+
/** Symbol ID that won */
|
|
1007
|
+
symbolId: number;
|
|
1008
|
+
/** Win amount */
|
|
1009
|
+
amount: number;
|
|
1010
|
+
/** Positions in the win */
|
|
1011
|
+
positions: Array<{
|
|
1012
|
+
reel: number;
|
|
1013
|
+
row: number;
|
|
1014
|
+
}>;
|
|
1015
|
+
/** Line index (for line wins) */
|
|
1016
|
+
lineIndex?: number;
|
|
1017
|
+
/** Way index (for ways wins) */
|
|
1018
|
+
wayIndex?: number;
|
|
1019
|
+
/** Multiplier applied */
|
|
1020
|
+
multiplier?: number;
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Game state with grid representation.
|
|
1024
|
+
*/
|
|
1025
|
+
interface IGameState {
|
|
1026
|
+
/** Grid of symbols [reel][row] */
|
|
1027
|
+
grid: ISymbol[][];
|
|
1028
|
+
/** Current bet */
|
|
1029
|
+
bet: number;
|
|
1030
|
+
/** Game mode */
|
|
1031
|
+
gameMode: number;
|
|
1032
|
+
/** Free spins remaining */
|
|
1033
|
+
freeSpinsRemaining?: number;
|
|
1034
|
+
/** Active bonus state */
|
|
1035
|
+
bonusState?: any;
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Money symbol interface for respins features.
|
|
1039
|
+
*/
|
|
1040
|
+
interface IMoneySymbol extends ISymbol {
|
|
1041
|
+
/** Is this a money/value symbol */
|
|
1042
|
+
isMoneySymbol?: boolean;
|
|
1043
|
+
/** Cash value of the symbol */
|
|
1044
|
+
value?: number;
|
|
1045
|
+
/** Is this a reset symbol (resets respin counter) */
|
|
1046
|
+
isResetSymbol?: boolean;
|
|
1047
|
+
/** Is this a jackpot symbol */
|
|
1048
|
+
isJackpotSymbol?: boolean;
|
|
1049
|
+
/** Jackpot type if applicable */
|
|
1050
|
+
jackpotType?: 'mini' | 'minor' | 'major' | 'grand';
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Trigger type for respins feature.
|
|
1054
|
+
*/
|
|
1055
|
+
type RespinsTriggerType = 'symbol_count' | 'specific_positions';
|
|
1056
|
+
/**
|
|
1057
|
+
* Position requirement for specific_positions trigger.
|
|
1058
|
+
*/
|
|
1059
|
+
interface IRespinsTriggerPosition {
|
|
1060
|
+
row: number;
|
|
1061
|
+
col: number;
|
|
1062
|
+
symbolId?: string | number;
|
|
1063
|
+
}
|
|
1064
|
+
/**
|
|
1065
|
+
* Weight configuration for symbol generation in respins.
|
|
1066
|
+
*/
|
|
1067
|
+
interface IRespinsSymbolWeight {
|
|
1068
|
+
symbolId: string | number;
|
|
1069
|
+
probability: number;
|
|
1070
|
+
baseValue?: number;
|
|
1071
|
+
isMoneySymbol?: boolean;
|
|
1072
|
+
isResetSymbol?: boolean;
|
|
1073
|
+
isJackpotSymbol?: boolean;
|
|
1074
|
+
jackpotType?: 'mini' | 'minor' | 'major' | 'grand';
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Full screen bonus configuration.
|
|
1078
|
+
*/
|
|
1079
|
+
interface IRespinsFullScreenBonus {
|
|
1080
|
+
multiplier: number;
|
|
1081
|
+
additionalAward?: number;
|
|
1082
|
+
}
|
|
1083
|
+
/**
|
|
1084
|
+
* Configuration for respins/hold & win mechanics.
|
|
1085
|
+
*/
|
|
1086
|
+
interface IRespinsConfig {
|
|
1087
|
+
/** Enable respins feature */
|
|
1088
|
+
enabled: boolean;
|
|
1089
|
+
/** Initial number of respins awarded */
|
|
1090
|
+
initialRespins?: number;
|
|
1091
|
+
/** Trigger type */
|
|
1092
|
+
triggerType: RespinsTriggerType;
|
|
1093
|
+
/** Minimum special symbols needed for trigger */
|
|
1094
|
+
minTriggerSymbols?: number;
|
|
1095
|
+
/** Specific positions required for trigger */
|
|
1096
|
+
triggerPositions?: IRespinsTriggerPosition[];
|
|
1097
|
+
/** Symbol weights for respin rounds */
|
|
1098
|
+
symbolWeights?: IRespinsSymbolWeight[];
|
|
1099
|
+
/** End feature if no new special symbols land */
|
|
1100
|
+
endOnNoSpecial?: boolean;
|
|
1101
|
+
/** Full screen bonus configuration */
|
|
1102
|
+
fullScreenBonus?: IRespinsFullScreenBonus;
|
|
1103
|
+
/** Grid size for respins (if different from base game) */
|
|
1104
|
+
gridRows?: number;
|
|
1105
|
+
gridCols?: number;
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Single step in a respins sequence.
|
|
1109
|
+
*/
|
|
1110
|
+
interface IRespinsStep {
|
|
1111
|
+
/** Respins remaining after this step */
|
|
1112
|
+
respinsRemaining: number;
|
|
1113
|
+
/** All locked positions */
|
|
1114
|
+
lockedPositions: Array<{
|
|
1115
|
+
row: number;
|
|
1116
|
+
col: number;
|
|
1117
|
+
}>;
|
|
1118
|
+
/** New symbols that landed */
|
|
1119
|
+
newSymbols: Array<{
|
|
1120
|
+
row: number;
|
|
1121
|
+
col: number;
|
|
1122
|
+
symbolId: string | number;
|
|
1123
|
+
}>;
|
|
1124
|
+
/** Value added in this step */
|
|
1125
|
+
valuesAdded: number;
|
|
1126
|
+
/** Jackpots awarded in this step */
|
|
1127
|
+
jackpotsAwarded: string[];
|
|
1128
|
+
/** Reason for this step */
|
|
1129
|
+
reason: 'initial_trigger' | 'respins' | 'jackpot_collected' | 'full_screen_bonus' | 'no_new_symbols';
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1132
|
+
* Result of respins feature execution.
|
|
1133
|
+
*/
|
|
1134
|
+
interface IRespinsResult {
|
|
1135
|
+
/** Whether feature was triggered */
|
|
1136
|
+
triggered: boolean;
|
|
1137
|
+
/** All steps in the respins sequence */
|
|
1138
|
+
steps: IRespinsStep[];
|
|
1139
|
+
/** Final total value collected */
|
|
1140
|
+
finalValue: number;
|
|
1141
|
+
/** All jackpots collected */
|
|
1142
|
+
jackpotsCollected: string[];
|
|
1143
|
+
/** Final locked positions */
|
|
1144
|
+
lockedPositions: Array<{
|
|
1145
|
+
row: number;
|
|
1146
|
+
col: number;
|
|
1147
|
+
}>;
|
|
1148
|
+
/** Total respins used */
|
|
1149
|
+
totalRespinsUsed: number;
|
|
1150
|
+
}
|
|
1151
|
+
type TransactionType = 'bet' | 'payout' | 'deposit' | 'withdrawal' | 'bonus_payout' | 'jackpot_win' | 'cascade_win' | 'scatter_win' | 'fee' | 'refund' | 'transfer';
|
|
1152
|
+
interface IWalletBalance {
|
|
1153
|
+
userId: string;
|
|
1154
|
+
amount: string;
|
|
1155
|
+
version: number;
|
|
1156
|
+
currency?: string;
|
|
1157
|
+
updatedAt: Date;
|
|
1158
|
+
}
|
|
1159
|
+
interface ITransaction {
|
|
1160
|
+
id: string;
|
|
1161
|
+
userId: string;
|
|
1162
|
+
type: TransactionType;
|
|
1163
|
+
amount: string;
|
|
1164
|
+
balanceBefore: string;
|
|
1165
|
+
balanceAfter: string;
|
|
1166
|
+
referenceId: string;
|
|
1167
|
+
metadata?: Record<string, any>;
|
|
1168
|
+
createdAt: Date;
|
|
1169
|
+
}
|
|
1170
|
+
interface IWalletConfig {
|
|
1171
|
+
currency?: string;
|
|
1172
|
+
precision?: number;
|
|
1173
|
+
allowNegative?: boolean;
|
|
1174
|
+
minBalance?: number;
|
|
1175
|
+
maxBalance?: number;
|
|
1176
|
+
}
|
|
1177
|
+
interface ITransactionResult {
|
|
1178
|
+
success: boolean;
|
|
1179
|
+
balance?: string;
|
|
1180
|
+
transactionId?: string;
|
|
1181
|
+
error?: string;
|
|
1182
|
+
code?: string;
|
|
1183
|
+
message?: string;
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Storage Interface - Implement this to connect to your DB (Postgres, Mongo, etc.)
|
|
1187
|
+
*/
|
|
1188
|
+
interface IWalletStorage {
|
|
1189
|
+
getBalance(userId: string): Promise<IWalletBalance | null>;
|
|
1190
|
+
updateBalance(userId: string, amount: string, version: number): Promise<IWalletBalance | null>;
|
|
1191
|
+
recordTransaction(transaction: ITransaction): Promise<void>;
|
|
1192
|
+
getTransactionHistory(userId: string, limit?: number): Promise<ITransaction[]>;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
declare class ConfigBuilder {
|
|
1196
|
+
private config;
|
|
1197
|
+
setGameId(id: string): this;
|
|
1198
|
+
setReelCount(count: number): this;
|
|
1199
|
+
setRowCount(count: number): this;
|
|
1200
|
+
setSymbolMap(map: SymbolMap): this;
|
|
1201
|
+
setPaytableData(data: PaytableData): this;
|
|
1202
|
+
setReelStrips(strips: ReelStrip[]): this;
|
|
1203
|
+
setLinePatterns(patterns: PaylinePattern[]): this;
|
|
1204
|
+
setCurrency(code: string, symbol: string, decimalSeparator?: string, thousandSeparator?: string, minDecimalPlaces?: number): this;
|
|
1205
|
+
setFeatures(features: IGameConfigData['features']): this;
|
|
1206
|
+
setBetRange(min: number, max: number, step: number, defaultBet?: number): this;
|
|
1207
|
+
build(): IGameConfigData;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
interface IBalanceProvider {
|
|
1211
|
+
getBalance(playerId: string): number;
|
|
1212
|
+
setBalance(playerId: string, amount: number): void;
|
|
1213
|
+
}
|
|
1214
|
+
declare class GameSession {
|
|
1215
|
+
private config;
|
|
1216
|
+
private playerId;
|
|
1217
|
+
private balanceProvider;
|
|
1218
|
+
private state;
|
|
1219
|
+
private spinEvaluator;
|
|
1220
|
+
private bonusManager;
|
|
1221
|
+
private historyManager;
|
|
1222
|
+
private rng;
|
|
1223
|
+
constructor(config: IGameConfigData, playerId: string, balanceProvider: IBalanceProvider, seed?: number);
|
|
1224
|
+
/**
|
|
1225
|
+
* Get the current full player state.
|
|
1226
|
+
*/
|
|
1227
|
+
getState(): IPlayerState;
|
|
1228
|
+
/**
|
|
1229
|
+
* Build the INIT response for the client.
|
|
1230
|
+
*/
|
|
1231
|
+
getInitResponse(): IInitResponse;
|
|
1232
|
+
/**
|
|
1233
|
+
* Set the player's bet.
|
|
1234
|
+
*/
|
|
1235
|
+
setBet(bet: number): void;
|
|
1236
|
+
/**
|
|
1237
|
+
* Process a spin request.
|
|
1238
|
+
*/
|
|
1239
|
+
spin(request: ISpinRequestData): ISpinResponseData;
|
|
1240
|
+
/**
|
|
1241
|
+
* Get history.
|
|
1242
|
+
*/
|
|
1243
|
+
getHistory(limit?: number): IHistoryResponse;
|
|
1244
|
+
/**
|
|
1245
|
+
* Process a bonus action (e.g., pick).
|
|
1246
|
+
*/
|
|
1247
|
+
bonusAction(action: string, payload?: any): IBonusResponse;
|
|
1248
|
+
/**
|
|
1249
|
+
* Helper to create an error response.
|
|
1250
|
+
*/
|
|
1251
|
+
private createErrorResponse;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
/**
|
|
1255
|
+
* Deterministic or non-deterministic RNG wrapper.
|
|
1256
|
+
* For production, you can use a cryptographically secure generator.
|
|
1257
|
+
*/
|
|
1258
|
+
declare class Random {
|
|
1259
|
+
private seed?;
|
|
1260
|
+
constructor(seed?: number);
|
|
1261
|
+
next(): number;
|
|
1262
|
+
nextInt(min: number, max: number): number;
|
|
1263
|
+
pick<T>(arr: T[]): T;
|
|
1264
|
+
shuffle<T>(arr: T[]): T[];
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
declare class SpinEvaluator {
|
|
1268
|
+
private config;
|
|
1269
|
+
private rng;
|
|
1270
|
+
constructor(config: IGameConfigData, rng: Random);
|
|
1271
|
+
/**
|
|
1272
|
+
* Generate a random spin result (visible symbols for each reel).
|
|
1273
|
+
* Returns a 2D array: [reelIndex][rowIndex]
|
|
1274
|
+
*/
|
|
1275
|
+
generateResult(): number[][];
|
|
1276
|
+
/**
|
|
1277
|
+
* Evaluate the result against all paylines and the paytable.
|
|
1278
|
+
* Returns win lines and total win amount.
|
|
1279
|
+
*/
|
|
1280
|
+
evaluateResult(result: number[][], stakePerLine: number): {
|
|
1281
|
+
winLines: IWinLine[];
|
|
1282
|
+
totalWin: number;
|
|
1283
|
+
};
|
|
1284
|
+
/**
|
|
1285
|
+
* Full spin processing: generate result, evaluate, build response.
|
|
1286
|
+
*/
|
|
1287
|
+
spin(request: ISpinRequestData): Omit<ISpinResponseData, 'balanceAfter'>;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
declare class BonusManager {
|
|
1291
|
+
private rng;
|
|
1292
|
+
private bonusState;
|
|
1293
|
+
constructor(rng: Random);
|
|
1294
|
+
/**
|
|
1295
|
+
* Check if a spin result should trigger a bonus.
|
|
1296
|
+
* This is a simple example: trigger on 3+ scatter symbols (e.g., symbol ID 9).
|
|
1297
|
+
*/
|
|
1298
|
+
checkTrigger(result: number[][]): {
|
|
1299
|
+
triggered: boolean;
|
|
1300
|
+
data?: any;
|
|
1301
|
+
};
|
|
1302
|
+
/**
|
|
1303
|
+
* Start a free spin bonus.
|
|
1304
|
+
*/
|
|
1305
|
+
startFreeSpins(spins: number, multiplier: number, bet: number): IFreeSpinBonus;
|
|
1306
|
+
/**
|
|
1307
|
+
* Start a pick bonus (e.g., pick items for prizes).
|
|
1308
|
+
*/
|
|
1309
|
+
startPickBonus(items: {
|
|
1310
|
+
id: string;
|
|
1311
|
+
label: string;
|
|
1312
|
+
value: number;
|
|
1313
|
+
}[]): IPickBonus;
|
|
1314
|
+
/**
|
|
1315
|
+
* Process a pick action.
|
|
1316
|
+
*/
|
|
1317
|
+
pickItem(itemId: string): {
|
|
1318
|
+
win: number;
|
|
1319
|
+
remaining: IPickBonus['items'];
|
|
1320
|
+
};
|
|
1321
|
+
/**
|
|
1322
|
+
* Process a free spin: deduct one spin, return the spin result.
|
|
1323
|
+
* The spin result is generated by the SpinEvaluator, but we need to apply the multiplier.
|
|
1324
|
+
*/
|
|
1325
|
+
processFreeSpin(spinResult: Omit<ISpinResponseData, 'balanceAfter'>): Omit<ISpinResponseData, 'balanceAfter'> & {
|
|
1326
|
+
spinsRemaining: number;
|
|
1327
|
+
};
|
|
1328
|
+
/**
|
|
1329
|
+
* Check if a bonus is active.
|
|
1330
|
+
*/
|
|
1331
|
+
isActive(): boolean;
|
|
1332
|
+
/**
|
|
1333
|
+
* Get the current bonus state.
|
|
1334
|
+
*/
|
|
1335
|
+
getState(): IBonusState | null;
|
|
1336
|
+
/**
|
|
1337
|
+
* End the current bonus.
|
|
1338
|
+
*/
|
|
1339
|
+
endBonus(): void;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
declare class HistoryManager {
|
|
1343
|
+
private history;
|
|
1344
|
+
private maxEntries;
|
|
1345
|
+
constructor(maxEntries?: number);
|
|
1346
|
+
/**
|
|
1347
|
+
* Add a spin result to history.
|
|
1348
|
+
*/
|
|
1349
|
+
addEntry(result: number[][], bet: number, win: number, balance: number, gameMode: 0 | 1): void;
|
|
1350
|
+
/**
|
|
1351
|
+
* Get all history entries.
|
|
1352
|
+
*/
|
|
1353
|
+
getEntries(): IHistoryEntry[];
|
|
1354
|
+
/**
|
|
1355
|
+
* Get the last N entries.
|
|
1356
|
+
*/
|
|
1357
|
+
getLast(n: number): IHistoryEntry[];
|
|
1358
|
+
/**
|
|
1359
|
+
* Clear history.
|
|
1360
|
+
*/
|
|
1361
|
+
clear(): void;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
/**
|
|
1365
|
+
* Manages progressive jackpot systems.
|
|
1366
|
+
* Handles contributions, tier tracking, and jackpot triggers.
|
|
1367
|
+
*/
|
|
1368
|
+
declare class JackpotManager {
|
|
1369
|
+
private config;
|
|
1370
|
+
private rng;
|
|
1371
|
+
private tiers;
|
|
1372
|
+
constructor(config: IJackpotConfig, rng: Random);
|
|
1373
|
+
/**
|
|
1374
|
+
* Calculate jackpot contribution from a bet.
|
|
1375
|
+
* Returns contributions for each tier.
|
|
1376
|
+
*/
|
|
1377
|
+
calculateContribution(totalStake: number): IJackpotContribution[];
|
|
1378
|
+
/**
|
|
1379
|
+
* Check if a jackpot was triggered.
|
|
1380
|
+
* Uses probability-based triggering.
|
|
1381
|
+
*/
|
|
1382
|
+
checkTrigger(): IJackpotWin | null;
|
|
1383
|
+
/**
|
|
1384
|
+
* Get current jackpot amounts for all tiers.
|
|
1385
|
+
*/
|
|
1386
|
+
getCurrentAmounts(): Record<string, number>;
|
|
1387
|
+
/**
|
|
1388
|
+
* Get a specific tier's current amount.
|
|
1389
|
+
*/
|
|
1390
|
+
getTierAmount(tierId: string): number | undefined;
|
|
1391
|
+
/**
|
|
1392
|
+
* Update a tier's current amount (for external sync).
|
|
1393
|
+
*/
|
|
1394
|
+
updateTierAmount(tierId: string, amount: number): void;
|
|
1395
|
+
/**
|
|
1396
|
+
* Check if a bet is eligible for jackpot (based on minBetRequired).
|
|
1397
|
+
*/
|
|
1398
|
+
isBetEligible(totalStake: number): boolean;
|
|
1399
|
+
/**
|
|
1400
|
+
* Get configuration for a specific tier.
|
|
1401
|
+
*/
|
|
1402
|
+
getTierConfig(tierId: string): IJackpotTier | undefined;
|
|
1403
|
+
/**
|
|
1404
|
+
* Get all tier configurations.
|
|
1405
|
+
*/
|
|
1406
|
+
getAllTiers(): IJackpotTier[];
|
|
1407
|
+
/**
|
|
1408
|
+
* Reset all tiers to seed amounts.
|
|
1409
|
+
*/
|
|
1410
|
+
resetAll(): void;
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
/**
|
|
1414
|
+
* Evaluator for "ways to win" mechanics (e.g., 243 ways, 1024 ways).
|
|
1415
|
+
* Instead of fixed paylines, wins are awarded for matching symbols
|
|
1416
|
+
* on adjacent reels starting from the leftmost reel.
|
|
1417
|
+
*/
|
|
1418
|
+
declare class WaysEvaluator {
|
|
1419
|
+
private config;
|
|
1420
|
+
private paytableData;
|
|
1421
|
+
private reelCount;
|
|
1422
|
+
private rowCount;
|
|
1423
|
+
constructor(config: IWaysConfig, paytableData: PaytableData, reelCount: number, rowCount: number);
|
|
1424
|
+
/**
|
|
1425
|
+
* Evaluate a spin result for ways-to-win.
|
|
1426
|
+
* Returns win lines and total win amount.
|
|
1427
|
+
*/
|
|
1428
|
+
evaluate(result: number[][], stakePerLine: number): {
|
|
1429
|
+
winLines: IWinLine[];
|
|
1430
|
+
totalWin: number;
|
|
1431
|
+
ways: number;
|
|
1432
|
+
};
|
|
1433
|
+
/**
|
|
1434
|
+
* Get the maximum possible ways for this configuration.
|
|
1435
|
+
*/
|
|
1436
|
+
getMaxWays(): number;
|
|
1437
|
+
/**
|
|
1438
|
+
* Check if ways-to-win is enabled.
|
|
1439
|
+
*/
|
|
1440
|
+
isEnabled(): boolean;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
/**
|
|
1444
|
+
* Manages gamble mini-games (card guess, ladder, wheel).
|
|
1445
|
+
* Allows players to risk their winnings for a chance to multiply.
|
|
1446
|
+
*/
|
|
1447
|
+
declare class GambleManager {
|
|
1448
|
+
private config;
|
|
1449
|
+
private rng;
|
|
1450
|
+
private consecutiveGambles;
|
|
1451
|
+
private currentGambleWin;
|
|
1452
|
+
constructor(config: IGambleConfig, rng: Random);
|
|
1453
|
+
/**
|
|
1454
|
+
* Check if gamble feature is enabled and available.
|
|
1455
|
+
*/
|
|
1456
|
+
canGamble(currentWin: number): boolean;
|
|
1457
|
+
/**
|
|
1458
|
+
* Process a gamble request.
|
|
1459
|
+
*/
|
|
1460
|
+
processGamble(request: IGambleRequest): IGambleResponse;
|
|
1461
|
+
/**
|
|
1462
|
+
* Card game: guess if card is red or black (50/50 chance).
|
|
1463
|
+
*/
|
|
1464
|
+
private playCardGame;
|
|
1465
|
+
/**
|
|
1466
|
+
* Ladder game: 60% chance to win, 40% to lose.
|
|
1467
|
+
*/
|
|
1468
|
+
private playLadderGame;
|
|
1469
|
+
/**
|
|
1470
|
+
* Wheel game: multiple outcomes based on wheel segments.
|
|
1471
|
+
*/
|
|
1472
|
+
private playWheelGame;
|
|
1473
|
+
/**
|
|
1474
|
+
* Get current consecutive gamble count.
|
|
1475
|
+
*/
|
|
1476
|
+
getConsecutiveGambles(): number;
|
|
1477
|
+
/**
|
|
1478
|
+
* Reset gamble state (e.g., after collecting winnings).
|
|
1479
|
+
*/
|
|
1480
|
+
reset(): void;
|
|
1481
|
+
/**
|
|
1482
|
+
* Get the current gamble win amount.
|
|
1483
|
+
*/
|
|
1484
|
+
getCurrentGambleWin(): number;
|
|
1485
|
+
/**
|
|
1486
|
+
* Get gamble configuration.
|
|
1487
|
+
*/
|
|
1488
|
+
getConfig(): IGambleConfig;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
/**
|
|
1492
|
+
* Manages "buy bonus" feature.
|
|
1493
|
+
* Allows players to purchase direct entry to bonus rounds.
|
|
1494
|
+
*/
|
|
1495
|
+
declare class BuyBonusManager {
|
|
1496
|
+
private config;
|
|
1497
|
+
private purchasesThisSession;
|
|
1498
|
+
private lastPurchaseTime;
|
|
1499
|
+
constructor(config: IBuyBonusConfig);
|
|
1500
|
+
/**
|
|
1501
|
+
* Check if buying bonus is enabled and available.
|
|
1502
|
+
*/
|
|
1503
|
+
canBuyBonus(currentBet: number): {
|
|
1504
|
+
canBuy: boolean;
|
|
1505
|
+
reason?: string;
|
|
1506
|
+
cost?: number;
|
|
1507
|
+
};
|
|
1508
|
+
/**
|
|
1509
|
+
* Calculate the cost to buy bonus.
|
|
1510
|
+
*/
|
|
1511
|
+
calculateCost(currentBet: number): number;
|
|
1512
|
+
/**
|
|
1513
|
+
* Record a bonus purchase.
|
|
1514
|
+
*/
|
|
1515
|
+
recordPurchase(): void;
|
|
1516
|
+
/**
|
|
1517
|
+
* Get the number of purchases made this session.
|
|
1518
|
+
*/
|
|
1519
|
+
getPurchasesThisSession(): number;
|
|
1520
|
+
/**
|
|
1521
|
+
* Reset session tracking.
|
|
1522
|
+
*/
|
|
1523
|
+
resetSession(): void;
|
|
1524
|
+
/**
|
|
1525
|
+
* Get configuration.
|
|
1526
|
+
*/
|
|
1527
|
+
getConfig(): IBuyBonusConfig;
|
|
1528
|
+
/**
|
|
1529
|
+
* Create a spin response that triggers bonus (for buy bonus feature).
|
|
1530
|
+
* This marks the spin as having triggered the bonus.
|
|
1531
|
+
*/
|
|
1532
|
+
createBonusTriggerSpin(baseSpinResult: Omit<ISpinResponseData, 'balanceAfter'>, bonusData: any): Omit<ISpinResponseData, 'balanceAfter'>;
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
/**
|
|
1536
|
+
* CascadingReelsManager - Handles tumbling/cascading reel mechanics
|
|
1537
|
+
*
|
|
1538
|
+
* Features:
|
|
1539
|
+
* - Symbol removal after wins
|
|
1540
|
+
* - Gravity-based symbol drops
|
|
1541
|
+
* - New symbol generation at top
|
|
1542
|
+
* - Chain reaction evaluation
|
|
1543
|
+
* - Progressive multiplier support
|
|
1544
|
+
* - Cascade termination conditions
|
|
1545
|
+
*/
|
|
1546
|
+
declare class CascadingReelsManager {
|
|
1547
|
+
private config;
|
|
1548
|
+
constructor(config: ICascadeConfig);
|
|
1549
|
+
/**
|
|
1550
|
+
* Execute a full cascade sequence until no more wins occur
|
|
1551
|
+
*/
|
|
1552
|
+
executeCascade(gameState: IGameState, initialWins: IWinEvaluation[]): ICascadeResult;
|
|
1553
|
+
/**
|
|
1554
|
+
* Remove symbols that are part of winning combinations
|
|
1555
|
+
*/
|
|
1556
|
+
private removeWinningSymbols;
|
|
1557
|
+
/**
|
|
1558
|
+
* Apply gravity to make symbols fall down into empty positions
|
|
1559
|
+
*/
|
|
1560
|
+
private applyGravity;
|
|
1561
|
+
/**
|
|
1562
|
+
* Fill empty positions at the top with new random symbols
|
|
1563
|
+
*/
|
|
1564
|
+
private fillEmptyPositions;
|
|
1565
|
+
/**
|
|
1566
|
+
* Generate a symbol based on weighted probabilities
|
|
1567
|
+
*/
|
|
1568
|
+
private generateWeightedSymbol;
|
|
1569
|
+
/**
|
|
1570
|
+
* Evaluate wins on the current grid state
|
|
1571
|
+
* This is a simplified version - in production you'd integrate with your WinEvaluator
|
|
1572
|
+
*/
|
|
1573
|
+
private evaluateWins;
|
|
1574
|
+
/**
|
|
1575
|
+
* Check if a cascade sequence should trigger special features
|
|
1576
|
+
*/
|
|
1577
|
+
checkCascadeTriggers(cascadeResult: ICascadeResult): {
|
|
1578
|
+
triggers: string[];
|
|
1579
|
+
data?: any;
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
/**
|
|
1584
|
+
* ExpandingWildsManager - Handles expanding and sticky wild mechanics
|
|
1585
|
+
*
|
|
1586
|
+
* Features:
|
|
1587
|
+
* - Wild expansion to cover entire reel
|
|
1588
|
+
* - Sticky wilds that persist for multiple spins
|
|
1589
|
+
* - Wild multiplier application
|
|
1590
|
+
* - Interaction with win evaluation
|
|
1591
|
+
* - Visual position tracking for animations
|
|
1592
|
+
*/
|
|
1593
|
+
declare class ExpandingWildsManager {
|
|
1594
|
+
private expandConfig;
|
|
1595
|
+
private stickyConfig;
|
|
1596
|
+
constructor(expandConfig: IExpandingWildConfig, stickyConfig?: IStickyWildConfig);
|
|
1597
|
+
/**
|
|
1598
|
+
* Process expanding wilds on the current grid
|
|
1599
|
+
*/
|
|
1600
|
+
processExpandingWilds(gameState: IGameState): IExpandingWildResult;
|
|
1601
|
+
/**
|
|
1602
|
+
* Determine if a reel should expand based on configuration
|
|
1603
|
+
*/
|
|
1604
|
+
private shouldReelExpand;
|
|
1605
|
+
/**
|
|
1606
|
+
* Check if wilds exist in specific configured positions
|
|
1607
|
+
*/
|
|
1608
|
+
private hasWildInSpecificPositions;
|
|
1609
|
+
/**
|
|
1610
|
+
* Apply sticky wilds logic for persistent wilds across spins
|
|
1611
|
+
*/
|
|
1612
|
+
processStickyWilds(gameState: IGameState, existingStickyWilds: Array<{
|
|
1613
|
+
reel: number;
|
|
1614
|
+
row: number;
|
|
1615
|
+
remainingSpins: number;
|
|
1616
|
+
}>): IStickyWildResult;
|
|
1617
|
+
/**
|
|
1618
|
+
* Add new sticky wilds to the grid
|
|
1619
|
+
*/
|
|
1620
|
+
addStickyWilds(gameState: IGameState, positions: Array<{
|
|
1621
|
+
reel: number;
|
|
1622
|
+
row: number;
|
|
1623
|
+
}>, persistSpins?: number): IStickyWildResult;
|
|
1624
|
+
/**
|
|
1625
|
+
* Calculate multiplier effect from wilds in a win line
|
|
1626
|
+
*/
|
|
1627
|
+
calculateWildMultiplier(winPositions: Array<{
|
|
1628
|
+
reel: number;
|
|
1629
|
+
row: number;
|
|
1630
|
+
}>, grid: ISymbol[][]): number;
|
|
1631
|
+
/**
|
|
1632
|
+
* Check for special wild interactions (e.g., expanding wild meeting sticky wild)
|
|
1633
|
+
*/
|
|
1634
|
+
checkWildInteractions(grid: ISymbol[][]): {
|
|
1635
|
+
interactions: string[];
|
|
1636
|
+
data?: any;
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
/**
|
|
1641
|
+
* ScatterEnhancementsManager - Advanced scatter symbol mechanics
|
|
1642
|
+
*
|
|
1643
|
+
* Features:
|
|
1644
|
+
* - Configurable scatter trigger conditions
|
|
1645
|
+
* - Scatter collection systems
|
|
1646
|
+
* - Progressive scatter triggers
|
|
1647
|
+
* - Scatter multiplier zones
|
|
1648
|
+
* - Scatter transformation mechanics
|
|
1649
|
+
* - Dynamic scatter behavior
|
|
1650
|
+
*/
|
|
1651
|
+
declare class ScatterEnhancementsManager {
|
|
1652
|
+
private config;
|
|
1653
|
+
constructor(config: IScatterConfig);
|
|
1654
|
+
/**
|
|
1655
|
+
* Evaluate scatter symbols on the current grid
|
|
1656
|
+
*/
|
|
1657
|
+
evaluateScatters(gameState: IGameState): IScatterResult;
|
|
1658
|
+
/**
|
|
1659
|
+
* Check if scatter conditions trigger bonus features
|
|
1660
|
+
*/
|
|
1661
|
+
private checkTriggerConditions;
|
|
1662
|
+
/**
|
|
1663
|
+
* Calculate number of spins awarded based on scatter count
|
|
1664
|
+
*/
|
|
1665
|
+
private calculateAwardedSpins;
|
|
1666
|
+
/**
|
|
1667
|
+
* Calculate immediate scatter payouts
|
|
1668
|
+
*/
|
|
1669
|
+
private calculateScatterPays;
|
|
1670
|
+
/**
|
|
1671
|
+
* Find clusters of adjacent scatter symbols
|
|
1672
|
+
*/
|
|
1673
|
+
private findScatterClusters;
|
|
1674
|
+
/**
|
|
1675
|
+
* Flood fill algorithm to find connected scatter positions
|
|
1676
|
+
*/
|
|
1677
|
+
private floodFillCluster;
|
|
1678
|
+
/**
|
|
1679
|
+
* Manage scatter collection system (collect scatters over multiple spins)
|
|
1680
|
+
*/
|
|
1681
|
+
manageScatterCollection(currentScatters: IScatterResult, collectedData: {
|
|
1682
|
+
count: number;
|
|
1683
|
+
values: number[];
|
|
1684
|
+
spinsRemaining: number;
|
|
1685
|
+
}): {
|
|
1686
|
+
updated: typeof collectedData;
|
|
1687
|
+
collectionTrigger?: IScatterTrigger;
|
|
1688
|
+
};
|
|
1689
|
+
/**
|
|
1690
|
+
* Apply scatter transformation mechanics (e.g., scatters becoming wilds)
|
|
1691
|
+
*/
|
|
1692
|
+
transformScatters(gameState: IGameState, scatterPositions: Array<{
|
|
1693
|
+
reel: number;
|
|
1694
|
+
row: number;
|
|
1695
|
+
}>): {
|
|
1696
|
+
modifiedGrid: ISymbol[][];
|
|
1697
|
+
transformed: Array<{
|
|
1698
|
+
reel: number;
|
|
1699
|
+
row: number;
|
|
1700
|
+
}>;
|
|
1701
|
+
};
|
|
1702
|
+
/**
|
|
1703
|
+
* Check for scatter in multiplier zones (special grid areas)
|
|
1704
|
+
*/
|
|
1705
|
+
checkMultiplierZones(scatterPositions: Array<{
|
|
1706
|
+
reel: number;
|
|
1707
|
+
row: number;
|
|
1708
|
+
}>): {
|
|
1709
|
+
totalMultiplier: number;
|
|
1710
|
+
zoneHits: Array<{
|
|
1711
|
+
reel: number;
|
|
1712
|
+
row: number;
|
|
1713
|
+
multiplier: number;
|
|
1714
|
+
}>;
|
|
1715
|
+
};
|
|
1716
|
+
/**
|
|
1717
|
+
* Implement progressive scatter trigger (accumulates across game session)
|
|
1718
|
+
*/
|
|
1719
|
+
updateProgressiveScatter(currentCount: number, progressiveState: {
|
|
1720
|
+
accumulated: number;
|
|
1721
|
+
threshold: number;
|
|
1722
|
+
level: number;
|
|
1723
|
+
}): {
|
|
1724
|
+
updated: typeof progressiveState;
|
|
1725
|
+
triggered: boolean;
|
|
1726
|
+
reward?: any;
|
|
1727
|
+
};
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
/**
|
|
1731
|
+
* RespinsManager - Handles Hold & Win / Respins mechanics
|
|
1732
|
+
*
|
|
1733
|
+
* Features:
|
|
1734
|
+
* - Locking symbols for respin rounds
|
|
1735
|
+
* - Money symbol collection and value summation
|
|
1736
|
+
* - Reset symbols that grant additional respins
|
|
1737
|
+
* - Jackpot symbols (Mini, Minor, Major, Grand)
|
|
1738
|
+
* - Progressive feature triggers
|
|
1739
|
+
* - Configurable grid sizes and respin counts
|
|
1740
|
+
*/
|
|
1741
|
+
declare class RespinsManager {
|
|
1742
|
+
private config;
|
|
1743
|
+
constructor(config: IRespinsConfig);
|
|
1744
|
+
/**
|
|
1745
|
+
* Check if respin feature should be triggered
|
|
1746
|
+
*/
|
|
1747
|
+
checkTrigger(gameState: IGameState): boolean;
|
|
1748
|
+
/**
|
|
1749
|
+
* Count special symbols (money, reset, jackpot) on the grid
|
|
1750
|
+
*/
|
|
1751
|
+
private countSpecialSymbols;
|
|
1752
|
+
/**
|
|
1753
|
+
* Check if special symbols are in required positions
|
|
1754
|
+
*/
|
|
1755
|
+
private checkSpecificPositions;
|
|
1756
|
+
/**
|
|
1757
|
+
* Check if a symbol is a special respin symbol
|
|
1758
|
+
*/
|
|
1759
|
+
private isSpecialSymbol;
|
|
1760
|
+
/**
|
|
1761
|
+
* Execute the respins feature
|
|
1762
|
+
*/
|
|
1763
|
+
execute(gameState: IGameState): IRespinsResult;
|
|
1764
|
+
/**
|
|
1765
|
+
* Generate a special symbol for respins (weighted random)
|
|
1766
|
+
* In production, this should use a certified RNG with configurable weights
|
|
1767
|
+
*/
|
|
1768
|
+
private generateRespinsSymbol;
|
|
1769
|
+
/**
|
|
1770
|
+
* Calculate potential payout for respins feature
|
|
1771
|
+
*/
|
|
1772
|
+
calculatePotentialPayout(betAmount: number): number;
|
|
1773
|
+
/**
|
|
1774
|
+
* Get configuration for client-side preview
|
|
1775
|
+
*/
|
|
1776
|
+
getConfig(): IRespinsConfig;
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
/**
|
|
1780
|
+
* In-Memory Implementation of IWalletStorage
|
|
1781
|
+
* Useful for testing or serverless environments without a DB connection.
|
|
1782
|
+
* NOT recommended for production persistent storage.
|
|
1783
|
+
*/
|
|
1784
|
+
declare class InMemoryWalletStorage implements IWalletStorage {
|
|
1785
|
+
private balances;
|
|
1786
|
+
private transactions;
|
|
1787
|
+
getBalance(userId: string): Promise<IWalletBalance | null>;
|
|
1788
|
+
updateBalance(userId: string, amount: string, version: number): Promise<IWalletBalance | null>;
|
|
1789
|
+
recordTransaction(transaction: ITransaction): Promise<void>;
|
|
1790
|
+
getTransactionHistory(userId: string, limit?: number): Promise<ITransaction[]>;
|
|
1791
|
+
}
|
|
1792
|
+
/**
|
|
1793
|
+
* WalletManager
|
|
1794
|
+
* Handles atomic financial operations for the slot engine.
|
|
1795
|
+
*/
|
|
1796
|
+
declare class WalletManager {
|
|
1797
|
+
private storage;
|
|
1798
|
+
private config;
|
|
1799
|
+
constructor(storage: IWalletStorage, config: IWalletConfig);
|
|
1800
|
+
/**
|
|
1801
|
+
* Place a bet (deduct funds)
|
|
1802
|
+
*/
|
|
1803
|
+
placeBet(userId: string, amount: number, gameId: string, roundId: string): Promise<ITransactionResult>;
|
|
1804
|
+
/**
|
|
1805
|
+
* Credit winnings
|
|
1806
|
+
*/
|
|
1807
|
+
creditWin(userId: string, amount: number, gameId: string, roundId: string, winType?: 'normal' | 'bonus' | 'jackpot'): Promise<ITransactionResult>;
|
|
1808
|
+
/**
|
|
1809
|
+
* Core transaction logic with optimistic locking
|
|
1810
|
+
*/
|
|
1811
|
+
private executeTransaction;
|
|
1812
|
+
/**
|
|
1813
|
+
* Transfer funds between users (e.g., P2P features)
|
|
1814
|
+
*/
|
|
1815
|
+
transfer(fromId: string, toId: string, amount: number): Promise<ITransactionResult>;
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
/**
|
|
1819
|
+
* Audit record storage interface.
|
|
1820
|
+
*/
|
|
1821
|
+
interface IAuditStorage {
|
|
1822
|
+
save(record: IAuditRecord): Promise<void>;
|
|
1823
|
+
findByPlayer(playerId: string, startTime: number, endTime: number): Promise<IAuditRecord[]>;
|
|
1824
|
+
findById(spinId: string): Promise<IAuditRecord | null>;
|
|
1825
|
+
getSummary(playerId: string, startTime: number, endTime: number): Promise<IPlayerActivitySummary>;
|
|
1826
|
+
}
|
|
1827
|
+
/**
|
|
1828
|
+
* In-memory audit storage (for development/testing).
|
|
1829
|
+
* In production, replace with database-backed implementation.
|
|
1830
|
+
*/
|
|
1831
|
+
declare class InMemoryAuditStorage implements IAuditStorage {
|
|
1832
|
+
private records;
|
|
1833
|
+
private playerIndex;
|
|
1834
|
+
save(record: IAuditRecord): Promise<void>;
|
|
1835
|
+
findByPlayer(playerId: string, startTime: number, endTime: number): Promise<IAuditRecord[]>;
|
|
1836
|
+
findById(spinId: string): Promise<IAuditRecord | null>;
|
|
1837
|
+
getSummary(playerId: string, startTime: number, endTime: number): Promise<IPlayerActivitySummary>;
|
|
1838
|
+
/**
|
|
1839
|
+
* Clear all records (for testing).
|
|
1840
|
+
*/
|
|
1841
|
+
clear(): void;
|
|
1842
|
+
/**
|
|
1843
|
+
* Get total record count.
|
|
1844
|
+
*/
|
|
1845
|
+
getCount(): number;
|
|
1846
|
+
}
|
|
1847
|
+
/**
|
|
1848
|
+
* Audit Manager for regulatory compliance and game integrity.
|
|
1849
|
+
* Records all spins, transactions, and significant events.
|
|
1850
|
+
*/
|
|
1851
|
+
declare class AuditManager {
|
|
1852
|
+
private storage;
|
|
1853
|
+
private gameId;
|
|
1854
|
+
private operatorId?;
|
|
1855
|
+
constructor(gameId: string, storage?: IAuditStorage, operatorId?: string);
|
|
1856
|
+
/**
|
|
1857
|
+
* Record a spin for audit purposes.
|
|
1858
|
+
*/
|
|
1859
|
+
recordSpin(params: {
|
|
1860
|
+
spinId: string;
|
|
1861
|
+
playerId: string;
|
|
1862
|
+
sessionId: string;
|
|
1863
|
+
stake: number;
|
|
1864
|
+
win: number;
|
|
1865
|
+
balanceBefore: number;
|
|
1866
|
+
balanceAfter: number;
|
|
1867
|
+
rngSeed: string;
|
|
1868
|
+
result: number[][];
|
|
1869
|
+
gameMode: 0 | 1;
|
|
1870
|
+
bonusTriggered: boolean;
|
|
1871
|
+
jackpotContributions: IJackpotContribution[];
|
|
1872
|
+
jackpotWins: IJackpotWin[];
|
|
1873
|
+
ipAddress?: string;
|
|
1874
|
+
deviceInfo?: string;
|
|
1875
|
+
location?: string;
|
|
1876
|
+
platform?: 'web' | 'mobile' | 'desktop';
|
|
1877
|
+
}): Promise<IAuditRecord>;
|
|
1878
|
+
/**
|
|
1879
|
+
* Get audit records for a player within a time range.
|
|
1880
|
+
*/
|
|
1881
|
+
getPlayerRecords(playerId: string, startTime: number, endTime: number): Promise<IAuditRecord[]>;
|
|
1882
|
+
/**
|
|
1883
|
+
* Get a specific spin record by ID.
|
|
1884
|
+
*/
|
|
1885
|
+
getSpinRecord(spinId: string): Promise<IAuditRecord | null>;
|
|
1886
|
+
/**
|
|
1887
|
+
* Get player activity summary for a period.
|
|
1888
|
+
*/
|
|
1889
|
+
getPlayerSummary(playerId: string, startTime: number, endTime: number): Promise<IPlayerActivitySummary>;
|
|
1890
|
+
/**
|
|
1891
|
+
* Export records for regulatory reporting.
|
|
1892
|
+
*/
|
|
1893
|
+
exportRecords(playerId: string, startTime: number, endTime: number, format?: 'json' | 'csv'): Promise<string>;
|
|
1894
|
+
/**
|
|
1895
|
+
* Verify game integrity by checking RNG seed chain.
|
|
1896
|
+
*/
|
|
1897
|
+
verifyRngChain(spinIds: string[]): Promise<{
|
|
1898
|
+
valid: boolean;
|
|
1899
|
+
errors: string[];
|
|
1900
|
+
}>;
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
/**
|
|
1904
|
+
* Debug Manager for testing and development.
|
|
1905
|
+
* Provides logging, forced outcomes, and state inspection.
|
|
1906
|
+
*/
|
|
1907
|
+
declare class DebugManager {
|
|
1908
|
+
private config;
|
|
1909
|
+
private spinCount;
|
|
1910
|
+
private lastRngSeed;
|
|
1911
|
+
private forcedOutcomesApplied;
|
|
1912
|
+
private logs;
|
|
1913
|
+
constructor(config?: Partial<IDebugConfig>);
|
|
1914
|
+
/**
|
|
1915
|
+
* Update debug configuration.
|
|
1916
|
+
*/
|
|
1917
|
+
configure(config: Partial<IDebugConfig>): void;
|
|
1918
|
+
/**
|
|
1919
|
+
* Check if debug mode is enabled.
|
|
1920
|
+
*/
|
|
1921
|
+
isEnabled(): boolean;
|
|
1922
|
+
/**
|
|
1923
|
+
* Get current debug state.
|
|
1924
|
+
*/
|
|
1925
|
+
getState(): IDebugState;
|
|
1926
|
+
/**
|
|
1927
|
+
* Reset debug state and logs.
|
|
1928
|
+
*/
|
|
1929
|
+
reset(): void;
|
|
1930
|
+
/**
|
|
1931
|
+
* Log a message at specified level.
|
|
1932
|
+
*/
|
|
1933
|
+
log(level: IDebugLogEntry['level'], category: string, message: string, data?: any): void;
|
|
1934
|
+
/**
|
|
1935
|
+
* Log a spin result.
|
|
1936
|
+
*/
|
|
1937
|
+
logSpin(spinId: string, result: ISpinResponseData, rngSeed: string): void;
|
|
1938
|
+
/**
|
|
1939
|
+
* Check and apply forced outcome if conditions match.
|
|
1940
|
+
*/
|
|
1941
|
+
checkForcedOutcome(params: {
|
|
1942
|
+
spinNumber: number;
|
|
1943
|
+
rngSeed: string;
|
|
1944
|
+
betAmount: number;
|
|
1945
|
+
playerId: string;
|
|
1946
|
+
}): ISpinResponseData | null;
|
|
1947
|
+
/**
|
|
1948
|
+
* Check if balance checks should be skipped.
|
|
1949
|
+
*/
|
|
1950
|
+
shouldSkipBalanceCheck(): boolean;
|
|
1951
|
+
/**
|
|
1952
|
+
* Get all logs (optionally filtered by level).
|
|
1953
|
+
*/
|
|
1954
|
+
getLogs(level?: IDebugLogEntry['level']): IDebugLogEntry[];
|
|
1955
|
+
/**
|
|
1956
|
+
* Export logs as JSON.
|
|
1957
|
+
*/
|
|
1958
|
+
exportLogs(): string;
|
|
1959
|
+
/**
|
|
1960
|
+
* Clear all logs.
|
|
1961
|
+
*/
|
|
1962
|
+
clearLogs(): void;
|
|
1963
|
+
/**
|
|
1964
|
+
* Determine if a log level should be output based on verboseLevel config.
|
|
1965
|
+
*/
|
|
1966
|
+
private shouldLogLevel;
|
|
1967
|
+
/**
|
|
1968
|
+
* Output log entry based on outputFormat config.
|
|
1969
|
+
*/
|
|
1970
|
+
private outputLog;
|
|
1971
|
+
/**
|
|
1972
|
+
* Get statistics about logged events.
|
|
1973
|
+
*/
|
|
1974
|
+
getStatistics(): {
|
|
1975
|
+
totalLogs: number;
|
|
1976
|
+
errorCount: number;
|
|
1977
|
+
warningCount: number;
|
|
1978
|
+
infoCount: number;
|
|
1979
|
+
debugCount: number;
|
|
1980
|
+
spinsTracked: number;
|
|
1981
|
+
forcedOutcomesApplied: number;
|
|
1982
|
+
};
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
/**
|
|
1986
|
+
* Session time tracking information.
|
|
1987
|
+
*/
|
|
1988
|
+
interface ISessionTimeInfo {
|
|
1989
|
+
sessionStartTime: number;
|
|
1990
|
+
elapsedMinutes: number;
|
|
1991
|
+
limitMinutes?: number;
|
|
1992
|
+
isLimitReached: boolean;
|
|
1993
|
+
warningThresholdReached: boolean;
|
|
1994
|
+
}
|
|
1995
|
+
/**
|
|
1996
|
+
* Loss tracking information.
|
|
1997
|
+
*/
|
|
1998
|
+
interface ILossTrackingInfo {
|
|
1999
|
+
sessionLoss: number;
|
|
2000
|
+
lossLimit?: number;
|
|
2001
|
+
isLimitReached: boolean;
|
|
2002
|
+
warningThresholdReached: boolean;
|
|
2003
|
+
}
|
|
2004
|
+
/**
|
|
2005
|
+
* Win tracking information.
|
|
2006
|
+
*/
|
|
2007
|
+
interface IWinTrackingInfo {
|
|
2008
|
+
sessionWin: number;
|
|
2009
|
+
winGoal?: number;
|
|
2010
|
+
isGoalReached: boolean;
|
|
2011
|
+
notificationSent: boolean;
|
|
2012
|
+
}
|
|
2013
|
+
/**
|
|
2014
|
+
* Reality check event.
|
|
2015
|
+
*/
|
|
2016
|
+
interface IRealityCheckEvent {
|
|
2017
|
+
timestamp: number;
|
|
2018
|
+
elapsedMinutes: number;
|
|
2019
|
+
totalSpins: number;
|
|
2020
|
+
totalStaked: number;
|
|
2021
|
+
totalWon: number;
|
|
2022
|
+
netResult: number;
|
|
2023
|
+
message: string;
|
|
2024
|
+
}
|
|
2025
|
+
/**
|
|
2026
|
+
* Self-exclusion status.
|
|
2027
|
+
*/
|
|
2028
|
+
interface ISelfExclusionStatus {
|
|
2029
|
+
isExcluded: boolean;
|
|
2030
|
+
exclusionUntil?: Date;
|
|
2031
|
+
remainingDays?: number;
|
|
2032
|
+
reason?: string;
|
|
2033
|
+
}
|
|
2034
|
+
/**
|
|
2035
|
+
* Responsible gaming alert.
|
|
2036
|
+
*/
|
|
2037
|
+
interface IRGAlert {
|
|
2038
|
+
type: 'session_time' | 'loss_limit' | 'win_goal' | 'reality_check' | 'self_exclusion' | 'bet_limit';
|
|
2039
|
+
severity: 'info' | 'warning' | 'critical';
|
|
2040
|
+
message: string;
|
|
2041
|
+
timestamp: number;
|
|
2042
|
+
actionRequired?: boolean;
|
|
2043
|
+
suggestedAction?: string;
|
|
2044
|
+
}
|
|
2045
|
+
/**
|
|
2046
|
+
* Player activity statistics for responsible gaming.
|
|
2047
|
+
*/
|
|
2048
|
+
interface IPlayerActivityStats {
|
|
2049
|
+
totalSessions: number;
|
|
2050
|
+
totalTimePlayed: number;
|
|
2051
|
+
totalStaked: number;
|
|
2052
|
+
totalWon: number;
|
|
2053
|
+
netResult: number;
|
|
2054
|
+
averageSessionDuration: number;
|
|
2055
|
+
longestSession: number;
|
|
2056
|
+
biggestLoss: number;
|
|
2057
|
+
biggestWin: number;
|
|
2058
|
+
lastSessionDate?: number;
|
|
2059
|
+
}
|
|
2060
|
+
/**
|
|
2061
|
+
* Responsible Gaming Manager - Comprehensive player protection system.
|
|
2062
|
+
*
|
|
2063
|
+
* Features:
|
|
2064
|
+
* - Session time limits with warnings
|
|
2065
|
+
* - Loss limits with automatic blocking
|
|
2066
|
+
* - Win goals with notifications
|
|
2067
|
+
* - Reality check reminders
|
|
2068
|
+
* - Self-exclusion enforcement
|
|
2069
|
+
* - Bet limit enforcement
|
|
2070
|
+
* - Activity monitoring and alerts
|
|
2071
|
+
* - Pattern analysis for problem gambling detection
|
|
2072
|
+
*/
|
|
2073
|
+
declare class ResponsibleGamingManager {
|
|
2074
|
+
private limits;
|
|
2075
|
+
private playerState;
|
|
2076
|
+
private alerts;
|
|
2077
|
+
private realityCheckCounter;
|
|
2078
|
+
private lastRealityCheckTime;
|
|
2079
|
+
constructor(limits: IResponsibleGamingLimits, playerState: IPlayerState);
|
|
2080
|
+
/**
|
|
2081
|
+
* Update player state (call after each spin).
|
|
2082
|
+
*/
|
|
2083
|
+
updatePlayerState(state: Partial<IPlayerState>): void;
|
|
2084
|
+
/**
|
|
2085
|
+
* Update responsible gaming limits (e.g., player changed their limits).
|
|
2086
|
+
*/
|
|
2087
|
+
updateLimits(newLimits: Partial<IResponsibleGamingLimits>): void;
|
|
2088
|
+
/**
|
|
2089
|
+
* Check if player can place a bet of the given amount.
|
|
2090
|
+
*/
|
|
2091
|
+
canPlaceBet(betAmount: number): Result<boolean, string>;
|
|
2092
|
+
/**
|
|
2093
|
+
* Check if player can continue playing (general eligibility).
|
|
2094
|
+
*/
|
|
2095
|
+
canContinuePlaying(): Result<boolean, string>;
|
|
2096
|
+
/**
|
|
2097
|
+
* Get session time tracking information.
|
|
2098
|
+
*/
|
|
2099
|
+
getSessionTimeInfo(): ISessionTimeInfo;
|
|
2100
|
+
/**
|
|
2101
|
+
* Get loss tracking information.
|
|
2102
|
+
*/
|
|
2103
|
+
getLossTrackingInfo(): ILossTrackingInfo;
|
|
2104
|
+
/**
|
|
2105
|
+
* Get win tracking information.
|
|
2106
|
+
*/
|
|
2107
|
+
getWinTrackingInfo(): IWinTrackingInfo;
|
|
2108
|
+
/**
|
|
2109
|
+
* Get self-exclusion status.
|
|
2110
|
+
*/
|
|
2111
|
+
getSelfExclusionStatus(): ISelfExclusionStatus;
|
|
2112
|
+
/**
|
|
2113
|
+
* Check if reality check is due.
|
|
2114
|
+
*/
|
|
2115
|
+
shouldShowRealityCheck(): boolean;
|
|
2116
|
+
/**
|
|
2117
|
+
* Generate reality check event.
|
|
2118
|
+
*/
|
|
2119
|
+
generateRealityCheck(): IRealityCheckEvent | null;
|
|
2120
|
+
/**
|
|
2121
|
+
* Check all limits and generate alerts.
|
|
2122
|
+
*/
|
|
2123
|
+
private checkAllLimits;
|
|
2124
|
+
/**
|
|
2125
|
+
* Add an alert to the list.
|
|
2126
|
+
*/
|
|
2127
|
+
private addAlert;
|
|
2128
|
+
/**
|
|
2129
|
+
* Get all active alerts.
|
|
2130
|
+
*/
|
|
2131
|
+
getAlerts(): IRGAlert[];
|
|
2132
|
+
/**
|
|
2133
|
+
* Clear alerts (call after player acknowledges them).
|
|
2134
|
+
*/
|
|
2135
|
+
clearAlerts(): void;
|
|
2136
|
+
/**
|
|
2137
|
+
* Get player activity statistics.
|
|
2138
|
+
*/
|
|
2139
|
+
getPlayerActivityStats(): IPlayerActivityStats;
|
|
2140
|
+
/**
|
|
2141
|
+
* Validate limits configuration.
|
|
2142
|
+
*/
|
|
2143
|
+
private validateLimits;
|
|
2144
|
+
/**
|
|
2145
|
+
* Reset session tracking (call when player starts new session).
|
|
2146
|
+
*/
|
|
2147
|
+
resetSession(): void;
|
|
2148
|
+
/**
|
|
2149
|
+
* Apply a win/loss result to session tracking.
|
|
2150
|
+
*/
|
|
2151
|
+
applyResult(stake: number, win: number): void;
|
|
2152
|
+
/**
|
|
2153
|
+
* Export responsible gaming report for player download.
|
|
2154
|
+
*/
|
|
2155
|
+
exportRGReport(): string;
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
declare const sampleConfig: IGameConfigData;
|
|
2159
|
+
|
|
2160
|
+
export { AuditManager, BonusManager, BuyBonusManager, CascadingReelsManager, ConfigBuilder, DebugManager, type DeepPartial, ExpandingWildsManager, GambleManager, GameSession, HistoryManager, type IAuditRecord, type IBonusResponse, type IBonusState, type IBuyBonusConfig, type IBuyBonusRequest, type ICascadeBonus, type ICascadeConfig, type ICascadeResult, type ICascadeStep, type ICurrencyConfig, type IDebugConfig, type IDebugLogEntry, type IDebugState, type IExpandingWildConfig, type IExpandingWildResult, type IForcedOutcome, type IFreeSpinBonus, type IFreeSpinsConfig, type IGambleConfig, type IGambleRequest, type IGambleResponse, type IGameConfigData, type IGameState, type IHistoryEntry, type IHistoryResponse, type IHoldAndSpinBonus, type IInitResponse, type IJackpotConfig, type IJackpotContribution, type IJackpotTier, type IJackpotWin, type IMoneySymbol, type IPickBonus, type IPlayerActivitySummary, type IPlayerState, type IRespinsBonus, type IRespinsConfig, type IRespinsFullScreenBonus, type IRespinsResult, type IRespinsStep, type IRespinsSymbolWeight, type IRespinsTriggerPosition, type IResponsibleGamingLimits, type IScatterConfig, type IScatterMultiplierZone, type IScatterResult, type IScatterTrigger, type IServerAck, type ISpinRequestData, type ISpinResponseData, type IStickyWildConfig, type IStickyWildResult, type ISymbol, type ISymbolConfig, type ITournamentConfig, type ITournamentPlayer, type ITournamentSpinRequest, type ITournamentState, type ITransaction, type ITransactionResult, type IWalletBalance, type IWalletConfig, type IWalletStorage, type IWaysConfig, type IWebSocketMessage, type IWheelBonus, type IWinDetails, type IWinEvaluation, type IWinLine, InMemoryAuditStorage, InMemoryWalletStorage, JackpotManager, type Nullable, type PaylinePattern, type PaytableData, Random, type ReelStrip, RespinsManager, type RespinsTriggerType, ResponsibleGamingManager, type Result, ScatterEnhancementsManager, type ScatterFeatureType, type ScatterTriggerType, SpinEvaluator, type SymbolBehavior, type SymbolMap, type TransactionType, WalletManager, WaysEvaluator, type WildExpandTrigger, sampleConfig };
|