每日與每週任務——一個讓你回來的理由
現在每一局結束都會推進一組每日與每週任務,在你完成任意一項的那一刻發放 XP,併為全新的每週排行榜提供積分。

通俗版
在此之前,opolyx 裡唯一的養成只是贏下一局後的一次性獎勵,日復一日沒有什麼可追逐的。任務改變了這一點:一小組每日與每週目標,會在你每次結束對局時向前推進,無論輸贏。
你無需領取,也沒有按鈕要按——對局結束的那一刻,伺服器就會檢查你的任務,為你完成的那些結算,並把 XP 直接加到你的等級上。同時會有六個任務在進行:
- 每日——玩 1 局、玩 3 局、贏 1 局。
- 每週——玩 10 局、贏 3 局、在極速模式贏 3 局。
- 每日任務每天重置;每週任務每週一重置。
| 任務 | 頻率 | 目標 | 獎勵 |
|---|---|---|---|
| 玩一局 | 每日 | 1 | +50 XP |
| 繼續玩 | 每日 | 3 | +150 XP |
| 贏一局 | 每日 | 1 | +250 XP |
| 常規 | 每週 | 10 局 | +400 XP |
| 連勝中 | 每週 | 3 勝 | +600 XP |
| 極速惡魔 | 每週 | 3 場極速勝利 | +500 XP |
結束對局還會贏得每週排行榜積分,所以你玩得越多,爬得越高。排行榜每週重置,讓每個人在週一早晨都有一次衝頂的乾淨機會。
技術細節
一整套留存迴圈的表結構其實早已存在,只是一直閒置、無人讀取——missions / user_missions(頻率、目標、進度、xp_reward)以及 weekly_top(week_start、積分)。遷移 0031 把它接入了已有的結束獎勵路徑,而不是另起爐灶。
在真正結束一局時,daemon 會遍歷每一名真人玩家,並呼叫一個 service-role 的 RPC。它推進本週期內該結束所滿足的每個任務,在首次越過目標時發放 XP,並累加到每週積分之中:
-- grant_play_rewards(p_game, p_user, p_won): security definer, service-role only
-- daily cadence = current_date; weekly = date_trunc('week', now())
-- weekly_top.points += 20 (play) + (won ? 200 : 0) + mission_xp_earned
-- idempotent per (game_id, user_id) via the game_play_grants guard; bots skipped| 事件匹配 | 推進 | 積分 |
|---|---|---|
| {"event":"play"} | 每次結束 | +20 |
| {"event":"win"} | 僅勝利 | +200 |
| {"event":"play","mode":"speed"} | 僅極速對局 | +20 |
冪等性靠一行按(對局,使用者)的守衛記錄來保證,因此重試的提交絕不會重複發放。應用遷移時暴露了一個提權陷阱:Postgres 的預設權限會把新函式的 EXECUTE 授予 anon/authenticated,而 revoke … from public 並不會移除它。一個任何已登入使用者都能呼叫的 SECURITY DEFINER 獎勵函式就是一座 XP 農場——透過 revoke … from public, anon, authenticated 修復,使得只有 {postgres, service_role} 能呼叫它,與 award_game_winner 保持一致。
目前獎勵只有 XP——金幣屬於變現路線,而那需要先有一個消耗出口。遊玩頁面的面板和排行榜都在客戶端讀取當前週期的進度,並把「周」錨定到 Postgres 所用的同一個週一邊界,因此兩者永遠不會不一致。
