4.3. 戦闘メッセージ解析

4.3.1. 解析手順
4.3.2. データ

4.3.1. 解析手順

既に先人 [URL1] の手によってデータ格納位置が判明している。 ROM イメージさえあれば、ドラクエビューワで完全なリストを閲覧することができる。 ここでは、 「どのようにすれば戦闘メッセージのデータ格納アドレスをサーチできるか」 を述べる。

勝手に以下のことを仮定し、それを信じてエミュレータ (GSD を推奨) で Diff サーチを行う。

  • メッセージ ID 自体のサイズは 2 バイト

「○○○○が あらわれた!」 「○○○○の こうげき!」 「○○○○に ○○の ダメージ!」 「○○○○を たおした!」 等、表示メッセージが変化するたびに執拗に Diff サーチをすることにより、 それらしい値変化をしているアドレスを細かく見ていく:

  • $7E3056

  • $7E5966

  • $7E5998

  • $7E59A8

  • $7E59B8

  • $7E59BA

  • $7E59BC

戦闘突入直後に、これらのアドレスひとつひとつに Break Point を置き、 メッセージの表示と関係があるかどうかをみる。ここからは運任せである。

$7E3056 は頻繁に Read されるので、メッセージの更新とは無関係とみなし、これを候補から除外する。 次に $7E5966 だが、これも同様な感じがするのでやはり除外する。 その次の $7E5998 でそれらしい挙動を見せるようになる。 GSD のアウトプットウィンドウの表示はこうなる:

$C0/2A36 8D 98 59    STA $5998  [$7E:5998]   A:000B X:0042 Y:0000 D:1E1F DB:7E S:083E (行末まで省略)
$C0/27B8 AD 98 59    LDA $5998  [$7E:5998]   A:0001 X:0004 Y:0000 D:1E1F DB:7E S:0837 (行末まで省略)
$C0/27C1 AD 98 59    LDA $5998  [$7E:5998]   A:0003 X:0004 Y:0000 D:1E1F DB:7E S:0837 (行末まで省略)

ここで、あらかじめ用意しておいた逆アセンブリコードリストと照合する。 バンクごとに逆アセンブリコードを用意しておくのが解析人の鉄則だ。 $C0/27B8, $C0/27C1 の命令を一つのルーチンが含んでいる。 これが戦闘メッセージのデータを取得するものであると狙いがつけられる。

C0/27B0:    08          PHP 
C0/27B1:    C230        REP #$30
C0/27B3:    F47E7E      PEA $7E7E
C0/27B6:    AB          PLB 
C0/27B7:    AB          PLB 
C0/27B8:    AD9859      LDA $5998
C0/27BB:    290700      AND #$0007
C0/27BE:    8D1E5A      STA $5A1E
C0/27C1:    AD9859      LDA $5998
C0/27C4:    4A          LSR A
C0/27C5:    4A          LSR A
C0/27C6:    4A          LSR A
C0/27C7:    48          PHA 
C0/27C8:    0A          ASL A
C0/27C9:    6301        ADC $01,S
C0/27CB:    AA          TAX 
C0/27CC:    68          PLA 
                                            // x == 戦闘メッセージ ID
C0/27CD:    BFD15AC1    LDA $C15AD1,X       // 戦闘メッセージ 開始アドレス郡
C0/27D1:    18          CLC 
C0/27D2:    69BDDE      ADC #$DEBD
C0/27D5:    85A0        STA $A0             $A0 = アドレス + DEBDh;
C0/27D7:    BFD35AC1    LDA $C15AD3,X       // 戦闘メッセージ 開始アドレス郡+
C0/27DB:    29FF00      AND #$00FF
C0/27DE:    69F600      ADC #$00F6
C0/27E1:    85A2        STA $A2             $A2 = (バンク & 0x00FF) + 00F6h;
C0/27E3:    64A4        STZ $A4             $A4 = 0000h;
                                            for(;;){
C0/27E5:    AD1E5A      LDA $5A1E
C0/27E8:    F013        BEQ $27FD               if($5A1E)  return;
                                                do{
C0/27EA:    22FF27C0    JSR $C027FF                 ■1. $A0 にストアされているアドレス値を incr.
                                                    ■2. a = 文字コードをセット
C0/27EE:    C9AC00      CMP #$00AC
C0/27F1:    F005        BEQ $27F8                   if(a == 00ACh) break;
C0/27F3:    C9AE00      CMP #$00AE
C0/27F6:    D0F2        BNE $27EA               }while(a != 00AEh);
C0/27F8:    CE1E5A      DEC $5A1E               --$5A1E;
C0/27FB:    80E8        BRA $27E5           }
C0/27FD:    28          PLP 
C0/27FE:    6B          RTL

このルーチンの LDA 命令をチェックしておくと、 $C15AD3 がいかにも戦闘メッセージデータのアドレスの先頭であることが特定できる。 ソニタウン [URL2] の結果と一致して、まずは一安心である。 あとは、このアドレスから 1 バイトずつ SFC 版ドラクエ 6 の小フォント文字コードとみなして、 力にまかせてデコードしていけばよい。 dq_analyzer [URL1] のデコーダにある配列を流用すればよい。 最初から dq6decoder -s する場合、戦闘メッセージは出力ファイルの 655599 行目の 39 半角文字目に現れる。

4.3.2. データ

ドラクエビューワ [URL2] を見ればよい。 と書くハズだったが、戦闘ルーチンのコード解析においてテキストベースでのリストがないと、 まるで話にならないことに気付いた。 ここにテキストベースの戦闘メッセージリストを公開する。 dq_analyzer [URL1] のデコーダが出力するものと基本的に同等のものである。 ただし「印字不可能文字」は文字コードの直接出力に修正した。

付録 B データ