DQ6 AI処理の解析3

前回からの続きです。

  • SR: $02CF86 AI行動決定用RAM領域初期化
02CF86LDX #$006AX=#$006A
02CF89STZ $25F3,X$25F3+X=#$00
02CF8CDEXX–
02CF8DDEXX–
02CF8EBPL #$F9if(n==off) goto $02CF89
02CF90LDX #$027EX=#$027E
02CF93STZ $FD00,X$FD00+X=#$00
02CF96DEXX–
02CF97DEXX–
02CF98BPL #$F9if(n==off) goto $02CF93
02CF9ARTSreturn

ここは初期化をしているだけの処理です。$7E35F3-365E、$7EFD00-FF7FをAI用のテンポラリ領域として使用するようです。

  • SR: $02CF9B AI判断用情報をメモリにセット
02CF9BLDA #$0017A=#$0017戦闘中キャラクターの最終インデックス
02CF9ESTA $258B$258B=A
02CFA1LDY #$04ACY=#$04AC戦闘中キャラクターアドレスの開始位置の最後(52Byte*23)
02CFA4LDA $205F,YA=$205F+Y
02CFA7AND #$0001A&=#$0001
02CFAABEQ #$03if(z==on) goto $02CFAF戦闘に参加していなければスキップ
02CFACJSR $CFBBSR: $02CFBB戦闘参加者のAI判断用情報をセット
02CFAFTYAA=Y
02CFB0SECc=on
02CFB1SBC #$0034A-=(#$0034+!c)開始位置を1キャラクター分前に移動する
02CFB4TAYY=A
02CFB5DEC $258B$258B–インデックスもデクリメントする
02CFB8BPL #$EAif(n==off) goto $02CFA4
02CFBARTSreturn

このSRはAI計算中の典型的な処理の実装がされています。Yに戦闘中キャラクターアドレスの開始位置、$7E258Bにそのインデックスがセットされ、デクリメントしてループしていく、というものです。こういう実装の仕方をしているのは取得したい情報にダイレクトにアクセスするためだと推測します。DQ6には戦闘中キャラクターインデックスを指定すると情報を返してくるSRが多数定義されていますが、A,X,Yレジスタをプッシュしてインデックスから開始アドレスを取得し、必要な情報を返して・・・というのはサイクル数を消費しすぎるということなのでしょう。AI処理中はこの手の処理がそこかしこに出てくるのでこの形を覚えておくと理解が進みます。逆にこれをまねて実装する場合はYの開始位置アドレスをループ中に変えないようにPHY、PLYするなどして値がずれないように注意する必要があります。

  • SR: $02CFBB 戦闘参加者のAI判断用情報をセット
02CFBBJSL $C2E4DCSR: $02E4DC 引数:1#$1A敵味方判定?
02CFC0BCS #$08if(c==on) goto $02CFCA
02CFC2LDA $205E,YA=$205E+Y
02CFC5AND #$FFFBA&=#$FFFB
02CFC8BRA #$06goto $02CFD0
02CFCALDA $205E,YA=$205E+Y
02CFCDORA #$0004Aor=#$0004
02CFD0STA $205E,Y$205E+Y=A
02CFD3JSL $C2E4DCSR: $02E4DC 引数:1#$18生死判定?
02CFD8BCS #$08if(c==on) goto $02CFE2
02CFDALDA $2050,YA=$2050+Y
02CFDDAND #$FFFDA&=#$FFFD
02CFE0BRA #$06goto $02CFE8
02CFE2LDA $2050,YA=$2050+Y
02CFE5ORA #$0002Aor=#$0002
02CFE8STA $2050,Y$2050+Y=A
02CFEBLDA $2061,YA=$2061+Y
02CFEEAND #$FF9FA&=#$FF9F
02CFF1PHAPush A
02CFF2JSL $C2E4DCSR: $02E4DC 引数:1#$10毒状態取得
02CFF7ASLA<<1
02CFF8ASLA<<1
02CFF9ASLA<<1
02CFFAASLA<<1
02CFFBASLA<<1
02CFFCORA $01,SAor=Stack($01)
02CFFESTA $2061,Y$2061+Y=A
02D001PLAPull A
02D002JSL $C2E4DCSR: $02E4DC 引数:1#$00現HP取得
02D007STA $2030,Y$2030+Y=A
02D00AJSL $C2E4DCSR: $02E4DC 引数:1#$08現MP取得
02D00FSTA $2032,Y$2032+Y=A
02D012JSL $C2E4DCSR: $02E4DC 引数:1#$1C最大HP取得
02D017STA $203C,Y$203C+Y=A
02D01ARTSreturn

  • SR: $02D01B 各キャラクター用AI判断用情報セット
02D01BJSL $C2E939SR: $02E939 引数:1#$00ターゲット情報セット?
02D020JSL $C2E966SR: $02E966 引数:1#$06ターゲット情報セット?
02D025LDA $00A=DP($00)
02D027STA $04DP($04)=A
02D029LDA $02A=DP($02)
02D02BSTA $06DP($06)=A
02D02DJSL $C2E966SR: $02E966 引数:1#$2Cターゲット情報セット?
02D032LDA $00A=DP($00)
02D034ORA $02Aor=DP($02)
02D036BEQ #$08if(z==on) goto $02D040
02D038LDA $00A=DP($00)
02D03ASTA $04DP($04)=A
02D03CLDA $02A=DP($02)
02D03ESTA $06DP($06)=A
02D040LDA #$0000A=#$0000
02D043STA $258B$258B=A
02D046TAYY=A
02D047LDA #$0000A=#$0000
02D04ASTA $203E,Y$203E+Y=A
02D04DSTA $2040,Y$2040+Y=A
02D050STA $2042,Y$2042+Y=A
02D053STA $2044,Y$2044+Y=A
02D056STA $2046,Y$2046+Y=A
02D059STA $2048,Y$2048+Y=A
02D05CSTA $204A,Y$204A+Y=A
02D05FLSR $06DP($06)>>1
02D061ROR $04DP($04)>>1
02D063BCC #$4Eif(c==off) goto $02D0B3
02D065LDA $2050,YA=$2050+Y
02D068AND #$0008A&=#$0008
02D06BBNE #$37if(z==off) goto $02D0A4
02D06DLDA $205D,YA=$205D+Y
02D070AND #$0080A&=#$0080
02D073BNE #$2Fif(z==off) goto $02D0A4
02D075LDA $2052,YA=$2052+Y
02D078AND #$0002A&=#$0002
02D07BBNE #$27if(z==off) goto $02D0A4
02D07DLDA $2050,YA=$2050+Y
02D080AND #$00E0A&=#$00E0
02D083BNE #$1Fif(z==off) goto $02D0A4
02D085LDA $204E,YA=$204E+Y
02D088AND #$0040A&=#$0040
02D08BBNE #$17if(z==off) goto $02D0A4
02D08DLDA $2055,YA=$2055+Y
02D090AND #$00C0A&=#$00C0
02D093BNE #$0Fif(z==off) goto $02D0A4
02D095JSR $D0C2SR: $02D0C2モンスターAI判断用情報セット
02D098CLCc=off
02D099ADC #$0004A+=(#$0004+c)
02D09CBCC #$03if(c==off) goto $02D0A1
02D09ELDA #$FFFFA=#$FFFF
02D0A1STA $204A,Y$204A+Y=A脅威値合計をセット
02D0A4LDA $2030,YA=$2030+Y
02D0A7CLCc=off
02D0A8ADC $204A,YA+=($204A+Y+c)
02D0ABBCC #$03if(c==off) goto $02D0B0
02D0ADLDA #$FFFFA=#$FFFF
02D0B0STA $203E,Y$203E+Y=A
02D0B3INC $258B$258B++
02D0B6TYAA=Y
02D0B7CLCc=off
02D0B8ADC #$0034A+=(#$0034+c)開始アドレスを次のキャラクターに移す
02D0BBTAYY=A
02D0BCCMP #$04ADA>=#$04AD?
02D0BFBCC #$86if(c==off) goto $02D047
02D0C1RTSreturn

  • SR: $02D0C2 モンスターAI判断用情報セット
02D0C2LDA $2051,YA=$2051+Y
02D0C5AND #$01FFA&=#$01FF
02D0C8CMP #$0100A>=#$0100?
02D0CBBCC #$04if(c==off) goto $02D0D1
02D0CDLDA #$0014A=#$0014
02D0D0RTSreturn
02D0D1LDX #$000BX=#$000B
02D0D4JSL $C00C7ASR: $000C7AA(2B)=A(1B)*X(1B)
02D0D8TAXX=A
02D0D9LDA #$0000A=#$0000脅威値合計のリセット
02D0DCPHAPush A
02D0DDJSL $C2C168SR: $02C168呪文かき消し環境か(該当c=on)
02D0E1BCS #$1Eif(c==on) goto $02D101
02D0E3LDA $2052,YA=$2052+Yマホトーン中か
02D0E6AND #$0008A&=#$0008
02D0E9BNE #$16if(z==off) goto $02D101
02D0EBLDA $2032,YA=$2032+YMPが0か
02D0EEBEQ #$11if(z==on) goto $02D101
02D0F0LDA $C8F19B,XA=$08F19B+X呪文脅威値取得
02D0F4STA $2040,Y$2040+Y=A
02D0F7CLCc=off
02D0F8ADC $01,SA+=(Stack($01)+c)
02D0FABCC #$03if(c==off) goto $02D0FF
02D0FCLDA #$FFFFA=#$FFFF
02D0FFSTA $01,SStack($01)=A
02D101LDA $205D,YA=$205D+Y踊り封じ中か
02D104AND #$0040A&=#$0040
02D107BNE #$11if(z==off) goto $02D11A
02D109LDA $C8F19D,XA=$08F19D+X踊り脅威値取得
02D10DSTA $2042,Y$2042+Y=A
02D110CLCc=off
02D111ADC $01,SA+=(Stack($01)+c)
02D113BCC #$03if(c==off) goto $02D118
02D115LDA #$FFFFA=#$FFFF
02D118STA $01,SStack($01)=A
02D11ALDA $C8F19F,XA=$08F19F+Xブレス脅威値取得
02D11ESTA $2044,Y$2044+Y=A
02D121CLCc=off
02D122ADC $01,SA+=(Stack($01)+c)
02D124BCC #$03if(c==off) goto $02D129
02D126LDA #$FFFFA=#$FFFF
02D129STA $01,SStack($01)=A
02D12BLDA $C8F1A1,XA=$08F1A1+X打撃攻撃脅威値取得
02D12FPHAPush A
02D130LDA $2052,YA=$2052+Y
02D133AND #$00F0A&=#$00F0マヌーサ系にかかっているか
02D136BEQ #$05if(z==on) goto $02D13D
02D138LDA $01,SA=Stack($01)
02D13ALSRA>>1命中率が50%になっているので直接攻撃脅威値を半減
02D13BSTA $01,SStack($01)=A
02D13DPLAPull A
02D13ESTA $2046,Y$2046+Y=A
02D141CLCc=off
02D142ADC $01,SA+=(Stack($01)+c)
02D144BCC #$03if(c==off) goto $02D149
02D146LDA #$FFFFA=#$FFFF
02D149STA $01,SStack($01)=A
02D14BLDA $C8F1A3,XA=$08F1A3+Xその他脅威値取得
02D14FSTA $2048,Y$2048+Y=A
02D152CLCc=off
02D153ADC $01,SA+=(Stack($01)+c)
02D155BCC #$03if(c==off) goto $02D15A
02D157LDA #$FFFFA=#$FFFF
02D15ASTA $01,SStack($01)=A
02D15CPLAPull A
02D15DRTSreturn

ここが1つ目のポイントです。まとめると以下の様な値をセットしています。1キャラクター分の領域にモンスターの状態に応じて値をセットしています。しれっとAI判定中に使われるので正しく理解しておけばなにをやってるかがわかりやすくなります。脅威値、脅威値合計の最大値はどれも#$FFFFでクリップされます。

アドレス意味備考
2030-1現在HP死んでいたら0
2032-3現在MP
203C-D最大HP回復系で使用
203E-F現在HP+脅威値合計
2040-1呪文脅威値呪文が使えない状態なら0
2042-3踊り脅威値踊りを封じられていたら0
2044-5ブレス脅威値
2046-7打撃攻撃脅威値マヌーサ系にかかっていたら半減
2048-9その他脅威値
204A-B脅威値合計

「脅威値」というのはあくまで勝手につけた名称で、「そのモンスターが本来持っている強さ」を数値化したものという認識をしています。AI行動決定時に同じHPを持つ異なる種類のモンスターが2体居た場合は、脅威値の大きい方を積極的に倒そうとします。ぶちスライム(脅威値合計:3)とキラーマジンガ(脅威値合計:240)がどちらもHP10だった場合はキラーマジンガを優先して倒そうとする、ということです。ちなみに、各脅威値の上位は以下のようになっています。

  • 打撃攻撃脅威値
キラーマジンガ240
ゾゾゲル206
マッスルアニマル189
ボーンファイター167
ダークドレアム(C)159

  • 呪文脅威値
ひだりて1875デスタムーア(最終形態)戦でザオリクを使うから?
アクバー1104
みぎて739デスタムーア(最終形態)戦でザオラルを使うから?
ばくだんいわ618メガンテを使うから?
メガザルロック595メガザルを使うから?

  • 踊り脅威値
デススタッフ1437
ホロゴースト501
しれんその1281
イーブルフライ110
ホラービースト92

  • ブレス脅威値
ダークドレアム(B)228
ダークドレアム(A)226
デスタムーア167
じごくのほのお163
ドラゴラム133

  • その他脅威値
ダークドレアム(B)430雄叫びを使うから?
ヘルクラッシャー418
デスタムーア351
デスタムーア323
デビット279

モンスターのパラメータを変えた場合にはこちらも変えないとAIが誤判定すると思われます。ちなみにこの値はAIの判定でしか使われていないようですが、モンスターの素の強さから何らかの計算をして算出されたものと思われますが、当然ROM中にはその計算式は存在しないので、どうやって計算しているのかは全くわかりません。たまたまデュランは攻撃力の45%(260*0.45=117)であることを見つけましたが、まじめに計算する場合、行動回数や行動パターンも関係すると思われるため、計算方法はかなり複雑になるのではと思われます。実際の値は$08F19B-に定義されているので気になる人は実際にみてみてください。脅威値と戦闘行動を1行に並べてみてみるといろいろ見えてくるかもしれません。

  • SR: $02D15E モンスター特別種族情報セット?
02D15ELDA #$0004A=#$00044種のモンスターグループについてセットする
02D161ASLA<<1
02D162TAYY=A
02D163LDA $2567,YA=$2567+YモンスターIDを取得
02D166JSR $D16ESR: $02D16Eモンスター特別種族情報セット?
02D169DEYY–
02D16ADEYY–
02D16BBPL #$F6if(n==off) goto $02D163
02D16DRTSreturn

  • SR: $02D16E モンスター特別種族情報セット?
02D16EPHYPush Y
02D16FASLA<<1
02D170TAXX=A
02D171LDA $C22B54,XA=$022B54+X
02D175TAXX=A
02D176TYAA=Y
02D177ASLA<<1
02D178ASLA<<1
02D179ASLA<<1
02D17ATAYY=A
02D17BLDA $C20168,XA=$020168+Xここに値がセットされているのはメタル系スライムのみ
02D17FAND #$01FFA&=#$01FF
02D182STA $264B,Y$264B+Y=A
02D185LDA $C2016A,XA=$02016A+Xすべて0 使っているのか?
02D189AND #$01FFA&=#$01FF
02D18CSTA $264D,Y$264D+Y=A
02D18FPLYPull Y
02D190RTSreturn

処理自体は何をやってるのかはわかりますが、値(#$8C)がセットされているのはメタルスライム・はぐれメタル・メタルキング・合体メタルスライムのみで、何を意図しているかはよくわかりません。今のところ大して重要ではなさそうということでさらっと流しておきます。

スポンサーリンク

コメントを書く

メールアドレスが公開されることはありません。コメントは管理者の承認後表示されます。