FFI・II ADVANCEの解析手順です。が、後からまとめているので、多少内容が前後していたりします。 ~FF1 //モンスター図鑑コンプリート まず下準備として、一旦ゲームをスタートしてからセーブを行い、セーブRAMの内容をバックアップします。 その後適当なモンスターを何体か倒し先ほどのデータに上書きして、バックアップしたファイルと比較します。 何故こんなややこしいことをするのかというと、まず余計なデータがサーチで引っかかるのを防ぐためと、 このようなリスト型やフラグ型のデータの場合、見えている数値が信用できないことが往々にしてあるためです。 そして比較の結果、倒した数(0x0000~0x03E7)OR既読フラグ(0x8000)という形で格納されていることが分かったので、 ゲーム中で数値サーチを行うと、0x02002A6C-0x02002BF0と判明。 しかしこのコード、そのまま使用するには問題があります。ゲームが変わると、全く別の数値が格納されてしまいます。 これを回避するために、特定のシーンでのみ有効にさせるための条件判定アドレスをサーチする事にします。 もっとも負担が少ないと思われるのがメニュー画面なので、そこを基準にnot equalサーチを繰り返して、 0x03003008が0xFFF1という条件を見つけました。 これをX-TA用シリアルコードに直すと、 モンスター図鑑完成 73003008FFF1 42002A6C83E7 000000C30002 となります。 //エンカウント制御 まず最初の手がかりは全くの偶然に発見しました。 キー入力情報のアドレスである0x02001D88(これはL押しながら0x0200、R押しながら0x0100の数値サーチですぐ見つかる) の近傍をメモリエディタで眺めていると、0x020019B8からの4バイトが勢いよく回っていたため、 おそらく乱数ではないかと判断し、試しに0x00000000で固定してみるとランダムエンカウントが発生しなくなりました。 ※このアドレス自体は、その場で動かずに連続でnot equalを32bitでサーチすれば2、3回で見つかります。 が、乱数の固まりだけに、そのままではNPCの移動方向や敵の攻撃パターンまでも固定されてしまうため、 ここからエンカウント判定を行っているプログラムを追跡するためVBA-SDLでブレイクポイントをセットして調査します。 困ったことに、VBA-SDLではon writeかon executeでしかブレイクポイントを仕掛けられないのですが、 今回のような「見える場所で回っている乱数」の場合はon writeでも問題ないことが多いです。 というのも、通常こういったカウンタ型の疑似乱数の場合、なにがしかの判定を行うごとにカウンタを進めるのが普通で、 それもプログラムの都合上、カウンタを進めた後で判定を行うことが多いため、その例に沿っていれば、 エンカウント判定は乱数カウンタの書き込みを行うサブルーチンからの復帰直後にある可能性が高いのです。 というわけで、VBA-SDLを起動し余計な判定が割り込まないようにフィールド上でF11を押してデバッガ起動、 bpw 20019b8 4 と入力してブレイクポイントをセットし、ゲームに復帰する、と間髪入れずにブレイク。 08068ab8 4770 bx lr と表示されます。いわゆるフレーム乱数処理に引っかかってしまいました。 しかし、"bx lr"とは主にサブルーチンからの戻りに使用される命令なので、 つまりここが乱数カウンタ書き込みサブルーチンの終了だと推測できます。 そして戻りアドレスであるlrはR14レジスタなので、そこを見てみると、 R14=08057dcb となっているので、フレーム乱数処理を呼び出しているの0x08057DC6番地のbl命令だと分かります。 このままではサーチすらままならないので、 eh 8057dc6 0 eh 8057dc8 0 と入力して、bl命令を潰します。 それからゲームに復帰すると今度はちゃんと動けるので、一歩移動します。 すると見事に上と同じアドレスでブレイク。 R14=08065c3d となっていますが、どのみち逆アセンブルしなければならないので、 n d の順にコマンドを入力して、サブルーチンから復帰後からの逆アセンブルリストを表示させます。すると 08065c48 4288 cmp r0, r1 08065c4a d305 bcc $08065c58 という箇所を発見。bccはキャリーフラグが0ならば(この場合r0がr1より小さいならば)分岐成立となるので、試しに 08065c4a e005 b $08065c58 としてみると一歩歩くごとにエンカウント。逆に 08065c4a e7ff b $08065c4c とするとエンカウントが無くなったので、エンカウント判定はここで確定のようです。 とりあえずPAR用ならこのままコード化出来るので、適切に機能させるための条件コードを考えます。 まずエンカウントのon/off切り替えですが、常識的に考えてキー入力で切り替えるのが普通です。 通常のワークコードであれば○+×でon、○+△でoffといった切り替えも可能なのですが、 プログラムパッチの場合は、常にどちらかのコードが有効になっていないと元に戻ってしまうため、別の方法を使います。 キーコードの中で、単体で押した際にもっとも数値が大きくなるのは、Lボタンの0x0200です。 ということは、Lボタンが押されていれば必ずキーコードの値は0x0200以上の値をとり、 逆にL以外の全てのキーが入力されたとしても0x01FF以下の数値になります。 このことをふまえれば、キーコードの値が0x0200より大きい値であることを条件にすれば、 Lボタンを押しながら移動したときにコードを切り替えることが出来るようになります。 そして、念のため移動中のみコードを有効にするための条件判定をつけるために、 ※実はこの判定を探したのはもっと後だったのですが、サーチの流れ上ここに書きます。 移動中、戦闘中などで比較サーチをしてみると、 0x020036E8番地が 0000 = 停止中 0001 = 移動中 0002 = 会話中 0003 = 戦闘中&メニュー画面 と変化したので、これをE条件判定コードとして使用することにします。 後は、先ほど見つけたプログラムアドレスを2で割って6ヘッダをつけて、各条件判定を組み合わせると、 E0030001:020036E8 64032E25:0000E7FF D2001D88:00300200 64032E25:0000E005 となり、暗号化すると、 PAR用エンカウント制御(通常エンカウント無し、L押しながら移動でエンカウント) 941D92B6 4724FF6A 64CDD9DF 099AE9D8 AE61F70F 7328F163 F1133C1A 85C786FC となります。 問題はX-Tです。 08065c48 4288 cmp r0, r1 という命令から、R1にロードされているのが敵の出現率だと予想されます(R0は乱数値のため) そこでその直前のプログラムを詳しく見てみます。 08065c3c 0d80 lsr r0, r0, #0x16 <乱数値を10ビット(0x000~0x3FF)に丸める 08065c3e 7821 ldrb r1, [r4, #0x0]