TOP > プログラミング関係解説&調査 > 反撃

反撃

当ページの内容は、ある程度のプログラミングの知識を必要とする。
まず、プログラミング関係解説&調査をひととおり読んでいただきたい。

本作には、攻撃を食らった時に自動的に反撃(カウンター)するシステムがある。
攻略では、技(その2)> 技による反撃で仕組みを解説している。
各技には隠し設定として「反撃属性」が設定されており、

  1. 反撃可能な技に設定された反撃属性の技で攻撃され命中する
  2. 反撃技を出せる状態である(マヒや眠りなど、行動不能な状態にない)
  3. 反撃する相手が反撃技の射程・範囲内にいる(敵が複数マスにまたがっている場合は一部でも含まれていれば良い。また、キューブの「ハイスピードオペ」のような回復技はこの条件を必ず満たしている)

以上の条件全てを満たした場合、攻撃を食らった後に自動的に反撃を出す仕組みである。
プログラム上でも、ほぼ上の手順でチェックして反撃を出すようになっている。
また、3.の、反撃技の範囲のチェックは、ダメージフィールド判定の序盤で紹介した、技の範囲確認処理と被る部分が多いため、一部説明が被る。
技の範囲チェックは反撃技に限らず、技を使う場合は共通である。ただ、通常の攻撃技は攻撃するマスに敵がいなくても発動するが(カラマスへの攻撃になる)、反撃技は範囲マスに敵がいない限り発動しない。

具体的な処理を紹介する。

メモリアドレス

反撃関係で重要なメモリアドレスは以下。
今回重要なのは技データの中の反撃関係の値になるが、技データ自体は色々な計算に使うため、様々なアドレスにコピーされる。
今回は反撃関係のコピー先に絞って紹介していく。

技データ13

下4ビットが技の属性の値になる。
属性数値
$0
$1
$2
$3
$4
$5
$6
$7
$8
$9
$A
$B
$C
$D
$E
$F

技データ13の値は、技使用時に[$7E:901D]に書き込まれる。
上4ビットに技のタイプ関係の値が入っているため、そちらの計算でも[$7E:901D]は頻繁に呼び出されることになるが、今回は下4ビットが必要な値になる。

技データ14~技データ15

反撃属性が2バイトに分けて入っている。
技データ14は上から順に手・足・突・鋭・鈍・締・飛・背属性、技データ15は火・水・風・土・精・善・悪が1ビットずつ対応。
技データ15の下1ビットは攻撃力依存の値(あり:%1、なし:%0

技ID&関連ステータス

味方キャラの使用技のデータの一部は、$7E:E900$7E:E9FFにコピーされる。
味方キャラ1であれば$7E:E900$7E:E93Fに入る。
味方キャラは戦闘中、最大で16種類の技を使用できるので、16種の技の中の一部データが以下のアドレスに入る。

技LV技ID技データ08技データ14技データ15
+反撃専用の値
00$7E:E900$7E:E910$7E:E920$7E:E930
01$7E:E901$7E:E911$7E:E921$7E:E931
02$7E:E902$7E:E912$7E:E922$7E:E932
03$7E:E903$7E:E913$7E:E923$7E:E933
04$7E:E904$7E:E914$7E:E924$7E:E934
05$7E:E905$7E:E915$7E:E925$7E:E935
06$7E:E906$7E:E916$7E:E926$7E:E936
07$7E:E907$7E:E917$7E:E927$7E:E937
08$7E:E908$7E:E918$7E:E928$7E:E938
09$7E:E909$7E:E919$7E:E929$7E:E939
10$7E:E90A$7E:E91A$7E:E92A$7E:E93A
11$7E:E90B$7E:E91B$7E:E92B$7E:E93B
12$7E:E90C$7E:E91C$7E:E92C$7E:E93C
13$7E:E90D$7E:E91D$7E:E92D$7E:E93D
14$7E:E90E$7E:E91E$7E:E92E$7E:E93E
16$7E:E90F$7E:E91F$7E:E92F$7E:E93F

技データ08は該当技が出せなくなる状態異常の値。
技データ14~技データ15は上の通り、反撃属性2バイト分で、技データ15の下1ビットだけ攻撃力依存の値になるのだが、上の「技データ15+反撃専用の値」というのは、技データ15の上7ビット+技データ13の上2ビット目に入っている反撃専用か否かの1ビットである。
つまり、技データ15の下1ビット位置に、技データ13の上2ビット目を入れた値になる。
後で$7E:E900~に技データがセットされる処理も紹介する。

サブルーチン

敵が味方に対し反撃する場合と、味方が敵に反撃する場合で、処理が少し変わってくるが、基本的な手順は変わらない。
今回は、味方側が反撃する場合をメインに紹介していく。

技ID&関連ステータス処理

最初に、上で紹介した、$7E:E900$7E:E9FFに技関係の値を入れていく処理を紹介する。
これまでも$7E:E900$7E:E9FFの値からの処理は何度か紹介したことはあるが(以下サブルーチンも、ひとつ前の技を出す機能についてで簡単に紹介している)、このメモリアドレスは反撃判定のための役割が大きいことが後々でわかる。
この処理は戦闘開始時、最大味方4キャラ分行われる。
下は技1種類分の処理なので、1キャラあたり16回ループ処理になる。
処理開始時、Xには味方キャラ番号に対応した1C00, 1C40, 1C80, 1CC0が入っている。

$C1/E94B PHX                     ;Xをスタックにプッシュ
$C1/E94C STX $14    [$00:0314]   ;Xを[$00:0314](1C?0)に書き込み
$C1/E94E LDY $0002,x             ;Yに[$0002,x](1C?0+2)をロード
$C1/E951 LDX $0004,y             ;Xに[$0004,y](シナリオ別キャラデータ開始位置+4)をロード
;シナリオ別キャラデータ開始位置+4は味方キャラデータ開始位置アドレス
$C1/E954 REP #$20                ;Aを16bit幅に変更、Mフラグをクリア
$C1/E956 LDA $000D,y             ;Aに[$000D,y+1][$000D,y]をロード
;[$000D,y+1][$000D,y]はシナリオ別キャラデータ開始位置+$D 習得技2バイト
$C1/E959 STA $10    [$00:0310]   ;Aを[$00:0311][$00:0310](習得技2バイト)に書き込み
$C1/E95B SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/E95D LDY $14    [$00:0314]   ;Yに[$00:0314](1C?0)をロード
$C1/E95F LDA #$10                ;Aに$10をロード
$C1/E961 STA $08    [$00:0308]   ;A($10)を[$00:0308]に書き込み
$C1/E963 STA $09    [$00:0309]   ;A($10)を[$00:0309]に書き込み
$C1/E965 LDA $D50005,x           ;Aに[$D50005,x](キャラデータ05+x/技ID)をロード
$C1/E969 STA $12    [$00:0312]   ;A(キャラデータ05)を[$00:0312]に書き込み
$C1/E96B BNE $06    [$E973]      ;ゼロフラグが立っていないとき[$E973]分岐
$C1/E973 STX $14    [$00:0314]   ;X(シナリオ別キャラデータ開始位置+4)を[$00:0314]に書き込み
$C1/E975 JSR $3D93  [$C1:3D93]   ;[$C1:3D93]へジャンプ
;
;$7E:E9??~へのコピー処理ループここから
;ループ回数は[$00:0308]と[$00:0309]($10=16回)
;($C1:3D93~$C1/3DAFのアドレス計算省略)
$C1/E978 LDA $D50008,x           ;Aに[$D50008,x](技データ08)をロード
$C1/E97C STA $13    [$00:0313]   ;A(技データ08)を[$00:0313]に書き込み
$C1/E97E LDA $D5000D,x           ;Aに[$D5000D,x](技データ13)をロード
$C1/E982 STA $18    [$00:0318]   ;A(技データ13)を[$00:0318]に書き込み
$C1/E984 ROL A                   ;Aをキャリーフラグを含めた9bitで左ローテート
$C1/E985 ROL A                   ;Aをキャリーフラグを含めた9bitで左ローテート
$C1/E986 ROL A                   ;Aをキャリーフラグを含めた9bitで左ローテート
$C1/E987 AND #$01                ;Aと$01で論理積(反撃専用時のみ$01、他は$00)
$C1/E989 STA $17    [$00:0317]   ;Aを[$00:0317]に書き込み
$C1/E98B LDA $D5000F,x           ;Aに[$D5000F,x](技データ15)をロード
$C1/E98F AND #$FE                ;Aと$FEで論理積(技データ15/下1ビットなし)
$C1/E991 ORA $17    [$00:0317]   ;Aと[$00:0317]で論理和
$C1/E993 STA $17    [$00:0317]   ;A(技データ15/下1ビットなし+反撃専用の値)を[$00:0317]に書き込み
$C1/E995 LDA $D5000E,x           ;Aに[$D5000E,x](技データ14)をロード
$C1/E999 STA $16    [$00:0316]   ;A(技データ14)を[$00:0316]に書き込み
$C1/E99B TYX                     ;Yレジスタの値をXレジスタに転送
$C1/E99C LSR $11    [$00:0311]   ;[$00:0311]を論理右シフト (/2)
$C1/E99E ROR $10    [$00:0310]   ;[$00:0310]をキャリーフラグを含めた9bitで右ローテート
$C1/E9A0 BCS $04    [$E9A6]      ;キャリーフラグが立っているとき[$E9A6]分岐
$C1/E9A6 LDA $12    [$00:0312]   ;Aに[$00:0312](キャラデータ05+x/技ID)をロード
$C1/E9A8 STA $7ECD00,x           ;Aを[$7ECD00,x]($7E:E900+x)に書き込み
$C1/E9AC LDA $13    [$00:0313]   ;Aに[$00:0313](技データ08)をロード
$C1/E9AE STA $7ECD10,x           ;Aを[$7E:E910]($7E:E910+x)に書き込み
$C1/E9B2 LDA $16    [$00:0316]   ;Aに[$00:0316](技データ14)をロード
$C1/E9B4 STA $7ECD20,x           ;Aを[$7E:E920]($7E:E920+x)に書き込み
$C1/E9B8 LDA $17    [$00:0317]   ;Aに[$00:0317](技データ15/下1ビットなし+反撃専用の値)をロード
$C1/E9BA STA $7ECD30,x           ;Aを[$7E:E930]($7E:E930+x)に書き込み
$C1/E9BE LDA $18    [$00:0318]   ;Aに[$00:0318](技データ13)をロード
$C1/E9C0 STA $7ECE10,x           ;Aを[$7E:EA10]($7E:EA10+x)に書き込み
$C1/E9C4 LDX $14    [$00:0314]   ;Xに[$00:0314]をロード
$C1/E9C6 INY                     ;Yをインクリメント +1
$C1/E9C7 DEC $09    [$00:0309]   ;[$00:0309]をデクリメント -1
$C1/E9C9 INX                     ;Xをインクリメント +1
$C1/E9CA DEC $08    [$00:0308]   ;[$00:0308]をデクリメント -1
$C1/E9CC BNE $97    [$E965]      ;ゼロフラグが立っていないとき[$E965]分岐

;$C1/E9CCでゼロフラグON
$C1/E9CE LDA $09    [$00:0309]   ;Aに[$00:0309]をロード
$C1/E9D0 BNE $02    [$E9D4]      ;ゼロフラグが立っていないとき[$E9D4]分岐
$C1/E9D2 BRA $18    [$E9EC]      ;フラグにかかわりなく常に分岐[$E9EC]
$C1/E9D4 TYX                     ;Yレジスタの値をXレジスタに転送
;未習得技分は00で埋めるループ処理
$C1/E9D5 LDA #$00                ;Aに$00をロード
$C1/E9D7 STA $7ECD00,x           ;A($00)を[$7ECD00,x]に書き込み
$C1/E9DB STA $7ECD10,x           ;A($00)を[$7ECD10,x]に書き込み
$C1/E9DF STA $7ECD20,x           ;A($00)を[$7ECD20,x]に書き込み
$C1/E9E3 STA $7ECD30,x           ;A($00)を[$7ECD30,x]に書き込み
$C1/E9E7 INX                     ;Xをインクリメント +1
$C1/E9E8 DEC $09    [$00:0309]   ;[$00:0309]をデクリメント -1
$C1/E9EA BNE $E9    [$E9D5]      ;ゼロフラグが立っていないとき[$E9D5]分岐
;未習得技分は00で埋めるループ処理ここまで
$C1/E9EC PLX                     ;Xレジスタにスタックからプル
$C1/E9ED LDY $0002,x             ;Yに[$0002,x]をロード
$C1/E9F0 LDA $000C,y             ;Aに[$000C,y](ひとつ前の技)をロード
$C1/E9F3 BNE $07    [$E9FC]      ;ゼロフラグが立っていないとき[$E9FC]分岐
$C1/E9F5 LDA $7ECD00,x           ;Aに[$7ECD00,x](技LV00の技ID)をロード
$C1/E9F9 STA $000C,y             ;Aを[$000C,y](ひとつ前の技)に書き込み
$C1/E9FC RTS                     ;サブルーチン戻り

;$C1/E9CCでゼロフラグOFF
$C1/E965 LDA $D50005,x           ;Aに[$D50005,x](キャラデータ05+x/技ID)をロード
$C1/E969 STA $12    [$00:0312]   ;Aを[$00:0312]に書き込み
$C1/E96B BNE $06    [$E973]      ;ゼロフラグが立っていないとき[$E973]分岐
$C1/E973 STX $14    [$00:0314]   ;Xを[$00:0314]に書き込み
$C1/E975 JSR $3D93  [$C1:3D93]   ;[$C1:3D93]へジャンプ
;ループここまで

シナリオ別キャラデータの習得技2バイトのデータは、1ビット毎に技が習得済みかどうかが格納されている。
習得済みの技に1、未修得技に0が入っていて、習得技2バイトのデータを右ローテートしつつ($C1/E99Eの処理)、習得している場合だけ$7E:E900$7E:E9FFに該当の技データを入れていくことになる。
全ループ終了時に$C1/E9CCででゼロフラグが立ち、$C1/E9CE$C1/E9FCの処理をしてループを抜けるが、ここでは、未修得の技の$7E:E9??~には$00を書き込み、更に、シナリオ別キャラデータの「ひとつ前の技」の値が$00の時(技IDが$00、つまり何の技も入っていない)、技LV00の技IDを書き込む処理をして、$C1/E9FCでサブルーチンを抜ける。

$7E:E900~に格納するデータの処理、$C1/E978~のループ処理を追いかけていくと、以下のようになっている。
ややこしいので、以下は味方キャラ番号1でのアドレスとする。
xがループ回数0~15にあたる。

  1. 味方キャラデータ05~20(技LV00~16に対応した技ID)→[$00:0312]$7E:E900+x
  2. 技データ08→[$00:0313]$7E:E910+x
  3. 技データ14→[$00:0316]$7E:E920+x
  4. 技データ13→[$00:0318]$7E:EA10+x
  5. 技データ13の上2ビット目 & $01[$00:0317]
  6. 技データ15 & $FE + [$00:0317]$7E:E930+x

$7E:E930+xの計算が少しややこしいが、結局は技データ15の上7ビットと、技データ13の上2ビット目を下1ビットに入れた値になる。
味方キャラ1の最初の技(技LV00)だったら以下のようになる。

アドレス内容
$7E:E900技ID
$7E:E910技データ08(該当技が出せなくなる状態異常の値)
$7E:E920技データ14(反撃属性:手・足・突・鋭・鈍・締・飛・背)
$7E:E930技データ15(反撃属性:火・水・風・土・精・善・悪)+反撃専用の値

$7E:E900から順にアドレスを+$10しながら、直前に食らった技の属性と照らし合わせてチェックしていくことで、反撃するかどうか、判定していけることになる。

以上は戦闘開始直後の処理。
ここからは、敵の攻撃→味方に命中→反撃を出す、という処理の中で重要な部分を紹介していく。

技データのコピー

技を使用している最中は、$7E:9010$7E:9028に該当技の技データ00~34がそのままコピーされて入る。
今回で言えば、敵の攻撃の最中は敵の技データが入るが、敵が技を出した後は、反撃を出すかどうか判定をした後、反撃を出す場合は反撃技の技データで上書きされることになる。

$7E:9010$7E:9028に技データをコピーするサブルーチンは以下の通り。

$C1/7852 STX $68    [$00:0368]  ;Xを[$00:0368]に書き込み
$C1/7854 PHB                    ;DBレジスタをスタックにプッシュ
$C1/7855 LDA #$7E               ;Aに$7Eをロード
$C1/7857 PHA                    ;Aをスタックにプッシュ
$C1/7858 PLB                    ;DBレジスタに値をプル
$C1/7859 LDY #$9010             ;Yに$9010をロード
;
;技データ00~34をコピーするループ処理
$C1/785C LDA $D50000,x           ;Aに[$D50000,x]をロード
$C1/7860 STA $0000,y             ;Aを[$7E:9010+n]に書き込み
$C1/7863 INX                     ;Xをインクリメント +1
$C1/7864 INY                     ;Yをインクリメント +1
$C1/7865 CPY #$9029              ;Yと$9029を減算比較(ステータスレジスタのみ変更)
$C1/7868 BNE $F2    [$785C]      ;ゼロフラグが立っていないとき[$785C]分岐
;ループここまで
;
$C1/786A PLB                     ;DBレジスタに値をプル
$C1/786B RTS                     ;サブルーチン戻り

ループ前に、A$7Eを、Y$9010をロードするため、ループ処理内で$C1/7860でロードされる[$0000,y]は、ループ1回目が[$7E:9010]固定、$C1/7864Yを加算しているため、$7E:9010から書き込み先アドレスが+1されていき、$C1/7865Y$9029を減算比較してゼロフラグが立たないならループから抜けているから、$7E:9028まで書き込んだ時点でループを抜けることになる。
つまりこのループ処理では、書き込み先アドレスは固定であり、$7E:9010$7E:9028に技データをコピーする専用のサブルーチンである。
$C1/785Cで読み込む技データのアドレス[$D50000,x]は、このサブルーチンに入る前の$C1/3D5C$C1/3DAFでアドレス計算をしているが省略。

ここで重要なのが、技データ13が入るアドレス$7E:901Dである。
技データ13は、下4ビットに技の属性の値が入る。
攻撃を食らった味方キャラが、技データ13の技の属性と一致する反撃属性の技を所持している場合、反撃を行うフラグがひとつ立つことになる。

反撃属性チェック

では、実際に$7E:901Dの値から、攻撃を食らったキャラの技の反撃属性をチェックしていく処理を見ていく。

$C1/A312 LDX $86    [$00:0386]   ;Xに[$00:0386]をロード
$C1/A314 BEQ $03    [$A319]      ;ゼロフラグが立っているとき[$A319]分岐
$C1/A319 BRL $FE10  [$A12C]      ;フラグにかかわりなく常に分岐[$A12C]
$C1/A12C LDX #$1C00              ;Xに$1C00をロード
$C1/A12F LDA $003B,x[$00:1C3B]   ;Aに[$00:1C3B](味方キャラ1 ヒット数)をロード
$C1/A132 STA $7ECE20,x[$7E:EA20] ;Aを[$7E:EA20]に書き込み
$C1/A136 LDX #$1C40              ;Xに$1C40をロード
$C1/A139 LDA $003B,x[$00:1C7B]   ;Aに[$00:1C7B](味方キャラ2 ヒット数)をロード
$C1/A13C STA $7ECE20,x[$7E:EA60] ;Aを[$7E:EA60]に書き込み
$C1/A140 LDX #$1C80              ;Xに$1C80をロード
$C1/A143 LDA $003B,x[$00:1CBB]   ;Aに[$00:1CBB](味方キャラ3 ヒット数)をロード
$C1/A146 STA $7ECE20,x[$7E:EAA0] ;Aを[$7E:EAA0]に書き込み
$C1/A14A LDX #$1CC0              ;Xに$1CC0をロード
$C1/A14D LDA $003B,x[$00:1CFB]   ;Aに[$00:1CFB](味方キャラ4 ヒット数)をロード
$C1/A150 STA $7ECE20,x[$7E:EAE0] ;Aを[$7E:EAE0]に書き込み
$C1/A154 LDX $78    [$00:0378]   ;Xに[$00:0378]をロード
$C1/A156 STX $A8    [$00:03A8]   ;Xを[$00:03A8]に書き込み
$C1/A158 LDA $7E901D[$7E:901D]   ;Aに[$7E:901D](敵の技データ13)をロード
$C1/A15C BMI $1D    [$A17B]      ;ネガティブフラグが立っているとき[$A17B]分岐
$C1/A15E INC A                   ;Aをインクリメント +1
$C1/A15F AND #$0F                ;Aと$0Fで論理積
$C1/A161 BEQ $18    [$A17B]      ;ゼロフラグが立っているとき[$A17B]分岐

$C1/A12F$C1/A150は、味方キャラ全員の被ダメージ時のヒット数を[$7E:EA?0]にコピーする処理である。
つまり敵の攻撃を食らったキャラは$01以上の値がコピーされ、攻撃を食らっていないキャラだと$00がコピーされる。
なお、上の処理は、実際には敵が何か技を出すと必ず実行されるので、敵が回復技を使った場合でもロード&書き込みが行われるが、敵が回復技を使った時は、味方側へのヒット数は全キャラ0ヒットになるため、$00がコピーされることになる。

その後の$C1/A158で、[$7E:901D]、つまり直前に敵が出した技の技データ13がロードされる。
技データ13の上4ビットは技のタイプ関係の値が入るが、回復技の時は一番上の1ビットに%1が入る。
つまり、回復技だと技データ13は$80以上の値であり、ロード時にネガティブフラグが立つ。
敵が回復技を使ったということは、味方は攻撃されていないから、反撃処理の必要はない。ネガティブフラグが立つと[$A17B]分岐で反撃処理を抜ける。
$C1/A15E~では技データ13をインクリメント(+1)してから、$0Fと論理積を取っているから、技データ13の下4ビットの値を+1した状態で取り出したことになる。
その値が0の時、つまりゼロフラグが立つ場合は反撃処理が行われない([$A17B]分岐)。
なぜ+1した値でゼロフラグ判定をしたのだろうか?

改めて、技データ13の下4ビットの値を、対応属性と見比べてみる。
表の一番右に、+1した値も載せた。

属性数値数値+1
$0$1
$1$2
$2$3
$3$4
$4$5
$5$6
$6$7
$7$8
$8$9
$9$A
$A$B
$B$C
$C$D
$D$E
$E$F
$F$10

+1することで、手属性に対応した値は$0から$1になる一方、無属性だと$Fから$10になる。
よって、ゼロフラグが立つのは無属性のみである。
本作では、無属性技に対し、反撃が行われない。
つまり、「敵が出した技が無属性なら、反撃処理を行わない」という分岐のため、技データ13の下4ビットの値に+1してゼロフラグ判定を行ったのである。

ここまでで、敵が出した技が回復技または無属性であったら反撃処理を行わない、という分岐を経ていることがわかった。
また、Aには技データ13の下4ビット+1が入った状態である。つまり、$01$0Fのいずれかが入っている。
続きを見てみる。

$C1/A163 STA $08    [$00:0308]   ;Aを[$00:0308]に書き込み
$C1/A165 STZ $09    [$00:0309]   ;[$00:0309]に$00を書き込み
$C1/A167 REP #$20                ;Aを16bit幅に変更、Mフラグをクリア
$C1/A169 LDA #$0000              ;Aに$0000をロード
$C1/A16C SEC                     ;キャリーフラグON
;
;技データ13の下4ビット+1の回数分ループ処理
$C1/A16D ROR A                   ;Aをキャリーフラグを含めた17bitで右ローテート
$C1/A16E DEC $08    [$00:0308]   ;[$00:0308]をデクリメント -1
$C1/A170 BNE $FB    [$A16D]      ;ゼロフラグが立っていないとき[$A16D]分岐
;ループここまで
;
$C1/A172 XBA                     ;Aレジスタの上位バイトと下位バイトを交換
$C1/A173 STA $86    [$00:0386]   ;Aを[$00:0387][$00:0386]に書き込み
$C1/A175 SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/A177 LDA #$00                ;Aに$00をロード
$C1/A179 BRA $49    [$A1C4]      ;フラグにかかわりなく常に分岐[$A1C4]

技データ13の下4ビット+1[$00:0308]に書き込んだ状態で、$C1/A16D$C1/A170のループ処理を行う。
ループ処理は、キャリーフラグONで$0000を右ローテートするから、16bitモードでの「%1 0000 0000 0000 0000」の右ローテートである。
1回右ローテートする度に[$00:0308]をデクリメント(-1)し、ゼロフラグが立つまで、つまり[$00:0308]0になるまで「%1 0000 0000 0000 0000」を右ローテートする、というループである。
これで何が起こるのか。
例えば敵が使った技が火属性だったとする。この場合、[$00:0308]の初期値は$09だから、9回ループすることになる。

%1 0000 0000 0000 0000%0 0000 0000 1000 0000

と、キャリーフラグの部分にあった%1が右に8回移動する。
16進数にすると$0080である。
ここで、上2桁と下2桁を入れ替えると、$8000になる。
下2桁が技データ14の反撃属性(手・足・突・鋭・鈍・締・飛・背)、上2桁が技データ15の反撃属性(火・水・風・土・精・善・悪)にちょうど対応する値になるのだ。
ループ後の$C1/A172におけるXBAの上位バイトと下位バイトの交換は、「使用技の属性にだけ1が立った2バイトの値を、技データ14~15の反撃属性に合わせる」ための入れ替えである。
そして入れ替えた値は[$00:0387][$00:0386]に書き込まれた。

習得技で反撃可能かチェック

以下の処理は便宜上味方キャラ1とする。

$C1/A1C4 STA $8D    [$00:038D]   ;Aを[$00:038D]に書き込み
$C1/A1C6 STA $10    [$00:0310]   ;Aを[$00:0310]に書き込み
$C1/A1C8 LDA #$1C                ;Aに$1Cをロード
$C1/A1CA STA $11    [$00:0311]   ;A($1C)を[$00:0311]に書き込み
$C1/A1CC LDX $5A    [$00:035A]   ;Xに[$00:035A]をロード
$C1/A1CE PHX                     ;Xをスタックにプッシュ
$C1/A1CF LDX $10    [$00:0310]   ;Xに[$00:0310]をロード
$C1/A1D1 STX $5A    [$00:035A]   ;Xを[$00:035A]に書き込み
$C1/A1D3 LDA $0001,x[$00:1C01]   ;Aに[$00:1C01](味方キャラ1の戦闘状態)をロード
$C1/A1D6 BIT #$40                ;Aと$40で論理積(ステータスフラグ変更のみ)
;戦闘状態$40:敵操作状態
$C1/A1D8 BEQ $22    [$A1FC]      ;ゼロフラグが立っているとき[$A1FC]分岐
$C1/A1DA LDA $7ECE20,x[$7E:EA20] ;Aに[$7E:EA20](被ダメージのヒット数)をロード
$C1/A1DE BEQ $1C    [$A1FC]      ;ゼロフラグが立っているとき[$A1FC]分岐
;1ヒット以上の時、反撃判定に続く

$C1/A1D3の戦闘状態のチェックは、戦闘状態が$40なら以降の処理をスキップ([$A1FC]分岐)だが、戦闘状態$40は敵操作状態(味方キャラとの戦闘)にあたるため、味方側の処理はスキップになる。
$C1/A1DA[$7E:EA20]は、少し前に味方キャラ1の被ダメージのヒット数が書き込まれたアドレスである。
つまり、敵からの攻撃を食らったかどうかの判定である。
1ヒット以上食らっている場合は反撃の条件を満たすため次の処理に続くが、敵から攻撃を食らっていない、つまりゼロフラグが立つなら以降の反撃処理はスキップになる。

;習得技で反撃できるか確認ループ処理
$C1/A1E0 LDA $7ECD00,x           ;Aに[$7E:E900+n]をロード
$C1/A1E4 BEQ $10    [$A1F6]      ;ゼロフラグが立っているとき[$A1F6]分岐
$C1/A1E6 LDA $7ECD20,x           ;Aに[$7E:E920+n]をロード
$C1/A1EA AND $86    [$00:0386]   ;Aと[$00:0386]で論理積
$C1/A1EC BNE $14    [$A202]      ;ゼロフラグが立っていないとき[$A202]分岐
$C1/A1EE LDA $7ECD30,x           ;Aに[$7E:E930+n]をロード
$C1/A1F2 AND $87    [$00:0387]   ;Aと[$00:0387]で論理積
$C1/A1F4 BNE $0C    [$A202]      ;ゼロフラグが立っていないとき[$A202]分岐
$C1/A1F6 INX                     ;Xをインクリメント +1
$C1/A1F7 TXA                     ;Xレジスタの値をAレジスタに転送
$C1/A1F8 AND #$0F                ;Aと$0Fで論理積
$C1/A1FA BNE $E4    [$A1E0]      ;ゼロフラグが立っていないとき[$A1E0]分岐
;ループ処理ここまで
;
$C1/A1FC PLX                     ;Xレジスタにスタックからプル
$C1/A1FD STX $5A    [$00:035A]   ;Xを[$00:035A]に書き込み
$C1/A1FF BRL $FFBB  [$A1BD]      ;フラグにかかわりなく常に分岐[$A1BD]
$C1/A1BD LDA $8D    [$00:038D]   ;Aに[$00:038D]をロード
$C1/A1BF CLC                     ;キャリーフラグクリア
$C1/A1C0 ADC #$40                ;A + $40
$C1/A1C2 BEQ $B7    [$A17B]      ;ゼロフラグが立っているとき[$A17B]分岐
$C1/A1C4 STA $8D    [$00:038D]   ;Aを[$00:038D]に書き込み
;(味方キャラ2の処理へ)

敵から攻撃された味方キャラの$7E:E9?0をチェックしていく。
味方キャラ1の技LV00だったら以下のようになっているから、

アドレス内容
$7E:E900技ID
$7E:E910技データ08(該当技が出せなくなる状態異常の値)
$7E:E920技データ14(反撃属性:手・足・突・鋭・鈍・締・飛・背)
$7E:E930技データ15(反撃属性:火・水・風・土・精・善・悪)+反撃専用の値

$C1/A1E0[$7E:E900]のゼロフラグ確認は、技IDが$00ではないか、つまり習得済みの何かの技IDが入っているかどうかの確認になる。
$C1/A1E6~で、[$7E:E930][$7E:E920]、つまり技データ15・14の反撃属性と[$00:0387][$00:0386]に書き込んだ敵の技の属性が一致するかどうか、論理積で確認している。
何かの属性が一致すれば、$C1/A1EC$C1/A1F4[$A202]にジャンプするから、$C1/A202以降の処理が、「敵が使ってきた技の属性と、味方が所持している何かの技の反撃属性が一致」ということがわかる。

上のループ処理は、$C1/A1F6$C1/A1FAの処理から、最大16回、つまり味方キャラの技の所持数だけ繰り返す。
途中で反撃属性が一致すれば反撃判定を続けるためループを抜けるし、反撃属性が一致しないのならループを16回した後[$A1E0]に抜け、味方キャラ1は反撃しないことになり、味方キャラ2の判定へ移る。これを味方キャラ全員分繰り返すことになるので、もし範囲攻撃などで複数の味方キャラが攻撃された場合、状況によっては複数の味方キャラが反撃を行うことになる。

以上からわかるが、同じ反撃属性を持つ技を2種類以上習得済みという場合、判定は習得レベルが低い順から行う都合で、習得レベルが低い方の技が反撃で出ることになる。
例えば高原なら、全ての技を覚えている状態だと、反撃属性が足属性の技が「C.H.ホールド」「パンチャマキック」「鬼不動返し」の3種類もある。どの技も正面3方向に出せるため、敵が高原の正面3マス位置から足属性技を当ててきた時、反撃として出せる技の候補が「C.H.ホールド」「パンチャマキック」「鬼不動返し」の3種類ということになる。
習得レベルは、「C.H.ホールド」が6、「パンチャマキック」が7、「鬼不動返し」が12だから、一番低いレベルで習得する「C.H.ホールド」が最優先ということになる。
ただし、「パンチャマキック」の反撃属性は手・足の2種、「鬼不動返し」の反撃属性は足・突の2種なので、反撃で出す機会がまったくないということではない。とはいえ「アームロック」の反撃属性の手・突・鋭・鈍・飛・背とも被り、「アームロック」の習得レベルが5と低めなので、全ての技を習得すると「アームロック」が最優先となってしまうのだが。

話を戻して、「敵が使ってきた技の属性と、味方が所持している何かの技の反撃属性が一致」時の$C1/A202~の処理を見てみる。

;[$A202]分岐
$C1/A202 STX $0B    [$00:030B]   ;Xを[$00:030B]に書き込み
$C1/A204 LDA $7ECD00,x           ;Aに[$7E:E900+n](技ID)をロード
$C1/A208 STA $6A    [$00:036A]   ;Aを[$00:036A]に書き込み
$C1/A20A LDA $7ECD10,x           ;Aに[$7E:E910+n](技データ08)をロード
$C1/A20E LDX $5A                 ;Xに[$00:035A]をロード
$C1/A210 AND $0039,x[$00:1C39]   ;Aと[$00:1C39](味方キャラ1状態異常)で論理積
$C1/A213 BEQ $04    [$A219]      ;ゼロフラグが立っているとき[$A219]分岐
;ゼロフラグOFF
$C1/A215 LDX $0B    [$00:030B]   ;Xに[$00:030B]をロード
$C1/A217 BRA $DD    [$A1F6]      ;フラグにかかわりなく常に分岐[$A1F6]
;ゼロフラグON
$C1/A219 LDA $6A    [$00:036A]   ;Aに[$00:036A]をロード
$C1/A21B JSR $3D7A  [$C1:3D7A]   ;[$C1:3D7A]へジャンプ

技IDを[$00:036A]に書き込んだ後、技データ08(該当技が出せなくなる状態異常の値)と、[$00:1C39](味方キャラ1の現在の状態異常)とで論理積を取っている。
該当の状態異常が一致した時はゼロフラグが立たない、つまり、「味方キャラ1は該当技が出せなくなる状態異常にかかっている」ということになる。
この場合は反撃技は出ないから、$C1/A1F6、つまりループに戻る。
状態異常判定にひっかからない場合、ゼロフラグが立つ場合は$C1/A219に進み、Aに技IDを読み込んだ状態で[$C1:3D7A]へジャンプする。

飛び先では、敵が反撃を出せる範囲にいるかどうかの判定を行う。
$C1/3D7A$C1/3DAF$C1/A21E$C1/A224と処理が進むが、これらはアドレス計算なので省略。
その次は$C1/3D2Bにジャンプするのだが、$C1/3D2B$C1/3D38の処理は、ダメージフィールドの解説でも紹介した、フィールド関係の値を計算するための領域$00:0488$00:04BEを、事前準備としてすべて$00で埋めるサブルーチンである。
$C1/3D38の後の処理から紹介する。

$C1/A227 JSR $723A  [$C1:723A]   ;[$C1:723A]へジャンプ
;
$C1/723A LDX $68    [$00:0368]   ;Xに[$00:0368]をロード
$C1/723C LDA $D5000D,x           ;Aに[$D5000D,x](反撃技の技データ13)をロード
$C1/7240 BIT #$20                ;Aと$20で論理積(ステータスフラグ変更のみ)
$C1/7242 BEQ $24    [$7268]      ;ゼロフラグが立っているとき[$7268]分岐
;ゼロフラグOFF(周囲攻撃)
$C1/7244 LDX $5A    [$00:035A]   ;Xに[$00:035A]をロード
$C1/7246 LDA $0028,x             ;Aに[0028,x]をロード
$C1/7249 PHA                     ;Aをスタックにプッシュ
$C1/724A LDA $0029,x             ;Aに[$0029,x]をロード
$C1/724D PHA                     ;Aをスタックにプッシュ
$C1/724E LDA $0018,x             ;Aに[$0018,x]をロード
$C1/7251 STA $0028,x             ;Aを[$0028,x]に書き込み
$C1/7254 LDA $0019,x             ;Aに[$0019,x]をロード
$C1/7257 STA $0029,x             ;Aを[$0029,x]に書き込み
$C1/725A JSR $380E  [$C1:380E]   ;[$C1:380E]へジャンプ
;ゼロフラグON(周囲攻撃以外)
$C1/7268 JSR $3B32  [$C1:3B32]   ;[$C1:3B32]へジャンプ

ここで、反撃で出す技の技データ13と$20で論理積を取り、ゼロフラグ判定をしている。
技データ13の上4ビットは技のタイプ関係の値の合計値が入る。

上4ビット内容
$0%0000通常
$2%0010範囲が周囲
$4%0100反撃専用
$8%1000回復

$20と論理積を取ってゼロフラグが立つのは、反撃技が周囲攻撃ではない場合ということになる。
反撃技が周囲攻撃なのは「スピンドル」「老狐の舞」などいくつかある。
分岐を追っていくとゼロフラグOFF(周囲攻撃)は[$C1:380E]へ、それ以外は[$C1:3B32]へジャンプである。
周囲攻撃の飛び先$C1/380Eは、ダメージフィールドで紹介した、「忍法火炎ぼたる」(周囲5×5マス攻撃)の攻撃範囲計算処理であるから、ここでは紹介を省くが、最終的には、マス目計算値が入る$00:0488$00:04BEの攻撃範囲のアドレスのみに、「$0F」を書き込む。

周囲攻撃以外の飛び先[$C1:3B32]以降について説明を続ける。

$C1/3B32 LDX $68    [$00:0368]   ;Xに[$00:0368]をロード
$C1/3B34 LDA $D50006,x           ;Aに[$D50006,x](技データ06)をロード
$C1/3B38 STA $12    [$00:0312]   ;A(技データ06)を[$00:0312]に書き込み
$C1/3B3A LDA $D50007,x           ;Aに[$D50007,x](技データ07)をロード
$C1/3B3E STA $13    [$00:0313]   ;A(技データ07)を[$00:0313]に書き込み
$C1/3B40 LDY $5A    [$00:035A]   ;Yに[$00:035A]をロード
$C1/3B42 LDA $0019,y[$00:1C59]   ;Aに[$00:1C19](味方キャラ1のY座標)をロード
$C1/3B45 ASL A                   ;Aを算術左シフト *2
$C1/3B46 ASL A                   ;Aを算術左シフト *2
$C1/3B47 ASL A                   ;Aを算術左シフト *2
$C1/3B48 ADC $0018,y[$00:1C58]   ;A + [$00:1C18](味方キャラのX座標)
$C1/3B4B REP #$21                ;Aを16bit幅に変更、キャリーフラグクリア
$C1/3B4D AND #$00FF              ;Aと$00FFで論理積
$C1/3B50 STA $10    [$00:0310]   ;Aを[$00:0311][$00:0310]に書き込み

各種データをロードしているので整理していく。

技データ06

コピー先は[$00:0312]
技の方向。
キャラが右下向きの時、上4ビットは下図の青数字、下4ビットは赤数字の合計値で表す。

124

421
技データ07

コピー先は[$00:0313]

上1~2ビット:自身依存係数

数値自身依存係数
%001
%011/2
%101/4
%11なし

上3~4ビット:自身依存ステータス

数値自身依存ステータス
%00
%01
%10
%11

下4ビット:射程

数値
(16進数)
数値
(2進数)
射程
$0%0000なし
$1%00011
$2%00102
$3%00111~2
$4%01003
$5%0101-
$6%01102~3
$7%01111~3
$8%10003~
$9%1001-
$A%1010-
$B%1011-
$C%11002~
$D%1101-
$E%11101~
$F%1111無限

4ビットの値をそれぞれマス目として見た時に、一番右に技を出すキャラが居るとした時に、左方向に向けて1が入ったマスに技が出せると見なせば良い。
一番左のビットは、その位置から無限に技の射程がある。
たとえば%0010なら

[0][0][1][0]キャラ

と見て、キャラから2マス目の位置のみに技が出せる。
%1100なら、

[1][1][0][0]キャラ

なので、キャラの3マス目の位置以降は距離無限で技が出せる。

座標

反撃技を使うキャラの座標は、味方キャラ1であれば、以下のように入っている。
2人目以降のアドレスは+$40

  • [$00:1C18]:キャラ位置のマス目のX座標(左から$00$06
  • [$00:1C19]:キャラ位置のマス目のY座標(上から$00$06

マス目と座標の対応は以下のようになっている。

(0,0)(1,0)(2,0)(3,0)(4,0)(5,0)(6,0)
(0,1)(1,1)(2,1)(3,1)(4,1)(5,1)(6,1)
(0,2)(1,2)(2,2)(3,2)(4,2)(5,2)(6,2)
(0,3)(1,3)(2,3)(3,3)(4,3)(5,3)(6,3)
(0,4)(1,4)(2,4)(3,4)(4,4)(5,4)(6,4)
(0,5)(1,5)(2,5)(3,5)(4,5)(5,5)(6,5)
(0,6)(1,6)(2,6)(3,6)(4,6)(5,6)(6,6)

$C1/3B42$C1/3B50の処理を見ると、[$00:1C19]*8+[$00:1C18] & $00FFの結果を[$00:0311][$00:0310]に書き込んでいる。
2進数に直してみるとわかるが、座標は$00$06だから、3ビットで表現できる。
Y座標の値を×8すると、2進数で3桁左にずれ、更にX座標を加算しているから、「上から3~5ビットにY座標の値、6~8ビットにX座標の値」という1バイトの値が[$00:0310]に書き込まれたことがわかる。[$00:0311]$00が入る。

アドレス
[$00:0310]キャラ座標:上から3~5ビットにY座標の値、6~8ビットにX座標の値
[$00:0311]$00
[$00:0312]技データ06
[$00:0313]技データ07
$C1/3B52 SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/3B54 LDA $D5000D,x           ;Aに[$D5000D,x](技データ13)をロード
$C1/3B58 BIT #$20                ;Aと$20で論理積(ステータスフラグ変更のみ)
$C1/3B5A BNE $25    [$3B81]      ;ゼロフラグが立っていないとき[$3B81]分岐
$C1/3B5C LDA $D50007,x           ;Aに[$D50007,x](技データ07)をロード
$C1/3B60 BIT #$0F                ;Aと$0Fで論理積(ステータスフラグ変更のみ)
$C1/3B62 BEQ $15    [$3B79]      ;ゼロフラグが立っているとき[$3B79]分岐
$C1/3B64 JSR $3B8E  [$C1:3B8E]   ;[$C1:3B8E]へジャンプ
;$C1/3B62 ゼロフラグON
$C1/3B79 LDX $10    [$00:0310]   ;Xに[$00:0311][$00:0310]をロード
$C1/3B7B LDA #$F0                ;Aに$F0をロード
$C1/3B7D STA $0488,x[$00:2FF7]   ;Aを[$00:2FF7]に書き込み
$C1/3B80 RTS                     ;サブルーチン戻り

;$C1/3B62 ゼロフラグOFF→$C1:3B8E
$C1/3B8E LDX $68    [$00:0368]   ;Xに[$00:0368]をロード
$C1/3B90 LDA $D5000D,x           ;Aに[$D5000D,x](技データ13)をロード
$C1/3B94 BIT #$80                ;Aと$80で論理積(ステータスフラグ変更のみ)
$C1/3B96 BEQ $18    [$3BB0]      ;ゼロフラグが立っているとき[$3BB0]分岐
;ゼロフラグOFF
$C1/3B98 LDX $10    [$00:0310]   ;Xに[$00:0310]をロード
$C1/3B9A CPY #$1C00              ;Yと$1C00を減算比較(ステータスレジスタのみ変更)
$C1/3B9D BCS $03    [$3BA2]      ;キャリーフラグが立っているとき[$3BA2]分岐
$C1/3B9F JSR $3AB2  [$C1:3AB2]   ;[$C1:3AB2]へジャンプ
$C1/3BA2 LDA #$F0                ;Aに$F0をロード
$C1/3BA4 STA $0488,x[$00:2FF7]   ;Aを[$0488,x]に書き込み
$C1/3BA7 LDA $6B    [$00:036B]   ;Aに[$00:036B]をロード
$C1/3BA9 BEQ $05    [$3BB0]      ;ゼロフラグが立っているとき[$3BB0]分岐
$C1/3BAB LDA #$00                ;Aに$00をロード
$C1/3BAD JSR $3CB3  [$C1:3CB3]   ;[$C1:3CB3]へジャンプ
;ゼロフラグON
$C1/3BB0 RTS                     ;サブルーチン戻り

$C1/3B54$C1/3B5Aは少し前と同じ、技データ13と$20で論理積を取ってゼロフラグ判定をしているのみなので、ここまでの手順だとゼロフラグが立つ。
$C1/3B5C$C1/3B62は技データ07と$0Fで論理積を取っており、下4ビットを取り出している。
下4ビットには射程が入っているが、値が0である、つまりゼロフラグが立つのは周囲攻撃または自身回復技の時だけのはずである。
周囲攻撃はこれより前に分岐になっているから、$C1/3B62でゼロフラグが立つのは回復技だけのはずである。
ただ、反撃で自身含めた範囲に回復技を使う場合は下1桁は1のようだ(キューブの「ハイスピードオペ」やマザーCOMの「システムリカバー」など)。

一方、ゼロフラグが立たない場合は$C1/3B8Eにジャンプするが、今度は技データ13と$80で論理積を取っている。
技データ13の上4ビットが$8なのは回復技なので、ここで回復技かどうかの判定を行っている。
ゼロフラグが立たないのは回復技ということであり、ここで反撃の「ハイスピードオペ」「システムリカバー」が分岐になる。
一方、回復技以外は$C1/3BB0にジャンプしてサブルーチンが戻る。

キャラの向き判定

今回は攻撃技に絞って紹介することとし、$C1/3BB0以降の処理を続けて説明していく。

;反撃キャラ向き判定
$C1/3B67 LDA $001D,y[$00:1C1D]   ;Aに[$00:1C1D](味方キャラ1の向き)をロード
$C1/3B6A AND #$03                ;Aと$03で論理積
$C1/3B6C BEQ $43    [$3BB1]      ;ゼロフラグが立っているとき[$3BB1]分岐
$C1/3B6E CMP #$01                ;Aと$01を減算比較(ステータスレジスタ変更のみ)
$C1/3B70 BEQ $58    [$3BCA]      ;ゼロフラグが立っているとき[$3BCA]分岐
$C1/3B72 CMP #$02                ;Aと$02を減算比較(ステータスレジスタ変更のみ)
$C1/3B74 BEQ $6D    [$3BE3]      ;ゼロフラグが立っているとき[$3BE3]分岐
$C1/3B76 BRL $0083  [$3BFC]      ;フラグにかかわりなく常に分岐[$3BFC]
;キャラの向き 右下($00)
$C1/3BB1 JSR $3C1A  [$C1:3C1A]   ;[$C1:3C1A]へジャンプ
;キャラの向き 左下($01)
$C1/3BCA JSR $3C24  [$C1:3C24]   ;[$C1:3C24]へジャンプ
;キャラの向き 右上($02)
$C1/3BE3 JSR $3C38  [$C1:3C38]   ;[$C1:3C38]へジャンプ
;キャラの向き 左上($03)
$C1/3BFC JSR $3C2E  [$C1:3C2E]   ;[$C1:3C2E]へジャンプ

味方キャラ1人目なら$00:1C1D、2人目以降は+$40のアドレスにキャラの向きの値が入っている。

数値向き
$00右下
$01左下
$02右上
$03左上

上の処理から、キャラの向きで処理先が分岐することがわかる。

;キャラの向き 右下($00)
$C1/3C1A LDX #$0009              ;Xに$0009をロード
$C1/3C1D BRA $1E    [$3C3D]      ;フラグにかかわりなく常に分岐[$3C3D]
;キャラの向き 左下($01)
$C1/3C24 LDX #$0007              ;Xに$0007をロード
$C1/3C27 BRA $14    [$3C3D]      ;フラグにかかわりなく常に分岐[$3C3D]
;キャラの向き 左上($03)
$C1/3C2E LDX #$FFF7              ;Xに$FFF7をロード
$C1/3C31 BRA $0A    [$3C3D]      ;フラグにかかわりなく常に分岐[$3C3D]
;キャラの向き 右上($02)
$C1/3C38 LDX #$FFF9              ;Xに$FFF9をロード
$C1/3C3B BRA $00    [$3C3D]      ;フラグにかかわりなく常に分岐[$3C3D]
;分岐合流
$C1/3C3D LSR $12    [$00:0312]   ;[$00:0312]を論理右シフト (/2)
$C1/3C3F BCS $01    [$3C42]      ;キャリーフラグが立っているとき[$3C42]分岐
$C1/3C41 RTS                     ;サブルーチン戻り
$C1/3C42 STZ $08    [$00:0308]   ;[$00:0308]に$00を書き込み
$C1/3C44 STX $14    [$00:0314]   ;Xを[$00:0314]に書き込み
$C1/3C46 LDX $10    [$00:0310]   ;Xに[$00:0311][$00:0310](キャラ座標)をロード
$C1/3C48 JSR $3C61  [$C1:3C61]   ;[$C1:3C61]へジャンプ

分岐により変わるのは、Xにロードする値になる。

$C1/3C3Dで、[$00:0312]2で割り、キャリーフラグが立つか判定をしている。
[$00:0312]には技データ06、つまり技を出す方向の値が入っている。
2で割ってキャリーフラグが立つのは、割り切れず余りが出る時、つまり今回で言えば下1桁が奇数の時である。
技データ06の下1桁が奇数になるのは、真正面方向に攻撃可能な時である。
キャラが右下向きの時、技データ06の上4ビットは下図の青数字、下4ビットは赤数字の合計値で表す。

124

421

真正面が攻撃できない技だとキャリーフラグが立たず$C1/3C41でサブルーチンが戻る。
ここではひとまず、キャリーフラグが立つ場合、つまり真正面方向に攻撃可能な場合を追ってみる。
その場合は$C1/3C42にジャンプし、[$00:0308]$00を書き込んで、Xに入った値の下1バイトのみ[$00:0314]に書き込み、X[$00:0311][$00:0310]($00+キャラ座標)をロードし[$C1:3C61]へジャンプする。

アドレス
[$00:0310]キャラ座標:上から3~5ビットにY座標の値、6~8ビットにX座標の値
[$00:0311]$00
[$00:0312]技データ06
[$00:0313]技データ07
[$00:0314]向き 右下:$09/左下:$07/左上:$F7/右上$F9

技の範囲判定

次のサブルーチンのループ処理は少々ややこしいが、まとめると、戦闘フィールドマスの計算用アドレス$00:0488$00:04BEの中で、技が当たる位置のマスに$0Fを書き込む処理になる。
周囲攻撃の場合はどのマスが範囲か、計算は比較的わかりやすいが、それ以外だと方向や射程を考慮しなければならないので、処理が少し複雑になりループ処理のループ回数も増える。

[$00:0308]は初期値が$00で、ループ前に+1されて$01からループ開始なのだが、この値は実質、技を出すキャラの距離(マス目の数)になる。

$C1/3C61 LDA $08    [$00:0308]   ;Aに[$00:0308]($00)をロード
$C1/3C63 BEQ $4B    [$3CB0]      ;ゼロフラグが立っているとき[$3CB0]分岐
$C1/3CB0 INC $08    [$00:0308]   ;[$00:0308]をインクリメント +1($01)
$C1/3CB2 RTS                     ;サブルーチン戻り

;ループ開始
$C1/3C4B REP #$21                ;Aを16bit幅に変更、キャリーフラグクリア
$C1/3C4D TXA                     ;Xレジスタの値(キャラ座標)をAレジスタに転送
$C1/3C4E ADC $14    [$00:0314]   ;A(キャラ座標) + [$00:0315][$00:0314](向き)
$C1/3C50 TAX                     ;Aレジスタの値をXレジスタに転送
$C1/3C51 SEP #$20                ;MフラグON Aレジスタは8bit幅
$C1/3C53 AND #$07                ;Aと$07で論理積
$C1/3C55 CMP #$07                ;Aと$07を減算比較(ステータスレジスタ変更のみ)
$C1/3C57 BEQ $07    [$3C60]      ;ゼロフラグが立っているとき[$3C60]分岐
$C1/3C59 TXA                     ;Xレジスタの値をAレジスタに転送
$C1/3C5A AND #$38                ;Aと$38で論理積
$C1/3C5C CMP #$38                ;Aと$38を減算比較(ステータスレジスタ変更のみ)
$C1/3C5E BNE $E8    [$3C48]      ;ゼロフラグが立っていないとき[$3C48]分岐
;ゼロフラグON
$C1/3C60 RTS                     ;サブルーチン戻り→ループを抜ける
;ゼロフラグOFF
$C1/3C48 JSR $3C61  [$C1:3C61]   ;[$C1:3C61]へジャンプ

$C1/3C4Bからのループ処理が、戦闘フィールドの1マスずつ、技の範囲かどうか判定していく処理になる。
まず、$C1/3C4Eのキャラ座標([$00:0310],上から3~5ビットにY座標の値、6~8ビットにX座標の値)に[$00:0315][$00:0314](向き)を加算する処理は何をやっているのだろうか?

仮に、キャラの座標が(2,3)だとする。つまり、左から3マス、上から4マスの位置である。
下の赤色背景マスの位置になる。

(0,0)(1,0)(2,0)(3,0)(4,0)(5,0)(6,0)
(0,1)(1,1)(2,1)(3,1)(4,1)(5,1)(6,1)
(0,2)(1,2)(2,2)(3,2)(4,2)(5,2)(6,2)
(0,3)(1,3)(2,3)(3,3)(4,3)(5,3)(6,3)
(0,4)(1,4)(2,4)(3,4)(4,4)(5,4)(6,4)
(0,5)(1,5)(2,5)(3,5)(4,5)(5,5)(6,5)
(0,6)(1,6)(2,6)(3,6)(4,6)(5,6)(6,6)

2進数だと(%010,%011)だから、[$00:0310]%0001 1010(=$1A)である。
このキャラが右下を向いている場合、[$00:0314](向き) = $09 = %0000 1001である。
%0000 1001」を座標と考えると、(1,1)である。つまり、右に1マス、下に1マスということになる。
ということは、キャラの座標+[$00:0314](向き)は、「キャラが向いている方向に座標を1マスずつ動かした位置」を意味している。
真正面方向1マス位置である、と言い換えても同じである。
キャラの座標(2,3) = %0001 1010(=$1A)$09(=%0000 1001)を加算すると、

$001A + $0009 = $0023 = %0010 0011

%00100011を下から3桁ずつとって並べると(%011,%100) = (3,4)である。
(2,3)にいるキャラの右下マス位置(3,4)が計算できた。

(0,0)(1,0)(2,0)(3,0)(4,0)(5,0)(6,0)
(0,1)(1,1)(2,1)(3,1)(4,1)(5,1)(6,1)
(0,2)(1,2)(2,2)(3,2)(4,2)(5,2)(6,2)
(0,3)(1,3)(2,3)(3,3)(4,3)(5,3)(6,3)
(0,4)(1,4)(2,4)(3,4)(4,4)(5,4)(6,4)
(0,5)(1,5)(2,5)(3,5)(4,5)(5,5)(6,5)
(0,6)(1,6)(2,6)(3,6)(4,6)(5,6)(6,6)

他の向きでも考え方は同じである。
左上向きなら[$00:0314](向き) = $F7 = %1111 0111である。
左方向も上方向もマス目の座標を-1するから、符号付き8ビット整数で考えた時の負の値を加算すれば良い。
キャラの座標(2,3) = %0001 1010(=$1A)$F7(=%1111 0111)を加算すると、

$001A + $00F7 = $0111

座標についてはキャリーフラグを考慮しなくて良いので$11(=%0001 0001)Y%010(=2)X%001(=1)であり、キャラの座標(2,3)の左上位置である(1,2)が計算できたことになる。

ただし、キャラがフィールドの隅にいる場合は、座標がフィールドからはみ出すことになる。
キャラの座標が(0,3)だったら、一番左の列、上から4マス目にいることになる。
この場合、左上向きや左下向きだと、真正面方向は戦闘フィールドの外でありマス目がない。
実際に、(0,3) = %0001 1000(=$18)で左上向きを計算してみると、

$0018 + $00F7 = $010F

$0F = %0000 1111であり、座標だと(7,1)である。
戦闘フィールドはXY0~6の値が入る7マス×7マスサイズだから、X座標が7というのは戦闘フィールド内ではない値である。
このようにはみ出した場合を考慮して、$C1/3C53からの処理が入る。
X座標が7になってしまった場合は、%00?? ?111と、下3ビットが111になっているから、$07と論理積を取った時にゼロフラグが立つ。
一方、Y座標が7になってしまった場合は、%0011 1???と、上3~5ビットが111になっている。よって、%0011 1000 = $38と論理積を取った時にゼロフラグが立つ。
$C1/3C53$C1/3C5Cで、$07と論理積及び、$38と論理積を取ってから減算しゼロフラグ判定をしているのは、このような理由からである。
ゼロフラグが立つ場合は、真正面方向がフィールド外である。
現在、「技が出せる方向が真正面方向」という前提でのサブルーチンなので、真正面方向がフィールド外だったら、技が出せないことになる。
よって、「フィールド外なので技は出ない」、このマスにおいて反撃技は出ないという判定になる。
もし、$07と論理積及び、$38と論理積のどちらもフィールド外判定になった場合、ループ処理で真正面方向のマスすべてを確認したことになるので、$C1/3C60でサブルーチンを抜ける。

一方、真正面方向がフィールド外でない場合は、$C1/3C48$C1/3C61と処理が続くことになる。

$C1/3C61 LDA $08    [$00:0308]   ;Aに[$00:0308](ループ回数)をロード
$C1/3C63 BEQ $4B    [$3CB0]      ;ゼロフラグが立っているとき[$3CB0]分岐
$C1/3C65 CMP #$01                ;Aと$01を減算比較(ステータスレジスタ変更のみ)
$C1/3C67 BEQ $10    [$3C79]      ;ゼロフラグが立っているとき[$3C79]分岐
$C1/3C69 CMP #$02                ;Aと$02を減算比較(ステータスレジスタ変更のみ)
$C1/3C6B BEQ $14    [$3C81]      ;ゼロフラグが立っているとき[$3C81]分岐
$C1/3C6D CMP #$03                ;Aと$03を減算比較(ステータスレジスタ変更のみ)
$C1/3C6F BEQ $18    [$3C89]      ;ゼロフラグが立っているとき[$3C89]分岐
$C1/3C71 LDA $13    [$00:0313]   ;Aに[$00:0313](技データ07)をロード
$C1/3C73 BIT #$08                ;Aと$08で論理積(ステータスフラグ変更のみ)
$C1/3C75 BEQ $39    [$3CB0]      ;ゼロフラグが立っているとき[$3CB0]分岐
$C1/3C77 BRA $18    [$3C91]      ;フラグにかかわりなく常に分岐[$3C91]

[$00:0308]は初期値が$01の状態でループ処理を開始しているので、最初のループ時は$C1/3C67の時点でゼロフラグが立ち$C1/3C79にジャンプする。
ループの終わり間際に[$00:0308]はインクリメント(+1)されるのでループを繰り返すと増加していくから、上の処理より、

  • ループ1回目:$C1/3C79にジャンプ
  • ループ2回目:$C1/3C81にジャンプ
  • ループ3回目:$C1/3C89にジャンプ

であり、ループ4回目以降だと$C1/3C71に進む。
ひとまず、ループ1回目~3回目の処理を見てみよう。

;ループ1回目のジャンプ先
$C1/3C79 LDA $13    [$00:0313]   ;Aに[$00:0313](技データ07)をロード
$C1/3C7B BIT #$01                ;Aと$01で論理積(ステータスフラグ変更のみ)
$C1/3C7D BEQ $31    [$3CB0]      ;ゼロフラグが立っているとき[$3CB0]分岐
$C1/3C7F BRA $10    [$3C91]      ;フラグにかかわりなく常に分岐[$3C91]
;ループ2回目のジャンプ先
$C1/3C81 LDA $13    [$00:0313]   ;Aに[$00:0313](技データ07)をロード
$C1/3C83 BIT #$02                ;Aと$02で論理積(ステータスフラグ変更のみ)
$C1/3C85 BEQ $29    [$3CB0]      ;ゼロフラグが立っているとき[$3CB0]分岐
$C1/3C87 BRA $08    [$3C91]      ;フラグにかかわりなく常に分岐[$3C91]
;ループ3回目のジャンプ先
$C1/3C89 LDA $13    [$00:0313]   ;Aに[$00:0313](技データ07)をロード
$C1/3C8B BIT #$04                ;Aと$04で論理積(ステータスフラグ変更のみ)
$C1/3C8D BEQ $21    [$3CB0]      ;ゼロフラグが立っているとき[$3CB0]分岐
$C1/3C8F BRA $00    [$3C91]      ;フラグにかかわりなく常に分岐[$3C91]

飛び先の処理と合わせて考えてみると、技データ07の下4ビット、つまり射程の値での分岐になっていることがわかる。

  • ループ1回目:技データ07から、1マス目が技の射程なら[$C1/3C91]へ、そうでなければ[$C1/3CB0]
  • ループ2回目:技データ07から、2マス目が技の射程なら[$C1/3C91]へ、そうでなければ[$C1/3CB0]
  • ループ3回目:技データ07から、3マス目が技の射程なら[$C1/3C91]へ、そうでなければ[$C1/3CB0]
  • ループ4回目以降:技データ07から、4マス目以降が技の射程なら[$C1/3C91]へ、そうでなければ[$C1/3CB0]

つまりループ回数は、キャラからのマス目の数に対応しており、ループ1回目はキャラから1マス距離の判定である(実際、ひとつ前の処理で、キャラの真正面1マス位置のマスの位置を計算していた)。
キャラの真正面1マスはフィールド外ではない、かつ、キャラの真正面1マスは技の射程かどうかが、ループ1回目における上の分岐・判定である。
ループ回数が何回であっても、技の射程内なら[$C1/3C91]へ、射程でなければ[$C1/3CB0]へ飛ぶ。
[$C1/3CB0]はこの後に紹介するがループ終了間際で、この後の$C1/3C91$C1/3C9Bの処理をスキップすることになる。
$C1/3C91$C1/3C9Bが、判定する位置のマスが技の射程である場合の処理である。

なお、技データ07の下4ビットに関してもう一度表を載せておく。
上処理だと、技データ07と$01$02$04$08で論理積を取ってゼロフラグ判定しているのだが、これは下4ビットのそれぞれの位に1が入っているかどうかを確認するためである。
下の通り、技データ07下4ビットは、下の位から順に1マス目・2マス目・3マス目・4マス目以降に対応している。
よって、それぞれの位の値を取り出すことにより、キャラ位置から幾つ目のマスが射程になっているか判定可能なのである。

数値
(16進数)
数値
(2進数)
射程
$0%0000なし
$1%00011
$2%00102
$3%00111~2
$4%01003
$6%01102~3
$7%01111~3
$8%10003~
$C%11002~
$E%11101~
$F%1111無限

では、判定する位置のマスが技の射程である場合の処理$C1/3C91~を見てみる。
なお、1回目のループ頭で、
Xレジスタの値(キャラ座標)をAレジスタに転送→キャラ座標に真正面方向+1の座標を加算→Xレジスタに転送
という処理を行ったから、この時点でもXレジスタに入っているのは、「キャラの座標に真正面方向+1の座標」である。

$C1/3C91 LDA #$F0                ;Aに$F0をロード
$C1/3C93 STA $0488,x             ;Aを[$0488,x](戦闘フィールドマスの計算用アドレス)に書き込み
$C1/3C96 JSR $3CE7  [$C1:3CE7]   ;[$C1:3CE7]へジャンプ
;
$C1/3CE7 CPY #$1C00              ;Yと$1C00を減算比較(ステータスレジスタのみ変更)
$C1/3CEA BCC $13    [$3CFF]      ;キャリーフラグが立っていないとき[$3CFF]分岐
;(敵が出す反撃だとここで$3CFF分岐)
$C1/3CEC TXA                     ;Xレジスタの値をAレジスタに転送
$C1/3CED CMP $0D    [$00:030D]   ;Aと[$00:030D]を減算比較(ステータスレジスタ変更のみ)
$C1/3CEF BNE $0D    [$3CFE]      ;ゼロフラグが立っていないとき[$3CFE]分岐
;ゼロフラグON
$C1/3CF1 LDA $0E    [$00:030E]   ;Aに[$00:030E]をロード
$C1/3CF3 BMI $1F    [$3D14]      ;ネガティブフラグが立っているとき[$3D14]分岐
$C1/3CF5 BCC $1D    [$3D14]      ;キャリーフラグが立っていないとき[$3D14]分岐
$C1/3CF7 LDA $001D,y[$00:1C5D]   ;Aに[$00:1C5D](キャラ1の向き)をロード
$C1/3CFA ORA #$80                ;Aと$80で論理和
$C1/3CFC STA $0E    [$00:030E]   ;Aを[$00:030E]に書き込み
;処理合流
$C1/3CFE RTS                     ;サブルーチン戻り
;
;$C1/3CEAで敵の反撃の場合
$C1/3CFF TXA                     ;Xレジスタの値をAレジスタに転送
$C1/3D00 CMP $34    [$00:0334]   ;Aと[$00:0334]を減算比較(ステータスレジスタ変更のみ)
$C1/3D02 BNE $0F    [$3D13]      ;ゼロフラグが立っていないとき[$3D13]分岐
$C1/3D13 RTS                     ;サブルーチン戻り
;
$C1/3C99 LDA $6B    [$00:036B]   ;Aに[$00:036B]をロード
$C1/3C9B BEQ $13    [$3CB0]      ;ゼロフラグが立っているとき[$3CB0]分岐
$C1/3CB0 INC $08    [$00:0308]   ;[$00:0308]をインクリメント +1
$C1/3CB2 RTS                     ;サブルーチン戻り
;ループここまで

$C1/3C93[$0488,x]は、マス目計算値が入る$00:0488$00:04BEの該当マスにあたる。
該当アドレスに「$0F」を書き込むことになる。
これで、「キャラの真正面1マスが技の射程だったら、該当マスの計算値アドレスに$0Fを書き込む」という処理が終了である。

この各マス判定のサブルーチンは、敵が反撃を出す場合にも使われるのだが、敵の場合、$C1/3CEAYと$1C00を減算比較した結果、キャリーフラグが立たない。
というのは、Yにはアドレス呼び出し用の値が入っているが、敵だとY1B?0、味方だとY1C00(+$40/+$80/+$C0)が入るため、敵なら減算結果が負の値、味方なら減算結果が0か正の値になる。

最終的に[$00:0308]をインクリメントしてループ頭に戻るが、1回目のループ頭で、

Xレジスタの値(キャラ座標)をAレジスタに転送→キャラ座標に真正面方向+1の座標を加算→Xレジスタに転送

という処理を行ったから、ループ終了時、Xレジスタに入っているのは、「キャラの座標に真正面方向+1の座標」、つまり$0Fを書き込んだばかりの位置の座標である。
ループを繰り返す場合、2周目で判定するのは、キャラ位置から真正面2マス位置である。
こうして、キャラ真正面方向のマスを1マスずつ、射程内かどうか判定していくことになる($0Fを書き込むかどうかは関係ない)。
ループ内の説明にも書いた通り、調べるマスがフィールド外に出るまでループしたら、そこでループ処理を抜ける。

ここまでで調べたのはあくまでも「真正面1方向」だけである。
技を出せる方向が他にもあるなら、対応した全方向に向けて上の処理を繰り返すことになる。
サンダウンの「マルチカウンター」は8方向だから、方向ごとに8回、上の処理を繰り返すことになる。

かなり前だが、キャラの向きを判定してから、まずはキャラの真正面方向に技を出せるかどうかの判定をした。
実は向きによる分岐とXにロードする値の処理は、$C1/3C15$C1/3C3Bに8方向まとめて入っていて、「マルチカウンター」なら、サンダウンが向いている真正面方向から順に8方向、Xの値を読み込みながらチェックしているのである。
もちろん、正面3方向なら3方向分だけで良いことになる。

$C1/3C15 LDX #$0001              ;Xに$0001をロード
$C1/3C18 BRA $23    [$3C3D]      ;フラグにかかわりなく常に分岐[$3C3D]
$C1/3C1A LDX #$0009              ;Xに$0009をロード
$C1/3C1D BRA $1E    [$3C3D]      ;フラグにかかわりなく常に分岐[$3C3D]
$C1/3C1F LDX #$0008              ;Xに$0008をロード
$C1/3C22 BRA $19    [$3C3D]      ;フラグにかかわりなく常に分岐[$3C3D]
$C1/3C24 LDX #$0007              ;Xに$0007をロード
$C1/3C27 BRA $14    [$3C3D]      ;フラグにかかわりなく常に分岐[$3C3D]
$C1/3C29 LDX #$FFFF              ;Xに$FFFFをロード
$C1/3C2C BRA $0F    [$3C3D]      ;フラグにかかわりなく常に分岐[$3C3D]
$C1/3C2E LDX #$FFF7              ;Xに$FFF7をロード
$C1/3C31 BRA $0A    [$3C3D]      ;フラグにかかわりなく常に分岐[$3C3D]
$C1/3C33 LDX #$FFF8              ;Xに$FFF8をロード
$C1/3C36 BRA $05    [$3C3D]      ;フラグにかかわりなく常に分岐[$3C3D]
$C1/3C38 LDX #$FFF9              ;Xに$FFF9をロード
$C1/3C3B BRA $00    [$3C3D]      ;フラグにかかわりなく常に分岐[$3C3D]

まとめると、周囲攻撃ではなく、キャラから見て8方向のどれかに技が出せる場合、

  1. キャラの真正面方向から、キャラ+1マス、+2マス……と、戦闘フィールド内部の位置のマスに技が出せるかどうか判定し、技が出せる場合、マス目計算値が入る$00:0488$00:04BEの該当位置に「$0F」を書き込む。
  2. 技の出せる全ての方向に対して1.の処理を実行する。

という処理を行ったことになる。
もし「マルチカウンター」だったら、下図でサンダウンが(2,3)に立っている時、サンダウンの向きは問わず、黄色マスに対応した$00:0488$00:04BE$0F、それ以外なら$00が入った状態になる。

(0,0)(1,0)(2,0)(3,0)(4,0)(5,0)(6,0)
(0,1)(1,1)(2,1)(3,1)(4,1)(5,1)(6,1)
(0,2)(1,2)(2,2)(3,2)(4,2)(5,2)(6,2)
(0,3)(1,3)(2,3)(3,3)(4,3)(5,3)(6,3)
(0,4)(1,4)(2,4)(3,4)(4,4)(5,4)(6,4)
(0,5)(1,5)(2,5)(3,5)(4,5)(5,5)(6,5)
(0,6)(1,6)(2,6)(3,6)(4,6)(5,6)(6,6)

敵位置のチェック

ここまでのサブルーチンで、マス目の計算用アドレス$00:0488$00:04BEに、技が当たるマスにだけ$0Fを書き込んだ。
反撃技を出す相手の位置が、$0Fを書き込んだマスと被っていれば、反撃技を出すことができる。
各マス目の敵味方の位置とダメージフィールドの状態は$00:04C8$00:04FEに書き込まれているので、該当アドレスの値と比較すれば良い。
$00:04C8$00:04FEの詳細はダメージフィールドでも解説したが、

  • 上1~3ビット:フィールドの状態、%000ならダメージフィールドなし
  • 上4ビット:敵キャラなら1、それ以外は0
  • 下4ビット:%0000ならキャラなし

というように値が入っている。

$C1/17F5 LDX $68    [$00:0368]   ;Xに[$00:0368]をロード
$C1/17F7 LDA $D5000D,x           ;Aに[$D5000D,x](技データ13)をロード
$C1/17FB BPL $0E    [$180B]      ;ネガティブフラグが立っていないとき[$180B]分岐
$C1/180B LDA $A8    [$00:03A8]   ;Aに[$00:03A8]をロード
$C1/180D LSR A                   ;Aを論理右シフト (/2)
$C1/180E LSR A                   ;Aを論理右シフト (/2)
$C1/180F LSR A                   ;Aを論理右シフト (/2)
$C1/1810 LSR A                   ;Aを論理右シフト (/2)
$C1/1811 INC A                   ;Aをインクリメント +1
$C1/1812 ORA #$10                ;Aと$10で論理和
$C1/1814 JSR $18BB  [$C1:18BB]   ;[$C1:18BB]へジャンプ

$C1/180Bで呼び出される[$00:03A8]だが、敵から攻撃を食らった後に、以下の処理で[$00:0378]からコピーされた値が入っている。

$C1/A154 LDX $78    [$00:0378]   ;Xに[$00:0378]をロード
$C1/A156 STX $A8    [$00:03A8]   ;Xを[$00:03A8]に書き込み

[$00:0378]は敵番号0~Eを$10倍した値で、敵アドレスの呼び出しなどに使う。
例えば敵IDは、敵が複数なら、$00:1B00, $00:1B10, $00:1B20……と、$00:1B00から+$10した値に順に入る。
つまり、[$00:03A8]に入った値は、攻撃してきた相手、つまりこれから反撃を出す相手の敵番号0~Eを$10倍した値ということである。
$C1/180B$C1/1812の処理は、[$00:03A8]を÷$10してから+1し、$10と論理和を取っている。
敵番号+1が下1桁、上1桁が1という値になるが、これは$00:04C8$00:04FEに入る敵キャラの値に対応している。

数値内容
$11敵キャラ1
$12敵キャラ2
$13敵キャラ3
$14敵キャラ4
$15敵キャラ5
$16敵キャラ6
$17敵キャラ7
$18敵キャラ8
$19敵キャラ9
$1A敵キャラA
$1B敵キャラB
$1C敵キャラC
$1D敵キャラD
$1E敵キャラE
$C1/18BB STA $12    [$00:0312]   ;Aを[$00:0312]に書き込み
$C1/18BD STZ $11    [$00:0311]   ;[$00:0311]に$00を書き込み
$C1/18BF LDA #$00                ;Aに$00をロード
$C1/18C1 STA $09    [$00:0309]   ;A($00)を[$00:0309]に書き込み
;マス目横一列判定ループここから
$C1/18C3 LDA #$00                ;Aに$00をロード
$C1/18C5 STA $08    [$00:0308]   ;A($00)を[$00:0308]に書き込み

先に計算された敵番号に対応した数値は[$00:0312]に書き込まれる。
$C1/18C3から、戦闘フィールドの横1列分のマス7マス分を判定するループである。
このループの中に更に、1マス毎のループが入る。
[$00:0308][$00:0309][$00:0311]$00を書き込んだ後は、1マス毎のループ処理に入る。

;1マス毎のループ処理ここから
$C1/18C7 LDA $09    [$00:0309]   ;Aに[$00:0309]をロード
$C1/18C9 ASL A                   ;Aを算術左シフト *2
$C1/18CA ASL A                   ;Aを算術左シフト *2
$C1/18CB ASL A                   ;Aを算術左シフト *2
$C1/18CC ADC $08    [$00:0308]   ;A + [$00:0308]
$C1/18CE STA $10    [$00:0310]   ;A($00)を[$00:0310]に書き込み
$C1/18D0 LDX $10    [$00:0310]   ;Xに[$00:0310]をロード
$C1/18D2 LDA $0488,x             ;Aに[$0488,x](計算用アドレス$00:0488~$00:04BE)をロード
$C1/18D5 BEQ $0C    [$18E3]      ;ゼロフラグが立っているとき[$18E3]分岐(技範囲外)
$C1/18D7 LDA $04C8,x             ;Aに[$04C8,x](フィールドの状態$00:04C8~$00:04FE)をロード
$C1/18DA AND #$1F                ;Aと$1Fで論理積
$C1/18DC CMP $12    [$00:0312]   ;Aと[$00:0312]を減算比較(ステータスレジスタ変更のみ)
$C1/18DE BNE $03    [$18E3]      ;ゼロフラグが立っていないとき[$18E3]分岐
;ゼロフラグON(敵がいるマス)
$C1/18E0 LDA #$FF                ;Aに$FFをロード
$C1/18E2 RTS                     ;サブルーチン戻り
;ゼロフラグOFF(敵がいないマス)
$C1/18E3 INC $08    [$00:0308]   ;[$00:0308]をインクリメント +1
$C1/18E5 LDA $08    [$00:0308]   ;Aに[$00:0308]をロード
$C1/18E7 CMP #$07                ;Aと$07を減算比較(ステータスレジスタ変更のみ)
$C1/18E9 BNE $DC    [$18C7]      ;ゼロフラグが立っていないとき[$18C7]分岐
;ループここまで

;横1列判定終了
$C1/18EB INC $09    [$00:0309]   ;[$00:0309]をインクリメント +1
$C1/18ED LDA $09    [$00:0309]   ;Aに[$00:0309]をロード
$C1/18EF CMP #$07                ;Aと$07を減算比較(ステータスレジスタ変更のみ)
$C1/18F1 BNE $D0    [$18C3]      ;ゼロフラグが立っていないとき[$18C3]分岐
;ループここまで

$C1/18F3 RTS                     ;サブルーチン戻り

$C1/18C7$C1/18CEは、一番上の列の判定だと[$00:0309]$00が入っているため、最終的にX$0000がロードされる。
2列目以降は[$00:0309]+1されていくため、呼び出し先アドレスが変わっていくことになる。

重要なのは$C1/18D5からで、[$0488,x]をロードするが、これは先程計算した、マス目の計算用アドレス$00:0488$00:04BEになる。
反撃技の当たるマスなら$F0が入っており、そうでないなら$00が入っているから、$C1/18D5のゼロフラグ分岐では、技範囲外だとゼロフラグが立ってループ最後の$C1/18E3までジャンプする。
そうでない場合は$C1/18D7でフィールドの状態[$04C8,x]$00:04C8$00:04FEを順にロードし、$1Fと論理積を取ることで、ダメージフィールドの値が入っている場合は除外する。
この値と、[$00:0312]に入った敵番号に対応した数値が一致する場合、つまり$C1/18DCの減算比較でゼロフラグが立つなら、「反撃技の範囲内に、攻撃してきた敵がいる」ということになる。
ゼロフラグが立つと$C1/18E0に進み、A$FFをロードしてから、サブルーチンを抜ける。
ゼロフラグが立たない場合は、初期値が$00[$00:0308]をインクリメント(+1)して$07と減算比較しているが、これは戦闘フィールドの横1列分の判定のため。
横1列、7マス分の判定の後は$C1/18EBに抜けて、ひとつ下の列に移動するサブルーチンのため、[$00:0309]をインクリメント(+1)する。
以上のループが、戦闘フィールドの最大7行分繰り返されて、反撃技が出せる範囲に敵がいないのならループが$C1/18F3に到達して反撃が出ないことになる。

$C1/1817 BNE $01    [$181A]      ;ゼロフラグが立っていないとき[$181A]分岐
;ゼロフラグON
$C1/1819 RTS                     ;サブルーチン戻り
;ゼロフラグOFF
$C1/181A LDX $68    [$00:0368]   ;Xに[$00:0368]をロード
;(以下省略)

反撃技を出す出さないに関わらず、ループを抜けた後はサブルーチン戻りで$C1/1817に戻るが、反撃技を出せる場合は最後に$FFAにロードしている。
一方、反撃技が出せない場合は、ループの最後に[$00:0309]($07) - $07の減算比較をした後だから、ゼロフラグが立った状態である。
このため、$C1/1817のゼロフラグ判定で、反撃技が出せない時はゼロフラグが立つから$C1/1819に進み、この後の反撃技を出す処理に進まないことになる。
反撃技が出せる場合はゼロフラグが立っていないので$C1/181A以降に進む。
この先は技を出す一連の処理に繋がるので、紹介は省くこととする。

なお、敵が味方に対し反撃技を出す場合、反撃技を出す法則自体は同じなので、手順はさほど違いがない。
ただ、処理するサブルーチンが一部変更される。
敵の場合は所持している技が最大4種類なので、技関係の各種の値をロードするサブルーチンが変わるが、向きや技を出すマスの判定などは味方キャラ時と同じサブルーチンを使っている。

技4種類の判定は、技1・2・3・4の順番になるので、使用可能な反撃技が2種類以上の場合、番号が低い技が優先されることになる。
例えば功夫編のイーシの技1~4は「双換手」「黄竜反身」「白蛇登心」「白蛇登心」で、「黄竜反身」と「双換手」はどちらも反撃属性が手、射程は真正面方向が被っているが、反撃時は「双換手」の方が優先されることになる。功夫編の12人衆の大半は反撃技を所持しており、反撃属性の被りも多いので発生しやすい。
最終編のヘリオスハウントだと、「レイザーソニック(タメ無)」「パルサーウォーク」「ヘルフレグランス」「リストレーション」で、「ヘルフレグランス」も「リストレーション」も無属性以外の全属性攻撃へ反撃する設定だが、「ヘルフレグランス」の方が優先順位が高いため、反撃で「リストレーション」が使われることはなく、しかもどちらの技も反撃専用技なので、ヘリオスハウントが「リストレーション」を使うことはない。技そのものはSF編のキャプテンスクウェア内の敵パピーテイルが「リストレーション」を使用するので見ることが可能である。
(この手の「設定されているが未使用技」は、リメイク版でもそのままである。意図して変更していないのかどうなのかはわからない)



このページをシェアする

上へ