This is the difficulty & seed-selection system that actually runs in the live game today. It is the OLD system — the one SuperPlay's own code marks as obsolete — but it is what serves every board you play. The newer per-seed win-rate engine is built and shipped but gated off (see WR Engine / Layouts). Everything here is on one page: the tiers, the weighting, the draw, pity, and the live proof. Це система складності й вибору seed-ів, яка реально працює в живій грі сьогодні. Це СТАРА система — та, що позначена в коді SuperPlay як застаріла — але саме вона видає кожну дошку, яку ти граєш. Новіший рушій win-rate на seed зібрано й привезено, але закрито воротами (див. WR-рушій / Layouts). Усе тут на одній сторінці: тіри, ваги, вибірка, pity і живий доказ.
For every level the game picks one of 5 "cost tiers" by a weighted dice-roll, then hands you a pre-baked board (seed) from that tier's bucket. The weights are set per-level by a difficulty index; easy levels weight the cheap/easy tiers, hard levels weight the expensive ones. The tier is not a price you pay — it's a difficulty band whose name happens to map to how generous the board is. Для кожного рівня гра обирає один із 5 «cost-тірів» зваженим кидком, потім видає тобі попередньо запечену дошку (seed) з бакета цього тіру. Ваги задані на рівень індексом складності; легкі рівні важать дешеві/легкі тіри, важкі — дорогі. Тір — це не ціна, яку ти платиш, це смуга складності, чия назва відповідає тому, наскільки щедра дошка.
FACT (dump). The LevelCost enum defines exactly five tiers, in this order (dump.cs:1211698, build 1.53.3):
ФАКТ (дамп). Enum LevelCost визначає рівно п'ять тірів, у цьому порядку (dump.cs:1211698, білд 1.53.3):
| # | LevelCost | Meaning (inferred)Значення (інференція) |
|---|---|---|
| 0 | SuperFree | easiest — most generous boardнайлегша — найщедріша дошка |
| 1 | Free | easyлегка |
| 2 | Cheap | mediumсередня |
| 3 | Expensive | hardважка |
| 4 | SuperExpensive | hardest — tightest boardнайважча — найтісніша дошка |
INFERENCE: the "Free/Expensive" naming is SuperPlay's, and the easiest→hardest direction is inferred from the weighting curve below (easy levels lean on SuperFree, hard levels on Expensive) and from the live capture. The enum itself only fixes names + integer order. ІНФЕРЕНЦІЯ: назви «Free/Expensive» — від SuperPlay, а напрям легше→важче виведено з кривої ваг нижче (легкі рівні тяжіють до SuperFree, важкі — до Expensive) і з живого захвату. Сам enum фіксує лише назви + порядок цілих.
FACT (dump + live config). Each level points at a difficulty index. That index is a row of five integer weights — one per tier. The game does a weighted random pick over the five tiers using those weights. The struct is LevelDifficultyIndexData = {superFreeProbability, freeCostProbability, cheapCostProbability, expensiveCostProbability, superExpensiveProbability} (dump.cs:1213102). The live config dcx-513 ships 39 such rows. Real rows below — weights are relative (a tier's share = its weight ÷ row total):
ФАКТ (дамп + живий конфіг). Кожен рівень вказує на індекс складності. Цей індекс — рядок із п'яти цілих ваг, по одній на тір. Гра робить зважений випадковий вибір по п'яти тірах за цими вагами. Структура LevelDifficultyIndexData = {superFreeProbability, freeCostProbability, cheapCostProbability, expensiveCostProbability, superExpensiveProbability} (dump.cs:1213102). Живий конфіг dcx-513 привозить 39 таких рядків. Реальні рядки нижче — ваги відносні (частка тіру = вага ÷ сума рядка):
| Index | SuperFree | Free | Cheap | Expensive | SuperExp | DominantДомінує |
|---|---|---|---|---|---|---|
| 1 | 480 | 1000 | 40 | 0 | 0 | Free (65%) |
| 2 | 28 | 323 | 140 | 15 | 0 | Free (63%) |
| 5 | 8 | 193 | 245 | 42 | 0 | Cheap (50%) |
| 9 | 0 | 7 | 440 | 120 | 0 | Cheap (77%) |
| 27 | 0 | 3 | 480 | 200 | 0 | Cheap (70%) |
| 127 | 0 | 1 | 230 | 400 | 0 | Expensive (63%) |
The curve (FACT, observed across all 39 rows): as the difficulty index rises, weight drains out of SuperFree (gone entirely past the early indices) and shifts Free → Cheap → Expensive. So a low index = easy board lottery, a high index = hard board lottery. SuperExpensive weight is 0 in every live row — that hardest tier is defined but unused in the current config.
Крива (ФАКТ, по всіх 39 рядках): зі зростанням індексу складності вага витікає з SuperFree (повністю зникає після ранніх індексів) і зсувається Free → Cheap → Expensive. Тобто низький індекс = легка лотерея дошки, високий = важка. Вага SuperExpensive = 0 у кожному живому рядку — цей найважчий тір визначено, але не використано в поточному конфізі.
The entry point is GetSeedForCurrentLevel(context, shouldApplyPityLogic). The chain (steps 1, 2, 5 are FACT from dump signatures + the live capture; the internal arithmetic of 3–4 is INFERENCE — those method bodies are not in the dump, only their addresses):
Точка входу — GetSeedForCurrentLevel(context, shouldApplyPityLogic). Ланцюг (кроки 1, 2, 5 — ФАКТ із сигнатур дампа + живого захвату; внутрішня арифметика 3–4 — ІНФЕРЕНЦІЯ, тіл цих методів немає в дампі, лише адреси):
1. Pity check ShouldApplyPityLogic(bakeData, attempts, costData, lastTime, …)
-> (applyPity?, reason) reason ∈ {None, AttemptCount, TimeFromLastAttempt, MultiplierTutorial}
2. Pick a tier GetCostBucket(applyPity, costProbabilities, filterEmptyBuckets, bakedSeeds[5][])
-> byte 0..4 (weighted random over the 5 tiers, per §2 weights)
3. Index bank bakedSeeds[tier] -> the seed array for that tier
4. No-repeat GetFilteredNoRepeatSeed(bucket) -> a seed not in this player's played-seed cache
5. Serve+cache return seed; CachePlayedSeed(seed) (so you don't replay the same board)
FACT: GetCostBucket's loss-weighting helper operates over (LevelCost, float) pairs — i.e. literally the 5 cost tiers with float weights (dump.cs:44029). INFERENCE: the exact "filter empty buckets" and pity-shift behaviour inside the body is reconstructed from the signature, not read from code.
ФАКТ: допоміжник зважування в GetCostBucket працює над парами (LevelCost, float) — тобто буквально 5 cost-тірів із float-вагами (dump.cs:44029). ІНФЕРЕНЦІЯ: точна поведінка «фільтрувати порожні бакети» й pity-зсуву всередині тіла відновлена із сигнатури, а не прочитана з коду.
FACT. Every level's LevelBakeData.seeds is a 5-element array of seed lists — sub-array [0]=SuperFree … [4]=SuperExpensive. The tier byte from §3 indexes straight into it. (The same struct also carries newSeeds and Genie variants — those feed the dormant new engine and are excluded from live play.) The norm is 5 sub-arrays per level (~10,181 of 10,238 levels); ~57 levels carry 0 or 3 instead, so "always 5" is the rule, not a universal.
ФАКТ. Поле LevelBakeData.seeds кожного рівня — це масив із 5 списків seed-ів: під-масив [0]=SuperFree … [4]=SuperExpensive. Байт тіру з §3 індексує прямо в нього. (Та сама структура несе ще newSeeds і Genie-варіанти — вони живлять сплячий новий рушій і виключені з живої гри.) Норма — 5 під-масивів на рівень (~10 181 із 10 238); ~57 рівнів мають 0 або 3, тож «завжди 5» — правило, а не універсал.
FACT (live config). For 165 levels the server config dcx-513 overrides the APK bake with its own per-tier banks (SuperFreeSeeds … SuperExpensiveSeeds) — 5,155 live seeds in total. All 165 carry SuperFree/Free/Cheap/Expensive; only 67 carry a SuperExpensive list. Every other level falls back to the APK Default bake. So the live difficulty for those 165 levels is whatever the server most recently pushed — not what shipped in the APK.
ФАКТ (живий конфіг). Для 165 рівнів серверний конфіг dcx-513 перекриває APK-бейк власними банками по тірах (SuperFreeSeeds … SuperExpensiveSeeds) — усього 5 155 живих seed-ів. Усі 165 мають SuperFree/Free/Cheap/Expensive; лише 67 мають список SuperExpensive. Решта рівнів падає назад на APK-бейк Default. Тож жива складність для цих 165 рівнів — це те, що сервер останнім запушив, а не те, що приїхало в APK.
FACT (dump). ShouldApplyPityLogic(...) returns a reason from LevelPityReason = {None=0, AttemptCount=1, TimeFromLastAttempt=2, MultiplierTutorial=3} (dump.cs:1211714). When pity fires, the tier pick (§3 step 2) is biased toward easier tiers. A per-level field pityTryCount exists. INFERENCE / MISSING: the exact attempt count that triggers AttemptCount pity, and the time window for TimeFromLastAttempt, are not in the dump (method bodies absent) and were never seen firing live. A capture of a real losing streak would pin them.
ФАКТ (дамп). ShouldApplyPityLogic(...) повертає причину з LevelPityReason = {None=0, AttemptCount=1, TimeFromLastAttempt=2, MultiplierTutorial=3} (dump.cs:1211714). Коли pity спрацьовує, вибір тіру (§3 крок 2) зміщується до легших тірів. Поле на рівень pityTryCount існує. ІНФЕРЕНЦІЯ / БРАКУЄ: точна кількість спроб, що вмикає pity AttemptCount, і часове вікно для TimeFromLastAttempt — не в дампі (тіл методів немає) і не спостерігались наживо. Захват реальної серії поразок їх зафіксує.
FACT (capture, 09/06/2026, build 1.53.3). Across a 9-level live session the on-device hook logged the tier picked for every board: ФАКТ (захват, 09/06/2026, білд 1.53.3). За живу сесію з 9 рівнів хук на пристрої залогував обраний тір для кожної дошки:
| Path firedСпрацював шлях | CountК-сть | Tiers seenБачені тіри |
|---|---|---|
GetCostBucket (OLD, live)(СТАРИЙ, живий) | 10 | SuperFree×2, Free×7, Cheap×1 |
GetCostBucketNew (new bucket id)(новий id бакета) | 1 | bucket 9 (once, level 0) |
ComputeBucketData (new WR formula)(нова WR-формула) | 0 | never firedне спрацював |
All 9 level requests logged pityLogic=0 (no losing streak in this session). The 17 difficulty-engine probes all came back empty (wrBucket="") — the new engine is wired but gated. Conclusion (FACT): the live game drives difficulty entirely through the cost-tier path on this page.
Усі 9 запитів рівнів залогували pityLogic=0 (без серії поразок у цій сесії). Усі 17 проб рушія складності повернулись порожніми (wrBucket="") — новий рушій під'єднано, але закрито воротами. Висновок (ФАКТ): жива гра веде складність повністю через cost-тірний шлях із цієї сторінки.
FACT (dump). The method that actually serves your board, GetCostBucket, carries the attribute [Obsolete("To be removed when the new baker is finalised")] (dump.cs:44143). SuperPlay considers this system end-of-life — yet it is the one running in production, because the replacement (the per-seed win-rate engine) is shipped but gated off (Min Level For Session Registration = 20000). When SuperPlay flips that gate, board difficulty moves from "weighted cost-tier lottery" (this page) to "per-seed target win-rate" (the WR Engine). Watching for that switch is the open thread.
ФАКТ (дамп). Метод, що реально видає твою дошку, GetCostBucket, має атрибут [Obsolete("To be removed when the new baker is finalised")] (dump.cs:44143). SuperPlay вважає цю систему такою, що доживає — але саме вона працює в проді, бо заміна (рушій win-rate на seed) привезена, але закрита воротами (Min Level For Session Registration = 20000). Коли SuperPlay відкриє ці ворота, складність дошки перейде від «зваженої cost-тірної лотереї» (ця сторінка) до «цільового win-rate на seed» (WR-рушій). Стежити за цим перемиканням — відкрита задача.
Sources. FACT = read directly from the 1.53.2/1.53.3 IL2CPP dump (dump.cs), the live server config (dcx-513 / dcx_wr_model.json), or the on-device frida capture (frida_1533_logcat.log). INFERENCE = reconstructed from method signatures where bodies are address-only. MISSING = pity thresholds and the per-level→difficulty-index assignment table, both unresolvable without a capture of the relevant runtime read.
Джерела. ФАКТ = прочитано напряму з IL2CPP-дампа 1.52.2/1.53.3 (dump.cs), живого серверного конфігу (dcx-513 / dcx_wr_model.json) або frida-захвату на пристрої (frida_1533_logcat.log). ІНФЕРЕНЦІЯ = відновлено із сигнатур методів, де тіла лише за адресами. БРАКУЄ = пороги pity і таблиця призначення рівень→індекс-складності, обидві нерозв'язні без захвату відповідного рантайм-читання.