#mydoujin.online《我的同人》拆包筆記
拆包日期:2026-09-14(同日以登入後的 HAR 與實機請求校正) 目標站台:https://mydoujin.online(副標「回到最粗的感動。」) 後端:https://mydoujin-backend.onrender.com(Express,跨網域,Render 代管) 前端 bundle:/assets/index-CQ9wDrWG.js(單檔 640 KB,沒有分 chunk)+ /assets/index-CREjinaa.css(444 bytes)。 2026-09-14 晚間前端改版成 /assets/index-2J2Lv2aK.js(CSS 沒變):事件選項文案與行動冷卻的前端鎖都變了,見 §5 與 §8。
這是 MyKirito(mykirito.com)的同人復刻:七種行動名稱、扔屎/沾屎、茶渡、轉生點、 狗頭人王伊爾凡格,全部照原作;預設頭像檔名就叫 kirito.webp。
#1. 技術棧與拆包方法
- React 19 + React Router 7 + Chakra UI v3(
chakra-*class)。Rolldown/Vite 打包,沒有 sourcemap。 - 變數名壓成單字母,但字串常值沒混淆:API 路徑、中文文案、能力鍵名全看得到。
- 首頁 HTML 與
/assets/*都能直接curl(帶瀏覽器 UA 即可,Cloudflare 沒擋靜態檔)。 - 應用層程式碼從
var Jy = "https://mydoujin-backend…"開始(bundle 偏移約 572 KB 處), 前面全是 React/Chakra/Router 的函式庫。切出這段餵 prettier 只有 4,581 行,一次讀得完。
複現指令:
curl -sA "Mozilla/5.0" -o index.html https://mydoujin.online/
grep -oE 'assets/[A-Za-z0-9_.\-]+\.(js|css)' index.html # 只有兩個檔
curl -sA "Mozilla/5.0" -O https://mydoujin.online/assets/index-CQ9wDrWG.js
node -e 'const s=require("fs").readFileSync("index-CQ9wDrWG.js","utf8");const i=s.indexOf("Jy=`https://mydoujin-backend");require("fs").writeFileSync("app.js",s.slice(s.lastIndexOf("var ",i)))'
npx prettier@3 --parser babel app.js > app.pretty.js
#2. 認證機制
- Discord OAuth:登入頁按鈕導向
${後端}/api/auth/discord,回來時 token 掛在網址參數?token=, 前端讀到就存進localStorage.token並用history.replaceState把參數洗掉。 - token 是 HS256 JWT,payload
{userId, discordId, username, iat, exp};本次樣本有效期 30 天(iat→exp = 2,592,000 秒)。 沒有滾動更新:伺服器不會回新 token,過期就得重新走 Discord 登入。 - 每個請求帶
Authorization: Bearer <token>(不是 cookie)。401/403 → 清 token、狀態變unauthorized。 - 前端啟動時先自己解 JWT 看
exp,過期直接登出,不打伺服器。 - 前端的 fetch 包裝
Qy():GET 逾時 10 秒、逾時後自動用 60 秒再試一次;POST 預設 10 秒不重試 (/api/action/resolve、/api/players/:id/:type、/api/dungeon/party/*給 20 秒,/api/dungeon/challenge30 秒)。 - 回應沒有
server-time之類的校時 header;冷卻倒數全靠lastActionAt(ISO 字串)+cooldownMs用本機時鐘算。 - 沒有 WebSocket/SSE;Boss 隊伍靠手動「刷新」。
token 是登入憑證,不要進版控、不要貼到任何地方。本 repo 的工具一律從環境變數
MD_TOKEN讀。
#3. API 全表
全部相對於 https://mydoujin-backend.onrender.com。回應都是 JSON;錯誤格式 {"error": "中文訊息"}。
#GET
| 端點 | 說明 | 回應要點 |
|---|---|---|
/api/users/me | 帳號 | id, discordId, username, nickname, activeCharacterId, personalStatus, currentFloor |
/api/characters/active | 現役角色 | {character: {...}},見 §4 |
/api/characters | 全部角色+轉生點 | {characters:[...], reincarnation:{total, spent, available, allocated:{九維}}};每隻角色帶 characterId, level, exp, totalExp, stats, reincarnationStats, combatStats, totalCombatStats, isDead, isSoiled, name, title, imagePath, reincarnationCount。reincarnationStats 就是該角色的 Lv.1 九維(base)——2026-09-17 九顆帳號實讀對出來的:同一隻跨帳號完全一致(22 隻,與等級/轉生次數/配點無關)、跟解鎖酬載的 base 逐維相符(20/20)、Lv.1 角色的 stats = 它 + 轉生配點(HP ×30、其餘 ×1)91/91 成立。所以 /api/characters 不給 basereincarnationStats;growth 仍然只有解鎖酬載給。抓法 tools/dump-roster.js |
/api/action/status | 行動冷卻與待處理事件 | {lastActionAt, cooldownMs, pendingEvent, isMaxLevel};2026-09-15 起多了 serverTime、cooldownRemainingMs、trainingOptions[](修行中 cooldownRemainingMs 會是幾十分鐘到幾小時,ArcGrove 實測 3039689 ms ≈ 50 分鐘,產線照原本的冷卻邏輯等就好) |
/api/characters/event-preferences | 事件偏好(2026-09-17 站方新增,bundle index-Bw98KMKC.js) | PUT {deprioritizedCharacterIds:[characterId…]},回 {deprioritizedCharacterIds};現況從 GET /api/characters 的 deprioritizedCharacterIds[] 讀。頁面文案:「減少所選角色的相關事件;共用事件仍可能正常出現。按『更新』儲存,轉生後保留。」只能選已取得的角色。是降權不是關掉,所以要拿新角色就把已擁有的全部列進去,池子裡剩下的就是還沒拿到的線 |
/api/action/train | 修行(2026-09-15 站方新增) | POST {trainingId},trainingId 是 train1h/train2h/train4h/train8h(trainingOptions[] 是 {id,name,hours})。頁面文案:「長時間修行換取大量經驗」「將鎖定 N 小時。期間無法行動、探索或挑戰其他玩家。」train1h 回 actionResult{exp:3600, levelUps, gains} 立刻到帳,然後 cooldownRemainingMs 3,600,000;有自己的每級配方(預算 23)、不進觸發那一級的加權、不翻倍(見 logs/20260914-升級實測.md)。不是七種行動之一,別當成免費經驗。修行鎖住期間轉生照樣成功、轉生後冷卻歸零(2026-09-17,見 §7) |
/api/players?page=N&limit=10[&name=完全相符] | 玩家列表 | {players:[{id, imagePath, level, nickname, personalStatus, characterName, characterTitle, floor, isDead, isSoiled}], pagination:{hasNextPage}} |
/api/players/:id | 單一玩家 | {id, nickname, character:{...}}(含 exp 與 combatStats,別人的經驗值看得到) |
/api/battle-reports | 我的戰報列表 | 陣列,每筆 participants, reportId, battleType, result, outcomes, createdAt;不含 logs |
/api/battle-reports/:reportId | 戰報內容 | 多 logs[],見 §6。不檢查戰報是不是自己的——任何 token 都讀得到任何 id(2026-09-15 實測 id 100/2000/3000 全回 200),id 有洞時回 {"error":"找不到該戰報"}。等於整座伺服器的對戰史都是公開資料:雙方等級、角色、九維、勝負都在裡面,一發 PvP 都不用打就能取樣,tools/scan-reports.js 用的就是這條 |
/api/dungeon/boss | 當層 Boss | {floorNumber, name, title, imagePath, maxPartySize, bosses:[{id, skills, normalAttack, passives, stats, rewards}]};打過會回 {cleared:true, currentFloor} |
/api/dungeon/party | 我的隊伍 | {viewerId, userVersion, maxPartySize, blockers[], latestBattle, party};party 有 id/code(六碼)/version/members[] |
#POST / PUT
POST /api/action/explore body {actionId} 行動(七種,見 §5)
POST /api/action/resolve body {optionId|null} 回覆隨機事件
POST /api/players/:id/challenge (無 body) 友好切磋(PvP)
POST /api/players/:id/chado (無 body) 「我要茶渡你」(賭上一切的決鬥,會沾屎/死亡)
PUT /api/users/me/status body {personalStatus} 個人狀態(≤30 字)
PUT /api/users/me/nickname body {nickname} 暱稱(≤12 字,只在第一次設定時出現)
POST /api/characters/reincarnate body {userCharacterId, allocation:{九維}, jumpToFirstFloor:bool} // 2026-09-15 起 allocation 配的是 total(見 §7)
PUT /api/characters/event-preferences body {deprioritizedCharacterIds:[characterId…]} // 事件偏好(2026-09-17 站方新加):降權這些角色的相關事件,共用事件照常;轉生後保留。讀取是 GET /api/characters 回的 deprioritizedCharacterIds(沒有 GET 這條端點,404)。工具 tools/set-event-prefs.js
POST /api/dungeon/party/:op body {partyId, version, ...} op 由前端拼(建立/加入/離開;帶 6 碼隊伍代碼)
POST /api/dungeon/challenge body {requestId(uuid), partyId, version, userVersion}
/api/dungeon/challenge 的 requestId 會先存進 localStorage["boss-challenge:<viewerId>"], 成功或 4xx 才清掉——這是冪等鍵,斷線重送同一個 requestId 不會打兩次。 2026-09-16 站方改版(bundle index-BwB6hilY.js → index-GxexBab5.js,只差 84 bytes,共三處): ① 有一把還沒清掉的挑戰鍵時,隊伍面板不再被鎖住(舊版 blocked: !!S || w、隊伍操作也擋 E.current || S;新版都只看 busy), 所以卡住的挑戰不會再把整個 Boss 頁凍住;② 挑戰回應改成 json().catch(() => null) 安全解析, 讀不到 body 時丟新訊息「讀不到挑戰結果,請刷新後查看戰報。」(舊版直接 r.error 會炸);③ 轉生點 HP 倍率 50 → 30(見 §7)。 攻略助手不碰 Boss 頁,①②不用改;③已跟上(v1.26.1)。
2026-09-17 再改版(index-IauX__kk.js → index-BLOKYYIh.js,多 773 bytes,只差一處):轉生頁配點的「+/-」鈕改成長按連發(按住 350 ms 後每 70 ms 加減一點,onPointerDown/onPointerUp),純前端 UI;轉生 HP 倍率仍是 xb={hp:30},其他沒動。
2026-09-16 再改版(index-GxexBab5.js → index-IauX__kk.js,多 89 bytes,共兩處;轉生 HP 倍率仍是 xb = {hp: 30},沒再動): ① 戰報字色表多了 FATIGUE/FATIGUE_SKIP 兩種 log 型別(跟 BLOCK/COUNTER 同一色 #e2c897)——前端只有配色、沒有文案, 內容是伺服器在 logs[] 裡給的,「疲勞」機制是什麼還沒量到(推斷:戰鬥拖太長時的減益或跳過回合); ② 事件結算視窗的 rewards.bonusStats 開始支援負數(t < 0 印紅字「- N 維度」,舊版寫死 +), 也就是事件可以扣能力值了。產線紀錄裡還沒有一筆負數 2026-09-17 已經有 5 個選項量到負數,分兩種: 無判定、每次都扣(pt_opt_006_look HP −10、pt_opt_005_drink 體 −1、pt_opt_002_hand_over 防 −1); 有判定、沒過才扣(pt_opt_006_grab 攻 DC100、pt_opt_006_step_back 敏 DC75,失敗各 HP −10)。 後者讓 pt_e006_treasure_below 整個事件的規則變成「沒有成功通過判定就掉 10 HP」,10 次觀測零例外 (「過了就不扣」只有 2 筆成功樣本,還不算釘死)。 攻略助手把 bonusStats 直接加進九維、build-event-options.js 的期望值是數值加總,負數會自然算進去; event-shot.js 的圖卡文字補了負號。注意收益表的 points 是總和:有判定的選項要除以失敗次數才是「一次扣多少」。
#4. 角色物件
{
"_id": "…", "userId": "…", "characterId": "kirito",
"level": 10, "exp": 79,
"name": "桐人", "title": "黑色劍士", "imagePath": "/images/characters/kirito.webp",
"isDead": false, "isSoiled": false, "reincarnationCount": 0,
"stats": { "hp": 1950, "atk": 45, "def": 21, "sta": 64, "agi": 34, "spd": 46, "tec": 38, "int": 22, "luk": 17 },
"combatStats": { "activeThrows": 0, "defenseThrows": 0, "assaultSoiled": 0, "counterSoiled": 0, "wins": 7, "losses": 0 },
"totalCombatStats": { … 同上,跨轉生累計 … }
}
九維與前端文案:
| 鍵 | 名稱 | 說明(照前端 yb) |
|---|---|---|
| hp | HP | 生命值,歸零即倒下。轉生點每點 +30( |
| atk | 攻擊 | 影響普通攻擊與技能傷害 |
| def | 防禦 | 減少受到的傷害 |
| sta | 體力 | 影響持續作戰能力與部分技能發動 |
| agi | 敏捷 | 影響迴避與攻擊命中 |
| spd | 反應速度 | 決定先攻、連擊次數,以及額外回合 |
| tec | 技巧 | 影響命中、爆擊傷害,以及反擊機率 |
| int | 智力 | 影響法術傷害與治療量 |
| luk | 幸運 | 最神奇的屬性,能在戰鬥中造成意想不到的效果 |
combatStats 的中文(主頁右半欄):主動扔屎/防衛扔屎/總主動扔屎/總防衛扔屎/遭襲沾屎/遭反殺沾屎/勝場/敗場/總勝場/總敗場。 isDead=「你的角色死亡了,請進行轉生」、isSoiled=「你的角色沾到屎了,請進行轉生」—— 兩句都只是畫在頁面頂端的橫幅,但只有 isDead 真的擋住行動。 兩者都要轉生才能繼續。 更正(2026-09-16,翻 bundle 查證):前端每一個擋行動的判斷式 (行動鈕、自律行動、Boss 挑戰、事件回覆)讀的都只有 isDead;isSoiled 全檔只出現在 那條橫幅(常數 pb)與一個文字顏色裡,沒有任何一處拿它當閘門。 所以沾屎不影響練功,只是掛著一條咖啡色的羞辱橫幅、要不要轉生洗掉是玩家自己的事。 這件事很重要:先前把沾屎當成「必須轉生」,會讓人以為輸掉茶渡=等級歸零, 因而不敢用茶渡——實際上輸了沒有任何機制上的損失。
exp 是「本級累積」:升級後從溢出量重新起算(實測 Lv.11 exp 177 → 九次休息 +180 → Lv.12 exp 16)。 前端沒有任何等級經驗表,「還差多少升級」只能靠觀察升級瞬間反推(攻略助手會自己學)。
#5. 行動(/api/action/explore)
| actionId | 名稱 | 實測 exp |
|---|---|---|
| hunt | 狩獵 | 20 |
| training | 自主訓練 | 20 |
| picnic | 外出野餐 | 20 |
| flirt | 汁妹 | 20 |
| charity | 做善事 | 20 |
| rest | 坐下休息 | 20 |
| fishing | 釣魚 | 20 |
七種行動都固定 +20 exp,跟等級、角色、行動種類都無關(2026-09-16 從九條產線的 全部 explore 紀錄回推,Lv.1~41 沒有一筆例外)。所以選哪個行動不影響升級速度, 只影響長出來的能力值——行動配方是為了戰力,不是為了衝等。
滿級是 Lv.100,滿級後 /api/action/explore 直接回 400(2026-09-16 23:20 牙王 Lv.100 實測 14 發狩獵): {"error":"Character has reached max level (100). Cannot explore further."},經驗 0、沒有事件。/api/action/status 的 isMaxLevel: true。 所以滿級後拿不到事件、解不了角色,要繼續走事件線只能轉生;能做的只剩 PvP 與 Boss。修行在 Lv.99 按會封頂在 100,多的 exp 作廢。
#5.1 經驗曲線(2026-09-16 量出來)
把每一級之間的 actionResult.exp 加總,就是那一級所需的經驗。Lv.2~38 都對得上:
每級所需經驗 = 20 × round(1.75 × 等級)
(Lv.20 → 700、Lv.28 → 980、Lv.31 → 1080、Lv.38 → 1320,全部零誤差。) 事件不給經驗——每級的加總只靠行動就補得滿,沒有缺口。
推論(Lv.38 以上是外推,標推斷值):升一級要 round(1.75 × 等級) 次行動, Lv.40 是 70 次、Lv.69 是 121 次。冷卻 10 秒,所以一小時最多約 348 次行動 ≈ 6,960 exp, 而每小時 600 發的額度只用掉約 380 發——綁住產能的是 10 秒冷卻,不是請求額度, 把 --rph 調高一點用都沒有。
回應:
{
"lastActionAt": "2026-09-14T11:49:47.499Z", "cooldownMs": 10000,
"pendingEvent": null,
"actionResult": { "actionId": "rest", "actionName": "坐下休息", "exp": 20, "level": 7, "levelUps": 0,
"gains": { "hp": 0, "atk": 0, … 九維 … } }
}
- 冷卻 10 秒(
cooldownMs),PvP 切磋後 30 秒。 - 冷卻中送出:2026-09-14 14:51 起改回 409(原本是 400),而且帶結構化欄位:
{ "error": "行動冷卻中,請等待 29 秒。", "code": "ACTION_COOLDOWN",
"cooldownRemainingMs": 28432, "retryAfter": 29, "serverTime": "2026-09-14T14:51:57.697Z" }
cooldownRemainingMs 比從中文訊息挖數字可靠(訊息是無條件進位的整數秒); serverTime 可以拿來校正本機時鐘——冷卻是用伺服器給的 lastActionAt 跟「現在」比, 本機時鐘偏幾秒就會提早送出去撞冷卻。回應的 HTTP Date header 也可以當備援(只到秒)。
gains只在levelUps > 0時非零;一次升多級也只回一組總和。升級 toast 文案升級!Lv.a → Lv.b。isMaxLevel為真時前端隱藏行動鈕(「已達到最高等級,無法再進行行動。」)。滿級是幾級未知,但下限是 80。滿級是 100(2026-09-16 掃全站 392 名玩家定的, 是人先問「這遊戲沒辦法升級超過 100 等吧」才去查的):
等級分佈 0s:137 10s:37 20s:28 30s:26 40s:60 50s:26 60s:32 70s:27 80s:11 90s:6 100s:2 最高 Lv.100 赤羽和一、Lv.100 numberman —— 只有兩人,一個都沒有超過
100 這個數字是從全站分佈推的,不是拆包拿到的:isMaxLevel 由伺服器算, 前端沒有任何等級上限常數。但 392 人裡有兩個剛好卡在 100、101 以上一個都沒有, 而 90s 還有 6 人,這個形狀是硬上限而不是「還沒有人練到」。 掃法:/api/players?page=N&limit=10 一頁 10 人,40 頁掃完全站。 九個帳號跑到現在一次都沒觸發過 isMaxLevel(最高才 Lv.83),所以那個旗標本身還沒實地驗過。
這件事會改變練功規劃:等級到頂之後,攻擊只剩兩條路——轉生點配到 atk(一點 +1), 以及事件的 bonusStats。而轉生點只能在轉生時重配,轉生又把等級打回 1, 所以「練到滿級再把點數挪過去」是做不到的,要嘛轉生前就配好、要嘛整輪重練。
- 行動可能附帶
pendingEvent(隨機事件);事件未回覆前不能再行動(前端把按鈕全鎖)。
#5.0a 事件偏好:把已擁有的角色線降權(2026-09-17 04:45,站方新增)
主頁多了「事件偏好」區塊,可多選已取得的角色,按「更新」送 PUT /api/characters/event-preferences。效果是降低那些角色線事件的出現率(不是關掉), 共用事件(公佈欄、訓練場等樞紐)照常。轉生後保留。實測 ArcGrove 在我們動手前已被設成 6 隻(桐人/牙王/艾基爾/食糞者/亞絲娜/詩乃,人手動設的)。 04:45 兩顆產線帳號改成「已擁有的全部降權」:ArcGrove 14 隻、LysanderSup 11 隻——剩下會正常出的就是還沒拿到的線 (ArcGrove 缺 瑞傑路德/莉茲貝特/小八/磚頭/芋頭;LysanderSup 缺 牙王/灰燼/莉茲貝特/哥布林英雄/芙莉蓮/小八/磚頭/食糞者)。 之後拿到新角色要再把它加進去,不然那條線會繼續佔池子。工具:MD_TOKEN=<token> node tools/set-event-prefs.js --all-owned(另一位 AI 同日寫的,桐人除外)。
同一版 bundle(比 index-BLOKYYIh.js 多 71 KB)其他可見的新字串:轉生頁「按住 + 或 - 可以連續加減點」「轉生點每點 +N 某維」、玩家頁「沒有上陣角色」「無稱號」、冷卻文案; 端點只多這一條。降權的實際幅度還沒量——要拿降權前後同一帳號的事件線分布比,先記著。
#5.0 角色取得不只靠事件(2026-09-17,官方 Discord #啵啵村)
作者「大木」被問「角色獲取方式只有透過事件嗎」,答「不是」;接著說「這遊戲的精髓就是怎麼獲得角色的都不知道」。 玩家丟出的猜法:個人狀態打特定文字、用特定角色茶渡人、「光是吃十次屎就是例外了」。
「吃屎」這條我們的資料直接證實:帳號對照 totalCombatStats(跨轉生累計;combatStats 每次轉生歸零, ly183 轉生後 combatStats.counterSoiled 是 0、totalCombatStats.counterSoiled 才是 885)與可轉生名單: counterSoiled(主動茶渡輸掉沾屎)880~890 次的 ly183、eth2000、onejun3096 全有食糞者,ArcGrove 59 次也有(人 9/17 補的), 0~3 次的 jun184、season0320、jy03work、leotek7414、LysanderSup 全沒有——4/4 對 0/5。 食糞者(詛咒的播種者)= 沾屎累積 N 次解鎖,門檻落在 7~59 次之間(Discord 玩家說 10 次)。這跟 5.1 的事件線完全無關,gainCharacters 出現在哪一發回應裡還沒抓到 (三顆都是 9/15 茶渡刷勝場時拿到的,當時 chado.js 不記 gainCharacters)。 再加兩顆對照(2026-09-17 04:40,另一位 AI 查 /api/characters 與 /api/characters/active):ArcGrove totalCombatStats.counterSoiled 59(assaultSoiled 1)有食糞者;LysanderSup counterSoiled 3(assaultSoiled 3)沒有——變成 4/4 對 0/5,門檻落在 7~59 之間,跟「10 次」不矛盾。注意 combatStats 每次轉生歸零(ArcGrove 轉成洛琪希後全是 0),累計要看 totalCombatStats。 大蒜:ly183 與 leotek7414 有、其餘沒有,共同點還沒找到(leotek 到過 Lv.100;garlic_ 前綴的事件只遇過 5 次、0 解鎖)。 索拉爾(太陽戰士,solaire):2026-09-17 發現只有 jun184 有(其餘六顆都沒有)。查證過程:
- 22:59:36 轉生前實讀
/api/characters:11 隻,沒有 solaire(kirito, agil, sinon, asuna, kibaou, melina, shanks, ashen_one, stone, hachiware, taro)。 - 04:50 再讀:13 隻,多了 solaire 與 brick。brick 有紀錄(03:46
brick_e003解的),solaire 沒有。 - 這段期間 jun184 的紀錄是連續的:
explore1128、event156、levelup32、reincarnate1、explore-error2,最長空窗只有 183 秒(兩段實驗之間)。全部 jsonl grep 不到 "solaire" 這個字, 所有事件文案也沒有出現過「太陽/索拉爾」。 - 所以那段期間唯一被丟掉的回應主體,就是 22:59:38 那一發轉生(當時
kind:'reincarnate'只存from/character/allocation/after.stats,沒存resp)。
結論:最可能是轉生回應給的,但分不出是「離開灰燼」還是「轉生成石頭」——只有 jun184 同時做了這兩件事。 level-probe.js 已改成把轉生回應整包存下來並在 log 上印「★ 轉生同時解鎖:…」,下一次任何帳號轉生就會抓到, 不必為了驗這件事特地燒一次轉生。
2026-09-17 補:Lv.1 九維撈到了,成長權重還沒。 解鎖酬載是找不回來了,但 GET /api/characters 的 reincarnationStats(見 §3 那一列)就是 base,所以索拉爾的 Lv.1 九維直接讀得到: {hp:420, atk:20, def:22, sta:21, agi:11, spd:13, tec:18, int:11, luk:8}(食糞者 {hp:510, atk:23, def:22, sta:22, agi:7, spd:9, tec:11, int:9, luk:8},同樣沒有酬載)。 兩隻都已進圖鑑,source 標「名冊 reincarnationStats」。 growth 這條路拿不到,要補齊只有兩個辦法:再解鎖一次(別顆帳號解到就有酬載), 或轉生成它、本級零行動按修行——長出來的每級成長就是 growthWeights(HP × 30,牙王與洛琪希都驗過)。 後者要燒掉 jun184 現役石頭 Lv.51 的進度,是回不去的操作,等人決定。 個人狀態文字(PUT /api/users/me/status)、特定角色茶渡:未測。PvP 目前人禁到 Lv.100,後者等解禁再試。
#5.1 隨機事件(pendingEvent → /api/action/resolve)
- 樞紐事件(2026-09-16):
daily_notice_board「公佈欄」與daily_training_ground「訓練場」的選項數 隨帳號進度變動(公佈欄 1~14 個、訓練場 2~12 個),每個選項對應一條角色線 (daily_opt_board_kob/_patches/_stone/_brick/_memorial/_smith,daily_opt_train_linie/_frieren/_als……)。 推斷值:選了會立那條線的旗標、讓那條線的關卡進池子——選項本身幾乎都給 0 點。linie/frieren兩個選項各只被一個帳號看過一次,對應的角色還沒在玩家列表出現過。 前端 bundle 裡沒有「任務」二字,人說的「任務欄」應該就是公佈欄。
{ "eventId": "agil_e001_market_row", "name": "迷宮區前的攤子",
"description": "……(劇情文字)",
"options": [ { "id": "agil_opt_001_haggle", "name": "……", "checkStat": "int", "baseDC": 50,
"effectiveStat": 18, "successChance": 69 },
{ "id": "agil_opt_002_leave", "name": "……", "checkStat": null } ] }
successChance 是官方值,不用自己算(2026-09-14 補)。只要 checkStat 不是 null, 選項就一定帶 effectiveStat 與 successChance:實測 3414 個有判定的選項全部都有, 而且跟事後 /api/action/resolve 回來的 chance 一個不差(1538 筆零誤差比對)。 checkStat 是 null 的選項沒有這兩個欄位(也不需要,那種選項不擲骰)。 所以工具與 userscript 都直接讀它,推斷公式只留當後備。
沒有 options 的事件前端送 {optionId: null}。回覆結果:
{ "stat": "int", "statValue": 24, "effectiveStat": 10, "roll": 30, "total": 40, "dc": 50, "chance": 61,
"critical": null, "isSuccess": false, "text": "……結果文字……",
"rewards": null | { "exp": N, "bonusStats": { "atk": 1, … } }, // 2026-09-16 新 bundle 起前端支援負值,事件可能扣能力
"battleResult": null | { "winner": "TEAM_A|TEAM_B|…", "logs": [...] },
"gainCharacters": [ { "id", "name", "title", "imagePath", "base": {九維}, "growth": {九維}, "normalAttack", "skills": [] } ]
// 解鎖新角色,「將可於下次轉生時使用」。base 是 Lv.1 九維、growth 是成長權重(九維合計 25),
// 平常的 /api/characters 不給這兩個,只有這一刻有(2026-09-16,全表在 docs/20260916-角色數值圖鑑.json)
}
判定規則(20 個樣本,logs/20260914-升級實測.md 有全表):
chance = 51 + effectiveStat,20/20 筆吻合。 等價於effectiveStat + 1d100 ≥ dc,目前看到的dc全是 50。total = effectiveStat + roll,roll是 1d100。- 釘死了(2026-09-17,522 筆有判定的紀錄)——來源是一位網友公開的試算表(
docs/20260917-網友試算表除錯.md有對照與出處), 它把每一發的stat/effectiveStat/dc/chance/roll/critical/isSuccess都存下來,比我們自己的紀錄完整:
| 規則 | 樣本 | 結果 |
|---|---|---|
chance = 101 − dc + effectiveStat,上限 95 | 522 | 517 筆直接吻合;另外 5 筆算出來會是 157~176,全部回 95 |
isSuccess ⟺ effectiveStat + roll ≥ dc(等價 roll > 100 − chance) | 522 | 521 筆吻合,唯一例外是大失敗(見下) |
roll ≤ 5 → critical: "fail",一律失敗 | 27 | 27/27。其中一筆 eff 111 + roll 3 = 114 ≥ dc 50 仍然失敗——所以大失敗是覆寫,不是加減 |
roll ≥ 96 → critical: "success" | 22 | 22/22 都成功,但 22 筆本來就都過得了,「大成功會覆寫失敗」還沒有反例證實 |
其餘 roll 一律 critical: null | 473 | 無例外 |
roll 實測涵蓋 1~100、平均 53.2,是乾淨的 1d100。校準也對得上:522 筆的 chance 加總預期 332.4 次成功,實際 348 次。 上限 95 的來源就是大失敗(5% 一定失敗),所以下限推測是 5,但樣本最低只到 14,沒證實。 dc 實測有 50/75/100 三種(先前寫「全是 50」已過時)。
effectiveStat不是原始能力值的函數,它隨等級遞減。 同樣 int 24:Lv.4 的小號拿到 20,Lv.12 的主帳號只有 10。 把能力值 ÷ effectiveStat對等級排開,會發現它幾乎只跟等級走、跟能力值本身無關:
| Lv | 3 | 4 | 5 | 6 | 8 | 12 | 14 | 17 | 18 | 19 | 20 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 值÷eff | 1.03 | 1.19 | 1.30 | 1.46 | 1.78 | 2.40 | 2.54 | 3.08 | 3.19 | 3.31 | 3.29 |
同一級不同能力值的三筆(Lv.4 的 24/17/15 → 20/14/13)比值都是 1.15~1.21,確認除數只看等級。 推斷值:effectiveStat ≈ 能力值 ÷ (0.6 + 等級/7),誤差 ±1(低等級吻合得好,Lv.20 那筆差 1)。 確切常數要更多等級的樣本才能定,這裡只用來排序,不當數值報。
- 實務意義:等級會稀釋判定能力。除數每級約 +0.13,要維持同樣的成功率,能力值每級得長 3 以上—— 而多數行動只給 +1。所以 Lv.20 帶 int 46 的主帳號(65%)反而輸給 Lv.4 帶 int 24 的小號(71%)。 要靠事件判定吃飯,就得一直選會長那一維的行動(智力:做善事 +6、釣魚 +5)。
- 事件獎勵大多是
bonusStats某一維 +1(20 個判定樣本外另見 13 次獎勵,12 次是 int +1、1 次 sta +1); 獎勵給的正是這個事件檢定用的那一維,所以過了判定會讓下次更容易過。 - 已看到的事件命名是
<NPC>_e<序>_<slug>或daily_opt_<slug>, NPC 全是 SAO 第一層的人(LUMAMA、洛克希、艾基爾、牙王、瑞傑路德、梅爾)。
#6. 戰鬥與戰報
- PvP 只有兩種:
challenge(友好切磋,「最安全的訓練」)與chado(我要茶渡你,「賭上一切手段的正義決鬥」)。 沒有原作的「認真對決」「決一死戰」。兩邊都是無 body 的 POST。 challenge回應(HAR 實錄):{reportId, winner, isSoiled, expGained, levelUps, level, lastActionAt, cooldownMs: 30000, logs[]}。 贏一場 43~53 exp(隨對手等級),和行動共用同一條冷卻。- 戰報
logs[]的type:BATTLE_START、SKILL_TEXT(使出技能)、DAMAGE(含actorId, targetId, skillId, skillTier, isNormalAttack, value, isCrit, blocked)、MISS、COUNTER、BLOCK、HEAL、SP_RECOVER、DEATH、HP_REMAINING(value, maxHp)、EXP_GAIN、PLAYER_DEATH、PLAYER_DEFEAT、LUCK_EVENT(tier: RED|…)、CHADO、BOSS_DIALOGUE。skillTier: standard | ultimate。桐人的技能:basic_attack、sonic_leap(音速跳躍)、horizontal_arc(水平扇形斬,兩擊)、vertical_arc(垂直四方斬,四擊)。 - 前端戰報只有逐行文字與上色,沒有任何統計(總傷害、命中率、爆擊率都要自己算)——這是攻略助手的切入點。
- Boss(1F 狗頭人王伊爾凡格):HP 3000、
skills: [whirlwind]、被動illfang_shield_block、illfang_draw_nodachi,獎勵 exp 300/gold 600 (gold 目前哪裡都沒顯示,可能是預留)。隊伍上限 2 人,六碼隊伍代碼。
#6.1 Boss(2026-09-14 實測補上)
POST /api/dungeon/challengebody{requestId, partyId, version, userVersion},單挑就把partyId與versiongive null。requestId是冪等鍵(uuid),斷線重送同一顆不會打成兩場。- 每個帳號有 60 分鐘的 Boss 挑戰冷卻。冷卻中不是回錯誤,而是在
GET /api/dungeon/party的blockers[]裡列出來,訊息是「<暱稱>的 Boss 挑戰冷卻中,還有 N 分鐘。」。 組隊時每個成員的冷卻都會列進來,任何一個沒好就不能打。 - 隊伍裡只有隊長能發起挑戰,其他成員送出會回
403 只有隊長可以開始挑戰。隊伍是持久的(有id、六碼code、version),不會打完自動解散。 - 打贏的結果在
outcomes[]:每個參戰者一筆{userId, name, expGained, isDead, newFloor}。newFloor才是上樓的真相,戰報logs裡的DEATH只是戰鬥中倒下。 - 實測獎勵與
bosses[].rewards.exp標示的不一樣:第 1 層標 300、實拿 100;第 2 層標 200、實拿 200。 標示值可能是整隊的總量或未扣成分,別拿rewards.exp當實際到手值。 - 已知樓層:1F 狗頭人王伊爾凡格(HP 3000)、2F 哥布林王巴爾戈克(HP 6500)、 4F 艾莉絲·伯雷亞斯·格雷拉特(HP 13000、攻 260)。隊伍上限 2 人。
#7. 轉生
- 轉生頁文案:「角色每升到 16 等以上的每一級可獲得 1 點,上限 100 點。」轉生點每點 +1 該維、 HP 每點 +30(
xb = {hp: 30})。 2026-09-16 站方把 HP 從每點 +50 砍成 +30(−40%),而且是溯及既往的: 已經配掉的點當場重算,九隻裡三隻的最大 HP 當場掉了「已配 HP 點數 × 20」—— jun184 配 84 點掉 1,680、ArcGrove 配 20 點掉 400、leotek 配 15 點掉 300, 配 0 點的 season 與 LysanderSup 一點都沒掉。對得分毫不差。 產線的日誌抓不到這種事:actionResult.gains照樣回報hp:+30, 是 level-probe 自己算的statDiff顯示 −1650 才露餡。改平衡不會有公告。 兩版 bundle 比對過:長度完全相同(643,045 字元),只差hp:50→hp:30這一個位元組, 同一版沒有動別的東西。 2026-09-15 實測驗證:jun184 從 Lv.17 升到 Lv.19,reincarnation.total86 → 87 → 88, 一次升級一點、跨轉生累計(該帳號已轉生 4 次)。所以「衝點數」=「衝 Lv.16 以上的升級次數」, 跟停在哪一級無關;每級要的行動數約1.7 × 等級,因此練到 Lv.31 左右轉生重來最便宜 (每點約 52.7 次行動,算式與對照表見logs/20260915-轉生點成本.md)。 POST /api/characters/reincarnatebody{userCharacterId, allocation, jumpToFirstFloor};allocation九維整數,總和 ≤total(2026-09-15 起退回全部舊配點重配,見下)。- 事件可能解鎖新角色(
gainCharacters),下次轉生時可選。目前帳號只有kirito。 推斷值(2026-09-15):角色物件的推斷錯了(2026-09-17 實讀推翻):reincarnationStats是「每維配了幾點轉生點」reincarnationStats是該角色的 Lv.1 九維(base),不是配了幾點。 九顆帳號/api/characters實讀:同一隻角色跨帳號完全一致(22 隻,跟等級、轉生次數、配點都無關), 跟解鎖酬載給的base逐維相符(20/20),而且 Lv.1 角色的stats=reincarnationStats+ 配點(HP ×30、其餘 ×1)91/91 成立。 形狀像「配點」是因為除了 HP 之外一點就是 +1,數量級剛好接近。 ⚠ 攻略助手 v1.22 起在九維旁印的青色「(+N)」讀的就是這個欄位,所以那個數字印的是 Lv.1 底值、不是轉生加成,要另外修 (正確的加成是reincarnation.allocated[stat] ×(HP 30/其餘 1))。/api/characters/active與/api/players/:id是同一種角色物件,也有這個欄位。轉生點配掉就鎖死2026-09-15 站方改了規則(轉生頁文案):「每次轉生都會退回全部舊配點,從零重新分配;未分配的點數會保留。」 也就是每次轉生時allocation要配的是total(spent + available),不是available。 實測(jun184):total 84、spent 19、available 65 的帳號在 Lv.6 再轉生一次、送{hp:84}→spent 84 / available 0、Lv.1 HP 4530。 反過來說,只配available會把退回來的舊點全部閒置——jun184 第一次就是這樣配了 19 點、65 點躺著。level-probe.js已改成配 total。 配錯的點從此追得回來(ArcGrove 那 44 點智力已被重配成攻 80/智 6),代價是回到 Lv.1。- body 多了
jumpToFirstFloor(「跳樓」):勾了本次轉生把樓層重設為 1 樓重新攻略。level-probe 要帶--reinc-jump-floor才會送 true。 - 修行鎖擋不住轉生,轉生會把行動冷卻一起歸零(2026-09-17 01:30,LysanderSup 實測):香克斯 Lv.100 於 23:18 按
train8h(cooldownRemainingMs28,800,000,鎖到 07:18),01:30 直接POST /api/characters/reincarnate成功,回來的角色是 Lv.1 莉妮耶, 下一秒/api/action/explore狩獵就過了。所以「Lv.99 按修行衝到 100 → 轉生」不用等修行做完; 修行頁「期間無法行動、探索或挑戰其他玩家」那句不含轉生。 - 一點 HP 值 30(改版前 50)、一點其他維值 1,而 PvP 戰力 ≈ 攻 × HP(
logs/20260915-戰力模型.md), 所以轉生點的最佳解仍是全配 HP:邊際效益要到HP = 30 × 攻才會換邊(ArcGrove Lv.56 約 HP 5000/攻 300 ≈ 17 倍,還差得遠)。 - Lv.1 基準九維(轉生紀錄與戰報都對得上):桐人
HP 360/攻 18、詩乃HP 300/攻 24、 亞絲娜HP 330/攻 20、梅琳娜HP 300/攻 14。 桐人完整九維(2026-09-16,轉生成桐人零配點時的after.stats,兩筆一致):HP 360/攻 18/防 12/體 12/敏 16/速 22/技 14/智 12/幸 8; 另有兩筆攻 23 的,多的 5 點來源未明(可能是稱號或事件加成),不當基準。全表在tools/data/20260916-growth-matrix.json的bases。
2026-09-16 11:07 瑞傑路德線破了(your88,Lv.80):結局關 rj_e008_the_written_name「留在委託書上的名字」只有一個選項「邀他繼續同行」(rj_opt_008_invite,無判定), 選了就解鎖 瑞傑路德·斯佩路迪亞(Dead End)+體力 +1。酬載:base HP 420/攻 21/防 15/體 17/敏 15/速 18/技 23/智 7/幸 8, growth 3,4,3,3,3,3,4,1,1,技能 superd_spear_thrust/third_eye/guardian_spear_sweep。 旗標(build-routes 推論,到過 1 隻/沒到過 22 隻):確定是第七關「你守這邊」選「留下擋住追兵,讓他護送孩子」(rj_opt_007_hold,會開打, 販奴車隊追兵;your88 Lv.80 打贏),打贏後下一個 rj 事件就是結局關。第二、第五關的四個「很可能」旗標只是 your88 剛好都選過,證據弱。 這一關的路徑:e001 先離開 ×4 → e002 暫時離開 ×2、等孩子把話說完 → e005 先把補給帶走、當眾說出 → e007 留下擋住追兵(勝)→ e008。
2026-09-17 芙莉蓮線的結局關兩個選項都給角色:ArcGrove 04:25 在 frieren_e006_departure「再走一段路」選 frieren_opt_006_join 解鎖,LysanderSup 09:30 同一關選 frieren_opt_006_bless 也解鎖(前面走 隱藏魔力→問、擬態寶箱→檢查、魔族的謊言→站住、花田→摘)。所以這一關不是「選對才給」,到得了結局關就有;旗標在前面幾關。
2026-09-17 06:16 索隆線破了(LysanderSup,Lv.42 莉妮耶):結局關 zoro_e004_the_way_back「回去的路」選 zoro_opt_e004_true(從沒人選過、無判定),解鎖 羅羅亞·索隆(三刀流劍士)。酬載:base HP 390/攻 22/防 15/體 20/敏 12/速 18/技 20/智 6/幸 8,growth 2,4,3,4,2,3,4,1,2(合計 25),普攻 basic_attack,技能 purgatory_oni_giri/black_rope_dragon_twister/three_thousand_worlds,被動 zoro_draw_swords/zoro_swordsman_will。這顆帳號走的路:e001「每一條路都通往別的地方」直接指一條路給他 → e002「三把刀的空位」不問目的地跟著他走 → e003「第三把刀」坐在旁邊不再追問 → e004。06:26 ArcGrove 走一模一樣的四步也解鎖了(2/2),這條路徑可以當攻略寫;旗標的強弱要等有完整紀錄的機器重跑 build-routes。索隆線的入口在公佈欄/十字路口的 daily_opt_crossroads_zoro_map。
#8. 前端行為備忘(寫 userscript 要知道的)
- 路由:
/(主頁:角色表、個人狀態、行動)、/players、/players/:id(切磋/茶渡)、/reports、/reports/:id、/boss、/reincarnation、/login。 - 主頁每次載入打
/api/users/me、/api/characters/active(會打兩三次)、/api/action/status。沒有輪詢;冷卻倒數是前端本機setInterval每秒減一。 - 行動鈕在
h2:contains("行動")的卡片裡,七顆button.chakra-button,順序固定=kb表。冷卻中/有事件/送出中全部disabled。 - 事件是 Chakra Dialog(
role="dialog"),選項是button,有判定的選項旁邊印「( 智力: 24 / 門檻:50 )」。 2026-09-14 晚間改版後(index-2J2Lv2aK.js):伺服器有給successChance就印「( 智力: 24 / 成功率 37% )」, 沒給才印「( 智力: 24 / 門檻 50 )」(冒號拿掉了);沒判定的選項印「( 直接行動 )」。 - 行動冷卻改由前端自己在 localStorage 記一把鎖(同一版改版,逐字讀自 bundle 的
wb()/Nb()/Eb()): 鍵是action-wait:<userId>:explore(PvP 是:challenge/:chado,事件回覆是:resolve),值是解鎖的 epoch 毫秒。 每收到一發回應就waitUntil(now + cooldownRemainingMs);回應沒有cooldownRemainingMs時退成lastActionAt ? cooldownMs : 0——注意這是從收到回應的那一刻算滿一整段冷卻,不是從lastActionAt算。 鎖跨重整、跨分頁(storage事件),每 250ms 讀一次;remaining()無條件進位成整數秒,> 0 就把七顆行動鈕全鎖。 所以攻略助手的「可以行動」要跟這把鎖對齊(remainingMs()取伺服器算法與這把鎖的較大值), 否則重整之後伺服器的lastActionAt是 null、遊戲卻還鎖著,自律行動會對著灰掉的按鈕一直按。/api/action/status的正常回應有沒有帶cooldownRemainingMs還沒實錄到(只在 409 與 explore 回應裡看過)——推斷值,待補。 - 主頁的九維表
table.stats-table(td.label/td.val左右各一組),玩家頁table.duel-table(th/td), 戰報頁與 Boss 頁table.boss-table。三種表的欄名都是中文,**沒有 data-* 屬性**,只能靠文字對。 - 戰報頁(
/reports/:id):兩張table.boss-table並排在一個兩欄 Grid 裡(左=participants.players[index],index由「切換顯示」鈕決定;右=participants.enemies[0]), 列是 玩家/等級/角色/稱號/HP/攻擊/防禦/體力/敏捷/反應速度/技巧/智力/幸運(td.label/td.val),BOSS 戰的右表沒有等級列。 下面才是h2「戰鬥過程」與逐行 log。participants兩邊都帶stats九維與level,所以雙方比較與雷達圖不必再打 API(2026-09-14 補)。 /api/players/:id回的character.combatStats(勝敗、扔屎、沾屎)、exp、reincarnationCount玩家頁都沒印,只顯示九維——攻略助手把它們補在兩張表下面。POST /api/players/:id/challenge的expGained隨對手等級變(實錄 43~53),沒有公式;原作 MyKirito Helper 是查表,本站只能照等級差記自己贏過的。- 前端路由是 React Router 的 BrowserRouter:
history.pushState之後補發一個popstate事件就會換頁,不用整頁重載(重載會多打 users/me、characters/active、action/status 三發)。 - 全站深色:背景
#1a202c,卡片#171923/#2d3748,強調色 teal(#0d9488一帶),茶渡鈕咖啡色#6f4e37。 - 所有 API 都走全域
fetch(Qy()直接呼叫fetch(o, …)),在 document-start 包一層window.fetch就能無痛旁聽全部回應,不必多打一發請求。
#6.2 隊伍與 Boss 的規則(2026-09-15 實測)
- 隊員的樓層必須相同,否則挑戰會被擋:
隊員樓層不同,無法挑戰 Boss。這條讓「強的帶弱的」行不通——強帳號通常樓層也比較深。 - 隊伍代碼是 6 碼英數,且不含 I、O、0、1(送錯會回
請輸入 6 碼英數代碼(不含 I、O、0、1)。)。沒有獨立的「建立」端點, 前端那顆鈕寫「建立/加入」,兩者都走join,代碼不存在就順便建立。 - 隊伍會一直留著,人可能早就組過隊忘了退。掛在隊伍裡時:只有隊長能發起挑戰, 而且隊友的狀態(冷卻中、有沒結的事件、樓層不同)會出現在
blockers[]擋住整隊。 想單挑得真的退隊——只把partyId/version送 null 會被回 409 「隊伍已變更,請刷新後再挑戰。」(2026-09-16 實測)。 隊伍動作:POST /api/dungeon/party/{join|leave|disband|remove},body 帶{partyId, version},join另帶{code}、remove另帶{memberId}。tools/boss.js --solo會忽略 blockers, 但還是要先退隊才送得出去。 - Boss 挑戰冷卻 60 分鐘,算在帳號上而不是隊伍上,而且隊友的冷卻也會擋住整隊:
<某人>的 Boss 挑戰冷卻中,還有 60 分鐘。 第 5 層是天花板更正(2026-09-16):有第 6 層,Boss 是小丑巴奇 (HP 46,000、攻 390、防 100)。戰報樣本裡亞絲娜 Lv.76 攻 379 單挑它輸了。 原本的說法是:打完第 5 層之後/api/dungeon/boss回{cleared:true, currentFloor:5}, 沒有第 6 層。所以樓層推到底的帳號再也不能打 Boss,也就不能靠 Boss 拿經驗。
#6.3 全站有 11 個角色(2026-09-15,掃 300 名玩家)
/api/characters 只回自己已解鎖的角色,列舉不到完整名單; 但 /api/players 會回每個玩家的 characterName/characterTitle/imagePath,掃過去就看得到全部:
| 角色 | 稱號 | 圖檔 | 300 人中 | 對應事件線 |
|---|---|---|---|---|
| 桐人 | 黑色劍士 | kirito | 238 | 預設 |
| 亞絲娜 | 閃光 | asuna | 13 | sao |
| 詩乃 | 冰之狙擊手 | sinon | 10 | sinon |
| 哥布林英雄 | 逆襲的綠皮 | goblin_hero | 10 | gh(未證實) |
| 洛琪希·米格路迪亞 | 水王級魔術師 | roxy | 9 | roxy(未證實) |
| 梅琳娜 | 木頭 | melina | 8 | mel |
| 食糞者 | 詛咒的播種者 | dung_eater | 5 | 不明 |
| 莉茲貝特 | 鍛冶師 | lisbeth | 3 | liz(未證實) |
| 牙王 | Aincrad解放部隊 | kibaou | 2 | kibaou |
| 瑞傑路德·斯佩路迪亞 | Dead End | ruijerd | 1 | rj(未證實) |
| 艾基爾 | 商人 | agil | 1 | agil |
四條「看起來沒有角色獎勵」的線(gh/roxy/liz/rj)各自都有一個對應的角色存在, 所以那幾條線幾乎確定還有一關我們沒觸發過。對應關係是照名字推的,還沒實際解鎖過任何一個。
食糞者對不上任何事件線。名字與稱號(詛咒的播種者)指向扔屎/沾屎那套 PvP 機制,但沒有證據。
#6.4 靜態站可以探角色圖檔:第 12 個角色 eris(2026-09-15)
前端 bundle 裡沒有任何角色資料(名字、id、解鎖條件全在後端;bundle 只寫死了預設圖 kirito.webp), 所以拆前端拆不出「怎麼解鎖」。但角色圖檔放在靜態站 https://mydoujin.online/images/characters/<id>.webp, 可以用猜 id 的方式探:不存在的路徑 SPA 也回 200(回的是 index.html),要看 Content-Type 是不是 image/webp, 只看狀態碼會全部誤判成存在。
探了約 130 個候選 id(SAO/無職轉生/艾爾登法環/哥布林殺手的角色名),存在的圖檔剛好是 §6.3 的 11 個加上一個:
| 圖檔 | 推測 | 300 名玩家裡 | 對應事件線 |
|---|---|---|---|
eris | 艾莉絲(無職轉生) | 0 | 不明——沒有任何一條已知事件線指向她 |
同日稍晚再探到 shanks(香克斯,海賊王;人問「香克斯怎麼拿」)——海賊王那一串(luffy/zoro/nami/…/mihawk/buggy,共 40 個) 只有 shanks 存在,所以是單一角色不是整條線。全部圖檔的 last-modified 都是同一個部署時間,看不出誰是新加的。
也就是全站至少有 13 個角色,其中 eris 與 shanks 在 9/15 早上掃的 300 名玩家裡都是 0 人。 要查「誰拿到了」用 tools/scan-players.js --find 香克斯(拿自己的 token 掃 /api/players)。她可能藏在還沒觸發過的關卡裡 (洛克希線與瑞傑路德線都是無職轉生的人物,最可能是這兩條線的分支),也可能根本還沒開放。 Boss 圖檔同一招:images/boss/illfang.webp 存在(狗頭人王),ilfang/kobold_lord 不存在。
這只證明「圖檔存在」,不證明「拿得到」;解鎖條件仍然只能靠產線踩出來。
#6.5 角色的 Lv.1 九維與成長權重來自解鎖酬載;公佈欄的選項數會跟著跑過的線增加(2026-09-16)
- 人轉來一張 11 隻角色的「Lv.1 九維+每級 25 點成長權重」表,逐格對照
docs/20260916-角色數值圖鑑.json(解鎖那一刻resolve.gainCharacters[]帶的base/growth)11 隻全部一致,所以那張表就是伺服器的定義,不是推測。 灰燼的 id 是ashen_one。桐人是初始角色,伺服器從沒吐過它的酬載,權重不知道。 - 權重跟本 repo 實測的「每級成長=本級行動的加權平均」怎麼疊還沒解出來(實測每級 23 點、權重 25 點); 已量到的偏移方向對得上(梅琳娜 智 4/攻 2 對應實測 int+1/atk−1;亞絲娜 速 5 對應 spd+1),只當方向。
- 公佈欄(
daily_notice_board)的選項數會跟著跑過的線增加:產線紀錄裡只見過 9 個選項,人那隻一直不轉生、 跑過很多線的帳號看到 16 個(截圖)。多出來的七個裡有「把那張紅髮男人的通緝令翻正」(推測是香克斯線入口)、 「貼一張徵求鍛冶師的紙條」(莉茲線?)、「補寫瑞傑路德救援孩子的紀錄」(瑞傑路德線後段?); 對應是照字面推的,見tools/data/20260915-event-supplement.json。轉生會不會清掉這些進度還沒驗。