本文章原文來自 http://www.fanicer.com/gallery/FileFmt.htm
以下內容沒有任何刪減及添加,本頁目的是讓更多人看到此文章。
若有任何版權問題,請到留言版留言。
下文分析了CrossGate(魔力寶貝)的文件格式,因為StoneAge(石器時代)和它差不多(最初均為同一小組作品),所以一併介紹。
原文作者為夢見草,由野風信子整理和完善。
一.圖片數據
圖片地址文件
CrossGate |
GraphicInfo*_*.bin |
StoneAge |
Adrn_*.bin |
這個文件存放了圖片的地址索引,由若干個大小一樣的塊組成,每個塊長度為40字節(StoneAge為80字節),格式如下:
字段類型 |
內容 |
說明 |
LONG |
序號; |
圖片的編號 |
DWORD |
地址; |
指明圖片在數據文件中的起始位置 |
DWORD |
塊長度; |
圖片數據塊的大小 |
LONG |
偏移量X; |
顯示圖片時,橫坐標偏移X |
LONG |
偏移量Y; |
顯示圖片時,縱坐標偏移Y |
LONG |
圖片寬度; |
... |
LONG |
圖片高度; |
... |
BYTE |
佔地面積-東; |
佔地面積是物件所佔的大小,1就表示占1格 |
BYTE |
佔地面積-南; |
同上 |
BYTE |
標誌; |
用於地圖,0表示障礙物,1表示可以走上去 |
BYTE[5] |
未知; |
在StoneAge中本字段長度為45字節 |
LONG |
地圖編號; |
低16位表示在地圖文件裡的編號,高16位可能表示版本,非地圖單位的此項均為0 |
其中偏移量XY是用於圖片定位的,比如X=-18,Y=-19,如果將圖片顯示在(100,100),那麼實際位置應該是(82,81),這樣才可以和其它圖片協調,在做人物動作gif的時候必須用這個參數來調整每一幀的位置,否則動作是抖動的,做地圖也需要,否則會錯位。
圖片數據文件
CrossGate |
Graphic*_*.bin |
StoneAge |
Real_*.bin |
這個文件包含了所有圖片的原始數據,每個數據塊由數據頭+數據組成,每個數據頭長度16字節,格式為:
字段類型 |
內容 |
說明 |
BYTE[2] |
魔數; |
固定為'RD' |
BYTE |
版本; |
偶數表示未壓縮,按位圖存放;奇數則表示壓縮過 |
BYTE |
未知; |
... |
LONG |
寬度; |
... |
LONG |
高度; |
... |
LONG |
塊長度; |
數據塊的長度,包括數據頭本身的長度(16BYTE) |
後三項和地址文件中的一樣,圖像數據緊跟在數據頭後面。
例如,要解開第100個圖片,首先在GraphicInfo_*.bin裡定位到第100條記錄,即偏移(40*100)字節的位置,根據讀出的地址在Graphic_*.bin中找到對應的數據塊,就可以讀出圖片數據了。
絕大部分圖片數據都是壓縮過的,算法後面會介紹。
二.動畫信息
動畫地址文件
CrossGate |
AnimeInfo*_*.bin |
StoneAge |
Spradrn_*.bin |
存放每個動畫在動畫序列文件中的地址索引,每個數據塊大小12字節
字段類型 |
內容 |
說明 |
DWORD |
序號; |
動畫序號 |
DWORD |
地址; |
指明在動畫信息文件中的地址 |
WORD |
動作數目; |
表示該角色有多少個完整的動作(包括各個方向) |
WORD |
未知; |
|
動畫信息文件
CrossGate |
Anime*_*.bin |
StoneAge |
Spr_*.bin |
該文件存放了全部動作的圖片序列,每個動作由數據頭+若干序列號組成,數據頭長度12字節。
字段類型 |
內容 |
說明 |
WORD |
方向號; |
0-7分別表示8個方向 |
WORD |
動作號; |
表示該動作的含義,比如坐下或者走路 |
DWORD |
時間; |
該動作完成一遍所需時間,單位為毫秒 |
DWORD |
幀數; |
該動畫有多少幀,決定後面數據的大小 |
某些動作號不是所有角色都有,比如跑步前的準備動作。
有多少幀,後面就跟有多少個序列號,每個序列號長10字節。
字段類型 |
內容 |
說明 |
DWORD |
圖片號; |
該幀所使用的圖片 |
CHAR[6] |
未知; |
... |
圖片號就是該幀所用的圖片序號,用圖片數據裡說的方法就可解出每一幀的圖片數據。。
例如要解出340號角色的1方向的第5個動作,先在AnimeInfo_*.bin中定位到第340號數據塊,即偏移(12*340)字節的位置,讀出地址和動作數,然後根據地址在Anime_*.bin中定位到對應的位置,然後從該位置開始查找方向1動作5的序列,根據幀數讀出每一幀的圖片號,通過圖片號解出對應的圖片就行了。
其中未知的字段表示我還不知道用處的。
注意:CrossGate的動畫序列地址文件AnimeInfo_*.bin,可能由於開發時的某些原因,造成存放了3遍序列,並且按前兩遍解出的動畫是錯誤的,要以第3遍為準,第2375號角色才是第0號,其他的版本沒有這問題。
三.地圖格式
地圖文件就是map目錄下的那些,CrossGate的地圖檔在最前面有12個字節的文件頭,內容為"MAP"(後9字節為0),StoneAge則沒有文件頭,其它完全一樣。
地圖檔格式
字段類型 |
說明 |
DWORD |
地圖長度-東(W) |
DWORD |
地圖長度-南(H) |
BYTE[W*H*2] |
地面的數據,每一個單位2字節,為0表示無地面 |
BYTE[W*H*2] |
地上的物件等,每一個物體2字節,為0表示該處無物件 |
BYTE[W*H*2] |
地圖標誌,每一個單位2字節,具體不清楚,只知道對會引起地圖切換的地方有標識 |
地圖是45度視角的四邊形,數據的存放順序是從東到西,由南至北,起點為左邊角(東0,南0)。
假設讀入的3X3地圖數據順序為123456789,對應的地圖顯示:
這樣讀出來的數據是地圖編號,在
圖片數據中說過,圖片地址文件的每一條記錄的最後一個字段就是地圖編號,現在就是根據這個編號反查出對應的圖片序號,將它顯示出來,由於遊戲本身沒有地圖索引文件(那是在運行遊戲的時候生成的),所以要自制一份方便查找,這裡要注意的是地圖編號並不是連貫的,比如StoneAge最大的編號為41000,實際上用到的只有1萬多點,中間有很多編號是未使用的。
前面說過,每個圖片都有偏移量用於對齊,畫地圖的時候也需要的,不過這裡有點問題,若只是將偏移量加上坐標,地面沒有問題,而建築物縱坐標則會錯位,我並不知道正確的做法,我是這樣處理的:
假設縱坐標偏移量為y,圖片高度h,要畫的坐標為y0,那麼實際的坐標y1就是
y1=y0+h-47+y
47是一個單位地面的高度(所以地面不必這樣處理,因為h-47=0),這樣做可以基本對齊,希望有朋友提供更標準的方法。
另外,關於縮略圖,就是將每個單位(佔地面積1X1)縮成如下的四個點:
□
□□□
如果一個物件面積為2X1,那麼就是
□
□□□□
□□□
縮略圖中每個圖片都只用一種顏色表示,而這個顏色好像也是遊戲自動生成的,所以要做縮略圖的話,自己要製作一份顏色表。
四.壓縮算法
這是JSS自定的一種Run-Length算法,用於StoneAge和CrossGate,下面是說明:
首字節(00) |
01 |
02 |
03 |
說明 |
0n |
String |
|
|
長度為n的字符串 |
1n |
m |
String |
|
長度為n*0x100+m的字符串 |
2x |
y |
z |
String |
長度為x*0x10000+y*0x100+z的字符串 |
8n |
X |
|
|
填充n個X |
9n |
X |
m |
|
填充n*0x100+m個X |
Ax |
X |
y |
z |
填充x*0x10000+y*0x100+z個X |
Cn |
|
|
|
填充n個背景色 |
Dn |
m |
|
|
填充n*0x100+m個背景色 |
Ex |
y |
z |
|
填充x*0x10000+y*0x100+z個背景色 |
比如,C9表示填充9個背景色,D1 10表示填充0x110個背景色,12 50表示後面跟著一個長度為0x250的字符串,91 02 30則表示將0x02重複0x130遍。
五.調色板
StoneAge的調色板文件是位於data/pal目錄下的palet_*.sap,CrossGate的則為bin/pal目錄下的palet_*.cgp,每個文件長度均為708字節,每種顏色3字節,所以每個文件都包含了236種顏色,要注意的是它不是從0號顏色開始排列的,而是從16號,即16-252,但實際上是16-240,前16種顏色和後16種顏色都是指定,文件中的240-252號顏色並沒有使用,下面是指定的32種顏色:
0-15號色
顏色號 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
RGB值 |
(00,00,00) |
(00,00,80) |
(00,80,00) |
(00,80,80) |
(80,00,00) |
(80,00,80) |
(80,80,00) |
(C0,C0,C0) |
顏色號 |
8 |
9 |
A |
B |
C |
D |
E |
F |
RGB值 |
(C0,DC,C0) |
(F0,CA,A6) |
(00,00,DE) |
(00,5F,FF) |
(A0,FF,FF) |
(D2,5F,00) |
(FF,D2,50) |
(28,E1,28) |
240-255號色
顏色號 |
F0 |
F1 |
F2 |
F3 |
F4 |
F5 |
F6 |
F7 |
RGB值 |
(96,C3,F5) |
(5F,A0,1E) |
(46,7D,C3) |
(1E,55,9B) |
(37,41,46) |
(1E,23,28) |
(F0,FB,FF) |
(A5,6E,3A) |
顏色號 |
F8 |
F9 |
FA |
FB |
FC |
FD |
FE |
FF |
RGB值 |
(80,80,80) |
(00,00,FF) |
(00,FF,00) |
(00,FF,FF) |
(FF,00,00) |
(FF,80,FF) |
(FF,FF,00) |
(FF,FF,FF) |
說一下常用的幾個調色板:
|
白天 |
傍晚 |
黑夜 |
凌晨 |
StoneAge |
palet_01.sap |
palet_02.sap |
palet_03.sap |
palet_04.sap |
CrossGate |
palet_00.cgp |
palet_01.cgp |
palet_02.cgp |
palet_03.cgp |
六.各版本對應的文件
CrossGate每個大版本都有相對獨立的文件,比如最初的版本圖片數據文件是Graphic_*.bin等,而龍沙的則是GraphicEx_*.bin,附加上了"Ex",下面是各個版本所使用的附加名。
版本 |
附加名 |
龍之沙時計 |
Ex |
樂園之卵(精靈) |
V3 |
樂園之卵 |
_PUK2 |
七.後續版本的改動
這裡說的是CrossGatePuk2(樂園之卵)的數據格式變動。
樂園之卵中的圖片不再使用全局調色板,靜態圖片都自帶調色板,動畫則是用隱藏調色板。
首先是自帶調色板,圖片數據中的文件頭被擴充至20字節,且版本字段大於等於2(之前的為0和1)。
字段類型 |
內容 |
說明 |
BYTE[2] |
魔數; |
固定為'RD' |
BYTE |
版本; |
偶數表示未壓縮,按位圖存放;奇數則表示壓縮過 |
BYTE |
未知; |
... |
LONG |
寬度; |
... |
LONG |
高度; |
... |
LONG |
塊長度; |
數據塊的長度,包括數據頭本身的長度(20BYTE) |
LONG |
調色板長度; |
調色板數據所佔的長度,通常為0x300,即256*3=768 |
還原後的數據最後那部分則是自帶的調色板數據,大小和調色板長度字段的內容相同。
隱藏調色板本身其實是一些4X1的自帶調色板的圖片,它們的地圖編號字段被重新解釋了,表示使用這個調色板的動畫序號,比如地圖編號為0x1B680,那麼在還原第0x1B680號動畫的時候,就要使用該圖片所帶的調色板。
隱藏調色板存在於GraphicInfoV3_*.bin中,即使是AnimeInfo_PUK2_*.bin中的動畫也是使用這裡的調色板,從3840幅圖片開始是隱藏調色板,不過並不是全部連續存在的,所以需要判斷,除了寬4高1外,普通圖片的地圖編號高位為0或者3(樂園版本的地圖),調色板的則不是,可以依此辨別。
樂園之卵的動畫也有很大改變,同一類型的各種寵物,以前是各自有獨立的圖片,現在是通過改變調色板來區別的(我認為如果能將玩家角色這樣簡化就好了,寵物反而不應這樣),方向也簡化了,右邊的三個方向是左邊對稱過去的,這是一種偷工減料,不過也減少了文件的體積……同時也導致了數據格式的改變。動畫信息文件中的數據頭結構變化:
字段類型 |
內容 |
說明 |
WORD |
方向號; |
0-7分別表示8個方向 |
WORD |
動作號; |
表示該動作的含義,比如坐下或者走路 |
DWORD |
時間; |
該動作完成一遍所需時間,單位為毫秒 |
DWORD |
幀數; |
該動畫有多少幀,決定後面數據的大小 |
WORD |
調色板號; |
沒完全弄清楚,我不用它來判斷 |
WORD |
反向; |
若為奇數表示該序列的圖片左右反向 |
DWORD |
未知; |
為0xFFFFFFFF,可能是結束符,便於以後再擴充? |
要提取樂園之卵後的圖片和動畫,就必須用以上新的格式。地圖的格式本身沒有變化,不過增加了附屬的文件,主要是和圖片分割有關…… 目前沒有研究,所以沒有資料了。