4.5. 店屋解析

4.5.1. 解析
4.5.1.1. サブルーチン $C5F5BE - 店共通処理
4.5.1.2. 構造体 $C58B93 - 店データ構造体

武器屋や道具屋などの各店のデータが、 プログラム内でどのように表現されているかについて解析し、 すべての店のデータのリストを見る手順を示す。

4.5.1. 解析

PAR サーチを利用する方法も考えられるが、 人オブジェクト解析 の過程を再利用するのがいいだろう。 おあつらえ向けなことに、 店屋セリフチェック用のフロアが存在する。 これを利用して、GSD の Breakpoint を下記命令に Exec 条件でセットし、 当フロアに進入する。

すると、このフロアにいる人数分だけ一時停止するはずなので、 「はなす」の処理を行うサブルーチンのアドレス、 すなわち $0006B0 に格納されているもの、をすべて記憶しておく。 そして、それらのアセンブリコードを観察すると、 よく似たリストがいくつかあるのがわかるだろう。 (下記コードリスト中の一部のコメントは、 記者の作業用メモなので、この時点では判明していない事実である)

// デバッグフロア 左上 あらくれ
CD/FE4C:    A24700      LDX #$0047
CD/FE4F:    22BEF5C5    JSR $C5F5BE         // 店屋共通処理
CD/FE53:    6B          RTL

// デバッグフロア 左上 剣士
CD/FE54:    A24800      LDX #$0048
CD/FE57:    22BEF5C5    JSR $C5F5BE         // 店屋共通処理
CD/FE5B:    6B          RTL

// デバッグフロア 左上 商人
CD/FE5C:    A24900      LDX #$0049
CD/FE5F:    22BEF5C5    JSR $C5F5BE         // 店屋共通処理
CD/FE63:    6B          RTL

// デバッグフロア 左上 じいさん 左
CD/FE64:    A24A00      LDX #$004A
CD/FE67:    22BEF5C5    JSR $C5F5BE         // 店屋共通処理
CD/FE6B:    6B          RTL

サブルーチン $C5F5BE は店屋処理そのものであり、 X レジスタの値が店の ID 値であることは明白である。

4.5.1.1. サブルーチン $C5F5BE - 店共通処理

サブルーチン $C5F5BE 全体を、ツールを使って一気に逆アセンブルすると失敗する。 なぜなら、JSL $C92C39 が何回も登場するからである。 人オブジェクト解析でも少し触れたが、まとめるとこういうことである:

  • JSL $C92C39 の次の命令の位置は、本来のそれより 11 バイト先にズレる。

  • その 11 バイトには、サブルーチン $C92C39 がスタックポインタ (S) を介して参照する定数データである。

    • [00]: 値がゼロであるときに、これ以降の記述の意味が正しい。

    • [01-02]: 構造体データのサイズ。バイト単位で示す。

    • [03-05]: 最初の構造体データの格納位置。

    • [06-07]: 構造体の何バイト目のデータをロードするかを示す。

    • [08]: ロードした値の 1 バイト目にかけるマスク。

    • [09-0A]: (必要ならば)ロードした値の 2-3 バイト目にかけるマスク。

これを踏まえて $C5F5BE のアセンブリリストを「整形」すると、 サブルーチンの最初のほうは以下のとおりになる。

// x: 店 ID
// JSL $C92C39 は人オブジェクト解析で既に解析済
C5/F5BE:    08          PHP 
C5/F5BF:    C230        REP #$30
C5/F5C1:    48          PHA 
C5/F5C2:    DA          PHX 
C5/F5C3:    5A          PHY 
C5/F5C4:    8B          PHB 
C5/F5C5:    F47E7E      PEA $7E7E
C5/F5C8:    AB          PLB 
C5/F5C9:    AB          PLB 
C5/F5CA:    8E753B      STX $3B75           $7E3B75 = x;
C5/F5CD:    22B52AC9    JSR $C92AB5         // まだ見ていない
            00
            0800
            938B
            C5
            0000
C5/F5D9:    8D793B      STA $3B79           $7E3B79 = a;
C5/F5DC:    22392CC9    JSR $C92C39         ■a = $C58B93[02] & 0xFF;
            00          // regular
            0800        // size: 8 byte
            938B
            C5          // $C58B93[02] & 0xFF: 売り物 1
            0200
            FF
            0000
C5/F5EB:    8D7B3B      STA $3B7B           $7E3B7B = a;
C5/F5EE:    22392CC9    JSR $C92C39         ■a = $C58B93[03] & 0xFF;
            00
            0800
            938B
            C5          // $C58B93[03] & 0xFF: 売り物 2
            0300
            FF
            0000

(同様に売り物をセットしていく……コード省略)

C5/F648:    20B1FC      JSR $FCB1           // まだ見ていない
C5/F64B:    D045        BNE $F692           if(zero が立っていない)
                                                goto LF692;
C5/F64D:    009E        BRK #$9E            // 「ここは コインを 品物にかえる~」
C5/F64F:    19

4.5.1.2. 構造体 $C58B93 - 店データ構造体

構造体 $C58B93 のメンバの意味を特定する。 アセンブリコードを追うのではなく、 データを改竄することで、メンバの意味を知れば十分だ。 この構造体の各メンバは、以下の表のとおりである。

表 4.18 構造体 $C58B93 - 店データ構造体 メモリレイアウト

Byte:Bit 80 40 20 10 08 04 02 01
00 店の種別
01
02 売り物 1
03 売り物 2
04 売り物 3
05 売り物 4
06 売り物 5
07 売り物 6

記者がソニタウンの解析資料 [URL2] の内容と照合した結果、 意味が一致していたので、これでよいだろう。

店の種別

店の種別を決定する値である。 店の人のしゃべるセリフの集合が定義されている配列が 5 個存在するのだが、 そのどれを用いるかを指定する値と考えればよい。

表 4.19 店の種別

店の種別
#$0000 未使用
#$0001 武器屋
#$0002 防具屋
#$0003 道具屋
#$0004 よろず屋
#$0005 カジノコイン景品交換所

これら配列 5 つのポインタの配列は $C5FD3B に存在する。

店屋のセリフセットのアドレスの配列
C5/FD3B:    45FD  // 0001
C5/FD3D:    7BFD  // 0002
C5/FD3F:    B1FD  // 0003
C5/FD41:    E7FD  // 0004
C5/FD43:    1DFE  // 0005

#$0001 は武器屋だが、$C5FD45 を見ると、 確かに武器屋のセリフの ID の配列であることがわかる。 同様にして、防具屋、道具屋、よろず屋、カジノ交換所のセリフ ID 配列が定義されている。 ただし、カジノ交換所のセリフ ID 配列は、 ほとんど道具屋のそれと同じである。 必要な部分だけカジノ固有のセリフ ID で差し替えられている。

0001: 武器屋セリフ配列
C5/FD45:    4818  // 0000: [DE]ここは 武器の店だ。[AD]どんな用だい?
C5/FD47:    6218  // 0001: [DE]じゃあ また 来てくれよな!
C5/FD49:    4918  // 0002: [DE]どれに するかね?[AF][D5]
C5/FD4B:    6118  // 0003: [DE]ほかにも 用は あるかい?
C5/FD4D:    4A18  // 0004: [DE]おっと それを買うには[AD]お金が~
C5/FD4F:    4B18  // 0005: [DE][B5]だな。[AF][D5]
C5/FD51:    4D18  // 0006: [DE]だれが 持つかね?[AF][D5]
C5/FD53:    5318  // 0007: [DE]さっそく そうび するかい?
C5/FD55:    5418  // 0008: [DE][B3]は [B5]を[AD]そうび させてもらった![AF][D5]
C5/FD57:    5218  // 0009: [DE][B3]は これを[AD]そうびできないが~
C5/FD59:    5618  // 000A: [DE]じゃあ [B3]の[AD]ひつぎの中に~
C5/FD5B:    5518  // 000B: [DE]ほらよ! [B3]さん![AF][D5]
C5/FD5D:    5718  // 000C: [DE]よし! じゃあ[AD]馬車の中の~
C5/FD5F:    5118  // 000D: [DE]じゃあ その [C3] の中に~
C5/FD61:    4F18  // 000E: [DE]少し 持ちものを へらして~
C5/FD63:    4E18  // 000F: [DE]ん? [B3]は[AD]それ以上~
C5/FD65:    5918  // 0010: [DE]おや? [B3]さんは[AD]なんにも 持っていないぜ![AF][D5]
C5/FD67:    5818  // 0011: [DE]だれが 売ってくれるんだい?[AF][D5]
C5/FD69:    5B18  // 0012: [DE]どれを 売るんだい?[AF][D5]
C5/FD6B:    5E18  // 0013: [DE][B5]だな。[AD][BB]ゴールドで[AD]引きとろう~
C5/FD6D:    6018  // 0014: [DE]それは ざんねんだな。[AF][D5]
C5/FD6F:    5F18  // 0015: [DE]よし! たしかに買いとったぜ。[AF][D5]
C5/FD71:    5C18  // 0016: [DE]わるいが それは うちでは~
C5/FD73:    5A18  // 0017: [DE]おや? その[C3]には[AD]なんにも~
C5/FD75:    5D18  // 0018: [DE]おっと! 買いとりたいが[AD]それ以上 お金を~
C5/FD77:    4C18  // 0019: [DE]これは 戦いのときに[AD]どうぐとして~
C5/FD79:    5018  // 001A: [DE]ほかの人が 持つかね?
売り物 N

メンバ「売り物 N (= 1,2,3,4,5,6)」は、 その店のメニューの N 番目に来るものである。 値は、そのアイテム ID である。 アイテム ID とアイテム名の対応は、 いつもお世話になっているドラクエビューア [URL2] で確認できる。