『整理』魔力宝贝Bin文件格式&图像压缩格式(下)
这是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遍。
RLE压缩方式,具体的压缩编码如下:
0a xx xx xx
a 个单独的颜色点
1a bb xx xx xx
abb 个单独的颜色点
2a bb cc xx xx xx
abbcc个单独的点
Ca
a 个透明色
Da bb
abb 个透明色
Ea bb cc
abbcc个透明色
8a xx
a 个颜色是XX的点
9a xx bb
abb 个颜色为xx的点
Aa xx bb cc
abbcc 个颜色为xx的点
以graphics_10.bin(图像压缩数据文件)为例,一幅图像的结构如下:
typedef struct
{
WORD fmtflag; //全部为"RD"
WORD unknow; //不知道什么用
DWORD width;
DWORD height;
DWORD size; // 整个结构大小,就是头+压缩数据
unsigned char * pdata; // 大小为(size - 16)
}st_RDHeader;
另外还有一个GraphicInfo_10.bin(图片信息索引数据),具体结构如下:
typedef struct
{
int idx; //索引号,基本上是按照顺序排列的
DWORD fileptr; //在数据文件中的偏移量
DWORD size; //大小,整个图像结构的大小,同上一个结构的SIZE
int ofs_x; //x偏移量
int ofs_y; //y偏移量,就是对齐点离坐上角的y 轴距离
DWORD width;
DWORD height;
DWORD colorkey; //随便猜得,不一定正确
DWORD unuse1;
DWORD unuse2;
}st_GrpInfo; // 40 bytes
其他情况,没有压缩
所有的a ,b ,c 都是表示单个十六进制数字。基本上超过3个点一样就用8a xx 了。
关于3.0的魔力宝贝添加的图片其实还是8位色的图片。按照8位色的图片解出来就行了,她不过是用了16位色的显示模式(其实是任何显示模式都可以)。另外,调色板前面的16个位置丢掉了,就是说实际上调色板是存储了后236个颜色的数值。
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' |
2
|
| BYTE | 版本; | 偶数表示未压缩,按位图存放;奇数则表示压缩过 |
1
|
| BYTE | 未知; | ... |
1
|
| LONG | 宽度; | ... |
4
|
| LONG | 高度; | ... |
4
|
| LONG | 块长度; | 数据块的长度,包括数据头本身的长度(20BYTE) |
4
|
| LONG | 调色板长度; | 调色板数据所占的长度,通常为0x300,即256*3=768 |
4
|
还原后的数据最后那部分则是自带的调色板数据,大小和调色板长度字段的内容相同。
隐藏调色板本身其实是一些4X1的自带调色板的图片,它们的地图编号字段被重新解释了,表示使用这个调色板的动画序号,比如地图编号为0x1B680,那么在还原第0x1B680号动画的时候,就要使用该图片所带的调色板。
隐藏调色板存在于GraphicInfoV3_*.bin中,即使是AnimeInfo_PUK2_*.bin中的动画也是使用这里的调色板,从3840幅图片开始是隐藏调色板,不过并不是全部连续存在的,所以需要判断,除了宽4高1外,普通图片的地图编号高位为0或者3(乐园版本的地图),调色板的则不是,可以依此辨别。
乐园之卵的动画也有很大改变,同一类型的各种宠物,以前是各自有独立的图片,现在是通过改变调色板来区别的(我认为如果能将玩家角色这样简化就好了,宠物反而不应这样),方向也简化了,右边的三个方向是左边对称过去的,这是一种偷工减料,不过也减少了文件的体积……同时也导致了数据格式的改变。动画信息文件中的数据头结构变化:
| 字段类型 | 内容 | 说明 |
字节
|
| WORD | 方向号; | 0-7分别表示8个方向 |
2
|
| WORD | 动作号; | 表示该动作的含义,比如坐下或者走路 |
2
|
| DWORD | 时间; | 该动作完成一遍所需时间,单位为毫秒 |
4
|
| DWORD | 帧数; | 该动画有多少帧,决定后面数据的大小 |
4
|
| WORD | 调色板号; | 没完全弄清楚,我不用它来判断 |
2
|
| WORD | 反向; | 若为奇数表示该序列的图片左右反向 |
2
|
| DWORD | 未知; | 为0xFFFFFFFF,可能是结束符,便于以后再扩充? |
4
|
要提取乐园之卵后的图片和动画,就必须用以上新的格式。地图的格式本身没有变化,不过增加了附属的文件,主要是和图片分割有关……