SSブログ

孤独へ向って突っ走れ (50) [  PC-98x1(補完計画)]

「テニス・テニス2」をT98NEXTでプレイしている方へ

はじめに
私が実験に使ったT98NEXTは "V1.00 build May 25 2010(17:39:40)" というものです。Windows上で普通にPC-9801用ソフトを動かすT98NEXTのバージョンとしては、この記事を書いている時点では最新のはずです。でも将来的にバージョンアップの結果、この記事の内容が当てはまらなくなることはありえます。




前回の記事で私は、「ゲーム内で2けたの半角数字を表示すると10の位の値のかわりに1の位の値が表示されるという問題は、エミュレータを変えなければ解決せず、エミュレータを変えれば解決する」と書きました。それが通常の結論だと思います。今日は、通常でない、あまり良くない方法を見つけたのでそれを報告します。

以下に記す方法を使うと、T98NEXTで「テニス・テニス2」をプレイしても文字化けがありません。ただし、大きな問題があります。一度この方法で「テニス・テニス2」のゲームを書き換えてしまうと、他のエミュレータや実機でそのデータを使った時に文字が変になります。
(もともとゲームソフトのほうに問題がなく、T98NEXTのほうに小さな問題があるのを、ゲームソフトのほうを改変することで修正するので、そういう良くないことになるのです。)

その他にも、そもそも他人が作ったソフトを勝手に改変するというのは、たとえそのソフトがすでに売られていない昔の物でも本当は良くありません。

そのへんをよく考えて、自己責任でご判断ください。




では始めます。
次のものを用意します。

「テニス・テニス2」のディスクイメージ。T98NEXTを使っているのが大前提なので、当然ありますね。おそらくはnfd。

そのディスクイメージからファイルを取り出してWindows上のフォルダにコピーできるソフト(Windows上で動くもの)。フリーソフトで存在します。私はDiskExplorerを使っています。DiskExplorerで直接nfdファイルは読み込めませんが、これは問題ありません。私は次のようにしています。T98NEXTに起動可能なハードディスクイメージをセットし、それを起ち上げ、その後でゲームのディスクを入れて、そこから必要なファイルをハードディスクへコピーし、T98NEXTを終了し、DiskExplorerを起動してハードディスクイメージを読み込んでファイルをWindows上へコピーします。

バイナリエディタ(Windows上で動くもの)。フリーソフトで存在します。私はたまたまBZというソフトを見つけて愛用していますが、バイナリエディタはきっとたくさん存在すると思います。大事なのはビューアではなくエディタだということです。見るだけでなく書き込みが必要です。

当たり前すぎて書くのを忘れていましたが、T98NEXTの起動に使っているWindowsマシン。当たり前ですね。

用意するものは、以上です。用意したものを使いこなす知識は必要ですが、プログラミングやデータ解析の知識は必要ありません。

作業を開始します。

ゲームのディスクイメージからT.EXEをWindows上のフォルダ内にコピーします。

後で元に戻せるように、書き換えるファイルとは別にT.EXEのバックアップを作成しておきます。

バイナリエディタにT.EXEを読み込み、ファイル先頭からオフセット196D0Hの場所を表示します。
tt78.png

ここでデータを確認します。196D0Hの場所(上の画像では左端の赤アンダーライン)が"17"になっていますか?そして1バイト前の場所(上の画像では右端の赤アンダーライン)が"74"になっていますか?もしもそうでなければ、この先へは絶対に進んではいけません。

バイナリエディタでオフセット196D0Hの値(上の画像では左端の赤アンダーライン)を"6F"に変更します。ここは慎重に、絶対に間違えないように。

バイナリエディタでT.EXEを上書き保存します。

この、Windows上にある改変したT.EXEをディスクイメージ内のT.EXEに上書きします。方法はわかりますね。先ほどディスクイメージ内のT.EXEをWindows上にコピーしたのと逆の手順です。

そのディスクイメージをT98NEXTにセットし、ゲームを開始してみてください。今までT98NEXTで "00月00日" と表示されていた所が "10月10日" になっています。バンザーイ!
tt79.png

でもこのディスクイメージはデータが改変されたので、T98NEXT以外(他のエミュや実機)では使えません。




++++ ++++ ++++ ++++ ++++
以下は、上に書いた記事が出来るまでの解析の記録です。どうして「T98NEXTのほうに小さな問題がある」なんてことが書けるのか、証拠があるのか、という時にだけ必要なものです。「テニス・テニス2」のゲームプレーヤーの方はお読みにならなくて良いです。
++++ ++++ ++++ ++++ ++++





追っかけ8-2
どうしてT98NEXTではキャラクタジェネレータからユーザー定義文字のフォントを読み出す命令を実行すると文字化けするのか。どのような文字化けかを思い返すに、2桁の半角文字を表すフォントが、10の位も1の位の値になった。これは、フォントの左半分も右半分のデータになったということだ。それにつけて思い出すことがある。PC-9801のキャラクタジェネレータでは、CGウィンドウを使ってフォントを読み出す時、2バイト文字のうち第1バイトが76H以上の文字のフォントはCGウィンドウの奇数アドレスからしか読み出せない。つまり全角文字の右半分と左半分を別々に読み出さなければならない。そしてユーザー定義文字の文字コードは第1バイトが76H以上だ。だから、テニス・テニス2のプログラムでは文字の右半分と左半分を別々に指定し、どちらもCGウィンドウの奇数アドレスから読み出している。上記のことを踏まえて考えると、T98NEXTがフォントの左半分も右半分のデータにしてしまうような、もっともありがちなミスとは何だろう。それは、2バイト文字のうち第1バイトが76H以上の文字のフォントはCGウィンドウの奇数アドレスからしか読み出せないというキャラクタジェネレータ(CGウィンドウ)の制約を考慮せずに、フォントの左半分が指定されても右半分が指定されてもCGウィンドウの偶数および奇数アドレスにフォントの全体を反映させてしまった場合ではないだろうか。私はそういう仮説を立てた。

この仮説が正しいかどうかは実験の結果で確認する。では、どういう実験をしようか。

T98NEXTの中身はブラックボックスであり、いじれない。T98NEXT上で実行するほうのプログラムを変更して実験するしかない。テニス・テニス2のプログラムのCS:9B71以降に、CGウィンドウから文字フォントを読み出すルーチンがある。その中に、文字コードの第1バイトが76Hならばフォントを左右半分ずつ読み出すルーチンへと行く条件分岐がある:
2C70:9B8C 80FC76 CMP AH,76
2C70:9B8F 7417 JZ 9BA8
いっぽう、第1バイトが76Hを含む特定の値でないならば、フォントを一度に全部読み出すルーチンへ行く:
2C70:9BA5 EB59 JMP Short 9C00
そこで、上記のJZ 9BA8をJZ 9C00に変えれば、プログラムはユーザー定義文字のフォントをCGウィンドウから読み出そうとする時に左右とも奇数アドレスから読まずに偶数と奇数のアドレスから読む。もしもその結果ゲームの2桁の半角数字が正しく表示されれば、上述の私の仮説は正しいことになる。

ジャンプ命令はアドレスを絶対アドレスではなく相対アドレスで指定するので、注意しなければならない。次のように考えた:

(このブロックに書かれている数値はすべて16進数)
jz 9ba8をjz 9c00に変えたい
jzは飛び先を1バイトの相対アドレスで指定する(short jump)
命令jz 9ba8の次のアドレスはcs:9b91
9ba8-9b91=17
このやり方で合っているかどうか確かめる
jz 9ba8のコードは7417
この計算でok
このjzの飛び先を9c00に変える
9c00-9b91=6f
従って、jz 9ba8をjz 9c00に変えるには
cs:9b90の値を17から6fに変更する

ここまでわかれば、後はT.EXEをバイナリエディタに読み込み、ロードモジュール内のCS:9B90に相当する1バイトを書き換えるだけだ。ではその1バイトはT.EXE全体の中のどこか。EXEファイルの構造を調べ直した。

MS-DOS時代のEXEファイルは、ヘッダとそれに後続するロードモジュールから成る。ヘッダ内のオフセット08Hからの2バイトにヘッダのサイズが入っている。これは同時にヘッダの直後から始まるロードモジュールの開始点でもある。ただし単位はバイトではなく16バイトのパラグラフ単位で入っているので、バイトに直すために10H倍してから計算する。ヘッダ内のオフセット16Hからの2バイトに、コードセグメントにロードする情報の先頭位置が、ロードモジュール内のオフセットとして入っている。ただしこれも、16バイトのパラグラフ単位で入っている。

T.EXEの場合、ファイル先頭からのオフセット08Hから2バイトの値は00C0H。これを10H倍してC00H。ファイル先頭からのオフセット16Hから2バイトの値は0EF4H。これを10倍してEF40H。C00HにEF40Hを足してFB40H。書き換えるのはCS:9B90だから、さらに9B90Hを足して196D0H。

実験開始。ゲームのディスクイメージからT.EXEをWindows上のフォルダ内にコピーする。後で元に戻せるように、書き換えるファイルとは別にT.EXEのバックアップを作成。バイナリエディタにT.EXEを読み込み、ファイル先頭からオフセット196D0Hの場所を表示する。その1バイト前からの値は74H,17H。上記JZ 9BA8のコードと一致する。間違いなし。
tt78.png
バイナリエディタでオフセット196D0Hの値を6FHに変更。上書き保存。このT.EXEをディスクイメージ内のT.EXEに上書きする。そのディスクイメージをT98NEXTにセットし、ゲームを開始する。2桁の半角数字は、T98NEXTでも正しく表示された(下図)。私の仮説は正しかった。

ただし、本当はこれは行うべきデータ改変ではない。なぜならゲームのプログラムは間違っていないからだ。それを改変する(あえて間違ったコードにする)のはプログラムの作者に失礼だし、ゲームがT98NEXT専用になってしまう。他のエミュレータや実機では表示が変になるはずだ。

とはいえ、ここまで出来れば私の大昔の劣等感は払拭された。若いころの私にはゲームのプロテクト外しもパラメータ変更もできなかった。でも今は、時間と努力を費やせばできる。私には認識力も知識も不足しているが、時間をかけて自分の間違いを見つけ出し、何度でも技術情報を調べれば、PC-98関係は何だってできる。もうPC-9801用ゲームを実際に解析することはないだろう。でもやろうと思えばできるという自信がついた。それで十分だ。

tt79.png
tt80.png
コメント(0) 

コメント 0

コメントの受付は締め切りました