5.23. メダルおじさん解析

5.23.1. 解析
5.23.1.1. メダルおじさん共通処理
5.23.1.2. 次の褒美を調べるサブルーチン
5.23.1.3. 持参したメダル枚数を調べる&回収するサブルーチン
5.23.1.4. 褒美 ID に対してアイテム ID を取得するサブルーチン
5.23.1.5. 褒美 ID に対して必要枚数を取得するサブルーチン
5.23.1.6. 褒美構造体

メダルおじさんに「はなす」ときの処理を解析する。 おじさんはどのようにして、勇者一行がこれまでに渡してきたメダル枚数を記憶しているのか、 パーティーメンバーが持っている「ちいさなメダル」をどのような優先順位で受け取るのか、 そして、交換する品物をどのように決定しているのかを見ていこう。

5.23.1. 解析

サブルーチン $C3F076 は 現在のメダル取得状態に応じたおじさんの台詞を表示したり、 パーティーから「ちいさなメダル」を受け取ったり、 その代わりに褒美を受け渡したりする処理を行う。 このサブルーチンから枝葉の処理を追っていけば、おじさん処理は全て把握できることになる。

メダルおじさん周りの台詞表示は、すべてサブルーチン $C1A92E 呼び出しで実現している。 このサブルーチンは、呼び出しコード直後に 2 バイトの定数を埋め込むことで、 その定数をメッセージ ID として解釈する。 これにより、逆アセンブルコードの解読を安定的に進めることができる。

5.23.1.1. メダルおじさん共通処理

サブルーチン $C3F076 は、メダルおじさんに「はなす」とすぐに始まる処理だ。 以下のように実装している。

  • 汎用サブルーチン $C9029E を用いて、メダルおじさんに譲渡済みのメダル枚数を取得する。 $7E3538#$3FC0 部分に枚数がセットされている。 これを $2BB2 にロードする。

  • X = #$000C - 1 をセットし、 サブルーチン $C3F239 を呼び出して、 その枚数を $2BBE にセットする。 すなわち、最後の褒美 ID に相当する枚数を調べる。

  • サブルーチン $C3F1BD を呼び出して、 その枚数、すなわちパーティーが持参したメダルの枚数を $2BB4 にセットする。

  • 所持枚数と譲渡済枚数の和が 256 以上であれば、255 に丸める。 この値を A レジスタにセットする。

  • 汎用サブルーチン $C902E9 を用いて、メダルおじさんに譲渡済みのメダル枚数を更新する。 $7E3538#$3FC0 部分に A レジスタの値をセットする。

  • まだ与えていない褒美を調べるためにサブルーチン $C3F199 を呼び出し、 結果を調べる。

    • もし与えていない褒美があれば【あいさつ】へ制御を移す。

    • すべての褒美を与えていれば【おめでとう】へ進む。

  • 【おめでとう】

    • メッセージ (ID #$0D6D) 「よくぞ○○枚も集めてくれた」を言わせる。 この台詞に出てくる枚数は $2BB6 の値と同じだ。

    • 制御を【終了】へ移す。

  • 【あいさつ】

    • メッセージ (ID #$0D64) 「よくぞ来た」を言わせる。

    • 譲渡済枚数 $2BB2 の値をテストする。

      • $2BB2 == 0 ならば

        • メッセージ (ID #$0D65) 「メダルを見つけた者には褒美をとらせよう」を言わせる。

        • $2BB4 をテストする。 $2BB4 == 0 ならば【終了】へ制御を移す。 そうでなければメッセージ (ID #$0D66) 「なんとメダルを持ってきたか」を言わせた後に、 【ステータス】へ制御を移す。

      • そうでなければ $2BB4 の値をテストする。 $2BB4 == 0 ならば【枚数告知】へ制御を移す。 そうでなければメッセージ (ID #$0D68) 「ほほうメダルを持ってきたか」を言わせた後に、 【ステータス】へ制御を移す。

  • 【ステータス】

    • メッセージ (ID #$0D67) 「これまでに持ってきたメダルは全部で○○枚じゃな」を言わせる。 この台詞は $2BB6 に格納した値と同じだ。 台詞を表示した直後に、更新された譲渡済枚数と、次回褒美枚数を比較する。

      • 譲渡済 < 次回褒美枚数 ⇒【次回褒美告知】へ制御を移す。

      • そうでなければ【褒美うけわたし】へ制御を進める。

  • 【褒美うけわたし】

    • 最初が詳細不明

    • メッセージ (ID #$0D69)「メダルを○○枚集めたので褒美をやろう」を言わせる。 この台詞の○○部分には $2BBA の値と同じものが用いられる。

    • メッセージ (ID #$0D6A)「~は○○を受け取った」を表示する。 ○○部分には $2BBC を用いて、褒美のアイテム名が表示される。

    • X = $2BB8 + 1 として、次回褒美 ID の値をチェックする。

      • X > #$000C であれば、制御を【おめでとう】に移す。

      • そうでなければ、$2BBC, $2BBA, $2BB8 をこの順で更新する。 それぞれサブルーチン $C3F21E 呼び出し、サブルーチン $C3F239 呼び出し、 X レジスタの値を利用する。

        • $2BB6 > $2BBA ⇒【褒美うけわたし】先頭へ制御を戻す。

        • そうでなければ【枚数告知】へ進む。

  • 【枚数告知】

    • メッセージ (ID #$0D6B)「現在○○枚のメダルを預かっておる」を言わせる。 この台詞では $2BB6 に格納されている値である、更新された譲渡済枚数を知らせる。

  • 【次回褒美告知】

    • メッセージ (ID #$0D6C)「○○枚に なったときは ××を あたえよう」を言わせる。 この台詞は $2BBA$2BBC にそれぞれ格納されている、 ○○に相当する値と××に相当するアイテムのアイテム構造体 ID と同じだ。

  • 【終了】

    サブルーチン呼び出し元に制御を戻す。

5.23.1.2. 次の褒美を調べるサブルーチン

サブルーチン $C3F199 は、メダルおじさんに譲渡済みのメダル枚数を A レジスタにセットしてから呼び出すものであり、 次の褒美に対応するメダル必要累積枚数と、褒美アイテムのアイテム構造体 ID を $2BBA, $2BBC にそれぞれセットする。

  • $78 = 譲渡済みメダル枚数 + 1 とする。

  • サブルーチン $C3F239を順次呼び出し、 $78 と、褒美構造体各データが定める必要累積枚数と比較していく。 構造体各データは、累積枚数フィールドの値の小さい順に配列されている。

    • 必要累積枚数が $78 以上になる褒美がない場合、 Carry フラグがセットされた状態で、サブルーチン呼び出し元に制御を戻す。

    • 必要累積枚数が $78 以上になる褒美が見つかった場合、同時に X レジスタに褒美構造体 ID がセットされることになる。 これにより、サブルーチン $C3F21Eを呼び出して 褒美となるアイテムのアイテム構造体 ID をも取得する。

    • 次の褒美に対応するメダル必要累積枚数と、褒美アイテムのアイテム構造体 ID を $2BBA, $2BBC にそれぞれセットする。

    • Carry フラグをリセットしてから、サブルーチン呼び出し元に制御を戻す。

5.23.1.3. 持参したメダル枚数を調べる&回収するサブルーチン

調査中。事実関係と予想を交えて記すと以下のようになる。

  • パーティ全員の持ち物とふくろから、この順にちいさなメダルを削除していく。

    ただしすべてのメダルを回収するのではなく、 回収カウンターが $2BBE 以上になったら、回収処理をストップする。 $2BBE共通処理サブルーチンでセット済みであり、 この値は最後の褒美を得るのに必要なメダル累積枚数だ。

  • 制御を呼び出し元に戻す前に、回収枚数を A レジスタにセットする。

検証していないが、例えば初めてメダルおじさんと会うときに、 一気にちいさなメダルを 102 枚持参したとする。 この解析結果の予想が正しければ、 2 枚は回収されずに、パーティの持ち物リストに残るわけだ。

5.23.1.4. 褒美 ID に対してアイテム ID を取得するサブルーチン

サブルーチン $C3F21E は、褒美構造体 $C31350 にアクセスすることにより、 褒美 ID に対応する褒美のアイテム ID を取得する。

  • サブルーチン呼び出し直後の X レジスタが褒美 ID を示している。 構造体のサイズが 2 であるので、$C31350 + X * 2 を計算するため、 汎用乗算サブルーチン $C01098 を利用する [11]

  • 褒美構造体の 1 バイト目からの 1 バイトが、褒美アイテムの ID だ。 この値を A レジスタにセットして、制御を呼び出し元に戻す。

5.23.1.5. 褒美 ID に対して必要枚数を取得するサブルーチン

サブルーチン $C3F239 は、褒美構造体 $C31350 にアクセスすることにより、 褒美 ID に対応するちいさなメダルの必要収集枚数を取得する。

  • 前述のサブルーチンと同様にして、 $C31350 + X * 2 を計算する。

  • 褒美構造体の 0 バイト目からの 1 バイトが、褒美を得るのに必要なメダルの枚数だ。 この値を A レジスタにセットして、制御を呼び出し元に戻す。

5.23.1.6. 褒美構造体

$C313502 バイトサイズの構造体データが #$0C 個配列されている。 これが、メダルおじさんの褒美リストだ。 構造体のメモリレイアウトは以下の通り。

表 5.29 $C31350 褒美構造体

Byte:Bit 80 40 20 10 08 04 02 01
00 必要枚数
01 アイテム ID

この配列を人間にとってわかりやすく表現すると、下のようになる。

表 5.30 メダル景品

褒美 ID 必要枚数 アイテム
#$00 5 とげのむち
#$01 10 ガーターベルト
#$02 20 やいばのブーメラン
#$03 30 ちからのゆびわ
#$04 35 インテリめがね
#$05 50 しのびのふく
#$06 60 せいぎのそろばん
#$07 70 しっぷうのバンダナ
#$08 80 ドラゴンクロウ
#$09 90 ふっかつのつえ
#$0A 95 しんぴのビキニ
#$0B 100 ゴールドパス



[11] 数値を二倍するだけなのに、乗算サブルーチンを呼びだす方法をとるのは珍しい。 ASL 命令を使うだけで間に合いそうなものだが。