← 技術文件

劇情 MOD

給原版關卡加事件:什麼時候觸發、要滿足什麼、做什麼、說哪些新臺詞。可以讓人物加入或留下、改變劇情分支,不佔原版的事件位,原版事件一個不動。

更新於 2026-11-03

劇情 MOD 給原版的關卡加事件:第幾回合、誰被擊破、誰和誰交戰、選了「說服」……的時候,播你寫的臺詞,讓人物加入、離場,或者改劇情變數讓後面的原版劇情換一條路走。觸發判斷由遊戲來做,你只寫條件和要做的事,不用懂原版的事件表。原版的事件一個都不會被改動或擠掉。

包的安裝和管理見 MOD 包:安裝與製作。需要 0.5.3 或更新的版本。

完整的示例是「東方不敗存活」,原始檔在 config/recomp/mods/master-asia:獨立軍線「死鬥!大嶼山大決戰(下)」和 OZ 線「絕望與悲傷之拳(下)」裡,多門在戰鬥中和東方不敗交談過之後可以說服他,擊墜數 50 以上時東方不敗撤退,過關後加入。

包的結構

yourname.story/
  mod.json
  story/
    <任意名>.json     劇情指令碼,可以有幾份
  data/
    pilots.json       需要時順便改數值(見數值 MOD)

打包時(tools/mods/pack.py)story/ 裡的劇情指令碼會被編譯成遊戲讀的格式,寫錯了會報出是哪個事件的哪一項。

寫法

{
  "schema": "srw64.story.v1",
  "events": [
    {
      "id": "persuade",
      "scene": 129,
      "when": { "persuade": { "by": 4, "target": 18 } },
      "if": { "vars": { "131": 0 }, "kills": { "4": 50 } },
      "do": [
        { "say": 4, "text": { "ja": "「師匠!」", "zh-Hans": "「師父!」", "en": "“Master!”" } },
        { "say": 18, "mode": 2, "text": { "ja": "「……」", "zh-Hans": "“……”", "en": "“...”" } },
        { "leave": 18 },
        { "set": { "131": 3 } }
      ]
    },
    {
      "id": "joins",
      "scene": 129,
      "when": { "after": "end" },
      "if": { "fired": ["persuade"] },
      "do": [ { "join": { "pilot": 18, "unit": 27 } } ]
    }
  ]
}

每個事件:

欄位 說明
id 事件名,包裡唯一,別的事件用它引用
scene 哪一關,寫場景號(0–255)。各關的場景號見場景號對照表
when 什麼時候觸發,見下
if 可選,還要滿足什麼
do 做什麼,按順序執行
repeat 可選,寫 true 可以反覆觸發
set_flags 可選,事件跑完時設上的標記,給後面的關用
note 可選,隨便寫說明,遊戲不讀

每個事件每關預設只觸發一次,遊戲自己記,跟著中斷存檔走,不用像原版那樣自己寫變數防止重複播放。

人物號、機體號見數值 MOD 的人物表和機體表。

when:什麼時候

寫法 意思
{"turn": {"turn": 3, "side": "player"}} 第 3 回合起、該陣營的回合開始(player、enemy、third)
{"defeated": 18} 某人物的單位被擊破(離場不算)
{"hp_below": {"who": 18, "percent": 30}} 某人物的 HP 降到 30% 以下
{"battle": {"between": [4, 18], "moment": "after"}} 兩人交戰之後(before 是交戰之前;人物號寫 0 表示任何人)
{"enemies_gone": true} 敵方全滅;寫 {"by_turn": 5} 限第 5 回合以內
{"remaining": {"side": "enemy", "at_most": 3}} 敵方(或 third 第三方)只剩 3 臺以下
{"persuade": {"by": 4, "target": 18}} 4 號站在 18 號旁邊時,指令選單出現「說服」,選了就觸發
{"after": "opening"}、"setup"、"end" 接在這關原版的開場、初期配置、結束事件之後

同一時刻原版也有事件要觸發時,先跑原版的,你的事件在下一次檢查時再看。開場、配置、結束之後的事件不能寫 repeat。

if:還要滿足什麼

寫法 意思
"vars": {"131": 0} 劇情變數(0–199)等於這個值(0–3)。原版用劇情變數記分支,例如場景 129 的 131 號是「多門在戰鬥中和東方不敗說過話」(說過是 0)
"kills": {"4": 50} 我方這個人物的擊墜數至少這麼多
"kills_below": {"4": 50} 擊墜數不到這麼多
"fired": ["persuade"] 本包的這些事件本關已經觸發過
"not_fired": [...] 本關還沒觸發過
"roster": {"pilots": [18], "units": [27]} 這些人物、機體在我方名冊裡(不管出沒出擊)
"not_roster": {...} 都不在名冊裡
"flags": ["persuaded"] 本包的這些標記已經設過
"not_flags": [...] 都沒設過

人物不在我方名冊裡時,kills 和 kills_below 都不成立。

成功和失敗兩套臺詞:同一個時機寫兩個事件,讓條件互斥,遊戲會選符合的那個。示例裡擊墜數夠就成功,不夠就播被拒的臺詞:

{ "id": "persuade", "when": { "persuade": { "by": 4, "target": 18 } },
  "if": { "vars": { "131": 0 }, "kills": { "4": 50 }, "not_fired": ["refused"] }, "do": [] },
{ "id": "refused", "when": { "persuade": { "by": 4, "target": 18 } },
  "if": { "vars": { "131": 0 }, "kills_below": { "4": 50 } }, "do": [] }

被拒的事件只觸發一次,成功的又要求 not_fired: refused,所以被拒之後本關兩個都不成立,選單裡不再出現「說服」,劇情照原版走。想讓玩家能再試,就給被拒的寫 "repeat": true,並去掉成功那個的 not_fired。

跨關:標記

fired 只管本關,到下一關就清空。要讓後面的關知道前面發生過什麼,在事件上寫 "set_flags": ["標記名"](小寫字母、數字、_、-,最多 32 個字),事件跑完時設上。標記只屬於你的包,和原版劇情變數無關,跟著中斷存檔和場間存檔走,開新遊戲才清空。

{ "id": "persuade", "scene": 129, "set_flags": ["persuaded"], "when": { "persuade": { "by": 4, "target": 18 } }, "do": [] },
{ "id": "comes-along", "scene": 81, "when": { "after": "opening" },
  "if": { "roster": { "pilots": [18] }, "flags": ["persuaded"] },
  "do": [ { "say": 18, "text": { "ja": "「ドモン、遅れを取るでないぞ!」", "zh-Hans": "「多門,別落在後面!」" } } ] }

這裡同時看名冊,是因為他之後可能又被原版劇情或別的事件從名冊刪掉;只看標記的話,人不在也會說話。

do:做什麼

動作 意思
{"say": 18, "text": {...}, "mode": 0} 一句臺詞,見下
{"join": {"pilot": 18, "unit": 27}} 人物和機體加入我方
{"remove": {"pilot": 18, "unit": 27}} 從名冊刪掉(單位要先離場)
{"leave": 18} 人物的單位離場(不算擊破)
{"leave_group": 11}、{"deploy": 11} 原版這關的出擊組離場、登場
{"set": {"131": 3}} 設劇情變數
{"if": {"var": 128, "is": 2}, "then": [...], "else": [...]} 按劇情變數分支
{"focus": 18} 鏡頭移到這個人物
{"bgm": 11}、{"sound": 124} 換音樂、放音效
{"fade": "out"}、{"fade": "in"}、{"wait": 30} 淡出、淡入、等待(幀)
{"close": "window"} 關掉對白視窗
{"op": "3D35", "args": [2335, 1]} 原版指令碼指令照寫,見關卡指令碼指令參考。可以直接用原版的臺詞,例如 {"op": "3D40", "args": [43215]}

臺詞:text 必須有 ja,其他語言沒寫的顯示日文(繁體沒寫時用簡體)。一句最多 200 字,閱讀器會自己分頁,不要寫 <STOP>。引號要自己寫,和原版臺詞一樣:日文、繁體用「」,簡體、英文用 「」。mode 是原版對白的顯示方式,地圖上一般我方寫 0、敵方寫 2;世界地圖上 0 和 1 上下交替。

加入的等級:照原版規則取這關的基準等級(由我方前 15 人的平均等級算出)。"level": {"offset": 3} 在基準上加減,"level": {"like": 4} 和 4 號人物同級(按加入那一刻算)。SP、能力、技能、精神由原版按等級算好;基礎值要改就用 data/pilots.json(敵方人物的 SP、精神常常是空的,示例就補了 SP)。

要注意的

  • 原版事件只看原版變數。想讓原版的某段事件不播或者換一段,就要改它判斷的變數。示例裡說服之後寫 131 = 3,原版結束事件只在 131 為 1 或 2 時播東方不敗的死別。
  • 單位離場(leave)不會觸發原版的擊破事件。原版擊破後要做的事(示例裡是王登場、開啟過關條件),要在你的事件裡自己做一遍。
  • 同一段劇情搬到另一關前,先看那關的原版事件:交談用哪個變數、某人被擊破後原版接著做什麼、結束事件按哪些變數播哪些段。示例的 OZ 線事件就是照場景 137 的原版事件改的。
  • 標記存在存檔旁邊(存檔資料夾 saves/ 裡的 story-state/),不在存檔檔案本身裡。把存檔拿到別的模擬器,或者刪掉這個資料夾,讀回來就沒有標記,跨關的事件不會觸發;本關之內的事件不受影響。
  • 追加劇本(campaign/)裡的關卡不跑劇情 MOD。

檢查和打包

python3 tools/mods/story.py compile story/master.json -o out.json
python3 tools/mods/pack.py yourname.story -o build/mods

第一條只編譯一份劇情指令碼,看每個事件編譯出的指令。第二條打包並用和遊戲相同的規則檢查。遊戲讀不了的包會在日誌裡報 SRW64_STORY_MOD_PROBLEM。

倉庫的 docs/guide/story-mods/ 資料夾裡有完整的格式說明和場景號對照表,可以整個交給 AI 助手,讓它照你的想法寫劇情指令碼。