『マリオカートWii』では“32768周逆走”すると、2ラップでゴールできるようになる。研究家が奇妙なバグ挙動を報告


10年以上前のゲームでありながらもいまだにTASなどの研究が非常に盛んである『マリオカートWii』において、また新たなバグ挙動の研究成果が発表されている。今回の内容は本作のラップカウントシステムの仕様の穴を突くものとなっている。その手段とは、32768周逆走である。これによって、本来ゴールには3ラップする必要があるが2ラップになったり、「LAP 8/3」といったありえない表示がゲーム内で実現してしまうほか、2フレームというとんでもなく短いラップタイムが実機でも実現してしまう可能性があった。TASユーザーのMalleo氏が解説動画を投稿しており、本稿では主に動画内で解説されている内容に触れる。

今回『マリオカートWii』のラップカウントシステムが研究の対象となったのは、プレイヤーのラップ記録に使われているメモリが、現実的な範囲でアンダーフローを起こせる仕様であったことに起因する。オーバーフロー/アンダーフローとはゲームのバグの話題などでは特によく聞かれる単語の一つであり、「想定されている最大値からさらに足そうとした時や、最小値からさらに引こうとした時にループして意図せぬ値になってしまう現象」のような理解で問題ない。正確を期すならばここで言うアンダーフローはオーバーフローの一種であるが、Malleo氏が本現象をアンダーフローと明言していることから本稿でもアンダーフローと記載する。所持数が0のアイテムを使って消費すると逆に99個になってしまうなどは(今どきこんなコテコテのバグが起こるゲームがあるのかどうかは別として)アンダーフローの代表的な現象と言えるだろう。
【UPDATE 2021/1/18 20:55】
本稿でアンダーフローという表現を使用している理由について追記

Image Credit : Malleo / 任天堂



ラップカウントシステムを構成する4つの変数

では『マリオカートWii』のラップカウントシステムは実際にどうなっているかというと、まず本作はプレイヤーのレース進行状況を管理するのに4つの値を扱う。ひとつめはcurrentLapという値で、文字通りプレイヤーが現在どのラップにいるのかを記録する。この値は1で始まり、プレイヤーが(正しい方向に)ゴールラインを踏むたびに+1される。『マリオカートWii』においてコースは3周でレース終了となるが、プレイヤーが3周を終えて、フィニッシュ後の自動運転となっている時はcurrentLapの値は4となっている。

ふたつめはlapCompletionという値で、これは0から1の間を取り、プレイヤーがそのコースにおける1周をどれほど終えたかを記録する値となっている。厳密には細かくチェックポイントの通過を確認するような仕様であるらしいが、簡単に言えばコースの1周のうち半分を終えているならばこの値は0.5になるということだ。ゴールラインを踏むごとに、この値は0にリセットされる。

みっつめはraceCompletionという値で、これはcurrentLapとlapCompletionの値を足した値となっている。つまりプレイヤーが1周を終え、2周目を半分ほど走破した時のraceCompletionの値は2.5となる。よっつめはmaxLapという値で、ほぼcurrentLapと同じだがラップカウントやジュゲムの表示に使われる値となっており、これについては後述する。

今回問題となるのは最初の3つの値、currentLap、lapCompletion、raceCompletionに使われているデータ型である。currentLapには2バイトの符号付き整数型、lapCompletionとraceCompletionにはそれぞれ4バイトの単精度浮動小数点型が使われている。つまり、currentLapは-32768から32767の範囲の値しか取ることができず、コースを32768周逆走することによってこの値をアンダーフローさせることができるのだ。また、raceCompletionに使われている4バイトの単精度浮動小数点型はcurrentLapとは比較にならないほど大きな範囲を取る型ではあるのだが、整数部にcurrentLapの値をそのまま持ってくる処理をしている都合上、結局ラップ-32768でraceCompletionの値もアンダーフローを起こしてしまう。

Image Credit : Malleo / 任天堂



突然終了してしまうレース

では実際にコースを32768周逆走してcurrentLapをアンダーフローさせるとどうなるのか。ラップ-32768を走り終えた瞬間に振り返り、ゴールラインを(本来の方向で)横切ると、99分59.999秒というカンストしたラップタイム、8/3というラップカウントと「LAP 5」と書かれたボードを持つジュゲムが表示される。また、この現象が起きた直後に再び逆走しゴールテープ前に戻ったあと、もう一度ゴールラインを正しい方向で横切るとFINISH!と表示されレースが終了する。ゴールラインを順路方向に横切ったのは2回であるにも関わらず、3周した扱いとなるのだ。

なぜアンダーフローが起きた直後のゴールでも即座にレースが終了せず、2回目でレースが終了するのか。これには前述したmaxLapという値の仕様が関係してくる。maxLapはゲームがラップカウントの表示やジュゲムの持つボードの種類を判断する時に使われる値で、ゲームを普通にプレイしている範囲ではcurrentLapとほぼ同じ値を取る。1周目であるなら1、2周目であるなら2となるわけだ。ただし、このmaxLapがcurrentLapと違う点はこの数値が正しい方向にゴールラインを横切った時のみに更新されるということだ。プレイヤーが何万周も逆走している間、currentLapはどんどん負の値に進んでいくが、maxLapは1に固定されたままである。

Image Credit : Malleo / 任天堂


さらに、このmaxLapを扱うゲーム内におけるコーディングが、例の「2周終了」の原因となっている。このコードにおいて、lapCountという変数はレース終了までの必要周回数であり、3に固定されている。if文ではmaxLapとlapCountの数値が比較され、maxLapがlapCount未満である限りcurrentLapの値がmaxLapに代入される。ラップ-32768を終えcurrentLapがアンダーフローしてからゴールラインを最初に踏む時、この処理は実行されmaxLapには本来ありえないほど大きな数値が格納されることになる。currentLapの最大値は32767だが、このmaxLapへの代入は下位バイトしか行われないため、maxLapはこの時最大で255となる。再び逆走したあとにもう一度ゴールラインを横切ると、同じif文が実行されるが今回はmaxLapがcurrentLapより大きい数字となってしまっているため、ゲームは例外処理コードを実行し、レースを即座に終了させるとともにラップ3のタイムを99分59.999秒に設定する。2回のゴールでレースが終了してしまうからくりはゲームの(おそらくはバグに備えた)仕様に起因するものだというわけだ。

残っている謎の内、まずラップカウントが8/3となる理由は単純に表示の上限が8とされているためだ。なぜ9ではなく8なのかは、完全に謎なようだ。ジュゲムが「LAP 5」と表示される理由としても、単純にテクスチャが5以降は用意されていないのだ。一番の謎は消えたラップ2である。ラップ1はそもそも32768周逆走している間の時間がすべてカウントされているのでカンストしているのは納得できる。ラップ3に関しても前述した例外処理コードによってカンスト数値に固定される。しかし、そもそもゴールラインを2度しか越えていないので、特殊な処理もなかったラップ2の数値は0秒であってもおかしくないのだが、実際はゴール時にラップ1やラップ3と同じくカンストの99分59.999秒として記録される。なぜなのか?

奇妙なゲーム内タイマーが邪魔をする

これは『マリオカートWii』におけるタイマーの奇妙な仕様が理由となっているようだ。本作のタイマーは(メモリ的にそれ以上の数字も容易に扱えるにも関わらず)8時間20分丁度に上限が設定されているのだ。レースが開始してから8時間20分以上が経過するとゲームは「バグ防止用モード」のような状態となり、すべてのラップの数値が99分59.999秒で固定される。なぜ8時間20分という中途半端な時間に上限が設定されているかは謎とされており、Malleo氏を始めとした『マリオカートWii』の研究者たちはこの仕様にひどくがっかりしている。

というのも、彼らにはこのラップアンダーフローの仕様を利用してFlapと呼ばれるタイムトライアルのカテゴリに革命をもたらすことを画策していたのである。FlapとはFast Lapの略であり、3周ではなく1周の時間を競う(ユーザー間における)タイムトライアルカテゴリのことである。このアンダーフローを発見したプレイヤーたちは、まずアンダーフローでcurrentLapを32767にした上でさらに追加で30000回以上逆走し、逆走のみでcurrentLapとraceCompletionを3にすれば例外処理コードを回避しつつゴールラインの上を素早く前後移動するだけで理論的にもっとも短いラップ3記録(2フレーム)を実現することができるのではないかと考えたのである。Flapに逆走してはいけないというルールはないため、65000回 以上逆走する根気とエラーを起こさないWiiさえあれば人間にも2フレームのラップタイムが実現可能なのだ。もちろんこれが可能だったとしてこの記録が正式に受理されるかどうかは、コミュニティ次第だとは言っている。

SwareJonge氏による0.03秒のラップタイムのスクリーンショット。これはゲーム内currentLap値を直接編集することで実現した。 Image Credit : Malleo / 任天堂


しかし残念ながら8時間20分を上限とする前述の仕様によってこれは実質的に不可能となってしまった。8時間20分(30000秒)以内にラップアンダーフローを実現するためには、最低限でも1周1秒未満で逆走できるコースが必要となる。到底人の手では現実的と言えない数字だ。Malleo氏は「何時間も研究したにも関わらず、最後に妙なタイマーの仕様に邪魔されてラップ記録が実現できなかったのは残念だ」と述べているが、彼らの熱意ならば8時間20分以内にアンダーフローを実現する方法や、他の新たな「壊し方」をもいずれ見つけてしまうのかもしれない。