DQ6 AI処理の解析7

だいぶ間が空きましたが、続きを見ていきます。前回は回復行動を見たので、今回は攻撃行動です。

攻撃系の行動はほとんど共通です。AIの行動区分の「攻撃系」にはニフラム・ザキなどの一発離脱系も含まれます(バシルーラはAIの選択対象外)。

  • SR: $02D675 AI判断用_SR_001A(直接攻撃)
02D675 LDX #$0004 X=#$0004
02D678 LDA $25DD A=$25DD 単体・グループ・全体かの情報
02D67B BMI #$07 if(n==on) goto $02D684
02D67D DEX X–
02D67E DEX X–
02D67F ASL A< <1
02D680 BCS #$02 if(c==on) goto $02D684
02D682 DEX X–
02D683 DEX X–
02D684 JSR $D688 SR: $($02D688+X)
02D687 RTS return

DQ6では単体・グループ・全体攻撃は戦闘行動IDは同じなので別の情報で判断して振り分けています。基本的にやってることはどれも同じなので、単体の直接攻撃をみてみます。

  • SR: $02D478 AI判断用_SR_0001(単体対象行動)
02D478 STZ $14 DP($14)=#$00
02D47A LDA #$0017 A=#$0017 最大インデックスからデクリメントしていく
02D47D STA $258B $258B=A
02D480 LDY #$04AC Y=#$04AC 最大インデックスの開始アドレス
02D483 LDA #$0001 A=#$0001
02D486 STA $254B $254B=A
02D489 STZ $2549 $2549=#$00
02D48C LDA $203E,Y A=$203E+Y
02D48F BEQ #$14 if(z==on) goto $02D4A5
02D491 JSR $D4B1 SR: $02D4B1 対象のステータスを調べる(無効c=on 反射v=on)
02D494 BCS #$0F if(c==on) goto $02D4A5
02D496 JSR $D4EB SR: $02D4EB 対象の戦闘行動の効果値取得(ダメージ系)
02D499 CMP $14 A>=DP($14)?
02D49B BCC #$08 if(c==off) goto $02D4A5
02D49D STA $14 DP($14)=A 効果値が最大なら差し替え
02D49F LDA $258B A=$258B
02D4A2 STA $2591 $2591=A 対象情報も更新
02D4A5 TYA A=Y
02D4A6 SEC c=on
02D4A7 SBC #$0034 A-=(#$0034+!c)
02D4AA TAY Y=A
02D4AB DEC $258B $258B–
02D4AE BPL #$DC if(n==off) goto $02D48C
02D4B0 RTS return

単体の行動なので、対象全てに対して効果値の算出を行い、効果値が最大の相手に対して行動するといういつものパターンです。

  • SR: $02D4EB 対象の戦闘行動の効果値取得
02D4EB JSL $C2E065 SR: $02E065 効果値算出(ダメージ系)
02D4EF STA $00 DP($00)=A
02D4F1 JSR $D52A SR: $02D52A 効果値の補正
02D4F4 LDA $0C A=DP($0C)
02D4F6 CMP #$8020 A==#$8020?
02D4F9 BNE #$02 if(z==off) goto $02D4FD
02D4FB ASL $00 DP($00)< <1 山彦の帽子装備でダメージが倍加するなら倍にする
02D4FD LDA $00 A=DP($00)
02D4FF SEC c=on
02D500 SBC $2030,Y A-=($2030+Y+!c) 対象の現HPと比較する
02D503 BCC #$22 if(c==off) goto $02D527 この行動で対象が倒せる場合
02D505 STA $00 DP($00)=A
02D507 LDA $0E A=DP($0E) 作戦がガンガン行こうぜか
02D509 CMP #$0000 A==#$0000?
02D50C BEQ #$02 if(z==on) goto $02D510
02D50E STZ $00 DP($00)=#$00 ガンガン行こうぜ以外は効果値は加算しない
02D510 LDA $00 A=DP($00)
02D512 CLC c=off
02D513 ADC $203E,Y A+=($203E+Y+c) 脅威値合計を加算する
02D516 BCC #$04 if(c==off) goto $02D51C
02D518 LDA #$FFFF A=#$FFFF
02D51B CLC c=off
02D51C ADC $203C,Y A+=($203C+Y+c)
02D51F BCC #$03 if(c==off) goto $02D524
02D521 LDA #$FFFF A=#$FFFF オーバーフロー対策
02D524 STA $00 DP($00)=A
02D526 RTS return
02D527 LDA $00 A=DP($00)
02D529 RTS return

ダメージ予想値が対象のHP以下であれば倒せないのでそのままダメージ予想値が効果値となりますが、倒せる場合は脅威値合計を加算します(脅威値合計のほうがダメージ値より大きくなるので優先的に選ばれやすくなる)。

  • SR: $02E065 効果値算出
02E065 PHP Push P Flag
02E066 PHB Push DB
02E067 REP #$30 m=off(A/M:16b) x=off(X/Y:16b)
02E069 PEA #$7E7E Push #$7E7E
02E06C PLB Pull DB
02E06D PLB Pull DB
02E06E PHX Push X
02E06F PHY Push Y
02E070 LDA $255F A=$255F
02E073 ASL A< <1
02E074 TAX X=A
02E075 LDA $C8EE67,X A=$08EE67+X
02E079 TAX X=A
02E07A LDA $C8C666,X A=$08C666+X
02E07E AND #$003F A&=#$003F 評価対象の戦闘行動の属性ID取得
02E081 CMP #$0021 A>=#$0021?
02E084 BCS #$FE if(c==on) goto $02E084
02E086 ASL A< <1
02E087 TAX X=A
02E088 JSR $E0D6 SR: $($02E0D6+X) AI効果値算出用SRのインデックス
02E08B LDA $2517 A=$2517
02E08E ORA #$0020 Aor=#$0020
02E091 STA $2517 $2517=A
02E094 LDA $258B A=$258B
02E097 STA $2559 $2559=A
02E09A JSL $C2852F SR: $02852F ダメージ補正処理
02E09E LDA $2559 A=$2559
02E0A1 STA $258B $258B=A
02E0A4 LDA $00 A=DP($00)
02E0A6 PLY Pull Y
02E0A7 PLX Pull X
02E0A8 PLB Pull DB
02E0A9 PLP Pull P Flag
02E0AA RTL return

ダメージ補正処理は実際の戦闘行動でも使用しているダメージ補正処理と同じです(バイキルトなら2倍、防御なら半減、フバーハなら半減などの補正)。DQ3に移植する際にも同じようにしたかったのですが、関連するメモリがそのまま流用できるのかわからなかったため、補正用のSRを新規定義しています。バイキルト・防御状態はチェックしていますが、簡易版にしています(特に種族特攻の計算はすっ飛ばしています)。

  • SR: $02E11B AI判断用効果値算出_SR_0001(直接攻撃)
02E11B LDA $2555 A=$2555
02E11E ASL A< <1
02E11F TAX X=A
02E120 LDA $C2F092,X A=$02F092+X
02E124 TAX X=A
02E125 LDA $205A,X A=$205A+X 行動主体の攻撃力取得
02E128 AND #$03FF A&=#$03FF
02E12B STA $00 DP($00)=A
02E12D LDA $258B A=$258B
02E130 ASL A< <1
02E131 TAX X=A
02E132 LDA $C2F092,X A=$02F092+X
02E136 TAX X=A
02E137 LDA $2058,X A=$2058+X 対象の守備力取得
02E13A AND #$03FF A&=#$03FF
02E13D STA $02 DP($02)=A
02E13F JSR $E143 SR: $02E143 直接攻撃推定ダメージ値取得
02E142 RTS return
  • SR: $02E143 直接攻撃推定ダメージ値取得
02E143 LDA $02 A=DP($02)
02E145 LSR A>>1
02E146 STA $04 DP($04)=A
02E148 LDA $00 A=DP($00)
02E14A SEC c=on
02E14B SBC $04 A-=(DP($04)+!c)
02E14D BCC #$22 if(c==off) goto $02E171
02E14F LSR A>>1
02E150 BEQ #$1F if(z==on) goto $02E171
02E152 STA $08 DP($08)=A
02E154 LDA $00 A=DP($00)
02E156 LSR A>>1
02E157 LSR A>>1
02E158 LSR A>>1
02E159 LSR A>>1
02E15A STA $06 DP($06)=A
02E15C CMP $08 A>=DP($08)?
02E15E BCS #$0B if(c==on) goto $02E16B
02E160 LDA $04 A=DP($04)
02E162 CMP $00 A>=DP($00)?
02E164 BCS #$05 if(c==on) goto $02E16B
02E166 LDA $08 A=DP($08)
02E168 STA $00 DP($00)=A
02E16A RTS return
02E16B LDA $06 A=DP($06)
02E16D LSR A>>1
02E16E STA $00 DP($00)=A
02E170 RTS return
02E171 STZ $00 DP($00)=#$00
02E173 RTS return

ここは直接攻撃によるダメージ値を乱数による変動なしで算出しています。いろいろやっていますが

  • 攻撃力-守備力1/2< =1なら0
  • 攻撃力1/16>(攻撃力-守備力1/2)1/2なら攻撃力1/32
  • 攻撃力=守備力1/2なら攻撃力1/32
  • 上記以外なら(攻撃力-守備力1/2)1/2

ということのようです。ちなみにダメージ呪文系はどうなっているかというと、

  • SR: $02E236 AI判断用効果値算出_SR_0009(メラ系)
02E236 JSL $C9291A SR: $09291A 戦闘行動の最小値を取得する
02E23A RTS return

で、単純に数値設定の最小値を取ってくるだけです(この後対象の耐性による補正などが入りますが)。最後に一発離脱系を見てみます。

  • SR: $02E23B AI判断用効果値算出_SR_000A(ザキ系)
02E23B LDA $258B A=$258B
02E23E ASL A< <1
02E23F TAX X=A
02E240 LDA $C2F092,X A=$02F092+X
02E244 TAX X=A
02E245 LDA $2030,X A=$2030+X 現HPを効果値のベースとする
02E248 STA $04 DP($04)=A
02E24A LDA $255F A=$255F
02E24D STA $258D $258D=A
02E250 JSL $C2A665 SR: $02A665 耐性を考慮した閾値取得?
02E254 CMP #$0081 A>=#$0081? 成功率が50%以下なら効果値を半減
02E257 BCS #$01 if(c==on) goto $02E25A
02E259 LSR A>>1
02E25A LDX #$0004 X=#$0004
02E25D JSL $C00D0C SR: $000D0C DP($00+X)=A(1Byte)*DP($00+X)
02E261 LDA $05 A=DP($05)
02E263 BEQ #$01 if(z==on) goto $02E266
02E265 DEC A–
02E266 STA $00 DP($00)=A
02E268 RTS return

ザキ系はダメージ系よりも効果値は低くなるようになっているようです(このへんはFC版DQ4のクリフトの反省があるのかもしれませんが)。省略しますが、ニフラム系は脅威値合計に成功率をかけてさらに1/32しているので、普通にプレイしていたらまず選択されることはありません(AIの区分がダメージ系と同じ区分なので)。DQ3に移植する際には一発離脱系の行動はダメージ系と別区分にしたので(効果値の計算式も若干変えた)、AIをONにしているとそこそこ目にする機会が多いと思います。マニュアルではまずやらないゾンビ系にもザキを撃ったりしてされ効いたりするのにはちょっとびっくりしましたが、AIがイメージと違う弱点を突くから耐性を変えるというのもどうかと思うのでそのままにしています。

結構長くなったので今回はこのへんで。次回は補助系行動を見てみます。