マップデータを解析する(4):境界データと面進行データ
前回までの調査で判った「差分データ」「境界パターンデータ」は、どんな順序で、いつ展開されるのか?
今回のレポートではその部分を調査してみます。


ZANACを本当に(つまりソースから)解析する
マップ生成の調査方法として、これまでは『ゲーム画面からデータ格納の仕組みを推測する』という手法を採っていましたが、 このへんで少し、アセンブリソースの解析についても触れたいと思います。

以前のレポートでも述べましたが、ZANACのパターン番号体系はASCIIコードに準拠している為、"ROUND"や"GAME OVER"などのゲーム中のメッセージが 判りやすい形で格納されています(mapview.exe)。

  (1)ソース中、文字列データの位置を特定する。
  (2)その文字列データを画面表示しているルーチンを調査する。
  (3)そのルーチンを呼び出している処理を探し、今度はそれらを調査することで、スコアや自機を格納しているRAMアドレスが判明する

という流れで調査を進めるのが、最も効率が良いのではないでしょうか。

さて、ソースの解析が順調に進み、画面右の「現在のROUND数」の表示処理から、ROUND数が格納されているRAMのアドレスが 判明したとします。
そのアドレスについて処理を行っているルーチンで、


という2つのルーチンが見つかりました。
このことから、

  ・アドレス945Cからのテーブルは、0面から8面までのマップデータの開始アドレス(2バイト長)を示す
  ・ある変数Aは、現在のマップデータ位置を示すポインタである

ということが判ります。
以下、アドレス945Cからのテーブルを「マップデータテーブル」、ある変数Aを「マップデータポインタ」と呼びます。
また、マップデータポインタで参照されるデータは、「マップデータ」として、ここからはマップデータの構成について調査してみます。


境界データ
マップデータテーブルの、1面のデータ開始位置を示す値(8番目、つまり+14,+15バイトの2バイト)を元に、 ソースの1面の面データと思われる部分を調べてみます。

例によって実際の内容は表記できないのですが、そのアドレスから+20バイトの辺りの2バイトは、どこかのアドレスを示しているような・・・
そうです、ここには差分データの回で調べた、「緑背景のイコン」の差分データの開始アドレスが格納されています。
しかも、2バイトほど隣にも、同じアドレスが見つかります。
これは、1面のマップ冒頭の、イコンが画面左右に1個ずつ、計2個並んでいるデータではないでしょうか?

マップデータを少し読み進めると、「茶色い小島」「茶色背景のイコン」「武器庫」「武器庫」の差分データ開始アドレスも見つかると思います。
とうやら、このデータは1面の差分アドレスの出現順序のデータと見て間違いないようです。

さて、境界パターンデータ(川)についてはどうでしょうか?
データの格納順序としては、この近辺にあるはずなのですが・・・

実は、このデータの中には、境界パターンデータを示すアドレスは含まれていません。
今発見した緑背景イコン×2と、茶色い小島のデータの間が不自然に開いているようですので、その中のアドレスっぽい値を探してみます。

9Exx(xx 9E)というアドレスが2つ見つかるので、さらにそのアドレスが指し示しているデータ近辺を調べてみます。 数バイト先に、まさに前回調べた、境界パターンデータの開始アドレスが含まれていました。
この、境界パターンデータの開始アドレスを含むデータを、「境界データ」と呼ぶことにします。

ZANACのマップにおいて、「緑の地表/水面」など、異なる地表の境界線は、この「境界データ」と、「境界パターンデータ」が組みになって表現されています。
また、前回調査した川のような地形は、これら「境界データ」「境界パターンデータ」の左岸&右岸のペアによって表現されているようです。

以上、マップデータとは少し離れてしまったようなので、ここからはさらにマップデータの調査を進めてみます。


マップデータ形式を調査
これまでの調査で、マップデータには「差分データのアドレス」「境界データのアドレス」が含まれていることがわかりました。 また、これらのデータが現れる順序も、ほぼゲーム中の画面に従っているようです。
もう少しマップデータの調査を進めてみます。

ROUND数の処理の所で出てきた「マップデータポインタ」に着目してみます。
マップデータポインタを操作しているルーチンを、ソースの中から探し出します。それほど多くはありません。
そのうちの一つのルーチンは、「マップデータポインタでマップデータを参照し、解釈する」ルーチンのはずです。
見当をつけてソースを読んでみますが、これがなかなか難しいです・・・

このレポートの中でもたびたび書いていますが、アセンブリソースの解析はどこが難しいのでしょうか。

まず第一に、『そのルーチンが呼び出される直前のレジスタ内容、メモリ内容を判断するのが難しいこと』。しかし、これはC言語など一般のプログラミング言語で言うところの、引数の内容ががよく判らない、というのと同じことでしょう。

第二に、こちらが重要なのですが、『変数名がわからない』こと。メモリ内容は名前ではなく、アドレスで管理されます。

他人の書いたソースファイルを読むとき、変数名から内容のあたりをつけてゆくことができない為、解析する場合、RAMアドレス-自分でつけた変数名の表を作成しながらでないと難しいでしょう (というか、少なくとも私はそうしているのですが、ひょっとしたら一般的な方法ではないのでしょうか?)。

アセンブリ言語に比べ、VisualBasic、C言語などが「高級言語」と呼ばれる理由が身をもってわかります。しかし、これもアセンブリソースを解析すればこそ体験できる不便さで、まさに解析の醍醐味と言えるのではないでしょうか?

さて、面倒くさいソース解析は私が代わりにやらせていただきました。
あるルーチンの中で、「マップデータポインタから1バイト読み出し、その値の末尾4ビット(0〜0Fh)によって、0〜0Chの12通りに分岐する」という処理がありました。
0〜0Fhだと、本当は15通りなのですが、プログラムには12通りの処理しかなく、残り3通りは存在しません。データが間違いなく12通りしかない!ということで、プログラムの小型化を図っているのでしょう。

この分岐先のルーチンをさらに調べることで、マップデータの構造が明確になってゆきます。
例えば、「差分データ」については、初めの1バイトの末尾4ビットが"5"で始まるデータ列、 「境界データ」については、初めの1バイトの末尾4ビットが"2"で始まるデータ列で参照しているようです。
以下、差分データと境界データが、マップデータ内でどのような形で参照されているのかのフォーマットを示します。


<差分データ参照のデータ列>
  0x85 nn             <-----"0x85"の末尾は5、nnは差分データ個数を示す
  n1 xx LL HH       <-----(※n1&0x08=0のとき)
  n1 xx yy LL HH    <-----(※n1&0x08!=0のとき)

   ただし、不明な数値n1、画面左からの表示位置xx、現在y位置からのyの差yy、差分データ格納アドレスHHLL 


<境界データ参照のデータ列>
  0x82 nn             <-----"0x82"の末尾は2、nnは差分データ個数を示す
  n1 xx bt LL HH    <-----(※n1&0x08!=0のとき)

   ただし、不明な数値n1、画面左からの表示位置xx、境界タイプ?bt、境界データ格納アドレスHHLL 


実際のソースを見ると判りますが、マップ中の「川」は、2つの境界データ参照が組になって表現されています。
2つの境界データ参照の表示位置xxの差は川幅となります。
ここまできてやっと、ZANACのマップの川の表現方法が判明しました。


面進行データ
なお、マップデータを調べてゆくと、上記のようなデータ列(初めの1バイトの末尾4ビットが0〜0Ch)の合間合間に、2バイトのデータが含まれていることがわかりました。
初めは意味の無いデータなのか?とも思いましたが、トレースデータと読みあわせを行ううち、

  ・合間合間の2バイトデータは、「初めの1バイトの末尾4ビットが0〜0Chで始まるデータ列」1つにつき、1つ存在
  ・この合間合間データが同じ「データ列」は、続けて処理されている

ということがわかりました。もしや、と思い、

  • マップデータ中、1面の初めのイコンを現すデータ列の前の「合間合間データ」

  •  と、
  • 実際のゲーム中にイコンが表示されるのはマップの下端(ゲーム開始直後、スクロールする前の画面下端)からy方向にどれだけ離れているか?(イコンの全マップ中のy座標)


  • とを比較してみると、見事に一致しました。ちなみに、イコンのy座標は十進数で50(=032h)となります。

    このことから、この合間合間データは、いわばデータ列に振られたインデックスで、ZANACマップの描画中、カウンタ(多分、マップのy座標のどこを描画中か?を示す)がインデックスと等しくなったとき、 そのデータ列がマップデータ描画に使用されるのではないか?と推測できます。

    ここで、差分データ参照、境界データ参照以外のデータ列にも注目してみましょう。
    あるデータ列は面の途中に表示されるボスを、あるデータ列は面データの終了を意味し、次面のデータ開始アドレスを示すようです。
    また、これは後付けで判明したのですが、各面の特殊兵器コンテナの内容を出現順に示すデータ列へのポインタ等も存在します。

    このことから、これらのデータ列の集合は、単純にマップ描画のみを担っているのではなく、ゲーム全体の進行に用いられているようです。
    よって、このデータ列の集合を「面進行データ」と呼ぶことにしました。

    以上、大変長くなりましたが、最後にプログラムの紹介です。

      seqview.c(seqview.lzh : ファイルサイズ 7,114バイト)

    (LZH形式で圧縮された、C言語ソースファイル、実行用バッチファイル、Cygwin上でコンパイルしたexeファイルです。
    展開後、生成されたファイル全てをzanac.romと同一のフォルダに移動し、seqview.batを実行してください。
    なお、展開後に生成されたseqview.exeは、Cygwinが無い環境では動かないかもしれません。
    その場合は、seqview.cをコンパイル後、seqview.batの内容を参考に実行してください。


    プログラムを実行すると、round0.txt〜round8.txtまでの9つのテキストファイルが生成されます。
    これらのファイルには、ROMファイルから読み出した、各面の面進行データの内容が記されています。

    面進行データの中には、これまで説明していなかった"Set Default Map Pattern"や、"borderline data change"などの文字列があります。
    これらのデータ列の意味はどうやって調べたのでしょうか?いえ、真面目に解析したわけではありません。
    次回のレポートで説明し、それをもって第一次中間報告のまとめとします。
    (今回は期待を持たせたカッコ良い終わり方にしました)



    文字ばっかりで長い!疲れつつZANAC解析のトップへ戻る

    トップへ戻る