diff --git a/packages/components-shared/src/components/Authenticate.svelte b/packages/components-shared/src/components/Authenticate.svelte index 61e7150be..b24573299 100644 --- a/packages/components-shared/src/components/Authenticate.svelte +++ b/packages/components-shared/src/components/Authenticate.svelte @@ -2,7 +2,15 @@ import { onMount, type Snippet } from 'svelte'; import { requestAuthenticate, requestReplay } from 'rgs-requests'; - import { stateUrlDerived, stateBet, stateConfig, stateModal, stateUi } from 'state-shared'; + import { + stateUrlDerived, + stateBet, + stateConfig, + stateMeta, + stateModal, + stateUi, + reconcileBetModeMeta, + } from 'state-shared'; import { API_AMOUNT_MULTIPLIER, MOST_USED_BET_INDEXES } from 'constants-shared/bet'; type Props = { children: Snippet }; @@ -66,6 +74,15 @@ stateConfig.betMenuOptions = stateConfig.betAmountOptions.filter((_, index) => MOST_USED_BET_INDEXES.includes(index), ); + + // Example of authenticateData.config.gameModes + // [ + // { "mode": "base", "costMultiplier": 1, "maxBet": 2000000000 }, + // { "mode": "bonus", "costMultiplier": 200, "maxBet": 2000000000 } + // ] + if (authenticateData.config?.gameModes?.length) { + stateMeta.betModeMeta = reconcileBetModeMeta(authenticateData.config.gameModes); + } } // round diff --git a/packages/state-shared/src/stateMeta.svelte.ts b/packages/state-shared/src/stateMeta.svelte.ts index de5d69c80..950754e62 100644 --- a/packages/state-shared/src/stateMeta.svelte.ts +++ b/packages/state-shared/src/stateMeta.svelte.ts @@ -59,3 +59,35 @@ export const stateMeta = $state({ export const stateMetaDerived = { betModeMetaList: () => Object.values(stateMeta.betModeMeta), }; + +/** + * Reconcile `betModeMeta` against the bet modes the RGS reports at authentication. + * + * `betModeMeta` defaults to a placeholder table that does not describe any + * particular game. Modes it lists that the RGS does not know are rejected with + * ERR_VAL "invalid amount" when played, and a costMultiplier that disagrees with + * the published math is wrong in the UI before it is ever sent. + * + * Server-reported modes win on identity and cost; presentation a game has already + * set (assets, copy, type) is kept for the modes that survive. + */ +export const reconcileBetModeMeta = ( + gameModes: { mode: string; costMultiplier: number }[], +): BetModeMeta => { + const reconciled: BetModeMeta = {}; + + gameModes.forEach(({ mode, costMultiplier }) => { + const key = mode.toUpperCase(); + const existing = stateMeta.betModeMeta[key] ?? stateMeta.betModeMeta[mode.toLowerCase()]; + + reconciled[key] = { + ...(existing ?? DEFAULT_BET_MODE_META.BASE), + mode: key, + costMultiplier, + // only infer when the game has not described this mode itself + type: existing?.type ?? (costMultiplier === 1 ? 'default' : 'buy'), + } as BetModeData; + }); + + return reconciled; +};