跳至内容

Jixun's Blog 填坑还是开坑,这是个好问题。

FC 魂斗罗汉化日记 (第四集)

第四集 - 标题界面的游戏介绍

(目录)

当你在标题界面什么都不干的时候,会使用打字特效介绍「魂斗罗」这个词的含义:

日文的游戏介绍界面

若显示完毕之后还是没有操作,则会跳转到游戏试玩界面。

用 YY-CHR 以及 FCEUX 的 PPU 查看器查看:

对比条时期的 PPU 差看起与 YY-CHR 读入的数据

当年的 ROM 卡槽相对来讲还是比较贵的,估计这也是为什么开发者选择了压缩图像。压缩的实现原理很简单:FC 对区块可以设定调色板,每个调色板可以选择四种颜色。一个背景色,一个共用色,以及两个独立的颜色。通过利用调色板的特性,可以储存双倍的单色图片/文字。

因为我不会操纵屏幕上的调色板,于是我选择把中文字模全部使用共用色导入到游戏内:

翻译后文字的字模

打开游戏观察:

导入字模但未更新翻译的视图

从 Name Table 可以看出,“乃”这个文字的贴图编码为 02 03 12 13

在 Rom 内也能够正常搜索到结果:

搜寻数据

但是,从这里开始到结束位置的字符数目对不上,于是回到 FCEUX 的调试器,针对写出屏幕下断 (第一个“乃”字的左上角地址为 $2114 ):

对屏幕写出事件下断点

断下后发现:这不还是从 $0700 读缓冲区后写出嘛,

PrintNextChar:
>07:CB9B:8D 07 20  STA $2007 = #$00
 07:CB9E:B9 00 07  LDA $0700,Y @ $0704 = #$03
 07:CBA1:C8        INY
 07:CBA2:C9 FF     CMP #$FF
 07:CBA4:D0 F5     BNE PrintNextChar
地址    内存内容
0700    01 21 14 02 03 FF 01 21 34 12 13 FF

继续,对 0703 下写入断点,看看数据怎么来的:

 04:906F:B9 57 91  LDA $9157,Y @ $915F = #$02
>04:9072:9D 03 07  STA $0703,X @ $0703 = #$02
 04:9075:B9 58 91  LDA $9158,Y @ $9160 = #$03
 04:9078:9D 04 07  STA $0704,X @ $0704 = #$03

缕一缕… 简单来说,程序从 $915F 读数据然后写到 $0703,而这里存放着之前搜到的内容; 点 Step Out 跳出函数,看上面一行的内容定位函数地址为 $9034,因此在这里下断。

重启游戏,运行,发现经过此函数的时候,寄存器的内容依次为:00 12 13 12 11

到文件搜索,发现这行内容刚好在刚才搜到的数据前面,数据如下:

          00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00011140     00 12 13 12 11 42 42 C3 04 05 06 07 22 08 09
00011150  09 0A 0A AB 0C 0C 05 04 0B 23 0D 0D 0B 0E 0E AB
00011160  0F 0F 08 10 10 81 FF

把数据与游戏的文字并列查看,效果如下:

00121312114242C3
04050607220809090A0AAB
0C0C05040B230D0D0B0E0EAB
0F0F08101081FF

而出现重复字符代码的地方,则刚好在相应的帖图块里包含这两个字符。

至于换行,通过观察换行处的字符,可以看见其二进制码的第一位都是 1

使用字库工具生成图库想办法导入到 rom,然后调整文字颜色为公用色。

最后,就是喜闻乐见的代码修改了:

; JSR $9034

;  012DD0:FF        UNDEFINED
; 04:ADC0:FF        UNDEFINED
.org $ADC0

LDA $0008
AND #$40
BNE _LARGE_LETTER           ; 如果是大字就跳 (24x24)
  LDA $0008
  ASL     ; A <<= 2 (字符 * 4)
  ASL
  AND #$7F
  TAY     ; Y = A

  ; A = (a * 4 overflow) ? 20 : 0
  ; Offset = A
  LDA $0008 ; A = [0008]
  AND #$20  ; 20 表示写出位置 + 20
  CLC

  ; 坐标~
  ADC $0042
  STA $0000

  LDA #$00
  ADC $0043
  STA $0001

  ; Load x offset.
  LDX $0021
  LDA #$01
  STA $0700,X
  STA $0706,X

  ; 写出坐标
  LDA $0000
  STA $0702,X
  CLC

  ADC #$20
  STA $0708,X

  LDA $0001
  STA $0701,X

  ADC #$00
  STA $0707,X

  LDA _TITLE_CHAR_TABLE + 0, Y
  STA $0703,X

  LDA _TITLE_CHAR_TABLE + 1, Y
  STA $0704,X

  LDA _TITLE_CHAR_TABLE + 2, Y
  STA $0709,X

  LDA _TITLE_CHAR_TABLE + 3, Y
  STA $070A,X

  LDA #$FF
  STA $0705,X
  STA $070B,X

  TXA     ; A = X
  CLC
  ADC #$0C  ; A += 0x0C
  STA $0021 ; Write x-offset

  ; 向右移动两个字节
  LDA $0042
  CLC
  ADC #$02
  STA $0042

  RTS

_LARGE_LETTER:
  LDA $0008
  CLC
  SBC #$40
  STA $0000


  ASL
  ASL
  ASL
  CLC
  ADC $0000
  TAY       ; Y = A

  LDA $0042
  CLC
  ADC #$20
  STA $0000
  LDA $0043
  ADC #$00
  STA $0001
  LDX $0021
  LDA #$01
  STA $0700,X
  STA $0707,X
  STA $070E,X
  LDA $0042
  STA $0702,X
  LDA $0043
  STA $0701,X
  LDA $0000
  STA $0709,X
  CLC
  ADC #$20
  STA $0710,X
  LDA $0001
  STA $0708,X
  ADC #$00
  STA $070F,X
  LDA $919B,Y
  STA $0703,X
  LDA $919C,Y
  STA $0704,X
  LDA $919D,Y
  STA $0705,X
  LDA $919E,Y
  STA $070A,X
  LDA $919F,Y
  STA $070B,X
  LDA $91A0,Y
  STA $070C,X
  LDA $91A1,Y
  STA $0711,X
  LDA $91A2,Y
  STA $0712,X
  LDA $91A3,Y
  STA $0713,X
  LDA #$FF
  STA $0706,X
  STA $070D,X
  STA $0714,X

  TXA
  CLC
  ADC #$15
  STA $0021

  LDA $0042
  CLC
  ADC #$03
  STA $0042
  RTS


_TITLE_CHAR_TABLE:
  .byte $0,$1,$10,$11
  .byte $2,$3,$12,$13
  .byte $4,$5,$14,$15
  .byte $6,$7,$16,$17
  .byte $8,$9,$18,$19
  .byte $a,$b,$1a,$1b
  .byte $c,$d,$1c,$1d
  .byte $e,$f,$1e,$1f
  .byte $20,$21,$30,$31
  .byte $22,$23,$32,$33
  .byte $24,$25,$34,$35
  .byte $26,$27,$36,$37
  .byte $28,$29,$38,$39
  .byte $2a,$2b,$3a,$3b

  ; 前引号
  ; .byte $2c,$2d,$3c,$3d
  .byte $0B,$00,$00,$00

  ; 逗号
  ; .byte $2e,$2f,$3e,$3f
  .byte $00,$00,$1B,$00

  ; 句号 (10)
  ; .byte $40,$41,$50,$51
  .byte $00,$00,$0A,$00

  ; 之 (11)
  .byte $F7,$F8,$F9,$FA

  ; 名
  .byte $FB,$FC,$FD,$FE

  .byte $46,$47,$56,$57
  .byte $48,$49,$58,$59
  .byte $4a,$4b,$5a,$5b
  .byte $4c,$4d,$5c,$5d
  .byte $4e,$4f,$5e,$5f
  .byte $60,$61,$70,$71
  .byte $62,$63,$72,$73
  .byte $64,$65,$74,$75
  .byte $66,$67,$76,$77
  .byte $68,$69,$78,$79
  .byte $6a,$6b,$7a,$7b
  .byte $6c,$6d,$7c,$7d
  .byte $6e,$6f,$7e,$7f

编译后,把翻译后的数据也一并回写到游戏里看看:

翻译后的游戏介绍

完成啦~

知识共享许可协议 本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。

评论区