NON-PRODUCTION

Sugar Rush — tài liệu ghép client

Slot cluster / tumble 7×7. Sticky multiplier trong free spins. Có buy FS và buy Super FS. Trang này chỉ được serve khi ENVIRONMENT != production.

1. Tổng quan

MụcGiá trị
Grid7 cột × 7 hàng · reels[col][row], row 0 = trên cùng
PayCluster ≥5 (4-neighbor: trên/dưới/trái/phải) hoặc pay-anywhere ≥12 nếu PayAnywhereMode
TumbleÔ thắng biến mất, symbol còn lại rơi xuống, ô trống fill từ trên
StickyTrong FS: mỗi lần cluster thắng trên ô, count tăng. Display = 2^(count-1)
FS≥3 scatter: 3→10, 4→12, 5→15, 6→20, ≥7→30 lượt
Buy FSGiá = buy_free_spins_price × bet
Buy SuperGiá = buy_super_free_spins_price × bet. Seed sticky ×2 trên mọi ô
free_spin_type0 normal · 1 free · 2 super
Base path/api/v1
Session gameplay nằm in-memory. Client bắt buộc gọi GET /api/v1/gameplay trước khi spin. Reconnect thì đọc lại state từ /gameplay (kể cả sticky multipliers).

2. Luồng ghép

  1. Mở game → GET /api/v1/gameplay. Render board, bet, paytable, money, sticky nếu đang FS.
  2. User chọn bet chỉ khi is_free_spin = false.
  3. Spin thường → POST /api/v1/spins body {"bet": ...}.
  4. Play tuần tự từng phần tử win_result[] (tumble). Highlight cluster theo positions.
  5. Nếu is_bonus_free_spin → popup +N FS, chuyển UI free-spin. Hiện sticky theo multipliers.
  6. Khi is_free_spin: không trừ bet, tiếp tục POST /spins tới is_finish_free_spin.
  7. Buy → POST /buy-freespins hoặc POST /buy-super-freespins (cấm khi đang FS).
  8. Luôn lấy số dư từ user_money của response vừa nhận.

3. Auth & envelope

Header

Authorization: Bearer <access_token>
Content-Type: application/json

Mọi API dưới /api/v1 đều cần JWT. Trang docs không cần token.

Envelope

HTTP 200 + code = 0 là thành công. Payload nằm trong msg.

{
  "code": 0,
  "msg": { ... }
}
codeÝ nghĩa
0OK
-1Unknown / thiếu JWT / token invalid (tùy HTTP status)
-2Invalid input (body JSON sai)
69Wrong game state — chưa /gameplay, đang FS mà đổi bet
1000Popup error (message i18n, buy không hợp lệ)

4. Grid & symbol

Mọi board (init_reels, win_result[].reels, cheat reels) đều là mảng cột:

reels[col][row]          // col 0..6 trái → phải; row 0..6 trên → dưới
multipliers[col][row]    // sticky count; display = 2^(count-1) khi count ≥ 1
6
1
2
3
4
5
7
0
0
1
2
3
4
5
0
0
0
6
1
2
3
4
5
6
1
2
3
4
5
6
1
2
3
4
5
6
1
2
3
4
5
6
1
2
3
4
5
6
1

Hàng đầu = row 0. Ô vàng viền = cluster Lollipop (0) thắng. Ô scatter (7) góc trên phải.

idSymbolPay?
0Lollipop
1Heart
2JellyBean
3Star
4GreenBear
5BlueBear
6OrangeBear
7ScatterKhông pay — trigger FS

Luôn dùng pay_table từ /gameplay. Line win = round(bet × multiplier × bonus_multiplier). bonus_multiplier lấy từ sticky trên các ô của cluster.

5. GET /api/v1/gameplay

Gọi 1 lần khi vào game. Thiếu bước này thì POST /spins trả code 69.

GET /api/v1/gameplay
FieldTypeClient dùng để
init_reelsint[7][7]Board preview idle
user_moneyint64Chip hiện tại
betint64Bet đang chọn trên server
betsint64[]Các mức bet hợp lệ
show_betsint64[]Giá trị hiển thị UI (cùng index)
pay_tablefloat[][]Bảng trả thưởng
is_free_spinboolĐang FS → restore UI, disable đổi bet / buy
free_spinsintSố FS còn lại
max_free_spinsintMốc max thanh FS
free_spin_potint64Tổng win đang cộng dồn (chưa credit)
free_spin_typeint0 / 1 / 2
multipliersint[7][7]Sticky count từng ô — restore overlay
buy_free_spins_priceint64Hệ số giá buy FS
buy_super_free_spins_priceint64Hệ số giá buy Super FS
{
  "code": 0,
  "msg": {
    "init_reels": [[6,1,2,3,4,5,6],[1,0,0,2,3,4,5],[2,0,0,0,1,2,3],[3,4,5,6,1,2,3],[4,5,6,1,2,3,4],[5,6,1,2,3,4,5],[7,1,2,3,4,5,6]],
    "user_money": 500000,
    "bet": 1000,
    "bets": [200, 1000, 2000, 10000],
    "show_bets": [200, 1000, 2000, 10000],
    "pay_table": [[50,20,10],[25,10,5],[15,8,4],[10,5,2],[8,3,1.5],[5,2,1],[3,1.5,0.8]],
    "is_free_spin": false,
    "free_spins": 0,
    "max_free_spins": 0,
    "free_spin_pot": 0,
    "free_spin_type": 0,
    "multipliers": [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]],
    "buy_free_spins_price": 100,
    "buy_super_free_spins_price": 200
  }
}

6. POST /api/v1/spins

POST /api/v1/spins
{ "bet": 1000 }

SpinResult

FieldTypeÝ nghĩa
betint64Bet server đang dùng
priceint640 spin thường; giá đã trừ nếu từ buy
user_moneyint64Chip sau giao dịch response này
win_amountint64Base: win đã credit. FS giữa chừng: win spin (chưa vào chip). FS xong: cả pot
is_free_spinboolSpin vừa rồi nằm trong FS
free_spinsintSố FS còn lại — source of truth
free_spin_potint64Pot sau spin. = 0 khi FS kết thúc
is_finish_free_spinboolSpin FS cuối. Credit pot vào user_money
is_bonus_free_spinboolVừa award thêm FS
number_of_bonus_free_spinsint+N cho popup
free_spin_typeint0 / 1 / 2
max_free_spinsintMax thanh progress
win_resultWinResult[]Chuỗi tumble, play tuần tự

WinResult / WinLine

FieldÝ nghĩa
reelsBoard trước khi xóa ô thắng bước này
linesCụm thắng. Rỗng = tumble dừng
positionspositions[col] = [row, ...] mọi ô thắng
multipliersSticky count cùng index với reels
win_amountTổng line win bước này
total_win_amountCộng dồn từ đầu spin tới bước này
lines[].symbol0–6
lines[].positionsÔ thuộc cluster
lines[].line_sizeSố ô cùng symbol
lines[].multiplierHệ số paytable
lines[].bonus_multiplierSticky nhân thêm
lines[].win_amountChip của cluster
{
  "code": 0,
  "msg": {
    "bet": 1000, "price": 0, "user_money": 509000, "win_amount": 10000,
    "is_free_spin": false, "free_spins": 10, "free_spin_pot": 0,
    "is_finish_free_spin": false, "is_bonus_free_spin": true,
    "number_of_bonus_free_spins": 10, "free_spin_type": 1, "max_free_spins": 10,
    "win_result": [{
      "lines": [{ "symbol": 0, "positions": [[1,2],[1,2],[1,2],[],[],[],[]], "win_amount": 10000, "line_size": 5, "multiplier": 10, "bonus_multiplier": 1 }],
      "reels": [[6,1,2,3,4,5,6],[1,0,0,2,3,4,5],[2,0,0,0,1,2,3],[3,4,5,6,1,2,3],[4,5,6,1,2,3,4],[5,6,1,2,3,4,5],[7,7,7,3,4,5,6]],
      "win_amount": 10000, "total_win_amount": 10000,
      "multipliers": [[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]],
      "positions": [[1,2],[1,2],[1,2],[],[],[],[]]
    }]
  }
}

7. POST /buy-freespins & /buy-super-freespins

POST /api/v1/buy-freespins
{ "bet": 1000 }

POST /api/v1/buy-super-freespins
{ "bet": 1000 }
Nút Buy chỉ enable khi !is_free_spin và đủ chip theo giá × bet.
{
  "code": 0,
  "msg": {
    "bet": 1000, "price": 200000, "user_money": 300000, "win_amount": 0,
    "is_free_spin": false, "free_spins": 10, "free_spin_pot": 0,
    "is_finish_free_spin": false, "is_bonus_free_spin": true,
    "number_of_bonus_free_spins": 10, "free_spin_type": 2, "max_free_spins": 10,
    "win_result": []
  }
}

8. Tumble / sticky / animation

  1. Với mỗi win_result[i]: vẽ reels + overlay sticky từ multipliers.
  2. Nếu lines.length > 0: highlight cluster, cộng win_amount vào counter.
  3. Xóa ô thắng. Gravity theo cột (row lớn = dưới). Fill từ trên (row 0).
  4. Board mới = win_result[i+1].reels. Đừng tự random.
  5. Phần tử cuối thường lines = []: hết tumble.
  6. Sticky display = 2^(count-1). Count 1 → ×1, count 2 → ×2, count 3 → ×4, count 4 → ×8…
Scatter không bị xóa khi paying symbol thắng. Chúng ở lại và rơi theo gravity.

9. Free spins

ScatterAward
3+10 FS
4+12 FS
5+15 FS
6+20 FS
≥7+30 FS

10. Cheat (chỉ non-prod / cheater)

{
  "bet": 1000,
  "reels": [
    [0,0,1,2,3,4,5],[0,0,0,1,2,3,4],[0,0,0,6,1,2,3],
    [4,5,6,1,2,3,4],[5,6,1,2,3,4,5],[6,1,2,3,4,5,6],[7,7,7,1,2,3,4]
  ]
}

Đủ 7 cột, mỗi cột 7 hàng. Production: field bị bỏ qua, luôn random.

11. Error & tiền

Tình huốngHành vi client
HTTP 401Token hết hạn — relogin
code 69Gọi lại GET /gameplay, sync state
code 1000Hiện popup msg (string i18n)
code -1 khi spin/buyHết tiền hoặc lỗi nội bộ — refresh qua /gameplay
Spin khi user đang room PvPHTTP 400 body "blocked"
EventChip
Base spin−bet ngay; +win_amount nếu thắng
Buy FS / Super−price ngay
FS giữa chừngKhông đổi. Chỉ tăng free_spin_pot
FS kết thúc+pot vào user_money

12. Checklist client