4.12. アイテム解析

4.12.1. 解析
4.12.1.1. $C41A3D - アイテム構造体へのポインタ
4.12.1.2. JSL $C92AB5 によるデータ取得
4.12.1.3. JSL $C92BD4 によるデータ取得
4.12.1.4. JSL $C92C39 によるデータ取得
4.12.1.5. $C4003D - アイテム構造体
4.12.2. TODO リスト

アイテムデータの解析を行う。 なお、アイテムデータは既に先人の手によって解明されているため、 今回はトレースからデータのアドレスを突き止めるのではなく、 「あらかじめアドレスが判明しているときに、どのように構造体のメンバーの意味を見切るか」 を重点的に解説する。

4.12.1. 解析

いつもとは違い、ロムデータの grep から始める。 アイテムデータに関するアドレスは既に判明しており、次の通りだ。

  • $C41A3D - アイテム構造体へのポインタ

  • $C4003D - アイテム構造体

プログラムは、いろいろな方法でアイテム ID から、 そのアイテムの構造体データのアドレスを取得する。 まずは、そのパターンをすべて grep で洗い出す。

4.12.1.1. $C41A3D - アイテム構造体へのポインタ

$C41A3D におけるバイナリデータの格納形式は以下のようになっている。

C4/1A3D:    C4    // DB
C4/1A3E:    3D00  // アイテム ID == 00h
C4/1A40:    5700  // アイテム ID == 01h
C4/1A42:    7100  // アイテム ID == 02h
C4/1A44:    8B00  // アイテム ID == 03h
C4/1A46:    A500  // アイテム ID == 04h
C4/1A48:    BF00  // アイテム ID == 05h
...

アイテム ID を X レジスタにセットして、 LDA $C41A3E,X のような感じでアクセスしていると想像できる。 よって、バイナリエディタで BF 3E 1A C4 をロムイメージから検索する。 すると、以下のように数件ヒットさせることに成功する。

C:\home\yojyo\data\work_dq6.smc : 00046096
C:\home\yojyo\data\work_dq6.smc : 000460E8
C:\home\yojyo\data\work_dq6.smc : 00046135
C:\home\yojyo\data\work_dq6.smc : 00046185
C:\home\yojyo\data\work_dq6.smc : 00046256
C:\home\yojyo\data\work_dq6.smc : 0004784F
6件見つかりました

すべてバンク C4 のサブルーチン内から呼ばれていることがわかった。 試しに $C46096 を含むサブルーチンのアセンブルコードを見てみよう。 LDA $C41A3E,X によって、アキュームレータに 2 バイトの値がロードされるが、 これは ID が X であるアイテムの構造体データの先頭を指しているのだ (この事実は、$C41A3D をバイナリダンプしないとわからないが)。 そして LDA $C40005,XLDA $C4000B,X といった形で、 アイテム構造体の [05][0B] の値をロードしているのだ。

AL = アイテム構造体[05]; C = !アイテム構造体[0B] & 04h;
C4/608D:    18          CLC 
C4/608E:    08          PHP                 //*+5
C4/608F:    C230        REP #$30
C4/6091:    48          PHA                 //*+3
C4/6092:    DA          PHX                 //*+1
C4/6093:    8A          TXA 
C4/6094:    0A          ASL A
C4/6095:    AA          TAX 
C4/6096:    BF3E1AC4    LDA $C41A3E,X       // アイテム構造体
C4/609A:    AA          TAX 
C4/609B:    E220        SEP #$20            // M-
C4/609D:    BF0500C4    LDA $C40005,X
C4/60A1:    8303        STA $03,S           $03,S = アイテム構造体[05];
C4/60A3:    BF0B00C4    LDA $C4000B,X
C4/60A7:    2904        AND #$04            AL = アイテム構造体[0B] & 04h;
C4/60A9:    D006        BNE $60B1           if(AL == 00h){
C4/60AB:    A305        LDA $05,S
C4/60AD:    0901        ORA #$01                // carry flag
C4/60AF:    8305        STA $05,S               $05,S |= 01h;
                                            }
C4/60B1:    C230        REP #$30            // mx
C4/60B3:    FA          PLX 
C4/60B4:    68          PLA                 // アイテム構造体[05];
C4/60B5:    28          PLP                 // Carry may be changed
C4/60B6:    6B          RTL

4.12.1.2. JSL $C92AB5 によるデータ取得

項タイトルのサブルーチン呼び出しの意味はここでは説明しない。 とりあえず今理解していただくのは、 以下のようなアセンブリコードがアイテム構造体のデータへのアクセスを行うということだけだ。

C4/5ED6:    22B52AC9    JSR $C92AB5         ■$00 = $C41A3D[0000]
            01
            1A00
            3D1AC4  // アイテム構造体データへのポインタ by sonitown
            0000    // [0000]: 名前文字列 ID
            00
C4/5EE2:    AE9948      LDX $4899
...

まずは、ロムイメージファイル全体から、 22 B5 2A C91 バイト後に 1A 00 3D 1A C4 がくるパターンを grep する。 次のリストは自作プログラムの grep 結果だ。 2 番目のフィールドがアイテム構造体を 1 バイト値の配列としてみなしたときのインデックスだ。 これを知りたいがために、簡易検索プログラムを自作しただけだ。 今回の作業と同様のことは Stirling で十分行える。

C389A6, 0017h
C389B5, 0019h
C3C4E9, 0013h
C3C507, 0015h
C3C532, 0013h
C3C54D, 0015h
C3CA24, 0011h
C45ED6, 0000h
C5F710, 0017h
C5F71F, 0019h
C5F780, 0015h
C5FCC1, 0017h
C5FCCF, 0019h

その後に、検索ヒットアドレスの周辺のサブルーチンを丹念に解読していけばよい。 過去の解析作業ですでに解読が済んでいるものである可能性が十分ある。 試しにひとつ紹介する。

4.12.1.3. JSL $C92BD4 によるデータ取得

前項とほぼ同様だ。 22 B5 2A C9 1A 00 3D 1A C4 今回は 3 件だけしかない。

C:\home\yojyo\data\work_dq6.smc : 00045F0A
C:\home\yojyo\data\work_dq6.smc : 00045F79
C:\home\yojyo\data\work_dq6.smc : 00046020
3件見つかりました

アイテム構造体のどこをアクセスしているのかを調べるには、 それぞれのサブルーチン呼び出しの周囲のコードを解読すればよい。 以下は [0002,0004] がアイテムの価格であることを突き止めたものだ。 JSL $C45F70 しているサブルーチンを遡行していけば、 解析が終わっている店屋共通処理の真っ只中にあるのがわかるだろう。 セリフの表示する行の直前にあることから、 以下に示すサブルーチンがアイテムの下取り価格であることが断定できる。

.routine  $40 = アイテムの売値
C4/5F70:    08          PHP 
C4/5F71:    C230        REP #$30
C4/5F73:    48          PHA 
C4/5F74:    DA          PHX 
C4/5F75:    29FF00      AND #$00FF
C4/5F78:    AA          TAX                 x = アイテム ID;
C4/5F79:    22D42BC9    JSR $C92BD4         ■$4A = $C41A3D[x] (2 byte)
            01          // STA アドレスを ** で指定する
            1A00        // sizeof
            3D1AC4      // アイテム構造体 ptr
            4A          // **
C4/5F84:    A00200      LDY #$0002
C4/5F87:    B74A        LDA [$4A],Y
C4/5F89:    8540        STA $40             $40 = [$4A],0002h;
C4/5F8B:    C8          INY 
C4/5F8C:    B74A        LDA [$4A],Y
C4/5F8E:    8541        STA $41             $41 = [$4A],0003h;
C4/5F90:    A24000      LDX #$0040          x = 0040h;
C4/5F93:    A90300      LDA #$0003          a = 0003h
C4/5F96:    22CD0CC0    JSR $C00CCD         ■$40,x *= AL (4 byte)
C4/5F9A:    4642        LSR $42
C4/5F9C:    6640        ROR $40
C4/5F9E:    4642        LSR $42
C4/5FA0:    6640        ROR $40             $40 >>= 2 (3 byte);
C4/5FA2:    FA          PLX 
C4/5FA3:    68          PLA 
C4/5FA4:    28          PLP 
C4/5FA5:    6B          RTL
@end

4.12.1.4. JSL $C92C39 によるデータ取得

前項とほぼ同様だ。 JSL $C92C39 の呼び出し時に、 構造体のアドレス、インデックス、そしてビットマスクを指定することで、 アイテム構造体の特定のメンバーデータにアクセスする箇所を grep する。 以下がその結果だ。見やすいように整形してある。

C0DCB2, C41A3D[000B],  mask: 0002h
C0FC64, C41A3D[000F],  mask: 0010h
C3C6DD, C41A3D[0010],  mask: 00E0h
C453B5, C41A3D[000B],  mask: 0001h
C46233, C41A3D[000B],  mask: 0002h
C4AE21, C41A3D[000F],  mask: 1FE0h

例えば $C3C6DD 周辺を見てみる。すると、 アイテム構造体の [0010] & 00E0 部分が、 使用後のアイテムの持続性に関係していることが判明する:

C3/C6CE:    08          PHP 
C3/C6CF:    C230        REP #$30
C3/C6D1:    48          PHA 
C3/C6D2:    DA          PHX 
C3/C6D3:    5A          PHY 
C3/C6D4:    8B          PHB 
C3/C6D5:    F47E7E      PEA $7E7E
C3/C6D8:    AB          PLB 
C3/C6D9:    AB          PLB 
C3/C6DA:    AE2A5A      LDX $5A2A
C3/C6DD:    22392CC9    JSR $C92C39         ■(RTL+B) a = $40 = $C41A3D[0010] & 00E0h
            01
            1A00
            3D1AC4      // アイテム構造体
            1000        // [0010h]
            E000        // & 00E0h
            00
C3/C6EC:    C90000      CMP #$0000
C3/C6EF:    D002        BNE $C6F3           if(a == 0000h){
C3/C6F1:    8020        BRA $C713               goto finish;
                                            }
C3/C6F3:    C90100      CMP #$0001
C3/C6F6:    D008        BNE $C700           if(a == 0001h){
C3/C6F8:    227799C5    JSR $C59977             ■メッセージ
            3F16        // しかし いちど使えば[AD]なくなってしまうだろう。[AF]
C3/C6FE:    8013        BRA $C713               goto finish;
                                            }
C3/C700:    C90200      CMP #$0002          
C3/C703:    D008        BNE $C70D           if(a == 0002h){ 
C3/C705:    227799C5    JSR $C59977             ■メッセージ
            4016        // しかも なんかい使っても[AD]なくならないぞ。[AF]
C3/C70B:    8006        BRA $C713               goto finish;
                                            }
C3/C70D:    227799C5    JSR $C59977         ■メッセージ
            4116        // しかし 使ったあと[AD]こわれてしまうことが あるようだ。[AF]
.label finish
C3/C713:    AB          PLB 
C3/C714:    C230        REP #$30
C3/C716:    7A          PLY 
C3/C717:    FA          PLX 
C3/C718:    68          PLA 
C3/C719:    28          PLP 
C3/C71A:    60          RTS

4.12.1.5. $C4003D - アイテム構造体

構造体一個あたりのデータ格納レイアウトを以下に示す。

表 4.26 $C4003D アイテム構造体 メモリレイアウト

Byte:Bit 80 40 20 10 08 04 02 01
00 アイテム名文字列 ID (2)
01
02 価格 (3)
03
04
05 品目分類 (1)
06 パラメータ分類 (1)
07 装備時のパラメータ上昇値 (2)
08
09 装備時のかっこよさ上昇値 (2)
0A
0B 未使用 Carry 捨てる 壊す
0C 装備グループフラグ 未使用
0D 装備グループフラグ
0E
0F キャプションマップキー 1C 装備グループフラグ
10 耐久度 キャプションマップキー
11 「つかう」メッセージ ID (2)
12
13 インパス用メッセージ 1 メッセージ ID (2)
14
15 インパス用メッセージ 2 メッセージ ID (2)
16
17 カジノ景品コイン枚数 (3)
18
19

各メンバーの意味は次の通り。

アイテム名文字列 ID

アイテム名を表す文字列(e.g. やくそう、こんぼう、etc.)である。

価格

店屋がそのアイテムを売るときの、ゴールド換算での価格。

品目分類

アイテムのおおまかな分類を示す値だ。 意味は次の通り。

表 4.27 品目分類

分類
0 武器
1 身をかざる物
2 道具
3 身につける物
4
5 頭に かぶる物

道具に関しては、やや特殊な処理をすることがあるらしい。

パラメータ分類

もしそのアイテムが装備可能であるとき、 装備時にどのパラメータのポイントが上昇するのかを表す。 値とパラメータの対応は次の通り。

表 4.28 パラメータ分類

分類
1 攻撃力
2 すばやさ
3 守備力

装備時のパラメータ上昇値

もしそのアイテムが装備可能であるとき、 上記が示すパラメータのポイントがどれだけ上昇するのかを表す。

装備時のかっこよさ上昇値

もしそのアイテムが装備可能であるとき、 上記が示すパラメータのポイントがどれだけ上昇するのかを表す。 符合込み?

Carry

調査中。 すべてのアイテムでこの値がゼロであるのが逆に気になる。

捨てる

このフラグが立っているアイテムは、 店屋に売ったり、「すてる」ことができる。

壊す

アイテムを「つかう」後に、それがなくなるかどうかを表すフラグだ。 「いのりのゆびわ」はこのフラグとは別に、処理が入ることがある。

装備グループフラグ

SFC 版ドラクエ 5 のときと同じ考え方に基づくフラグセット。 説明が難しい。

キャプションマップキー

調査中。

1C

調査中。 「どうぐせいり」で道具袋に収納するかどうかを示すフラグのような気がする。

耐久度

アイテムを「つかう」ことによる破壊確率を鑑定するための数値。 以下の順で決定する。

  • #$0000 ならば、特に指定なし。

  • #$0001 ならば、一度の使用でアイテムは壊れる。

  • #$0002 ならば、何度使ってもなくならないことを強調する。

  • それ以外であれば、壊れることがあることを断っておく。

「つかう」メッセージ ID

調査中。 値から「つかう」のときのウィンドウに表示されるメッセージの ID であることを予想している。

インパス用メッセージ メッセージ ID

そのアイテムにインパスの呪文をかけたときに表示するメッセージの ID だ。 特徴のないアイテムは、この値が #$169A になっている。

カジノ景品コイン枚数

カジノの景品交換所で、そのアイテムを手に入れるときのコイン枚数。

4.12.2. TODO リスト

  • メンバー "Carry" の意味を調べる。

  • メンバー "1C" が、道具整理に関するものであることを証明する。

  • メンバー "キャプションマップキー" の詳細を調査する。

  • 装備グループとキャラクターグループの対応を示す。別項になる。