速查 › 字型檔 .ffn

字型檔 .ffn

遊戲畫面上的每一個字都來自 data/fonts/fonts.big 裡的 12 個點陣字型。 這頁除了講格式,還會用這個檔把「孤兒資料到底怎麼產生的」完整證明一次 —— 它剛好留下了一組算得清清楚楚的證據。

這一份被改過

本站測試機的 fonts.big 檔案日期是 2022 年 11 月, 不是 2005 年的原廠狀態(判斷方法見模型那頁)。

所以這頁描述的是「這個檔案現在長什麼樣」。 這反而讓它成為很好的教材 —— 因為改動的痕跡都還在裡面。

先看規模

項目數字備註
檔案大小397,327 bytes388 KB。以封裝檔來說算小的,但不是最小
字型數12 個全部是 .ffn
目錄涵蓋率37.0% 剩下 250,411 bytes 沒被指向 —— 這頁後半會解釋那是什麼
解壓後合計777,520 bytes759 KB
不重複的內容9 種12 個檔只有 9 種內容

上面每個數字都是把 fonts.big 現場解開數出來的,不是引用他人資料。

兩種檔頭代號,大小寫不一樣

把 12 個字型解開後看開頭四個位元組,只有兩種:

46 4E 54 46   =  FNTF
46 6E 74 46   =  FntF      ← 中間兩個字母是小寫

大小寫跟「有沒有壓縮」完全對應

代號檔數外層是否 QFS 壓縮
FNTF5全部沒壓縮
FntF7全部有壓縮

12 個檔零例外。 所以看到 FntF 就知道它外面包了一層 QFS,看到 FNTF 就是直接讀。

檔頭第 9-10 個位元組也跟著分群:FntF 那七個全部是 414FNTF 那五個是 317 到 366 之間。 推測 看起來像是格式版本號,但本站沒有證實。

檔頭自己寫著檔案多大

第 5 到 8 個位元組是一個數字,跟解開後的實際長度比對:

字型代號解壓後大小檔頭宣告結果
Tw24_en.ffnFNTF4,0484,048相符
frk12_en.ffnFNTF17,10417,104相符
au20b_en.ffnFNTF18,00018,000相符
twcnb_en.ffnFNTF14,92814,928相符
hrdbg_en.ffnFntF72,54472,544相符
mini1_en.ffnFntF133,216133,216相符
mini2_en.ffnFntF264,288264,288相符
twc14 / 16 / 18FntF各 72,544各 72,544相符
dflt_en.ffnFNTF14,60813,520差 1,088
twn14_en.ffnFntF21,15220,064差 1,088

12 個裡有 10 個完全相符。剩下兩個各多出 1,088 個位元組 —— 部分已解 兩個差距一模一樣,不像隨機出錯。本站後來把那 1,088 個位元組打開看,得到三件事:

不是填充 開頭是 ff ff ff 04ff ff ff 05ff ff ff 06… 這種規律遞增的結構,不是一片 0
其中一個帶著標記 EAGL64
EAGL 是 EA 的圖形函式庫, 動畫那頁也出現過
兩個尾巴不一樣 逐位元組比對 90.8% 不同 —— 所以不是同一塊資料被複製兩份

還是不知道它是什麼,但至少知道它不是垃圾: 是兩塊各自不同、有結構的資料,接在宣告的長度後面。 仍未解

FSH 圖片音訊索引一樣, 這是又一個「格式自己帶著驗算方法」的例子。

12 個檔,只有 9 種內容

四個檔的內容完全相同

hrdbg_en.ffn
twc14_en.ffn      ← 這四個解開後
twc16_en.ffn         位元組完全一樣
twc18_en.ffn

都是 72,544 bytes,內容一個位元組不差。 名字看起來是 14、16、18 三種不同字級,實際上裝的是同一份東西。

推測 這是替換字型時常見的做法: 為了讓所有地方都顯示同一套字,把同一個字型檔複製到好幾個名字上。 但本站無法確認是誰、什麼時候做的。

孤兒資料是怎麼產生的:一個算得清楚的例子

前面說這個檔有 250,411 bytes 沒被目錄指向。 其中有三段大小完全相同

[189,700 → 252,239)   62,539 bytes
[262,244 → 324,783)   62,539 bytes
[334,788 → 397,327)   62,539 bytes

三段一模一樣大,這不會是巧合。看看它們前面各接著什麼:

目錄指向的項目佔用後面接著的空隙兩者相加
twc14_en.ffn10,00562,53972,544
twc16_en.ffn10,00562,53972,544
twc18_en.ffn10,00562,53972,544

72,544 正好是這三個字型解壓後的大小。

決定性的一步

如果推論成立 ——「原本這裡放的是未壓縮的 72,544 bytes, 後來被壓縮成 10,005 bytes 蓋在前面」—— 那麼那段空隙應該恰好等於 解壓後資料的第 10,005 個位元組之後的部分

本站直接比對:三段全部逐位元組相同,62,539 bytes 一個不差。

所以整件事的經過是這樣:

原本            [────────── 未壓縮字型 72,544 bytes ──────────]

改過之後        [壓縮版 10,005][──── 原本資料的後半段 62,539 bytes ────]
                 ↑
                 目錄現在只指到這裡,後面那段沒人認領

這就是「孤兒資料」的真面目

不是垃圾,也不是損壞。是舊資料沒被覆蓋掉的那一部分。

改檔的人把新版本寫進原本的位置、更新目錄的長度, 但沒有(也不需要)把後面清乾淨。 檔案於是一層一層留下痕跡。

比賽介面檔 ingame.big 也有同樣的現象,規模更大 —— 本站測試機那一份有 92.6% 是這種資料(剛安裝好的原版只有 0.04%),故事見 一個檔案裡的地層

中文字型走的是「日文」那個槽位

原版 12 個字型的檔名全部_en 結尾。 本站另外打開一份 2023 年的中文懶人包,同一個封裝檔長這樣:

⚠️ 這張表跟上面那張不要直接對數字,兩件事都不一樣: 上面那張量的是本站測試機那份 2022 年被改過的 fonts.big,欄位是解壓後大小; 這張量的是剛安裝好的原版與中文包,欄位是封裝檔內佔用。 所以同一個檔名在兩張表會出現兩個數字(Tw24_en.ffn 上面 4,048、這裡 5,751; au20b_en.ffn 上面 18,000、這裡 57,617)—— 差的不只是口徑,連檔案本身都被換過了,那正是本頁開頭「這一份被改過」在講的事。 同理,〈先看規模〉那個「解壓後合計 777,520」也是測試機那份,跟這一節的 204,523 不同口徑。

原版封裝檔內佔用 中文包封裝檔內佔用倍數
twcnb_en.ffn14,525 twcnb_jp.ffn180,07912×
au20b_en.ffn57,617 au20b_jp.ffn304,485
Tw24_en.ffn5,751 Tw24_jp.ffn140,88224×
frk12_en.ffn27,618 frk12_jp.ffn140,882
dflt_en.ffn5,815 dflt_en.ffn(沒改,而且另外多一個 dflt_jp.ffn 5,815
原版12 個字型204,523 bytes全部 _en
中文包13 個1,683,191 bytes 12 個 _jp + 留著原本的 dflt_en

這跟另一頁的發現是同一招

EA 官方繁體中文版那一頁量到: 官方的中文不是覆蓋英文,而是放進日文的槽位IGJPN.LOCFEJPN.LOC)。

字型這裡是一模一樣的做法:中文字型檔名結尾是 jp兩件事互相印證 —— 這個遊戲要顯示中文,走的是它原本給日文的那條路。

為什麼是日文槽位?合理的猜想是「日文本來就要顯示漢字, 那條路上的字型與編碼處理現成可用」。 但這是推想,檔案裡沒有寫。推測

2026-08-28 補上實測 「只能借現成語系的位子」這件事,現在有執行檔層的證據了。 組字型檔名的那段程式(0x004FE860)是 「名字表[編號] + 語系後綴.ffn」, 而語系後綴來自 0x004FE9BC 的一張跳表,只有四種

case 0、1 → "_en"    case 2 → "_sp"
case 3、4 → "_jp"    case 5 → "_es"

裡面沒有中文。所以不管是官方版走 _jp、 還是社群包蓋掉 _en,都不是偏好,是只有這幾個位子可以借。 這一頁原本是從檔名推出這件事的,兩邊互相印證。

⚠️ 另外要注意社群的中文包不只一份,動的槽位也不一樣, 所以不同頁的字型總量對不起來是正常的:

哪一份檔名結尾幾個
EA 官方繁體中文版(本節這張表量的就是它)
⚠️ 2026-08-30 訂正:這一列原本被拆成兩列 (「2023 年的中文懶人包」與「EA 官方繁體中文版」各一列,一列寫組成、 一列只寫 13)。那是同一個檔 —— 本機那份 2023 中文懶人包裡的 fonts.big 跟剛安裝好的官方繁中版逐位元組相同: 兩份都是 1,683,513 個位元組、13 個項目,SHA-256 前 12 碼同為 a5c92f50616f。也就是說那個懶人包直接沿用 EA 出貨的字型檔, 一個位元組都沒改。
_jp12 個 _jp + 留著 dflt_en = 13
_jp 的社群合包(另一份,不是上面那個) _jp13(其中 12 項 跟 EA 出貨那份逐位元組相同,只有 hrdbg_jp.ffn 不一樣)
中文版配大球場就跳出那一課量的那份社群包 _en12(直接蓋掉英文字型)

上表第二列那份合包,官方繁中版那一頁 量到它 13 個項目裡有 12 個跟 EA 出貨那份逐位元組相同 —— 它是拿官方的字型來用,不是自己做的。
本機能拿到的 fonts.big 全部量過一輪,去掉內容重複的一共七種。 走 _jp 的有兩種:上表第一列那份(1,683,513)與上表第二列 那份合包(1,686,625),兩者只差一個 hrdbg_jp.ffn。 其餘五種都是 12 個 _en 的路線(英文原版 204,820/ 2009 台灣模組 1,279,340/測試機現況 397,327/Taiwan_English_1X 420,650/ 另一份 2007 年的轉播畫面模組 351,434)。

所以你的遊戲能不能顯示中文,看檔名跟大小就知道

打開 data\fonts\fonts.big,看裡面的檔名結尾與合計大小

全部是 _en,合計約 200 KB沒裝中文字型
出現 _jp,合計超過 1 MB裝過中文字型了
全部是 _en,但合計遠超過 200 KB(例如 1.2 MB) 也裝過中文字型了 —— 那是直接蓋掉英文槽位的社群包 (中文版配大球場就跳出那一課量的那份就是), 檔名分不出來,要看大小
python mvp_fel_toolkit.py "你的遊戲資料夾" --big data\fonts\fonts.big --entries

工具在介面萬用工具那一課。 更完整的說明在 怎麼看出哪些檔還沒被動過

能改到什麼程度

你可能想做的事現況
知道遊戲用了哪些字型、多大 完全可改 檔頭讀得懂,本頁的表就是這樣來的
把某個字型換成另一個現有的 可以替換 四個檔內容相同就是這樣做出來的
自己做一個新字型 未解 字圖集與字元表讀得出來(見下面的訂正), 但本站沒有從零產生一份、再寫回去的辦法
加入原本沒有的字(例如中文字) 未解 同上,而且字圖集與字元表要一起

誠實邊界

本站解出的是容器層:有幾個字型、各多大、壓縮與否、檔頭前 10 個位元組怎麼讀。

⚠️ 2026-09-05 訂正:字符本身後來解開了。 這裡原本寫「字符本身長什麼樣、怎麼對應到文字編碼,本站沒有解讀」,那句已經不成立: 圖片的像素怎麼排那頁量到 au20b_en.ffn 裡有一張 格式 0x79、256×128、每個像素半個位元組的字圖集,後面接著一張 16 筆的 0x2A 調色盤;中文版配大球場就跳出 那一課把中文字型的字圖集(0x79、1024×512)與整張字元表讀了出來, 數到字型提供 1,529 個字,拿去跟中文語系檔用到的 1,536 個字對帳。

仍然沒解的是「從零產生一張新的字圖集與一張新的字元表、再寫回去」 —— 所以這頁能幫你判斷與替換,不能幫你造字。

📌 重點整理

接下來