红楼梦十二金钗游戏资源分析(四)

我们离正确画出第一张图只剩下调色板了,让我们继续吧

调色板的简易说明

我们知道每种颜色由红绿蓝三种颜色混合而成,这三种颜色值由六位二进制数字设定, 所以取值范围是 00h3fh,红绿蓝三色的数值确定后, 我们就可以知道这是什么颜色。由于程序同屏显示的最大颜色数是 256, 所以内存中一定会存储这 256 种颜色的三原色数值。

我查阅了一些 VESA 的资料,设置调色板基本还是靠调用寄存器, 但是这部分指令在日志中却没有找到, 所以我推测可能程序已经提前映射好了调色板的地址, 可以直接修改调色板而无需再调用寄存器,因为我的 cpu log 是从游戏中记录的, 而不是从头完整记录,从内存看来是不好下手了,我们看一看文件中是否有新的发现。

EVENT.PAT

我们通过搜索第一张图的读取内容,可以得知,图片保存的起始位置是 00071dh, 好巧不巧, EVENT.PAT 00033dh 附近有这样一串数字:

Untitled

因为前面有几行 00h,所以这个位置还比较明显,00071dh 正好是图片的起始位置, 而他的前面又是 3f 3f 3f,看到这里我们可以会心一笑,这是白色。

所以调色板到 033dh(不含)结束,256 色的调色板应该会占用 300h (注意是 16 进制)个字节,那么,调色板的起始位置应该是 003dh

Untitled

第一个颜色是 002100h,虽然跟我预期第一个应该是黑色 000000h(位置 003ah) 不太一致。简单扫了一下数据,没看到大于 3f 的数值, 那么这段数据应该就是调色板了,我们画一画试试:

test-origin-0x3d.png

人物是正确的,但是背景色一塌糊涂,难道调色板真的是从 003ah 开始, 虽然我不太相信,不过谨慎起见,从 003ah 画一次也不难:

test-origin-0x3a.png

这个错得就更多了,所以应该还是 003dh 开始, 而且程序要么对调色板进行了一些特殊处理,要么就是我们找错了调色板。

有个事情顺带提一下,之前在分析大富翁三时也讲过,因为现在我们表示颜色一般是用 8 位二进制显示了, 也就是 0-255,6 位颜色是 0-63,所以我们需要将 6 位颜色「放大」到 8 位, 不然画面会非常暗。

文件读取

前面也说了,直接通过寄存器的方式去查日志没有什么结果,所以这次我们搜搜看, 程序读取调色板后是如何处理的,我们在日志中搜索 int 21.*3f

Untitled

前面三条指令一共读取了 01b342h 个字节,回忆我们上一期的内容, 第一张图片读取的长度是 111426,也就是 01b342h,所以前三个读取了完整的图片, 那么为什么后面又读取了 150h 个字节呢。

回到 EVENT.PAT

我们回到 EVENT.PAT 的 00033dh 的位置:

Untitled

在这里我们还能发现更多对后续有帮助的信息, 比如 1d 07 00 00 其实是第一张图的起始位置,80 02 其实是图像宽度, 67 01 是图像高度,接下来这个 af bb 01 00 很可能就是第二张图的起始位置了, 这样我们可以算出第一张图的长度,01bbafh - 00071dh = 01b492h, 对比图片长度 01b342h,正好多了 150h 字节, 我们看看这 150h 个字节到底存了什么:

Untitled

我们又看到了 3f 3f 3f,看来这 150h 个字节就是我们要找的另一块调色板, 不过另外一个问题接踵而来。

两个调色板如何合并

144 + 112 = 256

150h 换成十进制是 336,只有 112 种颜色,那么如何跟第一块调色板合并, 这就变成了我们新的问题,一个近乎直觉的做法是:因为第一块调色板是完整的, 而且后面用 0 来填充了很多,所以这 112 色是第一块调色板后半块的补充。 这样的话,我们需要用第一块调色板的前 144 种颜色加上这 112 种颜色, 组成一块新的调色板,我们画画看:

test-144-112.png

还是不对,那么是不是应该把第二块调色板放在前面呢,也不对,这里就不再放图了。

回到日志

我们回到程序读取第二块调色板的日志:

0277:00000D0C  int  21                                                EAX:00003F50 EBX:0001000A ECX:00000150 EDX:1BF28180 ESI:00000070 EDI:0000578C EBP:00005738 ESP:00005734 DS:04FF ES:028F FS:0000 GS:0000 SS:028F CF:0 ZF:0 SF:0 OF:0 AF:0 PF:1 IF:1

内容被读取到了 04FF:8180 的位置,然后搜索 rep.*8180.*04ff, 看有没有再被复制到哪里:

0277:00001D10  repe movsb                                             EAX:00030150 EBX:00005800 ECX:00000150 EDX:00000287 ESI:00008180 EDI:000022F8 EBP:0000580E ESP:00005800 DS:04FF ES:0287 FS:0000 GS:0000 SS:028F CF:0 ZF:0 SF:0 OF:1 AF:1 PF:1 IF:1

复制到了 0287:22f8,那么索性我们搜程序有没有复制 300h 个字节, 我们在日志中搜 rep.*cx:....0300

Untitled

0287:21a8028f:556e 复制 300h 个字节,看上去和上面的内存地址有交集?

我们用 22f8h 减去 21a8h,正好也是 150h,这下似乎一切就明朗了, 在第二个调色板前面,还有 112 个颜色,我们也很好猜这 112 个颜色从哪里来。

总结

调色板似乎不是分两部分,而是三部分:

  1. 第一部分:EVENT.PAT 00003dh 开始,虽然完整定义了全部调色板,但是仅有前 112 色用于绘制人物。
  2. 第二部分:每个图片后定义了 112 色,用于绘制图片中的独有颜色。
  3. 第三部分:剩余 34 色,目前没有涉及,推测是用于绘制 UI 区域和鼠标。

最后,我们再次合并两个调色板,验证下我们的结论吧:

test.png