@omnitronix/happy-panda-game-engine 0.5.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.
- package/README.md +732 -0
- package/dist/__tests__/bonus-sequence.test.d.ts +7 -0
- package/dist/__tests__/bonus-sequence.test.d.ts.map +1 -0
- package/dist/__tests__/bonus-sequence.test.js +381 -0
- package/dist/__tests__/bonus-sequence.test.js.map +1 -0
- package/dist/__tests__/cherry-frequency.test.d.ts +8 -0
- package/dist/__tests__/cherry-frequency.test.d.ts.map +1 -0
- package/dist/__tests__/cherry-frequency.test.js +128 -0
- package/dist/__tests__/cherry-frequency.test.js.map +1 -0
- package/dist/__tests__/comprehensive.test.d.ts +16 -0
- package/dist/__tests__/comprehensive.test.d.ts.map +1 -0
- package/dist/__tests__/comprehensive.test.js +491 -0
- package/dist/__tests__/comprehensive.test.js.map +1 -0
- package/dist/__tests__/counter-manager.test.d.ts +7 -0
- package/dist/__tests__/counter-manager.test.d.ts.map +1 -0
- package/dist/__tests__/counter-manager.test.js +317 -0
- package/dist/__tests__/counter-manager.test.js.map +1 -0
- package/dist/__tests__/coverage-boost.test.d.ts +13 -0
- package/dist/__tests__/coverage-boost.test.d.ts.map +1 -0
- package/dist/__tests__/coverage-boost.test.js +606 -0
- package/dist/__tests__/coverage-boost.test.js.map +1 -0
- package/dist/__tests__/cpp-parity.test.d.ts +39 -0
- package/dist/__tests__/cpp-parity.test.d.ts.map +1 -0
- package/dist/__tests__/cpp-parity.test.js +392 -0
- package/dist/__tests__/cpp-parity.test.js.map +1 -0
- package/dist/__tests__/debug-trigger-bonus.test.d.ts +8 -0
- package/dist/__tests__/debug-trigger-bonus.test.d.ts.map +1 -0
- package/dist/__tests__/debug-trigger-bonus.test.js +359 -0
- package/dist/__tests__/debug-trigger-bonus.test.js.map +1 -0
- package/dist/__tests__/fixtures/cpp-parity-vectors.json +457 -0
- package/dist/__tests__/gdd-validation-1000.test.d.ts +14 -0
- package/dist/__tests__/gdd-validation-1000.test.d.ts.map +1 -0
- package/dist/__tests__/gdd-validation-1000.test.js +418 -0
- package/dist/__tests__/gdd-validation-1000.test.js.map +1 -0
- package/dist/__tests__/happy-panda-engine.test.d.ts +7 -0
- package/dist/__tests__/happy-panda-engine.test.d.ts.map +1 -0
- package/dist/__tests__/happy-panda-engine.test.js +414 -0
- package/dist/__tests__/happy-panda-engine.test.js.map +1 -0
- package/dist/__tests__/jackpot-manager.test.d.ts +8 -0
- package/dist/__tests__/jackpot-manager.test.d.ts.map +1 -0
- package/dist/__tests__/jackpot-manager.test.js +313 -0
- package/dist/__tests__/jackpot-manager.test.js.map +1 -0
- package/dist/__tests__/jackpot-trigger-trace.test.d.ts +6 -0
- package/dist/__tests__/jackpot-trigger-trace.test.d.ts.map +1 -0
- package/dist/__tests__/jackpot-trigger-trace.test.js +146 -0
- package/dist/__tests__/jackpot-trigger-trace.test.js.map +1 -0
- package/dist/__tests__/rng-gli19-compliance.test.d.ts +21 -0
- package/dist/__tests__/rng-gli19-compliance.test.d.ts.map +1 -0
- package/dist/__tests__/rng-gli19-compliance.test.js +480 -0
- package/dist/__tests__/rng-gli19-compliance.test.js.map +1 -0
- package/dist/__tests__/rng-seed-security.test.d.ts +19 -0
- package/dist/__tests__/rng-seed-security.test.d.ts.map +1 -0
- package/dist/__tests__/rng-seed-security.test.js +518 -0
- package/dist/__tests__/rng-seed-security.test.js.map +1 -0
- package/dist/__tests__/rng-seed-type.test.d.ts +16 -0
- package/dist/__tests__/rng-seed-type.test.d.ts.map +1 -0
- package/dist/__tests__/rng-seed-type.test.js +285 -0
- package/dist/__tests__/rng-seed-type.test.js.map +1 -0
- package/dist/__tests__/rng-stress-boundary.test.d.ts +15 -0
- package/dist/__tests__/rng-stress-boundary.test.d.ts.map +1 -0
- package/dist/__tests__/rng-stress-boundary.test.js +590 -0
- package/dist/__tests__/rng-stress-boundary.test.js.map +1 -0
- package/dist/__tests__/rtp-1million.test.d.ts +8 -0
- package/dist/__tests__/rtp-1million.test.d.ts.map +1 -0
- package/dist/__tests__/rtp-1million.test.js +156 -0
- package/dist/__tests__/rtp-1million.test.js.map +1 -0
- package/dist/__tests__/rtp-analysis.test.d.ts +8 -0
- package/dist/__tests__/rtp-analysis.test.d.ts.map +1 -0
- package/dist/__tests__/rtp-analysis.test.js +138 -0
- package/dist/__tests__/rtp-analysis.test.js.map +1 -0
- package/dist/__tests__/rtp-diagnostic.test.d.ts +6 -0
- package/dist/__tests__/rtp-diagnostic.test.d.ts.map +1 -0
- package/dist/__tests__/rtp-diagnostic.test.js +141 -0
- package/dist/__tests__/rtp-diagnostic.test.js.map +1 -0
- package/dist/__tests__/rtp-simulation.test.d.ts +8 -0
- package/dist/__tests__/rtp-simulation.test.d.ts.map +1 -0
- package/dist/__tests__/rtp-simulation.test.js +411 -0
- package/dist/__tests__/rtp-simulation.test.js.map +1 -0
- package/dist/__tests__/special-wins.test.d.ts +7 -0
- package/dist/__tests__/special-wins.test.d.ts.map +1 -0
- package/dist/__tests__/special-wins.test.js +179 -0
- package/dist/__tests__/special-wins.test.js.map +1 -0
- package/dist/__tests__/spin-generator.test.d.ts +7 -0
- package/dist/__tests__/spin-generator.test.d.ts.map +1 -0
- package/dist/__tests__/spin-generator.test.js +297 -0
- package/dist/__tests__/spin-generator.test.js.map +1 -0
- package/dist/__tests__/spin-handler.test.d.ts +7 -0
- package/dist/__tests__/spin-handler.test.d.ts.map +1 -0
- package/dist/__tests__/spin-handler.test.js +210 -0
- package/dist/__tests__/spin-handler.test.js.map +1 -0
- package/dist/__tests__/symbol-distribution.test.d.ts +6 -0
- package/dist/__tests__/symbol-distribution.test.d.ts.map +1 -0
- package/dist/__tests__/symbol-distribution.test.js +119 -0
- package/dist/__tests__/symbol-distribution.test.js.map +1 -0
- package/dist/__tests__/test-protocol-10000-spin.test.d.ts +14 -0
- package/dist/__tests__/test-protocol-10000-spin.test.d.ts.map +1 -0
- package/dist/__tests__/test-protocol-10000-spin.test.js +359 -0
- package/dist/__tests__/test-protocol-10000-spin.test.js.map +1 -0
- package/dist/__tests__/weighted-random.test.d.ts +7 -0
- package/dist/__tests__/weighted-random.test.d.ts.map +1 -0
- package/dist/__tests__/weighted-random.test.js +165 -0
- package/dist/__tests__/weighted-random.test.js.map +1 -0
- package/dist/__tests__/win-evaluator.test.d.ts +7 -0
- package/dist/__tests__/win-evaluator.test.d.ts.map +1 -0
- package/dist/__tests__/win-evaluator.test.js +264 -0
- package/dist/__tests__/win-evaluator.test.js.map +1 -0
- package/dist/config/happy-panda.config.d.ts +217 -0
- package/dist/config/happy-panda.config.d.ts.map +1 -0
- package/dist/config/happy-panda.config.js +721 -0
- package/dist/config/happy-panda.config.js.map +1 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +21 -0
- package/dist/config/index.js.map +1 -0
- package/dist/debug/debug-command-definitions.d.ts +38 -0
- package/dist/debug/debug-command-definitions.d.ts.map +1 -0
- package/dist/debug/debug-command-definitions.js +80 -0
- package/dist/debug/debug-command-definitions.js.map +1 -0
- package/dist/domain/debug-trigger-bonus-command.d.ts +17 -0
- package/dist/domain/debug-trigger-bonus-command.d.ts.map +1 -0
- package/dist/domain/debug-trigger-bonus-command.js +3 -0
- package/dist/domain/debug-trigger-bonus-command.js.map +1 -0
- package/dist/domain/index.d.ts +5 -0
- package/dist/domain/index.d.ts.map +1 -0
- package/dist/domain/index.js +21 -0
- package/dist/domain/index.js.map +1 -0
- package/dist/domain/types.d.ts +228 -0
- package/dist/domain/types.d.ts.map +1 -0
- package/dist/domain/types.js +30 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/engine/happy-panda-engine.d.ts +64 -0
- package/dist/engine/happy-panda-engine.d.ts.map +1 -0
- package/dist/engine/happy-panda-engine.js +324 -0
- package/dist/engine/happy-panda-engine.js.map +1 -0
- package/dist/engine/index.d.ts +5 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +21 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/game-engine.interface.d.ts +19 -0
- package/dist/game-engine.interface.d.ts.map +1 -0
- package/dist/game-engine.interface.js +9 -0
- package/dist/game-engine.interface.js.map +1 -0
- package/dist/happy-panda-v1.game-engine.d.ts +60 -0
- package/dist/happy-panda-v1.game-engine.d.ts.map +1 -0
- package/dist/happy-panda-v1.game-engine.js +524 -0
- package/dist/happy-panda-v1.game-engine.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/logic/handlers/index.d.ts +5 -0
- package/dist/logic/handlers/index.d.ts.map +1 -0
- package/dist/logic/handlers/index.js +21 -0
- package/dist/logic/handlers/index.js.map +1 -0
- package/dist/logic/handlers/spin-handler.d.ts +58 -0
- package/dist/logic/handlers/spin-handler.d.ts.map +1 -0
- package/dist/logic/handlers/spin-handler.js +265 -0
- package/dist/logic/handlers/spin-handler.js.map +1 -0
- package/dist/logic/index.d.ts +6 -0
- package/dist/logic/index.d.ts.map +1 -0
- package/dist/logic/index.js +22 -0
- package/dist/logic/index.js.map +1 -0
- package/dist/logic/services/counter-manager.d.ts +60 -0
- package/dist/logic/services/counter-manager.d.ts.map +1 -0
- package/dist/logic/services/counter-manager.js +268 -0
- package/dist/logic/services/counter-manager.js.map +1 -0
- package/dist/logic/services/index.d.ts +7 -0
- package/dist/logic/services/index.d.ts.map +1 -0
- package/dist/logic/services/index.js +23 -0
- package/dist/logic/services/index.js.map +1 -0
- package/dist/logic/services/jackpot-manager.d.ts +59 -0
- package/dist/logic/services/jackpot-manager.d.ts.map +1 -0
- package/dist/logic/services/jackpot-manager.js +142 -0
- package/dist/logic/services/jackpot-manager.js.map +1 -0
- package/dist/logic/services/win-evaluator.d.ts +51 -0
- package/dist/logic/services/win-evaluator.d.ts.map +1 -0
- package/dist/logic/services/win-evaluator.js +463 -0
- package/dist/logic/services/win-evaluator.js.map +1 -0
- package/dist/rng/dummy-rng-client.d.ts +39 -0
- package/dist/rng/dummy-rng-client.d.ts.map +1 -0
- package/dist/rng/dummy-rng-client.js +77 -0
- package/dist/rng/dummy-rng-client.js.map +1 -0
- package/dist/rng/index.d.ts +10 -0
- package/dist/rng/index.d.ts.map +1 -0
- package/dist/rng/index.js +27 -0
- package/dist/rng/index.js.map +1 -0
- package/dist/rng/rng-client.factory.d.ts +33 -0
- package/dist/rng/rng-client.factory.d.ts.map +1 -0
- package/dist/rng/rng-client.factory.js +57 -0
- package/dist/rng/rng-client.factory.js.map +1 -0
- package/dist/rng/rng-client.interface.d.ts +51 -0
- package/dist/rng/rng-client.interface.d.ts.map +1 -0
- package/dist/rng/rng-client.interface.js +9 -0
- package/dist/rng/rng-client.interface.js.map +1 -0
- package/dist/rng/rng-service.d.ts +93 -0
- package/dist/rng/rng-service.d.ts.map +1 -0
- package/dist/rng/rng-service.js +124 -0
- package/dist/rng/rng-service.js.map +1 -0
- package/dist/rng/spin-generator.d.ts +32 -0
- package/dist/rng/spin-generator.d.ts.map +1 -0
- package/dist/rng/spin-generator.js +338 -0
- package/dist/rng/spin-generator.js.map +1 -0
- package/dist/rng/weighted-random.d.ts +30 -0
- package/dist/rng/weighted-random.d.ts.map +1 -0
- package/dist/rng/weighted-random.js +58 -0
- package/dist/rng/weighted-random.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
/**
|
|
18
|
+
* Logic handlers exports
|
|
19
|
+
*/
|
|
20
|
+
__exportStar(require("./spin-handler"), exports);
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/logic/handlers/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;GAEG;AACH,iDAA+B"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spin Handler
|
|
3
|
+
*
|
|
4
|
+
* Coordinates the entire spin flow:
|
|
5
|
+
* 1. Determine spin type
|
|
6
|
+
* 2. Generate grid
|
|
7
|
+
* 3. Evaluate wins
|
|
8
|
+
* 4. Update counters
|
|
9
|
+
* 5. Update jackpots
|
|
10
|
+
* 6. Determine next spin type
|
|
11
|
+
* 7. Build response
|
|
12
|
+
*/
|
|
13
|
+
import { SpinType } from '../../config/happy-panda.config';
|
|
14
|
+
import { Grid, GameDirection, GameState, SpinWinResult, RngProvider } from '../../domain/types';
|
|
15
|
+
export interface SpinResult {
|
|
16
|
+
/** Resulting screen (3x3 grid) */
|
|
17
|
+
screen: Grid;
|
|
18
|
+
/** Win evaluation results */
|
|
19
|
+
wins: SpinWinResult;
|
|
20
|
+
/** Updated game state */
|
|
21
|
+
state: GameState;
|
|
22
|
+
/** The spin type that was actually executed this spin */
|
|
23
|
+
executedSpinType: SpinType;
|
|
24
|
+
/** Progressive jackpot won (if any) */
|
|
25
|
+
jackpotWon: number;
|
|
26
|
+
/** Pool jackpot won (if any) */
|
|
27
|
+
poolJackpotWon: number;
|
|
28
|
+
/** Bonus type triggered this spin */
|
|
29
|
+
bonusTriggered: SpinType | null;
|
|
30
|
+
/** Is this the final spin of bonus sequence */
|
|
31
|
+
isBonusComplete: boolean;
|
|
32
|
+
/** Total player winning (required by RGS for balance crediting) */
|
|
33
|
+
playerWinning: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Execute a single spin.
|
|
37
|
+
*/
|
|
38
|
+
export declare function executeSpin(state: GameState, rng: RngProvider): Promise<SpinResult>;
|
|
39
|
+
/** Minimum bet stake */
|
|
40
|
+
export declare const MIN_BET_STAKE = 1;
|
|
41
|
+
/** Maximum bet stake (reasonable upper bound) */
|
|
42
|
+
export declare const MAX_BET_STAKE = 100;
|
|
43
|
+
/**
|
|
44
|
+
* Validate bet parameters.
|
|
45
|
+
* @throws Error if parameters are invalid
|
|
46
|
+
*/
|
|
47
|
+
export declare function validateBetParams(gameDirection: GameDirection, betStake: number): void;
|
|
48
|
+
/**
|
|
49
|
+
* Create initial game state.
|
|
50
|
+
* @throws Error if parameters are invalid
|
|
51
|
+
*/
|
|
52
|
+
export declare function createInitialState(gameDirection: GameDirection, betStake: number): GameState;
|
|
53
|
+
/**
|
|
54
|
+
* Update state for new bet.
|
|
55
|
+
* @throws Error if parameters are invalid
|
|
56
|
+
*/
|
|
57
|
+
export declare function updateBet(state: GameState, gameDirection: GameDirection, betStake: number): GameState;
|
|
58
|
+
//# sourceMappingURL=spin-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spin-handler.d.ts","sourceRoot":"","sources":["../../../src/logic/handlers/spin-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAEL,QAAQ,EAET,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,IAAI,EACJ,aAAa,EACb,SAAS,EACT,aAAa,EACb,WAAW,EACZ,MAAM,oBAAoB,CAAC;AAoB5B,MAAM,WAAW,UAAU;IACzB,kCAAkC;IAClC,MAAM,EAAE,IAAI,CAAC;IACb,6BAA6B;IAC7B,IAAI,EAAE,aAAa,CAAC;IACpB,yBAAyB;IACzB,KAAK,EAAE,SAAS,CAAC;IACjB,yDAAyD;IACzD,gBAAgB,EAAE,QAAQ,CAAC;IAC3B,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,cAAc,EAAE,QAAQ,GAAG,IAAI,CAAC;IAChC,+CAA+C;IAC/C,eAAe,EAAE,OAAO,CAAC;IACzB,mEAAmE;IACnE,aAAa,EAAE,MAAM,CAAC;CACvB;AAqBD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,UAAU,CAAC,CAsLrB;AAMD,wBAAwB;AACxB,eAAO,MAAM,aAAa,IAAI,CAAC;AAC/B,iDAAiD;AACjD,eAAO,MAAM,aAAa,MAAM,CAAC;AAEjC;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAUtF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,aAAa,EAC5B,QAAQ,EAAE,MAAM,GACf,SAAS,CAsCX;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,SAAS,EAChB,aAAa,EAAE,aAAa,EAC5B,QAAQ,EAAE,MAAM,GACf,SAAS,CAiBX"}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Spin Handler
|
|
4
|
+
*
|
|
5
|
+
* Coordinates the entire spin flow:
|
|
6
|
+
* 1. Determine spin type
|
|
7
|
+
* 2. Generate grid
|
|
8
|
+
* 3. Evaluate wins
|
|
9
|
+
* 4. Update counters
|
|
10
|
+
* 5. Update jackpots
|
|
11
|
+
* 6. Determine next spin type
|
|
12
|
+
* 7. Build response
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.MAX_BET_STAKE = exports.MIN_BET_STAKE = void 0;
|
|
16
|
+
exports.executeSpin = executeSpin;
|
|
17
|
+
exports.validateBetParams = validateBetParams;
|
|
18
|
+
exports.createInitialState = createInitialState;
|
|
19
|
+
exports.updateBet = updateBet;
|
|
20
|
+
const happy_panda_config_1 = require("../../config/happy-panda.config");
|
|
21
|
+
const types_1 = require("../../domain/types");
|
|
22
|
+
const spin_generator_1 = require("../../rng/spin-generator");
|
|
23
|
+
const win_evaluator_1 = require("../services/win-evaluator");
|
|
24
|
+
const counter_manager_1 = require("../services/counter-manager");
|
|
25
|
+
const jackpot_manager_1 = require("../services/jackpot-manager");
|
|
26
|
+
// =============================================================================
|
|
27
|
+
// SPIN TYPE TO BONUS TYPE MAPPING
|
|
28
|
+
// =============================================================================
|
|
29
|
+
function bonusTypeToSpinType(bonusType) {
|
|
30
|
+
switch (bonusType) {
|
|
31
|
+
case 'bambooTriplets': return happy_panda_config_1.SpinType.BONUS_BAMBOO_TRIPLETS;
|
|
32
|
+
case 'bambooTwins': return happy_panda_config_1.SpinType.BONUS_BAMBOO_TWINS;
|
|
33
|
+
case 'camera': return happy_panda_config_1.SpinType.BONUS_CAMERA;
|
|
34
|
+
case 'fireworks': return happy_panda_config_1.SpinType.BONUS_FIREWORKS;
|
|
35
|
+
case 'centerBamboo': return happy_panda_config_1.SpinType.RESPIN_CENTER_BAMBOO;
|
|
36
|
+
default: return happy_panda_config_1.SpinType.BASE_GAME_SPIN;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// =============================================================================
|
|
40
|
+
// MAIN SPIN EXECUTION
|
|
41
|
+
// =============================================================================
|
|
42
|
+
/**
|
|
43
|
+
* Execute a single spin.
|
|
44
|
+
*/
|
|
45
|
+
async function executeSpin(state, rng) {
|
|
46
|
+
const { gameDirection, betStake, betGame, currentSpinType, spinsRemaining, counters, pendingBonuses, jackpots, centerBambooSymbol, } = state;
|
|
47
|
+
// Step 1: Generate grid based on spin type
|
|
48
|
+
// For RESPIN_CENTER_BAMBOO, pass the previous grid (state.screen) so edge positions
|
|
49
|
+
// can be preserved from the triggering paid_spin, matching C++ ScreenRespinCherry() behavior
|
|
50
|
+
const isRespin = currentSpinType === happy_panda_config_1.SpinType.RESPIN_CENTER_BAMBOO;
|
|
51
|
+
const grid = await (0, spin_generator_1.generateGrid)(currentSpinType, gameDirection, rng, isRespin ? centerBambooSymbol ?? undefined : undefined, isRespin ? state.screen : undefined);
|
|
52
|
+
// Step 2: Evaluate wins
|
|
53
|
+
const wins = (0, win_evaluator_1.evaluateSpin)(grid, gameDirection, betStake, betGame, currentSpinType);
|
|
54
|
+
// Step 3: Handle special jackpot bonus logic
|
|
55
|
+
let jackpotWon = 0;
|
|
56
|
+
let poolJackpotWon = 0;
|
|
57
|
+
let updatedJackpots = { ...jackpots };
|
|
58
|
+
if (currentSpinType === happy_panda_config_1.SpinType.BONUS_BAMBOO_TRIPLETS) {
|
|
59
|
+
// Every bamboo triplets bonus spin gets the ADD_WIN bonus (C++ Main Logic line 59)
|
|
60
|
+
// "please note scenario: each screen gets such winning, independent on pieces panda wins"
|
|
61
|
+
jackpotWon = happy_panda_config_1.BONUS_BAMBOO_TRIPLETS.ADD_WIN * betGame;
|
|
62
|
+
// Full panda piece = ALSO triggers progressive jackpot payout
|
|
63
|
+
if ((0, spin_generator_1.isCompletePandaPiece)(grid)) {
|
|
64
|
+
const { payout, newValue } = (0, jackpot_manager_1.payProgressiveJackpot)(jackpots.bonusJackpotValue, betGame);
|
|
65
|
+
jackpotWon += payout;
|
|
66
|
+
updatedJackpots.bonusJackpotValue = newValue;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Step 4: Update counters (only on paid spin and respin)
|
|
70
|
+
let updatedCounters = { ...counters };
|
|
71
|
+
let updatedPending = { ...pendingBonuses };
|
|
72
|
+
let bonusTriggered = null;
|
|
73
|
+
if (currentSpinType === happy_panda_config_1.SpinType.BASE_GAME_SPIN || currentSpinType === happy_panda_config_1.SpinType.RESPIN_CENTER_BAMBOO) {
|
|
74
|
+
const counterResult = await (0, counter_manager_1.updateCounters)(counters, pendingBonuses, wins.lineWins, grid, gameDirection, currentSpinType, wins.totalPayout, rng);
|
|
75
|
+
updatedCounters = counterResult.counters;
|
|
76
|
+
updatedPending = counterResult.pendingBonuses;
|
|
77
|
+
// Determine triggered bonus (for animation/display)
|
|
78
|
+
if (counterResult.triggeredBambooTriplets) {
|
|
79
|
+
bonusTriggered = happy_panda_config_1.SpinType.BONUS_BAMBOO_TRIPLETS;
|
|
80
|
+
}
|
|
81
|
+
else if (counterResult.triggeredBambooTwins) {
|
|
82
|
+
bonusTriggered = happy_panda_config_1.SpinType.BONUS_BAMBOO_TWINS;
|
|
83
|
+
}
|
|
84
|
+
else if (counterResult.triggeredCamera) {
|
|
85
|
+
bonusTriggered = happy_panda_config_1.SpinType.BONUS_CAMERA;
|
|
86
|
+
// Camera bonus also pays pool jackpot
|
|
87
|
+
const poolResult = (0, jackpot_manager_1.payPoolJackpot)(jackpots.poolJackpotValue, betGame);
|
|
88
|
+
poolJackpotWon = poolResult.payout;
|
|
89
|
+
updatedJackpots.poolJackpotValue = poolResult.newValue;
|
|
90
|
+
}
|
|
91
|
+
else if (counterResult.triggeredFireworks) {
|
|
92
|
+
bonusTriggered = happy_panda_config_1.SpinType.BONUS_FIREWORKS;
|
|
93
|
+
}
|
|
94
|
+
else if (counterResult.triggeredRespin > 0) {
|
|
95
|
+
bonusTriggered = happy_panda_config_1.SpinType.RESPIN_CENTER_BAMBOO;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Step 5: Update jackpots (progressive and pool on paid spins)
|
|
99
|
+
if (currentSpinType === happy_panda_config_1.SpinType.BASE_GAME_SPIN) {
|
|
100
|
+
const jackpotUpdate = await (0, jackpot_manager_1.updateJackpots)(updatedJackpots, grid, gameDirection, betGame, betStake, currentSpinType, wins.totalPayout, rng);
|
|
101
|
+
updatedJackpots = jackpotUpdate.jackpots;
|
|
102
|
+
}
|
|
103
|
+
// Step 6: Determine next spin type and remaining spins
|
|
104
|
+
let nextSpinType = happy_panda_config_1.SpinType.BASE_GAME_SPIN;
|
|
105
|
+
let nextSpinsRemaining = 0;
|
|
106
|
+
let newAccumulatedBonusWins = state.accumulatedBonusWins;
|
|
107
|
+
let newCenterBambooSymbol = state.centerBambooSymbol;
|
|
108
|
+
let isBonusComplete = false;
|
|
109
|
+
// Handle ongoing bonus spins
|
|
110
|
+
if (currentSpinType !== happy_panda_config_1.SpinType.BASE_GAME_SPIN && spinsRemaining > 1) {
|
|
111
|
+
// Continue current bonus
|
|
112
|
+
nextSpinType = currentSpinType;
|
|
113
|
+
nextSpinsRemaining = spinsRemaining - 1;
|
|
114
|
+
newAccumulatedBonusWins += wins.totalPayout + jackpotWon + poolJackpotWon;
|
|
115
|
+
}
|
|
116
|
+
else if (currentSpinType !== happy_panda_config_1.SpinType.BASE_GAME_SPIN && spinsRemaining === 1) {
|
|
117
|
+
// Bonus sequence ending, check for more pending bonuses
|
|
118
|
+
newAccumulatedBonusWins += wins.totalPayout + jackpotWon + poolJackpotWon;
|
|
119
|
+
const nextBonusType = (0, counter_manager_1.getNextBonusType)(updatedPending);
|
|
120
|
+
if (nextBonusType) {
|
|
121
|
+
// Start next bonus
|
|
122
|
+
const { pending: newPending, spins } = (0, counter_manager_1.consumeBonus)(updatedPending, nextBonusType);
|
|
123
|
+
updatedPending = newPending;
|
|
124
|
+
nextSpinType = bonusTypeToSpinType(nextBonusType);
|
|
125
|
+
nextSpinsRemaining = spins;
|
|
126
|
+
// Set center bamboo symbol if starting respin
|
|
127
|
+
if (nextBonusType === 'centerBamboo') {
|
|
128
|
+
newCenterBambooSymbol = grid[1][1];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// All bonuses complete, return to paid spin
|
|
133
|
+
nextSpinType = happy_panda_config_1.SpinType.BASE_GAME_SPIN;
|
|
134
|
+
nextSpinsRemaining = 0;
|
|
135
|
+
isBonusComplete = true;
|
|
136
|
+
newAccumulatedBonusWins = 0; // Reset for next bonus sequence
|
|
137
|
+
newCenterBambooSymbol = null;
|
|
138
|
+
// Reset bambooTriplets counter to ready state (#16)
|
|
139
|
+
updatedCounters.bambooTriplets = happy_panda_config_1.BONUS_BAMBOO_TRIPLETS.COUNTER_INIT;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else if (currentSpinType === happy_panda_config_1.SpinType.BASE_GAME_SPIN) {
|
|
143
|
+
// Check if any bonuses were triggered
|
|
144
|
+
const nextBonusType = (0, counter_manager_1.getNextBonusType)(updatedPending);
|
|
145
|
+
if (nextBonusType) {
|
|
146
|
+
const { pending: newPending, spins } = (0, counter_manager_1.consumeBonus)(updatedPending, nextBonusType);
|
|
147
|
+
updatedPending = newPending;
|
|
148
|
+
nextSpinType = bonusTypeToSpinType(nextBonusType);
|
|
149
|
+
nextSpinsRemaining = spins;
|
|
150
|
+
// Set center bamboo symbol if starting respin
|
|
151
|
+
if (nextBonusType === 'centerBamboo') {
|
|
152
|
+
newCenterBambooSymbol = grid[1][1];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Build updated state
|
|
157
|
+
const updatedState = {
|
|
158
|
+
...state,
|
|
159
|
+
currentSpinType: nextSpinType,
|
|
160
|
+
nextSpinType,
|
|
161
|
+
spinsRemaining: nextSpinsRemaining,
|
|
162
|
+
counters: updatedCounters,
|
|
163
|
+
pendingBonuses: updatedPending,
|
|
164
|
+
jackpots: updatedJackpots,
|
|
165
|
+
screen: grid,
|
|
166
|
+
accumulatedBonusWins: newAccumulatedBonusWins,
|
|
167
|
+
centerBambooSymbol: newCenterBambooSymbol,
|
|
168
|
+
};
|
|
169
|
+
// Calculate total player winning for RGS compatibility
|
|
170
|
+
const playerWinning = wins.totalPayout + jackpotWon + poolJackpotWon;
|
|
171
|
+
return {
|
|
172
|
+
screen: grid,
|
|
173
|
+
wins,
|
|
174
|
+
state: updatedState,
|
|
175
|
+
executedSpinType: currentSpinType,
|
|
176
|
+
jackpotWon,
|
|
177
|
+
poolJackpotWon,
|
|
178
|
+
bonusTriggered,
|
|
179
|
+
isBonusComplete,
|
|
180
|
+
playerWinning, // Required by RGS for win crediting
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
// =============================================================================
|
|
184
|
+
// STATE INITIALIZATION
|
|
185
|
+
// =============================================================================
|
|
186
|
+
/** Minimum bet stake */
|
|
187
|
+
exports.MIN_BET_STAKE = 1;
|
|
188
|
+
/** Maximum bet stake (reasonable upper bound) */
|
|
189
|
+
exports.MAX_BET_STAKE = 100;
|
|
190
|
+
/**
|
|
191
|
+
* Validate bet parameters.
|
|
192
|
+
* @throws Error if parameters are invalid
|
|
193
|
+
*/
|
|
194
|
+
function validateBetParams(gameDirection, betStake) {
|
|
195
|
+
if (gameDirection !== types_1.GameDirection.SINGLE && gameDirection !== types_1.GameDirection.BOTH) {
|
|
196
|
+
throw new Error(`Invalid game direction: ${gameDirection}. Must be 0 (8 lines) or 1 (16 lines)`);
|
|
197
|
+
}
|
|
198
|
+
if (!Number.isInteger(betStake)) {
|
|
199
|
+
throw new Error(`Bet stake must be an integer, got: ${betStake}`);
|
|
200
|
+
}
|
|
201
|
+
if (betStake < exports.MIN_BET_STAKE || betStake > exports.MAX_BET_STAKE) {
|
|
202
|
+
throw new Error(`Bet stake must be between ${exports.MIN_BET_STAKE} and ${exports.MAX_BET_STAKE}, got: ${betStake}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Create initial game state.
|
|
207
|
+
* @throws Error if parameters are invalid
|
|
208
|
+
*/
|
|
209
|
+
function createInitialState(gameDirection, betStake) {
|
|
210
|
+
validateBetParams(gameDirection, betStake);
|
|
211
|
+
const baseBet = gameDirection === types_1.GameDirection.SINGLE ? 8 : 16;
|
|
212
|
+
const betGame = baseBet * betStake;
|
|
213
|
+
return {
|
|
214
|
+
gameDirection,
|
|
215
|
+
betStake,
|
|
216
|
+
betGame,
|
|
217
|
+
currentSpinType: happy_panda_config_1.SpinType.BASE_GAME_SPIN,
|
|
218
|
+
nextSpinType: happy_panda_config_1.SpinType.BASE_GAME_SPIN,
|
|
219
|
+
spinsRemaining: 0,
|
|
220
|
+
counters: {
|
|
221
|
+
bambooTriplets: 1,
|
|
222
|
+
bambooTwins: 9, // Will be randomized on first trigger
|
|
223
|
+
camera: 5, // Will be randomized on first trigger
|
|
224
|
+
fireworks: 1,
|
|
225
|
+
},
|
|
226
|
+
pendingBonuses: {
|
|
227
|
+
bambooTriplets: 0,
|
|
228
|
+
bambooTwins: 0,
|
|
229
|
+
camera: 0,
|
|
230
|
+
fireworks: 0,
|
|
231
|
+
centerBamboo: 0,
|
|
232
|
+
},
|
|
233
|
+
jackpots: {
|
|
234
|
+
bonusJackpotValue: 100 * betGame,
|
|
235
|
+
poolJackpotValue: 0,
|
|
236
|
+
},
|
|
237
|
+
screen: [
|
|
238
|
+
[happy_panda_config_1.Symbol.NONE, happy_panda_config_1.Symbol.NONE, happy_panda_config_1.Symbol.NONE],
|
|
239
|
+
[happy_panda_config_1.Symbol.NONE, happy_panda_config_1.Symbol.NONE, happy_panda_config_1.Symbol.NONE],
|
|
240
|
+
[happy_panda_config_1.Symbol.NONE, happy_panda_config_1.Symbol.NONE, happy_panda_config_1.Symbol.NONE],
|
|
241
|
+
],
|
|
242
|
+
accumulatedBonusWins: 0,
|
|
243
|
+
centerBambooSymbol: null,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Update state for new bet.
|
|
248
|
+
* @throws Error if parameters are invalid
|
|
249
|
+
*/
|
|
250
|
+
function updateBet(state, gameDirection, betStake) {
|
|
251
|
+
validateBetParams(gameDirection, betStake);
|
|
252
|
+
// Can only change bet during paid spin with no pending bonuses
|
|
253
|
+
if (state.currentSpinType !== happy_panda_config_1.SpinType.BASE_GAME_SPIN || (0, counter_manager_1.hasPendingBonus)(state.pendingBonuses)) {
|
|
254
|
+
throw new Error('Cannot change bet during bonus or with pending bonuses');
|
|
255
|
+
}
|
|
256
|
+
const baseBet = gameDirection === types_1.GameDirection.SINGLE ? 8 : 16;
|
|
257
|
+
const betGame = baseBet * betStake;
|
|
258
|
+
return {
|
|
259
|
+
...state,
|
|
260
|
+
gameDirection,
|
|
261
|
+
betStake,
|
|
262
|
+
betGame,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=spin-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spin-handler.js","sourceRoot":"","sources":["../../../src/logic/handlers/spin-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/logic/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
/**
|
|
18
|
+
* Logic module exports
|
|
19
|
+
*/
|
|
20
|
+
__exportStar(require("./services"), exports);
|
|
21
|
+
__exportStar(require("./handlers"), exports);
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/logic/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;GAEG;AACH,6CAA2B;AAC3B,6CAA2B"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Counter Manager Service
|
|
3
|
+
*
|
|
4
|
+
* Manages bonus counters and trigger detection.
|
|
5
|
+
* Each bonus type has a counter that decrements on specific events.
|
|
6
|
+
* When a counter reaches 0, the bonus is triggered.
|
|
7
|
+
*/
|
|
8
|
+
import { SpinType } from '../../config/happy-panda.config';
|
|
9
|
+
import { Grid, GameDirection, BonusCounters, PendingBonuses, LineWin, RngProvider } from '../../domain/types';
|
|
10
|
+
/**
|
|
11
|
+
* Create initial bonus counters.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createInitialCounters(): BonusCounters;
|
|
14
|
+
/**
|
|
15
|
+
* Create empty pending bonuses.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createEmptyPendingBonuses(): PendingBonuses;
|
|
18
|
+
/**
|
|
19
|
+
* Randomize Bamboo Twins counter initial value (6 or 9).
|
|
20
|
+
*/
|
|
21
|
+
export declare function randomizeBambooTwinsCounter(gameDirection: GameDirection, rng: RngProvider): Promise<number>;
|
|
22
|
+
/**
|
|
23
|
+
* Randomize Camera counter initial value (3 or 5).
|
|
24
|
+
*/
|
|
25
|
+
export declare function randomizeCameraCounter(gameDirection: GameDirection, rng: RngProvider): Promise<number>;
|
|
26
|
+
/** Result of counter update */
|
|
27
|
+
export interface CounterUpdateResult {
|
|
28
|
+
counters: BonusCounters;
|
|
29
|
+
pendingBonuses: PendingBonuses;
|
|
30
|
+
triggeredBambooTriplets: boolean;
|
|
31
|
+
triggeredBambooTwins: boolean;
|
|
32
|
+
triggeredCamera: boolean;
|
|
33
|
+
triggeredFireworks: boolean;
|
|
34
|
+
triggeredRespin: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Update counters based on spin results.
|
|
38
|
+
* Only applies during paid_spin and respin_cherry.
|
|
39
|
+
*/
|
|
40
|
+
export declare function updateCounters(currentCounters: BonusCounters, currentPending: PendingBonuses, lineWins: LineWin[], grid: Grid, gameDirection: GameDirection, spinType: SpinType, totalWin: number, rng: RngProvider): Promise<CounterUpdateResult>;
|
|
41
|
+
/** Bonus type to consume */
|
|
42
|
+
export type BonusType = 'bambooTriplets' | 'bambooTwins' | 'camera' | 'fireworks' | 'centerBamboo';
|
|
43
|
+
/**
|
|
44
|
+
* Get the next bonus type to execute (priority order).
|
|
45
|
+
* Returns null if no bonuses pending.
|
|
46
|
+
*/
|
|
47
|
+
export declare function getNextBonusType(pending: PendingBonuses): BonusType | null;
|
|
48
|
+
/**
|
|
49
|
+
* Consume one bonus from pending.
|
|
50
|
+
* Returns updated pending and number of spins for that bonus.
|
|
51
|
+
*/
|
|
52
|
+
export declare function consumeBonus(pending: PendingBonuses, bonusType: BonusType): {
|
|
53
|
+
pending: PendingBonuses;
|
|
54
|
+
spins: number;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Check if any bonus is pending.
|
|
58
|
+
*/
|
|
59
|
+
export declare function hasPendingBonus(pending: PendingBonuses): boolean;
|
|
60
|
+
//# sourceMappingURL=counter-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counter-manager.d.ts","sourceRoot":"","sources":["../../../src/logic/services/counter-manager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAEL,QAAQ,EAOT,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,IAAI,EACJ,aAAa,EACb,aAAa,EACb,cAAc,EACd,OAAO,EACP,WAAW,EACZ,MAAM,oBAAoB,CAAC;AAO5B;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,aAAa,CAOrD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,cAAc,CAQ1D;AAED;;GAEG;AACH,wBAAsB,2BAA2B,CAC/C,aAAa,EAAE,aAAa,EAC5B,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,aAAa,EAAE,aAAa,EAC5B,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,MAAM,CAAC,CAIjB;AAMD,+BAA+B;AAC/B,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,aAAa,CAAC;IACxB,cAAc,EAAE,cAAc,CAAC;IAC/B,uBAAuB,EAAE,OAAO,CAAC;IACjC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,eAAe,EAAE,OAAO,CAAC;IACzB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,eAAe,EAAE,aAAa,EAC9B,cAAc,EAAE,cAAc,EAC9B,QAAQ,EAAE,OAAO,EAAE,EACnB,IAAI,EAAE,IAAI,EACV,aAAa,EAAE,aAAa,EAC5B,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,mBAAmB,CAAC,CA2I9B;AAMD,4BAA4B;AAC5B,MAAM,MAAM,SAAS,GAAG,gBAAgB,GAAG,aAAa,GAAG,QAAQ,GAAG,WAAW,GAAG,cAAc,CAAC;AAEnG;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,SAAS,GAAG,IAAI,CAQ1E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,SAAS,GACnB;IAAE,OAAO,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAsC5C;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAQhE"}
|