六代六種做法
技術篇
選哪條路,取決於手上有什麼。有可用的原始碼就移植,有維護中的開源引擎就修改,兩者都沒有就反組譯原版,再自己寫一個引擎。
| 代 | 手上有什麼 | 做法 | 主要風險 |
|---|---|---|---|
| I | 開源重製 open_ultima,但只有世界地圖、基礎地牢和地面戰鬥 | 接手後中文化,把缺的遊戲內容補完 | 上游太早期,補完等於寫半個遊戲 |
| II | 一個 Windows 移植版執行檔,沒有符號 | Ghidra 反編譯當行為參考,引擎手寫 | 反編譯碼纏著 MFC,不能直接用 |
| III | LairWare Mac 版的 MIT 原始碼 | 用 SDL2 重建 Mac API,遊戲邏輯幾乎不改 | Classic Mac 程式的 32 位元假設 |
| IV | 維護中的開源引擎 xu4 | 掛在引擎的文字出口,載入時查表換成中文 | 文字路徑不只一條 |
| V | 沒有可用的引擎,只有原版 | IDA Pro 反組譯當真值,Go 從零重寫 | 全部遊戲邏輯都要自己寫 |
| VI | ScummVM 的 Nuvie 引擎 | 給引擎加補丁,載入時查表換成中文 | 對話虛擬機和 Big5 衝突 |
共同原則:不把中文寫回原版檔案
老遊戲的資料檔靠固定位移找字串。把一句英文換成長度不同的中文,後面的內容全部錯位。所以 II 到 VI 代都讓原版資料保持唯讀,譯文放在外部檔案,執行時再覆蓋上去。查不到譯文就退回原文,畫面不會缺字。
這樣做還有一個好處:專案可以公開程式碼和譯文,不必散布原版資料,玩家自備就好。
有原始碼:III 代用 SDL2 重建 Mac API
LairWare 的 Mac 版是 C 寫的,遊戲邏輯很完整,綁定 Mac 的部分集中在繪圖和視窗。專案在 src/compat/ 用 SDL2 重建 QuickDraw 和 Toolbox 的函式,上游程式幾乎不改就能編譯。
文字的路也很短:全遊戲的繪字都走 UDrawThemePascalString,換掉這一處,所有文字就都是中文。
代價是 Classic Mac 的舊習慣。上游大量使用 "\p..." 這種 Pascal 字串,要用 clang 的 -fpascal-strings 編譯。還有一個藏得很深的錯誤,寫在驗證那一篇。
有開源引擎:IV 代選 xu4
IV 代最初評估的是 u4remastered,比較後放棄:
| u4remastered | xu4(採用) | |
|---|---|---|
| 技術 | C64 的 6502 組合語言,23,101 行 | C++、Allegro 5 |
| 平台 | 只有 Commodore 64 | Linux、Windows、Mac 原生 |
| 文字 | 單位元組,8×8 字元,每行 16 字 | 可以 16 位元碼位 |
| 中文化 | 要從零重寫引擎 | 掛在文字出口即可 |
u4remastered 的 talk.json 修過數十個對白錯誤,後來拿來當翻譯底本。xu4 遊戲內的捲動文字都經過 screenMessageN,掛在這裡就涵蓋主要文字。麻煩在商店:中文住在 Boron 腳本裡,走另一條路徑,一連串錯誤直到實機測試才現形。
有引擎但不能改資料:VI 代的 Plan B
VI 代第一個想法是直接把 Big5 寫進對話腳本。這個虛擬機把 0xA1 到 0xFE 當作指令,而 Big5 的第一個位元組剛好落在同一段。試了六個判別方法,還是有解決不了的邊界情況。
Plan B 放棄改腳本。虛擬機照常跑英文,輸出前用英文原句查表,換成中文。不會有對齊問題,譯文長度也不受限。缺點是輸出路徑有好幾條,漏掉一條就漏出一處英文,最後用到八個掛鉤點。戰鬥訊息裡的人名是執行時才決定的,整句查不到,又加了片段替換表。
只有執行檔:II 代和 V 代
這兩代都把反編譯當對照來源,不照抄。專案裡稱它為 oracle,意思是拿來問「原版在這裡會怎麼做」的標準答案。
II 代的對象是 John Alderson 的 Windows Native Ultima II,約 46,000 行 Ghidra 反編譯結果,夾著 MFC 執行環境。真正有用的是演算法:亂數公式、戰鬥命中、地牢格式、行星座標。引擎另外用 SDL2 寫乾淨版。
V 代的規模最大。DOS 版是 16 位元,只能讀組合語言。FM Towns 版是 32 位元的 Phar Lap 格式,IDA 的 Hex-Rays 可以反編譯成 C,所以遊戲邏輯都從這一版讀。同一張光碟上還有日文和英文兩個執行檔,兩者的差異就是雙位元組文字路徑。
反編譯結果也不能全信。實際踩過三種錯誤:把可寫的全域變數當常數,整段函式被摺成一行;參數列是空的,函式被安靜截斷,後面的機制整個不見;把全域變數傳播成字面值,看起來像「只有第一格有效」。遇到這些形狀就要回去讀組合語言。
來源:u2-cht 工程文件、u3-cht 在地化筆記、u4-cht README、u4-cht 商店文字、u5-cht 專案憲章、u6-cht README。