5.1. デバッグモード解析

5.1.1. 解析
5.1.1.1. $C1FFFE 参照位置一覧
5.1.1.2. デバッグモード
5.1.1.3. ゲームショーモード
5.1.2. 改竄

SFC 版ドラクエ 3 のデバッグモードについて解析する。 Shingo Endo 氏が SFC 版ドラクエ 6 の解析文書で指摘している 「$C1FFFE の値によるプログラムの処理分岐」が SFC 版ドラクエ 3 においても存在する。

5.1.1. 解析

最初に $C1FFFE の参照位置をすべて洗い出し、 周囲のコードを解析してデバッグモードにおける処理を特定していく。 必要ならば ROM イメージを改竄して、デバッグモード相当のプログラムを実行していくのが本章の狙いである。

5.1.1.1. $C1FFFE 参照位置一覧

プログラムが $C1FFFE の値をみるときは、 LDA $C1FFFE の形で参照すると推測できる。 そこで、単純に ROM イメージを "AF FE FF C1" で検索してみると、 割と参照位置が多く存在することを知る。

以下に、 参照位置のアドレス、 ロードした $C1FFFE の値を扱う命令コード、 コードをおおまかに解読して推測した役割の表を示す。

表 5.1 $C1FFFE 参照位置一覧

参照位置 命令 処理
$C02795 BPL 負の値がロードされると、サブルーチン呼び出し元に戻れない(改竄の項を参照)
$C02DB1 BPL $7E3500 & 0004h ルーラ関係?
$C1C9BD BPL 負の値がロードされると、すごろく「?」イベントの操作が可能になる
$C315B0 BPL 負の値がロードされると、へんげのつえで何に化けるかの指定が有効になる
$C31EA0 AND #$8000 負の値がロードされると、「ROMバージョン」ミニウィンドウ表示が有効になる
$C43C89 CMP #$0001 1 がロードされると、キャラクターのレベルアップが 5 までに制限される
$C46293 CMP #$0001 1 がロードされると、ふくろの処理に関する何かが無効になる?
$C463D4 CMP #$0001 1 がロードされると、冒険の書を保存(消去も)できなくなる
$C46536 BPL 負の値がロードされると、新しい「ぼうけんのしょ3」が風変わりな設定になる
$C56723 BPL 負の値がロードされると、すごろくでサイコロの出目操作が有効になる
$C6066C BPL 負の値がロードされると、「このフロアにあるマップや歩行属性は○○ワード大き過ぎます」テスト有効
$C650FC BPL 要呼び出し調査
$C65284 BPL 要呼び出し調査
$C6FFF3 CMP #$0000 負の値がロードされると、サブルーチン呼び出し元に戻れない(改竄の項を参照)
$C73C2E STA $C18B 1 がロードされると、まほうのたま使用時点で「すべてをつかさどる者」が出てきてゲームオーバー
$C767E6 BMI $67F8 負の値がロードされると、L ボタンでデバッグメニューウィンドウを表示できる
$C767EF BMI $67F8
$C76816 BPL 負の値がロードされると、R ボタンで座標ウィンドウを表示できる
$C76862 BPL 負の値がロードされると、すごろくでサイコロの出目を操作できる
$C76E8A CMP #$FFFF FFFFh8000h との違いで、ある特定のフラグをリセットするかセットするかという処理になる
$C76F27 CMP #$8000

以下では、$C1FFFE に何か負の値が格納されている状態をデバッグモード$C1FFFE0001h が格納されている状態をゲームショーモードとそれぞれ呼ぶことにする。

5.1.1.2. デバッグモード

$C1FFFEFFFFh 等の負の値で書き換えた場合、 先に述べたように、デバッグメニューの利用、すごろくの各種インチキ操作を含む、 プレイヤーにとってかなりの利益が得られる操作が可能となる。 以下の項では、解析で判明したそれらの利用方法を説明する。

5.1.1.2.1. デバッグメニュー使用可能

図 5.1 デバッグメニュー

デバッグメニュー

移動モードにおいて、ウィンドウが一枚も出ていない状態でコントローラの L ボタンを押すと、 図のようなデバッグメニューウィンドウが画面上に出現する。 各メニューアイテムを簡単に説明する。

いんちきルーラ

図 5.2 いんちきルーラ

いんちきルーラ

まず、行き先リストウィンドウ (ID: 0002h) をサブメニューとして表示する。 明らかに、通常のルーラよりも行き先候補が多い。 サブメニューウィンドウのいずれかの項目を選択すると、 そこを目的地とするルーラ処理を行う。

いんちきリレミト

だれの MP を消費することもなしにリレミト処理を行う。 パーティ内にリレミトを唱えられるキャラクターがいる必要はない。

いんちきラナルータ

上述「いんちきリレミト」のラナルータ版である。

おみせ

図 5.3 おみせ

おみせ

図のようなサブメニューを表示する。 選択する項目により、店屋の共通処理が始まる。

「ぶきや」「ぼうぐや」「どうぐや」「よろずや」の処理については店屋解析を参照。 「しんぷ」「シスター」は教会解析、 「やどや」は宿屋解析、 「ぎんこう」はゴールド銀行解析、 「なかまとうろくじょ」は仲間登録所解析、 「ルイーダのさかば」はルイーダの酒場解析、 「ダーマのしんでん」は転職解析、 「なまえかえや」は命名神解析、 「かくとうじょう」は格闘場解析、 「よそうや」は予想屋解析、 「ふっかけみせや」はふっかけ店屋解析、 「マッチメイク」は格闘場マッチメイク解析、 「メダルおじさん」はメダルおじさん解析、 「シスターセーブ」はシスターセーブ解析、 「おうさま」は王様解析をそれぞれ参照。

レベルアップ

図 5.4 レベルアップ

レベルアップ

この項目を選択すると、コマンドウィンドウで「つよさ」を選択したときと同じサブウィンドウ群が出る。 さらにこの状態でキャラクターを選択すると、「つよさ」ウィンドウが出る代わりに、 数値入力ウィンドウが出現する(上記画像)。 ここで 1 から 99 までの値を入力すると、選択したキャラクターのレベルがその値となる。 キャラクターのパラメータや、習得呪文もそれらしいものになる。 従ってレベルダウンも可能である。 0 の入力はキャンセル扱いになり、100 以上の値の入力は 99 が入力されたものとみなされる。

てんしょく

特に処理はない。 コードとしてはキャリーフラグをリセットするだけなので、処理は本当に何もない。

せいかく

図 5.5 せいかく

せいかく

この項目を選択すると、コマンドウィンドウで「つよさ」を選択したときと同じサブウィンドウ群が出る。 さらにこの状態でキャラクターを選択すると、「つよさ」ウィンドウが出る代わりに、 性格リストウィンドウ (ID: 00A7h) が出現する(上記画像)。 どれか性格を選択すると、選択キャラクターの素の性格がそれに設定される。

おかね

金額入力ウィンドウが出現する。 ここで入力した値が、そのまま現在のパーティの所持金として設定される。

フラグショップ

図 5.6 フラグショップ

フラグショップ

図のようなサブメニューを表示する。 ここで項目を選択すると、その項目が示すゲーム状態になっていることが保証されるらしい。 また、項目によっては対話的にオプションを要求 (オープニングで王様に会った?等) してくるものもある。

ゲーム中に利用するフラグ全般については、別の章で説明する。

ひとじょうたい

図 5.7 ひとじょうたい

ひとじょうたい

「だれを」ウィンドウが出現して、パーティ内キャラクターのだれか一人を選択することになる。 ここでキャラクターを選択すると、ステータスを「しに・まひ・どく」の中から設定することができる。 基本的に設定したくない状態だけがある。

「しに」を選択すると、キャラクターの HP がゼロにすることで死なせる。 「まひ」「どく」はキャラクター状態ビットを ON にする処理である。

ゲームじょうたい

図 5.8 ゲームじょうたい

ゲームじょうたい

現在いるフロアの情報を表示するウィンドウ (ID: 007Dh) が出現する。 例えば「ルーラ」では「できる」「できない」「あたまをぶつける」のどれかが表示される。

どうぐふくろ

アイテム ID が 0000h から 00E4h までの道具を一個ずつふくろに追加する。

せんたくせんとう

図 5.9 せんたくせんとう

せんたくせんとう

モンスターせんたくウィンドウ (ID: 00D1h) が出現する。 ここでモンスターを示す項目を選択すると、さらに数値入力ウィンドウが出現する。 数値を入力すると、再びモンスターせんたくウィンドウがアクティブになる。

モンスターと数値のペアを 4 回入力すると、さらに数値入力ウィンドウが出現する (同じ場所に出てくるため、わかりにくい)。 ここで入力するのは、戦闘シーンの背景グラフィックの ID である。 ゼロを入力するとランダムに背景が決まり、 004Ah 以上の値を入力すると 0049h を入力した扱いになる。

グラフィック ID を入力すると、戦闘モードに切り替わる。 登場するモンスターの群れは、先程指示したモンスターグループとなる。 各グループのモンスター頭数が、指定数値を考慮したものになっている。 画面背景も、指定のものになっている。

タイルせんとう

図 5.10 タイルせんとう

タイルせんとう

数値入力ウィンドウが出現する。 このウィンドウを出した場所によって、あらかじめゼロでない数値が表示されているかもしれない。 ここで 0069h 未満の数値を入力すると、いきなり戦闘モードに切り替わり、 登場するモンスターの群れは、先程指定した数値をタイルエンカウント ID とするものに基づく。

モンスターをみる

図 5.11 モンスターをみる

モンスターをみる

画面が切り替わり、モンスターのグラフィックを見るモードになる。 モンスターを選択すると、アニメーション個数だけリストされたミニウィンドウが出現する。 ここで番号を選択すると、そのモンスターに対応するアニメーションが再現される。

ぜんかいふく

パーティ全員の毒・マヒ状態を回復して、 HP と MP を完全に回復する。 死んでいるキャラクターにもこの回復を適用するが、 カンオケグラフィックの更新が次のキャラクター再描画の機会まで発生しない。

プログラムスタート

名前とは裏腹に、このデバッグメニューウィンドウを消去して、 再びデバッグメニューウィンドウを表示するという処理になっている。

サウンド

数値入力ウィンドウが出現する。 ここで入力した数値を ID とする BGM なり効果音なりが演奏される。 ゼロの入力は単に無視される。 入力値が 017Fh 以上のときは、017Eh が入力されたとして扱われる。 演奏ストップ機能はないらしい。

ほこうせってい

図 5.12 ほこうせってい

ほこうせってい

図のようなメッセージが出現する。 「はい」と答えると、キャンセル歩行ができる ($7E3500 |= 0002h) ようになり、 「いいえ」はその逆 ($7E3500 &= ~0002h) となる。

キャンセル歩行が有効であるとは、SELECT ボタンを押しながら十字キーを押すことで、 壁や水場等の通過できない地形を通過することができる状態を指すようだ。 船で移動中の場合は、上陸しないでそのまま移動し続けることになる。

エンカウントせってい

図 5.13 エンカウントせってい

エンカウントせってい

図のようなメッセージが出現する。 「いいえ」と答えると、フィールドやダンジョンを歩いていても敵が一切出現しなく ($7E3500 &= ~0001h) なる。 「はい」はその逆 ($7E3500 |= 0001h) である。 通常のゲームモードでは「はい」の状態である。

スタートフロアせってい

図 5.14 スタートフロアせってい

スタートフロアせってい

図のようなメッセージが出現する。 「はい」と答えると、 冒険の書を選択してゲームを開始する時点でのフロアが、 テストフロア (ID: 0001h) となるフラグ ($7E3500 |= 0004h) が立つ。 「いいえ」はその逆となる。

ざひょうウィンドウ

図 5.15 ざひょうウィンドウ

ざひょうウィンドウ

図 5.16 ざひょうウィンドウ

ざひょうウィンドウ

図のようなメッセージが出現する。 「はい」と答えると、移動モードにおいて R ボタンを押したときに、 画面右下に現在の座標を表示するウィンドウ (ID: 007C) が出現するようになる。

ひとひょうじ

図 5.17 ひとひょうじ

ひとひょうじ

図のようなメッセージが出現する。 「いいえ」と答えると、パーティキャラクターを含む、人のグラフィックが描画されなくなる。 通常は「はい」の状態である。

ROMバージョン

図 5.18 ROMバージョン

ROMバージョン

ROMバージョンの情報を示すウィンドウが画面右上に出現する。 デバッグモードでは、このデバッグメニューから表示しなくても、 冒険の書メニュー画面や、王様に冒険の書を記録させるときにもこの ROMバージョンウィンドウが出現する。

プレゼンよう

画面がエンディングの終盤付近(スタッフロール終了後くらい)に切り替わる。

へんげのつえ

数値入力ウィンドウが出現する。 ここで 9 未満の数値を入力すると、 次に「へんげのつえ」を使ったときに化けるグラフィック ($7EC36B) がそれになる。 人オブジェクトのグラフィック ID ではなく、「へんげのつえ」処理規定の ID である。

サブルーチン $C1CB19 がデバッグメニューウィンドウの入力処理を行う。 デバッグメニューの項目名文字列 ID と、処理アドレスの対応テーブルが $C8D4B0 に定義されている。

5.1.1.2.2. すごろくでインチキ

図 5.19 この後にサイコロを振ること

この後にサイコロを振ること

図 5.20 サイコロ操作の画像と似てしまった

サイコロ操作の画像と似てしまった

ウィンドウを出す前に L ボタンを押すと、図のように数値入力ウィンドウが出現する (末尾のGが実にデバッグモードらしい雰囲気をかもしている)。 ここに 1 以上 6 以下の値を入力すると、 次からサイコロを振ったときの目が入力値と同じになる。 ちなみに 0 とキャンセルボタン押しは、この数値入力ウィンドウのキャンセルとなる。 7 以上の値を入力すると 6 になる。

「?」マスに止まった直後、図のように数値入力ウィンドウが出現する。 ここに 32 以下の値を入力すると、 本来ランダムであるハズの「?」イベントが、 入力した値を ID とするイベントが発生する。 ID 値と発生するイベントの対応については、すごろく解析の章で説明する。

5.1.1.2.3. 「ぼうけんのしょ3」新規作成で謎のパーティになる

図 5.21 謎のパーティ

謎のパーティ

「ぼうけんのしょ3」を新規作成すると、最後のステレオ・モノラル選択直後、 性格診断から始まらずに、図のフロア(テスト)からゲームが始まる。 勇者の性格は「まけずぎらい」である。レベルはすでに 99 である。 そして、3 人の仲間「モツオ」「はげまる」「いんちき」とパーティを組んでいる状態である。 レベル 99 の戦士、魔法使い、遊び人である。呪文はすべて習得済みであり、 なぜか性格が空白になっていたりする。

5.1.1.3. ゲームショーモード

図 5.22 まほうのたま使用直後

まほうのたま使用直後

おそらく $C1FFFE0001h になっているビルドは、 SFC 版ドラクエ 3 の発売以前にゲームショー等でプログラムを動作させるためのものだと思われる。 試しに後述の改竄を施した上で、 最初からゲームをプレイしていくと、すぐに以下のことに気付く。

  • 王様やシスターが冒険の書を記録しなくなる(彼らの台詞は通常通りにもかかわらず)

  • パーティのレベルが 5 を上限に、レベルアップしなくなる(経験値は普通に増えていくにもかかわらず)

  • いざないの洞くつで「まほうのたま」を設置すると、 なぜか「すべてをつかさどる者」の台詞 (ID: 0FAC-0FB1) が出現して、ゲームが終了する (画面暗転後、ENIX のロゴマーク表示)。 そして、冒険の書選択画面になる。

5.1.2. 改竄

改竄作業は $C1FFFE の 2byte 値書き換えを含む。 この値を少なくとも負の値 (e.g. FFFFh) にしないと、デバッグモードでのみ有効なコードを処理させることができなくなる。 しかし、この値を負の値にすることで特定のサブルーチンが無限ループに陥るようにプログラムされている。 よって、そのようなすべてのサブルーチンのコードをも改竄する必要がある。

まず、$C1FFFE に相当するメモリを負の値、例えば FFFFh に書き換える。 バイナリエディタを用いるのが単純でよいだろう。 ROM イメージファイルを編集モードで開き、 ファイルオフセット 1FFFEh バイトにある 2 バイトを FF FF と上書きするだけである。

次にプログラムコードの改竄を行う。 まずサブルーチン $C6FFEC に含まれる以下のコードの分岐命令を適当に変更する必要がある。 これもバイナリエディタで適当に編集するだけでよい。 記者の場合は、$C6FFFA にある BEQ 命令 (Opcode F0) を BRA 命令 (Opcode 80) に改竄して動作を確認した。

C6/FFEC:    C230        REP #$30
C6/FFEE:    F47E7E      PEA $7E7E
C6/FFF1:    AB          PLB 
C6/FFF2:    AB          PLB 
C6/FFF3:    AFFEFFC1    LDA $C1FFFE         // リリース版では常に 0
C6/FFF7:    C90000      CMP #$0000
C6/FFFA:    F003        BEQ $FFFF           if($C1FFFE != 0000h){
                                                for(;;){
C6/FFFC:    EA          NOP                         ;
C6/FFFD:    80FD        BRA $FFFC               }
                                            }
C6/FFFF:    6B          RTL

最後の改竄箇所は以下のサブルーチンのどこかの分岐命令である。 プログラム改造の定石に従い、BPL 命令を他の命令(例えば BRA 命令)に書き換えるのがよい。

// ここへは JMP で飛んでくる
C0/2774:    C230        REP #$30
C0/2776:    AFE07D7E    LDA $7E7DE0
C0/277A:    1A          INC A
C0/277B:    1A          INC A
C0/277C:    8FE07D7E    STA $7E7DE0
C0/2780:    C90800      CMP #$0008
C0/2783:    90D8        BCC $275D
C0/2785:    AFE47F7E    LDA $7E7FE4
C0/2789:    F0C7        BEQ $2752
C0/278B:    E220        SEP #$20
C0/278D:    A901        LDA #$01
C0/278F:    8FDE7F7E    STA $7E7FDE         $7E7FDE = 01h
C0/2793:    C220        REP #$20
                                            for(;;){
C0/2795:    AFFEFFC1    LDA $C1FFFE             // リリース版では $C1FFFE == 0
C0/2799:    1009        BPL $27A4               if($C1FFFE < 0){
C0/279B:    AFF87F7E    LDA $7E7FF8                 // デバッグ版のみここを通る
C0/279F:    290010      AND #$1000
C0/27A2:    D008        BNE $27AC                   if($7E7FF8 & 1000h) break
                                                }
C0/27A4:    AFDE7F7E    LDA $7E7FDE
C0/27A8:    F0A8        BEQ $2752               if($7E7FDE == 0) goto ...
C0/27AA:    80E9        BRA $2795           }
                                            for(;;){
C0/27AC:    AFDE7F7E    LDA $7E7FDE
C0/27B0:    F0E3        BEQ $2795               if($7E7FDE == 0) goto 最初のループ
C0/27B2:    80F8        BRA $27AC           }

もしお使いの環境の PAR コード改造機能が、 RAM に加えて ROM の任意のアドレスの値を書き換えることを許していれば、 ROM イメージのバイナリデータを書き換える代わりに、 以下のコードを必要に応じて入力するとよい。

表 5.2 デバッグモードのための PAR コード改造

Address Value
$C1FFFE FFFF (2byte)
$C6FFFA 80 (1byte)
$C02799 80 (1byte)