Frosted Market Bonanza — Developer Guide

This document is based on the actual implementation in the game code and config. It does not rely on assumptions or external marketing text. When the code does not make a rule clear, this guide explicitly says: "Not clearly identifiable from the current code."

1. Game Overview

Frosted Market Bonanza is implemented as a cluster/cascade slot game in a 6-column × 5-row grid.

  • Grid size: 6 columns, 5 rows
  • Win system: cluster-based, not a classic payline system
  • The game uses symbol clusters and cascade refill logic
  • The base game may trigger a free-spin feature through scatter counts
  • The free-spin game has bomb multipliers and additional scatter retrigger logic
  • There is no standard wild symbol in the current implementation

Imagine the game as a 5-row board that is filled with symbols. The backend groups matching symbols by position, checks whether a cluster is large enough, pays out based on the cluster size, removes winning symbols, refills the grid, and repeats until no more winning clusters remain.

The implementation shows this clearly in games/frostedmarketbonanza/src/logic.ts:

  • minClusterSize = 8
  • groupSymbolPositions(...) is used to count symbols by position
  • winning symbols are excluded from scatter and multiplierSymbol
  • cluster wins are added together into cascadeWin
  • if the board has no wins and no nudge trigger, the engine may apply symbol conversion

Main symbols

From the pay table and symbolsMap in games/frostedmarketbonanza/src/maths/frosted-market-bonanza-R3.json:

  • H1, H2, H3, H4: high-value symbols
  • L1, L2, L3, L4, L5: low-value symbols
  • SC: scatter symbol
  • BN: multiplier bomb symbol
  • STACK1, STACK2: stack replacement symbols used during symbol resolution

The game's symbolsMap also maps raw display symbols like Pic1, Pic2, Pic3, Pic4, A, K, Q, J, 10, Scatter, and BOMB into the internal game values such as H1, H2, L1, SC, and BN.

Special symbols

Scatter

SC is the scatter symbol.

The config in games/frostedmarketbonanza/src/maths/frosted-market-bonanza-R3.json defines:

  • freeSpinsTrigger.minScatters = 4
  • freeSpinsTrigger.initialCount = 10
  • freeSpinsRetrigger.minScatters = 3
  • freeSpinsRetrigger.additionalSpins = 5

When the board reaches the free-spin trigger threshold, the game sets nextFeature = 'freespins' and prepares a free-spin feature.

Multiplier bomb

BN is the multiplier symbol in free games. The code checks configSymbols.multiplierSymbol and stores multiplier values on bomb positions as symbolName_x such as BN_2, BN_5, etc. The multiplier is then applied to the free-spin win total.

Wild behavior

There is no wild symbol in the current code. The pay table and symbol map do not define a wild symbol, and the cluster detector deliberately skips scatter and multiplierSymbol from cluster wins.

This means the implementation does not have a standard wild substitute rule in Frosted Market Bonanza.

Scatter behavior

Scatter logic is implemented in games/frostedmarketbonanza/src/logic.ts:

  • lastScCount is counted from symbolCounts[configSymbols.scatter]?.count
  • scatterPay is calculated from math.payTable[SC][lastScCount - 1] and then multiplied by stakeValue
  • scatter triggers are checked after the cascade loop ends
  • base game trigger threshold is 4 scatters
  • retrigger threshold in free games is 3 scatters

Bonus / free-spin behavior

The game supports free spins through freespins feature handling.

  • Base game triggers free spins at 4 scatters
  • Free-spin award: 10 spins initially
  • Retrigger: if a free spin finishes with 3 or more scatters, the code adds 5 more spins via pendingFeature
  • Free-spin results are stored in featureResults[0]

Multipliers

Multipliers are implemented as bomb multipliers in free games.

  • Bomb weights are defined for BOMB_SET1_Weights and BOMB_SET2_Weights
  • Selectable values include things like 2x, 3x, 4x, 5x, 8x, 10x, 12x, 15x, 20x, 25x, 50x, 100x
  • The game sums bomb values across the free-spin cascade and multiplies the total free-spin win by the total bomb multiplier

Other important mechanics

  • Nudge feature: on non-winning base-game spins with exactly 3 scatters, the code may nudge a limited number of reels and optionally add a scatter
  • Symbol conversion: on blank/no-win base spins, the engine may convert low symbols to high symbols and re-run the spin
  • Stack symbol replacement: STACK1 and STACK2 are resolved before evaluation and replaced with weighted high/low symbols
  • Buy bonus mode: buyBonus chooses BB_Trigger math and can place scatter symbols on the base spin before evaluation
  • Ante mode: ante changes the game type and base bet to anteBaseBet = 25

2. Important Slot/Game Terminology

This is the terminology that matters for this game.

Reel

A reel is one vertical strip of symbols. In the actual layout, the game has 6 columns, meaning 6 reel positions in the board. Each column is generated from a reel strip in the JSON math file.

Row

A row is one horizontal band in the 5-row board. The board is 5 rows high.

Symbol

A symbol is a value such as H1, L2, or SC. In the platform, raw display values such as Pic1 or Scatter are mapped to internal symbols.

Cluster

A cluster is a group of matching symbol positions that touch and reach the minimum size. For Frosted Market Bonanza, the minimum cluster size is 8.

Cascade

A cascade is one evaluation pass on the board. After a winning cluster is removed, the board is refilled and evaluated again. The code calls cascadeRefillReelView(...) and continues while there are wins.

Payline

Not used in this game's current implementation. The code does not evaluate paylines. It evaluates clusters.

Way

Not used as a separate pay system here. The game does not use standard ways-of-win logic.

Win

A win is represented as spinWin inside a cascade entry, and also as totalWin on the final SpinResult. The code sums all cluster wins and scatter wins into the final result.

Wild

Not clearly identifiable from the current code. There is no WILD symbol defined in this game's config or pay table.

Scatter

The SC symbol. In this game, scatters count toward feature trigger thresholds and also contribute a scatter pay when enough are present.

Multiplier

A free-spin multiplier is represented by BN bomb values such as 2x, 8x, 25x, 100x. These can be applied to the total free-spin win.

Free Spin

A free spin is a spin executed in feature mode, represented by gameType = 'FG', ANTE_FG, or BB. Free spins are tracked by pendingFeature and featureResults.

Feature

A feature is a special round or state triggered by a symbol condition. In this game, the relevant feature states are free spins, nudge, and symbol conversion.

Bet

The player bet is passed in as betAmount and then translated into a stake value for the game. The code uses stakeValue = totalBet / baseBet.

Stake

The stake is the normalized bet value used in the pay calculation. For example, if totalBet = 20 and baseBet = 20, then stakeValue = 1.

Win amount

The final win is computed from cluster payouts and scatter payouts. The cluster formula is winAmount = payTable[symbol][sizeIndex] * stakeValue.

RTP

Not clearly identifiable from the current code. There is no explicit RTP field exposed in the math config or game code as a directly readable value.

Volatility

Not clearly identifiable from the current code. The code exposes weights, payouts, and feature triggers, but no explicit volatility label or formula.


3. Repository / Code Structure

The game lives in games/frostedmarketbonanza.

File / FolderPurposeImportant formatNotes
games/frostedmarketbonanza/src/plugin.tsGame entry point for the platformpluginLoads the math JSON, exposes spin() and feature()
games/frostedmarketbonanza/src/engine.tsGame execution orchestratorengineChooses game mode, creates reels, runs base spin and optional conversion rerun
games/frostedmarketbonanza/src/logic.tsCore game logic and win evaluationlogicEvaluates clusters, scatter triggers, free spins, nudge, cascade refill
games/frostedmarketbonanza/src/interfaces.tsShared request/result contractstypesDefines GameSpinInput, SpinResult, feature structs
games/frostedmarketbonanza/src/symbol-conversion.tsPassive conversion featurehelperConverts low symbols to high symbols under certain conditions
games/frostedmarketbonanza/src/maths/frosted-market-bonanza-R3.jsonMath and configurationJSONContains reel strips, weights, pay table, free-spin settings
games/frostedmarketbonanza/project.jsonNx game registrationconfigRegisters the project and cert tasks
tools/game-tools/src/executors/simulate/analyzers/games/frosted-market-bonanza.analyzer.tsSimulation statsanalyzerCounts cluster wins, scatter wins, bomb multipliers, nudge triggers

Why these files matter

  • plugin.ts is the public entry point seen by the platform.
  • engine.ts decides which reel set and math mode to use and handles a conversion rerun.
  • logic.ts contains the true round evaluation logic.
  • interfaces.ts defines the data structures used across the request and response pipeline.
  • frosted-market-bonanza-R3.json stores the actual rules, reel strips, and weights.

Important files and responsibilities

games/frostedmarketbonanza/src/plugin.ts

This file loads the JSON math file and exposes the platform-level spin() API.

  • Input is a platform ISpinInput
  • The function extracts betAmount, isBuyBonus, extraData, gameMode, devMode, and rgsMaxWin
  • It converts the input into the internal GameSpinInput
  • It returns ISpinOutput<SpinResult>

games/frostedmarketbonanza/src/engine.ts

This is the orchestration layer.

  • Chooses regular reels vs ANTE vs BB_Trigger
  • Generates the initial reel view
  • Calls logic.spin()
  • If the spin is a non-winning base or ante spin without a nudge, it may apply applySymbolConversion() and run the spin again

games/frostedmarketbonanza/src/logic.ts

This is the heart of the game.

  • Runs cluster detection
  • Calculates cluster payouts
  • Handles cascade refill
  • Checks scatter triggers
  • Evaluates nudge feature
  • Manages free-spin flow and bomb multipliers
  • Applies win cap logic

games/frostedmarketbonanza/src/symbol-conversion.ts

This file defines the passive conversion feature.

  • Chooses a low symbol and a high symbol from configured weights
  • Counts how many appear
  • Triggers only if enough low/high symbols exist and the trigger roll says Yes
  • Replaces the chosen low symbol with the chosen high symbol

4. High-Level Game Architecture

The actual round flow is roughly:

Request ↓ Platform plugin entry (spin / feature) ↓ Engine selects math and reel strips ↓ Logic evaluates spin / free-spin state ↓ Cluster detection and scatter checks ↓ Feature evaluation (nudge, conversion, free spins) ↓ Win cap and total win calculation ↓ Response object

flowchart TD
    A[Incoming spin request] --> B[FrostedMarketBonanzaPlugin.spin]
    B --> C[FrostedMarketBonanzaEngine.executeSpin]
    C --> D[generateReelView]
    D --> E[FrostedMarketBonanzaLogic.spin]
    E --> F[Cluster detection + cascade refill]
    F --> G[Scatter check]
    G --> H{Feature trigger?}
    H -->|Yes| I[Free spins / nudge / symbol conversion]
    H -->|No| J[Final win cap + response]
    I --> K[Update pendingFeature / featureResults]
    K --> J
    J --> L[ISpinOutput<SpinResult>]

For feature rounds, the flow is:

flowchart TD
    A[previousSpinResult] --> B[FrostedMarketBonanzaPlugin.feature]
    B --> C[FrostedMarketBonanzaEngine.executeFeature]
    C --> D[FrostedMarketBonanzaLogic.runFeature]
    D --> E[select free-spin reel set]
    E --> F[spinFreeGame]
    F --> G[cluster detection + bomb multipliers]
    G --> H[update featureResults + pendingFeature]
    H --> I[apply win cap]
    I --> J[return updated SpinResult]

5. Request Flow

This is the real request path in the current code.

  1. The platform calls FrostedMarketBonanzaPlugin.spin() in games/frostedmarketbonanza/src/plugin.ts.
  2. plugin.spin() loads the math config from the JSON file for the selected gameMode.
  3. It reads input fields from the SDK request, including betAmount, isBuyBonus, devMode, extraData, and rgsMaxWin.
  4. It builds the internal GameSpinInput object and passes it into engine.executeSpin().
  5. engine.executeSpin() selects the reel set from the JSON based on buyBonus, ante, or default base game mode.
  6. It calls generateReelView(...) to create the board layout.
  7. logic.spin() runs the round evaluation.
  8. Inside logic.spin():
    • determines game type (BG, ANTE, FG, BB_Trigger, etc.)
    • calculates stakeValue = totalBet / baseBet
    • resolves stack symbols (STACK1, STACK2)
    • groups symbols by position
    • checks clusters with minimum size 8
    • calculates wins from pay table
    • handles cascade refill
    • evaluates scatter trigger and free-spin state
    • applies feature logic like nudge and symbol conversion
  9. If the spin qualifies for the passive symbol conversion flow, the engine may run applySymbolConversion() and a second logic.spin() call on the converted grid.
  10. Finally, the result is returned as a SpinResult and wrapped into ISpinOutput.

Important path details


6. Request Object

The public request enters as the SDK ISpinInput, but the actual game-specific request object inside the game is GameSpinInput in games/frostedmarketbonanza/src/interfaces.ts.

FieldTypeRequired?MeaningUsed in
betAmountnumberYesTotal bet value passed into the gameFrostedMarketBonanzaPlugin.spin(), logic.spin()
antebooleanNoWhether the round is using ante modeengine.executeSpin(), logic.spin()
buyBonusbooleanNoWhether the round is a buy-bonus trigger spinengine.executeSpin(), logic.spin()
combinationnumber[]NoOptional forced symbol sequence used in dev modegenerateReelView / debug tests
devModebooleanNoAllows debug overrides such as forced featuresplugin.ts, engine.ts
maxWinnumberNoExternal max-win cap value from platformapplyWinCap()
forceNudgeFeaturestringNoDev-only override for nudge decisionlogic.spin()
forceNudgeReelsnumberNoDev-only override for number of nudged reelslogic.spin()
forceSymbolConversionbooleanNoDev-only override for passive symbol conversionapplySymbolConversion()
forceBonusMultipliernumberNoDev-only override for free-spin bomb multiplierlogic.spin() / runFeature()

The platform request also contains fields such as:

  • gameMode
  • isBuyBonus
  • extraData
  • rgsMaxWin
  • devMode

These are not defined in the custom GameSpinInput interface, but they are used by the plugin before it builds the internal game input.

Feature request object

For free-spin continuation, the feature request is built as GameFeatureInput in games/frostedmarketbonanza/src/interfaces.ts:

  • previousSpinResult
  • isBuyBonus
  • combination
  • selectedReelSet
  • devMode
  • maxWin
  • forceBonusMultiplier

7. Response Object

The public response is an ISpinOutput<SpinResult> from the platform, and the actual game payload is the SpinResult object from games/frostedmarketbonanza/src/interfaces.ts.

FieldTypeMeaningWhere it is populated
cascadeDataCascadeData[]Per-cascade board informationlogic.spin()
betnumberOriginal betlogic.spin()
totalWinnumberTotal win after cluster + scatter + feature adjustmentslogic.spin() and runFeature()
baseWinnumberBase round win before feature adjustmentslogic.spin()
nextFeature`stringnull`Feature name if trigger is pending
pendingFeaturenumberRemaining feature count or pending free spinslogic.spin(), runFeature()
featureResultsFeatureResult[]Free-spin feature statelogic.spin(), runFeature()
activebooleanWhether the game is still activeset by logic.spin() and runFeature()
multipliernumberTotal bomb multiplier across the resultlogic.spin()
firstReelMultiplierValuenumberFirst free-spin bomb multiplierset in logic.spin()
newCascadeMultiplierValuenumberAdded multiplier on later cascadesset in logic.spin()
lineWinnumberThe total cluster win valueset as spinResult.totalWin before scatter addition
scatterPaynumberScatter payout onlylogic.spin()
maxCapReachedbooleanWhether the configured max win cap triggeredapplyWinCap()
maxWinnumberEffective max-win cap valueapplyWinCap()
antebooleanAnte mode persisted for the feature roundlogic.spin()
reelModifiersReelModifier[]Modifiers such as nudge or symbol conversionlogic.spin()

Important response distinction

  • lineWin: set to totalWin before scatter addition, so it represents the cluster win total in this implementation
  • scatterPay: scatter pay only
  • totalWin: cluster wins + scatter pay + feature totals, then capped if needed
  • featureResults[0].totalWin: cumulative free-spin total including trigger win on the first feature result
  • pendingFeature: remaining spins to play in feature mode

8. Game State

The main state is the SpinResult object in games/frostedmarketbonanza/src/interfaces.ts.

What is stored?

The result contains:

  • current board state (cascadeData[])
  • total win and base win
  • next feature to trigger
  • pending free-spin count
  • feature result metadata
  • reel modifiers from nudge / conversion
  • multiplier information
  • ante mode status

Where is it created?

  • logic.spin() creates the initial SpinResult
  • logic.runFeature() updates the same SpinResult object to continue free-spin rounds

Where is it modified?

  • cluster payouts are added within the cascade loop in logic.spin()
  • scatter triggers update nextFeature and pendingFeature
  • nudge adds to reelModifiers
  • symbol conversion adds to reelModifiers and rewrites cascadeData
  • free spins update featureResults[0] and decrement pendingFeature

Is it persisted?

The code does not persist the round state to a database in this game project. Instead, it keeps the state in-memory as previousSpinResult and passes it to the feature call.

In practice:

  • plugin.spin() returns the state to the caller
  • plugin.feature() receives previousSpinResult
  • the feature call continues from the previous result

Free-spin state representation

Free-spin state is represented by:

  • nextFeature = 'freespins' on trigger
  • pendingFeature stores the number of spins still to be processed
  • featureResults[0] stores the aggregate feature state
  • featureResults[0].currentCount tracks how many free spins have run
  • featureResults[0].totalWin tracks cumulative free-spin total

Cascade state representation

Each entry in cascadeData includes:

  • reelView
  • spinWin
  • scatterCount
  • scatterPositions
  • scatterPay
  • blustSymbols
  • multiplierPositions
  • bombTotalMultiplier

Feature state transition

flowchart TD
    A[Initial spin] --> B[Cluster win or scatter trigger]
    B --> C{Trigger free spins?}
    C -->|No| D[Round complete]
    C -->|Yes| E[Set nextFeature = freespins]
    E --> F[Create featureResults[0]]
    F --> G[Execute feature spin]
    G --> H{pendingFeature > 0?}
    H -->|Yes| I[Continue feature]
    H -->|No| J[Close feature]
    I --> G
    J --> K[Final result]

9. Math File — Most Important Section

The math engine is in games/frostedmarketbonanza/src/maths/frosted-market-bonanza-R3.json, and the rules are executed in games/frostedmarketbonanza/src/logic.ts.

Function: FrostedMarketBonanzaLogic.spin()

Purpose

This is the main round evaluator. It decides the board, cluster wins, cascades, scatter trigger, and the feature state for a base game or feature game.

Input

  • totalBet — total bet amount
  • math — full JSON game configuration
  • reelView — current board
  • isFreeGame — free-spin flag
  • buyBonus — buy-bonus flag
  • ante — ante flag
  • bombWeights — free-spin bomb weights
  • maxWin — external max win cap
  • forceNudgeFeature — dev override
  • forceNudgeReels — dev override
  • forceBonusMultiplier — dev override

Process

  • choose game type (BG, ANTE, FG, BB_Trigger, ANTE_FG, BB)
  • determine base bet and stakeValue
  • resolve stack symbols
  • count symbol positions in the grid
  • detect clusters for non-SC and non-BN symbols with minimum size 8
  • calculate cluster wins from math.payTable
  • apply multiplier bombs during free games
  • refill the board and continue cascade loop
  • evaluate scatter trigger and free-spin feature trigger
  • apply win cap using applyWinCap()
  • clean bomb suffixes from reel values before returning

Output

Returns a SpinResult with totalWin, scatterPay, nextFeature, pendingFeature, featureResults, and the board state.

Used by

  • FrostedMarketBonanzaEngine.executeSpin()
  • FrostedMarketBonanzaLogic.runFeature() calls spinFreeGame() which calls this method

Example

If a base spin has stakeValue = 1 and a cluster of H2 with size 8, then the pay table says H2 pays 50 at size 8, so the cluster win is 50.

Function: FrostedMarketBonanzaLogic.runFeature()

Purpose

This method executes the free-spin feature and updates the feature state.

Input

  • previousSpinResult
  • math
  • betAmount
  • isBuyBonus
  • selectedReelSet
  • maxWin
  • forceBonusMultiplier

Process

  • reads whether the round is ante-based from previousSpinResult.ante
  • selects a free-spin reel set using selectReelSet()
  • picks bomb weights based on the selected reel set
  • calls spinFreeGame()
  • appends the free-spin result to featureResults[0].spinResults
  • adds the result to featureResults[0].totalWin
  • handles retrigger logic with pendingFeature
  • applies max-win cap to the cumulative feature total
  • closes the feature when pendingFeature <= 0 or cap is reached

Output

Returns the updated SpinResult with the free-spin state and new total win.

Used by

  • FrostedMarketBonanzaEngine.executeFeature()

Example

Base spin triggers 10 free spins. The first free spin wins 200; a later free spin adds 500. The feature result total becomes 700 and the pendingFeature counter reduces from 10 to 9 after the spin.

Function: FrostedMarketBonanzaLogic.spinFreeGame()

Purpose

Creates the board for a free-spin round and delegates to the regular spin evaluator in feature mode.

Input

  • totalBet
  • math
  • reelStrips
  • buyBonus
  • ante
  • bombWeights
  • maxWin
  • forceBonusMultiplier
  • combination

Process

  • generates a reel view from the selected free-spin reel strips
  • calls the regular spin() method with isFreeGame: true

Output

One free-spin result.

Used by

  • runFeature()

Function: applySymbolConversion()

Purpose

Runs the base-game passive symbol conversion feature.

Input

  • reelView
  • mathByGameType
  • forceSymbolConversion (dev only)

Process

  • choose one low symbol and one high symbol from weighted arrays
  • count occurrences on the board
  • if there are fewer than 8 total relevant symbols, do nothing
  • roll a trigger using TriggerWeights
  • if triggered, replace every selected low symbol with the selected high symbol
  • record original positions and board state in reelModifiers

Output

Returns a new reel view plus SymbolConversionResult.

Used by

  • FrostedMarketBonanzaEngine.executeSpin()

Example

If L1 and H1 are selected and the board has L1 in 8 places, then the conversion can replace all L1 cells with H1. The code only does this when the trigger roll passes and the board qualifies.


10. Math Calculation Examples

Cluster win formula

The game uses cluster wins, not paylines.

The exact formula in code is:

const winAmount = multiply(symbolPay, stakeValue) ?? 0;

Where:

  • symbolPay comes from math.payTable[cluster.symbol][payIndex]
  • payIndex is set by Math.min(cluster.size - 1, payTable.length - 1)
  • stakeValue = totalBet / baseBet

Example:

  • total bet = 20
  • baseBet = 20
  • stakeValue = 1
  • cluster symbol = H2
  • cluster size = 8
  • pay table for H2 at size 8 = 50

Then:

  • winAmount = 50 × 1 = 50

Scatter payout formula

The code has:

const scPayouts = math.payTable[configSymbols.scatter];
scatterPay = multiply(scPayouts?.[lastScCount - 1] ?? 0, stakeValue);

From the JSON pay table:

  • SC values are [0, 0, 0, 60, 100, 2000, ...]

Examples:

  • 4 scatters -> 60 × stakeValue
  • 5 scatters -> 100 × stakeValue
  • 6 scatters -> 2000 × stakeValue

Free-spin multiplier example

If the free-spin bomb weights produce 5x and 3x, the game sums them:

  • total bomb multiplier = 5 + 3 = 8
  • if free-spin win total is 200, then multiplied total = 200 × 8 = 1600

This is exactly how the code does it:

if (totalBombMultiplier > 0 && freeSpinResult.totalWin > 0) {
  freeSpinResult.totalWin = multiply(freeSpinResult.totalWin, totalBombMultiplier);
}

Max win cap example

The game uses applyWinCap() with configCapMultiplier and rgsCap:

  • base game maxWinMultiplier = 10000
  • base game maxWinBbMultiplier = 10000
  • config cap uses totalBet × 10000

Example:

  • bet = 20
  • max multiplier = 10000
  • config cap = 20 × 10000 = 200000

If calculated win exceeds this value, the result is capped.


11. Symbol Generation

The actual symbol generation is largely driven by:

Reel strips

The BG, ANTE, FG, BB, and BB_Trigger sections in the math JSON define the reel strips. The base board is 6 columns × 5 rows, and each column contains a list of symbols.

Symbol weights

This game uses weighted symbol selection for:

  • STACK1_Weights
  • STACK2_Weights
  • BOMB_SET1_Weights
  • BOMB_SET2_Weights
  • ReelSelectionWeights
  • NudgeFeature.TriggerWeights
  • SymbolConversionFeature.TriggerWeights

Example from the config:

  • STACK1_Weights: H1 10, H2 25, H3 25, H4 25
  • STACK2_Weights: L1 15, L2 15, L3 20, L4 20, L5 18

This means the stack replacement logic chooses from a weighted set rather than a uniform random choice.

Weighted random selection example

The code uses selectWeightedRandom(...) from the SDK.

For STACK1_Weights:

  • H1 weight = 10
  • H2 weight = 25
  • H3 weight = 25
  • H4 weight = 25

Approximate distribution:

  • H1 ≈ 10 / 85 ≈ 11.8%
  • H2 ≈ 29.4%
  • H3 ≈ 29.4%
  • H4 ≈ 29.4%

Exact probabilities are derived from the actual weighted arrays in the JSON, not from a separate abstraction.

Special symbol generation

  • SC appears in reel strips and can be added by the nudge feature
  • BN is used as the bomb multiplier symbol inside free games
  • STACK1 and STACK2 are converted into high/low symbols before cluster evaluation

Symbol conversion weights

The conversion logic uses:

  • HighSymbolWeights: H1 10, H2 25, H3 25, H4 25
  • LowSymbolWeights: L1 15, L2 15, L3 20, L4 20, L5 18
  • TriggerWeights: Yes 1, No 49

This means the conversion trigger is weighted to be rare: roughly 1 in 50 if not forced by dev mode.


12. Win Evaluation

Win evaluation is cluster-based.

What counts as a win?

The game groups symbol positions with groupSymbolPositions(...) and checks them in the while (proceedNextCascade) loop.

It ignores:

  • SC (scatter)
  • BN (multiplier symbol)

It then evaluates each other symbol cluster:

if (count >= minClusterSize) {
  clusters.push({ symbol, positions, size: count });
}

with:

const minClusterSize = 8;

How many matching symbols are required?

At minimum, 8 positions of the same symbol are needed to form a winning cluster.

Are wins evaluated left-to-right?

No. This is not a payline or ways engine. The code groups positions by symbol and then evaluates cluster size, so the win logic is by symbol cluster, not left-to-right payline logic.

Can multiple wins happen simultaneously?

Yes. The code loops over all clusters and sums all cluster wins into cascadeWin.

for (const cluster of clusters) {
  ...
  cascadeWin = add(cascadeWin, winAmount);
}

Wild and scatter rules

  • Wild: not defined in the current code
  • Scatter: counted separately and not treated as a cluster-winning symbol
  • Multiplier bomb: not treated as cluster-paying symbol

Example

Suppose the board has 8 H2 symbols in a connected cluster and the stake value is 1.

  • H2 pay table at size 8 = 50
  • cluster win = 50

If there are also 4 scatters, the scatter pay is 60 and the total is 110 before any free-spin multiplier logic is applied.


13. Features

Feature: Nudge

Trigger

The game checks for nudge only when:

  • not in free game
  • game type is BG or ANTE
  • no cluster wins existed so far in the cascade loop
  • scatter count is 3 on the last cascade

What happens

The code selects a number of reels based on NudgeFeature.NumReelsWeights and optionally adds a scatter to one chosen reel. It then creates a NudgeFeatureModifier.

Relevant code

Implementation details

  • TriggerWeights: withScatter 37, no 64, withoutScatter 37
  • NumReelsWeights: 1 -> 100, 2 -> 5, 3 -> 1

This means the nudge is a weighted, rare, reel-shifting event that can optionally add a scatter to the result.

Feature: Symbol Conversion

Trigger

This is a passive base-game conversion feature. It is run only for base or ante spins when:

  • lineWin === 0
  • no nudge feature triggered
  • the board qualifies by low/high symbol counts

What happens

  • picks one low symbol and one high symbol from the weighted sets
  • counts them on the board
  • if the total count is at least 8, triggers a weighted Yes/No roll
  • if triggered, converts each low symbol to the chosen high symbol
  • re-runs the spin on the converted board

Relevant code

Important note

The code comment in games/frostedmarketbonanza/src/symbol-conversion.ts describes this as passive base-game logic. The current implementation also re-runs the spin from engine.ts. There is a known bug in the conversion branch that can drop the feature trigger state when a converted board creates a free-spin trigger. This is documented in docs/superpowers/handoff/2026-09-21-frosted-market-bonanza-freespin-trigger-bug.md. The current source is the truth for behavior, including the bug.

Feature: Free Spins

Trigger

4 scatters on a base game trigger 10 free spins.

What happens

  • nextFeature = 'freespins'
  • pendingFeature = 10
  • featureResults[0] is created
  • in the feature loop, each free-spin result is added to the total feature result

How it ends

  • when pendingFeature <= 0
  • or when max win cap is reached

Feature: Bomb multiplier in free spins

Trigger

The bomb multiplier is present in free games when a free-spin board contains BN symbols.

What happens

  • the game picks from BOMB_SET1_Weights or BOMB_SET2_Weights
  • values are stored as amounts like 2x, 5x, 25x, 100x
  • all multipliers in the final free-spin cascade are added into totalBombMultiplier
  • the free-spin total is multiplied by that total

14. Free Spins / Bonus Game

This game has a clear free-spin feature.

ComparisonNormal SpinFree Spin
Game typeBG, ANTE, BB_TriggerFG, ANTE_FG, BB
Scatter trigger4 scatters3 scatters retrigger
Initial spinsnot applicable10 spins
Bonus multipliernot presentBN bomb multipliers can appear
Net win capconfig max win cap per base gamesame cap by config but applied to cumulative feature total
State storageSpinResult onlyfeatureResults[0] + pendingFeature

Trigger logic

In base game, the trigger is:

if (lastScCount >= fsTriggerCount) {
  spinResult.nextFeature = 'freespins';
  ...
  if (isFreeGame) {
    spinResult.pendingFeature = features.freeSpinsRetrigger.additionalSpins;
  } else {
    spinResult.pendingFeature = features.freeSpinsTrigger.initialCount;
  }
}

with:

  • fsTriggerCount = features.freeSpinsTrigger.minScatters when not free game
  • fsTriggerCount = features.freeSpinsRetrigger.minScatters when free game

Free-spin state

The feature is stored in:

  • previousSpinResult.featureResults[0]
  • previousSpinResult.pendingFeature
  • previousSpinResult.nextFeature

The game decrements pendingFeature after each free-spin result.

Free-spin math change

The free-spin game uses separate reel strips and different ReelSelectionWeights, BOMB_SET weights, and different RallyNonRallyCascadeWeights arrays. The code also allows bomb multipliers to change the total free-spin win.

End condition

The free-spin feature ends when:

  • pendingFeature <= 0, or
  • the max-win cap was reached

At that point, featureResults[0].closed = true.


15. Cascade / Respin / Special Round Flow

This game does not use a traditional respin mechanic. It uses a cascade loop.

The actual pattern is:

  1. evaluate current board
  2. find clusters
  3. if cluster wins exist, remove winning symbols
  4. cascade refill occurs with cascadeRefillReelView()
  5. continue evaluating until no winning cluster remains
  6. after the cascade loop ends, check scatters and feature triggers
flowchart TD
    A[Initial reel view] --> B[Group symbols]
    B --> C[Find clusters >= 8]
    C --> D{Any cluster win?}
    D -->|No| E[Check scatter trigger]
    D -->|Yes| F[Add cluster win to cascade]
    F --> G[Remove winning symbols]
    G --> H[Refill board]
    H --> B
    E --> I[Feature trigger or round end]

This matches the implementation in logic.spin().


16. Complete End-to-End Example

Here is a simplified example based on the actual math and implementation.

Request

{
  "betAmount": 20,
  "gameMode": "R3",
  "devMode": false,
  "extraData": {}
}

This is the request sent to the platform plugin.

Step 1: plugin builds input

FrostedMarketBonanzaPlugin.spin() reads betAmount = 20 and gameMode = R3, loads the JSON math, and prepares the internal GameSpinInput.

Step 2: engine creates board

engine.executeSpin() checks the base game and picks math.BG.ReelSet_1.

Then it calls generateReelView() with:

  • rows = 5
  • columns = 6

This creates a 6 × 5 reel view.

Step 3: logic evaluates spin

logic.spin() determines:

  • gameType = 'BG'
  • baseBet = 20
  • stakeValue = 20 / 20 = 1

It resolves stack symbols and then groups symbols by position. Suppose the board contains 8 H2 symbols and 4 SC symbols.

Step 4: cluster evaluation

The cluster detector sees H2 count = 8 and SC count = 4.

The game ignores SC for cluster win purposes, but it does count cluster wins for H2.

From the pay table:

  • H2 pay at size 8 = 50
  • cluster win = 50 × 1 = 50

Step 5: scatter evaluation

Scatter trigger check sees lastScCount = 4 and the trigger threshold is 4.

The code sets:

  • nextFeature = 'freespins'
  • pendingFeature = 10
  • scatterPay = 60 × 1 = 60

Step 6: total win calculation

  • cluster win = 50
  • scatter win = 60
  • total win = 110

The result is then stored in the SpinResult, and the game is marked as active because feature is pending.

Step 7: free-spin state created

The featureResults[0] entry is created with:

  • featureType = 'freespins'
  • totalCount = 10
  • closed = false

Step 8: response

The platform returns a response similar to:

{
  "totalWin": 110,
  "featureTriggered": true,
  "gameData": {
    "nextFeature": "freespins",
    "pendingFeature": 10,
    "totalWin": 110,
    "scatterPay": 60,
    "featureResults": [
      {
        "featureType": "freespins",
        "totalCount": 10,
        "closed": false
      }
    ]
  }
}

This example is realistic in terms of structure, but it is intentionally constructed from the actual values present in the code.


17. Code-to-Game Mapping

Game conceptCode location
Game registrationgames/frostedmarketbonanza/project.json
Platform entrygames/frostedmarketbonanza/src/plugin.ts
Spin orchestrationgames/frostedmarketbonanza/src/engine.ts
Core round logicgames/frostedmarketbonanza/src/logic.ts
Request/result contractsgames/frostedmarketbonanza/src/interfaces.ts
Cluster detectiongroupSymbolPositions(...) called in logic.spin()
Scatter triggerlastScCount >= fsTriggerCount in logic.spin()
Free-spin triggernextFeature = 'freespins' in logic.spin()
Nudge featureNudgeFeature weights and nudge block in logic.spin()
Symbol conversiongames/frostedmarketbonanza/src/symbol-conversion.ts
Multiplier bombsfree-spin BN handling in logic.spin()
Win capapplyWinCap() call in logic.spin() and runFeature()
Response generationplugin.spin() and plugin.feature()
Simulation analysistools/game-tools/…/frosted-market-bonanza.analyzer.ts

18. Important Functions

FileFunction / classPurposeCalled byWhy it matters
games/frostedmarketbonanza/src/plugin.tsFrostedMarketBonanzaPlugin.spin()Main platform entry for a base spinplatform loaderBuilds request and returns response
games/frostedmarketbonanza/src/plugin.tsFrostedMarketBonanzaPlugin.feature()Continues the feature roundplatform loaderHandles free spins
games/frostedmarketbonanza/src/engine.tsFrostedMarketBonanzaEngine.executeSpin()Build board and orchestrate spinplugin spinChooses mode and reel set
games/frostedmarketbonanza/src/engine.tsFrostedMarketBonanzaEngine.executeFeature()Starts feature executionplugin featureCalls the feature logic
games/frostedmarketbonanza/src/logic.tsFrostedMarketBonanzaLogic.spin()Core game evaluatorengine and free-spin runnerDetermines wins, feature triggers
games/frostedmarketbonanza/src/logic.tsFrostedMarketBonanzaLogic.runFeature()Updates feature totals and continue stateengine executeFeatureControls free-spin progression
games/frostedmarketbonanza/src/logic.tsFrostedMarketBonanzaLogic.spinFreeGame()Generates a free-spin boardrunFeatureEnsures free-spin board is created
games/frostedmarketbonanza/src/symbol-conversion.tsapplySymbolConversion()Converts low symbols to high symbolsengine executeSpinPassive reuse feature
games/frostedmarketbonanza/src/maths/frosted-market-bonanza-R3.jsonJSON configContains all reel, pay, and feature dataplugin onLoadDefines the actual game rules

19. Configuration

All the actual game configuration is in games/frostedmarketbonanza/src/maths/frosted-market-bonanza-R3.json.

Symbol configuration

  • symbolsMap defines raw names to internal names
  • internal symbols include H1, H2, H3, H4, L1, L2, L3, L4, L5, SC, BN, STACK1, STACK2

Pay table

The payTable contains cluster payout values by symbol and cluster size.

Examples:

  • H1: [0, 0, ..., 200, 200, 500, 500, 1000]
  • H2: [0, 0, ..., 50, 50, 200, 200, 500]
  • SC: [0, 0, 0, 60, 100, 2000, ...]

Reel configuration

Each mode (BG, ANTE, FG, BB, BB_Trigger) has its own ReelSet_1 and sometimes ReelSet_2 values. The board size is fixed as 6 columns × 5 rows.

Weights

Weighted arrays determine:

  • stack symbol replacement
  • reel-set selection
  • free-spin bomb values
  • nudge trigger decisions
  • symbol conversion trigger

Bet configuration

games/frostedmarketbonanza/src/maths/frosted-market-bonanza-R3.json defines:

  • baseBet = 20
  • bbBaseBet = 20
  • anteBaseBet = 25

Feature configuration

  • features.freeSpinsTrigger.minScatters = 4
  • features.freeSpinsTrigger.initialCount = 10
  • features.freeSpinsRetrigger.minScatters = 3
  • features.freeSpinsRetrigger.additionalSpins = 5

Max win configuration

  • maxWinMultiplier = 10000
  • maxWinBbMultiplier = 10000

Where config is loaded

The config is loaded in games/frostedmarketbonanza/src/plugin.ts inside onLoad().


20. Error Handling and Validation

Invalid request

The code path does not implement a large custom validation layer for malformed requests. The game relies on the platform contract and the GameSpinInput types.

The plugin does do basic checks around math availability:

if (!m) {
  throw new Error(
    `[FrostedMarketBonanza] Math not loaded for mode "${mode}"...`
  );
}

This is in games/frostedmarketbonanza/src/plugin.ts.

Invalid bet

There is no explicit bet-validation function in the game. The code expects betAmount to be numeric and then computes stakeValue = totalBet / baseBet.

Invalid game state

The free-spin feature uses previousSpinResult and expects a valid SpinResult with pendingFeature and featureResults. If those are absent or malformed, the code will behave unpredictably. The current implementation does not contain a dedicated guard against that.

Invalid feature state

The code checks pendingFeature and closes the feature when it reaches zero or when the max cap is reached. This is the main guard in runFeature().

Important exceptions

The main explicit exception is the missing math error thrown in getMath().

Validation location

Validation is light and mostly occurs in:


21. External Dependencies

DependencyWhy it is usedWhich file uses itDoes it affect outcome?
@slot-platform/sdkCore game platform types and helpersgame filesYes, indirectly
@slot-platform/sdk/critical/reel-generatorGenerates board layout and reel viewgames/frostedmarketbonanza/src/engine.ts, games/frostedmarketbonanza/src/logic.tsYes
@slot-platform/sdk/critical/cluster-detectorDetects symbol clustersgames/frostedmarketbonanza/src/logic.tsYes
@slot-platform/sdk/critical/cascade-refillRefills the board after winsgames/frostedmarketbonanza/src/logic.tsYes
@slot-platform/sdk/critical/generic-logicWeighted random selectiongames/frostedmarketbonanza/src/logic.ts, games/frostedmarketbonanza/src/symbol-conversion.tsYes
@slot-platform/sdk/critical/rngRandom number generationgames/frostedmarketbonanza/src/logic.tsYes
@slot-platform/sdk/critical/reel-set-selectorchooses free-spin reel setgames/frostedmarketbonanza/src/logic.tsYes
@slot-platform/sdk/critical/win-capApplies max-win capgames/frostedmarketbonanza/src/logic.tsYes

The platform SDK is not just infrastructure; it is central to the actual game logic and math execution.


22. Testing

There are no dedicated game unit tests in the game folder itself. The code is exercised through simulation and certification tooling, especially in:

What these tools test

The analyzer tracks:

  • cluster wins
  • scatter pay wins
  • free-spin win totals
  • bomb multiplier distribution
  • nudge triggers
  • symbol conversion triggers
  • win distribution and reel-stop frequency

This is important because it confirms which features are actually present in the math and logic flow.

Important test insight

There is a known issue documented in docs/superpowers/handoff/2026-09-21-frosted-market-bonanza-freespin-trigger-bug.md: some converted-grid scatter triggers are being silently dropped because engine.executeSpin() copies only part of the converted result back into the original spin result.

This means the simulator and cert tooling are important because they reveal logic bugs that are not obvious from the code alone.


23. Things a New Developer Should Be Careful About

Here are the highest-risk areas in the current implementation.

  • Changing minClusterSize in games/frostedmarketbonanza/src/logic.ts changes the win threshold and dramatically changes all results.
  • Changing math.payTable values changes cluster payouts and scatter payouts.
  • Changing symbolsMap can break both the raw display mapping and the internal pay calculations.
  • Changing ReelSelectionWeights changes free-spin reel-set selection probabilities.
  • Changing BOMB_SET1_Weights and BOMB_SET2_Weights changes free-spin multiplier distribution.
  • Altering TriggerWeights for nudge or conversion changes feature frequency.
  • Editing pendingFeature handling in runFeature() changes free-spin progression.
  • Changing applyWinCap() parameters or the cap multipliers changes max-win behavior.
  • Reordering or deleting reelModifiers has a direct effect on debugging and feature-state interpretation.

24. Debugging Guide

Use this flow to inspect one round.

1. Put breakpoints here

2. Which function executes first?

The first real game function is FrostedMarketBonanzaPlugin.spin().

3. Where are random numbers generated?

The random choices go through:

  • selectWeightedRandom(...)
  • rng.randomNumber(...)
  • selectReelSet(...)

These are called inside games/frostedmarketbonanza/src/logic.ts.

4. Where are symbols generated?

  • generateReelView() creates the board
  • replaceStackSymbols() resolves stack symbols
  • applySymbolConversion() modifies the board after a blank spin

5. Where are wins calculated?

The cluster pay calculation happens in the cascade loop within logic.spin().

6. Where are features triggered?

  • scatter triggers are checked in logic.spin()
  • nudge feature is checked in the cascade loop
  • conversion is evaluated in engine.executeSpin()
  • free-spin continuation is updated in runFeature()

7. Where is the response created?

  • plugin.spin() wraps the final SpinResult into ISpinOutput<SpinResult>
  • plugin.feature() does the same for feature rounds

8. Useful variables to inspect

  • spinResult.totalWin
  • spinResult.scatterPay
  • spinResult.pendingFeature
  • spinResult.nextFeature
  • spinResult.featureResults
  • spinResult.cascadeData
  • spinResult.reelModifiers
  • lastScCount
  • stakeValue
  • totalBombMultiplier

25. Quick Reference

GAME

  • Type: cluster/cascade slot
  • Reels: 6 columns
  • Rows: 5
  • Win system: cluster-based, not payline-based
  • Wild: Not defined in current code
  • Scatter: SC
  • Free spins: yes
  • Main features: scatter trigger, nudge, symbol conversion, free-spin bomb multipliers

MATH ENTRY

GAME LOGIC ENTRY

REQUEST

RESPONSE

IMPORTANT FILES

IMPORTANT FUNCTIONS

  • FrostedMarketBonanzaPlugin.spin()
  • FrostedMarketBonanzaPlugin.feature()
  • FrostedMarketBonanzaEngine.executeSpin()
  • FrostedMarketBonanzaLogic.spin()
  • FrostedMarketBonanzaLogic.runFeature()
  • applySymbolConversion()

26. Things That Are Not Clear From The Code

This section lists items that cannot be confidently determined from the current implementation.

This list should be treated as a caution list for future debugging, not as a set of missing game rules.


Final Summary

Frosted Market Bonanza is a 6×5 cluster/cascade slot. Its core logic is:

  • build a board
  • find symbol clusters of size 8 or more
  • pay by cluster size from the pay table
  • remove winning symbols and refill the board
  • trigger free spins at 4 scatters in base game
  • continue free spins with bomb multipliers
  • optionally apply nudge or symbol conversion on certain non-winning spins

The most important implementation files are:

The code is the source of truth. If a behavior is debated between documentation and source, the actual implementation in the source files should be treated as authoritative.

Built with LogoFlowershow