基礎知識
戦闘関係
敵ターンにおける行動選択で、移動または向き変えが選択された場合、どのように移動または向き変えするかを紹介する。
移動または向き変えの手順は、以下の手順で進む。
敵サイズが大型の場合、敵に一番近い位置のマスと味方キャラとの距離(X方向+Y方向)を味方キャラ全員分計算し、一番距離が小さいキャラを決める。
同じ距離の味方キャラがいる場合、味方キャラ番号が小さいキャラが優先される。
味方キャラが戦闘不能の場合は判定除外。
敵に設定された移動パターン(敵キャラデータ00)は、データマップ>敵移動データのID$00~$28のいずれかなのだが、敵が行動異常$8~$Eの場合、移動パターンがそれぞれ$07~$0Dで固定になる。
移動パターン9×9マスの中心位置が敵が右下向きの位置として、一番近い味方キャラの位置を探す(もし味方キャラが敵から5マス以上離れていて9×9マスからはみ出す場合、4マスとして計算)。
敵の向きにより上下左右反転で考えること。
味方キャラの位置に書かれている数値が行動パターンになる。
| 行動パターン値 | 移動・向き変え |
|---|---|
| $00 | 味方キャラに近づく方向へ横方向に1マス移動 |
| $01 | 味方キャラに近づく方向へ縦方向に1マス移動 |
| $02 | 味方キャラから遠ざかる方向へ横方向に1マス移動 |
| $03 | 味方キャラから遠ざかる方向へ縦方向に1マス移動?(※表外注記) |
| $04 | 右に1マス移動 |
| $05 | 下に1マス移動 |
| $06 | 左に1マス移動 |
| $07 | 上に1マス移動 |
| $08 | 向いている横方向に1マス移動 |
| $09 | 向いている縦方向に1マス移動 |
| $0A | 向いている反対の横方向に1マス移動 |
| $0B | 向いている反対の縦方向に1マス移動 |
| $0C | 上下左右それぞれ1/4の確率で、ランダムに1マス移動 1回目の判定で移動不可だった場合、もう一度判定してランダム方向1マス移動 |
| $0D,$0E,$0F,$14以上 | 移動・向き変えしない |
| $10 | 反時計回りに向き変え |
| $11 | 時計回りに向き変え |
| $12 | 一番近くの味方キャラの方向へ向き変え |
| $13 | 時計回り・反時計回りにそれぞれ1/2の確率で向き変え |
$00~$0Bで、移動先に他のキャラがいて移動ができなかった場合、$0Cのランダム方向1マス移動の判定を1回行う。
それでも移動できなかったら、$13のランダム向き変えをして行動終了する。
行動パターン値$03は、本来なら敵と味方の座標を比較するべきはずが、敵と次の敵番号の仮座標とで比較をしているため、想定していただろう挙動を行わない。
移動パターンが40種、行動パターンが20種あるので、説明が長くなる。
(移動パターンも行動パターンも被りがあるので、実際にはこれより少ないが)
世界の合言葉は森部様の移動データページが一番まとまっているので、合わせて参考にしていただきたい。
計算に必要なメモリアドレスは以下のとおり。
敵の移動・向き変えは、敵に一番近い位置の味方キャラとの座標関係(相対距離と位置)が決定要素のひとつのため、敵の座標、幅、向きと味方の座標のアドレスが必要になる。
敵が大きいサイズの場合、一番近い味方位置に近い座標で距離を決めるので、敵の縦幅と横幅も必要である。
味方側で必要なのは座標のみで、向きは関係ない。
後の処理で紹介するが、敵からの相対距離が同じ味方キャラがいる場合、味方1>味方2>味方3>味方4と優先順位がある。
座標はXが0~6で右方向が正、Yが0~6で下方向が正。原点(0,0)は左上マスになる。
敵にも味方にも、途中計算用のX座標とY座標を記録するアドレスがあるが、今回は敵の移動なので敵の途中計算用座標が使われる。
今回だと、途中計算用座標に移動先の座標を書き込んでおいて、その移動先に他の敵や味方がいないか、という判定に用いる。
向きは、右下$00, 左下$40, 右上$80, 左上$C0。
| 敵種類n (n=0~3) | アドレス |
|---|---|
| 横幅 | $00:1An4 |
| 縦幅 | $00:1An5 |
| 敵番号n (n=0~E) | アドレス |
|---|---|
| 向き | $00:1Bn4 |
| 途中計算用X座標 | $00:1B08 |
| 途中計算用Y座標 | $00:1B09 |
| X座標 | $00:1BnA |
| Y座標 | $00:1BnB |
| 味方キャラ1~4 (n=0~3) | アドレス |
|---|---|
| X座標 | $00:1C18 + 40n |
| Y座標 | $00:1C19 + 40n |
敵種類nの$00:1An0が移動パターンで、敵キャラデータ00からコピーされている。
$00~$28まであるが、実際の敵データを見ると未使用となったパターンや被っているパターンも含まれている。
各種データアドレス>敵移動データに掲載してある。
移動パターンは1種類につき、9×9マスに対応した$51バイト(81バイト)の値が入っているが、ここに入っている値が行動パターン。
ただ、行動パターンが決まっているのは$00~$13のみで、$14以上は設定がない($14以上だと、サブルーチンで$0Fが採用されるようになっている。後で説明する)
それぞれに応じたサブルーチンがあり、例えば行動パターンが$08だったら、敵が向いている方向の横方向に1マス移動、もし移動したい方向に行けないようならランダム移動、といったようにサブルーチンが変わってくる。
行動異常データ00の上から6ビット目、%0000 0100の1が立っている位だが、ここに0が立っている行動異常の時、移動パターンは「行動異常-1」が使われる。
該当するのは行動異常$8~$Eで、これらの行動異常は、敵に設定された移動パターンではなく、各行動異常用の移動パターンが使用される、ということである。
「マザーイメージ」で行動異常$9になると、移動パターンがID$08で固定になり、敵が一番近い位置の味方キャラに近寄ってきたり、「忍法コマまわし」で行動異常$Aになると、移動パターンがID$09になって、反時計回りに回転し始める、といった挙動はこの仕様により生じている。
座標と向きの判定前、$C1/1D0E~$C1/1D1Aで、敵の現在の行動異常のデータが[$00:0320]~[$00:0327]にコピーされている。
つまり行動異常データ00の値が[$00:0320]に入っており、サブルーチンで計算に用いる。
移動の際には、移動先に既に他のキャラがいないか、といった判定を行う必要がある。
戦闘フィールド7×7マスの状態は$00:04C8~$00:04FEに入っている。
下に、$00:04??の??の値部分のみ記している。
| C8 | C9 | CA | CB | CC | CD | CE |
| D0 | D1 | D2 | D3 | D4 | D5 | D6 |
| D8 | D9 | DA | DB | DC | DD | DE |
| E0 | E1 | E2 | E3 | E4 | E5 | E6 |
| E8 | E9 | EA | EB | EC | ED | EE |
| F0 | F1 | F2 | F3 | F4 | F5 | F6 |
| F8 | F9 | FA | FB | FC | FD | FE |
各アドレスに入る数値は、何もなければ$00、それ以外はキャラクターの数値+ダメージフィールド状態の合計値になる。
敵が複数マスにまたがっている場合は該当マスに同じ数値が入る。
| 数値 | 内容 |
|---|---|
| $01 | 味方キャラ1 |
| $02 | 味方キャラ2 |
| $03 | 味方キャラ3 |
| $04 | 味方キャラ4 |
| $11 | 敵キャラ0 |
| $12 | 敵キャラ1 |
| $13 | 敵キャラ2 |
| $14 | 敵キャラ3 |
| $15 | 敵キャラ4 |
| $16 | 敵キャラ5 |
| $17 | 敵キャラ6 |
| $18 | 敵キャラ7 |
| $19 | 敵キャラ8 |
| $1A | 敵キャラ9 |
| $1B | 敵キャラA |
| $1C | 敵キャラB |
| $1D | 敵キャラC |
| $1E | 敵キャラD |
| $1F | 敵キャラE |
| $80 | 水フィールド |
| $A0 | 毒フィールド |
| $C0 | 火炎フィールド |
| $E0 | 電撃フィールド |
ここまでの説明の通り、敵の移動・向き変え手順はなかなかややこしいので、順に説明をしていく。
敵ターンにおける行動選択で、移動・向き変えが確定となるのは$C1/8F5Aからであるから、その後のサブルーチンから紹介していく。
以下でn, mは敵種類m(1~4)、敵番号n($0~$F)となる。
$C1/8F5A LDA #$00 ;Aに$00をロード $C1/8F5C STA $7E9106,x[$7E:AC06] ;Aを[$7E:ACn6]に書き込み $C1/8F60 LDA $7E8F07,x[$7E:AA07] ;Aに[$7E:AAn7](状態異常)をロード $C1/8F64 BIT #$02 ;Aと$02で論理積(ステータスフラグ変更のみ) $C1/8F66 BNE $0F [$8F77] ;ゼロフラグが立っていないとき[$8F77]分岐 ;ゼロフラグON 足かため状態ではない $C1/8F68 JSR $913A [$C1:913A] ;[$C1:913A]へジャンプ $C1/913A JSR $91F0 [$C1:91F0] ;[$C1:91F0]へジャンプ $C1/91F0 LDY $0002,x[$00:1B02] ;Yに[$00:1Bn2]をロード $C1/91F3 LDA $000A,x[$00:1B0A] ;Aに[$00:1BnA](敵X座標)をロード $C1/91F6 STA $14 [$00:0314] ;Aを[$00:0314]に書き込み $C1/91F8 CLC ;キャリーフラグクリア $C1/91F9 ADC $0004,y[$00:1A04] ;A + [$00:1A04+40m](敵の横幅) $C1/91FC DEC A ;Aをデクリメント -1 $C1/91FD STA $15 [$00:0315] ;Aを[$00:0315]に書き込み $C1/91FF LDA $000B,x[$00:1B0B] ;Aに[$00:1BnB](敵Y座標)をロード $C1/9202 STA $16 [$00:0316] ;Aを[$00:0316]に書き込み $C1/9204 CLC ;キャリーフラグクリア $C1/9205 ADC $0005,y[$00:1A05] ;A + [$00:1A05+40m](敵の縦幅) $C1/9208 DEC A ;Aをデクリメント -1 $C1/9209 STA $17 [$00:0317] ;Aを[$00:0317]に書き込み $C1/920B RTS ;サブルーチン戻り $C1/913D STZ $12 [$00:0312] ;[$00:0312]に$00を書き込み $C1/913F LDA #$FF ;Aに$FFをロード $C1/9141 STA $13 [$00:0313] ;Aを[$00:0313]に書き込み $C1/9143 STZ $1E [$00:031E] ;[$00:031E]に$00を書き込み $C1/9145 STZ $1F [$00:031F] ;[$00:031F]に$00を書き込み $C1/9147 LDY #$1C00 ;Yに$1C00をロード $C1/914A JSR $9166 [$C1:9166] ;[$C1:9166]へジャンプ
最初の判定は$C1/8F60で、敵の状態異常[$7E:AAn7]と$02で論理積を取ってゼロフラグとなるが、これは敵が足かため状態かどうかの判定である。
足かため状態だと、移動も向き変えもできないので、移動・向き変え処理から抜ける、ということである。
$C1/913Aからは、敵と味方との相対距離と位置を判定するための準備である。
以下のようにメモリに値をコピーしている。
| アドレス | 値 |
|---|---|
[$00:0314] | 敵X座標 |
[$00:0315] | 敵X座標+横幅-1 |
[$00:0316] | 敵Y座標 |
[$00:0317] | 敵Y座標+縦幅-1 |
[$00:0312] | $00 |
[$00:0313] | $FF |
[$00:031E] | $00 |
[$00:031F] | $00 |
敵の座標は左上を基準としているので、「敵X座標+横幅-1」は、敵の一番右マスのX座標、「敵Y座標+縦幅-1」は、敵の一番下マスのY座標、ということである。
サブルーチンの説明の前に、敵の移動・向き変えのため、敵と味方との相対距離をどう決めるかを図を含めて解説する。
敵と味方の相対距離と位置は、敵を中心とした9×9マス座標で考えた時に、一番近い位置の味方キャラはどこか、ということを決める。
9×9マスだと、敵と味方がX軸またはY軸で5マス以上離れている場合は範囲外にはみ出してしまうが、5マス以上離れていたら4マスという扱いにする。
下の図の★が敵位置で、右下向き(座標の値が正の方向)を基準として考える。
敵は複数マスにまたがっていることがほとんどだが、その場合、味方に一番近い位置のマスを基準にする。
例えば、現代編のナムキャット戦の初期位置は以下のようになっている。
7×7マスフィールドの座標は左上を(0,0)として右方向がX軸、下方向がY軸とする。
敵の座標は左上マスを基準にするので、ナムキャットの座標は(0,0)で、高原の座標は(5,4)である。
ナムキャットと高原の相対距離だが、ナムキャット側は一番下のマスが高原に一番近いので、座標で言えば(0,2)を基準とする(ナムキャット自身の座標とは異なることに注意)。
(0,2)を基準にすると、高原の位置は、X軸方向に+5、Y軸方向に+2である。
だが、移動・向き変え判定時は、敵を中心とした9×9マス座標で考え、5マス以上離れていたら4マスという扱いにする。
このため、移動・向き変え判定時は、
X軸方向に+4、Y軸方向に+2という位置で判定をする。
以上を踏まえた上で、続きのサブルーチンを見てみる。
;味方の状態判定 $C1/9166 LDA $0000,y ;Aに[$00:1C00+40y](味方キャラID)をロード $C1/9169 INC A ;Aをインクリメント +1 $C1/916A BEQ $0D [$9179] ;ゼロフラグが立っているとき[$9179]分岐 $C1/916C LDA $0001,y ;Aに[$00:1C01+40y](戦闘状態)をロード $C1/916F BIT #$40 ;Aと$40で論理積(ステータスフラグ変更のみ) $C1/9171 BEQ $06 [$9179] ;ゼロフラグが立っているとき[$9179]分岐 ;ゼロフラグOFF ($40:敵操作状態 $FF:通常) $C1/9173 LDA $0039,y ;Aに[$00:1C39+40y](状態異常)をロード $C1/9176 INC A ;Aをインクリメント +1 $C1/9177 BNE $01 [$917A] ;ゼロフラグが立っていないとき[$917A]分岐 ;ゼロフラグON ($00:戦闘離脱 $20:味方キャラ敵対)または戦闘不能 $C1/9179 RTS ;サブルーチン戻り ;ゼロフラグOFF 戦闘不能・離脱ではない $C1/917A JSR $91AB [$C1:91AB] ;[$C1:91AB]へジャンプ ; ;X座標相対距離判定 $C1/91AB LDA $0018,y ;Aに[$00:1A18+40y](味方 X座標)をロード $C1/91AE SEC ;キャリーフラグON $C1/91AF SBC $14 [$00:0314] ;A - [$00:0314](敵X座標) $C1/91B1 BCC $0D [$91C0] ;キャリーフラグが立っていないとき[$91C0]分岐 ;キャリーフラグON(X座標が味方-敵≧0) 減算の結果が0か正の数の時 $C1/91B3 LDA $0018,y ;Aに[$00:1A18+40y](味方 X座標)をロード $C1/91B6 SEC ;キャリーフラグON $C1/91B7 SBC $15 [$00:0315] ;A - [$00:0315](敵X座標+横幅-1) $C1/91B9 BCS $05 [$91C0] ;キャリーフラグが立っているとき[$91C0]分岐 ;キャリーフラグOFF(X座標が味方-敵の右幅<0) 減算の結果が負の数の時 $C1/91BB LDA #$04 ;Aに$04をロード $C1/91BD STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/91BF RTS ;サブルーチン戻り ;キャリーフラグOFF(X座標が味方-敵<0) 減算の結果が負の数の時 $C1/91C0 JSR $91E1 [$C1:91E1] ;[$C1:91E1]へジャンプ $C1/91E1 CLC ;キャリーフラグクリア $C1/91E2 ADC #$04 ;A + $04 $C1/91E4 BPL $03 [$91E9] ;ネガティブフラグが立っていないとき[$91E9]分岐 ;ネガティブフラグOFF $C1/91E9 CMP #$09 ;Aと$09を減算比較(ステータスレジスタ変更のみ) $C1/91EB BCC $02 [$91EF] ;キャリーフラグが立っていないとき[$91EF]分岐 ;キャリーフラグON $C1/91ED LDA #$08 ;Aに$08をロード ;キャリーフラグOFF $C1/91EF RTS ;サブルーチン戻り $C1/91C3 STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/91C5 RTS ;サブルーチン戻り $C1/917D JSR $919C [$C1:919C] ;[$C1:919C]へジャンプ $C1/919C STA $18 [$00:0318] ;Aを[$00:0318]に書き込み $C1/919E CMP #$04 ;Aと$04を減算比較(ステータスレジスタ変更のみ) $C1/91A0 BCS $06 [$91A8] ;キャリーフラグが立っているとき[$91A8]分岐 ;キャリーフラグOFF $C1/91A2 LDA #$04 ;Aに$04をロード $C1/91A4 SEC ;キャリーフラグON $C1/91A5 SBC $18 [$00:0318] ;A - [$00:0318] $C1/91A7 RTS ;サブルーチン戻り ;キャリーフラグON $C1/91A8 SBC #$04 ;A - $04 $C1/91AA RTS ;サブルーチン戻り $C1/9180 STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/9182 JSR $91C6 [$C1:91C6] ;[$C1:91C6]へジャンプ
ここから敵と味方との座標・相対位置判定になる。
$C1/9166~$C1/917Aは味方の状態の判定で、戦闘不能・離脱の味方は移動判定の基準としない。
$C1/91ABから、X座標についての相対位置判定を行う。
最初に、「味方X座標-敵X座標」の計算を行い、その結果から分岐していく。
上で図で説明したが、X軸にしぼって考えると、
敵位置から±4マス位置の範囲内に味方がいる場合は★からの距離(0~4)、5マス以上離れていたら距離4、として、最終的に$C1/9180にて、X軸相対距離を[$00:0310]に書き込む、という処理になっている。
敵のサイズ(横幅)の考慮もしなければならないので分岐が多い。
続いて、$C1/91C6から、Y座標相対距離判定を行う。
;Y座標相対距離判定 $C1/91C6 LDA $0019,y ;Aに[$00:1A19](味方Y座標)をロード $C1/91C9 SEC ;キャリーフラグON $C1/91CA SBC $16 [$00:0316] ;A - [$00:0316](敵Y座標) $C1/91CC BCC $0D [$91DB] ;キャリーフラグが立っていないとき[$91DB]分岐 ;キャリーフラグON(Y座標が味方>敵) 減算の結果が0か正の数の時 $C1/91CE LDA $0019,y ;Aに[$00:1A19](味方Y座標)をロード $C1/91D1 SEC ;キャリーフラグON $C1/91D2 SBC $17 [$00:0317] ;A - [$00:0317](敵Y座標+縦幅-1) $C1/91D4 BCS $05 [$91DB] ;キャリーフラグが立っているとき[$91DB]分岐 ;キャリーフラグOFF 減算の結果が負の数の時 $C1/91D6 LDA #$04 ;Aに$04をロード $C1/91D8 STA $11 [$00:0311] ;Aを[$00:0311]に書き込み $C1/91DA RTS ;サブルーチン戻り ;$C1/91CCでキャリーフラグOFFか、$C1/91D4でキャリーフラグON $C1/91DB JSR $91E1 [$C1:91E1] ;[$C1:91E1]へジャンプ $C1/91E1 CLC ;キャリーフラグクリア $C1/91E2 ADC #$04 ;A + $04 $C1/91E4 BPL $03 [$91E9] ;ネガティブフラグが立っていないとき[$91E9]分岐 ;ネガティブフラグOFF $C1/91E9 CMP #$09 ;Aと$09を減算比較(ステータスレジスタ変更のみ) $C1/91EB BCC $02 [$91EF] ;キャリーフラグが立っていないとき[$91EF]分岐 ;キャリーフラグON $C1/91ED LDA #$08 ;Aに$08をロード ;キャリーフラグOFF $C1/91EF RTS ;サブルーチン戻り $C1/91DE STA $11 [$00:0311] ;Aを[$00:0311]に書き込み $C1/91E0 RTS ;サブルーチン戻り $C1/9185 JSR $919C [$C1:919C] ;[$C1:919C]へジャンプ $C1/919C STA $18 [$00:0318] ;Aを[$00:0318]に書き込み $C1/919E CMP #$04 ;Aと$04を減算比較(ステータスレジスタ変更のみ) $C1/91A0 BCS $06 [$91A8] ;キャリーフラグが立っているとき[$91A8]分岐 ;キャリーフラグOFF $C1/91A2 LDA #$04 ;Aに$04をロード $C1/91A4 SEC ;キャリーフラグON $C1/91A5 SBC $18 [$00:0318] ;A - [$00:0318] $C1/91A7 RTS ;サブルーチン戻り ;キャリーフラグON $C1/91A8 SBC #$04 ;A - $04 $C1/91AA RTS ;サブルーチン戻り
実質、X座標とやっていることは同じである。
敵位置から±4マス位置の範囲内に味方がいる場合は★からの距離(0~4)、5マス以上離れていたら距離4、としている。
ただ、Y軸相対距離は最終的に、$C1/91A7または$C1/91AAの時点でAに書き込まれて終了になっている。
$C1/9188 CLC ;キャリーフラグクリア $C1/9189 ADC $10 [$00:0310] ;A + [$00:0310](X軸相対距離) $C1/918B CMP $13 [$00:0313] ;Aと[$00:0313]を減算比較(ステータスレジスタ変更のみ) $C1/918D BCS $0C [$919B] ;キャリーフラグが立っているとき[$919B]分岐 ;キャリーフラグOFF([$00:0313]の方が小さい) 減算の結果が負の数の時 $C1/918F STA $13 [$00:0313] ;Aを[$00:0313]に書き込み $C1/9191 STY $1E [$00:031E] ;Yを[$00:031E]に書き込み $C1/9193 TYA ;Yレジスタの値をAレジスタに転送 $C1/9194 CLC ;キャリーフラグクリア $C1/9195 ROL A ;Aをキャリーフラグを含めた9bitで左ローテート $C1/9196 ROL A ;Aをキャリーフラグを含めた9bitで左ローテート $C1/9197 ROL A ;Aをキャリーフラグを含めた9bitで左ローテート $C1/9198 INC A ;Aをインクリメント +1 $C1/9199 STA $12 [$00:0312] ;Aを[$00:0312]に書き込み ;キャリーフラグON([$00:0313]の方が大きいか同値) 減算の結果が0か正の数の時 $C1/919B RTS ;サブルーチン戻り $C1/914D LDY #$1C40 ;Yに$1C40をロード $C1/9150 JSR $9166 [$C1:9166] ;[$C1:9166]へジャンプ
$C1/9188~$C1/9189で、敵とのX軸相対距離 + Y軸相対距離を計算し、[$00:0313]と減算比較している。
[$00:0313]だが、$C1/9141にて、初期値として$FFが入っているから、最初の味方キャラの判定だと、減算結果は必ず負となり、キャリーフラグが立って$C1/918Fに進む。
$C1/918Fで、「敵とのX軸相対距離 + Y軸相対距離」が新たに[$00:0313]に書き込まれる。
以降の処理だが、$C1/9193~$C1/9199の処理で、Yレジスタに入っている味方キャラ番号に対応した$1C00, $1C40, $1C80, $1CC0のいずれかが[$00:031F][$00:031E]に書き出され、キャラに対応した$01, $02, $03, $04が算出されて[$00:0312]に書き込まれる。
$C1/919Bで処理合流となり、ここで味方キャラ1人分の処理が終了して、$C1/914Dで2人目判定へ飛ぶ。
ということで、味方キャラ1人分の判定により、
| アドレス | 内容 |
|---|---|
[$00:0313] | 敵とのX軸相対距離 + Y軸相対距離 |
[$00:0312] | [$00:0313]に入った味方キャラ番号$01~$04 |
[$00:031F][$00:031E] | [$00:0313]に入った味方キャラアドレス$1C00, $1C40, $1C80, $1CC0 |
が、記録された。
この後に味方キャラ2以降を判定して、「敵とのX軸相対距離 + Y軸相対距離」がより短いキャラが[$00:0313]と[$00:0312]を更新していくことになる。
ただし、「敵とのX軸相対距離 + Y軸相対距離」を比較して同値だったら、$C1/918Dのキャリーフラグ判定で更新スキップだから、味方キャラ番号が小さいキャラの値が残されることになる。
こうして、戦闘フィールドに居る味方キャラ全員分の判定をすると、最終的に、敵との距離が一番近い味方キャラ(相対距離が同値の場合、より味方番号の小さいキャラ)の値が[$00:0313]、[$00:0312]、[$00:031F][$00:031E]に残る、ということになる。
判定部分を省略すると、以下のように、$C1/913A~$C1/9165で4キャラ分の判定を行っていることがわかる。
$C1/913A JSR $91F0 [$C1:91F0] ;[$C1:91F0]へジャンプ ; ;(味方キャラ1の判定) ; $C1/914D LDY #$1C40 ;Yに$1C40をロード $C1/9150 JSR $9166 [$C1:9166] ;[$C1:9166]へジャンプ ; ;(味方キャラ2の判定) ; $C1/9153 LDY #$1C80 ;Yに$1C80をロード $C1/9156 JSR $9166 [$C1:9166] ;[$C1:9166]へジャンプ ; ;(味方キャラ3の判定) ; $C1/9159 LDY #$1CC0 ;Yに$1CC0をロード $C1/915C JSR $9166 [$C1:9166] ;[$C1:9166]へジャンプ ; ;(味方キャラ4の判定) ; $C1/915F LDA $12 [$00:0312] ;Aに[$00:0312]をロード $C1/9161 STA $7E9107,x[$7E:AC07] ;Aを[$7E:ACn7]に書き込み $C1/9165 RTS ;サブルーチン戻り
これで敵味方の相対距離判定が終わりになり、最後に、一番近い位置の味方キャラ番号が入った[$00:0312]が、[$7E:ACn7]にもコピーされてサブルーチンが終了する。
敵に一番近い位置の味方キャラの判定を終えたら、該当の味方キャラとの相対距離と位置から移動パターンを判定していく。
$C1/8F6B JSR $90C5 [$C1:90C5] ;[$C1:90C5]へジャンプ $C1/90C5 JSR $91F0 [$C1:91F0] ;[$C1:91F0]へジャンプ $C1/91F0 LDY $0002,x ;Yに[$00:1Bn2]をロード $C1/91F3 LDA $000A,x ;Aに[$00:1BnA](敵X座標)をロード $C1/91F6 STA $14 [$00:0314] ;Aを[$00:0314]に書き込み $C1/91F8 CLC ;キャリーフラグクリア $C1/91F9 ADC $0004,y[$00:1A04] ;A + [$00:1A04+40m](敵の横幅) $C1/91FC DEC A ;Aをデクリメント -1 $C1/91FD STA $15 [$00:0315] ;Aを[$00:0315]に書き込み $C1/91FF LDA $000B,x ;Aに[$00:1BnB](敵Y座標)をロード $C1/9202 STA $16 [$00:0316] ;Aを[$00:0316]に書き込み $C1/9204 CLC ;キャリーフラグクリア $C1/9205 ADC $0005,y[$00:1A05] ;A + [$00:1A05+40m](敵の縦幅) $C1/9208 DEC A ;Aをデクリメント -1 $C1/9209 STA $17 [$00:0317] ;Aを[$00:0317]に書き込み $C1/920B RTS ;サブルーチン戻り $C1/90C8 STZ $12 [$00:0312] ;[$00:0312]に$00を書き込み $C1/90CA LDA #$FF ;Aに$FFをロード $C1/90CC STA $13 [$00:0313] ;Aを[$00:0313]に書き込み $C1/90CE LDY $1E [$00:031E] ;Yに[$00:031F][$00:031E](一番近い位置の味方キャラアドレス)をロード $C1/90D0 BNE $03 [$90D5] ;ゼロフラグが立っていないとき[$90D5]分岐 $C1/90D5 JSR $91AB [$C1:91AB] ;[$C1:91AB]へジャンプ
上処理で、以下のように値が入った。
| アドレス | 内容 |
|---|---|
[$00:0314] | 敵X座標 |
[$00:0315] | 敵X座標+横幅-1 |
[$00:0316] | 敵Y座標 |
[$00:0317] | 敵Y座標+縦幅-1 |
[$00:0312] | $00 |
[$00:0313] | $FF |
また、$C1/90CEでYに[$00:031F][$00:031E]をロードしている。
先程までに計算した、敵に一番近い位置の味方キャラアドレス$1C00, $1C40, $1C80, $1CC0のいずれかである。
飛び先の$C1/91ABだが、先程、味方キャラ全員に対して行ったX座標のサブルーチンである。
その後にY座標のサブルーチンももう一度行っている。
省略できる部分は省略すると以下のようになる。
;X座標絶対位置判定 $C1/91AB LDA $0018,y ;Aに[$00:1A18+40y](味方 X座標)をロード ;(省略) $C1/91C3 STA $10 [$00:0310] ;Aを[$00:0310]に書き込み $C1/91C5 RTS ;サブルーチン戻り ; $C1/90D8 JSR $91C6 [$C1:91C6] ;[$C1:91C6]へジャンプ ; ;Y座標絶対位置判定 ;(省略) $C1/91DE STA $11 [$00:0311] ;Aを[$00:0311]に書き込み $C1/91E0 RTS ;サブルーチン戻り
ここで注意しなければならないのは、[$00:0310]と[$00:0311]に入るのは相対距離ではないという点。
X軸でいえば、$C1/91C5でサブルーチンが戻った後、相対距離を求める$C1/919C~$C1/9180の処理をしていない。
ということは、X軸で言えば、
一番左の位置を原点とした0~8の値が[$00:0310]に入る。
相対位置ではなく、左端を原点とした絶対位置が入る、ということである。
ただ、今回も、5マス以上離れている時は左側なら0、右側なら8が入ることになる。
Y軸も同じ処理である。
つまり、
[$00:0310]:X座標絶対位置(0~8)、5マス以上離れていたら左側なら0、右側なら8[$00:0311]:Y座標絶対位置(0~8)、5マス以上離れていたら上側なら0、下側なら8を、書き込んだことになる。
いわば、9×9マスで左上原点とした味方位置座標(X,Y)を求めたことと同じである(敵位置は(3,3)固定)。
$C1/90DB LDA $0004,x ;Aに[$00:1Bn4](向き)をロード $C1/90DE BIT #$40 ;Aと$40で論理積(ステータスフラグ変更のみ) $C1/90E0 BEQ $07 [$90E9] ;ゼロフラグが立っているとき[$90E9]分岐 ;ゼロフラグOFF(左下$40、左上$C0 $C1/90E2 LDA #$08 ;Aに$08をロード $C1/90E4 SEC ;キャリーフラグON $C1/90E5 SBC $10 [$00:0310] ;A - [$00:0310](X座標相対距離) $C1/90E7 STA $10 [$00:0310] ;Aを[$00:0310]に書き込み ;ゼロフラグON(右下$00、右上$80) $C1/90E9 LDA $0004,x ;Aに[$00:1Bn4](向き)をロード $C1/90EC BIT #$80 ;Aと$80で論理積(ステータスフラグ変更のみ) $C1/90EE BEQ $07 [$90F7] ;ゼロフラグが立っているとき[$90F7]分岐 ;ゼロフラグOFF(右上$80、左上$C0) $C1/90F0 LDA #$08 ;Aに$08をロード $C1/90F2 SEC ;キャリーフラグON $C1/90F3 SBC $11 [$00:0311] ;A - [$00:0311](Y座標相対距離) $C1/90F5 STA $11 [$00:0311] ;Aを[$00:0311]に書き込み ;ゼロフラグON(右下$00、左下$40) $C1/90F7 LDY $10 [$00:0310] ;Yに[$00:0310]をロード $C1/90F7 LDY $10 [$00:0310] ;Yに[$00:0311][$00:0310]をロード $C1/90F9 STY $1A [$00:031A] ;Yを[$00:031B][$00:031A]に書き込み
ここから敵の向き判定になる。
先に述べた通り、敵と味方の相対距離と位置は、敵を中心とした9×9マス座標で考えるのだが、敵が右下向きであることを基準としている。
敵の向きによっては、この9×9マスの2次元空間を、
| 敵の向き | 内容 |
|---|---|
| 右下向き | (基準) |
| 左下向き | 左右反転 |
| 右上向き | 上下反転 |
| 左上向き | 左右+上下反転 |
として考えなければならない。
先ほど算出した、[$00:0310][$00:0311]を味方位置座標と考えた場合、敵位置(3,3)の敵は右下向きという前提での座標ということである。
$C1/90DBで敵の向きをロードしている。
右下$00、左下$40、右上$80、左上$C0である。
$C1/90E0にて、$40との論理積を取ってゼロフラグ分岐があるが、ゼロフラグOFFは左下$40、左上$C0である。
左向きだと、左右反転で考える必要があるため、
$08 - [$00:0310](味方位置X座標)
を新たな[$00:0310]とする。
左右反転したら一番左マスを基準に、左方向に値が増える、というような感じである。
$C1/90E9からは、向きと$80との論理積でゼロフラグ分岐だが、今度は右上$80、左上$C0でゼロフラグOFFである。
上向きだと、上下反転で考える必要があるため、
$08 - [$00:0311](味方位置Y座標)
を新たな[$00:0311]とする。
左上向きの場合どちらもゼロフラグOFFになるから、これで左右+上下反転が行われたことになる。
逆に、右下向きはここで何の変更もする必要はなく、[$00:0310][$00:0311]どちらもそのままである。
$C1/90F7~$C1/90F9で、[$00:0311][$00:0310]が[$00:031B][$00:031A]にコピーされる。
$C1/90FB LDA $20 [$00:0320] ;Aに[$00:0320](行動異常データ00)をロード $C1/90FD BIT #$04 ;Aと$04(%0000 0100)で論理積(ステータスフラグ変更のみ) $C1/90FF BNE $06 [$9107] ;ゼロフラグが立っていないとき[$9107]分岐 ;ゼロフラグON(行動異常により移動補正あり) $C1/9101 LDA $7E8F02,x[$7E:AA02] ;Aに[$7E:AAn2](行動異常)をロード $C1/9105 BNE $07 [$910E] ;ゼロフラグが立っていないとき[$910E]分岐 ;ゼロフラグOFF(行動異常により移動補正なし) $C1/9107 LDY $0002,x ;Yに[$00:1Bn2]をロード $C1/910A LDA $0020,y ;Aに[$00:1A20+40m](敵キャラデータ00 移動パターン)をロード $C1/910D INC A ;Aをインクリメント +1 ;ゼロフラグOFF(行動異常により移動補正あり) $C1/910E DEC A ;Aをデクリメント -1 $C1/910F STA $4202 [$00:4202] ;Aを[$00:4202]に書き込み
$C1/90FBの[$00:0320]だが、順序ポイント判定の時に、敵の現在の行動異常のデータ8バイトが、[$00:0320]~[$00:0327]にコピーされたままである。
つまり、[$00:0320]に入っているのは、敵の現在の行動異常の行動異常データ00である。
行動異常データ00の上から5ビット目が0だと、行動異常による移動パターン補正が入る。1なら入らない。
$C1/90FFのゼロフラグ判定はそのための分岐であり、「行動異常データ00の上から5ビット目が0、かつ、行動異常番号0ではない」時は、Aに[$7E:AAn2](行動異常)をロードし、$C1/910Eにジャンプして、[$7E:AAn2]を-1する。つまり行動異常の値が-1される。
一方、行動異常による移動パターン補正が入らないパターンだと、[$00:1A20+40m](敵キャラデータ00 移動パターン)をロードする。
$C1/910D~$C1/910Eで、+1して-1することになるから、結局、$C1/910Fの時点のAは移動パターンの値そのままである。
ということから、$C1/910Fの時点のAの値をまとめると、
このようになる。
行動異常$8~$Eの状態の敵は、敵に元から設定された移動パターンの値は関係なく、該当の行動異常に設定された移動パターンに固定されてしまう、ということである。
さて、$C1/910Fでこの移動パターンの値が[$00:4202]に書き込まれて、符号付8bit x 8bitの計算になる。
$C1/910F STA $4202 [$00:4202] ;Aを[$00:4202]に書き込み $C1/9112 LDA #$51 ;Aに$51(81)をロード $C1/9114 STA $4203 [$00:4203] ;Aを[$00:4203]に書き込み $C1/9117 LDA $11 [$00:0311] ;Aに[$00:0311]をロード $C1/9119 ASL A ;Aを算術左シフト *2 $C1/911A ASL A ;Aを算術左シフト *2 $C1/911B ASL A ;Aを算術左シフト *2 $C1/911C ADC $11 [$00:0311] ;A + [$00:0311] $C1/911E ADC $10 [$00:0310] ;A + [$00:0310] $C1/9120 STA $12 [$00:0312] ;Aを[$00:0312]に書き込み $C1/9122 STZ $13 [$00:0313] ;[$00:0313]に$00を書き込み $C1/9124 REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/9126 LDA $D50060[$D5:0060] ;Aに[$D5:0061][$D5:0060]をロード $644B $C1/912A ADC #$0080 ;A + $0080 $C1/912D ADC $12 [$00:0312] ;A + [$00:0312] $C1/912F ADC $4216 [$00:4216] ;A + [$00:4217][$00:4216](移動パターン * $51) $C1/9132 TAX ;Aの値をXレジスタに転送 $C1/9133 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/9135 LDA $D50000,x ;Aに[$D50000,x](行動パターン)をロード $C1/9139 RTS ;サブルーチン戻り
まとめると、
[$00:0312] = [$00:0311](味方位置Y座標)*8 + [$00:0311](味方位置Y座標) + [$00:0310](味方位置X座標)
[$D5:0061][$D5:0060]($644B) + $0080 + [$00:0312] + 移動パターン * $51
に、$D50000を加算したアドレスが$C1/9135でロードされるのだが、これが該当の敵の行動パターンにあたる。
まず、[$00:0312]は何を表しているのか考えてみよう。
移動パターンは$00~$28の19種類あり、1つのパターンが9×9マスに対応した$51バイト(81バイト)の値である。
9バイトずつ区切ると9行の文字列になり、9×9マスと合致する。
[$00:0310][$00:0311]には、上図で左上を原点としたX座標とY座標が入っている。
Y座標[$00:0311]を9倍すればちょうど上からの該当の位置の列の値となり、これにX座標[$00:0310]を加算すると、ぴったり目的の味方位置になる、という計算が、
[$00:0312] = [$00:0311](味方位置Y座標)*8 + [$00:0311](味方位置Y座標) + [$00:0310](味方位置X座標)
である。
9倍の計算を、[$00:0311] × 8 + [$00:0311]で行っているのである。65C816には掛け算機能がないが、符号付8bit x 8bitのひと手間かかる計算方法より、ビットシフトと加算を使った方が速く済むということだろう。
ということで、9×9マスの左上基準で[$00:0312]を加算すると味方の座標位置になることがわかった。
あとは、移動パターンの開始アドレスを呼び出して、[$00:0312]を加算すれば行動パターンが算出できる。
その計算が
[$D5:0061][$D5:0060]($644B) + $0080 + [$00:0312] + 移動パターン * $51
である。
[$D5:0061][$D5:0060]($644B) + $0080
が、敵移動データ00の開始位置$D5:64CBのアドレス部分「$64CB」である。
ここに、移動パターン * $51を加算すれば、該当の敵の移動パターン開始アドレスが求められる。
最後に[$00:0312]を加算して、$C1/9135でロードされるのが、行動パターンとなる。
ここまででようやく、敵移動・向き変え時の行動パターンが求められたが、さらに、この行動パターンから、どういう移動をするかの分岐がある。
ここではまず例として、先程のナムキャット戦について見てみよう。
ナムキャットの移動パターンはID$00である。
移動パターンID$00のデータ$51バイトを、9バイト区切りで並べると以下のようになる。値により色分けした。
| ID$00 | ||||||||
|---|---|---|---|---|---|---|---|---|
| 11 | 0B | 0B | 0B | 0B | 0B | 0B | 0B | 12 |
| 0A | 12 | 12 | 12 | 12 | 12 | 12 | 12 | 09 |
| 0A | 12 | 12 | 12 | 12 | 12 | 09 | 09 | 09 |
| 0A | 12 | 12 | 12 | 12 | 12 | 12 | 12 | 12 |
| 0A | 12 | 12 | 12 | F0 | 0B | 08 | 08 | 08 |
| 0A | 12 | 12 | 12 | 08 | 09 | 08 | 08 | 08 |
| 0A | 12 | 12 | 12 | 08 | 09 | 09 | 08 | 08 |
| 0A | 12 | 0A | 12 | 09 | 09 | 09 | 09 | 08 |
| 12 | 08 | 0A | 09 | 09 | 09 | 09 | 08 | 09 |
高原との相対位置は下のようになっており、ナムキャットは初期配置で右下向きだから、ナムキャットの行動パターンは$08ということになる。
$C1/9139でAに$08が入った状態で、続きの処理を見てみよう。
(他パターンについて全部説明すると長くなるので別ページに分けてある)
$C1/8F6E CMP #$14 ;A($08)と$14を減算比較(ステータスレジスタ変更のみ) $C1/8F70 BCC $02 [$8F74] ;キャリーフラグが立っていないとき[$8F74]分岐 ;キャリーフラグON $C1/8F72 LDA #$0F ;Aに$0Fをロード ;キャリーフラグOFF $C1/8F74 JSR $8F8D [$C1:8F8D] ;[$C1:8F8D]へジャンプ
$C1/8F6E~$C1/8F70のキャリーフラグ分岐は、
Aに行動パターンを入れたまま$C1/8F8DへAに$0Fを入れて$C1/8F8Dへと、いうことである。
ということは、行動パターンが$14以上と$0Fは処理がこの先同一という意味になる。
実際、行動パターンは$13までしかない。
また、行動パターン$0Fは後で説明するとおり、「何もしない」である。
$C1/8F8D REP #$20 ;Aを16bit幅に変更、Mフラグをクリア $C1/8F8F AND #$001F ;Aと$001Fで論理積 $C1/8F92 ASL A ;Aを算術左シフト *2 $C1/8F93 ADC #$8E1E ;A + $8E1E $C1/8F96 TAX ;Aの値をXレジスタに転送(A:8E2E) $C1/8F97 LDA $C10000,x[$C1:8E2E] ;Aに[$C1:8E2F][$C1:8E2E]をロード $C1/8F9B STA $1C [$00:031C] ;Aを[$00:031D][$00:031C]に書き込み $C1/8F9D LDX $AC [$00:03AC] ;Xに[$00:03AD][$00:03AC]をロード $C1/8F9F SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/8FA1 JMP ($031C)[$C1:901E] ;[$C1:901E]へジャンプ(レジスタをスタックに積まない) $C1/901E LDA $0004,x[$00:1B04] ;Aに[$00:1B04](敵番号1の向き)をロード $C1/9021 BIT #$40 ;Aと$40で論理積(ステータスフラグ変更のみ) $C1/9023 BEQ $AF [$8FD4] ;ゼロフラグが立っているとき[$8FD4]分岐 ;ゼロフラグOFF(左下$40、左上$C0) $C1/9025 BRA $CD [$8FF4] ;フラグにかかわりなく常に分岐[$8FF4] ;ゼロフラグON(右下$00、右上$80) $C1/8FD4 LDY $0002,x[$00:1B02] ;Yに[$00:1B02]をロード $C1/8FD7 LDA $002F,y[$00:1A2F] ;Aに[$00:1A2F](敵データ15 タイプ)をロード $C1/8FDA BIT #$04 ;Aと$04で論理積(ステータスフラグ変更のみ) $C1/8FDC BEQ $01 [$8FDF] ;ゼロフラグが立っているとき[$8FDF]分岐 ;ゼロフラグON OBJECTではない $C1/8FDF JSR $E393 [$C1:E393] ;[$C1:E393]へジャンプ
$C1/8F96の時点のAの値は、
行動パターン($00~$13)*2 + $8E1E
だから、$C1/8F9Bでロードする値は、[$C1:8E1F][$C1:8E1E] ~ [$C1:8E45][$C1:8E44]の20パターンになる。
とりあえず、行動パターン$08のまま進めてみると、[$C1:8E2F][$C1:8E2E]($901E)をロードし、[$00:031D][$00:031C]に書き込んでいる。
これが、$C1/8FA1でのジャンプ先、[$C1:901E]の「901E」部分になる。
$C1/901Eでは敵の向きをロードしている。
$40と論理積を取って分岐判定の場合、要するに右向きか左向きかの判定である。
ナムキャットは右向きなのでゼロフラグON、$C1/8FD4にジャンプする。
もし左向きだったら、$C1/8FF4にジャンプである。
実は、$C1/8FD4は、行動パターン$04の処理に合流である。
また、$C1/8FF4は、行動パターン$06の処理に合流である。
後でまとめるが、行動パターン$04の処理は「右に移動」で、行動パターン$06の処理は「左に移動」である。
ここからわかるが、行動パターン$08は、「敵が向いている方向の左または右に移動」という処理なのである。
ジャンプ先の$C1/8FD4では、[$00:1A2F](敵データ15 タイプ)と$04の論理積を取ってゼロフラグ判定なので、敵がOBJECT(しょく台や岩などの障害物)かどうかの判定である。
OBJECTは移動しないので、もしOBJECTならここで移動処理を終了する。
そうでない場合、つまりゼロフラグが立つならOBJECTではないので、$C1/E393にジャンプする。
この先が行動パターン$04「右に移動」の処理である。
$C1/E393 LDX $AC [$00:03AC] ;Xに[$00:03AC]をロード $C1/E395 LDA $0004,x[$00:1B04] ;Aに[$00:1B04](向き)をロード $C1/E398 AND #$BF ;Aと$BF(%1011 1111)で論理積 $C1/E39A STA $0004,x[$00:1B04] ;Aを[$00:1B04]に書き込み $C1/E39D LDA $000A,x[$00:1B0A] ;Aに[$00:1B0A](X座標)をロード $C1/E3A0 CMP #$06 ;Aと$06を減算比較(ステータスレジスタ変更のみ) $C1/E3A2 BEQ $C7 [$E36B] ;ゼロフラグが立っているとき[$E36B]分岐 ;ゼロフラグOFF 右に移動可能なX座標位置 $C1/E3A4 INC A ;Aをインクリメント +1 $C1/E3A5 STA $0008,x[$00:1B08] ;Aを[$00:1B08](計算用X座標)に書き込み $C1/E3A8 LDA $000B,x[$00:1B0B] ;Aに[$00:1B0B](Y座標)をロード $C1/E3AB STA $0009,x[$00:1B09] ;Aを[$00:1B09](計算用Y座標)に書き込み $C1/E3AE JSR $41F2 [$C1:41F2] ;[$C1:41F2]へジャンプ ;ゼロフラグON X座標が$06なので右移動不可 $C1/E36B JSR $E7BD [$C1:E7BD] ;[$C1:E7BD]へジャンプ
$C1/E393~から、移動先の判定を行う。
$C1/E393~$C1/E39Aだが、向きの上2ビット目を削除という処理に等しい。つまり左向きだったら左向きではない状態、右向きに強制的に変更という意味である。
とはいえ、行動パターン$08だと、行動パターン$04の処理に入る前に右向き判定済みなので、ここで向きの値が変動することはない。
$C1/E39Dで敵のX座標をロードし、$06と減算比較してゼロフラグ判定だが、ここでゼロフラグが立つのはX座標が$06の場合、つまり戦闘フィールドの右隅にいる場合である。
この時はこれ以上右に移動できないから、別処理に進むのだが、ここではとりあえずナムキャットが原点(0,0)にいる前提で話を続ける。
右に移動可能であれば、X座標を+1した値を、[$00:1B08](計算用X座標)に書き込む。
Y座標はそのまま、[$00:1B09](計算用Y座標)に書き込む。
つまり、X座標のみ+1、右に1マス移動という処理をするということである。
ただ、移動先に移動可能かどうかを判定しなければならない。
その判定が次からである。
$C1/41F2 LDA #$10 ;Aに$10をロード $C1/41F4 STA $13 [$00:0313] ;A($10)を[$00:0313]に書き込み $C1/41F6 LDA $0001,x[$00:1B01] ;Aに[$00:1B01](戦闘状態)をロード $C1/41F9 CMP #$20 ;Aと$20を減算比較(ステータスレジスタ変更のみ) $C1/41FB BNE $02 [$41FF] ;ゼロフラグが立っていないとき[$41FF]分岐 $C1/41FF TXA ;Xレジスタの値(敵番号)をAレジスタに転送 $C1/4200 LSR A ;Aを論理右シフト (/2) $C1/4201 LSR A ;Aを論理右シフト (/2) $C1/4202 LSR A ;Aを論理右シフト (/2) $C1/4203 LSR A ;Aを論理右シフト (/2) $C1/4204 INC A ;Aをインクリメント +1 $C1/4205 ORA $13 [$00:0313] ;Aと[$00:0313]($10)で論理和 $C1/4207 STA $13 [$00:0313] ;A($11)を[$00:0313]に書き込み $C1/4209 JSR $4260 [$C1:4260] ;[$C1:4260]へジャンプ $C1/4260 LDY $0002,x[$00:1B02] ;Yに[$00:1B02]をロード $C1/4263 LDA $0004,y[$00:1A04] ;Aに[$00:1A04](横幅)をロード $C1/4266 STA $0A [$00:030A] ;Aを[$00:030A]に書き込み $C1/4268 LDA $0005,y[$00:1A05] ;Aに[$00:1A05](縦幅)をロード $C1/426B STA $0B [$00:030B] ;Aを[$00:030B]に書き込み $C1/426D STA $09 [$00:0309] ;Aを[$00:0309]に書き込み $C1/426F LDA #$08 ;Aに$08をロード $C1/4271 SEC ;キャリーフラグON $C1/4272 SBC $0A [$00:030A] ;A($08) - [$00:030A](横幅) $C1/4274 STA $12 [$00:0312] ;A($08-横幅)を[$00:0312]に書き込み $C1/4276 RTS ;サブルーチン戻り
まず準備として、$C1/41F2~$C1/4209の処理で、[$00:0313]に敵番号+1と$10の論理和を入れる。
これは後々、戦闘フィールド7×7マスの状態$00:04C8~$00:04FEの判定に使う値である。
敵が1人だけの場合は[$00:0313]に$11が入る。
$C1/4260からはメモリアドレスに以下の値が入る。
| アドレス | 値 |
|---|---|
[$00:030A] | 敵の横幅 |
[$00:030B],[$00:0309] | 敵の縦幅 |
[$00:0312] | $08-横幅 |
$C1/420C LDA $0008,x[$00:1B08] ;Aに[$00:1B08](計算用X座標)をロード $C1/420F CLC ;キャリーフラグクリア $C1/4210 ADC $0A [$00:030A] ;A + [$00:030A](横幅) $C1/4212 CMP #$08 ;Aと$08を減算比較(ステータスレジスタ変更のみ) $C1/4214 BCS $47 [$425D] ;キャリーフラグが立っているとき[$425D]分岐 ;キャリーフラグOFF (1マス移動しても敵横幅がフィールド外に出ない) $C1/4216 LDA $0009,x[$00:1B09] ;Aに[$00:1B09](計算用Y座標)をロード $C1/4219 CLC ;キャリーフラグクリア $C1/421A ADC $0B [$00:030B] ;A + [$00:030B](縦幅) $C1/421C CMP #$08 ;Aと$08を減算比較(ステータスレジスタ変更のみ) $C1/421E BCS $3D [$425D] ;キャリーフラグが立っているとき[$425D]分岐 ;キャリーフラグOFF (移動しても敵縦幅がフィールド外に出ない) $C1/4220 LDA $0009,x[$00:1B09] ;Aに[$00:1B09](計算用Y座標)をロード $C1/4223 ASL A ;Aを算術左シフト *2 $C1/4224 ASL A ;Aを算術左シフト *2 $C1/4225 ASL A ;Aを算術左シフト *2 $C1/4226 ADC $0008,x[$00:1B08] ;A + [$00:1B08](計算用X座標) $C1/4229 STA $10 [$00:0310] ;A(座標1バイト表示)を[$00:0310]に書き込み $C1/422B STZ $11 [$00:0311] ;[$00:0311]に$00を書き込み $C1/422D LDY $10 [$00:0310] ;Yに[$00:0310](座標1バイト表示)をロード
移動先座標が入った[$00:1B08]と[$00:1B09]に、それぞれ敵の横幅と縦幅を加算し、$08を減算することで、負になるかどうか、つまり、移動することで敵の横幅・縦幅分がフィールド外にはみ出ることはないかどうかの判定を$C1/420C~$C1/4220で行っている。
はみ出すなら移動はできないので、$C1/425Dにジャンプするが、
;キャリーフラグON(移動でフィールド外に出るので移動できない) $C1/425D ORA #$FF ;Aと$FFで論理和 $C1/425F RTS ;サブルーチン戻り
ここがジャンプ先でサブルーチンを抜ける。つまりここで移動は行わないことが決まる。
この先も$C1/425Dにジャンプする分岐があるが、いずれも移動不可でサブルーチンを抜けるということである。
ただ、$C1/425Fでサブルーチンを抜けると何もしない、ということではなく、行動パターン$0C(ランダム移動)を判定し、これでも移動できなければ行動パターン$13(ランダム向き変え)を行って処理終了となるのだが、これも後で説明する。
移動しても敵の横幅・縦幅分がフィールド内に収まるのなら、$C1/4220~に進む。
ここでは移動先座標の、X座標を下3ビット、Y座標をその上の3ビットに収めた数値を計算して、[$00:0310]に書き込んでいる。
この先で、$00:04C8~$00:04FEの戦闘フィールドを確認していくが、原点にあたる$00:04C8に[$00:0310]を加算すると、ちょうど敵の移動先座標となる仕組みである。
;ループ処理 ;$00:04C8~$00:04FEの戦闘フィールドの値を確認する $C1/422F LDA $0A [$00:030A] A:9001 X:1B00 Y:0001 P:envMxdIzc;Aに[$00:030A](横幅)をロード $C1/4231 STA $08 [$00:0308] A:9001 X:1B00 Y:0001 P:envMxdIzc;A(横幅)を[$00:0308]に書き込み ;横幅ループここから $C1/4233 LDA $04C8,y ;Aに[$00:04C8+y](移動先のマス)をロード $C1/4236 INY ;Yをインクリメント +1 $C1/4237 AND #$1F ;Aと$1Fで論理積 $C1/4239 CMP $13 [$00:0313] ;Aと[$00:0313]($11)を減算比較(ステータスレジスタ変更のみ) $C1/423B BEQ $04 [$4241] ;ゼロフラグが立っているとき[$4241]分岐 ;ゼロフラグOFF 移動先マスに自身はいない $C1/423D BIT #$0F ;Aと$0Fで論理積(ステータスフラグ変更のみ) $C1/423F BNE $1C [$425D] ;ゼロフラグが立っていないとき[$425D]分岐(サブルーチン抜ける) ;$C1/423BでゼロフラグON $C1/4241 DEC $08 [$00:0308] ;[$00:0308](横幅)をデクリメント -1 $C1/4243 BNE $EE [$4233] ;ゼロフラグが立っていないとき[$4233]分岐 ;横幅ループここまで $C1/4245 REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/4247 TYA ;Yレジスタの値をAレジスタに転送 $C1/4248 ADC $12 [$00:0312] ;A + [$00:0312]($08-横幅) $C1/424A AND #$00FF ;Aと$00FFで論理積 $C1/424D TAY ;Aの値をYレジスタに転送 $C1/424E SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/4250 DEC $09 [$00:0309] ;[$00:0309](縦幅)をデクリメント -1 $C1/4252 BNE $DB [$422F] ;ゼロフラグが立っていないとき[$422F]分岐 ;ループ処理ここまで $C1/4254 JSR $4277 [$C1:4277] A:0019 X:1B00 Y:0019 P:envMxdIZc;[$C1:4277]へジャンプ
上のループ処理で、フィールド$00:04C8~$00:04FEの移動先アドレスに、他キャラがいないかを確認している。
1マス移動するだけなので、敵サイズによっては、移動先に既に自身のアドレスがある場合もあるが、この場合は移動可能なので問題ない。
移動可能なのは、移動先に何もない($00)か、ダメージフィールドだけが入っている時、または$11(自分自身の一部)または$11にダメージフィールド分を加算した値が入っている場合。
$C1/423Bのゼロフラグ判定は、移動先に自分自身が入っているかどうかの判定である。
$C1/423Fのゼロフラグ判定は、移動先に自分自身以外のキャラがいるかどうかのため、もし他キャラがいる(ゼロフラグOFF)なら、移動不可でサブルーチンを抜ける($C1/425Dへ)。
こうして、ループ処理で自身の移動先マスを全てチェックし、$C1/423Fのゼロフラグ判定で$C1/425Dに抜けない限り、最終的にループを抜けて$C1/4254に到達する。
これで、移動先マスに移動可能なことが確定である。
$C1/4277 LDA $000B,x[$00:1B0B] ;Aに[$00:1B0B](敵Y座標)をロード $C1/427A ASL A ;Aを算術左シフト *2 $C1/427B ASL A ;Aを算術左シフト *2 $C1/427C ASL A ;Aを算術左シフト *2 $C1/427D ADC $000A,x[$00:1B0A] ;A + [$00:1B0A](敵X座標) $C1/4280 STA $14 [$00:0314] ;A(移動前敵座標1バイト)を[$00:0314]に書き込み $C1/4282 STZ $15 [$00:0315] ;[$00:0315]に$00を書き込み $C1/4284 LDY $14 [$00:0314] ;Yに[$00:0314]をロード $C1/4286 LDA $0B [$00:030B] ;Aに[$00:030B]をロード $C1/4288 STA $09 [$00:0309] ;Aを[$00:0309]に書き込み ;$00:04C8~$00:04FEの戦闘フィールド ;移動前のマスから敵位置のみ削除(ダメージフィールドある場合は残す) ;ループ処理 $C1/428A LDA $0A [$00:030A] ;Aに[$00:030A](横幅)をロード $C1/428C STA $08 [$00:0308] ;Aを[$00:0308]に書き込み $C1/428E LDA $04C8,y[$00:04C8] ;Aに[$00:04C8+y]をロード $C1/4291 AND #$E0 ;Aと$E0で論理積 $C1/4293 STA $04C8,y[$00:04C8] ;Aを[$00:04C8+y]に書き込み $C1/4296 INY ;Yをインクリメント +1 $C1/4297 DEC $08 [$00:0308] ;[$00:0308]をデクリメント -1 $C1/4299 BNE $F3 [$428E] ;ゼロフラグが立っていないとき[$428E]分岐 $C1/429B REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/429D TYA ;Yレジスタの値をAレジスタに転送 $C1/429E ADC $12 [$00:0312] ;A + [$00:0312] $C1/42A0 AND #$00FF ;Aと$00FFで論理積 $C1/42A3 TAY ;Aの値をYレジスタに転送 $C1/42A4 SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/42A6 DEC $09 [$00:0309] ;[$00:0309]をデクリメント -1 $C1/42A8 BNE $E0 [$428A] ;ゼロフラグが立っていないとき[$428A]分岐 ;ループ処理ここまで $C1/42AA RTS ;サブルーチン戻り $C1/4257 JSR $42AB [$C1:42AB] ;[$C1:42AB]へジャンプ
移動が確定したので、ループ処理で、移動前のマスから敵位置のみ削除する。
$C1/428E~$C1/4293で、マスの値と$E0で論理積を取ることにより、ダメージフィールドの値だけ残してキャラを削除できる。
$C1/42AB LDA $0B [$00:030B] ;Aに[$00:030B]をロード $C1/42AD STA $09 [$00:0309] ;Aを[$00:0309]に書き込み $C1/42AF LDY $10 [$00:0310] ;Yに[$00:0310]をロード ;$00:04C8~$00:04FEの戦闘フィールド ;移動先のマスに敵の値書き込み ;ループ処理 $C1/42B1 LDA $0A [$00:030A] ;Aに[$00:030A]をロード $C1/42B3 STA $08 [$00:0308] ;Aを[$00:0308]に書き込み $C1/42B5 LDA $04C8,y[$00:04C9] ;Aに[$00:04C9]をロード $C1/42B8 AND #$E0 ;Aと$E0で論理積 $C1/42BA ORA $13 [$00:0313] ;Aと[$00:0313]で論理和 $C1/42BC STA $04C8,y[$00:04C9] ;Aを[$00:04C9]に書き込み $C1/42BF INY ;Yをインクリメント +1 $C1/42C0 DEC $08 [$00:0308] ;[$00:0308]をデクリメント -1 $C1/42C2 BNE $F1 [$42B5] ;ゼロフラグが立っていないとき[$42B5]分岐 $C1/42C4 REP #$21 ;Aを16bit幅に変更、キャリーフラグクリア $C1/42C6 TYA ;Yレジスタの値をAレジスタに転送 $C1/42C7 ADC $12 [$00:0312] ;A + [$00:0312] $C1/42C9 AND #$00FF ;Aと$00FFで論理積 $C1/42CC TAY ;Aの値をYレジスタに転送 $C1/42CD SEP #$20 ;MフラグON Aレジスタは8bit幅 $C1/42CF DEC $09 [$00:0309] ;[$00:0309]をデクリメント -1 $C1/42D1 BNE $DE [$42B1] ;ゼロフラグが立っていないとき[$42B1]分岐 ;ループ処理ここまで $C1/42D3 RTS ;サブルーチン戻り $C1/425A AND #$00 ;Aと$00で論理積 $C1/425C RTS ;サブルーチン戻り
最後に、移動先のマスに敵の値を論理和で書き込む。
既にダメージフィールドがある場合、単純に上書きではフィールドの値が消されてしまうため、論理和である。
全てのマスにループ処理で書き込んで、移動処理終了となる。
これで、$C1/425AでAに$00を書き込み、サブルーチンを抜けるのだが、移動不可で$C1/425Dからサブルーチンを抜けた場合は、Aに$FFを書き込んでからサブルーチンを抜けていた。
その差が次の処理で出る。
$C1/E3B1 BNE $B8 [$E36B] ;ゼロフラグが立っていないとき[$E36B]分岐 ;ゼロフラグON(移動成功) $C1/E3B3 BRL $0000 [$E3B6] ;フラグにかかわりなく常に分岐[$E3B6] $C1/E3B6 LDA #$08 ;Aに$08をロード $C1/E3B8 STA $63 [$00:0363] ;Aを[$00:0363]に書き込み $C1/E3BA LDA #$80 ;Aに$80をロード $C1/E3BC STA $0005,x[$00:1B05] ;Aを[$00:1B05](技関係状態)に書き込み $C1/E3BF LDA $0001,x[$00:1B01] ;Aに[$00:1B01]をロード $C1/E3C2 BIT #$20 ;Aと$20で論理積(ステータスフラグ変更のみ) $C1/E3C4 BEQ $17 [$E3DD] ;ゼロフラグが立っているとき[$E3DD]分岐 $C1/E3C6 JSR $E834 [$C1:E834] ;[$C1:E834]へジャンプ
$C1/E3B1で、移動したかどうかで分岐になる。
ゼロフラグが立つ時は移動に成功したことになり、敵の[$00:1B05](技関係状態)に$80を書き込んで、移動状態であることを記録する。
$C1/E36B JSR $E7BD [$C1:E7BD] ;[$C1:E7BD]へジャンプ
ひとまず移動についての紹介はここまでとする。
上で紹介したのはあくまでも行動パターンの中のひとつに過ぎない。
次ページで、行動パターン別にどういう挙動を取るかを紹介する。