Skip to content

Derive bet modes from the RGS instead of the placeholder table - #36

Open
soulrap wants to merge 1 commit into
engineio:mainfrom
soulrap:betmode-meta-from-rgs
Open

Derive bet modes from the RGS instead of the placeholder table#36
soulrap wants to merge 1 commit into
engineio:mainfrom
soulrap:betmode-meta-from-rgs

Conversation

@soulrap

@soulrap soulrap commented Aug 28, 2026

Copy link
Copy Markdown

Problem

stateMeta.betModeMeta defaults to DEFAULT_BET_MODE_META in
state-shared/src/constants.ts:

mode costMultiplier type
BASE 1.0 default
ANTE 1.2 activate
SUPERANTE 5 activate
SUPERSPIN 25 activate
BONUS 100 buy
SUPER 200 buy

That table describes no particular game, and nothing overrides it — none of
the six sample apps assign betModeMeta. So every game ships the same six modes
in its buy/activate dialog regardless of what its math actually published.

Reproduced with the scatter sample against a live RGS session. Its math
declares exactly two modes (base cost 1.0, bonus cost 200), but the dialog
offered six. Pressing a buy option returned:

ERR_VAL   "invalid amount"

Two distinct failures are folded together here:

  1. Modes that do not exist. ANTE, SUPERANTE, SUPERSPIN and SUPER are not in
    this game's math. The RGS rejects them.
  2. A cost that disagrees. BONUS is declared at 100x, while the published
    math has it at 200x. Even for a real mode, the dialog shows the wrong price
    before any request is sent.

The fix

/wallet/authenticate already returns the authoritative list:

"gameModes": [
  { "mode": "base",  "costMultiplier": 1,   "maxBet": 2000000000 },
  { "mode": "bonus", "costMultiplier": 200, "maxBet": 2000000000 }
]

Authenticate.svelte already consumes config for betLevels and
jurisdiction — it just ignores gameModes. This reconciles against it in the
same place:

if (authenticateData.config?.gameModes?.length) {
    stateMeta.betModeMeta = reconcileBetModeMeta(authenticateData.config.gameModes);
}

reconcileBetModeMeta (new, in state-shared) keeps only the modes the server
reports, takes costMultiplier from the server, and preserves any presentation
a game has already set — assets, copy, and type — for the modes that survive.
type is only inferred (costMultiplier === 1 ? 'default' : 'buy') for a
server mode the game has not described itself.

Deriving from the server rather than from each game's local config means this
cannot drift from what the RGS will actually accept, and it fixes all six
samples without per-app wiring.

Verification

Against a live session, scatter, with the buy dialog opened:

before after
modes offered 6 (3 activate, 2 buy, + base) 1 (BONUS)
bonus price shown $100.00 $200.00
pressing buy ERR_VAL "invalid amount" round plays
existing copy preserved ("Each spin may have a random multiplier applied to winning lines.")

A full bonus round then settled correctly end to end — $992.00 → $792.00 on the
buy, freespins with a global multiplier, → $842.40 on payout.

Note

The placeholder table is left in place as the pre-authentication default, so
nothing changes for a game that sets its own meta before this runs, and the
dialog still has something to render if gameModes is absent. If you would
rather the default table were dropped entirely, or that this live in a derived
value rather than an assignment, happy to redo it.

`stateMeta.betModeMeta` defaults to a placeholder table (ANTE / SUPERANTE /
SUPERSPIN / BONUS / SUPER) that describes no particular game, and nothing
overrides it - none of the sample games do. Two things follow:

- Modes the published math does not have are offered in the buy/activate
  dialog. Playing one is rejected by the RGS with ERR_VAL "invalid amount".
- BONUS is declared at costMultiplier 100. A game whose bonus costs 200x
  shows the wrong price before the request is ever sent.

/wallet/authenticate already returns the authoritative list as
config.gameModes, and Authenticate.svelte already consumes config for
betLevels and jurisdiction - it just ignores gameModes. Reconcile against it
there: server modes win on identity and cost, presentation a game has set
(assets, copy, type) is kept for the modes that survive.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant