文章 15
评论 3
浏览 65386
PS1 月下夜想曲 Best 版本研究(一):日版 SLPM_860.23 为什么是最佳底本

PS1 月下夜想曲 Best 版本研究(一):日版 SLPM_860.23 为什么是最佳底本

缘起:先决定改哪个版本

给《恶魔城:月下夜想曲》做改造——改数值、改 Boss 行为、加新招式——第一个问题其实不是「怎么改」,而是「改哪个版本」。

手头是日版 SLPM_860.23,而开源编辑器 SotN-Editor 只认美版 SLUS_000.67。两个可执行文件都是 563200 字节,乍看差不多。真正逐字节比对之后才发现:99.9% 相同,但有 633 段很短的差异,而且全局变量地址整体偏移了 8 字节。

8 个字节,足够让所有硬编码地址的改版工具在新版本上静默出错。

这篇记录我们把这套工具改造成日美双版本支持的过程与依据。

一、三个版本的基本盘

项目美版 SLUS_000.67日版 SLPM_860.23
PSX 可执行文件563200 字节563200 字节
DRA.BIN(游戏覆盖层)1153136 字节1139408 字节
BIN/F_GAME.BIN(公共图形)270336 字节内容相同
地图数据 ST/、BOSS/58 个同结构,大小略有差异

区域判定只要看两处:

  1. PSX-EXE 文件头里的字符串:美版是 for North America area,日版是 for Japan area;
  2. DRA.BIN 的第一个双字(主函数指针):美版 0x800E3988,日版 0x800E3AA0。

二、差异一:EXE 几乎一样,救了大命

两个可执行文件的加载基址和代码段布局完全一致,所以原编辑器里所有指向 EXE 内部的地址——LOAD_IMAGE_ADDR、VSYNC_ADDR、SPU_INIT_ADDR 等等——在日版里一个都不用改。

这是整个适配能在一个晚上跑通的前提。

三、差异二:全局变量整体后移 8 字节

代码几乎一样,但日版的数据段 / BSS 比美版大 8 字节,于是所有被游戏代码引用的全局变量地址都 +8。

验证方法是笨办法,但可靠:在美版代码里找出所有地址装载指令(lui + addiu 的组合),用 32 字节唯一片段把它们映射到日版代码,再读日版指令里的立即数。

结果:

  • 共 685 个全局地址成功映射;
  • 129 个差值为 +8,39 个为 +16,9 个为 +12——说明数据段中间还有几处小的插入;
  • 编辑器实际用到的全局变量全部落在 +8 区段。

举几个例子:

用途美版日版
Alucard 实体 / 实体列表起点0x000733D80x000733E0
多边形列表0x00086FEC0x00086FF4
房间图块索引0x000730840x0007308C
Alucard Z 深度0x000974080x00097410

其中多边形列表那一组在日版代码里有 138 处互相印证,实体列表起点有 22 处——可信度非常高。

四、差异三:DRA.BIN 是「分段重排」的

DRA.BIN 加载到 0x800A0000,两版内容差异极大,只有 17% 的字节相同。但结构一致:它是若干段数据与代码的拼接,日版在中间插入或删除了少量数据,于是不同区段的偏移差在 0、+8、+108、+332、+356、-424、-64 之间跳。

所以不能整体平移,只能一张表一张表地对齐。好在每种表都有可以校验的特征:

  • 武器名表:0x34 步长,前两个指针指向 Shift-JIS 文本;
  • 装备表:0x20 步长;
  • 敌人数据表:0x28 步长,带 0x7FFF 常量;
  • CLUT:1024 字节逐字节比对,错位后 100% 相同。

五、最容易翻车的地方:文本有两种编码

这是整个适配里最反直觉的一块。日版文本不是同一种编码:

说明文字(描述)是真 Shift-JIS。 比如武器说明「半魚人を召喚して攻撃する【消費】」,标准 CP932,以 0x00 结尾。

物品名 / 敌人名不是 Shift-JIS,而是游戏自造的一字节字模编码:

  • 0xA1–0xDF:半角片假名(与 Shift-JIS 单字节区一致);
  • 0x20 / 0x00:空格;
  • 其它值:游戏内部汉字字模的索引,没有字模表就无法还原。

实测解码:

原始字节解码含义
C7 C9 C9 CC B8ヌノノフク布の服
B6 DC C9 D1 C8 B1 C3カワノムネアテ革の胸当て
B1 B6 C2 B7 C9 3Cアカツキノ?暁の剣(0x3C 是「剣」的字模索引)

于是编辑器现在的策略是:名字按上表解码,无法解码的显示为 ?;如果一整串几乎全是字模索引(多数敌人名都这样),就直接留空,避免刷出一屏乱码。描述走 CP932 转 UTF-8。半角片假名顺便转成全角,读起来舒服些。

界面上还得自动加载 msgothic.ttc 并启用日文字形范围,否则日文全变方块。

六、验证结果

无窗口自检模式(--selftest)逐张地图对比,房间数和实体数基本一致:

地图美版 房间/实体日版 房间/实体
ST/NO332 / 42432 / 426
ST/LIB16 / 44816 / 448
ST/RNO039 / 94839 / 948
BOSS/BO03 / 303 / 30

唯一的明显差异是 ST/WRP(传送房间):15 / 60 对 15 / 380。这是两版地图数据本身就不同,不是解码错误。

七、已知限制(写下来免得后人重踩)

  1. 日版初始化走不到「主循环地址」。 美版主函数初始化完会跳到 0x000E4100 停下来,日版会进入一段循环,实测跑 10 亿条指令仍停在同一处。所以模拟器只能靠指令上限返回。实测不影响地图解析。
  2. 汉字无法还原,原因见上。
  3. 日版地图里的敌人 / 物品 ID 与美版并不完全相同,同一拾取点可能对应不同物品——两版显示的名字本来就该不一样。
  4. ST/WRP 在日版下实体处理极慢(有时超过 90 秒),因为某些实体的更新函数跑满指令上限。
  5. 欧版(SLES)没适配。它的 EXE 头同样带 for Europe area,会被误判成美版地址表,大概率只能部分工作。

小结

结论是:日版 SLPM_860.23 适合当改造底本——EXE 与美版 99.9% 相同,工具链几乎可以直接复用;需要重新对齐的只有 DRA.BIN 里的表和那 +8 的全局偏移。代价是要额外处理一套自造的字模编码。

下一篇讲重打包:怎么从「没有代码空间」走到「可以随便扩容」。


系列文章


标题:PS1 月下夜想曲 Best 版本研究(一):日版 SLPM_860.23 为什么是最佳底本
作者:Miaocat
地址:https://small7g.cn/articles/2026/11/04/1793783133880.html

Lazy Cat Days. 什么都有,又好像什么都没有.

取消