読者です 読者をやめる 読者になる 読者になる

FC『ダブルムーン伝説』預かり所バグの実用化 その1

2012/02/13 追記: 預けアイテム個数が 48 を超えているとさらにアイテムを預けられることが判明したため、補足記事を書きました。

預かり所バグに関しては一応TAS動画(28:40.85)の投稿者コメントでグダグダと書きましたが、不十分もいいところなので少しまともに説明してみます。

まず、預けアイテム/PTキャラID付近のメモリマップを確認しておきます:

$63FE U8 預けアイテム個数
$63FF-$642E U8[48] 預けアイテム
$642F-$6436 U8[8] 宝箱開封済フラグ
$6437 U8 おそらく普通は常に0だが、セーブデータには記録される
$6438 U8 船座標y
$6439 U8 船座標x
$643A-$643C U24 町ブックマーク
$643D-$643E U16 カジノチップ枚数のコピー
$6477-$647A U8[4] PTキャラID
$647B-$6481 U8[7] 雑用
$6482-$6484 U24 所持金

預かり所バグは、48個アイテムを預けているときに49番目の空欄を引き出すことにより発生します。ただしこの操作には前提条件があります:

  • $642F (宝箱フラグ先頭Byte, 49番目の空欄に相当)が0でないこと
  • $642F が 0xAE でないこと(この値だと預けアイテム7ページ目を開いた瞬間フリーズ)*1
  • $63FE (預けアイテム個数)が 0x2B 以上であること(さもないと預けアイテム7ページ目を開けない)

49番目の空欄を引き出したとき何が起こるかというと、大まかには「$63FE-$64FD が1Byte左ローテート」されます。厳密には以下の通り:

  • $63FE は $63FF の値から1を引いたものになる
  • $63FF-$642D は次のアドレスの値になる
  • $642E は変化しない
  • $642F-$64FC は次のアドレスの値になる
  • $64FD は $63FE の値になる

実際に例を見てみます。初期状態でアイテムを48個預けていて、メモリが以下のようであったとしましょう:

      00 01 02 03 04 05 06 07   08 09 0A 0B 0C 0D 0E 0F
63F0: .. .. .. .. .. .. .. .. - .. .. .. .. .. .. 30 3F  # 預けアイテム個数預けアイテム
6400: 40 41 42 43 44 45 46 47 - 48 49 4A 4B 4C 4D 4E 4F
6410: 50 51 52 53 54 55 56 57 - 58 59 5A 5B 5C 5D 5E 5F
6420: 60 61 62 63 64 65 66 67 - 68 69 6A 6B 6C 6D 6E 01  # 宝箱フラグ
6430: 02 03 00 00 00 00 00 00 - BE EF 11 12 13 00 .. ..  # 船座標町ブックマーク
...
6470: .. .. .. .. .. .. .. 00 - 01 02 03 00 00 00 00 00  # PTキャラID
6480: 00 00 A0 86 01 00 .. .. - .. .. .. .. .. .. .. ..  # 所持金
...
64F0: .. .. .. .. .. .. .. .. - .. .. .. .. .. .. .. ..

このとき、49番目の空欄(アイテムID 0x01, ルーンテクター)を引き出すと、メモリは以下のように変化します:

      00 01 02 03 04 05 06 07   08 09 0A 0B 0C 0D 0E 0F
63F0: .. .. .. .. .. .. .. .. - .. .. .. .. .. .. 3E 40
6400: 41 42 43 44 45 46 47 48 - 49 4A 4B 4C 4D 4E 4F 50
6410: 51 52 53 54 55 56 57 58 - 59 5A 5B 5C 5D 5E 5F 60
6420: 61 62 63 64 65 66 67 68 - 69 6A 6B 6C 6D 6E 6E 02
6430: 03 00 00 00 00 00 00 BE - EF 11 12 13 00 .. .. ..
...
6470: .. .. .. .. .. .. .. 01 - 02 03 00 00 00 00 00 00
6480: 00 A0 86 01 00 .. .. .. - .. .. .. .. .. .. .. ..
...
64F0: .. .. .. .. .. .. .. .. - .. .. .. .. .. 30 .. ..

これを見ると、空欄を何度も引き出し続ければ所持金でPTキャラIDを上書きできそうです。ただし、先に述べた前提条件を崩さないよう注意する必要があります:

  • 次回の預けアイテム個数 $63FE が 0x2B 以上になるようにする
  • 次回の49番目の空欄 $642F が 0 または 0xAE にならないようにする

前者については、なるべくIDが大きなアイテムを預けアイテムの先頭に配置しておけば問題ありません。厄介なのは後者ですが、0になってしまったら改めて宝箱を開ける、などの対策を講じれば何とかなります。

PTキャラIDを書き換えられると何が嬉しいのかは次回

なお、先の例では49番目の空欄が 0x01 (ルーンテクター)だったので、これを引き出すことでルーンテクターが入手できそうに思えますが、実際は不可能です。これはアイテム入手処理の作業用変数 $64F5 が預かり所バグによりシフトされる領域内にあり、その結果、キャラデータではなくROM領域(正しくはMMC3レジスタ?)に対して書き換え処理が行われるためです*2

*1:たまにフリーズしないことがあるようだが条件不明

*2:$CF7F, $CEAE に対して書き込みが行われる模様。NesDevWikiによればこれらはIRQ関連レジスタのようだが、このゲームはIRQを使用していないので書き込んでも影響が出ないものと思われる