裏CHUNSOFT > ROMイメージ改造・解析 > ダメージ計算式

ダメージ計算式

とにかく式だけ知りたい方へ

ダメージ計算式は以下の通りです。

(ダメージ)=(攻撃力)*(112〜143)*(15/16)^(防御力)/128
但し、15/16は乗じる度に切り上げ、/128は切り捨て。

計算過程を詳しく知りたい方へ

攻撃力の取得からダメージ計算までのルーチンの逆アセンブルリストです。 これを見ながら解説していきます。 数値は全て16進数です。 $XXはメモリ(変数)を表します。 ダメージ計算に影響しない命令にはコメントを付けていません。 1つ1つ解説するまでもない命令は、複数の命令をまとめて1つのコメントで解説しています。

021527  BF 7D 86 7E  LDA $7E867D+"X" ; "A" = (攻撃力)
02152B  85 02        STA $02         ; $02 = "A"
02152D  84 00        STY $00         ; 
02152F  86 01        STX $01         ; 
021531  DA           PHX             ; 
021532  22 EF 28 C2  JSR $C228EF     ; 下のルーチンへ

$02に攻撃力を代入します。 ここは問題ないでしょう。

0228EF  08           PHP             ; 
0228F0  E2 30        SEP #$30        ; 
0228F2  A9 7E        LDA #$7E        ; 
0228F4  48           PHA             ; 
0228F5  AB           PLB             ; 
0228F6  A4 00        LDY $00         ; 
0228F8  A6 01        LDX $01         ; 
0228FA  A5 02        LDA $02         ; "A" = $02
0228FC  48           PHA             ; "A"の値をプッシュ
0228FD  22 5F F6 C3  JSR $C3F65F     ; $00 = (乱数) (乱数生成ルーチン)
022901  A5 00        LDA $00         ; "A" = $00
022903  29 1F        AND #$1F        ; "A" = 00〜1F
022905  18           CLC             ; 
022906  69 70        ADC #$70        ; "A" += 70
022908  85 00        STA $00         ; $00 = "A"
02290A  68           PLA             ; プッシュしていた値を"A"に代入
02290B  85 01        STA $01         ; $01 = "A"
02290D  22 CB E3 C3  JSR $C3E3CB     ; 下のルーチンへ

$00に乱数で00h〜1Fhの値を代入し、それに70hを加えます。 これで、$00は70h〜8Fh(112〜143)の値をとります。 これはダメージのランダム変化に使用されます。 すなわち、ダメージのランダム変化は32段階です。

また、攻撃力の値が$01に代入されました。

03E3CB  08           PHP             ; 
03E3CC  E2 20        SEP #$20        ; 
03E3CE  A5 01        LDA $01         ; "A" = $01
03E3D0  49 FF        EOR #$FF        ; "A" = "A" xor FF
03E3D2  EB           XBA             ; 
03E3D3  A9 00        LDA #$00        ; "A" = NN00 (NN = "A" xor FF)
03E3D5  85 01        STA $01         ; $01 = "A"
03E3D7  C2 20        REP #$20        ; 
03E3D9  0A           ASL             ; "A" *= 2 (を10000で割った余り)
03E3DA  B0 02        BCS $E3DE       ; 
03E3DC  65 00        ADC $00         ; 上の演算で"A"が10000を超えなければ"A" += $00
(中略)                               ; 上3行の処理を計8回繰り返す
03E401  85 00        STA $00         ; $00 = "A"
03E403  28           PLP             ; 
03E404  6B           RTL             ; 下のルーチンへ

"A"を2倍して、それが10000hを超えなければ"A"に$00を加えるという処理を8回も繰り返しています。 一見訳の分からないことをしているように見えますが、落ち着いて考えてみましょう。

$00は最大でも8Fhですから、この繰り返しが行われる前の"A"の上位8ビット(NNの部分)が$00の加算により変化することはありません。 そして、加算された$00もその後一緒に2倍されていきますから、この処理は次のように言い換えることができます。

(新しい値)=0
"A"のbit15が0ならば(新しい値)+=$00*80h
"A"のbit14が0ならば(新しい値)+=$00*40h
"A"のbit13が0ならば(新しい値)+=$00*20h
"A"のbit12が0ならば(新しい値)+=$00*10h
"A"のbit11が0ならば(新しい値)+=$00*08h
"A"のbit10が0ならば(新しい値)+=$00*04h
"A"のbit9が0ならば(新しい値)+=$00*02h
"A"のbit8が0ならば(新しい値)+=$00
$00=(新しい値)

ところで、"A"のbit8〜15は03E3D0hでxorされた値なので、攻撃力のbit0〜7とはそれぞれのビットが互いに違う関係にあります。 なので、"A"のbit8〜15を攻撃力のbit0〜7に置き換えると、次のようになります。

(新しい値)=0
攻撃力のbit7が1ならば(新しい値)+=$00*80h
攻撃力のbit6が1ならば(新しい値)+=$00*40h
攻撃力のbit5が1ならば(新しい値)+=$00*20h
攻撃力のbit4が1ならば(新しい値)+=$00*10h
攻撃力のbit3が1ならば(新しい値)+=$00*08h
攻撃力のbit2が1ならば(新しい値)+=$00*04h
攻撃力のbit1が1ならば(新しい値)+=$00*02h
攻撃力のbit0が1ならば(新しい値)+=$00
$00=(新しい値)

つまりこの処理は何の難しいこともない、(攻撃力)*$00を求める処理だったのです。 そして、$00の値は(攻撃力)*$00に変わります。

022911  C2 20        REP #$20        ; 
022913  DA           PHX             ; 
022914  BE 91 86     LDX $8691+"Y"   ; "X" = (防御力)
022917  80 0F        BRA $2928       ; 022928へジャンプ
022919  A5 00        LDA $00         ; "A" = $00
02291B  4A           LSR * 4         ; "A" /= 10 (余りは切り捨て)
02291F  49 FF FF     EOR #$FFFF      ; "A" = "A" xor FFFF
022922  38           SEC             ; 
022923  65 00        ADC $00         ; "A" += $00 + 1 (を10000で割った余り)
022925  85 00        STA $00         ; $00 = "A"
022927  CA           DEX             ; "X" --
022928  D0 EF        BNE $2919       ; "X" != 0のとき022919へジャンプ
02292A  FA           PLX             ; 
02292B  A5 00        LDA $00         ; "A" = $00
02292D  0A           ASL             ; "A" *= 2 (を10000で割った余り)
02292E  90 03        BCC $2933       ; 
022930  A9 00 FF     LDA #$FF00      ; 上の処理で"A"が10000を超えると"A" = FF00
022933  E2 20        SEP #$20        ; 
022935  EB           XBA             ; "A"の上位8バイトと下位8バイトを交換(交換された後の下位8バイトがダメージになる)
022936  48           PHA             ; 

いよいよダメージ計算です。 "X"は防御力ですから、防御力の値だけ次の処理を繰り返していることが分かります。

"A" = $00
"A" /= 10
"A" = "A" xor FFFF
"A" += $00 + 1
$00 = "A"

この処理を1つの式にまとめると次のようになります(数値は10進数)。

$00(新)=(($00/16) xor 65535)+$00+1

パッと見ただけでは$00はどうなるのか分かりませんね。 しかし、($00/16) xor 65535は、65535-$00/16と同じですから、この式を次ように変更しても同じです。

$00(新)=65535-$00/16(切り捨て)+$00+1=$00*15/16(切り上げ)+65536

これを65536で割った余りが新しい$00になりますから、$00(新)=$00*15/16、つまり防御力1につき$00に15/16を乗じるということです。

後は簡単です。 "A"に$00を代入して2倍し、その上位8バイト、すなわち256で割った値がダメージになります。 式で表すと、

(ダメージ)=$00*(15/16)^(防御力)*2/256=(攻撃力)*(112〜143)*(15/16)^(防御力)/128
但し、15/16は乗じる度に切り上げ、/128は切り捨て。

となります。 022930hはダメージが255を超えた場合に255にする処理です。

2009年2月25日更新

裏CHUNSOFT > ROMイメージ改造・解析 > ダメージ計算式