前後に特別な記載が無い限り、解説の内容はDX版と通常版で共通。 スクリーンショットは調査の都合で混在(ただし、片方のみに触れるのが適切な場合はそちらを使う)。
ムービーファイル: LA_JP_ACE_TAS_4775f.bk2
今回のTASにおいての大まかなルートは以下の通り。
このゲームはRAMアドレス#FFE7hに汎用のタイミングカウンタを持っている。 これはスプライトなどで使われる各種カウンタ処理のタイミングを制御するための大本に当たる物で、 メインループ中で必ず1回インクリメントが行われる。なお、オーバーフローする状態でもそのままインクリメントは行われ続ける(FFh→00h→01h...)。
スプライトなどの各種カウンタ処理はこの汎用カウンタをAND命令などで手元の値と比較し、 「nフレームに一度なにかを実行する」という処理などを行っている。 なお、これはあくまでメインループ中で行われる処理なので、 全体の処理が1フレーム内に収まらなかった場合(ラグが起きている場合)はそれに準じて遅れる。 つまり、表示フレームとイコールではない。; 汎用カウンターのインクリメント処理 0216:21 E7 FF LD HL,#FFE7h SP:dfff A:e7 B:00 C:ff D:68 E:67 F:00 H:c1 L:bf Cy:176975040 0219:34 INC (HL) SP:dfff A:e7 B:00 C:ff D:68 E:67 F:00 H:ff L:e7 Cy:176975052
スプライトのイベント用カウンタ(#C49*h)の内容は 基本的に(全ての調査はしていないが、恐らく殆どの物が?) 設定された値から4フレームに一度デクリメントされる。 これらのタイミングは前述の汎用カウンタを元にして行われている。
汎用カウンタは他の状態に関わらずメインループ中でインクリメントされ続けるので、 スプライトのイベントカウンタが待ち時間として使われる場合は処理が始まるタイミング次第で最大3フレーム差が出る事になる。 今回のTASにおいては剣の取得時、待ち時間用のイベントカウンタがセットされた直後のフレームでデクリメントが発生するよう剣を取るタイミングを僅かにずらして最適化している。
以下は#03hとANDして結果がゼロの時だけ(=4フレーム間に一度だけ)実行する結果サンプル(JS使用)。
汎用カウンタ | 00 | 00000000 |
---|---|---|
比較値 | 03 | 00000011 |
結果 | RUN(0) |
; 剣を取った直後の該当処理より一部抜粋 ; 汎用カウンタ値(今回#F8h)をAレジスタにロードする 77E3:F0 E7 LDH A,(#FFE7h) SP:dff7 A:00 B:00 C:02 D:1c E:0e F:a0 H:c4 L:82 Cy:177065120 ; 汎用カウンタ内容#F8h(11111000)と #03h(00000011) で AND。 ; 今回は結果ゼロ。 77E5:E6 03 AND #03h SP:dff7 A:f8 B:00 C:02 D:1c E:0e F:a0 H:c4 L:82 Cy:177065132 ; ノーゼロであれば(=4フレームに一度の機会でなければ)77EFへジャンプ。 ; 0000(#00h,該当) → 0001(#01h,非該当) → 0010(#02h,非該当) → 0011(#03h,非該当) → 0100(#04h,該当) 以降繰り返し... ; 今回は両方共ゼロ、つまり4フレームに一度来る非成立。カウンターのデクリメント処理へ 77E7:20 06 JR NZ,77EFh SP:dff7 A:00 B:00 C:02 D:1c E:0e F:a0 H:c4 L:82 Cy:177065140 ; イベントカウンタのデクリメント用のサブルーチンを開始 77E9:CD 87 08 CALL #0887h SP:dff7 A:00 B:00 C:02 D:1c E:0e F:a0 H:c4 L:82 Cy:177065148 ; イベントカウンタのベースアドレスと処理中番号と合算 0887:21 50 C4 LD HL,#C450h SP:dff5 A:00 B:00 C:02 D:1c E:0e F:a0 H:c4 L:82 Cy:177065172 088A:18 08 JR 0894h SP:dff5 A:00 B:00 C:02 D:1c E:0e F:a0 H:c4 L:50 Cy:177065184 0894:09 ADD HL,BC SP:dff5 A:00 B:00 C:02 D:1c E:0e F:a0 H:c4 L:50 Cy:177065196 ; イベントカウンタの値をAにロード 0895:7E LD A,(HL) SP:dff5 A:00 B:00 C:02 D:1c E:0e F:80 H:c4 L:52 Cy:177065204 ; AND Aでゼロかどうかを確かめる。今回ノーゼロ。 0896:A7 AND A SP:dff5 A:52 B:00 C:02 D:1c E:0e F:80 H:c4 L:52 Cy:177065212 ; サブルーチン終了 0897:C9 RET SP:dff5 A:52 B:00 C:02 D:1c E:0e F:20 H:c4 L:52 Cy:177065216 ; 先のイベントカウンタの値がゼロであれば77EFへジャンプ(77EEをスキップ)。 ; 今回はノーゼロなので処理を行う 77EC:28 01 JR Z,77EFh SP:dff7 A:52 B:00 C:02 D:1c E:0e F:20 H:c4 L:52 Cy:177065232 ; イベントカウンタをデクリメント。 77EE:35 DEC (HL) SP:dff7 A:52 B:00 C:02 D:1c E:0e F:20 H:c4 L:52 Cy:177065240
部屋中の移動タイルは複数の移動先に関わらず固定の番号を持っており、 これらはマップ情報としてタイル位置に応じて複数スロット(#D416h-#D419hまでの4バイト(=4スロット)分)を持って移動先を管理し、 リンクが接触したタイルの位置とそれらを照らし合わせる事によって管理がされている。
前者がタイルの位置番号。後者がタイル内容。 このマップでは移動タイルの位置として35,33,00,00が振られており、それぞれの位置には共通のドアタイル「E2」が使われている事がわかる。
通常ならリンクが踏んでいるタイルの位置と タイル自体の位置のそれぞれを照合して、 同一だった番号のスロットから読み出された移動先が使われる。 だが、移動タイルに対してリンクが特定の 不正な方法で触れると「タイルに接触はしたが、移動先判定を行う際に位置がずれる」という 移動スロットのどれにも該当しない状態が起きてしまう事がある。
通常のスロット用としては[マップカテゴリ][サブルームID][ベースマップ位置][リンクX位置][リンクY位置]の5バイトが4つに連なった #D401h-#D419hの20バイト(5バイト*4スロット分)が使われているが、 この状態が起きると移動先を制御するルーチンは処理を誤り 本来なら移動先情報として読み出されてはいけない#D415h-#D419hが読み出される。
ここで読み出されてしまう#D415hの内容は敵の撃破数、その後の#D416h-#D419hの4バイトはスロット判別用のタイル位置に相当しており、 [敵撃破数][S1-判別タイル位置][S2-判別タイル位置][S3-判別タイル位置][S4-判別タイル位置]がそのまま [マップカテゴリ][サブルームID][ベースマップ位置][リンクX位置][リンクY位置]に対応して書き込まれてしまう事になる。 「それまでの敵の撃破数を変えると移動先が変化する」というのは 敵の撃破数が誤って読み出された後に書き込まれる場所がマップカテゴリ値にあたるのに由来し、 また、これが任意コード実行が出来る原因の一つともなる(後述)。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
D40* | 未使用 | スロット0番、試行1回目(5バイト) | スロット1番、試行2回目(5バイト) | スロット2番、試行3回目(5バイト) | ||||||||||||
マップカテゴリ | サブルームID | ベースマップ位置 | リンク開始X位置 | リンク開始Y位置 | マップカテゴリ | サブルームID | ベースマップ位置 | リンク開始X位置 | リンク開始Y位置 | マップカテゴリ | サブルームID | ベースマップ位置 | リンク開始X位置 | リンク開始Y位置 | ||
D41* | スロット3番、試行4回目(5バイト) | 4回分の試行に失敗時(5バイト) | 未使用 | |||||||||||||
マップカテゴリ | サブルームID | ベースマップ位置 | リンク開始X位置 | リンク開始Y位置 | 敵撃破数 | S1-判別タイル位置 | S2-判別タイル位置 | S3-判別タイル位置 | S4-判別タイル位置 |
; 実際に処理を読んだ時のトレースログ(DX版) ; おことわり 下記のトレースログはTASを製作する前の調査として取得した物であり ; 完成されたTASのキーファイルから得られる動作によるログではありません。 ; 移動先スロット先頭にあたるRAMアドレス0xD416をHLにロード 18B4:21 16 D4 LD HL,#D416h SP:dffb A:00 B:04 C:00 D:00 E:00 F:a0 H:d4 L:01 Cy:172156280 ; Cレジスタを0x00に初期化(これが試行回数になる) 18B7:0E 00 LD C,#00h SP:dffb A:00 B:04 C:00 D:00 E:00 F:a0 H:d4 L:16 Cy:172156292 ; ここから移動先スロットチェックのルーチン ; #FF98h、リンクのX座標をAにロード 18B9:F0 98 LDH A,(#FF98h) SP:dffb A:00 B:04 C:00 D:00 E:00 F:a0 H:d4 L:16 Cy:172156300 ; Aレジスタをスワップ(4bitの循環右ローテーション) 18BB:CB 37 SWAP A SP:dffb A:62 B:04 C:00 D:00 E:00 F:a0 H:d4 L:16 Cy:172156312 ; 0x0FとANDする事で ; AレジスタにリンクX座標の上部4ビットだけを ; 下位4ビットに収めた物に相当する値を取り出す 18BD:E6 0F AND #0Fh SP:dffb A:26 B:04 C:00 D:00 E:00 F:00 H:d4 L:16 Cy:172156320 ; 0x0F(00001111)とAND ; 0x26 00100110 ; 0x0F 00000110 ; 結果 ; 0x06 00000110 ; 結果となったAレジスタの内容をEレジスタにコピー 18BF:5F LD E,A SP:dffb A:06 B:04 C:00 D:00 E:00 F:20 H:d4 L:16 Cy:172156328 ; #FF99h、リンクのY座標をAにロード 18C0:F0 99 LDH A,(#FF99h) SP:dffb A:06 B:04 C:00 D:00 E:06 F:20 H:d4 L:16 Cy:172156332 ; Y座標は下部が基点となっているので、中央点に直すために0x08を引く 18C2:D6 08 SUB #08h SP:dffb A:30 B:04 C:00 D:00 E:06 F:20 H:d4 L:16 Cy:172156344 ; 0xF0(11110000)とANDして、上位4ビットをそのまま取り出す ; 0x28 00101000 ; 0xF0 11110000 ; 結果 ; 0x20 00100000 18C4:E6 F0 AND #F0h SP:dffb A:28 B:04 C:00 D:00 E:06 F:40 H:d4 L:16 Cy:172156352 ; リンクX座標上位4ビットだけを下位4ビットに収めた結果が入ったEレジスタと ; リンクY座標上位4ビットだけを上位4ビットに収めた結果が入ったAレジスタとでOR ; 1タイルのサイズは縦横ともに丁度0x0Fなので、 ; 結果としてリンクが現在居るタイル位置に相当する0xYXという形が出来上がる 18C6:B3 OR E SP:dffb A:20 B:04 C:00 D:00 E:06 F:20 H:d4 L:16 Cy:172156360 ; その結果を先のタイル移動先スロットとコンペア 18C7:BE CP (HL) SP:dffb A:26 B:04 C:00 D:00 E:06 F:00 H:d4 L:16 Cy:172156364 ; ゼロではない=このスロットではない ; 故にジャンプ不成立 18C8:28 07 JR Z,18D1h SP:dffb A:26 B:04 C:00 D:00 E:06 F:50 H:d4 L:16 Cy:172156372 ; HLをインクリメントし、直前スロットのアドレスから+1 18CA:23 INC HL SP:dffb A:26 B:04 C:00 D:00 E:06 F:50 H:d4 L:16 Cy:172156380 ; Cをインクリメントし、試行回数1回分をカウント 18CB:0C INC C SP:dffb A:26 B:04 C:00 D:00 E:06 F:50 H:d4 L:17 Cy:172156388 ; 試行回数をAレジスタにコピーして0x04とコンペア ; 結果がノーゼロなら18B9へ戻る ; つまり、試行回数が0x04(=4回目の試行が失敗した直後)でなければ ; 直前のスロット処理へ戻るという処理 18CC:79 LD A,C SP:dffb A:26 B:04 C:01 D:00 E:06 F:10 H:d4 L:17 Cy:172156392 18CD:FE 04 CP #04h SP:dffb A:01 B:04 C:01 D:00 E:06 F:10 H:d4 L:17 Cy:172156396 18CF:20 E8 JR NZ,18B9h SP:dffb A:01 B:04 C:01 D:00 E:06 F:50 H:d4 L:17 Cy:172156404 ; また直前の処理へ戻ってくる。内容については ; スロットアドレスと試行回数が ; インクリメントされている以外は同一なのでほぼ省略。 18B9:F0 98 LDH A,(#FF98h) SP:dffb A:01 B:04 C:01 D:00 E:06 F:50 H:d4 L:17 Cy:172156416 18BB:CB 37 SWAP A SP:dffb A:62 B:04 C:01 D:00 E:06 F:50 H:d4 L:17 Cy:172156428 18BD:E6 0F AND #0Fh SP:dffb A:26 B:04 C:01 D:00 E:06 F:00 H:d4 L:17 Cy:172156436 18BF:5F LD E,A SP:dffb A:06 B:04 C:01 D:00 E:06 F:20 H:d4 L:17 Cy:172156444 18C0:F0 99 LDH A,(#FF99h) SP:dffb A:06 B:04 C:01 D:00 E:06 F:20 H:d4 L:17 Cy:172156448 18C2:D6 08 SUB #08h SP:dffb A:30 B:04 C:01 D:00 E:06 F:20 H:d4 L:17 Cy:172156460 18C4:E6 F0 AND #F0h SP:dffb A:28 B:04 C:01 D:00 E:06 F:40 H:d4 L:17 Cy:172156468 18C6:B3 OR E SP:dffb A:20 B:04 C:01 D:00 E:06 F:20 H:d4 L:17 Cy:172156476 18C7:BE CP (HL) SP:dffb A:26 B:04 C:01 D:00 E:06 F:00 H:d4 L:17 Cy:172156480 18C8:28 07 JR Z,18D1h SP:dffb A:26 B:04 C:01 D:00 E:06 F:50 H:d4 L:17 Cy:172156488 18CA:23 INC HL SP:dffb A:26 B:04 C:01 D:00 E:06 F:50 H:d4 L:17 Cy:172156496 ; また失敗なので試行回数をインクリメント 18CB:0C INC C SP:dffb A:26 B:04 C:01 D:00 E:06 F:50 H:d4 L:18 Cy:172156504 18CC:79 LD A,C SP:dffb A:26 B:04 C:02 D:00 E:06 F:10 H:d4 L:18 Cy:172156508 18CD:FE 04 CP #04h SP:dffb A:02 B:04 C:02 D:00 E:06 F:10 H:d4 L:18 Cy:172156512 18CF:20 E8 JR NZ,18B9h SP:dffb A:02 B:04 C:02 D:00 E:06 F:50 H:d4 L:18 Cy:172156520 ; 中略。3回目の試行 18B9:F0 98 LDH A,(#FF98h) SP:dffb A:02 B:04 C:02 D:00 E:06 F:50 H:d4 L:18 Cy:172156532 18BB:CB 37 SWAP A SP:dffb A:62 B:04 C:02 D:00 E:06 F:50 H:d4 L:18 Cy:172156544 18BD:E6 0F AND #0Fh SP:dffb A:26 B:04 C:02 D:00 E:06 F:00 H:d4 L:18 Cy:172156552 18BF:5F LD E,A SP:dffb A:06 B:04 C:02 D:00 E:06 F:20 H:d4 L:18 Cy:172156560 18C0:F0 99 LDH A,(#FF99h) SP:dffb A:06 B:04 C:02 D:00 E:06 F:20 H:d4 L:18 Cy:172156564 18C2:D6 08 SUB #08h SP:dffb A:30 B:04 C:02 D:00 E:06 F:20 H:d4 L:18 Cy:172156576 18C4:E6 F0 AND #F0h SP:dffb A:28 B:04 C:02 D:00 E:06 F:40 H:d4 L:18 Cy:172156584 18C6:B3 OR E SP:dffb A:20 B:04 C:02 D:00 E:06 F:20 H:d4 L:18 Cy:172156592 18C7:BE CP (HL) SP:dffb A:26 B:04 C:02 D:00 E:06 F:00 H:d4 L:18 Cy:172156596 18C8:28 07 JR Z,18D1h SP:dffb A:26 B:04 C:02 D:00 E:06 F:40 H:d4 L:18 Cy:172156604 18CA:23 INC HL SP:dffb A:26 B:04 C:02 D:00 E:06 F:40 H:d4 L:18 Cy:172156612 ; またまた失敗なので試行回数をインクリメント 18CB:0C INC C SP:dffb A:26 B:04 C:02 D:00 E:06 F:40 H:d4 L:19 Cy:172156620 18CC:79 LD A,C SP:dffb A:26 B:04 C:03 D:00 E:06 F:00 H:d4 L:19 Cy:172156624 18CD:FE 04 CP #04h SP:dffb A:03 B:04 C:03 D:00 E:06 F:00 H:d4 L:19 Cy:172156628 18CF:20 E8 JR NZ,18B9h SP:dffb A:03 B:04 C:03 D:00 E:06 F:50 H:d4 L:19 Cy:172156636 ; 中略。4回目の試行。 18B9:F0 98 LDH A,(#FF98h) SP:dffb A:03 B:04 C:03 D:00 E:06 F:50 H:d4 L:19 Cy:172156648 18BB:CB 37 SWAP A SP:dffb A:62 B:04 C:03 D:00 E:06 F:50 H:d4 L:19 Cy:172156660 18BD:E6 0F AND #0Fh SP:dffb A:26 B:04 C:03 D:00 E:06 F:00 H:d4 L:19 Cy:172156668 18BF:5F LD E,A SP:dffb A:06 B:04 C:03 D:00 E:06 F:20 H:d4 L:19 Cy:172156676 18C0:F0 99 LDH A,(#FF99h) SP:dffb A:06 B:04 C:03 D:00 E:06 F:20 H:d4 L:19 Cy:172156680 18C2:D6 08 SUB #08h SP:dffb A:30 B:04 C:03 D:00 E:06 F:20 H:d4 L:19 Cy:172156692 18C4:E6 F0 AND #F0h SP:dffb A:28 B:04 C:03 D:00 E:06 F:40 H:d4 L:19 Cy:172156700 18C6:B3 OR E SP:dffb A:20 B:04 C:03 D:00 E:06 F:20 H:d4 L:19 Cy:172156708 18C7:BE CP (HL) SP:dffb A:26 B:04 C:03 D:00 E:06 F:00 H:d4 L:19 Cy:172156712 18C8:28 07 JR Z,18D1h SP:dffb A:26 B:04 C:03 D:00 E:06 F:40 H:d4 L:19 Cy:172156720 18CA:23 INC HL SP:dffb A:26 B:04 C:03 D:00 E:06 F:40 H:d4 L:19 Cy:172156728 ; 4回目の試行も失敗に終わり、試行回数のCレジスタをインクリメント。 18CB:0C INC C SP:dffb A:26 B:04 C:03 D:00 E:06 F:40 H:d4 L:1a Cy:172156736 18CC:79 LD A,C SP:dffb A:26 B:04 C:04 D:00 E:06 F:00 H:d4 L:1a Cy:172156740 ; 4回やってもダメな場合、ジャンプ命令を無視してそのまま続行する。 ; この場合ジャンプで飛んでいないが、 ; 途中で成立しても同じく18D1に飛んでくるのでやる事は変わらない。 18CD:FE 04 CP #04h SP:dffb A:04 B:04 C:04 D:00 E:06 F:00 H:d4 L:1a Cy:172156744 18CF:20 E8 JR NZ,18B9h SP:dffb A:04 B:04 C:04 D:00 E:06 F:c0 H:d4 L:1a Cy:172156752 ; AにC(ここまでに試行した回数)をロード 18D1:79 LD A,C SP:dffb A:04 B:04 C:04 D:00 E:06 F:c0 H:d4 L:1a Cy:172156760 ; これをSLAで4倍(0x04→0x08→0x10)に元々の値を合算して合計5倍(データサイズ分) 18D2:CB 27 SLA A SP:dffb A:04 B:04 C:04 D:00 E:06 F:c0 H:d4 L:1a Cy:172156764 18D4:CB 27 SLA A SP:dffb A:08 B:04 C:04 D:00 E:06 F:00 H:d4 L:1a Cy:172156772 18D6:81 ADD A,C SP:dffb A:10 B:04 C:04 D:00 E:06 F:00 H:d4 L:1a Cy:172156780 ; 結果をEレジスタへコピー 18D7:5F LD E,A SP:dffb A:14 B:04 C:04 D:00 E:06 F:00 H:d4 L:1a Cy:172156784 ; Dレジスタを00で初期化 18D8:16 00 LD D,#00h SP:dffb A:14 B:04 C:04 D:00 E:14 F:00 H:d4 L:1a Cy:172156788 ; 0xD401というRAMアドレスをHLにロード。 ; これが移動先として書き込む内容のベースアドレスになる。 18DA:21 01 D4 LD HL,#D401h SP:dffb A:14 B:04 C:04 D:00 E:14 F:00 H:d4 L:1a Cy:172156796 ; 先に試行回数から得た値をアドレスに合算する。 ; 通常であればこれが最大の4スロット目(0から始めて3で4つ)でも ; ((3*2)+(3*2)+3)=0x0Fになるはずだが、 ; 今回は4スロット全てに該当しなかった(試行回数が0から始めて04、5回目相当になっている)ので ; 結果が0x14となっている。 ; つまり、HLの内容が移動先として書き込む内容が ; 含まれた正規のアドレスでなくなってしまっている。 ; 正常に掴まされる形式としては[マップカテゴリ][サブルームID][ベースマップ位置][リンクX位置][リンクY位置]の順。 ; 読み込まれるアドレスの先頭に当たる0xD415は敵を倒した数に相当し、 ; 続く0xD416と0xD417は前述の移動先スロットの前二つに相当する。 ; 追記: 移動として読み込まれる全ては [マップカテゴリ][サブルームID][ベースマップ位置][開始リンクX位置][開始リンクY位置] 18DD:19 ADD HL,DE SP:dffb A:14 B:04 C:04 D:00 E:14 F:00 H:d4 L:01 Cy:172156808 ; アドレス算出結果をスタックに積んでおく 18DE:E5 PUSH HL SP:dffb A:14 B:04 C:04 D:00 E:14 F:00 H:d4 L:15 Cy:172156816 ; 0xD415、敵を倒した数を誤ってマップカテゴリの値としてロードしつつHLをインクリメント 18DF:2A LD A,(HL+) SP:dff9 A:14 B:04 C:04 D:00 E:14 F:00 H:d4 L:15 Cy:172156832 ; マップカテゴリの値として書き込み 18E0:EA A5 DB LD (#DBA5h),A SP:dff9 A:00 B:04 C:04 D:00 E:14 F:00 H:d4 L:16 Cy:172156840 ; マップカテゴリとして書き込まれた値を0x02とコンペアし、 ; もし02以外であれば0x18F1へジャンプ。今回成立。 18E3:FE 02 CP #02h SP:dff9 A:00 B:04 C:04 D:00 E:14 F:00 H:d4 L:16 Cy:172156856 18E5:20 0A JR NZ,18F1h SP:dff9 A:00 B:04 C:04 D:00 E:14 F:50 H:d4 L:16 Cy:172156864 ; D416、移動先スロット用リンク位置の1番目を誤ってサブルームID用内容としてロード 18F1:2A LD A,(HL+) SP:dff9 A:00 B:04 C:04 D:00 E:14 F:50 H:d4 L:16 Cy:172156876 ; 結果を0xFFF7、サブルームIDへ書き込み 18F2:E0 F7 LDH (#FFF7h),A SP:dff9 A:35 B:04 C:04 D:00 E:14 F:50 H:d4 L:17 Cy:172156884 ; AにOWUWの現在値をロードしてAND Aでノーゼロかどうかチェック(今回は関係ない直後のジャンプで使用) 18F4:FA A5 DB LD A,(#DBA5h) SP:dff9 A:35 B:04 C:04 D:00 E:14 F:50 H:d4 L:17 Cy:172156896 18F7:A7 AND A SP:dff9 A:00 B:04 C:04 D:00 E:14 F:50 H:d4 L:17 Cy:172156912 ; D417、移動タイルスロット2番目を誤って全体部屋位置の値としてロード 18F8:2A LD A,(HL+) SP:dff9 A:00 B:04 C:04 D:00 E:14 F:a0 H:d4 L:17 Cy:172156916 ; 全体部屋位置に書き込み 18F9:E0 F6 LDH (#FFF6h),A SP:dff9 A:33 B:04 C:04 D:00 E:14 F:a0 H:d4 L:18 Cy:172156924 ; 以下省略(リンクX位置とY位置に書き込みを行う処理が続くが、特に読む必要がないため)
宝箱の開閉状態等におけるマップ状態フラグはRAM上において OW(#D800h-#D8FFh)、UW1(#D900h-#D9FFh)、UW2(#DA00h-#DAFFh)の範囲で管理されている。 読み書きの処理としてはベースアドレス#D800hにマップカテゴリ値を上位、ベースマップ位置を下位として合算し、 更にサブルームIDの値(=UW1、UW2の区別)に応じてUW2だった場合に+#100hの合算をする事で算出される。
通常であればマップカテゴリの値は#1hが限度であり(移動時に2を渡すと横スクロールフラグを立てた上で1が書き込まれる)、 通常なら他を合算してもフラグ記録アドレスとして扱われる範囲は#D800h-#DAFFhの中へ収まる。 だが、犬小屋バグなどでマップカテゴリの値を#3h以上などの異常な内容とした場合は 単純にマップカテゴリ値を上位バイトとして合算するコードのために想定される範囲を超え、 各種ステータスなどを含んだ#DB00h以降のアドレスへ誤って書き込もうとするケースが出てくる事になる。
今回のTASにおいては犬小屋バグで異常移動を発生させる際に敵を倒した数(マップカテゴリ値)を#03hとし、 その上で宝箱を開くマップをベースマップ位置#96hとすることで#DB96、ゲームモード2の内容を破壊している。
フラグ・ベースアドレス | D | 8 | 0 | 0 |
---|---|---|---|---|
マップカテゴリ値 | 0 | 3 | * | * |
ベースマップ・現在位置値 | * | * | 9 | 6 |
UW1、UW2の区別(サブルームID値依存) | * | 0 | * | * |
フラグとして実際に書き込まれるアドレス | D | B | 9 | 6 |
; 無印版TAS フレーム4774-4775(end)より一部抜粋 ; ゲームモードDB96hの破壊まで ; サブルーチン開始 51D8:CD E2 51 CALL #51E2h SP:dff9 A:ff B:00 C:0f D:00 E:ff F:40 H:c3 L:bf Cy:335395644 ; 現在マップカテゴリ値をDレジスタにロードする 51E2:FA A5 DB LD A,(#DBA5h) SP:dff7 A:ff B:00 C:0f D:00 E:ff F:40 H:c3 L:bf Cy:335395668 51E5:57 LD D,A SP:dff7 A:03 B:00 C:0f D:00 E:ff F:40 H:c3 L:bf Cy:335395684 ; ベースアドレス0xD800をHLにロード 51E6:21 00 D8 LD HL,#D800h SP:dff7 A:03 B:00 C:0f D:03 E:ff F:40 H:c3 L:bf Cy:335395688 ; 現在マップ位置をEレジスタにロードする 51E9:F0 F6 LDH A,(#FFF6h) SP:dff7 A:03 B:00 C:0f D:03 E:ff F:40 H:d8 L:00 Cy:335395700 51EB:5F LD E,A SP:dff7 A:96 B:00 C:0f D:03 E:ff F:40 H:d8 L:00 Cy:335395712 ; 現在サブルームIDを読み込み、1A以上なら51F7へジャンプ 今回成立 51EC:F0 F7 LDH A,(#FFF7h) SP:dff7 A:96 B:00 C:0f D:03 E:96 F:40 H:d8 L:00 Cy:335395716 51EE:FE 1A CP #1Ah SP:dff7 A:35 B:00 C:0f D:03 E:96 F:40 H:d8 L:00 Cy:335395728 51F0:30 05 JR NC,51F7h SP:dff7 A:35 B:00 C:0f D:03 E:96 F:40 H:d8 L:00 Cy:335395736 ; マップフラグベースアドレスD800とDEを合算。Dはマップカテゴリ値、Eはベースマップ位置 ; 0xD800+0x0396=0xDB96、つまり結果がゲームモードのアドレスとなっている 51F7:19 ADD HL,DE SP:dff7 A:35 B:00 C:0f D:03 E:96 F:40 H:d8 L:00 Cy:335395748 ; サブルーチン終了 51F8:C9 RET SP:dff7 A:35 B:00 C:0f D:03 E:96 F:00 H:db L:96 Cy:335395756 ; 現在のアドレス内容をAレジスタに読み込み 51DB:7E LD A,(HL) SP:dff9 A:35 B:00 C:0f D:03 E:96 F:00 H:db L:96 Cy:335395772 ; 0x10(00010000)とOR、つまり4ビット(5番目)にフラグを立てる ; 本来であればこれが宝箱の開閉フラグとして使われる 51DC:F6 10 OR #10h SP:dff9 A:07 B:00 C:0f D:03 E:96 F:00 H:db L:96 Cy:335395780 ; 書き込まれる。これでDB96hの内容が破壊された事になる。 51DE:77 LD (HL),A SP:dff9 A:17 B:00 C:0f D:03 E:96 F:00 H:db L:96 Cy:335395788
ゲームモードの値はメインループに含まれる処理分岐のアドレス算出に直接使われており、 これが破壊されて不正に大きな値を持つ事によってRAM・EchoRAMを含んだ想定されない範囲へのジャンプが起こり得るようになる。
; ゲームモード破壊以後・異常ジャンプまで ; ここから暴走ジャンプ ; (#DB96h)=ゲームモードをロード 431E:FA 96 DB LD A,(#DB96h) SP:dffd A:01 B:00 C:00 D:00 E:03 F:a0 H:76 L:50 Cy:335443580 ; ここでRSTでスタックに4322が積まれる(これが分岐元のアドレスになる) 4321:C7 RST 00H SP:dffd A:17 B:00 C:00 D:00 E:03 F:a0 H:76 L:50 Cy:335443596 0000:C3 72 28 JP #2872h SP:dffb A:17 B:00 C:00 D:00 E:03 F:a0 H:76 L:50 Cy:335443612 ; Eにゲームモード値をコピーしておく 2872:5F LD E,A SP:dffb A:17 B:00 C:00 D:00 E:03 F:a0 H:76 L:50 Cy:335443628 ; Dを00で初期化 2873:16 00 LD D,#00h SP:dffb A:17 B:00 C:00 D:00 E:17 F:a0 H:76 L:50 Cy:335443632 ; ゲームモード値をSLAで二倍 2875:CB 23 SLA E SP:dffb A:17 B:00 C:00 D:00 E:17 F:a0 H:76 L:50 Cy:335443640 ; DをCy付き左ローテートで事実上Cy格納、今回無し 2877:CB 12 RL D SP:dffb A:17 B:00 C:00 D:00 E:2e F:00 H:76 L:50 Cy:335443648 ; 先のRST元PCの4322をスタックからHLに取り出し 2879:E1 POP HL SP:dffb A:17 B:00 C:00 D:00 E:2e F:80 H:76 L:50 Cy:335443656 ; これを上位が先のCy結果入りD、下位8ビットがDB96ゲームモードのDEと合算する 287A:19 ADD HL,DE SP:dffd A:17 B:00 C:00 D:00 E:2e F:80 H:43 L:22 Cy:335443668 ; そのアドレスからEに入れる 287B:5E LD E,(HL) SP:dffd A:17 B:00 C:00 D:00 E:2e F:80 H:43 L:50 Cy:335443676 ; 続いてHLをインクリメントして今度はDに入れる 287C:23 INC HL SP:dffd A:17 B:00 C:00 D:00 E:c9 F:80 H:43 L:50 Cy:335443684 287D:56 LD D,(HL) SP:dffd A:17 B:00 C:00 D:00 E:c9 F:80 H:43 L:51 Cy:335443692 ; DEをPUSHして即POP HLでHLに移す 287E:D5 PUSH DE SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:43 L:51 Cy:335443700 287F:E1 POP HL SP:dffb A:17 B:00 C:00 D:fa E:c9 F:80 H:43 L:51 Cy:335443716 ; JP (HL)で飛ぶ。大本のゲームモードが狂っているので飛び先を誤りRAM(Echo RAM)上の#FAC9hに出てくる 2880:E9 JP (HL) SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443728
*0 | *1 | *2 | *3 | *4 | *5 | *6 | *7 | *8 | *9 | *A | *B | *C | *D | *E | *F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0* | 空 | あ | い | う | え | お | か | き | く | け | こ | さ | し | す | せ | そ |
1* | た | ち | つ | て | と | な | に | ぬ | ね | の | は | ひ | ふ | へ | ほ | ま |
2* | み | む | め | も | や | ゆ | よ | ら | り | る | れ | ろ | わ | を | ん | が |
3* | ぎ | ぐ | げ | ご | ざ | じ | ず | ぜ | ぞ | だ | ぢ | づ | で | ど | ば | び |
4* | ぶ | べ | ぼ | ぱ | ぴ | ぷ | ぺ | ぽ | ゃ | ゅ | ょ | っ | * | * | * | * |
5* | * | ア | イ | ウ | エ | オ | カ | キ | ク | ケ | コ | サ | シ | ス | セ | ソ |
6* | タ | チ | ツ | テ | ト | ナ | ニ | ヌ | ネ | ノ | ハ | ヒ | フ | ヘ | ホ | マ |
7* | ミ | ム | メ | モ | ヤ | ユ | ヨ | ラ | リ | ル | レ | ロ | ワ | ヲ | ン | ガ |
8* | ギ | グ | ゲ | ゴ | ザ | ジ | ズ | ゼ | ゾ | ダ | ヂ | ヅ | デ | ド | バ | ビ |
9* | ブ | ベ | ボ | パ | ピ | プ | ペ | ポ | ャ | ュ | ョ | ッ | * | * | * | * |
A* | * | ! | ? | ー | 空 | . | 、 | 。 | 「 | 」 | * | * | * | * | * | * |
B* | * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ァ | ィ | ゥ | ェ | ォ |
C* | R | * | * | * | * | * | * | * | * | * | * | * | * | * | * | * |
D* | * | A | B | C | D | E | F | |||||||||
E* | ||||||||||||||||
F* | * | ↑ | ↓ | ← | → | * | * | * | * | * | * | * | * | * | 空 | * |
リンクの名前文字として使えるのは濁音と半濁音を含んだ平仮名全てと「ー(長音)」のみ。 また、「あ」は先頭の01以外はダミー。絵文字の重複は本編中でどちらが使われているのか不明。
余談: 「R」は「Rモトごろく」でしか使われてない……気がする。
セーブ1 | い | う | け | ね | ぐ |
---|---|---|---|---|---|
02 | 03 | 09 | 18 | 31 | |
セーブ2 | る | ば | ど | が | め |
29 | 3E | 3D | 2F | 22 | |
セーブ3 | ば | あ | め | ぬ | め |
3E | 01 | 22 | 17 | 22 |
上記の名前によって行われる操作については以下の通り。
プレイ中データのリンクの名前はRAMアドレス#DB4Fh-#DB53hに5バイト(一文字1バイト)で格納されている。
プレイ中データのリンクの名前とは別に 各セーブデータ(プレイ中の物も含む)のリンクの名前もRAM上に格納されており、 それぞれセーブ1が#DB80h-#DB84h、セーブ2が#DB85h-#DB89h、セーブ3が#DB8Ah-#DB8Ehにある。 これらは何れかのデータでプレイを始めてもRAM上に保持され続けており、 今回のTASにおいては先に実行されるプレイ中リンクの文字列(データ1)から相対ジャンプを行う事で データ2、データ3の名前を実行している。
DX(JP)版においてもコード実行までは同様の方法で行えますが、各種アドレスなどの違いで「だちるねら」「けばうげま」「げばどがげ」でないと通りません。また、挙動が不安定で実行が出来ない事があります(後日追記)。
DB95とDB96を適切な値に修正しながらDB94にも#C2h(JP NZ, #****h)を書き込んでおくことで セーブ3の名前列を通り過ぎた後にゲームモードの値二つ自体がジャンプ先のアドレスとして使われ、 メインルーチン中のアドレス#0301hへのジャンプが成立する。
DX版を含めた一連の実行コードについてはpirohiko先生に相談した上で最終的に同氏に書いて頂きました。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
DAC* | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
DAD* | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
DAE* | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
DAF* | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
DB0* | 04 | 01 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
DB1* | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
DB2* | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
DB3* | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
DB4* | 00 | 00 | 00 | 00 | 01 | 00 | 00 | 31 | 00 | 00 | 00 | 00 | 00 | 00 | 01 | 02 |
DB5* | 03 | 09 | 18 | 31 | A1 | 00 | 00 | 00 | 00 | 00 | 10 | 03 | 00 | 00 | 00 | 03 |
DB6* | 35 | 33 | 00 | 00 | 40 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 16 |
DB7* | 50 | 27 | 00 | 00 | 00 | 00 | 20 | 30 | 30 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
DB8* | 02 | 03 | 09 | 18 | 31 | 29 | 3E | 3D | 2F | 22 | 3E | 01 | 22 | 17 | 22 | 00 |
DB9* | 00 | 00 | 00 | 00 | C2 | 01 | 03 | E4 | 1C | E4 | 80 | 00 | A3 | 00 | 00 | 00 |
; TAS(無印版)中における実際のトレースログ EDジャンプまで ; HLはこのまま維持されて後のコード実行にも使われる FAC9:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443732 FACA:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443736 FACB:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443740 FACC:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443744 FACD:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443748 FACE:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443752 FACF:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443756 FAD0:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443760 FAD1:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443764 FAD2:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443768 FAD3:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443772 FAD4:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443776 FAD5:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443780 FAD6:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443784 FAD7:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443788 FAD8:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443792 FAD9:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443796 FADA:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443800 FADB:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443804 FADC:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443808 FADD:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443812 FADE:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443816 FADF:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443820 FAE0:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443824 FAE1:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443828 FAE2:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443832 FAE3:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443836 FAE4:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443840 FAE5:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443844 FAE6:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443848 FAE7:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443852 FAE8:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443856 FAE9:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443860 FAEA:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443864 FAEB:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443868 FAEC:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443872 FAED:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443876 FAEE:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443880 FAEF:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443884 FAF0:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443888 FAF1:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443892 FAF2:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443896 FAF3:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443900 FAF4:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443904 FAF5:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443908 FAF6:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443912 FAF7:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443916 FAF8:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443920 FAF9:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443924 FAFA:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443928 FAFB:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443932 FAFC:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443936 FAFD:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443940 FAFE:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443944 FAFF:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443948 FB00:04 INC B SP:dffd A:17 B:00 C:00 D:fa E:c9 F:80 H:fa L:c9 Cy:335443952 FB01:01 00 00 LD BC,#0000h SP:dffd A:17 B:01 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335443956 FB04:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335443968 FB05:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335443972 FB06:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335443976 FB07:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335443980 FB08:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335443984 FB09:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335443988 FB0A:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335443992 FB0B:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335443996 FB0C:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444000 FB0D:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444004 FB0E:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444008 FB0F:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444012 FB10:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444016 FB11:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444020 FB12:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444024 FB13:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444028 FB14:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444032 FB15:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444036 FB16:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444040 FB17:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444044 FB18:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444048 FB19:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444052 FB1A:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444056 FB1B:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444060 FB1C:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444064 FB1D:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444068 FB1E:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444072 FB1F:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444076 FB20:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444080 FB21:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444084 FB22:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444088 FB23:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444092 FB24:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444096 FB25:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444100 FB26:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444104 FB27:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444108 FB28:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444112 FB29:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444116 FB2A:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444120 FB2B:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444124 FB2C:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444128 FB2D:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444132 FB2E:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444136 FB2F:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444140 FB30:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444144 FB31:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444148 FB32:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444152 FB33:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444156 FB34:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444160 FB35:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444164 FB36:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444168 FB37:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444172 FB38:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444176 FB39:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444180 FB3A:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444184 FB3B:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444188 FB3C:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444192 FB3D:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444196 FB3E:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444200 FB3F:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444204 FB40:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444208 FB41:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444212 FB42:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444216 FB43:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444220 FB44:01 00 00 LD BC,#0000h SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444224 ; DB47/FB47は汎用カウンタが一周するに応じてカウント(インクリメント)処理がされる。 ; しかしながらこれはゲーム中での使用箇所が見つかっておらず、 ; また、リセット処理もされないので一度カウントが進みきるとFFで固定になる。 ; TASにおいて最速で宝箱からのコード実行を行おうとするとHLがデクリメントされてしまうので、 ; 名前欄の一文字目はそれに合わせた物になっている。 ; 他のタイミングなど、実機で行う場合はセーブ1の一文字目を「あ」にするとよい。 ; 未使用カウンタでデクリメントされるHL FB47:32 LD (HL-),A SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c9 Cy:335444236 FB48:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c8 Cy:335444244 FB49:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c8 Cy:335444248 FB4A:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c8 Cy:335444252 FB4B:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c8 Cy:335444256 FB4C:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c8 Cy:335444260 FB4D:00 NOP SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c8 Cy:335444264 ; FB4F-FB53がプレイ中リンク名 ; 直前のFB4E=剣レベル、つまり事実上0x01強制 ; 1文字目、2文字目FB50で 「い(0x02)」「う(0x03)」 ; Bレジスタに03、Cレジスタに02をロード FB4E:01 02 03 LD BC,#0302h SP:dffd A:17 B:00 C:00 D:fa E:c9 F:00 H:fa L:c8 Cy:335444268 ; 3文字目「け(0x09)」 ; 元々あったHLと先のBCを合算 FB51:09 ADD HL,BC SP:dffd A:17 B:03 C:02 D:fa E:c9 F:00 H:fa L:c8 Cy:335444280 ; 4文字目「ね(0x18)」 5文字目「ぐ(0x31)」 ; 0x31先に相対ジャンプする。 ; ジャンプ先のDB85/FB85はセーブデータ2の名前先頭 FB52:18 31 JR FB85h SP:dffd A:17 B:03 C:02 D:fa E:c9 F:00 H:fd L:ca Cy:335444288 ; セーブデータ2のリンク名先頭 ; 「る(0x29)」でHLを倍に FB85:29 ADD HL,HL SP:dffd A:17 B:03 C:02 D:fa E:c9 F:00 H:fd L:ca Cy:335444300 ; 「ば(0x3E)」「ど(0x3D)」でAに3Dをロード FB86:3E 3D LD A,#3Dh SP:dffd A:17 B:03 C:02 D:fa E:c9 F:10 H:fb L:94 Cy:335444308 ; 「が(0x2F)」でCPL、1の補数=全ビット反転 FB88:2F CPL SP:dffd A:3d B:03 C:02 D:fa E:c9 F:10 H:fb L:94 Cy:335444316 ; 「め(0x22)」で0xC2、JP命令(0xC2)をゲームモード直前のFB94/DB94へ書き込み FB89:22 LD (HL+),A SP:dffd A:c2 B:03 C:02 D:fa E:c9 F:70 H:fb L:94 Cy:335444320 ; セーブデータ3リンク名先頭 ; 「ば(0x3E)」「あ(0x01)」で Aレジスタに01をロード FB8A:3E 01 LD A,#01h SP:dffd A:c2 B:03 C:02 D:fa E:c9 F:70 H:fb L:95 Cy:335444328 ; 「め(0x22)」でFB95/DB95ゲームモード一つ目に ; 01(=EDシーケンス中)を書き込みつつHLをインクリメント FB8C:22 LD (HL+),A SP:dffd A:01 B:03 C:02 D:fa E:c9 F:70 H:fb L:95 Cy:335444336 ; 「ぬ(0x17)」でCy付き左ローテート ; 今回はCyが1なのでAレジスタ値が01→03 ローテート自体で01→02、右にCy入って03 FB8D:17 RLA SP:dffd A:01 B:03 C:02 D:fa E:c9 F:70 H:fb L:96 Cy:335444344 ; 「め(0x22)」で破壊されていたDB96/FB96を03で修正。 ; 03はEDシーケンス中で無操作進行する値 FB8E:22 LD (HL+),A SP:dffd A:03 B:03 C:02 D:fa E:c9 F:00 H:fb L:96 Cy:335444348 ; 名前列はここまで FB8F:00 NOP SP:dffd A:03 B:03 C:02 D:fa E:c9 F:00 H:fb L:97 Cy:335444356 FB90:00 NOP SP:dffd A:03 B:03 C:02 D:fa E:c9 F:00 H:fb L:97 Cy:335444360 FB91:00 NOP SP:dffd A:03 B:03 C:02 D:fa E:c9 F:00 H:fb L:97 Cy:335444364 FB92:00 NOP SP:dffd A:03 B:03 C:02 D:fa E:c9 F:00 H:fb L:97 Cy:335444368 FB93:00 NOP SP:dffd A:03 B:03 C:02 D:fa E:c9 F:00 H:fb L:97 Cy:335444372 ; 先に書き込んでおいたFB94/DB94のジャンプ命令を踏んで ; ゲームモードにあたるDB95/FB95とDB96/FB96自体をジャンプ先として利用する ; 0301はメインループ中に相当しており ; 結果ここまでの操作によってエンディングシーケンスへのジャンプが成立する FB94:C2 01 03 JP NZ,#0301h SP:dffd A:03 B:03 C:02 D:fa E:c9 F:00 H:fb L:97 Cy:335444376 ; メインループ中へ戻ってきた! 0301:FA 7C C1 LD A,(#C17Ch) SP:dffd A:03 B:03 C:02 D:fa E:c9 F:00 H:fb L:97 Cy:335444392