敵キャラクタについて(1):敵キャラクタワークエリアを見る
前回までは、ZANACのマップデータについて解析を進めてきましたが、今回からは敵キャラクタについて解析してゆきます。

ZANACには、多くの個性豊かな敵キャラクタが登場しますね。
倒すとパワーアップアイテムを落とすもの、自機を目指して突っ込んでくるもの、弾をばらまくもの・・・
当然ながら、これらの敵キャラクタの挙動も、全てROM内に収められたプログラムによって実現されています。

マップデータの展開においてさえ、「画面の無駄な部分も描画する」等、様々な技巧が凝らされているZANACです。これらの敵キャラクタのプログラムにおいても、 きっと素晴らしいテクニックが駆使されているのではないでしょうか。


敵キャラクタ用のワークエリア
まずは、ゲーム中に敵キャラクタがどのように扱われているか?について調査してみたいと思います。

プログラムを解析してみると、04496Hからのルーチンにおいて、

「0E3A0Hから0E640Hまで32バイトごとに調べ、全てがノンゼロだったらCyフラグを1にして呼び出し元に戻る」

という処理が行われていました。

まるで、このルーチンの呼び出し元は「敵キャラクタを新たに発生させるルーチン」で、このルーチンが敵キャラクタを発生させる前に、ワークエリアの空きを探しているように見えないでしょうか?

そこで、
『ZANACでは敵キャラクタ用のワークエリアとして、0E3A0Hから0E65FHまでを32バイトごとに区切って使用している。1キャラクタあたり32バイトとすると、22種の敵キャラクタを同時に処理できる。』
と仮定することとします。

なんだか、22種類というのがずいぶん半端な数で少々不安ですが・・・。
この仮定の元、今度はプログラム中で04496Hの呼び出し元を探し、次々と解析してゆけばいいのですが・・・解析する根気がありませんでした。
例によって、より楽な方法でこれを検証してみようと思います。


敵キャラクタ用ワークエリアを覗く(1) MSXエミュレータによる方法
ワークエリアの特定ぐらいであれば、まじめにプログラムを解析しなくても、エミュレータでゲームを遊びながらメモリビューワー等でこれらのメモリの状況を見れば良いわけです。
「星をみるひと」「パワーブレイザー」の改造でも、同じ手法でメモリを特定したものです。

というわけで、MSXエミュレータで調査を行おうとしたのですが、リアルタイムなメモリビュワー機能がついているエミュレータがなかなか見つかりません。 「no$MSX」等は、いったんゲームを止めて、その瞬間のメモリを見ることはできるのですが、 「m88」や「NNesterJ」「G-NES」のように、リアルタイムでメモリ使用状況を表示させるMSXエミュレータは存在しないようです。

残念ながら、別の手段を考えなければなりません。


敵キャラクタ用ワークエリアを覗く(2) ZANACを改造する
リアルタイムに敵ワークエリア(らしきもの)の利用状況を覗くため、ZANAC自体を改造し、ゲーム中にメモリを表示する機能を付加することにしました。

しかし、メモリ内容を覗くルーチンを仕込む場所はどこに確保すれば良いのでしょうか?
もっとも簡単なのは、ROMファイル内で使用されていない領域を見つけ、そこに追加ルーチンを書き込んでしまう方法なのですが、 ZANACにはそんな空きは無いようです。

ちなみに、ZANACのROMファイルのうち、使用されていない容量は5バイト程度ではないかと推測しています。
ROMファイルを逆アセンブルすると、ファイル最後尾に、0FFHが5バイト書き込まれています。 この5バイトは、プログラムとは無関係と思われます (その直前の部分は、ゲーム中にALCの値を画面表示するルーチンのようです)。

まだ全体を完全に解析したわけではないのですが、未使用領域が5バイトとは、まるでパズルのようですね。 1Kバイトも空き容量があるゲームもあるのに・・・まあ、大容量のROMソフトの場合、バンク切り替え等の関係で いくらか無駄な空き容量が出てしまうのはしょうがないのかもしれません。


タイトル画面用パターンデータを潰す
ZANACのROMファイル中に空き容量を確保するのは難しいため、既に使われている領域のうち、削ってもゲーム本編に支障の出ない部分を探します。

真っ先に思いついたのが、「タイトル画面用のキャラクタパターンデータ」です。
パターンジェネレータの回でも少し触れましたが、 MSXのパターンジェネレータはZANACの実行中、「標準」「タイトル」「最終面」の各状態で変化します。 状態変化の都度、ROM内の圧縮された差分パターンデータを元に更新されます。

ZANACでは、タイトル画面に移ると、一時的にタイトルロゴ用のパターンデータが展開されて使用されますが、 ゲーム本編がスタートすると、タイトルロゴ用のパターンデータは使用されなくなります。 これらの領域を潰し、追加ルーチンの書き込み用に利用させてもらいましょう。

ただし、この部分に直接コードを書いてしまうと、パターン展開用ルーチンの誤動作により、ゲームがタイトル画面から進まなくなってしまう可能性があります(というか、進まなくなりました)。 そのため、パターン展開用ルーチンをうまく騙してやる必要があります。

バイナリエディタをお持ちの方は、以下をお試しください。

(1)ZANACのROMファイルをバイナリエディタで開く。
(2)先頭から+01D2CH近辺を表示させる。この部分はMSXからは04D2CHに見える。
(3)+01D2CHから"FF FF 01"となっているデータのうち、+01D2EHの"01"を"00"に変更する。

これでゲームを開始すると、"ZANAC"のロゴが乱れて表示されたでしょうか?
これは、パターン展開ルーチンが、タイトルロゴ用のパターンデータの展開時に、 先ほど書き換えたデータ"00"が、差分パターンデータの終了であると認識してしまったためです。

これにより、ROMファイルの+01D2FH〜+01EEFH(MSXから見ると05D2FH〜05EEFH)の449バイトが利用可能になりました。


敵キャラクタ用ワークエリア(らしきもの)表示パッチと、ワークエリアの利用状況

  zanac-dispenmwork.exe (zanac-dispenmwork.lzh : ファイルサイズ 11,034バイト)

LZH形式で圧縮された、Windowsの実行ファイルです。プログラムはWdiffで作成しました。
展開後、生成されたzanac-dispenmwork.exeをzanac.romと同一のフォルダに移動し、実行してください。

また、.exeファイルを実行したくない方向けに、テキスト形式のリストも用意しました。
このリストを元にバイナリエディタで修正しても良いでしょう。
一部、改造内容のコメントもつけてあります。

※ただし、ROMイメージの形式、ROM出荷時期等により、うまくパッチ適用を行えない場合もあります。ご了承ください。


パッチ適用後、エミュレータで実行すると、画面右に22行の"00000000"が表示されると思います。
"00"が1バイトを表現しているので一行あたり4バイト、つまり画面右には88バイトの情報が常に表示されています。
これらのデータは、22の敵キャラクタ用ワークエリアのうち、各々の初めの4バイトの内容を表示しています。

そのままゲーム本編をスタートさせてみてください。敵キャラクタが登場するたび、"00000000"の新たな行が目まぐるしく変わってゆくはずです。敵キャラクタが破壊、もしくは画面の外に出ると、元の"00000000"に戻ると思います。

それ以外にも気づいた点を列挙すると・・・

  1. 初めの1バイトは、敵キャラクタ種別を表している。0BDH=サート(撃つとランダーになる敵)、0ACH=緑色の空中敵、0C6H=イコン(地上敵)など。

  2. 空中敵はワークエリア先頭から、地上敵はワークエリア末尾から使用される。

  3. 空中敵で横幅が16ドットあるものは、必ず"27"で始まる行と一組になって登録されている。
    (地上敵や、横幅が8ドットの敵弾やミサイルは、1行のみで表現される)

  4. ボス戦の一つ目コアのワーク1バイト目について・・・画面上から出現時、1バイト目は"4B"だが、スクロールが止まってボス戦が始まると、"CB"に変化する。
まずi.については、各ワークエリアの先頭1バイトが敵キャラクタの種別を表していると見て間違いないようです。

次にii.については、これは空中敵と地上敵の出現時、ワークの取り合いを防ぐ為でしょうか?
このパッチを当ててゲームを進めると分かるとおり、空中敵の出現〜破壊もしくは消失の間、ワークエリア先頭付近は目まぐるしく変化しています。
空中敵用ワークの開放と再割り当てが激しく行われるためです(1面ではなく、攻撃の激化する後半面に行くとより実感できます)。
しかし、地上敵については、空中敵の攻撃の激しさとは無関係に、あらかじめマップに配置された順番どおりに出現してきます。
そのため地上敵の出現時は、ワーク空きの可能性が高い末尾から空きを検索しているのではないでしょうか。

iii.については、おそらくキャラクタ種別"27"は、「自分が登録されたときに一緒に登録されたワークの隣にスプライトを表示、キャラクタの移動やアルゴリズムは 相棒のワークと同様に実行する」という働きをしているのではないでしょうか。
一見、キャラクタ27をわざわざワークとして登録するのはムダな気もするのですが・・・いえ、ZANACのことです、きっとこれにも意味があるのに違いありません!

最後にiv.についてですが、ボス戦でスクロールが止まる、すなわちコアの当たり判定が発生すると同時に、キャラクタ種別が変わっています。
04BHから0CBHへの変化については、ちょうど「最上位ビットが0から1になった」とも言えます。
敵キャラクタ種別を表すワークの1バイト目の最上位ビットは、当たり判定の有無を表現しているのではないでしょうか?


敵キャラクタワークを表示させることができたことで、これを今後のZANACの敵キャラクタ解析の足がかりとすることができます。

例えば、ワーク1バイト目の値によって分岐しているところがあれば、その飛び先は各々の敵キャラクタのアルゴリズムを示しているでしょうし、 また、ワークの2バイト目、3バイト目は各キャラクタのx座標、y座標を示しているようなので、ここから当たり判定等の処理も辿っていけるのではないでしょうか?

まあ、プログラム解析はめんどくさいので、とりあえず敵キャラクタの絵と1バイト目の対応を記録して「敵キャラクタ図鑑」でも作ってみることにします。
(2005/08/06)


久々にZANAC解析のトップへ戻る

トップへ戻る