DQ3戦闘部分解説19

今回は戦闘行動実行SRのうち、特徴的なものをピックアップして解説します。

  • SR: $028DA9 直接攻撃後半
028DA9 JSR $8DB0 SR: $028DB0 直接攻撃基本ダメージ計算
028DAC JSR $8E70 SR: $028E70 ダメージ確定メイン
028DAF RTL return
  • SR: $028DB0 直接攻撃基本ダメージ計算
028DB0 LDX $23E4 X=$23E4 攻撃主体インデックスをXにセット
028DB3 LDY $23E8 Y=$23E8 攻撃対象インデックスをYにセット
028DB6 JSL $02CA62 SR: $02CA62 引数:1#$2041 守備力取得
028DBC LSR A>>1 守備力を1/2する(2)
028DBD PHA Push A
028DBE JSL $02CA5B SR: $02CA5B 引数:1#$203F 攻撃力取得
028DC4 STA $02 DP($02)=A
028DC6 PHA Push A
028DC7 LSR A>>1
028DC8 LSR A>>1
028DC9 LSR A>>1 攻撃力を1/8する(3)
028DCA STA $04 DP($04)=A
028DCC PLA Pull A
028DCD SEC c=on
028DCE SBC $01,S A-=Stack($01) 攻撃力-守備力1/2(4)
028DD0 STA $00 DP($00)=A
028DD2 PLA Pull A
028DD3 JSL $02CAD9 SR: $02CAD9 引数:1#$203C 引数:2#$00FF 攻撃主体のグループ番号取得
028DDB CMP #$0005 A>=#$0005? PC側か
028DDE BCS #$04 if(c==on) goto $028DE4
028DE0 JSR $8E0E SR: $028E0E モンスター直接攻撃ダメージ計算
028DE3 RTS return
028DE4 JSR $8DEB SR: $028DEB PC側直接攻撃ダメージ計算
028DE7 JSR $8E4A SR: $028E4A PC側直接攻撃ダメージ補正
028DEA RTS return

ダメージ算出に当たって使用されるファクターは

  1. 攻撃力($02)
  2. 攻撃力1/8($04)
  3. 攻撃力-守備力1/2($00)

です。

  • SR: $028E0E モンスター直接攻撃ダメージ計算
028E0E LDA $00 A=DP($00)
028E10 BMI #$06 if(n==on) goto $028E18 3)がマイナスか
028E12 LDA $04 A=DP($04)
028E14 CMP $00 A>=DP($00)?
028E16 BCC #$1B if(c==off) goto $028E33 2)<3)か
028E18 LDA $02 A=DP($02)
028E1A CMP #$0010 A>=#$0010? 攻撃力が16以上か
028E1D BCS #$0A if(c==on) goto $028E29 攻撃力が16以上か
028E1F JSL $0012D1 SR: $0012D1 乱数発生 $00-FF
028E23 AND #$0001 A&=#$0001 1/2の確率で1ダメージ
028E26 STA $00 DP($00)=A
028E28 RTS return
028E29 LDA $04 A=DP($04)
028E2B DEC A–
028E2C JSL $00133E SR: $00133E 0~(2)-1の間で乱数発生
028E30 STA $00 DP($00)=A
028E32 RTS return
028E33 LDA $02 A=DP($02)
028E35 CMP #$0008 A>=#$0008? 攻撃力が8以上か
028E38 BCC #$E5 if(c==off) goto $028E1F
028E3A JSL $001472 SR: $001472 $63-99の乱数発生
028E3E LDX #$0000 X=#$0000
028E41 JSL $0010D6 SR: $0010D6 $00,X(3B)=A(1B)*$00,X(2Byte) (3)*$63-99の間の乱数
028E45 LDA $01 A=DP($01) 上2バイトだけ使う
028E47 STA $00 DP($00)=A
028E49 RTS return
  • SR: PC側直接攻撃ダメージ計算
028DEB LDA $00 A=DP($00)
028DED BMI #$15 if(n==on) goto $028E04
028DEF CMP #$0002 A>=#$0002?
028DF2 BCC #$10 if(c==off) goto $028E04
028DF4 JSL $001472 SR: $001472 $63-99の乱数発生
028DF8 LDX #$0000 X=#$0000
028DFB JSL $0010D6 SR: $0010D6 $00,X(3B)=A(1B)*$00,X(2Byte) (3)*$63-99の間の乱数
028DFF LDA $01 A=DP($01)
028E01 STA $00 DP($00)=A 上2バイトだけ使う
028E03 RTS return
028E04 JSL $0012D1 SR: $0012D1 乱数発生 $00-FF
028E08 AND #$0001 A&=#$0001 1/2の確率で1ダメージ
028E0B STA $00 DP($00)=A
028E0D RTS return
  • SR: $028E4A 味方直接攻撃ダメージ補正
028E4A LDA $23F2 A=$23F2
028E4D CMP #$0001 A==#$0001?
028E50 BNE #$13 if(z==off) goto $028E65
028E52 LSR $00 DP($00)>>1
028E54 LSR $00 DP($00)>>1
028E56 LSR $00 DP($00)>>1 ダメージ値を1/8する
028E58 LDA #$0002 A=#$0002
028E5B JSL $00133E SR: $00133E 乱数発生 00-A A(1B)
028E5F INC A++
028E60 CLC c=off
028E61 ADC $00 A+=DP($00)
028E63 STA $00 DP($00)=A
028E65 RTS return

「DQ3 ダメージ値」で検索すると見つかる計算式どおりの実装です(当たり前ですが)。$028E4Aはいまいち何をしてるか不明です。パーティアタック時のダメージ計算のようにも見えます。SR: $028E70をコールする直前はダメージ値は$00にセットされていることが期待されています。

  • SR: $028E70 ダメージ確定メイン
028E70 LDA #$0000 A=#$0000
028E73 PEA $23AE Push $23AE
028E76 PEA $0010 Push $0010
028E79 PEA $7E00 Push $7E00
028E7C JSL $0902E9 SR: $0902E9 会心・痛恨が起きないフラグをクリア
028E80 JSL $028E92 SR: $028E92 ゾンビキラー・ドラゴンキラーによるダメージアップチェック
028E84 JSL $028EFB SR: $028EFB ダメージ確定メイン
028E88 LDA $00 A=DP($00)
028E8A STA $23FA $23FA=A
028E8D JSL $029200 SR: $029200 ダメージ確定後の処理メイン
028E91 RTS return
  • SR: $028E92 ゾンビキラー・ドラゴンキラーによるダメージアップチェック
028E92 PHP Push P Flag
028E93 REP #$30 m=off(A/M:16b), x=off(X/Y:16b)
028E95 PHA Push A
028E96 PHX Push X
028E97 PHY Push Y
028E98 PHB Push DB
028E99 PEA $7E7E Push $7E7E
028E9C PLB Pull DB
028E9D PLB Pull DB
028E9E LDA $23E4 A=$23E4
028EA1 STA $2428 $2428=A
028EA4 LDA #$0000 A=#$0000 アイテム種別:武器をセット
028EA7 JSL $02B8AA SR: $02B8AA 装備アイテムID取得
028EAB LDA $242C A=$242C
028EAE STA $245C $245C=A
028EB1 LDX #$0000 X=#$0000
028EB4 LDA $23EE A=$23EE
028EB7 CMP $028F8B,X A==$028F8B+X? 単体攻撃のみ?
028EBB BEQ #$07 if(z==on) goto $028EC4
028EBD DEX X–
028EBE DEX X–
028EBF BPL #$F6 if(n==off) goto $028EB7
028EC1 LDX #$8000 X=#$8000
028EC4 STX $245E $245E=X
028EC7 LDA $23EE A=$23EE
028ECA ASL A<<1
028ECB TAX X=A
028ECC LDA $022BE0,X A=$022BE0+X
028ED0 TAX X=A
028ED1 LDA $02007A,X A=$02007A+X
028ED5 AND #$0010 A&=#$0010
028ED8 BEQ #$13 if(z==on) goto $028EED 戦闘行動が種族特効ONの行動か
028EDA LDX #$0002 X=#$0002
028EDD LDA $245C A=$245C
028EE0 AND #$00FF A&=#$00FF
028EE3 CMP $028F99,X A==$028F99+X? 装備武器が種族特効武器リストにマッチするか
028EE7 BEQ #$07 if(z==on) goto $028EF0
028EE9 DEX X–
028EEA DEX X–
028EEB BPL #$F6 if(n==off) goto $028EE3
028EED LDX #$8000 X=#$8000 該当しない場合は最上位ビットをONにする
028EF0 STX $2460 $2460=X 種族特効ダメージ計算用SRオフセット
028EF3 PLB Pull DB
028EF4 REP #$30 m=off(A/M:16b), x=off(X/Y:16b)
028EF6 PLY Pull Y
028EF7 PLX Pull X
028EF8 PLA Pull A
028EF9 PLP Pull P Flag
028EFA RTL return
  • SR: $028EFB ダメージ確定メイン
028EFB PHP Push P Flag
028EFC PHB Push DB
028EFD REP #$30 m=off(A/M:16b), x=off(X/Y:16b)
028EFF PEA $7E7E Push $7E7E
028F02 PLB Pull DB
028F03 PLB Pull DB
028F04 LDA $23E8 A=$23E8
028F07 ASL A<<1
028F08 TAX X=A
028F09 LDA $02CBD3,X A=$02CBD3+X
028F0D STA $0A DP($0A)=A キャラクターアドレスorモンスターIDセット
028F0F TAX X=A
028F10 LDA $2049,X A=$2049+X
028F13 STA $2420 $2420=A
028F16 LDA $2050,X A=$2050+X
028F19 AND #$0001 A&=#$0001
028F1C STA $241E $241E=A
028F1F LDA $23EE A=$23EE
028F22 ASL A<<1
028F23 TAX X=A
028F24 LDA $022BE0,X A=$022BE0+X
028F28 STA $08 DP($08)=A 戦闘行動戦闘アドレスセット
028F2A JSR $8F4B SR: $028F4B 複数攻撃武器ダメージカット計算
028F2D JSR $8F82 SR: $028F82 意味なし?
028F30 JSR $9015 SR: $029015 バイキルト時のダメージ値計算
028F33 JSR $903E SR: $02903E 会心痛恨処理メイン
028F36 JSR $8F90 SR: $028F90 種族特効時のダメージ加算
028F39 JSR $913E SR: $02913E PC側ダメージ系耐性計算
028F3C JSR $9179 SR: $029179 フバーハ時のダメージ軽減計算
028F3F JSR $919B SR: $02919B 防御時のダメージ軽減計算
028F42 JSR $91A8 SR: $0291A8 耐性によるダメージ調整
028F45 JSR $91DF SR: $0291DF 毒針装備時の一撃必殺失敗(1ダメージ)
028F48 PLB Pull DB
028F49 PLP Pull P Flag
028F4A RTL return

このSRで耐性等を考慮したダメージ値の調整を行います。呪文ダメージなど、固定範囲のダメージ値の場合はこのSRをコールする前には数値設定($022EE0-)の範囲の値がセットされた状態でこのSRが呼ばれることになります。

  • SR: $028F4B 複数攻撃武器ダメージカット計算
028F4B LDA $23EE A=$23EE
028F4E CMP #$00AC A==#$00AC? 戦闘行動がグループ攻撃か
028F51 BEQ #$05 if(z==on) goto $028F58
028F53 CMP #$00AD A==#$00AD? 戦闘行動が全体攻撃か
028F56 BNE #$1D if(z==off) goto $028F75
028F58 LDA $23DA A=$23DA 何体目を攻撃しているか?
028F5B DEC A–
028F5C CMP #$0005 A>=#$0005?
028F5F BCC #$03 if(c==off) goto $028F64
028F61 LDA #$0005 A=#$0005 5体目以降は33/256で固定
028F64 ASL A<<1
028F65 TAX X=A
028F66 LDA $028F76,X A=$028F76+X ダメージ低減率取得
028F6A LDX #$0000 X=#$0000
028F6D JSL $001146 SR: $001146 $00,x=A(1Byte)*$00,x
028F71 LDA $01 A=DP($01) 上位2バイトを使用
028F73 STA $00 DP($00)=A
028F75 RTS return
  • SR: $029015 バイキルト時のダメージ値計算
029015 LDX $08 X=DP($08)
029017 LDA $020079,X A=$020079+X
02901B AND #$0020 A&=#$0020 戦闘行動がバイキルトに依存するか
02901E BEQ #$1D if(z==on) goto $02903D
029020 LDA $23E4 A=$23E4
029023 ASL A<<1
029024 TAX X=A
029025 LDA $02CBD3,X A=$02CBD3+X
029029 TAX X=A
02902A LDA $2051,X A=$2051+X
02902D AND #$0008 A&=#$0008 行動主体がバイキルト中か
029030 BEQ #$0B if(z==on) goto $02903D
029032 LDA $23DA A=$23DA 攻撃対象が現在実行中の行動の何番目か(1からカウント)
029035 DEC A–
029036 ORA $23D8 Aor=$23D8 現在の攻撃が何回目か
029039 BNE #$02 if(z==off) goto $02903D 複数対象攻撃の2体目以降or複数回数攻撃の2回目以降だと0にならないのでバイキルトの対象外になる
02903B ASL $00 DP($00)<<1 ダメージ値を単純に2倍化
02903D RTS return

この計算式を見ると、バイキルトとは「攻撃力を2倍化するのではなく、ダメージ値を2倍化する」というのがその実体であることがわかります。

(12/03追記)

  • SR: $02903E 会心・痛恨判定
02903E LDA $23AE A=$23AE
029041 AND #$0010 A&=#$0010 会心・痛恨が発生しない条件(バイキルト中?)
029044 BNE #$20 if(z==off) goto $029066
029046 JSL $02B774 SR: $02B774 毒針ヒット判定?
02904A CMP #$0001 A==#$0001? 毒針ヒット?
02904D BEQ #$14 if(z==on) goto $029063
02904F CMP #$0002 A==#$0002? 外れ
029052 BEQ #$12 if(z==on) goto $029066
029054 JSR $90A7 SR: $0290A7 特殊武器会心判定(会心c=on)
029057 BCS #$0A if(c==on) goto $029063
029059 JSR $90D1 SR: $0290D1 痛恨判定(会心c=on)
02905C BCS #$05 if(c==on) goto $029063
02905E JSR $9067 SR: $029067 会心判定(会心c=on)
029061 BCS #$03 if(c==on) goto $029066
029063 JSR $90E9 SR: $0290E9 会心痛恨処理
029066 RTS return

$23AEの4ビット目はおそらくバイキルト中にセットされるフラグです。「バイキルト中には会心・痛恨は発生しない」という実装ですね。

  • SR: $0290A7 特殊武器会心判定
0290A7 LDX #$0000 X=#$0000
0290AA LDA $245C A=$245C 装備武器取得?
0290AD AND #$00FF A&=#$00FF
0290B0 CMP #$0010 A==#$0010? まじんのおのアイテムID
0290B3 BEQ #$08 if(z==on) goto $0290BD
0290B5 INX X++
0290B6 CMP #$0014 A==#$0014? 破壊の剣アイテムID
0290B9 BEQ #$02 if(z==on) goto $0290BD
0290BB CLC c=off
0290BC RTS return
0290BD LDA $0290CF,X A=$0290CF+X 特殊武器会心率分母配列から分母をセット
0290C1 AND #$00FF A&=#$00FF
0290C4 JSL $00133E SR: $00133E 乱数発生 00-A A(1B)
0290C8 CMP #$0000 A==#$0000? 0なら会心
0290CB BNE #$EE if(z==off) goto $0290BB
0290CD SEC c=on
0290CE RTS return

まじんのおの、破壊の剣のアイテムIDがハードコードされています。特殊防具回避率のようにアイテムID、分母を1レコードに持った配列で実装しそうなものですが、そうしていないようです。従ってまじんのおの、破壊の剣以外で会心率を別途設定したい、という場合はプログラムを書く必要があります。(自分は特に必要性を感じないのでパス)

  • SR: $0290D1 痛恨判定
0290D1 LDA $23EE A=$23EE
0290D4 CMP #$0002 A==#$0002? 戦闘行動が「つうこん」か
0290D7 BNE #$0E if(z==off) goto $0290E7
0290D9 LDA #$0007 A=#$0007 痛恨率分母設定
0290DC JSL $00133E SR: $00133E 乱数発生 00-A A(1B)
0290E0 CMP #$0000 A==#$0000? 1/8で痛恨
0290E3 BNE #$02 if(z==off) goto $0290E7
0290E5 SEC c=on
0290E6 RTS return
0290E7 CLC c=off
0290E8 RTS return

モンスター側の痛恨の一撃は戦闘行動として#$002:つうこんが設定されていない限りは通常攻撃でも痛恨の一撃は発生しない、ということになります。

  • SR: $029067 会心判定
029067 LDX $23E4 X=$23E4
02906A STX $2428 $2428=X
02906D JSL $02CAD9 SR: $02CAD9 引数:1#$203C 引数:2#$00FF グループID取得
029075 CMP #$0005 A>=#$0005? 行動主体がPC側か
029078 BCC #$2B if(c==off) goto $0290A5
02907A JSL $02BE8A SR: $02BE8A 引数:1#$24 職業ID取得
02907F BCS #$18 if(c==on) goto $029099
029081 CMP #$0001 A==#$0001? 職業がぶとうかか
029084 BNE #$13 if(z==off) goto $029099
029086 JSL $02C240 SR: $02C240 引数:1#$0A レベル取得
02908B CMP #$0005 A>=#$0005? レベルが5以上か
02908E BCC #$09 if(c==off) goto $029099
029090 PHA Push A
029091 JSL $0012D1 SR: $0012D1 乱数発生 $00-FF
029095 CMP $01,S A==or>=Stack($01)? レベルを閾値として使用
029097 PLA Pull A
029098 RTS return
029099 JSL $0012D1 SR: $0012D1 乱数発生 $00-FF
02909D AND #$003F A&=#$003F 1/48の確率
0290A0 SEC c=on
0290A1 BNE #$02 if(z==off) goto $0290A5
0290A3 CLC c=off
0290A4 RTS return
0290A5 SEC c=on
0290A6 RTS return

広く知られているとおり、Lv5以上のぶとうかの会心発生率について職業特性として(レベル+1)/256となるように実装されていることがわかります。それ以外は1/48です。

  • SR: $0290E9 会心痛恨発生処理
0290E9 JSL $01E32E SR: $01E32E 引数:1#$005F SE再生?
0290EF LDA #$0009 A=#$0009 戦闘メッセージID:「かいしんの いちげき」
0290F2 PHA Push A
0290F3 LDX $23E4 X=$23E4
0290F6 JSL $02CAD9 SR: $02CAD9 引数:1#$203C 引数:2#$00FF グループID取得
0290FE CMP #$0005 A>=#$0005? 行動主体がPC側か
029101 BCS #$05 if(c==on) goto $029108
029103 LDA #$000A A=#$000A 戦闘メッセージID:「つうこんの いちげき」
029106 STA $01,S Stack($01)=A
029108 PLA Pull A
029109 JSL $01A87A SR: $01A87A 戦闘メッセージ表示
02910D LDA #$0001 A=#$0001
029110 PEA $23AD Push $23AD
029113 PEA $0020 Push $0020
029116 PEA $7E00 Push $7E00
029119 JSL $0902E9 SR: $0902E9 RAM上情報変更
02911D LDX $23E4 X=$23E4
029120 JSL $02CA5B SR: $02CA5B 引数:1#$203F 攻撃力取得
029126 STA $00 DP($00)=A
029128 LSR A>>1 攻撃力1/2
029129 PHA Push A
02912A JSL $0014A3 SR: $0014A3 $5A-83の乱数発生
02912E LDX #$0000 X=#$0000
029131 JSL $0010D6 SR: $0010D6 $00,X(3B)=A(1B)*$00,X(2Byte)
029135 LDA $01 A=DP($01) 攻撃力に乱数をかけて上1バイトを使用
029137 CLC c=off
029138 ADC $01,S A+=Stack($01) 攻撃力1/2に加算
02913A STA $00 DP($00)=A ダメージ値決定
02913C PLA Pull A
02913D RTS return

会心・痛恨時のダメージ計算は攻撃力1/2+攻撃力*(0.35~0.51)で計算され、対象の防御力が無視されることがわかります。

  • SR: $028F90 種族特効時のダメージ加算
028F90 LDX $2460 X=$2460 種族特効ダメージ用計算SRへのオフセット
028F93 BMI #$03 if(n==on) goto $028F98 なし(#$8000)のときはスキップ)
028F95 JSR $8F9D SR: $($028F9D+X)
028F98 RTS return
  • SR: $028FA1 ドラゴンキラー装備時のドラゴン系へのダメージ計算
028FA1 LDA $241E A=$241E 対象がモンスター?
028FA4 BNE #$1E if(z==off) goto $028FC4
028FA6 LDA $2420 A=$7E2420 モンスターID?
028FA9 ASL A<<1
028FAA TAX X=A
028FAB LDA $132500,X A=$132500+X モンスター基本情報へのオフセット取得
028FAF TAX X=A
028FB0 LDA $130002,X A=$130002+X
028FB4 AND #$0040 A&=#$0040 対象がドラゴンか
028FB7 BEQ #$0B if(z==on) goto $028FC4
028FB9 LDA $23AE A=$23AE
028FBC AND #$0010 A&=#$0010 バイキルト中?
028FBF BNE #$04 if(z==off) goto $028FC5
028FC1 JSR $9004 SR: $029004 16~32を加算
028FC4 RTS return
028FC5 LDA #$0018 A=#$0018 バイキルト中は固定ダメージ24を加算?
028FC8 CLC c=off
028FC9 ADC $00 A+=DP($00)
028FCB STA $00 DP($00)=A
028FCD RTS return
  • SR: $028FCE ゾンビキラー装備時のゾンビ系へのダメージ計算
028FCE LDA $23EE A=$23EE
028FD1 PHA Push A
028FD2 LDA #$001B A=#$001B 戦闘行動IDをニフラムに差し替え
028FD5 STA $23EE $23EE=A
028FD8 LDA $23AE A=$23AE
028FDB AND #$0010 A&=#$0010 バイキルト中?
028FDE BNE #$0D if(z==off) goto $028FED
028FE0 JSR $A3EB SR: $02A3EB 耐性を考慮して成否判定+PC側耐性計算?
028FE3 BCC #$03 if(c==off) goto $028FE8
028FE5 JSR $9004 SR: $029004 16~32を加算
028FE8 PLA Pull A
028FE9 STA $23EE $23EE=A
028FEC RTS return
028FED LDA $00 A=DP($00)
028FEF PHA Push A
028FF0 LDA #$0018 A=#$0018
028FF3 STA $00 DP($00)=A
028FF5 JSR $A3CE SR: $02A3CE
028FF8 LDA $00 A=DP($00)
028FFA CLC c=off
028FFB ADC $01,S A+=Stack($01)
028FFD STA $01,S Stack($01)=A
028FFF PLA Pull A
029000 STA $00 DP($00)=A
029002 BRA #$E4 goto $028FE8

ゾンビキラーも同じ…とおもったら、なんとゾンビ系フラグは使用されずに、ニフラム耐性が使用されているようです。86氏のDQ3Plusパッチに「ゾンビキラー効果対象をニフラム耐性→ゾンビ系bitに変更」という記述がありましたが、この部分をドラゴン特効と同じように変更しているものと思われます(未確認)。

コメント

  1. タカオ より:

    「会心・痛恨時のダメージ計算は攻撃力1/2+攻撃力*(0.3~0.57)で計算」とありますが、要は0.8~1.07という振れ幅だということですよね。
     しかし例えば攻撃力丁度400にして会心出させてみたところ、いくらやっても実測ダメージが340~404の区間、つまり0.85~1.01倍相当に止どまり(平均値こそ0.5%しか差がありませんが)理論値より更に狭まっているのは何故でしょうか。、
     必要ならば検証用のセーブデータをお送りすることも可能ですので、ご教示して頂けませんでしょうか。よろしくお願いします。m(._.)m

    管理者より返信:

    $5A(90)、$83(131)の$100(256)に対する割合の記述が間違っていたので修正しました。それぞれ0.35、0.51なので実測通りということでしょう。

  2. 匿名 より:

    「Lv5以上のぶとうかの会心発生率について職業特性としてレベル/255」とあるので、乱数は1~255の範囲で発生するということでしょうか?0~255だと式と合わなかったので。

    管理者より返信:

    たしかにそうですね。修正しておきます。ご指摘ありがとうございました。

  3. 匿名 より:

    乱数とレベルが等号の場合も会心なので、(レベル+1)/256ではないでしょうか?

    管理者より返信:

    たしかにそうですね。修正しておきます。ご指摘ありがとうございました。