『ゼルダの伝説 ムジュラの仮面』VC版にて、デバッグメニューを呼び出す方法が発見される。「大翼の歌」を“63回”吹きメモリを上書き


往年の名作『ゼルダの伝説 ムジュラの仮面』(以下、ムジュラの仮面)にて、ゲーム内でデバッグメニューを呼び出す方法が発見された。デバッグメニューとはその名のとおり、ゲームの開発者がデバッグ用に使うメニューのこと。『ムジュラの仮面』ではルピーやハートの最大値、オカリナの各歌の所持状況などさまざまな値を自由に変更することが出来る。当然、通常ならばプレイヤーは絶対にアクセスできないメニューだが、チートツールなどを使わずに呼び出す方法が見つかってしまったのだ。

『ゼルダの伝説』シリーズは非常にスピードランの人気が高いシリーズだ。コミュニティの規模が大きく、走者の数も多い。そして、その分だけ各タイトルの研究も進んでいる。スピードランとは基本的には「許されたありとあらゆる手段を用いて、なにがなんでも早くクリアする」のが趣旨である。もちろん競技性や公平性を担保するために最低限のルールや制限が課せられることもあるが、特にAny%と呼ばれるカテゴリではその制限も無いことが多く、早くクリアするためならなんでも許される傾向がある。そして、そんなAny%では往々にしてスピードランナー達によってゲームは「壊されて」しまう。もちろん物理的な意味で破壊するのではなく、ゲームとしての原型をとどめていないほど、通常プレイからは乖離したプレイになるということだ。『ゼルダの伝説』シリーズはその研究の進み具合も相まって、特に壊されているゲームとして有名だ。

今回の『ムジュラの仮面』のデバッグメニュー呼び出しも、ゲームブレイカーたるスピードランナー達の研究の成果だ。実際に呼び出すにあたっては複雑な手順を踏む必要があるのだが、その前にIndex Warpと呼ばれる以前から知られていたバグ技について説明する。

 

鍵を握るSoar Index

『ムジュラの仮面』には「大翼の歌」というオカリナの歌が存在しており、これを使用すると起動したことがあるフクロウ像へとワープすることができる。そして、クロックタウンにはHidden Owl(隠しフクロウ)と呼ばれるフクロウ像が存在する。このフクロウ像は本来なら辿り着くことは出来ないが、ボムホバーと呼ばれるテクニックなどで壁を超えると叩いて起動することができる。そして、他のフクロウ像を一切起動せずこの隠しフクロウのみを起動した状態で大翼の歌を使うと、起動したことがない正規のフクロウ像にワープすることが可能なのだ。

この時、ワープする先のフクロウ像はSoar Indexと呼ばれている値で決まる。大翼の歌を使用する前、マップ画面でカーソルを合わせていた位置によってSoar Indexは決まり、ワープする先に対応するという仕組みだ。たとえばゴロンの里にカーソルを合わせていた場合のSoar Indexは9であり、対応するフクロウ像はロックビル。よってロックビルにワープすることができるというわけだ。

Image Credit : Sva

ここまでが今まで知られていたIndex Warpというバグ技だったのだが、さらにこれを悪用するIndex Warp Text Overflowという技が2019年に発見された。これを説明するためには、まずSoar Indexと、『ムジュラの仮面』のテキスト表示の手順について説明する必要がある。

たとえば先の例では、ゴロンの里にカーソルを事前に合わせていた時のSoar Indexは9であった。この時大翼の歌を使うとロックビルへワープすることができるわけだが、その時表示される「ロックビルへ飛びますか?」というテキストボックスの内容もまた、当たり前の話だがSoar Indexの値から計算されている。この時の、メモリ上での動作が非常に大切となる。

『ムジュラの仮面』のゲームがこの「○○に飛びますか?」というテキストボックスに表示する行き先を計算する時の手順は以下のとおりだ。まず、表示するテキストの長さが取得される。この値をまとめて格納している場所がメモリ上に存在し(便宜上「文字数格納域」と呼ぶ)、そのアドレス域からSoar Indexを2倍にした値分のオフセットアドレスの値を「テキストの長さ」として読み込む。具体的には、Soar Indexが2だった場合、文字数格納域の最初のアドレスから4バイト先のアドレスを参照する。英語版ではこのアドレスに格納されている値は08であり、つまり表示されるべきワープ先の文字数が8であることを示している。

Image Credit: fggkyle

次に、実際に行き先として表示される文字列を取得する。こちらも同じく、行き先の文字列をまとめて格納している場所があり(便宜上「文字列格納域」と呼ぶ)、Soar Indexを16倍した値をオフセットとして、そこから上で求めた文字数分の値を読み込む。先程の例と同じようにSoar Indexが2だった場合は、文字列格納域の最初のアドレスから32バイト先のアドレスを参照し、そこから8バイト分(上で求めた文字数)のデータを読み込むということだ。英語版では読み込んだデータは53 6E 6F 77 68 65 61 64となり、これはSoar Index 2の時のワープ先である「Snowhead」(スノーヘッド)という8文字となる。

Image Credit: fggkyle

さて、以上の手順でSoar Indexからワープ先を示すテキストが得られたわけだが、実際にこれがゲーム上で表示されるにはもうひとつ手順が挟まれている。『ムジュラの仮面』には「メッセージ格納域」とでも呼ぶべきメモリ域が存在する。ゲーム上で表示されるテキストは一旦このメッセージ格納域に書き込まれる必要がある。Soar Index 2の時の例だと、「スノーヘッドに飛びますか」の英語版である「Soar to Snowhead」というテキストがこのメッセージ格納域に書き込まれ、その後読み出されてゲーム上で実際に表示されるということだ。

 

Soar Indexの値を自由に書き換える

Soar Indexが0~10の間に収まっている場合、上記の手順はなんの問題もなく動くわけだが、残念ながらこのSoar Indexを任意の値にする方法がIndex Warpの時点から知られていた。Sva氏のIndex Warp解説動画では最後に説明されているが、マップのカーソル画面でRに合せていた時、Soar Indexは11となっている。この状態で大翼の歌を使用し、ワープ画面をキャンセルし、再びポーズ画面のマップでRに合わせる、という手順を踏むとSoar Indexにさらに1を加えて12にすることができる。「マップでカーソルをRに合わせる→閉じて大翼の歌を吹く→ワープ画面をキャンセルする」という一連の動作を繰り返すごとにSoar Indexが1ずつ増えていき、Soar Indexを任意の値にすることができるわけだ。

Image Credit : Sva

ではSoar Indexの値を好きに弄れると先程説明したメッセージ表示の手順はどうなってしまうのか?たとえばSoar Indexを30にした場合で考えてみると、まず文字数格納域から30*2=60バイト先のアドレスの値が「文字数」として読み込まれる。この例では170となる。次に、文字列格納域から30*16=4800バイト先のアドレスから、170バイト分が「文字列」として読み込まれる。最後に、この170バイト分のデータがメッセージ格納域に書き込まれる。最後にゲームによってメッセージ格納域が読み込まれ、実際にテキストを表示しようとするが、もちろんこれは適切なデータではないためバグった表示となる。

Image Credit: fggkyle 実際の170バイト分のデータ

さて、Soar Indexが30の時はたまたま文字数の値が170だったから良かったものの、本来メッセージ格納域は200バイト分しか用意されていない。だが当然、Soar Indexの値によっては文字数として200以上の数値が読み込まれてしまうことはある。たとえば文字数が1000だった場合、Soar Index*16で指定されたアドレスから1000バイト分のデータが読み込まれるし、メッセージ格納域にもその1000バイト分のデータが書き込まれる。この時、データは200バイト分までで切り落とされるのではなく、メッセージ格納域として用意されている領域のさらに先まで、800バイト分上書きされてしまうのだ。つまり、ゲーム内の手順によってメモリを操作し、適切なSoar Indexを指定しこれを読み込むことで、メッセージ格納域のさらに先にある本来ならば弄れないメモリ領域を限りなく任意の値で上書きすることが可能なのである。これがIndex Warp Text Overflow、そしてデバッグメニュー呼び出しの仕組みだ。

 

大翼の歌を63回吹いてデバッグメニューの扉開く

Index Warp Text Overflowの仕組みが理解できたならば、つまりデバッグメニューを呼び出すための手順のほとんどはSoar Indexによって読み込むメモリの内容を操作するための動きだということがわかるだろう。実際の手順はこちらのいわび氏の記事にて詳細に解説されている。脈絡がない上に精密な動作を要求されるが、メモリの内容を弄るための手順であるのでゲーム画面上での意味はない。準備が全て終わったら、Soar Indexを+1するための手順である「マップでカーソルをRに合わせる→閉じて大翼の歌を吹く→ワープ画面をキャンセルする」を63回繰り返すと、メッセージ格納域の奥のアドレスがいい感じに上書きされてデバッグメニューが開けるようになってしまうというわけだ。

このデバッグメニュー呼び出しの手順は現在日本版のWiiUバーチャルコンソールでのみ可能となっている。日本版と英語版では文字数格納域のアドレスなどが違うため、もし英語版でもデバッグメニューを呼び出したい場合は全く違った手順を踏む必要があるだろう。

また、このデバッグメニュー呼び出しは実際にAny%カテゴリの最速ルートに採用されている。Speedrun.comの該当ページを見れば分かるが、このデバッグメニュー呼び出しが実用化される前の記録は「No Text Overflow」というカテゴリに移動しており、以前の記録も1時間15分ほどであったのがこのテクニックによって一気に50分を切るところまでタイムが縮んでいる。デバッグメニューを呼び出すためのメモリ書き換え手順が、実際にタイム短縮になるような形で発見されたというのは、奇跡的なことだと言えるし、あるいはスピードランナー達の恐るべき努力と研究の成果であるとも言えるだろう。

『ゼルダの伝説』シリーズのスピードランに使われるテクニック達は、ほとんどリバースエンジニアリングの域に達している。8月上旬に開催されていた国内の大規模オンラインスピードランイベントである「RTA in Japan Online 2019」ではSva氏が『ゼルダの伝説 スカイウォードソード』を走り、こちらも今回のデバッグメニュー呼び出しに劣らないような荒唐無稽なテクニックが多数披露されたことで話題を集めた。『ゼルダの伝説』ランナー達の情熱は留まる所を知らず、これからもさまざまなテクニックやバグ技が産み出されていくことは間違いないだろう。少しでも興味深いと感じたならば、ぜひコミュニティごと追うべきだ。