基礎知識
戦闘関係
前ページ、マップタイマー概要の続き。
ここではマップタイマーを計算するサブルーチンを紹介する。
前ページの説明を前提とするので、まずは上リンクから、前ページに一通り目を通していただきたい。
マップタイマーが動く場合、まずはマップタイマー開始の処理が入る。
タイマーの残り時間が0になるまで、マップタイマーのカウントダウン用サブルーチンで1フレームにつき1回カウントダウンする。
残り時間が0になったら、マップタイマー終了の処理をする。
という手順になる。
マップタイマー開始だが、何かしらのイベントによりマップタイマーがONになると、$C0/3284~の処理が開始になる。
とりあえずは重要な部分だけ(というよりは筆者にもわかった部分を)紹介する。
$C0/328A REP #$20 ;Mフラグをクリア Aレジスタは16bit幅 $C0/328C LDA $000AC0[$00:0AC0] ;Aに[$00:0AC0]をロード $C0/3290 ORA $30 [$00:0030] ;Aと[$00:0030]で論理和 $C0/3292 STA $000AC0[$00:0AC0] ;Aを[$00:0AC0]に書き込み $C0/3296 LDA $30 [$00:0030] ;Aに[$00:0030]をロード $C0/3298 EOR #$FFFF ;Aと$FFFFで排他的論理和 $C0/329B AND $000AC2[$00:0AC2] ;Aと[$00:0AC2]で論理積 $C0/329F STA $000AC2[$00:0AC2] ;Aを[$00:0AC2]に書き込み $C0/32A3 LDA $8E01,y ;Aに[$7F:CB70]をロード $C0/32A6 STA $00,x ;Aを[$00:0AE0]に書き込み $C0/32A8 SEP #$20 ;MフラグON Aレジスタ8bitモード $C0/32AA LDX $32 [$00:0032] ;Xに[$00:0032]をロード $C0/32AC LDA $8E03,y ;Aに$8E03,yをロード $C0/32AF STA $000AD0,x ;Aを$000AD0,xに書き込み
この部分では、マップタイマーの初期値を読み込んでいる。
2行目の$C0/328Cで[$00:0AC0]の値をAにロードしているが、これは前ページに記した通り、「マップタイマー判定値」である。
16bitモードのため、[$00:0AC0][$00:0AC1]両方とも読み込んでいる。
既に他のタイマーが動いていれば何らかの値が入っているし、他のタイマーが動いていないのなら$0000である。
$C0/3290では[$00:0030]と論理和を取っている。
これより前に、[$00:0030]には「新たに開始するマップタイマーの番号」が入っている。
例えば幕末編の鐘だったら、マップタイマー00なので「$0001」である。
「マップタイマー判定値」と、「新たに開始するマップタイマーの番号」との論理和を取ることで、「マップタイマー判定値」の中の「新たに開始するマップタイマーの番号」部分に1が立つ仕組みである。
ここで「マップタイマー判定値」の更新が行われ、$C0/3292で新たな「マップタイマー判定値」として[$00:0AC0][$00:0AC1]に書き込まれた、ということになる。
続いてもう一度[$00:0030]、つまり「新たに開始するマップタイマーの番号」がAにロードされ、$C0/3298では$FFFFと排他的論理和を取っている。
その後に[$00:0AC2]、前ページに記した「マップタイマー関連フラグ値」との論理積を取っている。
「マップタイマー関連フラグ値」は、0ならタイマーを動かし、1ならタイマーを動かさない、という「マップタイマー判定値」とは真逆の値の判定をする値である。
よって、「新たに開始するマップタイマーの番号」部分は「マップタイマー関連フラグ値」を0にしなければならない。
このためにまず、「新たに開始するマップタイマーの番号」と$FFFFで排他的論理和をとり、該当番号部分を0にする。
例えば幕末編の鐘だったら、排他的論理和を取ると$FFFEである。
この値と「マップタイマー関連フラグ値」との論理積を取って、「マップタイマー関連フラグ値」を更新し、$C0/329Fで新たな「マップタイマー関連フラグ値」として[$00:0AC2][$00:0AC3]に書き込まれた。
$C0/32A3以降だが、
$C0/32A3 LDA $8E01,y ;Aに[$7F:CB70]をロード $C0/32A6 STA $00,x ;Aを[$00:0AE0]に書き込み
「$8E01,y」をAにロードして、「$00,x」に書き込んでいる。
これがマップタイマーの初期残り時間のセットに当たる。
この時点でYに入っている値を$8E01と足したアドレスに、マップタイマーの初期残り時間が入っているのだが、Yに入る値はこれ以前に計算されており、詳細は省く。
例えば幕末編の鐘だとY:3D6Fで、[$7F:CB70]から初期残り時間を読み出す。
西部編の鐘だとY:52CEで、[$7F:E0CF]から初期残り時間を読み出す。
鐘はどちらのシナリオでも1分のタイマーなのに、まったく別のアドレスから値を読み出していることがわかる。
何故なのかというと、マップタイマーの初期残り時間が入っているアドレスを+2したアドレスには、マップタイマー終了時の処理に使う値が入っているのである。
幕末編の鐘と西部編の鐘とでは、残り時間は同一であるが、鐘を鳴らした後の処理は全く異なるため、別のアドレスからの読み出しをしているようである。
$C0/32AA LDX $32 [$00:0032] ;Xに[$00:0032]をロード $C0/32AC LDA $8E03,y ;Aに$8E03,yをロード $C0/32AF STA $000AD0,x ;Aを$000AD0,xに書き込み
$C0/32AAでは、Xに[$00:0032]をロードしているが、これは新たに開始するマップタイマーの番号である。
前ページでは便宜上、マップタイマーに00から15まで番号を振ったが、実はこの時点での[$00:0032]には、マップタイマー番号を16進数にした値が入っている。
つまり幕末編の鐘や西部編の鐘だったら、[$00:0032]には$0000が入っている。
$C0/32ACで「$8E03,y」をAにロードして、「$000AD0,x」に書き込んでいる。
先に述べたが、「マップタイマーの初期残り時間」が入っているアドレスを+2したのが「$8E03,y」で、マップタイマー終了時の処理に使う値になる。
この値が「$000AD0,x」に入る。
直前にXにマップタイマー番号を入れたため、「$000AD0,x」は「$00:0AD?」(?はマップタイマー番号0~F)のことである。
つまり、$00:0AD0~$00:0ADFには、マップタイマー00~15終了時に関する値が入っている、ということである。
以上で、マップタイマーを動かす上で必要な初期値がロードされた。
実際には他にも諸々の処理を挟むようだが、とりあえず筆者が説明できるのはこの程度である。
概要でも説明した通り、マップタイマーのカウントダウン用サブルーチンは以下のふたつの部分に分かれているので、順に説明していく。
$C0/1A69~$C0/1A97:$C0/1A98~$C0/1ADB:まず、$C0/1A69~$C0/1A97だが、以下のようになっている。
$C0/1A69 LDA $0200 [$00:0200] ;Aに[$00:0200]をロード $C0/1A6C BNE $29 [$1A97] ;ゼロフラグが立っていないとき[$1A97]分岐 $C0/1A6E LDX $0AC0 [$00:0AC0] ;Xに[$00:0AC0]をロード $C0/1A71 BEQ $24 [$1A97] ;ゼロフラグが立っているとき[$1A97]分岐 $C0/1A73 REP #$20 ;Mフラグをクリア、Aレジスタを16bit幅 $C0/1A75 LDX #$0AE0 ;Xに$0AE0をロード $C0/1A78 LDA #$0001 ;Aに$0001をロード $C0/1A7B STA $30 [$00:0030] ;Aを[$00:0030]に書き込み ; $C0/1A7D LDA $30 [$00:0030] ;Aに[$00:0030]をロード $C0/1A7F BIT $0AC0 [$00:0AC0] ;Aと[$00:0AC0]で論理積(ステータスフラグのみ変更) $C0/1A82 BEQ $0B [$1A8F] ;ゼロフラグが立っているとき[$1A8F]分岐 $C0/1A84 BIT $0AC2 [$00:0AC2] ;Aと[$00:0AC2]で論理積(ステータスフラグのみ変更) $C0/1A87 BNE $06 [$1A8F] ;ゼロフラグが立っていないとき[$1A8F]分岐 $C0/1A89 LDA $00,x ;Aに[$00,x](マップタイマーXX)をロード $C0/1A8B BEQ $02 [$1A8F] ;ゼロフラグが立っているとき[$1A8F]分岐 $C0/1A8D DEC $00,x ;[$00,x](マップタイマーXX)をデクリメント(-1) $C0/1A8F INX ;Xをインクリメント(+1) $C0/1A90 INX ;Xをインクリメント(+1) $C0/1A91 ASL $30 [$00:0030] ;[$00:0030]を算術左シフト(×2) $C0/1A93 BCC $E8 [$1A7D] ;キャリーフラグが立っていないとき[$1A7D]分岐 ; $C0/1A95 SEP #$20 ;MフラグON。Aは8bit幅 $C0/1A97 60 RTS ;サブルーチン終了
順に見ていく。
最初に行うのは、「マップタイマー00~15までの動作状況を確認」である。
$C0/1A69 LDA $0200 [$00:0200] ;Aに[$00:0200]をロード $C0/1A6C BNE $29 [$1A97] ;ゼロフラグが立っていないとき[$1A97]分岐 $C0/1A6E LDX $0AC0 [$00:0AC0] ;Xに[$00:0AC0]をロード $C0/1A71 BEQ $24 [$1A97] ;ゼロフラグが立っているとき[$1A97]分岐
最初に判定されるのは[$00:0200]に入っている値で、マップタイマーが一時停止しているかどうかの判定になる。
[$00:0200]の値はマップタイマーが止まる、セリフウィンドウ表示中や、プレイヤーが操作できないイベントの最中、戦闘中、マップ切り替えの暗転中などに$01や$02が入り、それ以外では$00が入る(数値の詳細は未確認だが、マップタイマーが一時停止している時は必ず$00なのは確定)。
次の[$00:0AC0]は「マップタイマー判定値」である。
Xにロードしており、この時Xは16bitモードのため、[$00:0AC0][$00:0AC1]両方とも読み込んでいる。
ひとつもマップタイマーが動作していない場合、[$00:0AC0][$00:0AC1]どちらも$00が入る。
この2つのメモリをチェックすることで、マップタイマーが現在動いているかどうかを判定し、動いていないと判定されたら、いずれも[$C0/1A97]へジャンプする。
$C0/1A71から$C0/1A97までは、マップタイマーの処理(タイマーの値を1減らす)に当たるため、[$C0/1A97]へジャンプするということは、マップタイマーイベントが発生していないため該当の処理を飛ばした、ということである。
$C0/1A73 REP #$20 ;Mフラグをクリア、Aレジスタを16bit幅 $C0/1A75 LDX #$0AE0 ;Xに$0AE0をロード $C0/1A78 LDA #$0001 ;Aに$0001をロード $C0/1A7B STA $30 [$00:0030] ;Aを[$00:0030]に書き込み
ここからは、「動作しているマップタイマーのタイマー残り時間を-1する」部分に当たる。
まずAを16bitモードに変更し、Xに$0AE0をロードしている。
「0AE0」は、タイマー残り時間を記録しておくメモリのアドレス[$00:0AE0]~[$00:0AFF]の最初の値である。
ここで、タイマー残り時間を呼び出すための準備として、Xに$0AE0をロードしたのである。
また、$C0/1A78~$C0/1A7Bでは、[$00:0030]に$0001を書き込んでいる。
前ページにも記したが、「マップタイマー判定値」と、マップタイマーに対応した2進数の桁の値で論理積を取ることで、該当のマップタイマーが動作中なら0が、動作していないなら2進数の桁の値が返ってくるようになっている。
[$00:0030]に入るのはその「マップタイマーに対応した2進数の桁の値」の初期値である。
[$00:0030]の値はこの後のサブルーチンで次々変更されていくことになる。
次から、マップタイマー00から15までのそれぞれの動作判定及び、動作していたらタイマー残り時間を-1する処理が入る。
プログラミングにおける、いわゆるループ処理(サブルーチンを一定条件を満たすまで繰り返し行う処理のこと)を使う。
ここではマップタイマー00から順に16回繰り返して、各タイマーをチェックする。
$C0/1A7D LDA $30 [$00:0030] ;Aに[$00:0030]をロード $C0/1A7F BIT $0AC0 [$00:0AC0] ;Aと[$00:0AC0]で論理積(ステータスフラグのみ変更) $C0/1A82 BEQ $0B [$1A8F] ;ゼロフラグが立っているとき[$1A8F]分岐 $C0/1A84 BIT $0AC2 [$00:0AC2] ;Aと[$00:0AC2]で論理積(ステータスフラグのみ変更) $C0/1A87 BNE $06 [$1A8F] ;ゼロフラグが立っていないとき[$1A8F]分岐 $C0/1A89 LDA $00,x ;Aに[$00,x](マップタイマーXX)をロード $C0/1A8B BEQ $02 [$1A8F] ;ゼロフラグが立っているとき[$1A8F]分岐 $C0/1A8D DEC $00,x ;[$00,x](マップタイマーXX)をデクリメント(-1) $C0/1A8F INX ;Xをインクリメント(+1) $C0/1A90 INX ;Xをインクリメント(+1) $C0/1A91 ASL $30 [$00:0030] ;[$00:0030]を算術左シフト(×2) $C0/1A93 BCC $E8 [$1A7D] ;キャリーフラグが立っていないとき[$1A7D]分岐
以上がループ処理部分である。
最後の$C0/1A93で、キャリーフラグが立っていないとき[$1A7D]分岐とあるから、条件を満たすまで一番上の$C0/1A7Dに戻ってループすることがわかる。
具体的に各部を見てみよう。
$C0/1A7D LDA $30 [$00:0030] ;Aに[$00:0030]をロード $C0/1A7F BIT $0AC0 [$00:0AC0] ;Aと[$00:0AC0]で論理積(ステータスフラグのみ変更) $C0/1A82 BEQ $0B [$1A8F] ;ゼロフラグが立っているとき[$1A8F]分岐 $C0/1A84 BIT $0AC2 [$00:0AC2] ;Aと[$00:0AC2]で論理積(ステータスフラグのみ変更) $C0/1A87 BNE $06 [$1A8F] ;ゼロフラグが立っていないとき[$1A8F]分岐
ループ部分の最初の処理。
まず、先程初期値として$0001を入れた[$00:0030]がAに読み込まれている。16bitモードなので4桁である。
ループ1回目なら、必ずAに$0001が入るということである。
次は[$00:0030]($0001)と[$00:0AC0]で論理積を取っているが、16bitモードなので実際には「マップタイマー判定値」の4桁が読み込まれている。
次の判定が「ゼロフラグが立っているとき[$1A8F]分岐」とあり、マップタイマーを-1する処理を飛ばしてしまうことから、ここでは、
「マップタイマー判定値」に格納されている、マップタイマー00に対応した桁の値が%1になっている時は次の判定に進む。
ということである。
他に同時に動いているタイマーがあったとしても、論理積を取ったので、マップタイマー00の数値だけ一致しているかどうかが判定できる。
続いて$C0/1A84では、同じく、「マップタイマー判定値」と[$00:0AC2]との論理積を取っている。
[$00:0AC2]には「マップタイマー関連フラグ値」が入っている。
「マップタイマー関連フラグ値」は、「マップタイマー判定値」と同じくマップタイマー00~15に対応しているが、「マップタイマー判定値」とは逆に、「0」が入っているタイマーは動かし、「1」が入っているタイマーは動かさない、という仕様である。
たとえば幕末編において、本丸2階・天井裏の落とし穴の開閉はマップタイマーを使って制御しており、おぼろ丸が落とし穴前の特定のマスの上に乗ることがタイマー起動条件になるが、この落とし穴はカラクリ源内を倒すと動かなくなるため、「カラクリ源内撃破前か後か」という判定もしなければならない。
そういった、複数の起動条件が絡む時に必要となるのが「マップタイマー関連のフラグ」であり、特にストーリー進行がフラグによって複雑に分岐する幕末編で多用される値である。
$C0/1A87では、ゼロフラグが立っていないとき[$1A8F]分岐となっているので、「マップタイマー関連フラグ値」が0なら分岐せず次の判定に進む。
ループ1回目なら、
「マップタイマー関連フラグ値」に格納されている、マップタイマー00に対応した桁の値が%0になっている時は次の判定に進む。
ということである。
ここでも論理積を取っているため、マップタイマー00の数値だけ一致しているかどうかが判定できる。
ここまでで、判定したいマップタイマーが動作中かどうかを確認できた。
以降は判定したいマップタイマーが動作中の場合の処理になる。
$C0/1A89 LDA $00,x ;Aに[$00,x](マップタイマーXX)をロード $C0/1A8B BEQ $02 [$1A8F] ;ゼロフラグが立っているとき[$1A8F]分岐 $C0/1A8D DEC $00,x ;[$00,x](マップタイマーXX)をデクリメント(-1) $C0/1A8F INX ;Xをインクリメント(+1) $C0/1A90 INX ;Xをインクリメント(+1) $C0/1A91 ASL $30 [$00:0030] ;[$00:0030]を算術左シフト(×2) $C0/1A93 BCC $E8 [$1A7D] ;キャリーフラグが立っていないとき[$1A7D]分岐
$C0/1A75で、Xに$0AE0をロードしているため、ループ1回目だと「LDA $00,x」は「LDA $00:0AE0」である。
前ページで述べた通り、これはマップタイマー01の残り時間の入っているメモリである。
$C0/1A8Bは、タイマー残り時間が0だったら[$1A8F]に飛ぶ、という分岐。タイマーの残り時間が既に0であれば残り時間の処理をする必要がない。
$C0/1A8Dで、ようやくマップタイマーの残り時間を-1する処理を行う。
続いてINXを2回繰り返して、Xを+2する。
マップタイマー残り時間を呼び出すための値を+2したことで、ループ2回目では$00:0AE2から値を読み込むことになる。
最後に、[$00:0030]の値を算術左シフトで2倍する。
[$00:0030]はマップタイマーに対応した2進数の桁の値になる、と述べた通りだが、左シフトすることで、2進数表記した時に全体を1桁左に移動させることになる。
最初に[$00:0030]に入れた値は$0001で、2進数なら%0000 0000 0000 0001。マップタイマー00に対応した位置に「1」が入っている。
これを左シフトすると、%0000 0000 0000 0010。これでマップタイマー01に対応した位置に「1」が移動した。
このように左シフトを繰り返していくと、最終的には15回目のループで%1000 0000 0000 0000まで1が移動し、16回目のループではこれ以上左にシフトできない。
できないのではなく実際には、%1 0000 0000 0000 0000と17桁目に1が移動することになるのだが、スーパーファミコンのプログラムでは、2進数で扱える数値は16桁(16ビット)までなので、桁溢れが生じる。英語で言えばキャリーオーバー、ここでキャリーフラグが立つということである。
$C0/1A93の処理はキャリーフラグが立っていないとき[$1A7D]分岐であるから、キャリーフラグが立ったらループの最初に戻らず、ループ処理を抜ける。
ということで、上のループ処理では、16回ループするとループ処理を抜けることになる。
以上、ループ中に、
「マップタイマーXXが動作中かを確認し、動作中なら処理を続ける」
「マップタイマーXXの残り時間を読み込む」
「残り時間が0でないのなら、残り時間を-1する」
「次のループ用に残り時間が入っているメモリのアドレスを+2する」
「[$00:0030]を算術左シフト」
を行うことで、マップタイマー00から順に01、02、03……と、マップタイマー15まで同じように処理してループを抜ける、ということがわかった。
$C0/1A95 SEP #$20 ;MフラグON。Aは8bit幅 $C0/1A97 RTS ;サブルーチン終了
ループが終わったら、Aを8bitモードに戻してサブルーチン終了である。
以上の処理はあくまでも、動作中の各マップタイマーの残り時間を減らす処理である。
減らした後、タイマーの残り時間が0だったら、タイマー終了時イベントへと移行するはずである。
西部編なら鐘が鳴ってマッドドッグのセリフが入るし(また、8つ目の鐘なら罠仕掛けイベント自体が終了である)、幕末編なら鐘が鳴っておぼろ丸が「かねの音‥‥」と呟くイベントが入る。
この次の$C0/1A98~$C0/1ADBこそが、「各マップタイマーが、タイマー終了時の処理に飛ぶかどうかの判断・処理」に当たる。
実際には、$C0/1A97と$C0/1A98の間に諸々の処理が挟まっているが、ここでは省略して$C0/1A98以降を説明する。
$C0/1A98 LDX $0AC0 [$00:0AC0] ;Xに[$00:0AC0]をロード $C0/1A9B BEQ $3E [$1ADB] ;ゼロフラグが立っているとき[$1ADB]分岐 $C0/1A9D REP #$20 ;Mフラグをクリア、Aレジスタを16bit幅 $C0/1A9F LDX #$0AE0 ;Xに$0AE0をロード $C0/1AA2 LDY #$0AD0 ;Yに$0AD0をロード $C0/1AA5 LDA #$0001 ;Aに$0001をロード $C0/1AA8 STA $30 [$00:0030] ;Aを[$00:0030]に書き込み ; $C0/1AAA LDA $30 [$00:0030] ;Aに[$00:0030]をロード $C0/1AAC BIT $0AC0 [$00:0AC0] ;Aと[$00:0AC0]で論理積(ステータスフラグのみ変更) $C0/1AAF BEQ $21 [$1AD2] ;ゼロフラグが立っているとき[$1AD2]分岐 $C0/1AB1 BIT $0AC2 [$00:0AC2] ;Aと[$00:0AC2]で論理積(ステータスフラグのみ変更) $C0/1AB4 BNE $1C [$1AD2] ;ゼロフラグが立っていないとき[$1AD2]分岐 $C0/1AB6 LDA $00,x [$00:0AE0] ;Aに[$00,x](マップタイマーXX)をロード $C0/1AB8 BNE $18 [$1AD2] ;ゼロフラグが立っていないとき[$1AD2]分岐 ;(カウントダウン終了時処理) $C0/1AD2 INX ;Xをインクリメント(+1) $C0/1AD3 INX ;Xをインクリメント(+1) $C0/1AD4 INY ;Yをインクリメント(+1) $C0/1AD5 ASL $30 [$00:0030] ;[$00:0030]を算術左シフト(×2) $C0/1AD7 BCC $D1 [$1AAA] ;キャリーフラグが立っていないとき[$1AAA]分岐 ; $C0/1AD9 SEP #$20 ;MフラグON。Aは8bit幅 $C0/1ADB RTS ;サブルーチン終了
前の、$C0/1A69~$C0/1A97の処理とよく似ている。
異なるのは、ループ前に「$C0/1AA2 LDY #$0AD0」という処理が入っていて、ループ内にも$C0/1AD4 INYでYを+1する処理が入っていること。
また、$C0/1AB6から、「マップタイマーXXの残り時間の値が0だったら、$C0/1AB8の後に続くカウントダウン終了時処理を実行」という分岐が起こる。
マップタイマー残り時間が0になっていたら、上で「(カウントダウン終了時処理)」と省略した処理をしてから、残りのマップタイマーの処理を続ける。
つまり、複数のマップタイマーが動いていた場合、同時にカウントダウンが終了した場合、カウントダウン終了時処理には優先順位がある、ということである。
といっても、1フレーム毎に上のサブルーチンは実行されているので、通常のプレイでフレーム単位までピッタリ一致してカウントダウンが終了することはまずない気もするが、もしも被った場合は優先順位がある、という話である。
カウントダウン終了時処理を行うか、マップタイマーの残り時間が0でない場合は、Xを+2、Yを+1、[$00:0030]を2倍し、ループを繰り返すか抜けるかをキャリーフラグで判断、という手順になる。
$C0/1AB8の後のカウントダウン終了時処理は以下の通りである。
$C0/1ABA LDA $30 [$00:0030] ;Aに[$00:0030]をロード $C0/1ABC EOR #$FFFF ;Aと$FFFFで排他的論理和 $C0/1ABF AND $0AC0 [$00:0AC0] ;Aと[$00:0AC0]で論理積 $C0/1AC2 STA $0AC0 [$00:0AC0] ;Aを[$00:0AC0]に書き込み $C0/1AC5 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C0/1AC7 LDA #$01 ;Aに$01をロード $C0/1AC9 STA $01B8 [$00:01B8] ;Aを[$00:01B8]に書き込み $C0/1ACC LDA $0000,y ;Aに[$0000,y]をロード $C0/1ACF BRL $00A2 [$1B74] ;フラグにかかわりなく常に[$1B74]分岐 $C0/1B74 STZ $0201 [$00:0201] ;[$00:0201]に0を書き込み $C0/1B77 PHA ;Aをスタックにプッシュ $C0/1B78 JSR $41EA [$C0:41EA] ;[$C0:41EA]にジャンプ
カウントダウンを終了するマップタイマーの番号が[$00:0030]に入っているが、$C0/1ABCでは、その値と$FFFFで排他的論理和を取っている。
更に、$C0/1ABFで、「マップタイマー判定値」である[$00:0AC0]との論理積を取っている。
ここで何をしたのかというと、「マップタイマー判定値」の中でONになっていた(2進数で1が立っていた)カウントダウンを終了するマップタイマーの値を0に変更し、タイマーの動作状態をOFFに変えたのである。
新たな「マップタイマー判定値」の状態が$C0/1AC2で[$00:0AC0]に書き込まれている。
$C0/1ACCで、Aに[$0000,y]をロードをしているが、これはカウントダウン開始時の、
$C0/32AA LDX $32 [$00:0032] ;Xに[$00:0032]をロード $C0/32AC LDA $8E03,y ;Aに$8E03,yをロード $C0/32AF STA $000AD0,x ;Aを$000AD0,xに書き込み
この処理の$C0/32AFで、各マップタイマーに対応した$00:0AD0~$00:0ADFに読み込まれた値である。
この値を$C0/1B77でスタックにプッシュ(入れる)処理をしてから、[$C0:41EA]にジャンプしている。
後に、ジャンプ先[$C0:41EA]以降の処理で、飛び先(アドレス)を読み出すための計算に使われており、カウントダウン終了後のイベントを呼び出すための数値だったことがわかる。
マップタイマーそのものとは関係がないため、とりあえずここまででマップタイマー終了処理完了、ということにする。