Scatter pays (pay-anywhere)
TL;DR
Самый простой способ оценки выигрышей: сколько штук одного символа на всём board? Если ≥ MIN_KIND — платим из range-paytable. Никаких линий, никаких кластеров, никаких связности. Wild считается ко всем paying символам. Типичный минимум 8 штук на 6×5 поле.
Info
Не путать со scatter-trigger — символом, который запускает freegame. В терминологии «scatter-pays» это про payout-механику, а не про триггер. Один и тот же символ может быть и тем и другим (но обычно scatter-trigger — это отдельный спецсимвол S без payout, см. mechanics MOC).
Как работает
Конфиг
То же pay_group с диапазонами, что у cluster pays:
pay_group = {
((8,8), "H1"): 5,
((9,10), "H1"): 10,
((11,13), "H1"): 50,
((14,30), "H1"): 500,
...
}
paytable = convert_range_table(pay_group)Алгоритм evaluate
для каждого base_sym из paying_symbols:
count = sum(1 for cell in board.flat if cell == base_sym or cell in wildSyms)
если count < MIN_KIND: continue
if (count, base_sym) в paytable:
win = paytable[(count, base_sym)] × multiplier
wins.append({symbol, kind: count, win, positions: all_positions(base_sym, wildSyms)})
O(num_reels × num_rows × num_paying_symbols). Тривиально.
Wild
Wild контрибьютит ко всем paying-символам. Если на 6×5 поле 6 H1 и 3 W → kind для H1 = 9.
В отличие от cluster — нет «не стартует» правила; wild просто учитывается во всех счётчиках.
Мат-эффект
- Hit frequency низкая для каждого отдельного символа, но высокая суммарно — обычно несколько символов «попадают» одновременно.
- Volatility высокая — большой спред между min payout (8 штук) и max (full board).
- Часто комбинируется с tumbling и global-multiplier для очень volatile профиля.
- RTP заметно весит во freegame с global mult.
Варианты и подвиды
- Базовый scatter-pays — без модификаторов.
- Scatter + tumble (стандарт) — победившие символы исчезают, новые падают.
- Scatter + global mult — multiplier инкрементируется на каждый tumble, применяется к концу цепочки.
- Scatter + position-multiplier — multiplier-symbols на board добавляются к global mult в финале раунда.
Реализационные заметки
Бэк (TS)
function evaluateScatterPays(
board: SymbolName[][],
paytable: Map<string, number>,
wildSyms: SymbolName[],
payingSyms: SymbolName[],
minKind: number,
): WinData {
const wins: WinDetail[] = [];
for (const sym of payingSyms) {
const positions: Position[] = [];
for (let r = 0; r < board.length; r++) {
for (let c = 0; c < board[0].length; c++) {
const s = board[r][c];
if (s === sym || wildSyms.includes(s)) positions.push({reel: r, row: c});
}
}
const kind = positions.length;
if (kind < minKind) continue;
const key = `${kind}:${sym}`;
const basePay = paytable.get(key) ?? 0;
if (basePay > 0) {
wins.push({symbol: sym, kind, win: basePay, positions, meta: {}});
}
}
return {totalWin: sum(wins, w => w.win), wins};
}Edge cases
- Wild-only board — wild считается ко всем paying симсам. Получаем win для каждого, что обычно нежелательно. Решение: запретить full-wild-board через reelstrip-конструкцию (на проде он не выпадает) или явно проверить и обнулить.
- Несколько paying-символов одновременно платят — нормально, складываем
totalWin. - Big-cluster свыше последнего range — берём максимальный диапазон через
convert_range_table.
Фронт
winInfo.positions — все клетки символа на board. Фронт рисует pulse-highlight всех клеток. С tumble — после tumbleBoard event-а позиции исчезают.
meta.overlay для badge-позиции — обычно центр масс положений символа.
Compliance / cert
- Help раскрывает: «Symbols pay anywhere on the reels. Pay calculations based on count of symbols on board, not position.»
- Range-paytable: лучше рисовать таблицей
(8): 5×, (9-10): 10×, ...— игроку нужно понимать пороги. - Wild contribution к count тоже раскрывается.
Примеры реализаций
- NetEnt Bonanza (6 reels, scatter+tumble + Megaways).
- NetEnt Money Train series.
- Pragmatic Play Gates of Olympus (6×5 scatter+tumble + multipliers).
- Stake math-sdk sample:
games/0_0_scatter/.