今回からHP回復処理を見ていきます。
- SR: $0921AC まんたんHP回復処理
0921AC | JSR $22ED | SR: $0922ED | ベホマズン回復倍率取得 |
---|---|---|---|
0921AF | JSR $2286 | SR: $092286 | ベホマラー回復倍率取得 |
0921B2 | JSR $2342 | SR: $092342 | 単体回復呪文回復倍率取得 |
0921B5 | LDA $2BBE | A=$2BBE | ここからベホマズン実行判断 |
0921B8 | BMI #$0D | if(n==on) goto $0921C7 | |
0921BA | CMP $2BBC | A>=$2BBC? | |
0921BD | BCS #$08 | if(c==on) goto $0921C7 | |
0921BF | CMP $2BC0 | A>=$2BC0? | |
0921C2 | BCS #$03 | if(c==on) goto $0921C7 | |
0921C4 | JMP $223C ($09223C) | goto $09223C | ベホマズン実行決定 |
0921C7 | LDA $2BBC | A=$2BBC | ここからベホマラー実行判断 |
0921CA | BMI #$0A | if(n==on) goto $0921D6 | |
0921CC | CMP $2BC0 | A==$2BC0? | |
0921CF | BEQ #$05 | if(z==on) goto $0921D6 | |
0921D1 | BCC #$03 | if(c==off) goto $0921D6 | |
0921D3 | JMP $2252 ($092252) | goto $092252 | ベホマラー実行決定 |
0921D6 | LDA $2BC0 | A=$2BC0 | 単体回復実行判断 |
0921D9 | BPL #$02 | if(n==off) goto $0921DD | |
0921DB | CLC | c=off | 回復不要 |
0921DC | RTS | return | |
0921DD | LDY #$0000 | Y=#$0000 | ここからは単体回復処理 |
0921E0 | LDA $2BE8,Y | A=$2BE8+Y | |
0921E3 | TAX | X=A | |
0921E4 | AND #$4000 | A&=#$4000 | 死亡中なら飛ばす |
0921E7 | BNE #$4B | if(z==off) goto $092234 | |
0921E9 | TXA | A=X | |
0921EA | AND #$0800 | A&=#$0800 | 回復不要なら飛ばす |
0921ED | BEQ #$45 | if(z==on) goto $092234 | |
0921EF | TXA | A=X | |
0921F0 | AND #$0080 | A&=#$0080 | ホイミで回復 |
0921F3 | BNE #$1D | if(z==off) goto $092212 | |
0921F5 | TXA | A=X | |
0921F6 | AND #$0100 | A&=#$0100 | ベホイミで回復 |
0921F9 | BNE #$28 | if(z==off) goto $092223 | |
0921FB | TXA | A=X | |
0921FC | AND #$0200 | A&=#$0200 | ベホマで回復 |
0921FF | BEQ #$33 | if(z==on) goto $092234 | |
092201 | LDA #$0010 | A=#$0010 | |
092204 | LDX #$0025 | X=#$0025 | |
092207 | JSR $2456 | SR: $092456 | 指定の回復呪文を使えるキャラクターを決定(いないc=off) |
09220A | BCC #$28 | if(c==off) goto $092234 | |
09220C | LDA #$0025 | A=#$0025 | ベホマの戦闘行動ID |
09220F | JMP $2231 ($092231) | goto $092231 | |
092212 | LDA #$0004 | A=#$0004 | |
092215 | LDX #$001F | X=#$001F | |
092218 | JSR $2456 | SR: $092456 | 指定の回復呪文を使えるキャラクターを決定(いないc=off) |
09221B | BCC #$17 | if(c==off) goto $092234 | |
09221D | LDA #$001F | A=#$001F | ホイミの戦闘行動ID |
092220 | JMP $2231 ($092231) | goto $092231 | |
092223 | LDA #$0008 | A=#$0008 | |
092226 | LDX #$0022 | X=#$0022 | |
092229 | JSR $2456 | SR: $092456 | 指定の回復呪文を使えるキャラクターを決定(いないc=off) |
09222C | BCC #$06 | if(c==off) goto $092234 | |
09222E | LDA #$0022 | A=#$0022 | ベホイミの戦闘行動ID |
092231 | JSR $2481 | SR: $092481 | 単体回復処理 |
092234 | INY | Y++ | |
092235 | INY | Y++ | |
092236 | CPY $2BB4 | Y>=$2BB4? | |
092239 | BCC #$A5 | if(c==off) goto $0921E0 | |
09223B | RTS | return | |
09223C | LDA $2BC4 | A=$2BC4 | ここから下はベホマラー・ベホマズンの回復処理 |
09223F | STA $BE7D | $BE7D=A | |
092242 | LDX $2BC8 | X=$2BC8 | |
092245 | JSL $C433BA | SR: $0433BA 引数:1#$01 引数:2#$FF 引数:3#$FE | 現在MP減算 |
09224C | LDY #$002B | Y=#$002B | ベホマズンの戦闘行動ID |
09224F | JMP $2265 ($092265) | goto $092265 | |
092252 | LDA $2BC2 | A=$2BC2 | |
092255 | STA $BE7D | $BE7D=A | |
092258 | LDX $2BC6 | X=$2BC6 | |
09225B | JSL $C433BA | SR: $0433BA 引数:1#$01 引数:2#$FF 引数:3#$FE | 現在MP減算 |
092262 | LDY #$0028 | Y=#$0028 | ベホマラーの戦闘行動ID |
092265 | STY $33DA | $33DA=Y | |
092268 | JSL $C2CC0A | SR: $02CC0A 引数:1#$1860 | 戦闘行動構造体アクセスSR インデックス:Y |
09226E | STA $BE77 | $BE77=A | |
092271 | JSL $C1E32E | SR: $01E32E 引数:1#$0065 | 再生BGM設定? |
092277 | JSL $C1A8D4 | SR: $01A8D4 引数:1#$0002 | メッセージ表示 |
09227D | JSL $C912A4 | SR: $0912A4 | 生存者全員回復 |
092281 | INC $2BBA | $2BBA++ | |
092284 | SEC | c=on | |
092285 | RTS | return |
この処理がまんたん処理のHP回復行動の1セットです。$0921AC-DCでそれぞれの回復呪文による回復倍率(後述)を求め、それに従ってどの呪文を実行するかを判断していますが、ここに論理バグがあります(後述)。$0921DD-23Bが単体回復処理、$0923C-85がベホマラー・ベホマズンの回復処理です。単体回復の場合は先頭から順番に回復して終わりまで、ベホマラー・ベホマズンの場合は1回だけ実行したらこの処理を抜けます。その後HP差分を求める処理を再度実行し、更に回復行動が必要かを判断します。これはまんべんなく回復呪文を実行することによってまんたん中にMP切れが起きた場合にも誰か一人だけ完全回復して残りは瀕死のまま、という状況に陥らないようにするためだと思われます。
- SR: $092286 ベホマラー回復倍率取得
092286 | STZ $2BBC | $2BBC=#$00 | 0で初期化 |
---|---|---|---|
092289 | LDX $2BB4 | X=$2BB4 | |
09228C | DEX | X– | |
09228D | DEX | X– | |
09228E | BMI #$54 | if(n==on) goto $0922E4 | |
092290 | LDA $2BE8,X | A=$2BE8+X | |
092293 | BMI #$F7 | if(n==on) goto $09228C | 行動不能なら飛ばす |
092295 | AND #$0020 | A&=#$0020 | |
092298 | BEQ #$F2 | if(z==on) goto $09228C | ベホマラーを覚えていないなら飛ばす |
09229A | PHX | Push X | |
09229B | TXA | A=X | |
09229C | LSR | A>>1 | |
09229D | STA $2BC2 | $2BC2=A | ベホマラー実行者IDをセット |
0922A0 | TAX | X=A | |
0922A1 | LDY #$0028 | Y=#$0028 | ベホマラーの戦闘行動ID |
0922A4 | JSL $C2B44A | SR: $02B44A | 消費MP計算(MPオーバーc=off) |
0922A8 | STA $2BC6 | $2BC6=A | 消費MPをセット |
0922AB | PLX | Pull X | |
0922AC | BCC #$DE | if(c==off) goto $09228C | MPオーバーなら調査を続行 |
0922AE | LDY $2BB4 | Y=$2BB4 | |
0922B1 | DEY | Y– | |
0922B2 | DEY | Y– | |
0922B3 | BMI #$2F | if(n==on) goto $0922E4 | |
0922B5 | LDA $2BE8,Y | A=$2BE8+Y | |
0922B8 | AND #$4000 | A&=#$4000 | 死亡中なら飛ばす |
0922BB | BNE #$F4 | if(z==off) goto $0922B1 | |
0922BD | LDA $2BE8,Y | A=$2BE8+Y | |
0922C0 | AND #$0800 | A&=#$0800 | 回復不要なら飛ばす |
0922C3 | BEQ #$EC | if(z==on) goto $0922B1 | |
0922C5 | PHX | Push X | |
0922C6 | LDA $2BCE,Y | A=$2BCE+Y | HP差分をセット |
0922C9 | STZ $70 | DP($70)=#$00 | |
0922CB | STA $71 | DP($71)=A | |
0922CD | LDA $2BCA | A=$2BCA | |
0922D0 | LDX #$0070 | X=#$0070 | |
0922D3 | JSL $C01295 | SR: $001295 | $00,x(3B)=$00,X(3B)/A(2B?) 剰余=A,$30 |
0922D7 | LDA $70 | A=DP($70) | |
0922D9 | CLC | c=off | |
0922DA | ADC $2BBC | A+=($2BBC+c) | 回復倍率を加算 |
0922DD | STA $2BBC | $2BBC=A | |
0922E0 | PLX | Pull X | |
0922E1 | JMP $22B1 ($0922B1) | goto $0922B1 | |
0922E4 | LDA $2BBC | A=$2BBC | 回復倍率が0のままなら1引いて#$FFFFにしてリターン |
0922E7 | BNE #$03 | if(z==off) goto $0922EC | |
0922E9 | DEC $2BBC | $2BBC– | |
0922EC | RTS | return |
前半部分($092286-AD)では、誰がベホマラーを実行するかを決めています。これまた例によってパーティの後ろからチェックしていきます。そして後半部分($0922AE-E3)では生存者のHP差分に対する回復倍率を求め、それを合計しています。「回復倍率」というのは、「HP差分を特定の回復行動の最小値で割ったもの」です。要は、「全快するのにその呪文を何回唱える必要があるか」ということです。当然この値が小さければ小さいほど効率がいいということになるので、ベホマラーが使用できない場合は#$FFFFを回復倍率とすることで使用されるのを回避しています。また、回復倍率を求める際にHP差分を1バイト左にシフトすることで、得られた商の上1バイトが整数部分、下1バイトが小数部分(分母は256)ということになり、より高い精度で倍率が得られることになります。これは他の呪文との効果比較のために使用されます。これを踏まえてベホマズンの回復倍率取得を見ると何をやっているか見えてきます。
- SR: $0922ED ベホマズン回復倍率取得
略 | |||
---|---|---|---|
092315 | LDY $2BB4 | Y=$2BB4 | |
092318 | DEY | Y– | |
092319 | DEY | Y– | |
09231A | BMI #$1D | if(n==on) goto $092339 | |
09231C | LDA $2BE8,Y | A=$2BE8+Y | |
09231F | AND #$4000 | A&=#$4000 | 死亡中なら飛ばす |
092322 | BNE #$F4 | if(z==off) goto $092318 | |
092324 | LDA $2BE8,Y | A=$2BE8+Y | |
092327 | AND #$0800 | A&=#$0800 | |
09232A | BEQ #$EC | if(z==on) goto $092318 | |
09232C | LDA #$0100 | A=#$0100 | 完全回復なので回復倍率は#$0100 |
09232F | CLC | c=off | |
092330 | ADC $2BBE | A+=($2BBE+c) | |
092333 | STA $2BBE | $2BBE=A | |
092336 | JMP $2318 ($092318) | goto $092318 | |
略 |
ベホマ・ベホマズンは完全回復なのでHP差分がいくつであろうが回復倍率は#$0100ということになります。
- SR: $092342 単体回復呪文回復倍率取得
092342 | STZ $2BC0 | $2BC0=#$00 | |
---|---|---|---|
092345 | LDY #$0000 | Y=#$0000 | |
092348 | LDA #$0080 | A=#$0080 | |
09234B | ORA #$0100 | Aor=#$0100 | |
09234E | ORA #$0200 | Aor=#$0200 | |
092351 | EOR #$FFFF | A^=#$FFFF | |
092354 | AND $2BE8,Y | A&=$2BE8+Y | |
092357 | STA $2BE8,Y | $2BE8+Y=A | |
09235A | TAX | X=A | |
09235B | AND #$4000 | A&=#$4000 | 死亡中なら飛ばす |
09235E | BNE #$60 | if(z==off) goto $0923C0 | |
092360 | TXA | A=X | |
092361 | AND #$0800 | A&=#$0800 | 回復不要なら飛ばす |
092364 | BEQ #$5A | if(z==on) goto $0923C0 | |
092366 | LDA #$FFFF | A=#$FFFF | |
092369 | STA $2BB8 | $2BB8=A | テンポラリの回復倍率用バッファ |
09236C | STZ $2BD6 | $2BD6=#$00 | |
09236F | LDX $2BB4 | X=$2BB4 | 詠唱可能者を後ろから探す |
092372 | DEX | X– | |
092373 | DEX | X– | |
092374 | BMI #$35 | if(n==on) goto $0923AB | |
092376 | LDA $2BE8,X | A=$2BE8+X | |
092379 | BMI #$F7 | if(n==on) goto $092372 | 行動不能なら飛ばす |
09237B | STA $2BB6 | $2BB6=A | |
09237E | LDA #$0004 | A=#$0004 | ホイミを習得しているか |
092381 | AND $2BB6 | A&=$2BB6 | |
092384 | BEQ #$06 | if(z==on) goto $09238C | |
092386 | LDA #$001F | A=#$001F | ホイミの戦闘行動ID |
092389 | JSR $23D3 | SR: $0923D3 | 指定呪文の回復倍率取得 |
09238C | LDA #$0008 | A=#$0008 | ベホイミを習得しているか |
09238F | AND $2BB6 | A&=$2BB6 | |
092392 | BEQ #$06 | if(z==on) goto $09239A | |
092394 | LDA #$0022 | A=#$0022 | ベホイミの戦闘行動ID |
092397 | JSR $23D3 | SR: $0923D3 | 指定呪文の回復倍率取得 |
09239A | LDA #$0010 | A=#$0010 | ベホマを習得しているか |
09239D | AND $2BB6 | A&=$2BB6 | |
0923A0 | BEQ #$06 | if(z==on) goto $0923A8 | |
0923A2 | LDA #$0025 | A=#$0025 | ベホマの戦闘行動ID |
0923A5 | JSR $23D3 | SR: $0923D3 | 指定呪文の回復倍率取得 |
0923A8 | JMP $2372 ($092372) | goto $092372 | |
0923AB | LDA $2BB8 | A=$2BB8 | |
0923AE | BMI #$10 | if(n==on) goto $0923C0 | #$FFFFのままなら回復倍率加算処理は飛ばす |
0923B0 | CLC | c=off | |
0923B1 | ADC $2BC0 | A+=($2BC0+c) | 回復倍率を加算 |
0923B4 | STA $2BC0 | $2BC0=A | |
0923B7 | LDA $2BE8,Y | A=$2BE8+Y | |
0923BA | ORA $2BD6 | Aor=$2BD6 | 回復フラグをセット |
0923BD | STA $2BE8,Y | $2BE8+Y=A | |
0923C0 | INY | Y++ | |
0923C1 | INY | Y++ | |
0923C2 | CPY $2BB4 | Y>=$2BB4? | |
0923C5 | BCS #$03 | if(c==on) goto $0923CA | |
0923C7 | JMP $2348 ($092348) | goto $092348 | |
0923CA | LDA $2BC0 | A=$2BC0 | 回復倍率が0のままなら1引いて#$FFFFにしてリターン |
0923CD | BNE #$03 | if(z==off) goto $0923D2 | |
0923CF | DEC $2BC0 | $2BC0– | |
0923D2 | RTS | return |
ループが入れ子になっているのでちょっとわかりにくいですが、$092345-C6までが各キャラクターの回復倍率を得るための大きなループで、その中に$09236F-AAでどの呪文を実行するかを決めるループがあります。
- SR: $0923D3 指定呪文の回復倍率取得
0923D3 | PHA | Push A | |
---|---|---|---|
0923D4 | PHX | Push X | |
0923D5 | PHY | Push Y | |
0923D6 | LDA $2BCE,Y | A=$2BCE+Y | |
0923D9 | STZ $70 | DP($70)=#$00 | |
0923DB | STA $71 | DP($71)=A | |
0923DD | LDA $05,S | A=Stack($05) | |
0923DF | TAX | X=A | |
0923E0 | JSR $24ED | SR: $0924ED | 回復最小量取得 |
0923E3 | CMP #$FFFF | A==#$FFFF? | ベホマなら#$0100をセットする |
0923E6 | BNE #$06 | if(z==off) goto $0923EE | |
0923E8 | LDA #$0100 | A=#$0100 | |
0923EB | JMP $23F7 ($0923F7) | goto $0923F7 | |
0923EE | LDX #$0070 | X=#$0070 | |
0923F1 | JSL $C01295 | SR: $001295 | $00,x(3B)=$00,X(3B)/A(2B?) 剰余=A,$30 |
0923F5 | LDA $70 | A=DP($70) | |
0923F7 | LDX $2BB8 | X=$2BB8 | |
0923FA | CPX #$0100 | X>=#$0100? | |
0923FD | BCS #$0F | if(c==on) goto $09240E | |
0923FF | CMP #$0100 | A>=#$0100? | |
092402 | BCS #$0A | if(c==on) goto $09240E | |
092404 | CMP $2BB8 | A>=$2BB8? | |
092407 | BCC #$49 | if(c==off) goto $092452 | |
092409 | BEQ #$47 | if(z==on) goto $092452 | |
09240B | JMP $2413 ($092413) | goto $092413 | |
09240E | CMP $2BB8 | A>=$2BB8? | |
092411 | BCS #$3F | if(c==on) goto $092452 | |
092413 | PHA | Push A | |
092414 | LDA $05,S | A=Stack($05) | |
092416 | LSR | A>>1 | |
092417 | TAX | X=A | |
092418 | LDA $07,S | A=Stack($07) | |
09241A | TAY | Y=A | |
09241B | JSL $C2B44A | SR: $02B44A | 消費MP計算(MPオーバーc=off) |
09241F | BCC #$30 | if(c==off) goto $092451 | |
092421 | PLA | Pull A | |
092422 | STA $2BB8 | $2BB8=A | テンポラリの回復倍率を更新 |
092425 | LDA $05,S | A=Stack($05) | |
092427 | CMP #$001F | A==#$001F? | このSRに入った時のAレジスタの値がホイミか |
09242A | BNE #$09 | if(z==off) goto $092435 | |
09242C | LDA #$0080 | A=#$0080 | ホイミで回復フラグON |
09242F | STA $2BD6 | $2BD6=A | |
092432 | JMP $2452 ($092452) | goto $092452 | |
092435 | CMP #$0022 | A==#$0022? | このSRに入った時のAレジスタの値がベホイミか |
092438 | BNE #$09 | if(z==off) goto $092443 | |
09243A | LDA #$0100 | A=#$0100 | ベホイミで回復フラグON |
09243D | STA $2BD6 | $2BD6=A | |
092440 | JMP $2452 ($092452) | goto $092452 | |
092443 | CMP #$0025 | A==#$0025? | このSRに入った時のAレジスタの値がベホマか |
092446 | BNE #$0A | if(z==off) goto $092452 | |
092448 | LDA #$0200 | A=#$0200 | ベホマで回復フラグON |
09244B | STA $2BD6 | $2BD6=A | |
09244E | JMP $2452 ($092452) | goto $092452 | |
092451 | PLA | Pull A | |
092452 | PLY | Pull Y | |
092453 | PLX | Pull X | |
092454 | PLA | Pull A | |
092455 | RTS | return |
$7E2BB8, $7E2BD6をグローバル変数のように使い、回復倍率が一番小さい値とその呪文を探しています。ホイミ・ベホイミ・ベホマについて4人分、最大12回繰り返すと対象の一人に対する回復倍率の最小値とその呪文が何かが取得出来ます。大体の流れがわかったところで、最初に言及した論理バグについてもう一度見てみます。$0921B5の時点で、回復倍率については以下のメモリにセットされています。
$7E2BBC ベホマラー回復倍率
$7E2BBE ベホマズン回復倍率
$7E2BC0 単体回復倍率(全員分)
- SR: $0921AC まんたんHP回復処理(再掲)
略 | |||
---|---|---|---|
0921B5 | LDA $2BBE | A=$2BBE | ここからベホマズン実行判断 |
0921B8 | BMI #$0D | if(n==on) goto $0921C7 | |
0921BA | CMP $2BBC | A>=$2BBC? | |
0921BD | BCS #$08 | if(c==on) goto $0921C7 | |
0921BF | CMP $2BC0 | A>=$2BC0? | |
0921C2 | BCS #$03 | if(c==on) goto $0921C7 | |
0921C4 | JMP $223C ($09223C) | goto $09223C | ベホマズン実行決定 |
0921C7 | LDA $2BBC | A=$2BBC | ここからベホマラー実行判断 |
0921CA | BMI #$0A | if(n==on) goto $0921D6 | |
0921CC | CMP $2BC0 | A==$2BC0? | |
0921CF | BEQ #$05 | if(z==on) goto $0921D6 | |
0921D1 | BCC #$03 | if(c==off) goto $0921D6 | <-BCSが正しい? |
0921D3 | JMP $2252 ($092252) | goto $092252 | ベホマラー実行決定 |
0921D6 | LDA $2BC0 | A=$2BC0 | 単体回復実行判断 |
0921D9 | BPL #$02 | if(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ではどう修正するかを考えていきます。
コメント