DQ3 まんたん処理の仕組み4

今回からHP回復処理を見ていきます。

  • SR: $0921AC まんたんHP回復処理
0921ACJSR $22EDSR: $0922EDベホマズン回復倍率取得
0921AFJSR $2286SR: $092286ベホマラー回復倍率取得
0921B2JSR $2342SR: $092342単体回復呪文回復倍率取得
0921B5LDA $2BBEA=$2BBEここからベホマズン実行判断
0921B8BMI #$0Dif(n==on) goto $0921C7
0921BACMP $2BBCA>=$2BBC?
0921BDBCS #$08if(c==on) goto $0921C7
0921BFCMP $2BC0A>=$2BC0?
0921C2BCS #$03if(c==on) goto $0921C7
0921C4JMP $223C ($09223C)goto $09223Cベホマズン実行決定
0921C7LDA $2BBCA=$2BBCここからベホマラー実行判断
0921CABMI #$0Aif(n==on) goto $0921D6
0921CCCMP $2BC0A==$2BC0?
0921CFBEQ #$05if(z==on) goto $0921D6
0921D1BCC #$03if(c==off) goto $0921D6
0921D3JMP $2252 ($092252)goto $092252ベホマラー実行決定
0921D6LDA $2BC0A=$2BC0単体回復実行判断
0921D9BPL #$02if(n==off) goto $0921DD
0921DBCLCc=off回復不要
0921DCRTSreturn
0921DDLDY #$0000Y=#$0000ここからは単体回復処理
0921E0LDA $2BE8,YA=$2BE8+Y
0921E3TAXX=A
0921E4AND #$4000A&=#$4000死亡中なら飛ばす
0921E7BNE #$4Bif(z==off) goto $092234
0921E9TXAA=X
0921EAAND #$0800A&=#$0800回復不要なら飛ばす
0921EDBEQ #$45if(z==on) goto $092234
0921EFTXAA=X
0921F0AND #$0080A&=#$0080ホイミで回復
0921F3BNE #$1Dif(z==off) goto $092212
0921F5TXAA=X
0921F6AND #$0100A&=#$0100ベホイミで回復
0921F9BNE #$28if(z==off) goto $092223
0921FBTXAA=X
0921FCAND #$0200A&=#$0200ベホマで回復
0921FFBEQ #$33if(z==on) goto $092234
092201LDA #$0010A=#$0010
092204LDX #$0025X=#$0025
092207JSR $2456SR: $092456指定の回復呪文を使えるキャラクターを決定(いないc=off)
09220ABCC #$28if(c==off) goto $092234
09220CLDA #$0025A=#$0025ベホマの戦闘行動ID
09220FJMP $2231 ($092231)goto $092231
092212LDA #$0004A=#$0004
092215LDX #$001FX=#$001F
092218JSR $2456SR: $092456指定の回復呪文を使えるキャラクターを決定(いないc=off)
09221BBCC #$17if(c==off) goto $092234
09221DLDA #$001FA=#$001Fホイミの戦闘行動ID
092220JMP $2231 ($092231)goto $092231
092223LDA #$0008A=#$0008
092226LDX #$0022X=#$0022
092229JSR $2456SR: $092456指定の回復呪文を使えるキャラクターを決定(いないc=off)
09222CBCC #$06if(c==off) goto $092234
09222ELDA #$0022A=#$0022ベホイミの戦闘行動ID
092231JSR $2481SR: $092481単体回復処理
092234INYY++
092235INYY++
092236CPY $2BB4Y>=$2BB4?
092239BCC #$A5if(c==off) goto $0921E0
09223BRTSreturn
09223CLDA $2BC4A=$2BC4ここから下はベホマラー・ベホマズンの回復処理
09223FSTA $BE7D$BE7D=A
092242LDX $2BC8X=$2BC8
092245JSL $C433BASR: $0433BA 引数:1#$01 引数:2#$FF 引数:3#$FE現在MP減算
09224CLDY #$002BY=#$002Bベホマズンの戦闘行動ID
09224FJMP $2265 ($092265)goto $092265
092252LDA $2BC2A=$2BC2
092255STA $BE7D$BE7D=A
092258LDX $2BC6X=$2BC6
09225BJSL $C433BASR: $0433BA 引数:1#$01 引数:2#$FF 引数:3#$FE現在MP減算
092262LDY #$0028Y=#$0028ベホマラーの戦闘行動ID
092265STY $33DA$33DA=Y
092268JSL $C2CC0ASR: $02CC0A 引数:1#$1860戦闘行動構造体アクセスSR インデックス:Y
09226ESTA $BE77$BE77=A
092271JSL $C1E32ESR: $01E32E 引数:1#$0065再生BGM設定?
092277JSL $C1A8D4SR: $01A8D4 引数:1#$0002メッセージ表示
09227DJSL $C912A4SR: $0912A4生存者全員回復
092281INC $2BBA$2BBA++
092284SECc=on
092285RTSreturn

この処理がまんたん処理のHP回復行動の1セットです。$0921AC-DCでそれぞれの回復呪文による回復倍率(後述)を求め、それに従ってどの呪文を実行するかを判断していますが、ここに論理バグがあります(後述)。$0921DD-23Bが単体回復処理、$0923C-85がベホマラー・ベホマズンの回復処理です。単体回復の場合は先頭から順番に回復して終わりまで、ベホマラー・ベホマズンの場合は1回だけ実行したらこの処理を抜けます。その後HP差分を求める処理を再度実行し、更に回復行動が必要かを判断します。これはまんべんなく回復呪文を実行することによってまんたん中にMP切れが起きた場合にも誰か一人だけ完全回復して残りは瀕死のまま、という状況に陥らないようにするためだと思われます。

  • SR: $092286 ベホマラー回復倍率取得
092286STZ $2BBC$2BBC=#$000で初期化
092289LDX $2BB4X=$2BB4
09228CDEXX–
09228DDEXX–
09228EBMI #$54if(n==on) goto $0922E4
092290LDA $2BE8,XA=$2BE8+X
092293BMI #$F7if(n==on) goto $09228C行動不能なら飛ばす
092295AND #$0020A&=#$0020
092298BEQ #$F2if(z==on) goto $09228Cベホマラーを覚えていないなら飛ばす
09229APHXPush X
09229BTXAA=X
09229CLSRA>>1
09229DSTA $2BC2$2BC2=Aベホマラー実行者IDをセット
0922A0TAXX=A
0922A1LDY #$0028Y=#$0028ベホマラーの戦闘行動ID
0922A4JSL $C2B44ASR: $02B44A消費MP計算(MPオーバーc=off)
0922A8STA $2BC6$2BC6=A消費MPをセット
0922ABPLXPull X
0922ACBCC #$DEif(c==off) goto $09228CMPオーバーなら調査を続行
0922AELDY $2BB4Y=$2BB4
0922B1DEYY–
0922B2DEYY–
0922B3BMI #$2Fif(n==on) goto $0922E4
0922B5LDA $2BE8,YA=$2BE8+Y
0922B8AND #$4000A&=#$4000死亡中なら飛ばす
0922BBBNE #$F4if(z==off) goto $0922B1
0922BDLDA $2BE8,YA=$2BE8+Y
0922C0AND #$0800A&=#$0800回復不要なら飛ばす
0922C3BEQ #$ECif(z==on) goto $0922B1
0922C5PHXPush X
0922C6LDA $2BCE,YA=$2BCE+YHP差分をセット
0922C9STZ $70DP($70)=#$00
0922CBSTA $71DP($71)=A
0922CDLDA $2BCAA=$2BCA
0922D0LDX #$0070X=#$0070
0922D3JSL $C01295SR: $001295$00,x(3B)=$00,X(3B)/A(2B?) 剰余=A,$30
0922D7LDA $70A=DP($70)
0922D9CLCc=off
0922DAADC $2BBCA+=($2BBC+c)回復倍率を加算
0922DDSTA $2BBC$2BBC=A
0922E0PLXPull X
0922E1JMP $22B1 ($0922B1)goto $0922B1
0922E4LDA $2BBCA=$2BBC回復倍率が0のままなら1引いて#$FFFFにしてリターン
0922E7BNE #$03if(z==off) goto $0922EC
0922E9DEC $2BBC$2BBC–
0922ECRTSreturn

前半部分($092286-AD)では、誰がベホマラーを実行するかを決めています。これまた例によってパーティの後ろからチェックしていきます。そして後半部分($0922AE-E3)では生存者のHP差分に対する回復倍率を求め、それを合計しています。「回復倍率」というのは、「HP差分を特定の回復行動の最小値で割ったもの」です。要は、「全快するのにその呪文を何回唱える必要があるか」ということです。当然この値が小さければ小さいほど効率がいいということになるので、ベホマラーが使用できない場合は#$FFFFを回復倍率とすることで使用されるのを回避しています。また、回復倍率を求める際にHP差分を1バイト左にシフトすることで、得られた商の上1バイトが整数部分、下1バイトが小数部分(分母は256)ということになり、より高い精度で倍率が得られることになります。これは他の呪文との効果比較のために使用されます。これを踏まえてベホマズンの回復倍率取得を見ると何をやっているか見えてきます。

  • SR: $0922ED ベホマズン回復倍率取得
092315LDY $2BB4Y=$2BB4
092318DEYY–
092319DEYY–
09231ABMI #$1Dif(n==on) goto $092339
09231CLDA $2BE8,YA=$2BE8+Y
09231FAND #$4000A&=#$4000死亡中なら飛ばす
092322BNE #$F4if(z==off) goto $092318
092324LDA $2BE8,YA=$2BE8+Y
092327AND #$0800A&=#$0800
09232ABEQ #$ECif(z==on) goto $092318
09232CLDA #$0100A=#$0100完全回復なので回復倍率は#$0100
09232FCLCc=off
092330ADC $2BBEA+=($2BBE+c)
092333STA $2BBE$2BBE=A
092336JMP $2318 ($092318)goto $092318

ベホマ・ベホマズンは完全回復なのでHP差分がいくつであろうが回復倍率は#$0100ということになります。

  • SR: $092342 単体回復呪文回復倍率取得
092342STZ $2BC0$2BC0=#$00
092345LDY #$0000Y=#$0000
092348LDA #$0080A=#$0080
09234BORA #$0100Aor=#$0100
09234EORA #$0200Aor=#$0200
092351EOR #$FFFFA^=#$FFFF
092354AND $2BE8,YA&=$2BE8+Y
092357STA $2BE8,Y$2BE8+Y=A
09235ATAXX=A
09235BAND #$4000A&=#$4000死亡中なら飛ばす
09235EBNE #$60if(z==off) goto $0923C0
092360TXAA=X
092361AND #$0800A&=#$0800回復不要なら飛ばす
092364BEQ #$5Aif(z==on) goto $0923C0
092366LDA #$FFFFA=#$FFFF
092369STA $2BB8$2BB8=Aテンポラリの回復倍率用バッファ
09236CSTZ $2BD6$2BD6=#$00
09236FLDX $2BB4X=$2BB4詠唱可能者を後ろから探す
092372DEXX–
092373DEXX–
092374BMI #$35if(n==on) goto $0923AB
092376LDA $2BE8,XA=$2BE8+X
092379BMI #$F7if(n==on) goto $092372行動不能なら飛ばす
09237BSTA $2BB6$2BB6=A
09237ELDA #$0004A=#$0004ホイミを習得しているか
092381AND $2BB6A&=$2BB6
092384BEQ #$06if(z==on) goto $09238C
092386LDA #$001FA=#$001Fホイミの戦闘行動ID
092389JSR $23D3SR: $0923D3指定呪文の回復倍率取得
09238CLDA #$0008A=#$0008ベホイミを習得しているか
09238FAND $2BB6A&=$2BB6
092392BEQ #$06if(z==on) goto $09239A
092394LDA #$0022A=#$0022ベホイミの戦闘行動ID
092397JSR $23D3SR: $0923D3指定呪文の回復倍率取得
09239ALDA #$0010A=#$0010ベホマを習得しているか
09239DAND $2BB6A&=$2BB6
0923A0BEQ #$06if(z==on) goto $0923A8
0923A2LDA #$0025A=#$0025ベホマの戦闘行動ID
0923A5JSR $23D3SR: $0923D3指定呪文の回復倍率取得
0923A8JMP $2372 ($092372)goto $092372
0923ABLDA $2BB8A=$2BB8
0923AEBMI #$10if(n==on) goto $0923C0#$FFFFのままなら回復倍率加算処理は飛ばす
0923B0CLCc=off
0923B1ADC $2BC0A+=($2BC0+c)回復倍率を加算
0923B4STA $2BC0$2BC0=A
0923B7LDA $2BE8,YA=$2BE8+Y
0923BAORA $2BD6Aor=$2BD6回復フラグをセット
0923BDSTA $2BE8,Y$2BE8+Y=A
0923C0INYY++
0923C1INYY++
0923C2CPY $2BB4Y>=$2BB4?
0923C5BCS #$03if(c==on) goto $0923CA
0923C7JMP $2348 ($092348)goto $092348
0923CALDA $2BC0A=$2BC0回復倍率が0のままなら1引いて#$FFFFにしてリターン
0923CDBNE #$03if(z==off) goto $0923D2
0923CFDEC $2BC0$2BC0–
0923D2RTSreturn

ループが入れ子になっているのでちょっとわかりにくいですが、$092345-C6までが各キャラクターの回復倍率を得るための大きなループで、その中に$09236F-AAでどの呪文を実行するかを決めるループがあります。

  • SR: $0923D3 指定呪文の回復倍率取得
0923D3PHAPush A
0923D4PHXPush X
0923D5PHYPush Y
0923D6LDA $2BCE,YA=$2BCE+Y
0923D9STZ $70DP($70)=#$00
0923DBSTA $71DP($71)=A
0923DDLDA $05,SA=Stack($05)
0923DFTAXX=A
0923E0JSR $24EDSR: $0924ED回復最小量取得
0923E3CMP #$FFFFA==#$FFFF?ベホマなら#$0100をセットする
0923E6BNE #$06if(z==off) goto $0923EE
0923E8LDA #$0100A=#$0100
0923EBJMP $23F7 ($0923F7)goto $0923F7
0923EELDX #$0070X=#$0070
0923F1JSL $C01295SR: $001295$00,x(3B)=$00,X(3B)/A(2B?) 剰余=A,$30
0923F5LDA $70A=DP($70)
0923F7LDX $2BB8X=$2BB8
0923FACPX #$0100X>=#$0100?
0923FDBCS #$0Fif(c==on) goto $09240E
0923FFCMP #$0100A>=#$0100?
092402BCS #$0Aif(c==on) goto $09240E
092404CMP $2BB8A>=$2BB8?
092407BCC #$49if(c==off) goto $092452
092409BEQ #$47if(z==on) goto $092452
09240BJMP $2413 ($092413)goto $092413
09240ECMP $2BB8A>=$2BB8?
092411BCS #$3Fif(c==on) goto $092452
092413PHAPush A
092414LDA $05,SA=Stack($05)
092416LSRA>>1
092417TAXX=A
092418LDA $07,SA=Stack($07)
09241ATAYY=A
09241BJSL $C2B44ASR: $02B44A消費MP計算(MPオーバーc=off)
09241FBCC #$30if(c==off) goto $092451
092421PLAPull A
092422STA $2BB8$2BB8=Aテンポラリの回復倍率を更新
092425LDA $05,SA=Stack($05)
092427CMP #$001FA==#$001F?このSRに入った時のAレジスタの値がホイミか
09242ABNE #$09if(z==off) goto $092435
09242CLDA #$0080A=#$0080ホイミで回復フラグON
09242FSTA $2BD6$2BD6=A
092432JMP $2452 ($092452)goto $092452
092435CMP #$0022A==#$0022?このSRに入った時のAレジスタの値がベホイミか
092438BNE #$09if(z==off) goto $092443
09243ALDA #$0100A=#$0100ベホイミで回復フラグON
09243DSTA $2BD6$2BD6=A
092440JMP $2452 ($092452)goto $092452
092443CMP #$0025A==#$0025?このSRに入った時のAレジスタの値がベホマか
092446BNE #$0Aif(z==off) goto $092452
092448LDA #$0200A=#$0200ベホマで回復フラグON
09244BSTA $2BD6$2BD6=A
09244EJMP $2452 ($092452)goto $092452
092451PLAPull A
092452PLYPull Y
092453PLXPull X
092454PLAPull A
092455RTSreturn

$7E2BB8, $7E2BD6をグローバル変数のように使い、回復倍率が一番小さい値とその呪文を探しています。ホイミ・ベホイミ・ベホマについて4人分、最大12回繰り返すと対象の一人に対する回復倍率の最小値とその呪文が何かが取得出来ます。大体の流れがわかったところで、最初に言及した論理バグについてもう一度見てみます。$0921B5の時点で、回復倍率については以下のメモリにセットされています。

$7E2BBC ベホマラー回復倍率

$7E2BBE ベホマズン回復倍率

$7E2BC0 単体回復倍率(全員分)

  • SR: $0921AC まんたんHP回復処理(再掲)
0921B5LDA $2BBEA=$2BBEここからベホマズン実行判断
0921B8BMI #$0Dif(n==on) goto $0921C7
0921BACMP $2BBCA>=$2BBC?
0921BDBCS #$08if(c==on) goto $0921C7
0921BFCMP $2BC0A>=$2BC0?
0921C2BCS #$03if(c==on) goto $0921C7
0921C4JMP $223C ($09223C)goto $09223Cベホマズン実行決定
0921C7LDA $2BBCA=$2BBCここからベホマラー実行判断
0921CABMI #$0Aif(n==on) goto $0921D6
0921CCCMP $2BC0A==$2BC0?
0921CFBEQ #$05if(z==on) goto $0921D6
0921D1BCC #$03if(c==off) goto $0921D6<-BCSが正しい?
0921D3JMP $2252 ($092252)goto $092252ベホマラー実行決定
0921D6LDA $2BC0A=$2BC0単体回復実行判断
0921D9BPL #$02if(n==off) goto $0921DD

ここで、パーティ全員のレベルが高く、瀕死の状態を想定してみます。ベホマズン回復倍率・単体回復倍率はベホマ4回分でどちらも#$0400、ベホマラー回復倍率は各人5回必要と仮定すると#$1400となります。$0921C2でc=onで見てしまっているために、ベホマズンと単体回復倍率のどちらも#$0400の場合にもc=onとなってしまい、ベホマラーの実行判断に飛ばされてしまいます。さらに$0921D1でAレジスタのベホマラーの回復倍率と単体回復の回復倍率の合計($7E2BC0)を比較してc=offなら単体回復に飛ばすようになっているため、上記の例では#1400と#0400を比較してベホマラーの方が回復効率が悪いにもかかわらずベホマラーが選択される、という結果になります。この実装のためにいかなる状況でもベホマズンは使用されず、ベホマ4回の方が効率が良くてもベホマラーを延々と実行するようになっています。ベホマズンを1回実行するよりもベホマ4回のほうが消費MPが少ないのでベホマズンを使わない点については実害はないと思いますが、ベホマラー連発についてはバグっぽい感じです。ところが、試しに$0921D1のBCCをBCSに変えてみると今度はベホマラーは一切使用されませんwww。習得レベルの関係上、ベホマラー(僧侶・賢者:Lv34)を習得していていてベホマ(僧侶・賢者:Lv30)を習得していないという状態がないため、単純に回復倍率のみで比較した場合に今度はベホマラーはベホマを上回るケースがない上に、ベホイミで代替されてしまうという状態になります。消費MPでの比較がない以上しょうがない気もしますが。最終的にどっちがいいのかという話になりますが、ベホマラーをむやみに連発するオリジナルのほうが効率面からは良くないといえるでしょう。

まんたんの内部の処理を見てきましたが、オリジナルDQ3のまんたん処理における問題は以下の点にあると考えます。

  • ベホマズンが選択肢に入っているのにいかなる状況でも使用されない(これはこれでいい?)
  • ベホマが使える状態でもベホマラーを乱発する(バグ?)
  • 使用者が無条件でパーティ最後列に固定されるため、複数人が回復呪文を使用出来る状態でも最後尾のキャラクターがベホマラー乱発する実装によりベホマラーを乱発し、あっという間にMPが枯渇するケースがある

オリジナルをプレイする場合、パーティ全員が瀕死に近い場合は手動でベホマを4回使えばこの状況は回避されます。しかしこんな大欠陥があるにもかかわらずなんでRTAなどで問題にならないのかと思ったのですが、よくよく考えて見ればベホマラーを習得する前にクリアしてしまうからでした。以上の解析結果を踏まえて次回からはDQ3 K.Mixではどう修正するかを考えていきます。

コメント

タイトルとURLをコピーしました