スカイデストロイヤーで学ぶ「奇跡を強制召還する手法」

 さて、2022年5月28日に公開された4STさんの新作「発売から37年目の真実…闇夜に現れるという不気味な幽霊船は実在するのか|スカイデストロイヤー」を見て、幽霊船ゾンビの出現&破壊に挑んだ強者もいるかと思います。

 ウチもこんな感じで動画の翌日には幽霊船ゾンビを出現させて倒すツイートをしていたわけですが、実はコレ、莫大な時間と3D酔いと戦いの果てに勝利を掴み取ったシイナさんと違って、私のヤツはプログラムハックで強制召還したインチキ画像です。

・ ※動画の超ネタバレが含まれるので先に前述の4ST動画を見てね!


<前準備>

 ゲームソフト:ファミコン版スカイデストロイヤー
 ROMダンパー:https://www.amazon.co.jp/dp/B087GGBVMV/
 エミュレータFCE-UX:https://fceux.com/web/home.html
 emuhaste:https://i486.mods.jp/ichild/download/emulator-cheet-program-emuhaste
 ※ゲームソフト以外は好みでいいです。

<幽霊船ゾンビの出現条件をおさらい>

1.夜になってから、母艦ノースザネリ(以下、母艦)出現の瞬間に倒す。
 =出現前から魚雷を発射しなければ間に合わない。

2.母艦は8つのグラフィックで構成されている。
 内部的に状態変化カウンタが存在しているのは確実。

<母艦の各フレーム値を特定>

1.FCE-UXでゲームを進行する。

2.母艦が出現する直前あたりでステートセーブ。

3.現れた直前にポーズしてemuhasteでサーチ開始。

4.母艦が形態変化する都度にポーズして「変動」などで絞り込み。
=これでアドレス$006Bの値が母艦の形状と連動していることが確定。

 動作を調べたところ「母艦が出現した瞬間に$006Bに08がセットされ、時間経過ごとに07,06,05..とカウントダウンとともに表示座標が左にずれてゆく。値が08のタイミングで母艦を倒せば、幽霊船ゾンビが出現する」というプロセスでした。

 当然、アドレス$006Bに08を常時セットし続けることで、どのタイミングで倒しても確実に幽霊船ゾンビが出現することになります。

 ちなみに幽霊船ゾンビのX座標は$00ACに格納されており、母艦を08のタイミングで倒した瞬間に$00AC=FFがセットされて画面に出現。これが1フレームごとに-1ずつ減算され、00になると同時に画面から消滅します。
 なので、アドレス$00ACに00以外の値を書き込み続けることで常に幽霊船ゾンビを画面に固定することもできます……が、それはあまり面白くないですよねぇ。

<母艦のカウントダウン処理をハックする>

 母艦($006B)が08からカウントダウンする…ということは、そのルーチンがプログラムに存在するはず。
 そんなわけで、当該処理をFCE-UXのデバッガで実際に見てみましょう。

1.母艦が出現した瞬間にポーズ。

2.FCE-UXでDebug→Debuggerを起動し、Breakpointの[Add]でAddress 006B-006BをWriteにセット。

3.ポーズを解除して少し待つと、下記の箇所で自動停止する。
>00:ED88:C6 6B DEC $006B = #$06

4.デバッガの[Run]をクリックするとゲームが再開&再び自動停止し、デバッガの表示が下記のように変化する。
>00:ED88:C6 6B DEC $006B = #$05

 DECはデクリメント(1減らす命令)で、母艦が形態変化するタイミングで毎回$006Bが1ずつカウントダウン書き込みが行われ、デバッガのブレークポイント機能が「$006BへのWriteを検出し、プログラムを停止」させています。
 なので、アドレス$ED88にある2バイトコード”C6 6B”が「母艦を形態変化させるルーチン」というコトですね。

<ROMを書き換えてみる>

 ファミコン版スカイデストロイヤーが発売したのは1985年でROM容量もたったの24キロバイトしかないので、バイナリエディタで C6 6B とサーチするだけであっさり見つかります。
 ファミコンのCPU(6502)では「何もしない命令nop = EA」なので C6 6B を EA EA と書き換えることで母艦が「出現しても08のまま動かない固定建造物」になります。

<さらに幽霊船ゾンビを追跡!!>

 前述のとおり幽霊船ゾンビのX座標はアドレス$00ACに格納されているのですから、固定化された母艦を倒したタイミングで幽霊船ゾンビを出現させ、ブレークポイント00AC-00ACにWriteで仕掛けると――

>00:FA00:C6 AC DEC $00AC = #$4B

 まあ当然出てくるわけです。
 これを EA EAに書き換えると幽霊船ゾンビも固定建造物と化します。

 ちなみにDEC $00AC はもう一つ存在しており、こちらは「母艦を倒す前に00AC-00ACにWriteブレークポイントを仕掛ける」ことでヒットします。

>00:D6EE:C6 AC DEC $00AC = #$00

 実はプログラム的には面白い仕組みになっていて、コードが実行された瞬間、符号無し整数00をマイナス1し、00→FF(幽霊船ゾンビの初期カウンタ)がセットされます。

 当然、ここを EA EAに書き換えてしまうと幽霊船ゾンビに内部カウンタFFがセットされることは一生なくなるので「幽霊船ゾンビが絶対に出現しない改造バージョン」という悲しいシロモノになってしまいます。

 さらに、このヒット位置から少し上に遡ると以下のコードが見つかります。

00:D6E6:A5 30 LDA $0030 = #$02
00:D6E8:29 03 AND #$03
00:D6EA:C9 02 CMP #$02
00:D6EC:D0 0C BNE $D6FA
00:D6EE:C6 AC DEC $00AC

 これを人に分かる言語に解釈すると次の通り。

00:D6E6:A5 30  アドレス$0030をレジスタAにロード
00:D6E8:29 03 レジスタAと2進数11との論理積を取る。
00:D6EA:C9 02 その値が02
00:D6EC:D0 0C でなければ下の処理を飛び越えて次へ。
00:D6EE:C6 AC 幽霊船ゾンビ出現!

 このうち、$0030に格納されているパラメータ=時間帯であり、02=夜です。
 ここまで言えば勘の良い人なら気づきそうですが、最後にこんな画像で本記事を締めるとしましょう。

// 夜かどうかを判定するルーチンをnopで破壊
C9 02 D0 0C → EA EA EA EA (夜判定無効化)

\明るい幽霊船ゾンビ!/