Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/StakeEngine/math-sdk/llms.txt

Use this file to discover all available pages before exploring further.

0_0_scatter demonstrates the scatter pay win type on a large tumbling board. The freegame introduces a persistent global multiplier that grows with every tumble, and board-resident multiplier symbols (M) are applied as a final multiplier after tumbling ends.

Game overview

PropertyValue
Reels6
Rows5 (all reels)
Win typeScatter (pay-anywhere)
Win cap5000×
Target RTP97%
SymbolsH1–H4 (high), L1–L4 (low), Wild (W), Scatter (S), Multiplier (M)

How to run

make run GAME=0_0_scatter
Or directly:
python3 games/0_0_scatter/run.py

Mechanics

Basegame

  • Any group of 8 or more adjacent like symbols on the 6×5 board pays, regardless of reel or row boundaries.
  • Winning symbols are removed; symbols above fall down to fill gaps (tumble). Tumbling continues until no winning groups remain.
  • Minimum 3 Scatters trigger the freegame. Freespins awarded: 2 × (number of Scatters on board).
  • Freespin awards by scatter count: 3S → 8 spins, 4S → 12, 5S → 15, 6S → 17, 7S → 19, 8S → 21, 9S → 23, 10S → 24.
Because new Scatters can tumble onto the board during basegame evaluation, there is no fixed upper limit on how many freespins can be awarded. The total is always 2 × (current Scatters on board). This overrides the standard updateTotalFreeSpinAmount in game_executables.py.

Freegame

  • Global multiplier starts at 1 at the beginning of each freespin (it does not carry over between individual spins).
  • After each tumble: the global multiplier increments by +1 (update_global_mult()).
  • The global multiplier is applied to every tumble win as symbols are removed from the board.
  • After all tumbles complete: remaining Multiplier (M) symbols on the board are summed and their total is applied as an additional multiplier to the cumulative tumble win.
  • Retrigger: 2+ Scatters during freegame award additional spins (same 2× formula).
Multiplier symbols (M) on the board do not increment the global multiplier — they are evaluated separately as a final board multiplier after tumbling is complete. Only tumbles (symbol removals) increment the global multiplier.

Paytable

Pays are grouped by cluster-size ranges (8,8), (9,10), (11,13), (14,36):
t1, t2, t3, t4 = (8, 8), (9, 10), (11, 13), (14, 36)
pay_group = {
    (t1, "H1"): 3.0,  (t2, "H1"): 7.5,  (t3, "H1"): 15.0, (t4, "H1"): 60.0,
    (t1, "H2"): 2.0,  (t2, "H2"): 5.0,  (t3, "H2"): 10.0, (t4, "H2"): 40.0,
    (t1, "H3"): 1.3,  (t2, "H3"): 3.2,  (t3, "H3"): 7.0,  (t4, "H3"): 30.0,
    (t1, "H4"): 1.0,  (t2, "H4"): 2.5,  (t3, "H4"): 6.0,  (t4, "H4"): 20.0,
    (t1, "L1"): 0.6,  (t2, "L1"): 1.5,  (t3, "L1"): 4.0,  (t4, "L1"): 10.0,
    (t1, "L2"): 0.4,  (t2, "L2"): 1.2,  (t3, "L2"): 3.5,  (t4, "L2"): 8.0,
    (t1, "L3"): 0.2,  (t2, "L3"): 0.8,  (t3, "L3"): 2.5,  (t4, "L3"): 5.0,
    (t1, "L4"): 0.1,  (t2, "L4"): 0.5,  (t3, "L4"): 1.5,  (t4, "L4"): 4.0,
}
self.paytable = self.convert_range_table(pay_group)

Freespin count override

The standard updateTotalFreeSpinAmount is overridden in game_executables.py to implement the 2 × scatters formula:
def update_freespin_amount(self, scatter_key: str = "scatter"):
    """Update current and total freespin number and emit event."""
    self.tot_fs = self.count_special_symbols(scatter_key) * 2
    if self.gametype == self.config.basegame_type:
        basegame_trigger, freegame_trigger = True, False
    else:
        basegame_trigger, freegame_trigger = False, True
    fs_trigger_event(self, basegame_trigger=basegame_trigger, freegame_trigger=freegame_trigger)

Board multiplier evaluation

After all tumbles complete, set_end_tumble_event() in game_executables.py sums any remaining Multiplier symbols and applies them to the spin win:
def set_end_tumble_event(self):
    """After all tumbling events have finished, multiply tumble-win by sum of mult symbols."""
    if self.gametype == self.config.freegame_type:  # Only multipliers in freegame
        board_mult, mult_info = self.get_board_multipliers()
        base_tumble_win = copy(self.win_manager.spin_win)
        self.win_manager.set_spin_win(base_tumble_win * board_mult)
        if self.win_manager.spin_win > 0 and len(mult_info) > 0:
            send_mult_info_event(self, board_mult, mult_info, base_tumble_win,
                                 self.win_manager.spin_win)
            update_tumble_win_event(self)

    if self.win_manager.spin_win > 0:
        set_win_event(self)
    set_total_event(self)
get_board_multipliers() in game_calculations.py sums all M symbol values still present on the board:
def get_board_multipliers(self, multiplier_key: str = "multiplier") -> list:
    board_mult = 0
    mult_info = []
    for reel, _ in enumerate(self.board):
        for row, _ in enumerate(self.board[reel]):
            if self.board[reel][row].check_attribute(multiplier_key):
                board_mult += self.board[reel][row].get_attribute(multiplier_key)
                mult_info.append(
                    {"reel": reel, "row": row,
                     "value": self.board[reel][row].get_attribute(multiplier_key)}
                )
    return max(1, board_mult), mult_info

Game flow (gamestate.py)

def run_spin(self, sim: int, simulation_seed=None):
    self.reset_seed(sim)
    self.repeat = True
    while self.repeat:
        self.reset_book()
        self.draw_board()

        self.get_scatterpays_update_wins()
        self.emit_tumble_win_events()

        while self.win_data["totalWin"] > 0 and not (self.wincap_triggered):
            self.tumble_game_board()
            self.get_scatterpays_update_wins()
            self.emit_tumble_win_events()

        self.set_end_tumble_event()
        self.win_manager.update_gametype_wins(self.gametype)

        if self.check_fs_condition() and self.check_freespin_entry():
            self.run_freespin_from_base()

        self.evaluate_finalwin()
        self.check_repeat()

    self.imprint_wins()

def run_freespin(self):
    self.reset_fs_spin()
    while self.fs < self.tot_fs:
        # Global multiplier resets to 1 at the start of each freespin
        self.update_freespin()
        self.draw_board()

        self.get_scatterpays_update_wins()
        self.emit_tumble_win_events()

        while self.win_data["totalWin"] > 0 and not (self.wincap_triggered):
            self.tumble_game_board()
            self.update_global_mult()  # Increment multiplier with every tumble

            self.get_scatterpays_update_wins()
            self.emit_tumble_win_events()

        self.set_end_tumble_event()
        self.win_manager.update_gametype_wins(self.gametype)

        if self.check_fs_condition():
            self.update_fs_retrigger_amt()

    self.end_freespin()
Note that update_global_mult() is called after tumble_game_board() and before get_scatterpays_update_wins() — the incremented multiplier applies to the wins evaluated on the newly tumbled board.

Game-specific events

Event typeWhen emittedContents
winInfoAfter every scatter-pay evaluation (each tumble step)Winning combinations, positions, cluster sizes, multipliers applied
tumbleBannerAfter each tumble — from emit_tumble_win_events()Cumulative tumble win with global multiplier applied
setWinAfter all tumbles complete for a spinTotal win for the full spin (reveal → next reveal)
setTotalWinAfter setWinCumulative round win. In basegame equals setWin; in freegame increments across spins.

Comparison with cluster game

FeatureCluster (0_0_cluster)Scatter (0_0_scatter)
Board size7×76×5
Min cluster size58
Grid position multipliersYes (freegame)No
Board multiplier symbolsNoYes (M symbol, freegame only)
Global multiplier resetsEach freespinEach freespin
Global multiplier increments+1 per freespin+1 per tumble (within a spin)
Freespin trigger4+ Scatters3+ Scatters
Freespins awardedFixed count table2 × scatter count
The scatter game is the most complex sample game. Read game_executables.py alongside gamestate.py — most of the freegame multiplier logic lives in the executables layer rather than gamestate.py itself.

Build docs developers (and LLMs) love