@energy8platform/platform-core 0.23.3 → 0.24.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 +5 -3
- package/dist/index.cjs.js +60 -17
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +20 -6
- package/dist/index.esm.js +60 -17
- package/dist/index.esm.js.map +1 -1
- package/dist/shell.cjs.js +60 -17
- package/dist/shell.cjs.js.map +1 -1
- package/dist/shell.d.ts +21 -7
- package/dist/shell.esm.js +60 -17
- package/dist/shell.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/shell/GameShell.ts +2 -1
- package/src/shell/components/BottomBar.ts +7 -3
- package/src/shell/components/GameInfo.ts +21 -2
- package/src/shell/components/ReplayModal.ts +2 -1
- package/src/shell/format.ts +14 -11
- package/src/shell/shell.css.ts +6 -0
- package/src/shell/types.ts +19 -6
package/README.md
CHANGED
|
@@ -684,7 +684,7 @@ await removeGameShell();
|
|
|
684
684
|
| `theme` | `ThemeConfig?` | `{ scheme?: 'dark' \| 'light', accent? }`. Defaults to dark. `accent` also tints the BUY BONUS button; per-card accents are `BonusOption.accentColor`. |
|
|
685
685
|
| `language` | `string` | Currently `'en'` is the source language. |
|
|
686
686
|
| `isSocial` | `boolean?` | Swap built-in text to social-casino vocabulary (bet → play, win → …). Game-supplied strings are untouched. |
|
|
687
|
-
| `currency` | `CurrencyConfig` | `{ symbol, position: 'left'\|'right',
|
|
687
|
+
| `currency` | `CurrencyConfig` | `{ symbol, position: 'left'\|'right', maxDecimals?, minDecimals?, separator? }`. `maxDecimals` (default 2) / `minDecimals` (default `maxDecimals`): **win & total-win** show up to `maxDecimals`, trimming trailing zeros down to `minDecimals`; **balance / bet / prices** stay fixed at `minDecimals`. |
|
|
688
688
|
| `availableBets` | `number[]` | Bet ladder shown in the bet picker. |
|
|
689
689
|
| `defaultBet` / `currentBet` | `number` / `number \| null` | `currentBet` restores a saved bet; `null` falls back to `defaultBet`. |
|
|
690
690
|
| `balance` / `win` | `number` | Initial readouts. |
|
|
@@ -715,7 +715,8 @@ the previous value.
|
|
|
715
715
|
shell.setBalance(n); shell.setWin(n); shell.setBet(n);
|
|
716
716
|
shell.setBusy(true); // disables controls mid-spin
|
|
717
717
|
shell.setMode('freeSpins');
|
|
718
|
-
shell.setFreeSpins({ current: 1, total: 10, totalWin: 0 }); //
|
|
718
|
+
shell.setFreeSpins({ current: 1, total: 10, totalWin: 0 }); // counter shows "1 / 10"
|
|
719
|
+
shell.setFreeSpins({ total: 9, totalWin: 0 }); // current omitted/null → single number "9" (decrement it for a countdown)
|
|
719
720
|
shell.setAutoplay({ active: true, remaining: 25 });
|
|
720
721
|
shell.setTurbo(2);
|
|
721
722
|
shell.setBuyBonusEnabled(false); // grey out BUY BONUS (e.g. insufficient balance)
|
|
@@ -768,7 +769,8 @@ draws the rest:
|
|
|
768
769
|
- `{ type: 'controls' }` — auto-generated control legend.
|
|
769
770
|
- `{ type: 'paytable', rows: PaytableRow[] }` — symbol → win tiers (`"<count> x<multiplier>"`).
|
|
770
771
|
- `{ type: 'wins', kind, grid, … }` — auto-drawn win illustration. `kind` is `'classic'` (paylines),
|
|
771
|
-
`'cluster'`, `'anywhere'`, or `'
|
|
772
|
+
`'cluster'`, `'anywhere'`, `'ways'`, or `'shapes'` — `{ kind: 'shapes', shapes: ShapeDef[] }` lists
|
|
773
|
+
named cell patterns (`{ cells: CellRef[], name, description? }`) as a grid-illustration row each.
|
|
772
774
|
- `{ type: 'custom', title, html | node }` — your own rules markup.
|
|
773
775
|
|
|
774
776
|
```typescript
|
package/dist/index.cjs.js
CHANGED
|
@@ -1278,6 +1278,12 @@ const SHELL_CSS = SHELL_FONT_CSS + `
|
|
|
1278
1278
|
#${SHELL_ROOT_ID} .ge-gi-mode-st span { color:var(--shell-plaque-label); font-size:10px; letter-spacing:.1em; text-transform:uppercase; }
|
|
1279
1279
|
#${SHELL_ROOT_ID} .ge-gi-mode-st b { color:#fff; font-size:14px; font-weight:800; font-variant-numeric:tabular-nums; }
|
|
1280
1280
|
#${SHELL_ROOT_ID} .ge-gi-mode-desc { color:rgba(255,255,255,.78); font-size:14px; line-height:1.5; margin:0; }
|
|
1281
|
+
/* shapes — row list (grid illustration left, name + description right), modes-style text */
|
|
1282
|
+
#${SHELL_ROOT_ID} .ge-gi-shapes { display:flex; flex-direction:column; }
|
|
1283
|
+
#${SHELL_ROOT_ID} .ge-gi-shape { display:flex; align-items:center; gap:16px; padding:12px 0; }
|
|
1284
|
+
#${SHELL_ROOT_ID} .ge-gi-shape + .ge-gi-shape { border-top:1px solid var(--shell-plaque-line); }
|
|
1285
|
+
#${SHELL_ROOT_ID} .ge-gi-shape .ge-gi-pl-svg { flex:0 0 auto; width:96px; }
|
|
1286
|
+
#${SHELL_ROOT_ID} .ge-gi-shape-tx { flex:1; min-width:0; display:flex; flex-direction:column; gap:4px; }
|
|
1281
1287
|
#${SHELL_ROOT_ID} .ge-gi-custom { color:rgba(255,255,255,.88); font-size:15px; line-height:1.6; }
|
|
1282
1288
|
|
|
1283
1289
|
/* buy bonus cards — art-forward, centred, flat (no gradients); --card-acc/--card-ink per card.
|
|
@@ -1452,22 +1458,25 @@ const SHELL_CSS = SHELL_FONT_CSS + `
|
|
|
1452
1458
|
|
|
1453
1459
|
/** The shared money formatter for every shell readout (balance, win, total win, bet, prices).
|
|
1454
1460
|
*
|
|
1455
|
-
* `
|
|
1456
|
-
* is the MINIMUM.
|
|
1457
|
-
* —
|
|
1458
|
-
*
|
|
1461
|
+
* `maxDecimals` is the MAXIMUM fraction digits (default 2); `minDecimals` (defaults to
|
|
1462
|
+
* `maxDecimals`) is the MINIMUM. By default the value is shown at exactly `minDecimals` places.
|
|
1463
|
+
* With `variableDecimals` — used only for win / total-win — it is rounded to `maxDecimals`, then
|
|
1464
|
+
* trailing zeros are trimmed down to (but never past) `minDecimals`, so small wins keep their
|
|
1465
|
+
* significant digits. Balance / bet / prices stay fixed at `minDecimals`.
|
|
1459
1466
|
*
|
|
1460
|
-
* Example with `
|
|
1461
|
-
*
|
|
1462
|
-
* 0.
|
|
1467
|
+
* Example with `maxDecimals: 4, minDecimals: 2`:
|
|
1468
|
+
* fixed → 0.0673 → 0,07 0.3 → 0,30
|
|
1469
|
+
* variable → 0.0673 → 0,0673 0.067 → 0,067 0.3 → 0,30 0 → 0,00
|
|
1463
1470
|
*/
|
|
1464
|
-
function formatCurrency(value, currency) {
|
|
1465
|
-
const
|
|
1466
|
-
const minDecimals = Math.max(0, Math.min(
|
|
1471
|
+
function formatCurrency(value, currency, variableDecimals = false) {
|
|
1472
|
+
const maxDecimals = currency.maxDecimals ?? 2;
|
|
1473
|
+
const minDecimals = Math.max(0, Math.min(maxDecimals, currency.minDecimals ?? maxDecimals));
|
|
1467
1474
|
const thousands = currency.separator?.thousands ?? '.';
|
|
1468
1475
|
const decimal = currency.separator?.decimal ?? ',';
|
|
1469
1476
|
const safe = Number.isFinite(value) ? value : 0;
|
|
1470
|
-
|
|
1477
|
+
// fixed callers round at minDecimals; variable callers round at maxDecimals then trim back down.
|
|
1478
|
+
const places = variableDecimals ? maxDecimals : minDecimals;
|
|
1479
|
+
const fixed = safe.toFixed(places);
|
|
1471
1480
|
const [intPart, rawFrac = ''] = fixed.split('.');
|
|
1472
1481
|
// trim trailing zeros, but keep at least `minDecimals` fraction digits
|
|
1473
1482
|
let fracPart = rawFrac;
|
|
@@ -1628,6 +1637,7 @@ function iconBtn(ge, name, onClick, active = false) {
|
|
|
1628
1637
|
function renderBottomBar(shell) {
|
|
1629
1638
|
const { state, config } = shell;
|
|
1630
1639
|
const fmt = (n) => formatCurrency(n, config.currency);
|
|
1640
|
+
const fmtWin = (n) => formatCurrency(n, config.currency, true); // win / total-win: variable decimals
|
|
1631
1641
|
const mobile = shell.layout === 'mobile';
|
|
1632
1642
|
const bar = document.createElement('div');
|
|
1633
1643
|
bar.className = 'ge-shell-bottom';
|
|
@@ -1671,10 +1681,13 @@ function renderBottomBar(shell) {
|
|
|
1671
1681
|
auto = config.features.autoplay ? autoButton(shell) : null;
|
|
1672
1682
|
buy = (config.features.buyBonus !== false || config.onBonusBuy) ? buyBtn(shell) : null;
|
|
1673
1683
|
}
|
|
1674
|
-
const winEl = state.win > 0 ? readout('win', shell.t('Win'),
|
|
1684
|
+
const winEl = state.win > 0 ? readout('win', shell.t('Win'), fmtWin(state.win)) : null;
|
|
1675
1685
|
// FS/replay left blocks: spins counter + accumulated Total Win (shown even at €0).
|
|
1676
|
-
|
|
1677
|
-
const
|
|
1686
|
+
// current = number → "current / total"; current = null/undefined → just the (game-driven) total.
|
|
1687
|
+
const fs = state.freeSpins;
|
|
1688
|
+
const fsText = fs.current == null ? `${fs.total}` : `${fs.current} / ${fs.total}`;
|
|
1689
|
+
const fsCounter = showFsBlocks ? readout('fs-counter', shell.t('Free spins'), fsText) : null;
|
|
1690
|
+
const fsTotalWin = showFsBlocks ? readout('fs-totalwin', shell.t('Total win'), fmtWin(fs.totalWin)) : null;
|
|
1678
1691
|
if (mobile) {
|
|
1679
1692
|
// rows: [balance · win] · [menu · auto · spin · FS counter · Total Win · turbo · buy] · [− bet +]
|
|
1680
1693
|
// FS counter + Total Win live in the controls row (alongside menu/turbo), not the top readouts.
|
|
@@ -2050,7 +2063,7 @@ function paytableCard(r) {
|
|
|
2050
2063
|
}
|
|
2051
2064
|
// ── wins (one section = one pay type; cells filled in the accent colour, no line) ──
|
|
2052
2065
|
function winFallbackTitle(kind) {
|
|
2053
|
-
return { classic: 'Paylines', cluster: 'Cluster pays', anywhere: 'Pays anywhere', ways: 'Ways to win' }[kind];
|
|
2066
|
+
return { classic: 'Paylines', cluster: 'Cluster pays', anywhere: 'Pays anywhere', ways: 'Ways to win', shapes: 'Winning shapes' }[kind];
|
|
2054
2067
|
}
|
|
2055
2068
|
function sectionWins(s, el) {
|
|
2056
2069
|
if (s.kind === 'classic') {
|
|
@@ -2074,6 +2087,15 @@ function sectionWins(s, el) {
|
|
|
2074
2087
|
row.appendChild(winDesc(s.description));
|
|
2075
2088
|
el.appendChild(row);
|
|
2076
2089
|
}
|
|
2090
|
+
else if (s.kind === 'shapes') {
|
|
2091
|
+
if (s.description)
|
|
2092
|
+
el.appendChild(winDesc(s.description));
|
|
2093
|
+
const list = document.createElement('div');
|
|
2094
|
+
list.className = 'ge-gi-shapes';
|
|
2095
|
+
for (const sh of s.shapes)
|
|
2096
|
+
list.appendChild(shapeRow(s.grid, sh));
|
|
2097
|
+
el.appendChild(list);
|
|
2098
|
+
}
|
|
2077
2099
|
else {
|
|
2078
2100
|
if (s.description)
|
|
2079
2101
|
el.appendChild(winDesc(s.description));
|
|
@@ -2084,6 +2106,25 @@ function sectionWins(s, el) {
|
|
|
2084
2106
|
}
|
|
2085
2107
|
return el;
|
|
2086
2108
|
}
|
|
2109
|
+
/** One named shape: grid illustration (left) + name and optional description (right) — modes-style. */
|
|
2110
|
+
function shapeRow(grid, sh) {
|
|
2111
|
+
const row = document.createElement('div');
|
|
2112
|
+
row.className = 'ge-gi-shape';
|
|
2113
|
+
const tx = document.createElement('div');
|
|
2114
|
+
tx.className = 'ge-gi-shape-tx';
|
|
2115
|
+
const h = document.createElement('b');
|
|
2116
|
+
h.className = 'ge-gi-mode-h';
|
|
2117
|
+
h.textContent = sh.name;
|
|
2118
|
+
tx.appendChild(h);
|
|
2119
|
+
if (sh.description) {
|
|
2120
|
+
const p = document.createElement('p');
|
|
2121
|
+
p.className = 'ge-gi-mode-desc';
|
|
2122
|
+
p.textContent = sh.description;
|
|
2123
|
+
tx.appendChild(p);
|
|
2124
|
+
}
|
|
2125
|
+
row.append(gridSvg(grid, sh.cells), tx);
|
|
2126
|
+
return row;
|
|
2127
|
+
}
|
|
2087
2128
|
function winDesc(text) {
|
|
2088
2129
|
const p = document.createElement('p');
|
|
2089
2130
|
p.className = 'ge-gi-win-desc';
|
|
@@ -2490,6 +2531,7 @@ function buildModal(opts) {
|
|
|
2490
2531
|
function buildReplayModal(shell, opts) {
|
|
2491
2532
|
const { bonusId, bet, payoutMultiplier } = opts;
|
|
2492
2533
|
const fmt = (n) => formatCurrency(n, shell.config.currency);
|
|
2534
|
+
const fmtWin = (n) => formatCurrency(n, shell.config.currency, true); // total win: variable decimals
|
|
2493
2535
|
const bonus = Array.isArray(shell.config.features.buyBonus)
|
|
2494
2536
|
? shell.config.features.buyBonus.find((b) => b.id === bonusId)
|
|
2495
2537
|
: undefined;
|
|
@@ -2518,7 +2560,7 @@ function buildReplayModal(shell, opts) {
|
|
|
2518
2560
|
row('Cost multiplier', `${costMultiplier}×`);
|
|
2519
2561
|
row('Total cost bet', fmt(bet * costMultiplier));
|
|
2520
2562
|
row('Payout multiplier', `${payoutMultiplier}×`);
|
|
2521
|
-
row('Total win',
|
|
2563
|
+
row('Total win', fmtWin(payoutMultiplier * bet), true);
|
|
2522
2564
|
ui.body.appendChild(rows);
|
|
2523
2565
|
const actions = document.createElement('div');
|
|
2524
2566
|
actions.className = 'ge-modal-actions';
|
|
@@ -2807,12 +2849,13 @@ class GameShell extends EventEmitter {
|
|
|
2807
2849
|
}
|
|
2808
2850
|
animateMoney() {
|
|
2809
2851
|
const fmt = (n) => formatCurrency(n, this.config.currency);
|
|
2852
|
+
const fmtWin = (n) => formatCurrency(n, this.config.currency, true); // win: variable decimals
|
|
2810
2853
|
const bal = this.barHost.querySelector('[data-ge="balance"]');
|
|
2811
2854
|
const win = this.barHost.querySelector('[data-ge="win"]');
|
|
2812
2855
|
if (bal && this.state.balance !== this.prevBalance)
|
|
2813
2856
|
this.moneyAnims.push(animateReadout(bal, this.prevBalance, this.state.balance, fmt));
|
|
2814
2857
|
if (win && this.state.win !== this.prevWin)
|
|
2815
|
-
this.moneyAnims.push(animateReadout(win, this.prevWin, this.state.win,
|
|
2858
|
+
this.moneyAnims.push(animateReadout(win, this.prevWin, this.state.win, fmtWin));
|
|
2816
2859
|
this.prevBalance = this.state.balance;
|
|
2817
2860
|
this.prevWin = this.state.win;
|
|
2818
2861
|
}
|