FF3 でバグを使って最速クリアする方法

FF4 の 64 階層バグの動画をみていたく感動した。動画投稿者の方の web サイトを見たらいろいろ書いてあったので、ファミコンの FF3 のバグを起こしてエンディングへ行く方法を mess のデバッガで調べた。

http://www.nicovideo.jp/watch/sm16743542

この動画で調べると動作原理的に重要なパラメータが3つある。

  • キャラ1のジョブ番号
  • 戦闘終了フラグ
  • 座標位置とゲーム進行上のフラグ

このゲームはキャラが4人いるのでこの手のパラメータは4つ用意してある。以降の説明のメモリアドレスなどは先頭キャラについて言及する。

ジョブ番号

これは CPU address $6100 に格納される番号で、0x00 から 0x0f が正常値、それ以外がプログラム上の想定外の値で不正値とする。これのメモリの直前がアイテムで、アイテムのメモリ領域を何かしらのバグを利用すると $6100 が高確率で不正な値に書き換えられる。

戦闘中でのジョブ番号はコマンド欄($7400から4 byte)の展開に indirect jump table (C でいうところの関数ポインタ)を利用する。このテーブルは正常値の範囲でのみ用意されているので、不正値だとどこを実行するかは予測できない。

この中ではメモリを盛大に破壊して、プログラムが止まるもの、運良く止まらないものがでてくる。動画で紹介されたジョブ番号は 0x1e で、RAM を盛大に破壊してゲームが止まらないことが多い。

戦闘終了フラグ

コマンド(たたかう、にげる、アイテムなど)も indirect jump table で構成され、不正値が入ると動作が不安定になる。ジョブ 0x1e の4番目のコマンド 0xa8 は 2 byte を定数に書き換えるだけでかなり安全なコードで、これ自体は重要ではない。

動画の 7:30 付近で先頭キャラのコマンド選択で2度キャンセルしているが、そのときにコマンド展開が暴走して RAM を広範囲に破壊する。address は $7400-$7bff のあたりが破壊されるらしい。

キャラ1が4番目のコマンドを実行して、戦闘が強制終了する。これは前述のようにあまり重要ではないが何故かプレイヤー側のコマンド選択が強制的に終わる。このあとに戦闘終了フラグを参照していて、戦闘続行、戦闘強制終了(おそらく1度目のくらやみのくもに使うことが正常)、戦闘勝利、GAMEOVER にわかれる。コマンド 0xa8 実行ではなくキャラ4のコマンドを普通に選択したあとでもよい。

address は $78d3 で data は bitfield を持っているらしい。

  • bit7 gameover
  • bit2 戦闘勝利
  • bit1 強制終了

各bitの優先順位はよくわからんが、 bit7=0,bit2=0,bit1=1 を満たすと戦闘は終わる。(0xff でロード画面, 0x00 で戦闘続行)

座標位置とゲーム進行上のフラグ

戦闘集合後、移動画面に戻るための処理を行う。このときに、プレイヤーの位置情報をカートリッジ RAM から zero page にコピーする。位置情報の他に進行のフラグも入っているらしく、戻すべき情報が破壊されているとエンディングに突入してしまうことがある。

address はカートリッジRAMの方が $7480-$74ff, zero page が $0000-$007f である。現段階ではどれがエンディングフラグかはわからないが、町の中とダンジョンで正常に起こした戦闘から、エンディングに突入する直前の RAM の $78d3 と $7480-$74ff だけを同じ値にすると戦闘が終わった後に同じ動作をすることを確認した。(セーブが出来る屋外は戦闘終了後の処理が違うのでエンディングにいかない)

最適化を行うために

現段階での不確定要素は RAM の破壊の法則で、これは本来プログラムでないものを実行するので予想はしづらい。とはいえ、破壊すべきアドレスと破壊して欲しい値を絞り込めたので最適化がしやすくなったと思う。

補足

ろうが... で有名なジョブ 0xb7 のコマンド 0x1e (表示名は空欄)は戦闘を強制終了できるが、 $78d3 を参照せずに直接終わらせるので、そこを書き換えなくてもいいようだ。