5.12. ふっかけ店屋解析

5.12.1. 解析
5.12.1.1. ふっかけ店屋共通サブルーチン
5.12.1.2. 半額計算サブルーチン

アッサラームの町には標準価格で商品を売るつもりのない店がある。 対応するデバッグメニューの名前にちなみ、これらの店を「ふっかけ店屋」と呼ぶことにする。 この節では、ふっかけ店屋を処理するための共通サブルーチンを解析する。 値段を店主自ら値切っていく過程が、コードの形でどのように表現されているかが見所だ。

5.12.1. 解析

各ふっかけ店屋を処理するための共通サブルーチン$C3CF9B である。 このサブルーチンもまた別のサブルーチンをいくつか呼び出す。 そのようなサブルーチンのうち、本流の処理を助ける目的専用のものが二つある。 一つは、通常の店屋でも用いられる「店屋構造体からメニューを構成するサブルーチン」であり、 もう一つがふっかけ店屋専用の 売値の半額を計算するサブルーチン $C3D0E5 である。 以下、共通サブルーチンと半額計算サブルーチンの解析を行って得られた事実を述べる。

5.12.1.1. ふっかけ店屋共通サブルーチン

各ふっかけ店屋の処理を実装しているサブルーチン $C3CF9B における制御の流れを記す。 台詞を表示するサブルーチンは一律 $C1A92E を用いるようなので、 これを利用して、逆アセンブルコードから処理の意味を読み解く。

  • 店屋共通処理でも利用するサブルーチン $C3CEC6 を呼び出し、 商品リストデータを初期化する。

  • 台詞 (ID: #$0A0B) 「おお! わたしの ともだち! お待ちしておりました」 を店屋に言わせる。

  • はい・いいえウィンドウを表示して、プレイヤーの入力を待つ。

    • キャンセルボタンで抜けた⇒【そう言わずに】へ制御を進める。

    • 「はい」⇒【メニュー表示】へ制御を進める。

    • それ以外⇒そのまま進む。

  • 【そう言わずに】

    店屋に台詞 (ID: #$0A0C) 「まあそういわずに~」を言わせる。 次に制御を進める。

  • 【メニュー表示】

    店屋の商品リストをウィンドウに表示し、プレイヤーの入力を待つ。

    • キャンセルボタンで抜けた⇒ 店屋に台詞 (ID: #$0A0D) 「おや? お気にめしませんでした?」を言わせる。 そして、制御を【終了】へ進める。

    • それ以外⇒制御を【売値初期化】へ進める。

  • 【売値初期化】

    この時点で、A レジスタにプレイヤーが選択した商品のリスト番号がロード済みである。

    • $33DA = $2BBA,Y (where Y == A * 2) を行う。これは商品のアイテム構造体 ID を示す。

    • $33E2 = $2BCA,Y (where Y == A * 3) を行う。これは上記アイテムの標準価格を示す。 ただし、両辺を 4 バイト長の整数とみなすように処理する。

    • $33E2 <<= 4 を行う。 ここでも両辺を 4 バイト長の整数とみなすように処理する。 すなわち、標準価格を 16 倍にした金額をセットする。

    • ウィンドウに台詞を表示するための用のメモリに $33E2 の値をストアする。

  • 店屋に台詞 (ID: #$0A0E) 「おお! お目が高い! ○○ゴールドですが~」を言わせる。

  • はい・いいえウィンドウを表示して、プレイヤーの入力を待つ。

    • キャンセル抜け or いいえ ⇒【半額負ける:一回目】へ制御を進める。

    • はい ⇒【お買い上げ】へ制御を進める。

  • 【半額負ける:一回目】

    • サブルーチン $D0E5 を呼び出して売値の半額を計算する。

    • 店屋に台詞 (ID: #$0A0F) 「おお お客さん とても 買いもの上手~」を言わせる。

    • はい・いいえウィンドウを表示して、プレイヤーの入力を待つ。

      • キャンセル抜け or いいえ ⇒【半額負ける:二回目】へ制御を進める。

      • はい ⇒【お買い上げ】へ制御を進める。

  • 【半額負ける:二回目】

    • サブルーチン $D0E5 を呼び出して売値の半額を計算する。

    • 店屋に台詞 (ID: #$0A14) 「おお これいじょう まけると わたし おおぞんします!」を言わせる。

    • はい・いいえウィンドウを表示して、プレイヤーの入力を待つ。

      • キャンセル抜け or いいえ ⇒【半額負ける:三回目】へ制御を進める。

      • はい ⇒【お買い上げ】へ制御を進める。

  • 【半額負ける:三回目】

    • サブルーチン $D0E5 を呼び出して売値の半額を計算する。

    • 店屋に台詞 (ID: #$0A10) 「おお あなた ひどいひと!わたしに 首つれと いいますか?」を言わせる。

    • はい・いいえウィンドウを表示して、プレイヤーの入力を待つ。

      • キャンセル抜け or いいえ ⇒【諦める】へ制御を進める。

      • はい ⇒ 次の【お買い上げ】へ制御を進める。

  • 【お買い上げ】

    プレイヤーが買うことを決めた直後の処理である。 $33E2 に売値がセット済みである。

    • $70 = $33E2 の後、汎用サブルーチン $C45B66 を呼び出して、 パーティの所持金を $70 ゴールド分減らすことを試みる。

      • 所持金不足の場合、 店屋に台詞 (ID: #$0A12) 「おお! でも おカネが たりません!」を言わせる。 そして、制御を【終了】へ進める。

    • 店屋に台詞 (ID: #$0A13) 「おお! 買ってくれますか?」を言わせる。

    • そのアイテムをパーティの持ち物に追加するために、 A レジスタに $33DA すなわち商品のアイテム構造体 ID をロードして、 汎用サブルーチン $C44824 を呼び出す。

    • 制御を【終了】へ進める。

  • 【諦める】

    店屋がふっかけることを諦めた状態の処理である。

    • 店屋に台詞 (ID: #$0A11) 「そうですか。ざんねんです」を言わせる。

    • 制御を次の【終了】へ進める。

  • 【終了】

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

初め、ふっかけ店屋は商品を標準価格の 16 倍の金額で客に売りつけようとする。 客がそれを拒むと、店主は売値を市価の 8 倍、4 倍、 そして 2 倍へと値段を大幅に下げてくる。 この値段調整の方法論は理に適っている。

5.12.1.2. 半額計算サブルーチン

サブルーチン $C3D0E5 は、 共通サブルーチン $C3CF9B から呼び出されるサブルーチンである。 短い処理なので、すべてのコードを以下に掲載する。

C3/D0E5:    4EE433      LSR $33E4      1
C3/D0E8:    6EE233      ROR $33E2
C3/D0EB:    ADE333      LDA $33E3      2
C3/D0EE:    8D82BE      STA $BE82
C3/D0F1:    ADE233      LDA $33E2
C3/D0F4:    8D81BE      STA $BE81
C3/D0F7:    60          RTS

1

このサブルーチンコードは、A レジスタが 16 ビットモードの状態で呼び出されることを暗黙的に事前条件としている。 最初の連続する LSR, ROR 命令実行により、4 バイト長で算術処理 $33E2 >>= 1 を行う。

2

3 バイト長で $BE81 = $33E2 を処理する。

$33E2 は店屋のふっかける金額であり、 $BE81 は台詞をウィンドウに表示するために使うものである。