『モンスターワールドII ドラゴンの罠』1989年オリジナル版のリバースエンジニアリング:正確性の探究

こんにちは、Lizardcube社(現在フランスのパリを基点にしています)のOmarです。私は新作ゲーム「Wonder Boy: The Dragon’s Trap」のテクニカルディレクタ兼プログラマです。このゲームは、1989年にセガ/ウエストンにより発売された『モンスターワールドII ドラゴンの罠』のリメイク版です。このオリジナルは、初期のmetroidvaniaスタイル(訳注:メトロイド(METROID)や悪魔城ドラキュラ(Castlevania)風)のアクションアドベンチャーであり、カルト的な古典作品になっています。我々はこのゲームのライセンスをオリジナルの開発者から買い取りました。ゲームはDotEmuで公開される予定です。

メカドラゴンの呪いにより半人半竜のモンスターにされてしまった孤独な冒険者の、一生に一度の挑戦が始まる!
姿を変えられたアンチヒーローは呪いを解く方法を求め、モンスターランドの幾多の罠を冒険し、物を投げたり呪いを放ったりしてくる数多のドラゴンを倒していきます。
トカゲ・ネズミ・ピラニア・ライオン・タカ……1つの体でいくつもの変身、生き残ることはできるか?
変身ヒーローの6つの異なる形態が、このノンストップのアクション・アドベンチャーのプラットフォームの登場人物です!

リメイク版の様子がこちらです。 (2016年6月公開のトレーラー)

この記事は私たちの、より幅広い読者層向けに書いた開発ブログからのクロスポストです。しかし、この記事で扱う主な問題はあまりに技術的になってしまうため、表面的なところを触れてみるだけに留めておきます。ゲーム制作の裏側の一部を説明し伝える試みは素晴らしいだろうと考えたのです。

『モンスターワールドII ドラゴンの罠』のリメーク版を開発することを決めた際、自らに課した最も重要な目標の中に、オリジナル作品のゲーム性に忠実かつ敬意を示した作品を作るというものがありました。コントローラを握るプレーヤに、慣れ親しんだ我が家(つまり、昔なじみのモンスターワールドです)のように感じてほしいのです。つまり、操作やゲームプレー・メカニクスなどは、特に正確でなければいけないということです。タイミング、物理的な特性、反応を適切だと感じられるようにしたいですし、安っぽいリメークにはしたくありません。

こういったレベルで再現することは、やりすぎであるように見えるかもしれません―もしあなたが、このゲームと共に少年時代を過ごしたのでなければ。そう、例えば、ゼルダやメトロイド、マリオのリメイクを作ることを想像してみてください。間違ったものを作ることは単純に許されません!『スーパーマリオブラザーズ』をオリジナルの物理/タイミングから外れた形でリメイクなんてしたら、あなたのオフィスの前で暴動が起こることは間違いないでしょう。

『ドラゴンの罠』は私たちの少年時代でしたし、任天堂の古典作品と同じぐらいに敬意と正確性をもってこのゲームを扱いたいと思ったのです。

オリジナル版には未知の要素が数多くあります。

  • ヒットポイントは、どのように計算されているか
  • アイテムドロップには、どんな規則性があるか
  • ポーションの補充には、どんな規則性があるか
  • ボックスに当たると、どのようなアニメーションが表示されるか
  • Cyclopsは、なぜ水中のボックスに入っているのか
  • キャラクターの物理的特性には、どんな方程式が組まれているのか
  • そもそも、すべての謎に気が付いているか

当て推量ですべてを真似したり、作り変えることでオリジナル版が持つマジックを失ったりはしたくありません。そのため、まずはオリジナル版のコードを詳しく調べることから始めました。

ゲームデータを抽出する方法(困難な道のり)

私の計画は、ゲームデータの抽出を正確に最初から行うというものでした。そのため、コンテンツを抽出するためにオリジナル版のカートリッジを取り出してダンプしました。レトロゲームを扱うフォーラムで知り合った人なら、私が昔のSEGA 8ビットゲームに取りつかれているのを知っているでしょう。私はカートリッジに次のようなことをしました。

Dumping a prototype cartridge
プロトタイプカートリッジのダンプ

(劇的な効果を狙って、上の写真では『R-TYPE』のプロトタイプを使っています。1987年に開発者が使用していた、大きくて長いボードに配置したものです(コンパイル社がこのバージョンを作りました)。日本製のコンソールなのでボードを自家製のアダプタに挿し込みました。コンソールの後ろ側には、恐らくアクセサリをつなぐためにデザインされた拡張ポートがあります(日の目を見たことはありません)。書き込み可能なカートリッジと、カスタムメイドの変換アダプタを挿し込み、Z80アセンブラを使ってセガ・マスターシステム用の簡単なソフトウェアをプログラミングしました。ソフトウェアはコンソール上で実行されるとRAMにコピーされ、そこからレジュームされます。RAMに書き込まれたコードは、起動に使ったカートリッジをディアクティベートし、ゲームカートリッジのデータを読み取ります(こちらでは『R-TYPE』のプロトタイプを使っていますが、『モンスターワールドII ドラゴンの罠』のカートリッジでも同じ過程を踏みます)。そして、書き込み可能なカートリッジを再アクティベートし(後ろに挿し込みます)、ゲームデータをそこに書き込みます。書き込み可能なカートリッジはバッテリにサポートされているので、電源につながなくてもコンテンツは無事に保てます。次に、すべてを電源から抜き、カスタムメイドのSmsReaderを使ってパソコンからカートリッジを逆読み取りします。コンソールからオリジナルのカートリッジを読み取ると、実際のCPU、Z80が使うのと同じタイミングでアクセスできるようになり、正確なタイミングを必要とするであろうカートリッジの整合性を最大化できます。これらのように、カスタムメイドされた風変りなハードウェアの部品は、Mike GordonやCharles MacDonaldといったSmsPowerコミュニティのメンバーによって設計、構築されました。)

こうして、オリジナル版からデータを抽出できました。データは、262144バイトと、つまり256キロバイトのファイルにピッタリ合います。バイナリエディタで検証することもできますが、最初から多くは分からないでしょう。

Hexadecimal dump of the original game data
オリジナルゲームデータの16進ダンプ

コードを読む

解析は簡単ではありませんが、とにかくゲームのすべての詳細はそろいました。ある部分のバイトは(Z80アセンブラによる)プログラムコードであり、別の部分はゲームデータで、正直どれがどれとも、どのフォーマットがこれらのデータに適しているかも簡単には言えません。古いビデオゲームではエンジンもデータフォーマットも標準化されておらず、すべてはプログラマが所定のハードウェアのためにカスタマイズしたものです。オリジナルのゲームがどのような仕組みなのかを知る上でも、これは私が解読しなければなりません。このプロセスをリバースエンジニアリングと呼びます。

私は逆アセンブラでバイナリデータをZ80アセンブラコードにコンバートしました。それが次のようになります。

 029C: 21 AC 02     ld hl,02ACh
 029F: 11 6C CF     ld de,CF6Ch
 02A2: 06 14        ld b,14h
 02A4: 7E           ld a,(hl)
 02A5: EF           rst 28h
 02A6: 12           ld (de),a
 02A7: 23           inc hl
 02A8: 13           inc de
 02A9: 10 F9        djnz -07h (02A4h)
 02AB: C9           ret
 02AC: 26 80        ld h,80h
 02AE: A2           and d
 02AF: 81           add c
 02B0: FF           rst 38h
 02B1: 82           add d

読むのは難しいですね。たとえZ80 CPUの命令セットZ80上でのプログラミングを学んだとしても、逆アセンブルして得られたこのコードは、ほとんどのオフセット/番号/アドレス(例えば02AChやCF6Ch)が明示的な意味を持っておらず途方に暮れてしまいます。そんなわけでマスターシステムハードウェアの仕組みを学ばなければなりません。MEKA(作ったのは私です)のようなデバッガと連携したエミュレータの助けを借りると、マシンの状態を調べながらコードに踏み込むことができます。目的は、それぞれのアドレスには何が含まれているか、そしてコードの各断片が何に使われているかを見つけることです。

何とかこの混乱状態を脱するために、とりあえず当たって砕けろ戦法で当て推量していきます。それぞれの目的を理解しようとしながらコードブロックを個別に見ていくと、大まかながらもそれらを分類できるようになってきました(”アドレスXXXのこの関数は、カニの動きを制御するためのものかもしれない”)。また、ゲームを実行中にRAMメモリのダンプを解析することで、ゲームがデータをどこに格納しているのかについて、徐々に大まかな全体図を描けるようになってきました(”プレーヤの変数は、アドレスXXX辺りに格納されている”、”スクロールに関する変数はあそこかもしれない”などなど)。さらにROMをハッキングすることで、ゲームがデータをどのように扱っているかに関する自分の仮定を検証しました。そして私は、レベルがゲーム実行中、どのようにエンジンに格納されるかという疑問から、カートリッジのROMにどのように格納されるかという疑問までさかのぼりました(当時のROMは安くなくストレージを削減する必要があったため、この格納のプロセスはたいてい解凍と展開という段階を踏んでいました)。

繰り返しの作業は数ヵ月にわたりました。長く面倒なプロセスでしたが、最終的には散乱していた物事が収束しはじめ、以前よりもはるかに深くゲームのロジックを理解できるようになりました。データの意味をすべてのレベルで抽出できるようになったことで、私はついに秘密のドアの場所を突き止めたのです。コードを検証したことで、ゲームのアイテムがドロップする原理やアタックのロジックを理解することができました。ゲームの物理的特性を理解するために私が用いたテクニックの1つは、オリジナル版のゲームの実行中に、各種メモリの位置をキャプチャしてグラフ化することです。私はカスタムエミュレータを作成し、あらゆる種類のメモリ視覚化機能とフックを追加しました。

This graphing tool plots values in memory at runtime
実行時にメモリ内の値をプロットするグラフ化ツール

これまでの成果を踏まえたこのツールを使うことで、私たちはオリジナルのゲームの仕組みに関して高いレベルの理解を維持しつつ新たなゲームの開発に着手することができました。もちろん、オリジナル版からの変更もあります。オリジナル版は30FPSでの動作だったので、それよりもスムーズな物理特性にしたいと思っています。新バージョンではそれを2倍にし、4:3の画面比率をワイドスクリーン画面に変更する予定です。これまでに蓄えてきた知識があれば、オリジナルの詳細を見過ごすなんてことはありません。ゲームへの変更や追加項目は偶発的なものではなく、すべて意図的なものです。

Visualizing collision boxes for different characters
キャラクターに応じた衝突の境界ボックスの視覚化

Visualizing the position of game triggers/events
ゲームトリガ・イベント位置の視覚化

ここで紹介したことは新しいゲームを作る際の部分的な作業でしかありませんが、目的を達成するための最初のステップとして必要なものでした。こうした知識を土台に据えることで、偉大なオリジナル版の足取りに沿って新たなゲームを作ることができます。

そこからのみ、さらに優れたものが生まれ得るのです。

この短い販促を読んでいただきありがとうございます。Twitter(@lizardcube)やWeb(http://www.TheDragonsTrap.com)などで私たちをフォローしてみてください。インターネット回線を通じて、ゲームに関する重要な情報を提供しています。