TOP > プログラミング関係解説&調査 > 敵ターンにおける行動選択 > 敵の移動・向き変え(2)

敵ターンにおける行動選択 > 敵の移動・向き変え(2)

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

前ページの続き。

行動パターン別の挙動

ここで、$C1/8FA1まで話を戻し、行動パターン別にどういう挙動を取るかを紹介する。

$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レジスタに転送
$C1/8F97 LDA $C10000,x           ;Aに[$C10000,x+1][$C10000,x]をロード
$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:[$00:031C]]へジャンプ(レジスタをスタックに積まない)

$C1/8F96の時点のAの値は、

行動パターン($00~$13)*2 + $8E1E

だから、$C1/8F9Bでロードする値は、[$C1:8E1F][$C1:8E1E][$C1:8E45][$C1:8E44]の20パターンになる。
前ページでは、20パターンの中で行動パターン$08を紹介しただけなので、他について説明する。

[$C1:8E1F][$C1:8E1E][$C1:8E45][$C1:8E44]の値から、$C1/8FA1JMP ($031C)での飛び先を計算してみると、以下のようになった。

行動パターンジャンプ先
$00$C1/8FA4
$01$C1/8FB0
$02$C1/8FBC
$03$C1/8FC8
$04$C1/8FD4
$05$C1/8FE4
$06$C1/8FF4
$07$C1/9004
$08$C1/901E
$09$C1/9027
$0A$C1/9030
$0B$C1/9039
$0C$C1/9047
$0D$C1/9068
$0E$C1/9068
$0F$C1/9068
$10$C1/9069
$11$C1/906B
$12$C1/906D
$13$C1/908E

$C1/8FA4$C1/908Eにサブルーチン開始位置がまとまっている。
また、$0D$0Fのジャンプ先はどれも$C1/9068だから、処理が同一ということになる。
前ページの通り、行動パターンに$14以上が指定されていたら$0Fとするので、$0D$0F$14以上の処理は同一ということである。

行動パターン$04$07

では、$C1/8FA4~がどうなっているのかを見ていくが、アドレス順ではなく、わかりやすい順に説明していく。
まず、行動パターン$04~行動パターン$07について説明する。
というのは、他の行動パターンは、分岐後に行動パターン$04$07にジャンプすることが多い。
何故なら、行動パターン$04$07はそれぞれ、右・下・左・上に1マス移動、という、各方向への移動処理だからである。

;行動パターン$04 右に1マス移動
$C1/8FD4 LDY $0002,x             ;Yに[$00:1A02]をロード
$C1/8FD7 LDA $002F,y             ;Aに[$00:1A2F](タイプ)をロード
$C1/8FDA BIT #$04                ;Aと$04で論理積(ステータスフラグ変更のみ)
$C1/8FDC BEQ $01    [$8FDF]      ;ゼロフラグが立っているとき[$8FDF]分岐
;ゼロフラグOFF
$C1/8FDE RTS                     ;サブルーチン戻り
;ゼロフラグON
$C1/8FDF JSR $E393  [$C1:E393]   ;[$C1:E393]へジャンプ
$C1/8FE2 BRA $30    [$9014]      ;フラグにかかわりなく常に分岐[$9014]

;行動パターン$05 下に1マス移動
$C1/8FE4 LDY $0002,x             ;Yに[$00:1A02]をロード
$C1/8FE7 LDA $002F,y             ;Aに[$00:1A2F](タイプ)をロード
$C1/8FEA BIT #$04                ;Aと$04で論理積(ステータスフラグ変更のみ)
$C1/8FEC BEQ $01    [$8FEF]      ;ゼロフラグが立っているとき[$8FEF]分岐
;ゼロフラグOFF
$C1/8FEE RTS                     ;サブルーチン戻り
;ゼロフラグON
$C1/8FEF JSR $E348  [$C1:E348]   ;[$C1:E348]へジャンプ
$C1/8FF2 BRA $20    [$9014]      ;フラグにかかわりなく常に分岐[$9014]

;行動パターン$06 左に1マス移動
$C1/8FF4 LDY $0002,x             ;Yに[$00:1A02]をロード
$C1/8FF7 LDA $002F,y             ;Aに[$00:1A2F](タイプ)をロード
$C1/8FFA BIT #$04                ;Aと$04で論理積(ステータスフラグ変更のみ)
$C1/8FFC BEQ $01    [$8FFF]      ;ゼロフラグが立っているとき[$8FFF]分岐
;ゼロフラグOFF
$C1/8FFE RTS                     ;サブルーチン戻り
;ゼロフラグON
$C1/8FFF JSR $E372  [$C1:E372]   ;[$C1:E372]へジャンプ
$C1/9002 BRA $10    [$9014]      ;フラグにかかわりなく常に分岐[$9014]

;行動パターン$07 上に1マス移動
$C1/9004 LDY $0002,x             ;Yに[$00:1Bn2]をロード
$C1/9007 LDA $002F,y             ;Aに[$00:1A2F](タイプ)をロード
$C1/900A BIT #$04                ;Aと$04で論理積(ステータスフラグ変更のみ)
$C1/900C BEQ $01    [$900F]      ;ゼロフラグが立っているとき[$900F]分岐
;ゼロフラグOFF
$C1/900E RTS                     ;サブルーチン戻り
;ゼロフラグON
$C1/900F JSR $E327  [$C1:E327]   ;[$C1:E327]へジャンプ
$C1/9012 BRA $00    [$9014]      ;フラグにかかわりなく常に分岐[$9014]

;分岐先
$C1/9014 LDX $AC                 ;Xに[$00:03AC]をロード
$C1/9016 LDA $0005,x             ;Aに[$00:1Bn5](技関係状態)をロード
$C1/9019 BMI $02    [$901D]      ;ネガティブフラグが立っているとき[$901D]分岐
;ネガティブフラグOFF
$C1/901B BRA $3C    [$9059]      ;フラグにかかわりなく常に分岐[$9059]
;ネガティブフラグON
$C1/901D RTS                     ;サブルーチン戻り

4パターンとも、敵タイプがOBJECT(移動不可)でないのなら別処理へ飛んでいる。
それぞれのジャンプ先で、移動処理を行う。

行動パターン挙動ジャンプ先
$04右に1マス移動$C1/E393
$05下に1マス移動$C1/E348
$06左に1マス移動$C1/E372
$07上に1マス移動$C1/E327
;上に1マス移動
$C1/E327 LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/E329 LDA $0004,x             ;Aに[$00:1Bn4](向き)をロード
$C1/E32C ORA #$80                ;Aと$80で論理和
$C1/E32E STA $0004,x             ;Aを[$00:1Bn4](向き)に書き込み
$C1/E331 LDA $000B,x             ;Aに[$00:1BnB](敵Y座標)をロード
$C1/E334 BEQ $35    [$E36B]      ;ゼロフラグが立っているとき[$E36B]分岐
$C1/E336 DEC A                   ;Aをデクリメント -1
$C1/E337 STA $0009,x             ;Aを[$00:1Bn9](敵Y座標計算値)に書き込み
$C1/E33A LDA $000A,x             ;Aに[$00:1BnA](敵X座標)をロード
$C1/E33D STA $0008,x             ;Aを[$00:1Bn8](敵X座標計算値)に書き込み
$C1/E340 JSR $41F2  [$C1:41F2]   ;[$C1:41F2]へジャンプ
;(移動処理)
$C1/E343 BNE $26    [$E36B]      ;ゼロフラグが立っていないとき[$E36B]分岐
$C1/E345 BRL $006E  [$E3B6]      ;フラグにかかわりなく常に分岐[$E3B6]

;下に1マス移動
$C1/E348 LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/E34A LDA $0004,x             ;Aに[$00:1Bn4](向き)をロード
$C1/E34D AND #$7F                ;Aと$7Fで論理積
$C1/E34F STA $0004,x             ;Aを[$00:1Bn4](向き)に書き込み
$C1/E352 LDA $000B,x             ;Aに[$00:1BnB](敵Y座標)をロード
$C1/E355 CMP #$06                ;Aと$06を減算比較(ステータスレジスタ変更のみ)
$C1/E357 BEQ $12    [$E36B]      ;ゼロフラグが立っているとき[$E36B]分岐
$C1/E359 INC A                   ;Aをインクリメント +1
$C1/E35A STA $0009,x             ;Aを[$00:1Bn9](敵Y座標計算値)に書き込み
$C1/E35D LDA $000A,x             ;Aに[$00:1BnA](敵X座標)をロード
$C1/E360 STA $0008,x             ;Aを[$00:1Bn8](敵X座標計算値)に書き込み
$C1/E363 JSR $41F2  [$C1:41F2]   ;[$C1:41F2]へジャンプ
;(移動処理)
$C1/E366 BNE $03    [$E36B]      ;ゼロフラグが立っていないとき[$E36B]分岐
$C1/E368 BRL $004B  [$E3B6]      ;フラグにかかわりなく常に分岐[$E3B6]
$C1/E36B JSR $E7BD  [$C1:E7BD]   ;[$C1:E7BD]へジャンプ
$C1/E36E JSR $E414  [$C1:E414]   ;[$C1:E414]へジャンプ
$C1/E371 RTS                     ;サブルーチン戻り

;左に1マス移動
$C1/E372 LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/E374 LDA $0004,x             ;Aに[$00:1Bn4](向き)をロード
$C1/E377 ORA #$40                ;Aと$40で論理和
$C1/E379 STA $0004,x             ;Aを[$00:1Bn4](向き)に書き込み
$C1/E37C LDA $000A,x             ;Aに[$00:1BnA](敵X座標)ををロード
$C1/E37F BEQ $EA    [$E36B]      ;ゼロフラグが立っているとき[$E36B]分岐
$C1/E381 DEC A                   ;Aをデクリメント -1
$C1/E382 STA $0008,x             ;Aを[$00:1Bn8](敵X座標計算値)に書き込み
$C1/E385 LDA $000B,x             ;Aに[$00:1BnB](敵Y座標)をロード
$C1/E388 STA $0009,x             ;Aを[$00:1Bn9](敵Y座標計算値)に書き込み
$C1/E38B JSR $41F2  [$C1:41F2]   ;[$C1:41F2]へジャンプ
;(移動処理)
$C1/E38E BNE $DB    [$E36B]      ;ゼロフラグが立っていないとき[$E36B]分岐
$C1/E390 BRL $0023  [$E3B6]      ;フラグにかかわりなく常に分岐[$E3B6]

;右に1マス移動
$C1/E393 LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/E395 LDA $0004,x             ;Aに[$00:1Bn4](向き)をロード
$C1/E398 AND #$BF                ;Aと$BFで論理積
$C1/E39A STA $0004,x             ;Aを[$00:1Bn4](向き)書き込み
$C1/E39D LDA $000A,x             ;Aに[$00:1BnA](敵X座標)ををロード
$C1/E3A0 CMP #$06                ;Aと$06を減算比較(ステータスレジスタ変更のみ)
$C1/E3A2 BEQ $C7    [$E36B]      ;ゼロフラグが立っているとき[$E36B]分岐
$C1/E3A4 INC A                   ;Aをインクリメント +1
$C1/E3A5 STA $0008,x             ;Aを[$00:1Bn8](敵X座標計算値)に書き込み
$C1/E3A8 LDA $000B,x             ;Aに[$00:1BnB](敵Y座標)をロード
$C1/E3AB STA $0009,x             ;Aを[$00:1Bn9](敵Y座標計算値)に書き込み
$C1/E3AE JSR $41F2  [$C1:41F2]   ;[$C1:41F2]へジャンプ
;(移動処理)
$C1/E3B1 BNE $B8    [$E36B]      ;ゼロフラグが立っていないとき[$E36B]分岐
$C1/E3B3 BRL $0000  [$E3B6]      ;フラグにかかわりなく常に分岐[$E3B6]

処理をそれぞれ追いかけてみると、移動したい方向に移動できるか(フィールド外にはならないか)を判定してから、[$00:1Bn8](敵X座標計算値)と[$00:1Bn9](敵Y座標計算値)を、それぞれインクリメント(+1)またはデクリメント(-1)して、移動先座標をセットしている。
その上で、どの方向の処理でも$C1/41F2にジャンプしているが、この$C1/41F2$C1/425Cの処理(移動できない場合は$C1/425Fでサブルーチン戻り)が、前ページで説明した移動処理であり、移動できればA$00を入れて戻り、移動出来なければA$FFを入れて戻ることになる。

最終的にどの移動でも$C1/9014にジャンプする。

;分岐先
$C1/9014 LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/9016 LDA $0005,x[$00:1B35]   ;Aに[$00:1Bn5](技関係状態)をロード
$C1/9019 BMI $02    [$901D]      ;ネガティブフラグが立っているとき[$901D]分岐
;ネガティブフラグOFF(移動不可)
$C1/901B BRA $3C    [$9059]      ;フラグにかかわりなく常に分岐[$9059]
;ネガティブフラグON(移動成功)
$C1/901D RTS                     ;サブルーチン戻り

$C1/9016でロードする[$00:1Bn5](技関係状態)がポイントで、前ページの通り、移動可能な時は[$00:1Bn5](技関係状態)に$80を書き込んでいた。
つまり、一番上のビットに1が立っているから、移動できるのならネガティブフラグが立つ。
この場合は$C1/901Dに進み、サブルーチンを抜ける。
一方、移動できなかった時は、$C1/901B$C1/9059にジャンプするが、これは行動パターン$0Cの処理の途中で、後で説明するが、行動パターン$0Cはランダム移動である。
つまり、上下左右それぞれの移動ができなかった場合、行動パターン$0Cの処理に飛んでランダム移動を試す、ということである。
ちなみに、行動パターン$0Cのランダム移動も不可だった時は、ランダム向き変えへジャンプする。

行動パターン$00$03

さて、基本の上下左右移動が判明したので、分岐後に行動パターン$04$07に飛ぶパターンを見てみよう。
まず、行動パターン$00$03である。

;行動パターン$00
$C1/8FA4 LDY $1E    [$00:031E]   ;Yに[$00:031E]をロード
$C1/8FA6 LDA $000A,x             ;Aに[$00:1B0A](敵X座標)をロード
$C1/8FA9 CMP $0018,y             ;Aと[$00:1C18](味方X座標)を減算比較(ステータスレジスタ変更のみ)
$C1/8FAC BCS $46    [$8FF4]      ;キャリーフラグが立っているとき[$8FF4]分岐→行動パターン$06
;キャリーフラグOFF(敵X座標 - 味方X座標<0、敵が左で味方が右)
$C1/8FAE BRA $24    [$8FD4]      ;フラグにかかわりなく常に分岐[$8FD4]→行動パターン$04

;行動パターン$01
$C1/8FB0 LDY $1E    [$00:031E]   ;Yに[$00:031E]をロード
$C1/8FB2 LDA $000B,x             ;Aに[$00:1B0B](敵Y座標)をロード
$C1/8FB5 CMP $0019,y             ;Aと[$00:1C19](味方Y座標)を減算比較(ステータスレジスタ変更のみ)
$C1/8FB8 BCS $4A    [$9004]      ;キャリーフラグが立っているとき[$9004]分岐→行動パターン$07
;キャリーフラグOFF(敵Y座標 - 味方Y座標<0、敵が上で味方が下)
$C1/8FBA BRA $28    [$8FE4]      ;フラグにかかわりなく常に分岐[$8FE4]→行動パターン$05

;行動パターン$02
$C1/8FBC LDY $1E    [$00:031E]   ;Yに[$00:031E]をロード
$C1/8FBE LDA $000A,x             ;Aに[$00:1B0A](敵X座標)をロード
$C1/8FC1 CMP $0018,y             ;Aと[$00:1C18](味方X座標)を減算比較(ステータスレジスタ変更のみ)
$C1/8FC4 BCC $2E    [$8FF4]      ;キャリーフラグが立っていないとき[$8FF4]分岐→行動パターン$06
;キャリーフラグON(敵X座標 - 味方X座標≧0、敵が右で味方が左)
$C1/8FC6 BRA $0C    [$8FD4]      ;フラグにかかわりなく常に分岐[$8FD4]→行動パターン$04

;行動パターン$03
$C1/8FC8 LDY $1E    [$00:031E]   ;Yに[$00:031E]をロード
$C1/8FCA LDA $000B,x             ;Aに[$00:1B0B](敵Y座標)をロード
$C1/8FCD CMP $0019,x             ;Aと[$00:1B19](次の敵のY座標)を減算比較(ステータスレジスタ変更のみ)
$C1/8FD0 BCC $32    [$9004]      ;キャリーフラグが立っていないとき[$9004]分岐→行動パターン$07
;キャリーフラグON(敵Y座標 - 次の敵のY座標≧0)
;$C1/8FCDのCMP $0019,xは、CMP $0019,yで味方を指定するはずだった?
$C1/8FD2 BRA $10    [$8FE4]      ;フラグにかかわりなく常に分岐[$8FE4]→行動パターン$05

行動パターン$03はちょっと妙な値の指定があるので後で説明するとして、基本的にはどれも、「敵の座標-味方の座標」でキャリーフラグが立つかどうかの分岐を行っている。
行動パターン$00$02は、「敵X座標 - 味方X座標」でキャリーフラグが立つかどうかの分岐である。
行動パターン$00は、

  • 敵X座標 - 味方X座標≧0(敵が右で味方が左)なら、行動パターン$06で左に1マス移動
  • 敵X座標 - 味方X座標<0(敵が左で味方が右)なら、行動パターン$04で右に1マス移動

だから、「敵が味方の方向へ右または左に1マス移動」ということになる。
一方、行動パターン$02は条件が逆転しているから、

  • 敵X座標 - 味方X座標≧0(敵が右で味方が左)なら、行動パターン$04で右に1マス移動
  • 敵X座標 - 味方X座標<0(敵が左で味方が右)なら、行動パターン$06で左に1マス移動

よって、「敵が味方とは逆の方向へ右または左に1マス移動」である。
行動パターン$00は味方に接近で、行動パターン$02は味方から逃げる方向への移動ということがわかる。ただしどちらも横方向への移動である。

行動パターン$01は、行動パターン$00の上下方向バージョンと考えれば良い。

  • 敵X座標 - 味方X座標≧0(敵が下で味方が上)なら、行動パターン$07で上に1マス移動
  • 敵Y座標 - 味方Y座標<0(敵が上で味方が下)なら、行動パターン$05で下に1マス移動

だから、「敵が味方の方向へ上または下に1マス移動」ということになる。

よって、行動パターン$03は「敵が味方とは逆の方向へ上または下に1マス移動」ということだろう……
と思ってよく見ると、座標の指定がおかしい。

移動パターン$01の座標指定は、

$C1/8FB2 LDA $000B,x   ;Aに[$00:1B0B](敵Y座標)をロード
$C1/8FB5 CMP $0019,y   ;Aと[$00:1C19](味方Y座標)を減算比較(ステータスレジスタ変更のみ)

敵Y座標は「$000B,x」、$000BXレジスタを加算した値のアドレスから取得する。
Xレジスタには敵番号を指定するための値$1Bn0が入っている。
味方Y座標の方は、「$0019,y」、$0019Yレジスタを加算した値のアドレスから取得する。
Yレジスタには味方キャラを指定するための値、$1C00, $1C40, $1C80, $1CC0のいずれかが入る。

ところが、行動パターン$03はこうなっている。

$C1/8FCA LDA $000B,x   ;Aに[$00:1B0B](敵Y座標)をロード
$C1/8FCD CMP $0019,x   ;Aと[$00:1B19](次の敵のY座標)を減算比較(ステータスレジスタ変更のみ)

$C1/8FCDでのアドレス指定がおかしい。
移動パターン$01からして、CMP $0019,xではなくCMP $0019,yとするはずだ。
$0019,xで指定すると、X$1B00なら$0019,x[$00:1B19]になる。
次の敵番号の計算用Y座標が指定されているのである。
よって、味方キャラの位置は関係なくなり、まったく別の敵キャラとの位置判定で移動方向が決まることになる。
戦闘によっては次の敵番号の敵がいないこともある。前の戦闘の値が残されていることもある。
このため行動パターン$03だと、妙な動きをする可能性が高い。

行動パターン$03が比較的多い移動パターンはID$0C(行動異常$D)で、「ウォ~ウォ~」「スリートイメージ」の追加効果や、岩間さまが反撃「のたうち」で自身に行動異常$Dのパターンがある。
だが、上の処理のため、「敵が味方とは逆の方向へ上または下に1マス移動」という、おそらく想定していたであろう挙動がうまく働かない可能性がある。

とはいえ、デバッグでも気づかれないまま製品版でもそのままなので、さほど気にされなかったのかもしれない。
移動パターンID$0Cは、行動パターン$02と行動パターン$03が混ざっており、行動パターン$02はうまく動くはずだから見逃されたのかもしれない。

行動パターン$08$0B

続いて、行動パターン$08~行動パターン$0Bについて。
行動パターン$08~行動パターン$0Bは、敵の向きを判定してから行動パターン$04$07のいずれかに分岐するパターンである。

;行動パターン$08 敵が向いている方向の左または右に移動
$C1/901E LDA $0004,x[$00:1B34]   ;Aに[$00:1Bn4](向き)をロード
$C1/9021 BIT #$40                ;Aと$40で論理積(ステータスフラグ変更のみ)
$C1/9023 BEQ $AF    [$8FD4]      ;ゼロフラグが立っているとき[$8FD4]分岐→行動パターン$04
;ゼロフラグOFF(左下$40、左上$C0)
$C1/9025 BRA $CD    [$8FF4]      ;フラグにかかわりなく常に分岐[$8FF4]→行動パターン$06

;行動パターン$09 敵が向いている方向の上または下に移動
$C1/9027 LDA $0004,x[$00:1B34]   ;Aに[$00:1Bn4](向き)をロード
$C1/902A BIT #$80                ;Aと$80で論理積(ステータスフラグ変更のみ)
$C1/902C BEQ $B6    [$8FE4]      ;ゼロフラグが立っているとき[$8FE4]分岐→行動パターン$05
;ゼロフラグOFF(右上$80、左上$C0)
$C1/902E BRA $D4    [$9004]      ;フラグにかかわりなく常に分岐[$9004]→行動パターン$07

;行動パターン$0A 左向きなら右に1マス移動、右向きなら左に1マス移動
$C1/9030 LDA $0004,x[$00:1B34]   ;Aに[$00:1Bn4](向き)をロード
$C1/9033 BIT #$40                ;Aと$40で論理積(ステータスフラグ変更のみ)
$C1/9035 BNE $9D    [$8FD4]      ;ゼロフラグが立っていないとき[$8FD4]分岐→行動パターン$04
;ゼロフラグON(右下$00、右上$80)
$C1/9037 BRA $BB    [$8FF4]      ;フラグにかかわりなく常に分岐[$8FF4]→行動パターン$06

;行動パターン$0B 上向きなら下に1マス移動、下向きなら上に1マス移動
$C1/9039 LDA $0004,x[$00:1B34]   ;Aに[$00:1Bn4](向き)をロード
$C1/903C BIT #$80                ;Aと$80で論理積(ステータスフラグ変更のみ)
$C1/903E BNE $A4    [$8FE4]      ;ゼロフラグが立っていないとき[$8FE4]分岐→行動パターン$05
;ゼロフラグON(右下$00、左下$40)
$C1/9040 BRA $C2    [$9004]      ;フラグにかかわりなく常に分岐[$9004]→行動パターン$07

上のサブルーチン中でも説明してしまったが、それぞれの分岐から、

  • 行動パターン$08:敵が向いている方向の左または右に移動
  • 行動パターン$09:敵が向いている方向の上または下に移動
  • 行動パターン$0A:敵が左向きなら右に1マス移動、右向きなら左に1マス移動
  • 行動パターン$0B:敵が上向きなら下に1マス移動、下向きなら上に1マス移動

と、なる。

行動パターン$0C

行動パターン$0Cは、これまでの移動パターンで移動できなかった時にも辿り着く処理である。
(ただしその場合は$C1/9059から開始)

;行動パターン$0C 乱数で1/4で上下左右どちらか移動
$C1/9047 JSR $6150  [$C1:6150]   ;[$C1:6150]へジャンプ
;戦闘乱数生成処理(省略)
$C1/904A AND #$C0                ;A(乱数)と$C0(%1100 0000)で論理積
$C1/904C BEQ $B6    [$9004]      ;ゼロフラグが立っているとき[$9004]分岐→行動パターン$07
$C1/904E CMP #$40                ;Aと$40を減算比較(ステータスレジスタ変更のみ)
$C1/9050 BEQ $92    [$8FE4]      ;ゼロフラグが立っているとき[$8FE4]分岐→行動パターン$05
$C1/9052 CMP #$80                ;Aと$80を減算比較(ステータスレジスタ変更のみ)
$C1/9054 BEQ $9E    [$8FF4]      ;ゼロフラグが立っているとき[$8FF4]分岐→行動パターン$06
$C1/9056 BRL $FF7B  [$8FD4]      ;フラグにかかわりなく常に分岐[$8FD4]→行動パターン$04
$C1/9059 LDA $7E9106,x[$7E:AC36] ;Aに[$7E:ACn6]をロード
$C1/905D BEQ $E3    [$9042]      ;ゼロフラグが立っているとき[$9042]分岐
$C1/905F LDA #$00                ;Aに$00をロード
$C1/9061 STA $7E9106,x[$7E:AC36] ;Aを[$7E:ACn6]に書き込み
$C1/9065 BRL $0026  [$908E]      ;フラグにかかわりなく常に分岐[$908E]→行動パターン$13

;$C1/905DゼロフラグON
$C1/9042 INC A                   ;Aをインクリメント +1
$C1/9043 STA $7E9106,x[$7E:AC36] ;Aを[$7E:ACn6]に書き込み

行動パターン$0Cは、最初に戦闘乱数生成サブルーチン$C1:6150にジャンプしており、$C1/904Aに戻った時点でA$00$FFの乱数が入っている。
その後は乱数との論理積または減算で分岐になっている。

  1. 乱数と$C0(%1100 0000)との論理積でゼロフラグが立つのは、乱数が$00$3Fの時(確率1/4)→行動パターン$07
    (論理積を取ると残った乱数は、$40$80$C0の3パターンしかない)
  2. 乱数から$40を減算してゼロフラグ(確率1/3)→行動パターン$05
    (残った乱数は、$40$80の2パターンしかない)
  3. 乱数から$80を減算してゼロフラグ(確率1/2)→行動パターン$06
  4. 残りは1/1で→行動パターン$04

と、ちょっとややこしいが、結局各確率1/4で行動パターン$04$07を選ぶサブルーチンである。
つまり、上下左右いずれかに1/4の確率で1マス移動だから、ランダム移動と考えても良い。

さらに、ここでいずれの方向にも移動できなかった場合、$C1/9042に進んで[$7E:ACn6]をロードする。
これは敵の移動・向き変えサブルーチンに入る時、$C1/8F5C$00を書き込まれたアドレスである。
よってまず$C1/9042に進み、[$7E:ACn6]+1して、つまり$01を書き込んで、$C1/9047に戻る。
ということは、最初の乱数で決めた方向へ移動ができなかった場合、もう一度乱数を生成して移動判定をする、ということである。
これでも移動できなかったのなら、$C1/905Dの判定では今度はゼロフラグが立たないから、[$7E:ACn6]$00を書き込んで、$C1/908Eにジャンプするが、そのジャンプ先は行動パターン$13(ランダム向き変え)である。
行動パターン$0Cに指定された場合、最大で2回移動判定をして、それでも移動できなければランダム向き変えを試みる、ということがわかる。

また、先に説明した通り、行動パターン$04~行動パターン$07(上下左右移動)ができなかった時のジャンプ先は$C1/9059である。
この時も、$C1/905D$C1/9042$C1/9047と進むので、一度だけランダム移動判定をする、ということがわかる。

行動パターン$0D$0F


;行動パターン$0D,$0E,$0F 何もしない
$C1/9068 RTS                     ;サブルーチン戻り

行動パターン$0D, $0E, $0Fの飛び先はこれだけなので、結局何もしない。
先に記した通り、行動パターン$14以上も$0F扱いなので、ここに辿り着く。

行動パターン$10$11

行動パターン$10以降は向き変えである。

;行動パターン$10 反時計回りに向き変え
$C1/9069 BRA $30    [$909B]      ;フラグにかかわりなく常に分岐[$909B]
;行動パターン$10飛び先
$C1/909B BRL $53D8  [$E476]      ;フラグにかかわりなく常に分岐[$E476]
$C1/909E RTS                     ;サブルーチン戻り

;行動パターン$11 時計回りに向き変え
$C1/906B BRA $2A    [$9097]      ;フラグにかかわりなく常に分岐[$9097]
;行動パターン$11飛び先
$C1/9097 BRL $538F  [$E429]      ;フラグにかかわりなく常に分岐[$E429]
$C1/909A RTS                     ;サブルーチン戻り

行動パターン$10のジャンプ先$C1/E476、行動パターン$11のジャンプ先$C1/E429を見てみると、以下のようになっている。

;行動パターン$11 時計回りに向き変え
$C1/E429 LDX $AC    [$00:03AC]   ;Xに[$00:03AC]をロード
$C1/E42B LDA $0004,x             ;Aに[$00:1Bn4](向き)をロード
$C1/E42E AND #$C0                ;Aと$C0で論理積
$C1/E430 BEQ $0A    [$E43C]      ;ゼロフラグが立っているとき[$E43C]分岐
;ゼロフラグOFF
$C1/E432 CMP #$40                ;Aと$40を減算比較(ステータスレジスタ変更のみ)
$C1/E434 BEQ $0A    [$E440]      ;ゼロフラグが立っているとき[$E440]分岐
;ゼロフラグOFF
$C1/E436 CMP #$C0                ;Aと$C0を減算比較(ステータスレジスタ変更のみ)
$C1/E438 BEQ $0A    [$E444]      ;ゼロフラグが立っているとき[$E444]分岐
;ゼロフラグOFF(右上$80)
$C1/E43A BRA $0C    [$E448]      ;フラグにかかわりなく常に分岐[$E448]
;$C1/E430でゼロフラグON(右下$00)
$C1/E43C LDA #$40                ;Aに$40をロード
$C1/E43E BRA $0A    [$E44A]      ;フラグにかかわりなく常に分岐[$E44A]
;$C1/E434でゼロフラグON(左下$40)
$C1/E440 LDA #$C0                ;Aに$C0をロード
$C1/E442 BRA $06    [$E44A]      ;フラグにかかわりなく常に分岐[$E44A]
;$C1/E438でゼロフラグON(左上$C0)
$C1/E444 LDA #$80                ;Aに$80をロード
$C1/E446 BRA $02    [$E44A]      ;フラグにかかわりなく常に分岐[$E44A]
;右上$80
$C1/E448 LDA #$00                ;Aに$00をロード
;右下$00(Aに$40), 左下$40(Aに$C0), 左上$C0(Aに$80)
$C1/E44A STA $0004,x             ;Aを[$00:1Bn4](向き)に書き込み

行動パターン$11のサブルーチンの方が先に書いてあるのでまず説明する。
向き変えは移動とは異なり、マスの状態を判定する必要がない。
よって、$C1/E42Bで敵キャラの向き[$00:1Bn4]をロードし、値から向きを判断・分岐して、[$00:1Bn4]を変更する、という手順になる。
上処理を追っていくと、

  • 右上$80→右下$00
  • 右下$00→左下$40
  • 左下$40→左上$C0
  • 左上$C0→右上$80

と値を変えて、[$00:1Bn4]に上書きしているから、時計回りに向き変えの処理ということがわかる。

なお、この後の$C1/E44D$C1/E475は順序ポイントなどの処理などが続くので、ひとまずここでは省く。

;行動パターン$10 反時計回りに向き変え
$C1/E476 LDX $AC    [$00:03AC]   A:909E X:1B30 Y:0503 P:envMxdIZc;Xに[$00:03AC]をロード
$C1/E478 LDA $0004,x[$00:1B34]   A:909E X:1B30 Y:0503 P:envMxdIZc;Aに[$00:1Bn4](向き)をロード
$C1/E47B AND #$C0                A:909E X:1B30 Y:0503 P:envMxdIZc;Aと$C0で論理積
$C1/E47D BEQ $C5    [$E444]      A:909E X:1B30 Y:0503 P:envMxdIZc;ゼロフラグが立っているとき[$E444]分岐(右下$00)→右上$80
;ゼロフラグOFF
$C1/E47F CMP #$40                A:909E X:1B30 Y:0503 P:envMxdIZc;Aと$40を減算比較(ステータスレジスタ変更のみ)
$C1/E481 BEQ $C5    [$E448]      A:909E X:1B30 Y:0503 P:envMxdIZc;ゼロフラグが立っているとき[$E448]分岐(左下$40)→右下$00
;ゼロフラグOFF
$C1/E483 CMP #$C0                A:909E X:1B30 Y:0503 P:envMxdIZc;Aと$C0を減算比較(ステータスレジスタ変更のみ)
$C1/E485 BEQ $B5    [$E43C]      A:909E X:1B30 Y:0503 P:envMxdIZc;ゼロフラグが立っているとき[$E43C]分岐(左上$C0)→左下$40
;ゼロフラグOFF(右上$80)
$C1/E487 BRA $B7    [$E440]      A:909E X:1B30 Y:0503 P:envMxdIZc;フラグにかかわりなく常に分岐[$E440]→左上$C0

行動パターン$10のジャンプ先は行動パターン$11と兼ねており、

  • 右下$00→右上$80
  • 左下$40→右下$00
  • 左上$C0→左下$40
  • 右上$80→左上$C0

ということで、反時計回りに向き変えになっている。

行動パターン$12

行動パターン$12も向き変え処理だが、一番近い味方キャラの方向を判定してそちらを向く、という処理である。

;行動パターン$12 味方キャラ方向へ向き変え
$C1/906D STZ $10    [$00:0310]   ;[$00:0310]に$00を書き込み
$C1/906F LDA $1A    [$00:031A]   ;Aに[$00:031A]をロード
$C1/9071 CMP #$04                ;Aと$04を減算比較(ステータスレジスタ変更のみ)
$C1/9073 BCS $04    [$9079]      ;キャリーフラグが立っているとき[$9079]分岐
;キャリーフラグOFF([$00:031A]が0~3 減算の結果が負)
$C1/9075 LDA #$40                ;Aに$40をロード
$C1/9077 STA $10    [$00:0310]   ;Aを[$00:0310]に書き込み
;キャリーフラグON([$00:031A]が4以上 減算の結果が0か正)
$C1/9079 LDA $1B    [$00:031B]   ;Aに[$00:031B]をロード
$C1/907B CMP #$04                ;Aと$04を減算比較(ステータスレジスタ変更のみ)
$C1/907D BCS $06    [$9085]      ;キャリーフラグが立っているとき[$9085]分岐
;キャリーフラグOFF([$00:031B]が0~3 減算の結果が負)
$C1/907F LDA #$80                ;Aに$80をロード
$C1/9081 ORA $10    [$00:0310]   ;Aと[$00:0310]で論理和
$C1/9083 STA $10    [$00:0310]   ;Aを[$00:0310]に書き込み
;キャリーフラグON([$00:031B]が4以上 減算の結果が0か正)
$C1/9085 LDA $0004,x             ;Aに[$00:1Bn4](向き)をロード
$C1/9088 EOR $10    [$00:0310]   ;Aと[$00:0310]で排他的論理和XOR
$C1/908A JSR $E44A  [$C1:E44A]   ;[$C1:E44A]へジャンプ
$C1/908D RTS                     ;サブルーチン戻り

$C1/E44A STA $0004,x[$00:1B34]   ;Aを[$00:1Bn4](向き)に書き込み

行動パターン$12では、[$00:031A][$00:031B]の値が必要となる。
前ページから、[$00:031A][$00:031B]は、9×9マス基準、敵が(3,3)にいる場合の味方位置が入っている。

  • [$00:031A]:味方位置X座標(0~8)
  • [$00:031B]:味方位置Y座標(0~8)

X軸なら、敵右向きの時、

□□□□★□□□□
012345678

というように味方位置の値が入っている。
この値から$04を減算ということは、敵の向いている方向に味方が居るなら減算結果は正か0、向いている方向と逆に味方がいるなら減算結果は負、というようにキャリーフラグで分岐になる。
分岐によって、初期値で$00が入った[$00:0310]に値が加算されたり論理和を取っていく仕組みである。
ということでまとめてみると、

X座標距離Y座標距離味方位置[$00:0310]
1~31~3左上$40 OR $80 = $C0
4以上1~3右上$80
1~34以上左下$40
4以上4以上右下$00

ということになる。
最終的に、[$00:1Bn4](向き)と、[$00:0310]に入る値で排他的論理和を取る。
例えば敵が右下向き、つまり[$00:1Bn4](向き)が$00なら、

  • $00 XOR $C0 = $C0(左上)
  • $00 XOR $80 = $80(右上)
  • $00 XOR $40 = $40(左下)
  • $00 XOR $00 = $00(右下)

すべて、味方の方向へ向くように向き変えをすることがわかる。

行動パターン$13

最後の行動パターン$13はランダム向き変えになる。
行動パターン$0Cのランダム移動ができなかった場合もここに飛ぶ。

;行動パターン$13 向き変え(ランダム)
$C1/908E JSR $6150  [$C1:6150]   ;[$C1:6150]へジャンプ
;戦闘乱数生成処理(省略)
$C1/9091 BIT #$01                ;A(乱数)と$01で論理積(ステータスフラグ変更のみ)
$C1/9093 BEQ $02    [$9097]      ;ゼロフラグが立っているとき[$9097]分岐
;ゼロフラグOFF(乱数が奇数)
$C1/9095 BRA $04    [$909B]      ;フラグにかかわりなく常に分岐[$909B]
;ゼロフラグON(乱数が偶数)
$C1/9097 BRL $538F  [$E429]      ;フラグにかかわりなく常に分岐[$E429]→行動パターン$11
$C1/909A RTS                     ;サブルーチン戻り
;$C1/9095の分岐先
$C1/909B BRL $53D8  [$E476]      ;フラグにかかわりなく常に分岐[$E476]→行動パターン$10
$C1/909E RTS                     ;サブルーチン戻り

まず戦闘乱数($00$FF)を生成し、乱数と$01の論理積を取って、ゼロフラグ判定をしている。
つまり乱数の下1ビットが01かで決まる。
乱数が奇数ならゼロフラグOFF、偶数ならゼロフラグONと、1/2の確率で分岐になる。
乱数が奇数なら、行動パターン$10(反時計回りに向き変え)にジャンプ。
乱数が偶数なら、行動パターン$11(時計回りに向き変え)にジャンプとなる。

移動パターンの説明

移動パターンの大半は、

  • 味方の方を向いているなら味方の方へ1マス移動
  • 味方の方を向いていないなら、味方の方へ向き変え

という、ID$00、ID$04$05$06$0Fなどや、その中でも敵が向いている方向に味方キャラが隣接している時は逃げるID$01、ID$02、ID$03などがあるが、中でも特徴的なパターンについてざっと解説する。

ID$01

浪人やアクロフォビアなど。
敵が向いている方向に味方キャラが隣接していると、行動パターン$0A$0Bで向いている方向の逆に移動する以外は、味方の方を向いているなら味方の方へ1マス移動、味方の方を向いていないなら、味方の方へ向き変え。
浪人は移動頻度が3とやや高めなこともあり、目の前に味方キャラがいるのに移動して逃げる、という行動をしばしば見せるのはこのため。

ID$06

敵対時のストレイボウ、ヘッドプラッカー、フェミノフォビアなど。
右下向きのとき、

0B 12 12
12 ↘ 0B
09 0A 09
  • $09:向いている縦方向に1マス移動
  • $0A:向いている反対の横方向に1マス移動
  • $0B:向いている反対の縦方向に1マス移動
  • $12:一番近くの味方キャラの方向へ向き変え

と、味方が正面にいる時にも遠ざかろうとするパターンがあるので、ストレイボウ戦のようにうまく動くと嵌めて倒せる。
ヘッドプラッカー戦で、ヘッドプラッカーを隅に追い詰めて閉じ込めた時、上下移動しながら攻撃してくるのも上の挙動のため。

ID$07

(行動異常$8

ジェムパラペット、スタビライザー、マザーCOMなどに最初から設定されている他、行動異常$8の時もこれだが、すべての位置で行動パターン$F0のため、移動しない。
ジェムパラペット、スタビライザー、マザーCOMは移動せず技を使うが、行動異常$8は全ての技が使用不可なので、一切行動しなくなる。

ID$08

(行動異常$9

ボイスハートのみ設定されている他、行動異常$9の移動パターン。「マザーイメージ」などで発生。
原始編の♀の敵に悪属性技、♂の敵に善属性技でも発生。
味方に接近してくるが、隣接するとランダムで向き変えをする。
行動異常$9も全ての技が使用不可なので、技を一切使わず味方に接近してくる。

ID$09

(行動異常$A

オディオモールやピュアオディオ、大顔面、ヘーベル1号など。
行動異常$Aの効果でもあり、基本は反時計回りに向き変え(味方が真後ろ4マス以上の位置のみ時計回り)。
オディオモールやピュアオディオが移動せず向き変えばかりするのはこれが原因。
また、「忍法コマまわし」「ウホ」の行動異常$Aの反時計回り回転の仕組みもこれが原因。

ID$0A

(行動異常$B

ケケモグラ、ひとだま、翔電、ポウンバードに設定。
行動異常$Bの効果でもあり、どの位置でも上下左右それぞれ1/4の確率で、ランダムに1マス移動のランダム移動効果。

ID$0C

(行動異常$D

技でのみ発生の行動異常$Dの効果。
味方技だと、「スリートイメージ」「ウォ~ウォ~」など。
敵自身に発生する技だと、「のたうち」「静岩くずし」など。
カウンター行動異常だと、王国兵、コスモストローラ、ジェムパラペット。原始編の動物系の敵に火属性技でも発生。
味方が3マス以内なら行動パターン$02$03、4マス以上なら行動パターン$0A(向いている反対の横方向に1マス移動)。
だが、先に述べた通り、行動パターン$03が問題で、

  • $02:味方キャラから遠ざかる方向へ横方向に1マス移動
  • $03:味方キャラから遠ざかる方向へ縦方向に1マス移動?(座標指定がおかしい?)

縦移動が正しく起こらない可能性があり、ランダム移動のようになってしまう可能性もあり。

ID$0D

(行動異常$E

技でのみ発生の行動異常$Eの効果。
「シャドウイメージ」「ならくの暗黒」「ブラウンシュガー」で発生する。
隣接していないなら上へ移動、隣接時は向き変えや何もしない。



このページをシェアする

上へ